/* 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 . */ #include "slavefuncs.h" #include "common/asprintf.h" #include "common/options.h" #include #include #include #include #include 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 uncomressed 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); } } // Main loop while(!quit) { // request work fprintf(stderr,"Requesting work...\n"); 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 */ 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,"Got data tarball\n"); fprintf(stderr,"Got uncompressed data!\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 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 */ fprintf(stderr,"Creating output directory %s\n", pathtoOutdir); mkdir(pathtoOutdir, 0700); fprintf(stderr,"Marking frame started on server... "); _web_startframe(slavekey, password, jobnum, framenum); /* Execute blender */ 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 */ fprintf(stderr, "Finished frame %d in job %d, uploading...\n", framenum, jobnum); 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{ fprintf(stderr,"Nothing to do. Idling...\n"); 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; }