Files @ b8f62f7ddf7f
Branch filter:

Location: DistRen/src/server/slave.c

ethanzonca
Updated render power function
/*
  Copyright 2009 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando

  This file is a part of DistRen.

  DistRen is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  DistRen is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with DistRen.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "slavefuncs.h"

#include "common/asprintf.h"
#include "common/options.h"
#include "common/protocol.h"
#include "common/remoteio.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>


int main(int argc, char *argv[])
{

  char *datadir;
  char *server;
  char *username;
  char *hostname;
  cfg_opt_t myopts[] = {
    CFG_SIMPLE_STR("username", &username),
    CFG_SIMPLE_STR("datadir", &datadir),
    CFG_SIMPLE_STR("server", &server),
    CFG_SIMPLE_STR("hostname", &hostname),
    CFG_END()
  };
  cfg_t * my_cfg;

  struct options_common *commonopts;

  struct distrenjob *myjob; /* Structure to hold data gathered from the XML file */

  struct remoteio *comm_slave;

  /**
     initializations
  */
  datadir = NULL;
  server = NULL;
  username = NULL;

  char curopt;

  while(((char)-1) != (curopt = getopt(argc, argv, "u:h")))
     {
       if(curopt == ':')
         {
           fprintf(stderr, "-%c: is missing an argument\n", optopt);
           return 1;
         }
       else if(curopt == '?')
         {
           fprintf(stderr, "-%c: invalid option specified\n", optopt);
           return 1;
         }
       else if(curopt == 'h')
         {
           fprintf(stderr, "Usage: distrenslave [option] \nStarts a distren slave\n\t-u\tset username (run after fresh install)\n\t-h\tshow this help\n");
           return 2;
         }
       else if(curopt == 'u')
         username = strdup(optarg);
         fprintf(stderr, "Putting username \"%s\" in distrenslave.conf\n", username);
         conf_replace("distrenslave.conf", "!username", username);
         fprintf(stderr, "Please invoke distrenslave with no arguments to run with the username you just set\n");
         return 0;
     }

  /* Get conf data */
  options_init(argc, argv, &my_cfg, myopts, "slave", &commonopts);


  /* Notifies the user if there no username in .conf */
  if(checkUsername(username))
    return 1;

  fprintf(stderr, "Connecting to server...\n");
  if(remoteio_open(&comm_slave, commonopts->remoteio, server))
    {
      fprintf(stderr, "Error connecting to server; exiting\n");
      return 1;
    }


  // Variables needed for main loop
  int jobnum = 0;
  int framenum = 0;

  char *urltoTar;      /* Full URL to the server-side location of job#.tgz */
  char *pathtoTar;     /* Full path to the location of the job#.tgz */

  char *urltoOutput;   /* Full URL where output is posted */
  char *pathtoOutput;  /* Full path to the output (rendered) file */

  char *pathtoJobfile; /* Full path to the job's main file */
  char *pathtoXml;     /* Full path to the job's xml file */
  char *outputExt;     /* Output Extension (e.g., JPG) */

  int haveWork = 0;
  int quit = 0;

  // Main loop
  while(!quit)
    {

    // request work
    fprintf(stderr,"Requesting work...\n");
    sendSignal(comm_slave, DISTREN_REQUEST_GETWORK);

    /* If we got a frame */
    if(haveWork)
      {
        fprintf(stderr,"Got work from server...\n");
        /* @TODO: Add remotio hooks */
        // jobnum = remoteio_read(jobnum); /* Set jobnum from remoteio (we could use info from struct, but we need this info to download the xmlfile */
        // framenum = remoteio_read(jobnum); /* Set framenum from remoteio */

        fprintf(stderr, "Preparing to render frame %d in job %d\n", framenum, jobnum);

        prepareJobPaths(jobnum, datadir, &urltoTar, &pathtoTar, &pathtoJobfile, &urltoOutput, &pathtoXml);

        if(downloadTar(urltoTar, pathtoTar))
          return 1;

        unpackJob(pathtoTar, jobnum);

        /* Parses a job's XML file, puts data in the myjob struct */
        if(distrenjob_unserialize(&myjob, pathtoXml) == 0)
          {
            fprintf(stderr, "Well, the XML craziness may have worked. Maybe. \n");
            free(pathtoXml);

            /* Frees things up if it was successful. distrenjob_unserialize() really (usually) only fails if malloc'ing inside it fails */
            distrenjob_free(&myjob);
          }
        else
          {
            fprintf(stderr, "XML job data parsing has failed. Please contact a developer, or try again.\n");
            return 1;
          }

        /* Variable-fillers which require XML */
        outputExt = myjob->output_format;

        /* Prepares the path to the jobfile */
        _distren_asprintf(&pathtoOutput, "%s/job%d/output/job%d-frame%d.%s", datadir, jobnum, jobnum, framenum, outputExt );
        free(outputExt);

        /* Execute blender */
        if(exec_blender(pathtoJobfile, pathtoOutput, framenum))
          {
            fprintf(stderr,"Error running Blender. Check your installation and/or your PATH.\n");
            return 1;
          }
        free(pathtoJobfile);

        /* Post-execution */
        fprintf(stderr, "Finished frame %d in job %d, uploading...\n", framenum, jobnum);
        uploadOutput(pathtoOutput, urltoOutput); // @TODO: Handle return value

        free(urltoOutput);
        free(pathtoOutput);

        // Tell the server that rendering and upload are complete of "jobjum.framenum"
	char *jobFrame;
	_distren_asprintf(&jobFrame, "%s.%s", jobnum, framenum);
        sendExtSignal(comm_slave, DISTREN_REQUEST_DONEFRAME, jobFrame);
	free(jobFrame);
      }
    else
      fprintf(stderr,"Nothing to do. Idling...\n");

    // @TODO: If the server says that every frame for the last jobnum is finished, OR if the data is getting old
    if(1 == 0)
      {
        // Note: individual frames are already deleted after uploading,
        // except for ones that couldn't be uploaded
        delete_jobdata(jobnum, datadir);
      }

    sleep(5); // Poll 5 seconds. @TODO: Remove all polling
  }

  fprintf(stderr,"Closing connection to server...\n");
  remoteio_close(comm_slave);
  fprintf(stderr,"Goodbye!\n");
  return 0;
}