diff --git a/render_renderfarmfi.py b/render_renderfarmfi.py index 38796ee0e040af0ca7a011a5162edace451da865..355d35aa84642f76f097e30a0985673081c8976e 100644 --- a/render_renderfarmfi.py +++ b/render_renderfarmfi.py @@ -21,12 +21,12 @@ DEV = False bl_info = { "name": "Renderfarm.fi", "author": "Nathan Letwory <nathan@letworyinteractive.com>, Jesse Kaukonen <jesse.kaukonen@gmail.com>", - "version": (20,), - "blender": (2, 6, 2), + "version": (21,), + "blender": (2, 6, 3), "location": "Render > Engine > Renderfarm.fi", "description": "Send .blend as session to http://www.renderfarm.fi to render", "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"\ + "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ "Scripts/Render/Renderfarm.fi", "tracker_url": "https://projects.blender.org/tracker/index.php?"\ "func=detail&aid=22927", @@ -42,9 +42,10 @@ import hashlib import http.client import xmlrpc.client import math -from os.path import isabs, isfile +from os.path import isabs, isfile, join, exists import os import time +import imp from bpy.props import PointerProperty, StringProperty, BoolProperty, EnumProperty, IntProperty, CollectionProperty @@ -53,6 +54,12 @@ bpy.found_newer_version = False bpy.up_to_date = False bpy.download_location = 'http://www.renderfarm.fi/blender' +bpy.rffi_creds_found = False +bpy.rffi_user = '' +bpy.rffi_hash = '' +bpy.passwordCorrect = False +bpy.loginInserted = False + bpy.errorMessages = { 'missing_desc': 'You need to enter a title, short and long description', 'missing_creds': 'You haven\'t entered your credentials yet' @@ -118,7 +125,6 @@ class ORESession(bpy.types.PropertyGroup): class ORESettings(bpy.types.PropertyGroup): username = StringProperty(name='E-mail', description='E-mail for Renderfarm.fi', maxlen=256, default='') password = StringProperty(name='Password', description='Renderfarm.fi password', maxlen=256, default='') - hash = StringProperty(name='Hash', description='hash calculated out of credentials', maxlen=33, default='') shortdesc = StringProperty(name='Short description', description='A short description of the scene (100 characters)', maxlen=101, default='-') tags = StringProperty(name='Tags', description='A list of tags that best suit the animation', maxlen=102, default='') @@ -139,8 +145,6 @@ class ORESettings(bpy.types.PropertyGroup): fps = IntProperty(name='FPS', description='FPS', min=1, max=120, default=25) prepared = BoolProperty(name='Prepared', description='Set to True if preparation has been run', default=False) - loginInserted = BoolProperty(name='LoginInserted', description='Set to True if user has logged in', default=False) - passwordCorrect = BoolProperty(name='PasswordCorrect', description='Set to False if the password is incorrect', default=True) debug = BoolProperty(name='Debug', description='Verbose output in console', default=False) selected_session = IntProperty(name='Selected Session', description='The selected session', default=0) hasUnsupportedSimulation = BoolProperty(name='HasSimulation', description='Set to True if therea re unsupported simulations', default=False) @@ -447,7 +451,7 @@ class RENDERFARM_MT_Session(bpy.types.Menu): layout = self.layout ore = context.scene.ore_render - if (ore.loginInserted == True): + if (bpy.loginInserted == True): layout.operator('ore.completed_sessions') layout.operator('ore.accept_sessions') layout.operator('ore.active_sessions') @@ -467,21 +471,28 @@ class LOGIN_PT_RenderfarmFi(RenderButtonsPanel, bpy.types.Panel): return (rd.use_game_engine==False) and (rd.engine in cls.COMPAT_ENGINES) def draw(self, context): + + # login + if not bpy.loginInserted: + print("trying to log in in draw()") + if _login(None, False, True): + bpy.passwordCorrect = True + bpy.loginInserted = True + layout = self.layout ore = context.scene.ore_render checkStatus(ore) - if (ore.passwordCorrect == False): + if bpy.passwordCorrect == False: row = layout.row() row.label(text="Email or password missing/incorrect", icon='ERROR') - if ore.hash=='': col = layout.column() - if ore.hash=='': - col.prop(ore, 'username', icon=bpy.statusMessage['username']) - col.prop(ore, 'password', icon=bpy.statusMessage['password']) + col.prop(ore, 'username', icon=bpy.statusMessage['username']) + col.prop(ore, 'password', icon=bpy.statusMessage['password']) layout.operator('ore.login') else: - layout.label(text='Successfully logged in', icon='INFO') + layout.label(text='Successfully logged in as:', icon='INFO') + layout.label(text=bpy.rffi_user) layout.operator('ore.change_user') class SESSIONS_PT_RenderfarmFi(RenderButtonsPanel, bpy.types.Panel): @@ -495,7 +506,7 @@ class SESSIONS_PT_RenderfarmFi(RenderButtonsPanel, bpy.types.Panel): def draw(self, context): ore = context.scene.ore_render - if (ore.passwordCorrect == True and ore.loginInserted == True): + if (bpy.passwordCorrect == True and bpy.loginInserted == True): layout = self.layout layout.template_list(ore, 'all_sessions', ore, 'selected_session', rows=5) @@ -526,7 +537,7 @@ class RENDER_PT_RenderfarmFi(RenderButtonsPanel, bpy.types.Panel): ore = sce.ore_render rd = sce.render - if (ore.passwordCorrect == False or ore.loginInserted == False): + if (bpy.passwordCorrect == False or bpy.loginInserted == False): layout.label(text='You must login first') else: layout.prop(ore, 'title', icon=bpy.statusMessage['title']) @@ -603,7 +614,7 @@ class UPLOAD_PT_RenderfarmFi(RenderButtonsPanel, bpy.types.Panel): sce = context.scene ore = sce.ore_render rd = sce.render - if (ore.passwordCorrect == False or ore.loginInserted == False): + if (bpy.passwordCorrect == False or bpy.loginInserted == False): layout.label(text="You must login first") else: if (bpy.ready): @@ -765,14 +776,12 @@ def ore_upload(op, context): bpy.context.scene.render.engine = 'RENDERFARMFI_RENDER' return {'CANCELLED'} try: - print("Creating auth proxy") - authproxy = xmlrpc.client.ServerProxy(rffi_xmlrpc_secure, verbose=DEV) - print("Getting session key") - res = authproxy.auth.getSessionKey(ore.username, ore.hash) + _read_credentials() + res = _login(op, True) key = res['key'] userid = res['userId'] print("Creating server proxy") - proxy = xmlrpc.client.ServerProxy(rffi_xmlrpc, verbose=DEV) #r'http://xmlrpc.renderfarm.fi/session') + proxy = xmlrpc.client.ServerProxy(rffi_xmlrpc, verbose=DEV) proxy._ServerProxy__transport.user_agent = 'Renderfarm.fi Uploader/%s' % (bpy.CURRENT_VERSION) print("Creating a new session") res = proxy.session.createSession(userid, key) # This may use an existing, non-rendered session. Prevents spamming in case the upload fails for some reason @@ -836,18 +845,57 @@ def showStatus(layoutform, property, message): if bpy.statusMessage[property] == 'ERROR': layoutform.label(text='', icon='ERROR') +def _write_credentials(hash, user): + with open(join(bpy.utils.user_resource('CONFIG', 'rffi', True), 'rffi_credentials.py'), 'w') as pwfile: + pwfile.write('hash=\''+hash+'\'\n') + pwfile.write('user=\''+user+'\'') + +def _read_credentials(): + bpy.rffi_creds_found = False + bpy.rffi_user = '' + bpy.rffi_hash = '' + + pwfile = bpy.utils.user_resource('CONFIG', 'rffi', True) + try: + pwmod = imp.find_module('rffi_credentials',[pwfile]) + except ImportError as e: + _write_credentials('', '') + pwmod = imp.find_module('rffi_credentials',[pwfile]) + try: + user_creds = imp.load_module('rffi_credentials', pwmod[0], pwmod[1], pwmod[2]) + bpy.rffi_user = user_creds.user + bpy.rffi_hash = user_creds.hash + bpy.rffi_creds_found = True + except ImportError as e: + # doesn't exist yet, write template + _write_credentials('', '') + pwfile = bpy.utils.user_resource('CONFIG', 'rffi', True) + pwmod = imp.find_module('rffi_credentials',[pwfile]) + try: + user_creds = imp.load_module('rffi_credentials', pwmod[0], pwmod[1], pwmod[2]) + bpy.rffi_user = user_creds.user + bpy.rffi_hash = user_creds.hash + bpy.rffi_creds_found = True + except Exception as e2: + print("Couldn't write rffi_credentials.py", e2) + finally: + if pwmod[0]: pwmod[0].close() + + return bpy.rffi_creds_found + + def checkStatus(ore): bpy.errors = [] - if ore.hash=='' and (ore.username=='' or ore.password==''): + if bpy.rffi_creds_found == False and bpy.rffi_hash == '': bpy.errors.append('missing_creds') if '' in {ore.title, ore.longdesc, ore.shortdesc}: bpy.errors.append('missing_desc') bpy.infoError = True - - setStatus('username', ore.hash=='' and ore.username=='') - setStatus('password', ore.hash=='' and ore.password=='') + + setStatus('username', bpy.rffi_hash=='' and ore.username=='') + setStatus('password', bpy.rffi_hash=='' and ore.password=='') setStatus('title', ore.title=='') setStatus('longdesc', ore.longdesc=='') @@ -874,13 +922,12 @@ class OreSession: done = 100 return done -def xmlSessionsToOreSessions(sessions, stage=None): #, queue): +def xmlSessionsToOreSessions(sessions, stage=None): output = [] for session in sessions: s = session['title'] if stage: s = s + ' (' + stage + ')' - #t = session['timestamps'] sinfo = OreSession(session['sessionId'], s) if stage in {'Completed', 'Active'}: sinfo.frames = session['framesRendered'] @@ -889,48 +936,75 @@ def xmlSessionsToOreSessions(sessions, stage=None): #, queue): output.append(sinfo) return output -def doRefresh(op, rethrow=False): +def _login(op, rethrow=False, print_errors=True): + res = None + if _read_credentials(): + try: + print("credentials read, refreshing") + proxy = xmlrpc.client.ServerProxy(rffi_xmlrpc_secure, verbose=DEV) + res = proxy.auth.getSessionKey(bpy.rffi_user, bpy.rffi_hash) + except xmlrpc.client.Error as v: + print("xmlrpc error") + if op: op.report({'WARNING'}, "Error at refresh : " + str(type(v)) + " -> " + str(v.faultCode) + ": " + v.faultString) + if print_errors: print(v) + if rethrow: + raise v + return None + except Exception as v: + print("dorefresh exception") + if op: op.report({'WARNING'}, "Non XMLRPC Error at refresh: " + str(v)) + if print_errors: print(v) + if rethrow: + raise v + return None + + return res + +def doRefresh(op, rethrow=False, print_errors=True): sce = bpy.context.scene ore = sce.ore_render - try: - - proxy = xmlrpc.client.ServerProxy(rffi_xmlrpc_secure, verbose=DEV) - res = proxy.auth.getSessionKey(ore.username, ore.hash) - userid = res['userID'] - proxy = xmlrpc.client.ServerProxy(rffi_xmlrpc, verbose=DEV) - bpy.ore_sessions = [] + if _read_credentials(): + try: + res = _login(op, True, print_errors) + proxy = xmlrpc.client.ServerProxy(rffi_xmlrpc, verbose=DEV) - sessions = proxy.session.getSessions(userid, 'accept', 0, 100, 'full') - bpy.ore_sessions = xmlSessionsToOreSessions(sessions, stage='Pending') - bpy.ore_pending_sessions = bpy.ore_sessions + bpy.ore_sessions = [] - sessions = proxy.session.getSessions(userid, 'completed', 0, 100, 'full') - bpy.ore_sessions = xmlSessionsToOreSessions(sessions, stage='Completed') - bpy.ore_completed_sessions = bpy.ore_sessions + sessions = proxy.session.getSessions(userid, 'accept', 0, 100, 'full') + bpy.ore_sessions = xmlSessionsToOreSessions(sessions, stage='Pending') + bpy.ore_pending_sessions = bpy.ore_sessions - sessions = proxy.session.getSessions(userid, 'cancelled', 0, 100, 'full') - bpy.ore_sessions = xmlSessionsToOreSessions(sessions, stage='Cancelled') - bpy.ore_cancelled_sessions = bpy.ore_sessions + sessions = proxy.session.getSessions(userid, 'completed', 0, 100, 'full') + bpy.ore_sessions = xmlSessionsToOreSessions(sessions, stage='Completed') + bpy.ore_completed_sessions = bpy.ore_sessions - sessions = proxy.session.getSessions(userid, 'render', 0, 100, 'full') - bpy.ore_sessions = xmlSessionsToOreSessions(sessions, stage='Rendering') - bpy.ore_active_sessions = bpy.ore_sessions - - updateCompleteSessionList(ore) - - return 0 - except xmlrpc.client.Error as v: - op.report({'WARNING'}, "Error at refresh : " + str(type(v)) + " -> " + str(v.faultCode) + ": " + v.faultString) - print(v) - if rethrow: - raise v - return 1 - except Exception as v: - op.report({'WARNING'}, "Non XMLRPC Error at refresh: " + str(v)) - print(v) - if rethrow: - raise v + sessions = proxy.session.getSessions(userid, 'cancelled', 0, 100, 'full') + bpy.ore_sessions = xmlSessionsToOreSessions(sessions, stage='Cancelled') + bpy.ore_cancelled_sessions = bpy.ore_sessions + + sessions = proxy.session.getSessions(userid, 'render', 0, 100, 'full') + bpy.ore_sessions = xmlSessionsToOreSessions(sessions, stage='Rendering') + bpy.ore_active_sessions = bpy.ore_sessions + + updateCompleteSessionList(ore) + + return 0 + except xmlrpc.client.Error as v: + print("xmlrpc error") + if op: op.report({'WARNING'}, "Error at refresh : " + str(type(v)) + " -> " + str(v.faultCode) + ": " + v.faultString) + if print_errors: print(v) + if rethrow: + raise v + return 1 + except Exception as v: + print("dorefresh exception") + if op: op.report({'WARNING'}, "Non XMLRPC Error at refresh: " + str(v)) + if print_errors: print(v) + if rethrow: + raise v + return 1 + else: return 1 class ORE_RefreshOp(bpy.types.Operator): @@ -993,12 +1067,13 @@ class ORE_CancelSession(bpy.types.Operator): proxy = xmlrpc.client.ServerProxy(rffi_xmlrpc_secure, verbose=DEV) if len(bpy.ore_complete_session_queue)>0: s = bpy.ore_complete_session_queue[ore.selected_session] + _read_credentials() try: - res = proxy.auth.getSessionKey(ore.username, ore.hash) + res = proxy.auth.getSessionKey(bpy.rffi_user, bpy.rffi_hash) key = res['key'] userid = res['userId'] res = proxy.session.cancelSession(userid, key, s.id) - doRefresh(self) + doRefresh(self, True) self.report({'INFO'}, 'Session ' + s.title + ' with id ' + str(s.id) + ' cancelled') except xmlrpc.client.Error as v: self.report({'ERROR'}, 'Could not cancel session ' + s.title + ' with id ' + str(s.id)) @@ -1096,22 +1171,28 @@ class ORE_LoginOp(bpy.types.Operator): ore.password = ore.password.strip() ore.username = ore.username.strip() - if ore.hash=='': - if ore.password != '' and ore.username != '': - ore.hash = hashlib.md5(ore.password.encode() + ore.username.encode()).hexdigest() - ore.password = '' - ore.loginInserted = False + if ore.password != '' and ore.username != '': + print("writing new credentials") + _write_credentials(hashlib.md5(ore.password.encode() + ore.username.encode()).hexdigest(),ore.username) + _read_credentials() + ore.password = '' + ore.username = '' + bpy.loginInserted = False + bpy.passwordCorrect = False try: doRefresh(self, True) - ore.passwordCorrect = True - ore.loginInserted = True + bpy.passwordCorrect = True + bpy.loginInserted = True except xmlrpc.client.Error as v: bpy.ready = False - ore.loginInserted = False - ore.passwordCorrect = False + bpy.loginInserted = False + bpy.passwordCorrect = False + ore.username = bpy.rffi_user + _write_credentials('', '') + _read_credentials() ore.hash = '' ore.password = '' self.report({'WARNING'}, "Incorrect login: " + v.faultString) @@ -1128,7 +1209,7 @@ class ORE_ResetOp(bpy.types.Operator): sce = context.scene ore = sce.ore_render ore.prepared = False - ore.loginInserted = False + bpy.loginInserted = False bpy.prepared = False ore.hash = '' ore.username = '' @@ -1208,10 +1289,15 @@ class ORE_ChangeUser(bpy.types.Operator): def execute(self, context): ore = context.scene.ore_render + _write_credentials('', '') + _read_credentials() ore.password = '' ore.hash = '' - ore.passwordCorrect = False - ore.loginInserted = False + bpy.rffi_user = '' + bpy.rffi_hash = '' + bpy.rffi_creds_found = False + bpy.passwordCorrect = False + bpy.loginInserted = False return {'FINISHED'} @@ -1222,23 +1308,12 @@ class RenderfarmFi(bpy.types.RenderEngine): def render(self, scene): print('Do test renders with Blender Render') - -#~ def menu_export(self, context): - #~ import os - #~ default_path = os.path.splitext(bpy.data.filepath)[0] + ".py" - #~ self.layout.operator(RenderfarmFi.bl_idname, text=RenderfarmFi.bl_label) - - def register(): bpy.utils.register_module(__name__) bpy.types.Scene.ore_render = PointerProperty(type=ORESettings, name='ORE Render', description='ORE Render Settings') - #~ bpy.types.INFO_MT_render.append(menu_export) - def unregister(): bpy.utils.unregister_module(__name__) - #~ bpy.types.INFO_MT_render.remove(menu_export) - if __name__ == "__main__": register()