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 #####
21 import http
, http
.client
, http
.server
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"
37 def poll(cls
, context
):
40 def execute(self
, context
):
42 netsettings
= scene
.network_render
45 conn
= clientConnection(netsettings
, report
= self
.report
)
49 client
.sendJobBaking(conn
, scene
)
51 self
.report({'INFO'}, "Job sent to master")
52 except Exception as err
:
53 self
.report({'ERROR'}, str(err
))
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"
66 def poll(cls
, context
):
69 def execute(self
, context
):
71 netsettings
= scene
.network_render
73 conn
= clientConnection(netsettings
, report
= self
.report
)
77 scene
.network_render
.job_id
= client
.sendJob(conn
, scene
, True)
80 bpy
.ops
.render
.render('INVOKE_AREA', animation
=True)
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"
93 def poll(cls
, context
):
96 def execute(self
, context
):
97 bpy
.ops
.render
.render('INVOKE_AREA', animation
=True)
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"
110 def poll(cls
, context
):
113 def execute(self
, context
):
114 scene
= context
.scene
115 netsettings
= scene
.network_render
118 conn
= clientConnection(netsettings
, report
= self
.report
)
122 scene
.network_render
.job_id
= client
.sendJob(conn
, scene
, True)
124 self
.report({'INFO'}, "Job sent to master")
125 except Exception as err
:
126 self
.report({'ERROR'}, str(err
))
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"
140 def poll(cls
, context
):
143 def execute(self
, context
):
144 scene
= context
.scene
145 netsettings
= scene
.network_render
148 conn
= clientConnection(netsettings
, report
= self
.report
)
152 scene
.network_render
.job_id
= client
.sendJob(conn
, scene
, False)
154 self
.report({'INFO'}, "Job sent to master")
155 except Exception as err
:
156 self
.report({'ERROR'}, str(err
))
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"
170 def poll(cls
, context
):
173 def execute(self
, context
):
174 netsettings
= context
.scene
.network_render
175 conn
= clientConnection(netsettings
, report
= self
.report
)
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)
192 netrender
.jobs
.append(j
)
193 netsettings
.jobs
.add()
194 job
= netsettings
.jobs
[-1]
196 j
.results
= j
.framesStatus() # cache frame status
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"
211 def poll(cls
, context
):
214 def execute(self
, context
):
215 netsettings
= context
.scene
.network_render
217 if netsettings
.active_slave_index
>= 0:
220 slave
= netrender
.slaves
.pop(netsettings
.active_slave_index
)
221 netrender
.blacklist
.append(slave
)
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
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"
241 def poll(cls
, context
):
244 def execute(self
, context
):
245 netsettings
= context
.scene
.network_render
247 if netsettings
.active_blacklisted_slave_index
>= 0:
250 slave
= netrender
.blacklist
.pop(netsettings
.active_blacklisted_slave_index
)
251 netrender
.slaves
.append(slave
)
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
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"
272 def poll(cls
, context
):
275 def execute(self
, context
):
276 netsettings
= context
.scene
.network_render
277 conn
= clientConnection(netsettings
, report
= self
.report
)
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
= []
297 for i
in range(len(netrender
.blacklist
)):
298 slave
= netrender
.blacklist
[i
]
300 netrender
.blacklist
[i
] = s
301 netsettings
.slaves_blacklist
.add()
302 slave
= netsettings
.slaves_blacklist
[-1]
306 netrender
.slaves
.append(s
)
308 netsettings
.slaves
.add()
309 slave
= netsettings
.slaves
[-1]
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"
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
)
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()
338 print( response
.status
, response
.reason
)
340 netsettings
.jobs
.remove(netsettings
.active_job_index
)
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"
353 def poll(cls
, context
):
356 def execute(self
, context
):
357 netsettings
= context
.scene
.network_render
358 conn
= clientConnection(netsettings
, report
= self
.report
)
361 with
ConnectionContext():
362 conn
.request("POST", "/clear", json
.dumps({'clear':False}))
363 response
= conn
.getresponse()
365 print( response
.status
, response
.reason
)
367 while(len(netsettings
.jobs
) > 0):
368 netsettings
.jobs
.remove(0)
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"
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
)
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
)
401 content
= response
.read()
403 job
= netrender
.model
.RenderJob
.materialize(json
.loads(str(content
, encoding
='utf8')))
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
:
420 if not finished_frames
:
421 self
.report({'ERROR'}, "Job doesn't have any finished frames")
429 for i
in range(len(finished_frames
)):
430 current
= finished_frames
[i
]
435 elif last
+ 1 == current
:
438 if last
+ 1 < current
or i
+ 1 == len(finished_frames
):
440 frame_ranges
.append((first
, last
))
442 frame_ranges
.append((first
,))
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
))
452 self
.report({'ERROR'}, "Results downloaded but skipped %i frames with errors" % nb_error
)
454 self
.report({'WARNING'}, "Results downloaded but skipped %i unfinished frames" % nb_missing
)
456 self
.report({'INFO'}, "All results downloaded")
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"
469 def poll(cls
, context
):
472 def execute(self
, context
):
473 address
, port
= clientScan(self
.report
)
476 scene
= context
.scene
477 netsettings
= scene
.network_render
478 netsettings
.server_address
= address
479 netsettings
.server_port
= port
480 netrender
.valid_address
= True
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"
493 def poll(cls
, context
):
496 def execute(self
, context
):
497 netsettings
= context
.scene
.network_render
499 system
= versioning
.SYSTEMS
.get(netsettings
.vcs_system
, None)
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
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"
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
)
538 if netsettings
.use_ssl
:
539 webbrowser
.open("https://%s:%i" % (netsettings
.server_address
, netsettings
.server_port
))
541 webbrowser
.open("http://%s:%i" % (netsettings
.server_address
, netsettings
.server_port
))
544 def invoke(self
, context
, event
):
545 return self
.execute(context
)