Files @ d231345767d5
Branch filter:

Location: DistRen/src/server/simpleslave.c - annotation

ethanzonca
Added output extension and resolution support in render calls and _web calls, breaks slave.c
3c5489e556ae
abcf8952747b
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
92659c5651ef
92659c5651ef
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
d10a3b76be5c
b6511767dab2
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
7d056f57c29a
3c5489e556ae
7d056f57c29a
ef03a563218c
ef03a563218c
3c5489e556ae
3c5489e556ae
7d056f57c29a
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
7d056f57c29a
1478394cbd10
3c5489e556ae
3c5489e556ae
536058b6e341
cb26ccfc122d
ef03a563218c
3c5489e556ae
cb26ccfc122d
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
cb26ccfc122d
3c5489e556ae
3c5489e556ae
536058b6e341
3c5489e556ae
536058b6e341
536058b6e341
3c5489e556ae
cb26ccfc122d
3c5489e556ae
cb26ccfc122d
cb26ccfc122d
cb26ccfc122d
cb26ccfc122d
cb26ccfc122d
cb26ccfc122d
3c5489e556ae
3c5489e556ae
cb26ccfc122d
cb26ccfc122d
cb26ccfc122d
cb26ccfc122d
cb26ccfc122d
cb26ccfc122d
cb26ccfc122d
cb26ccfc122d
cb26ccfc122d
cb26ccfc122d
cb26ccfc122d
3c5489e556ae
ef03a563218c
3c5489e556ae
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
cb26ccfc122d
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
cb26ccfc122d
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
3c5489e556ae
3c5489e556ae
3c5489e556ae
4ec01e2efee7
7d056f57c29a
cb26ccfc122d
7d056f57c29a
7d056f57c29a
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
d231345767d5
d231345767d5
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
6331e72e3889
3c5489e556ae
b6511767dab2
0e43edb16f3f
78516a1d1aee
3c5489e556ae
3c5489e556ae
df7e1f917a6d
78516a1d1aee
3c5489e556ae
0e43edb16f3f
4ec01e2efee7
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
536058b6e341
d0f64b1f3376
930f5ea4c9a5
930f5ea4c9a5
d0f64b1f3376
d0f64b1f3376
195048ceb561
536058b6e341
536058b6e341
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
1478394cbd10
536058b6e341
1478394cbd10
195048ceb561
536058b6e341
e129dd8d5b5c
8c97631a877d
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
e129dd8d5b5c
e129dd8d5b5c
d231345767d5
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
8c97631a877d
e129dd8d5b5c
e129dd8d5b5c
3c5489e556ae
78516a1d1aee
6331e72e3889
6331e72e3889
0e43edb16f3f
0e43edb16f3f
4e072ce1165f
e129dd8d5b5c
0307f7fcc410
0307f7fcc410
4e072ce1165f
0307f7fcc410
e0266092c553
e129dd8d5b5c
0e43edb16f3f
0e43edb16f3f
3c5489e556ae
0e43edb16f3f
6331e72e3889
930f5ea4c9a5
6331e72e3889
6331e72e3889
6331e72e3889
6331e72e3889
0307f7fcc410
0307f7fcc410
0e43edb16f3f
6331e72e3889
0307f7fcc410
dae3ac7c3173
dae3ac7c3173
dae3ac7c3173
6331e72e3889
930f5ea4c9a5
930f5ea4c9a5
930f5ea4c9a5
930f5ea4c9a5
930f5ea4c9a5
930f5ea4c9a5
930f5ea4c9a5
930f5ea4c9a5
930f5ea4c9a5
930f5ea4c9a5
930f5ea4c9a5
3c5489e556ae
df7e1f917a6d
e129dd8d5b5c
e129dd8d5b5c
df7e1f917a6d
e129dd8d5b5c
e129dd8d5b5c
e129dd8d5b5c
df7e1f917a6d
4ec01e2efee7
df7e1f917a6d
e129dd8d5b5c
e129dd8d5b5c
e129dd8d5b5c
e129dd8d5b5c
d231345767d5
3c5489e556ae
3c5489e556ae
0307f7fcc410
3c5489e556ae
3c5489e556ae
3c5489e556ae
7f610e2808f2
3c5489e556ae
df7e1f917a6d
df7e1f917a6d
df7e1f917a6d
78516a1d1aee
0307f7fcc410
df7e1f917a6d
df7e1f917a6d
df7e1f917a6d
df7e1f917a6d
e129dd8d5b5c
e129dd8d5b5c
e129dd8d5b5c
e129dd8d5b5c
df7e1f917a6d
3c5489e556ae
df7e1f917a6d
df7e1f917a6d
7f610e2808f2
7f610e2808f2
df7e1f917a6d
df7e1f917a6d
df7e1f917a6d
3c5489e556ae
4f1cbf0f8f32
e129dd8d5b5c
e129dd8d5b5c
e129dd8d5b5c
e129dd8d5b5c
9cf7971fa223
4f1cbf0f8f32
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
3c5489e556ae
7f610e2808f2
7f610e2808f2
7f610e2808f2
7f610e2808f2
7f610e2808f2
7f610e2808f2
7f610e2808f2
7f610e2808f2
7f610e2808f2
7f610e2808f2
7f610e2808f2
7f610e2808f2
3c5489e556ae
3c5489e556ae
3c5489e556ae
/*
  Copyright 2010 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 "common/config.h"

#include "slavefuncs.h"

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

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

#define DEBUG 0


int main(int argc, char *argv[])
{
  char *datadir;
  char *server;
  char *username;
  char *password;
  char *hostname;

  multiio_context_t multiio;

  cfg_opt_t myopts[] = {
    CFG_SIMPLE_STR("username", &username),
    CFG_SIMPLE_STR("password", &password),
    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;

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

  char curopt;
  int runBenchmark = 0;
  int updateConf = 0;
  multiio = multiio_context_new();

  while(((char)-1) != (curopt = getopt(argc, argv, "u:p:rh")))
     {
       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: distrensimpleslave [option] \nStarts a distren slave\n\t-u\tset Slave ID/Username (run after fresh install)\n\t-p\tset Slave Passphrase (run after fresh install)\n\t-r\tRecalculate render power (benchmark)\n\t-h\tshow this help\n");
           return 2;
         }
       else if(curopt == 'r')
         {
           runBenchmark = 1;
           break;
         }
       else if(curopt == 'u'){
         username = strdup(optarg);
         updateConf = 1;
       }
       else if(curopt == 'p'){
         password = strdup(optarg);
         updateConf = 1;
       }
     }

if(updateConf){
  if(DEBUG)
    fprintf(stderr, "Putting Slave ID \"%s\" and Slave Passphrase \"%s\" in distrenslave.conf\n", username, password);
  if(username != NULL)
    conf_replace("distrenslave.conf", "!username", username);
  if(password != NULL)
    conf_replace("distrenslave.conf", "!password", password);

  fprintf(stderr, "Please invoke distrensimpleslave with no arguments to run with the slave ID and/or passphrase you just set\n");
  return 0;
}
  /* Get conf data */
 options_init(argc, argv, &my_cfg, myopts, "slave", &commonopts, multiio);

  if(!datadir)
    {
      fprintf(stderr, "datadir not set\n");
      return 1;
    }
  if(!server)
    {
      fprintf(stderr, "server not set\n");
      return 1;
    }
  if(!username)
    {
      fprintf(stderr, "username not set, try the -u flag \n");
      return 1;
    }
  if(!password)
    {
      fprintf(stderr, "password not set, try the -p flag\n");
      return 1;
    }
  if(!hostname)
    {
      fprintf(stderr, "hostname not set\n");
      return 1;
    }

  
  /* Notifies the user if there no username in .conf */
  if(checkUsername(username))
    return 1;
  if(!strncmp(password, "!password",10))
    {
      fprintf(stderr, "You haven't specified a password. Please edit distrenslave.conf or try the -p flag!\n");
      return 1;
    }

  // Variables needed for main loop
  int jobnum = 0;
  int framenum = 0;
  int xres = 0;
  int yres = 0;
  int slavekey = atoi(username); // @TODO: Make this more friendly

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

  // Temporary for uncompressed testing
  // char *urltoJobfile;

  char *urltoOutput;   /* Full URL where output is posted */
  char *pathtoOutput;  /* Full path to the output (rendered) file */
  char *pathtoOutdir;  /* Full path to output directory */
  char *pathtoRenderOutput; /* Contains blender framenum placeholder */

  char *urltoJobfile; /* Used if we aren't using compression */
  char *pathtoJob; /* Path to job data folder */
  char *pathtoJobfile; /* Full path to the job's main file */
  char *outputExt = "jpg";     /* Output Extension (e.g., JPG) */

  int haveWork = 0;
  int quit = 0;

  fprintf(stderr,"\nDistRen SimpleSlave Pre-Alpha %s\n- Experimental build: Use at your own risk!\n\n", PACKAGE_VERSION);

  /* @TODO @FIXME create datadir (/var/distren/) if it doesn't exist, or notify the user */

  int benchmarkTime = 0;
  int renderPower = 0;

  // @TODO: create _web function to force recalc if !isset($render_power) on server
  if(runBenchmark)
    {
      if(slaveBenchmark(datadir, &benchmarkTime, &renderPower))
	{
	  fprintf(stderr,"Benchmark failed! Exiting.\n");
	  return 1;
	}
      else
	{
	  fprintf(stderr,"Benchmark successful, time taken was %d seconds, giving you a render power of %d.\n",
		  benchmarkTime, renderPower);
	  _web_setrenderpower(slavekey, password, renderPower);
	  return 0;
	}
    }

  if(!DEBUG)
    fprintf(stderr, "Running...");
  // Main loop
  while(!quit)
    {

    // request work
    if(DEBUG)
      fprintf(stderr,"Requesting work from %s...\n", hostname);
    haveWork = _web_getwork(slavekey, password, &jobnum, &framenum, &xres, &yres, outputExt);

    /* If we got a frame */
    if(haveWork)
      {
        fprintf(stderr,"\nGot work from server...\n");
        if(DEBUG)
          fprintf(stderr, "Preparing to render frame %d in job %d\n", framenum, jobnum);

        prepareJobPaths(jobnum, framenum, outputExt, datadir, &urltoTar, &pathtoTar, &pathtoTardir, &pathtoJob, &pathtoJobfile, &urltoJobfile, &urltoOutput, &pathtoOutput, &pathtoRenderOutput, &pathtoOutdir);
        //free(outputExt);
        mkdir(pathtoTardir, 0700);
        int dlret = downloadTar(urltoTar, pathtoTar);
        //int dlret = downloadTar(urltoJobfile, pathtoJobfile);
        if(dlret == 0)
          fprintf(stderr,"Data retrieved successfully!\n");
        else if(dlret == 3){
          _web_resetframe(slavekey, password, jobnum, framenum);  // Unassign the frame on the server so other slaves can render it
          return 0; // ouput dir doesn't exist
        }
        else
          if(DEBUG)
            //fprintf(stderr,"Using existing uncompressed data %s...\n", pathtoJobfile);
            fprintf(stderr,"Using existing tarball %s...\n", pathtoTar);

        // Check if tar exists already
        struct stat jbuffer;
        int jstatus = stat(pathtoJobfile, &jbuffer);
        if(jstatus == -1){
          fprintf(stderr,"Main job file does not exist, extracting...\n");

          // If error unpacking tarball
          if(unpackJob(pathtoJob, pathtoTar)){
            _web_resetframe(slavekey, password, jobnum, framenum);  // Unassign the frame on the server so other slaves can render it
            fprintf(stderr,"Extraction failed, exiting.\n");
            return 1;
          }
	  else
	    if(DEBUG)
              fprintf(stderr,"Whatever happened in the unpackjob() function supposedly worked.\n");
        }
	else{
	  if(DEBUG)
	    fprintf(stderr,"Using already extracted data.\n");
        }

        struct stat tbuffer;
        int tstatus = stat(pathtoJobfile, &tbuffer);
	if(tstatus == -1){
          fprintf(stderr,"The main job file does not exist! Data may be corrupt, or the archive is malformatted.\n");
          return 1;
        }

        /* ignore return because directory may exist already */
        if(DEBUG)
          fprintf(stderr,"Creating output directory %s\n", pathtoOutdir);
        mkdir(pathtoOutdir, 0700);

        if(DEBUG)
          fprintf(stderr,"Marking frame started on server... ");
        _web_startframe(slavekey, password, jobnum, framenum);

        /* Execute blender */
        if(DEBUG){
          fprintf(stderr,"Executing blender on file %s\n", pathtoJobfile);
          fprintf(stderr,"Directing output to file %s\n", pathtoOutput);
        }
        if(exec_blender(pathtoJobfile, pathtoRenderOutput, outputExt, xres, yres, framenum))
          {
            fprintf(stderr,"Error running Blender. Check your installation and/or your PATH.\n");
            _web_resetframe(slavekey, password, jobnum, framenum);  // Unassign the frame on the server so other slaves can render it
            return 1;
          }
        free(pathtoJobfile);
        pathtoJobfile = NULL;

        struct stat buffer;
        int fstatus = stat(pathtoOutput, &buffer);
        if(fstatus == -1){
          fprintf(stderr,"*** %s doesn't exist! Scene may not have camera, or your blender installation is not working.\n", pathtoOutput);
          _web_resetframe(slavekey, password, jobnum, framenum);  // Unassign the frame on the server so other slaves can render it
          return 1;
        }
        else{
          /* Post-execution */
          if(DEBUG)
            fprintf(stderr, "Finished frame %d in job %d, uploading...\n", framenum, jobnum);
          else
            fprintf(stderr,"Finished.\n");
          uploadOutput(pathtoOutput, urltoOutput, jobnum, framenum, slavekey); // @TODO: Handle return value

          free(urltoOutput);
          free(pathtoOutput);
          urltoOutput = NULL;
          pathtoOutput = NULL;
          // Tell the server that rendering and upload are complete
          _web_finishframe(slavekey, password, jobnum, framenum);
        }
      }
    else{
      if(DEBUG)
        fprintf(stderr,"No work to do. Idling...\n");
      else
        fprintf(stderr,".");
      sleep(60); // Poll every 300 seconds @TODO: remove polling
    }

    // @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);
      }
  }

  free(my_cfg);
  free(outputExt);
  free(datadir);
  free(urltoTar);
  free(pathtoTar);
  free(pathtoTardir);
  free(pathtoJob);
  free(pathtoJobfile);
  free(urltoJobfile);
  free(urltoOutput);
  free(pathtoRenderOutput);
  free(pathtoOutdir);
  fprintf(stderr,"Goodbye!\n");
  return 0;
}