Extensions: change the constant for the complete status
[blender-addons-contrib.git] / netrender / operators.py
blobc7012b39b132d205f93946008b49be3ee1e4aaf5
1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
19 import bpy
20 import os
21 import http, http.client, http.server
22 import webbrowser
23 import json
25 import netrender
26 from netrender.utils import *
27 import netrender.client as client
28 import netrender.model
29 import netrender.versioning as versioning
31 class RENDER_OT_netclientsendbake(bpy.types.Operator):
32 """Send a baking job to the Network"""
33 bl_idname = "render.netclientsendbake"
34 bl_label = "Bake on network"
36 @classmethod
37 def poll(cls, context):
38 return True
40 def execute(self, context):
41 scene = context.scene
42 netsettings = scene.network_render
44 try:
45 conn = clientConnection(netsettings, report = self.report)
47 if conn:
48 # Sending file
49 client.sendJobBaking(conn, scene)
50 conn.close()
51 self.report({'INFO'}, "Job sent to master")
52 except Exception as err:
53 self.report({'ERROR'}, str(err))
55 return {'FINISHED'}
57 def invoke(self, context, event):
58 return self.execute(context)
60 class RENDER_OT_netclientanim(bpy.types.Operator):
61 """Start rendering an animation on network"""
62 bl_idname = "render.netclientanim"
63 bl_label = "Animation on network"
65 @classmethod
66 def poll(cls, context):
67 return True
69 def execute(self, context):
70 scene = context.scene
71 netsettings = scene.network_render
73 conn = clientConnection(netsettings, report = self.report)
75 if conn:
76 # Sending file
77 scene.network_render.job_id = client.sendJob(conn, scene, True)
78 conn.close()
80 bpy.ops.render.render('INVOKE_AREA', animation=True)
82 return {'FINISHED'}
84 def invoke(self, context, event):
85 return self.execute(context)
87 class RENDER_OT_netclientrun(bpy.types.Operator):
88 """Start network rendering service"""
89 bl_idname = "render.netclientstart"
90 bl_label = "Start Service"
92 @classmethod
93 def poll(cls, context):
94 return True
96 def execute(self, context):
97 bpy.ops.render.render('INVOKE_AREA', animation=True)
99 return {'FINISHED'}
101 def invoke(self, context, event):
102 return self.execute(context)
104 class RENDER_OT_netclientsend(bpy.types.Operator):
105 """Send Render Job to the Network"""
106 bl_idname = "render.netclientsend"
107 bl_label = "Send job"
109 @classmethod
110 def poll(cls, context):
111 return True
113 def execute(self, context):
114 scene = context.scene
115 netsettings = scene.network_render
117 try:
118 conn = clientConnection(netsettings, report = self.report)
120 if conn:
121 # Sending file
122 scene.network_render.job_id = client.sendJob(conn, scene, True)
123 conn.close()
124 self.report({'INFO'}, "Job sent to master")
125 except Exception as err:
126 self.report({'ERROR'}, str(err))
129 return {'FINISHED'}
131 def invoke(self, context, event):
132 return self.execute(context)
134 class RENDER_OT_netclientsendframe(bpy.types.Operator):
135 """Send Render Job with current frame to the Network"""
136 bl_idname = "render.netclientsendframe"
137 bl_label = "Send current frame job"
139 @classmethod
140 def poll(cls, context):
141 return True
143 def execute(self, context):
144 scene = context.scene
145 netsettings = scene.network_render
147 try:
148 conn = clientConnection(netsettings, report = self.report)
150 if conn:
151 # Sending file
152 scene.network_render.job_id = client.sendJob(conn, scene, False)
153 conn.close()
154 self.report({'INFO'}, "Job sent to master")
155 except Exception as err:
156 self.report({'ERROR'}, str(err))
159 return {'FINISHED'}
161 def invoke(self, context, event):
162 return self.execute(context)
164 class RENDER_OT_netclientstatus(bpy.types.Operator):
165 """Refresh the status of the current jobs"""
166 bl_idname = "render.netclientstatus"
167 bl_label = "Client Status"
169 @classmethod
170 def poll(cls, context):
171 return True
173 def execute(self, context):
174 netsettings = context.scene.network_render
175 conn = clientConnection(netsettings, report = self.report)
177 if conn:
178 with ConnectionContext():
179 conn.request("GET", "/status")
180 response = conn.getresponse()
181 content = response.read()
182 print( response.status, response.reason )
184 jobs = (netrender.model.RenderJob.materialize(j) for j in json.loads(str(content, encoding='utf8')))
186 while(len(netsettings.jobs) > 0):
187 netsettings.jobs.remove(0)
189 netrender.jobs = []
191 for j in jobs:
192 netrender.jobs.append(j)
193 netsettings.jobs.add()
194 job = netsettings.jobs[-1]
196 j.results = j.framesStatus() # cache frame status
198 job.name = j.name
200 return {'FINISHED'}
202 def invoke(self, context, event):
203 return self.execute(context)
205 class RENDER_OT_netclientblacklistslave(bpy.types.Operator):
206 """Exclude from rendering, by adding slave to the blacklist"""
207 bl_idname = "render.netclientblacklistslave"
208 bl_label = "Client Blacklist Slave"
210 @classmethod
211 def poll(cls, context):
212 return True
214 def execute(self, context):
215 netsettings = context.scene.network_render
217 if netsettings.active_slave_index >= 0:
219 # deal with data
220 slave = netrender.slaves.pop(netsettings.active_slave_index)
221 netrender.blacklist.append(slave)
223 # deal with rna
224 netsettings.slaves_blacklist.add()
225 netsettings.slaves_blacklist[-1].name = slave.name
227 netsettings.slaves.remove(netsettings.active_slave_index)
228 netsettings.active_slave_index = -1
230 return {'FINISHED'}
232 def invoke(self, context, event):
233 return self.execute(context)
235 class RENDER_OT_netclientwhitelistslave(bpy.types.Operator):
236 """Remove slave from the blacklist"""
237 bl_idname = "render.netclientwhitelistslave"
238 bl_label = "Client Whitelist Slave"
240 @classmethod
241 def poll(cls, context):
242 return True
244 def execute(self, context):
245 netsettings = context.scene.network_render
247 if netsettings.active_blacklisted_slave_index >= 0:
249 # deal with data
250 slave = netrender.blacklist.pop(netsettings.active_blacklisted_slave_index)
251 netrender.slaves.append(slave)
253 # deal with rna
254 netsettings.slaves.add()
255 netsettings.slaves[-1].name = slave.name
257 netsettings.slaves_blacklist.remove(netsettings.active_blacklisted_slave_index)
258 netsettings.active_blacklisted_slave_index = -1
260 return {'FINISHED'}
262 def invoke(self, context, event):
263 return self.execute(context)
266 class RENDER_OT_netclientslaves(bpy.types.Operator):
267 """Refresh status about available Render slaves"""
268 bl_idname = "render.netclientslaves"
269 bl_label = "Client Slaves"
271 @classmethod
272 def poll(cls, context):
273 return True
275 def execute(self, context):
276 netsettings = context.scene.network_render
277 conn = clientConnection(netsettings, report = self.report)
279 if conn:
280 with ConnectionContext():
281 conn.request("GET", "/slaves")
282 response = conn.getresponse()
283 content = response.read()
284 print( response.status, response.reason )
286 slaves = (netrender.model.RenderSlave.materialize(s) for s in json.loads(str(content, encoding='utf8')))
288 while(len(netsettings.slaves_blacklist) > 0):
289 netsettings.slaves_blacklist.remove(0)
291 while(len(netsettings.slaves) > 0):
292 netsettings.slaves.remove(0)
294 netrender.slaves = []
296 for s in slaves:
297 for i in range(len(netrender.blacklist)):
298 slave = netrender.blacklist[i]
299 if slave.id == s.id:
300 netrender.blacklist[i] = s
301 netsettings.slaves_blacklist.add()
302 slave = netsettings.slaves_blacklist[-1]
303 slave.name = s.name
304 break
305 else:
306 netrender.slaves.append(s)
308 netsettings.slaves.add()
309 slave = netsettings.slaves[-1]
310 slave.name = s.name
312 return {'FINISHED'}
314 def invoke(self, context, event):
315 return self.execute(context)
317 class RENDER_OT_netclientcancel(bpy.types.Operator):
318 """Cancel the selected network rendering job"""
319 bl_idname = "render.netclientcancel"
320 bl_label = "Client Cancel"
322 @classmethod
323 def poll(cls, context):
324 netsettings = context.scene.network_render
325 return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0
327 def execute(self, context):
328 netsettings = context.scene.network_render
329 conn = clientConnection(netsettings, report = self.report)
331 if conn:
332 job = netrender.jobs[netsettings.active_job_index]
334 with ConnectionContext():
335 conn.request("POST", cancelURL(job.id), json.dumps({'clear':False}))
336 response = conn.getresponse()
337 response.read()
338 print( response.status, response.reason )
340 netsettings.jobs.remove(netsettings.active_job_index)
342 return {'FINISHED'}
344 def invoke(self, context, event):
345 return self.execute(context)
347 class RENDER_OT_netclientcancelall(bpy.types.Operator):
348 """Cancel all running network rendering jobs"""
349 bl_idname = "render.netclientcancelall"
350 bl_label = "Client Cancel All"
352 @classmethod
353 def poll(cls, context):
354 return True
356 def execute(self, context):
357 netsettings = context.scene.network_render
358 conn = clientConnection(netsettings, report = self.report)
360 if conn:
361 with ConnectionContext():
362 conn.request("POST", "/clear", json.dumps({'clear':False}))
363 response = conn.getresponse()
364 response.read()
365 print( response.status, response.reason )
367 while(len(netsettings.jobs) > 0):
368 netsettings.jobs.remove(0)
370 return {'FINISHED'}
372 def invoke(self, context, event):
373 return self.execute(context)
375 class netclientdownload(bpy.types.Operator):
376 """Download render results from the network"""
377 bl_idname = "render.netclientdownload"
378 bl_label = "Client Download"
380 @classmethod
381 def poll(cls, context):
382 netsettings = context.scene.network_render
383 return netsettings.active_job_index >= 0 and len(netsettings.jobs) > netsettings.active_job_index
385 def execute(self, context):
386 netsettings = context.scene.network_render
388 conn = clientConnection(netsettings, report = self.report)
390 if conn:
391 job_id = netrender.jobs[netsettings.active_job_index].id
393 with ConnectionContext():
394 conn.request("GET", "/status", headers={"job-id":job_id})
395 response = conn.getresponse()
397 if response.status != http.client.OK:
398 self.report({'ERROR'}, "Job ID %i not defined on master" % job_id)
399 return {'ERROR'}
401 content = response.read()
403 job = netrender.model.RenderJob.materialize(json.loads(str(content, encoding='utf8')))
405 conn.close()
407 finished_frames = []
409 nb_error = 0
410 nb_missing = 0
412 for frame in job.frames:
413 if frame.status == netrender.model.FRAME_DONE:
414 finished_frames.append(frame.number)
415 elif frame.status == netrender.model.FRAME_ERROR:
416 nb_error += 1
417 else:
418 nb_missing += 1
420 if not finished_frames:
421 self.report({'ERROR'}, "Job doesn't have any finished frames")
422 return {'ERROR'}
424 frame_ranges = []
426 first = None
427 last = None
429 for i in range(len(finished_frames)):
430 current = finished_frames[i]
432 if not first:
433 first = current
434 last = current
435 elif last + 1 == current:
436 last = current
438 if last + 1 < current or i + 1 == len(finished_frames):
439 if first < last:
440 frame_ranges.append((first, last))
441 else:
442 frame_ranges.append((first,))
444 first = current
445 last = current
447 getResults(netsettings.server_address, netsettings.server_port, job_id, job.resolution[0], job.resolution[1], job.resolution[2], frame_ranges)
449 if nb_error and nb_missing:
450 self.report({'ERROR'}, "Results downloaded but skipped %i frames with errors and %i unfinished frames" % (nb_error, nb_missing))
451 elif nb_error:
452 self.report({'ERROR'}, "Results downloaded but skipped %i frames with errors" % nb_error)
453 elif nb_missing:
454 self.report({'WARNING'}, "Results downloaded but skipped %i unfinished frames" % nb_missing)
455 else:
456 self.report({'INFO'}, "All results downloaded")
458 return {'FINISHED'}
460 def invoke(self, context, event):
461 return self.execute(context)
463 class netclientscan(bpy.types.Operator):
464 """Listen on network for master server broadcasting its address and port"""
465 bl_idname = "render.netclientscan"
466 bl_label = "Client Scan"
468 @classmethod
469 def poll(cls, context):
470 return True
472 def execute(self, context):
473 address, port = clientScan(self.report)
475 if address:
476 scene = context.scene
477 netsettings = scene.network_render
478 netsettings.server_address = address
479 netsettings.server_port = port
480 netrender.valid_address = True
482 return {'FINISHED'}
484 def invoke(self, context, event):
485 return self.execute(context)
487 class netclientvcsguess(bpy.types.Operator):
488 """Guess VCS setting for the current file"""
489 bl_idname = "render.netclientvcsguess"
490 bl_label = "VCS Guess"
492 @classmethod
493 def poll(cls, context):
494 return True
496 def execute(self, context):
497 netsettings = context.scene.network_render
499 system = versioning.SYSTEMS.get(netsettings.vcs_system, None)
501 if system:
502 wpath, name = os.path.split(os.path.abspath(bpy.data.filepath))
504 rpath = system.path(wpath)
505 revision = system.revision(wpath)
507 netsettings.vcs_wpath = wpath
508 netsettings.vcs_rpath = rpath
509 netsettings.vcs_revision = revision
513 return {'FINISHED'}
515 def invoke(self, context, event):
516 return self.execute(context)
519 class netclientweb(bpy.types.Operator):
520 """Open new window with information about running rendering jobs"""
521 bl_idname = "render.netclientweb"
522 bl_label = "Open Master Monitor"
524 @classmethod
525 def poll(cls, context):
526 netsettings = context.scene.network_render
527 return netsettings.server_address != "[default]"
529 def execute(self, context):
530 netsettings = context.scene.network_render
533 # open connection to make sure server exists
534 conn = clientConnection(netsettings, report = self.report)
536 if conn:
537 conn.close()
538 if netsettings.use_ssl:
539 webbrowser.open("https://%s:%i" % (netsettings.server_address, netsettings.server_port))
540 else:
541 webbrowser.open("http://%s:%i" % (netsettings.server_address, netsettings.server_port))
542 return {'FINISHED'}
544 def invoke(self, context, event):
545 return self.execute(context)