/*
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 .
*/
#include "slavefuncs.h"
#include "common/asprintf.h"
#include "common/options.h"
#include
#include
#include
#include
#include
#define DEBUG 0
int main(int argc, char *argv[])
{
char *datadir;
char *server;
char *username;
char *password;
char *hostname;
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;
while(((char)-1) != (curopt = getopt(argc, argv, "u:th")))
{
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-t\tEnter test mode\n\t-h\tshow this help\n");
return 2;
}
else if(curopt == 't')
{
slaveTest();
return 0;
}
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);
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\n");
return 1;
}
if(!password)
{
fprintf(stderr, "password not set\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 your distrenslave.conf file appropriately\n");
return 1;
}
// Variables needed for main loop
int jobnum = 0;
int framenum = 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 *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,"DistRenSimpleSlave Pre-Alpha\n\t- this version of DistRen is still experimental\n\t so things might go horribly wrong!\n");
int benchmarkTime = 0;
int renderPower = 0;
char option[1] = "";
fprintf(stderr,"Do you want to recalculate render power? (y/n): ");
scanf("%s", option);
if(!strcmp(option, "y"))
{
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);
}
}
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);
/* 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 */
// outputExt = remotio)read(outputExt); /* Set output extension from remotio */
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);
/* // Commented for decompression
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
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, 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(300); // 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;
}