netrender: fix reload
[blender.git] / release / scripts / io / netrender / ui.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
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.
7 #
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.
12 #
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.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 import bpy
20 import sys, os
21 import http, http.client, http.server, urllib
22 import subprocess, shutil, time, hashlib
23
24 import netrender
25 import netrender.slave as slave
26 import netrender.master as master
27
28 from netrender.utils import *
29
30 VERSION = b"0.3"
31
32 PATH_PREFIX = "/tmp/"
33
34 QUEUED = 0
35 DISPATCHED = 1
36 DONE = 2
37 ERROR = 3
38
39 def init_file():
40     if netrender.init_file != bpy.data.filepath:
41         netrender.init_file = bpy.data.filepath
42         netrender.init_data = True
43         netrender.init_address = True
44
45 def init_data(netsettings):
46     init_file()
47
48     if netrender.init_data:
49         netrender.init_data = False
50
51         netsettings.active_slave_index = 0
52         while(len(netsettings.slaves) > 0):
53             netsettings.slaves.remove(0)
54
55         netsettings.active_blacklisted_slave_index = 0
56         while(len(netsettings.slaves_blacklist) > 0):
57             netsettings.slaves_blacklist.remove(0)
58
59         netsettings.active_job_index = 0
60         while(len(netsettings.jobs) > 0):
61             netsettings.jobs.remove(0)
62
63 def verify_address(netsettings):
64     init_file()
65
66     if netrender.init_address:
67         netrender.init_address = False
68
69         try:
70             conn = clientConnection(netsettings.server_address, netsettings.server_port, scan = False)
71         except:
72             conn = None
73
74         if conn:
75             conn.close()
76         else:
77             netsettings.server_address = "[default]"
78
79 class RenderButtonsPanel():
80     bl_space_type = "PROPERTIES"
81     bl_region_type = "WINDOW"
82     bl_context = "render"
83     # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
84
85     def poll(self, context):
86         rd = context.scene.render
87         return (rd.use_game_engine==False) and (rd.engine in self.COMPAT_ENGINES)
88
89 # Setting panel, use in the scene for now.
90 @rnaType
91 class RENDER_PT_network_settings(bpy.types.Panel, RenderButtonsPanel):
92     bl_label = "Network Settings"
93     COMPAT_ENGINES = {'NET_RENDER'}
94
95     def draw(self, context):
96         layout = self.layout
97
98         scene = context.scene
99         netsettings = scene.network_render
100
101         verify_address(netsettings)
102
103         layout.prop(netsettings, "mode", expand=True)
104
105         if netsettings.mode in ("RENDER_MASTER", "RENDER_SLAVE"):
106             layout.operator("render.netclientstart", icon='PLAY')
107
108         layout.prop(netsettings, "path")
109
110         split = layout.split(percentage=0.7)
111
112         col = split.column()
113         col.label(text="Server Adress:")
114         col.prop(netsettings, "server_address", text="")
115
116         col = split.column()
117         col.label(text="Port:")
118         col.prop(netsettings, "server_port", text="")
119
120         if netsettings.mode != "RENDER_MASTER":
121             layout.operator("render.netclientscan", icon='FILE_REFRESH', text="")
122
123         layout.operator("render.netclientweb", icon='QUESTION')
124
125 @rnaType
126 class RENDER_PT_network_slave_settings(bpy.types.Panel, RenderButtonsPanel):
127     bl_label = "Slave Settings"
128     COMPAT_ENGINES = {'NET_RENDER'}
129
130     def poll(self, context):
131         scene = context.scene
132         return (super().poll(context)
133                 and scene.network_render.mode == "RENDER_SLAVE")
134
135     def draw(self, context):
136         layout = self.layout
137
138         scene = context.scene
139         rd = scene.render
140         netsettings = scene.network_render
141
142         layout.prop(netsettings, "slave_clear")
143         layout.prop(netsettings, "slave_thumb")
144         layout.prop(netsettings, "slave_outputlog")
145         layout.label(text="Threads:")
146         layout.prop(rd, "threads_mode", expand=True)
147         sub = layout.column()
148         sub.enabled = rd.threads_mode == 'FIXED'
149         sub.prop(rd, "threads")
150 @rnaType
151 class RENDER_PT_network_master_settings(bpy.types.Panel, RenderButtonsPanel):
152     bl_label = "Master Settings"
153     COMPAT_ENGINES = {'NET_RENDER'}
154
155     def poll(self, context):
156         scene = context.scene
157         return (super().poll(context)
158                 and scene.network_render.mode == "RENDER_MASTER")
159
160     def draw(self, context):
161         layout = self.layout
162
163         scene = context.scene
164         netsettings = scene.network_render
165
166         layout.prop(netsettings, "master_broadcast")
167         layout.prop(netsettings, "master_clear")
168
169 @rnaType
170 class RENDER_PT_network_job(bpy.types.Panel, RenderButtonsPanel):
171     bl_label = "Job Settings"
172     COMPAT_ENGINES = {'NET_RENDER'}
173
174     def poll(self, context):
175         scene = context.scene
176         return (super().poll(context)
177                 and scene.network_render.mode == "RENDER_CLIENT")
178
179     def draw(self, context):
180         layout = self.layout
181
182         scene = context.scene
183         netsettings = scene.network_render
184
185         verify_address(netsettings)
186
187         if netsettings.server_address != "[default]":
188             layout.operator("render.netclientanim", icon='RENDER_ANIMATION')
189             layout.operator("render.netclientsend", icon='FILE_BLEND')
190             layout.operator("render.netclientsendframe", icon='RENDER_STILL')
191             if netsettings.job_id:
192                 row = layout.row()
193                 row.operator("render.render", text="Get Image", icon='RENDER_STILL')
194                 row.operator("render.render", text="Get Animation", icon='RENDER_ANIMATION').animation = True
195
196         split = layout.split(percentage=0.3)
197
198         col = split.column()
199         col.label(text="Name:")
200         col.label(text="Category:")
201
202         col = split.column()
203         col.prop(netsettings, "job_name", text="")
204         col.prop(netsettings, "job_category", text="")
205
206         row = layout.row()
207         row.prop(netsettings, "priority")
208         row.prop(netsettings, "chunks")
209
210 @rnaType
211 class RENDER_PT_network_slaves(bpy.types.Panel, RenderButtonsPanel):
212     bl_label = "Slaves Status"
213     COMPAT_ENGINES = {'NET_RENDER'}
214
215     def poll(self, context):
216         scene = context.scene
217         netsettings = scene.network_render
218         if netsettings.mode != "RENDER_CLIENT":
219             return False
220         verify_address(netsettings)
221         return (super().poll(context)
222                 and netsettings.server_address != "[default]")
223
224     def draw(self, context):
225         layout = self.layout
226
227         scene = context.scene
228         netsettings = scene.network_render
229
230         row = layout.row()
231         row.template_list(netsettings, "slaves", netsettings, "active_slave_index", rows=2)
232
233         sub = row.column(align=True)
234         sub.operator("render.netclientslaves", icon='FILE_REFRESH', text="")
235         sub.operator("render.netclientblacklistslave", icon='ZOOMOUT', text="")
236
237         init_data(netsettings)
238
239         if netsettings.active_slave_index >= 0 and len(netsettings.slaves) > 0:
240             layout.separator()
241
242             slave = netrender.slaves[netsettings.active_slave_index]
243
244             layout.label(text="Name: " + slave.name)
245             layout.label(text="Address: " + slave.address[0])
246             layout.label(text="Seen: " + time.ctime(slave.last_seen))
247             layout.label(text="Stats: " + slave.stats)
248
249 @rnaType
250 class RENDER_PT_network_slaves_blacklist(bpy.types.Panel, RenderButtonsPanel):
251     bl_label = "Slaves Blacklist"
252     COMPAT_ENGINES = {'NET_RENDER'}
253
254     def poll(self, context):
255         scene = context.scene
256         netsettings = scene.network_render
257         if netsettings.mode != "RENDER_CLIENT":
258             return False
259         verify_address(netsettings)
260         return (super().poll(context)
261                 and netsettings.server_address != "[default]")
262
263     def draw(self, context):
264         layout = self.layout
265
266         scene = context.scene
267         netsettings = scene.network_render
268
269         row = layout.row()
270         row.template_list(netsettings, "slaves_blacklist", netsettings, "active_blacklisted_slave_index", rows=2)
271
272         sub = row.column(align=True)
273         sub.operator("render.netclientwhitelistslave", icon='ZOOMOUT', text="")
274
275         init_data(netsettings)
276
277         if netsettings.active_blacklisted_slave_index >= 0 and len(netsettings.slaves_blacklist) > 0:
278             layout.separator()
279
280             slave = netrender.blacklist[netsettings.active_blacklisted_slave_index]
281
282             layout.label(text="Name: " + slave.name)
283             layout.label(text="Address: " + slave.address[0])
284             layout.label(text="Seen: " + time.ctime(slave.last_seen))
285             layout.label(text="Stats: " + slave.stats)
286
287 @rnaType
288 class RENDER_PT_network_jobs(bpy.types.Panel, RenderButtonsPanel):
289     bl_label = "Jobs"
290     COMPAT_ENGINES = {'NET_RENDER'}
291
292     def poll(self, context):
293         scene = context.scene
294         netsettings = scene.network_render
295         if netsettings.mode != "RENDER_CLIENT":
296             return False
297         verify_address(netsettings)
298         return (super().poll(context)
299                 and netsettings.server_address != "[default]")
300
301     def draw(self, context):
302         layout = self.layout
303
304         scene = context.scene
305         netsettings = scene.network_render
306
307         row = layout.row()
308         row.template_list(netsettings, "jobs", netsettings, "active_job_index", rows=2)
309
310         sub = row.column(align=True)
311         sub.operator("render.netclientstatus", icon='FILE_REFRESH', text="")
312         sub.operator("render.netclientcancel", icon='ZOOMOUT', text="")
313         sub.operator("render.netclientcancelall", icon='PANEL_CLOSE', text="")
314         sub.operator("render.netclientdownload", icon='RENDER_ANIMATION', text="")
315
316         init_data(netsettings)
317
318         if netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0:
319             layout.separator()
320
321             job = netrender.jobs[netsettings.active_job_index]
322
323             layout.label(text="Name: %s" % job.name)
324             layout.label(text="Length: %04i" % len(job))
325             layout.label(text="Done: %04i" % job.results[DONE])
326             layout.label(text="Error: %04i" % job.results[ERROR])
327
328 @rnaType
329 class NetRenderSettings(bpy.types.IDPropertyGroup):
330     pass
331
332 @rnaType
333 class NetRenderSlave(bpy.types.IDPropertyGroup):
334     pass
335
336 @rnaType
337 class NetRenderJob(bpy.types.IDPropertyGroup):
338     pass
339
340 def addProperties():
341     bpy.types.Scene.PointerProperty(attr="network_render", type=NetRenderSettings, name="Network Render", description="Network Render Settings")
342     
343     NetRenderSettings.StringProperty( attr="server_address",
344                     name="Server address",
345                     description="IP or name of the master render server",
346                     maxlen = 128,
347                     default = "[default]")
348     
349     NetRenderSettings.IntProperty( attr="server_port",
350                     name="Server port",
351                     description="port of the master render server",
352                     default = 8000,
353                     min=1,
354                     max=65535)
355     
356     NetRenderSettings.BoolProperty( attr="master_broadcast",
357                     name="Broadcast",
358                     description="broadcast master server address on local network",
359                     default = True)
360     
361     NetRenderSettings.BoolProperty( attr="slave_clear",
362                     name="Clear on exit",
363                     description="delete downloaded files on exit",
364                     default = True)
365     
366     NetRenderSettings.BoolProperty( attr="slave_thumb",
367                     name="Generate thumbnails",
368                     description="Generate thumbnails on slaves instead of master",
369                     default = False)
370     
371     NetRenderSettings.BoolProperty( attr="slave_outputlog",
372                     name="Output render log on console",
373                     description="Output render text log to console as well as sending it to the master",
374                     default = True)
375     
376     NetRenderSettings.BoolProperty( attr="master_clear",
377                     name="Clear on exit",
378                     description="delete saved files on exit",
379                     default = False)
380     
381     default_path = os.environ.get("TEMP")
382     
383     if not default_path:
384         if os.name == 'nt':
385             default_path = "c:/tmp/"
386         else:
387             default_path = "/tmp/"
388     elif not default_path.endswith(os.sep):
389         default_path += os.sep
390     
391     NetRenderSettings.StringProperty( attr="path",
392                     name="Path",
393                     description="Path for temporary files",
394                     maxlen = 128,
395                     default = default_path,
396                     subtype='FILE_PATH')
397     
398     NetRenderSettings.StringProperty( attr="job_name",
399                     name="Job name",
400                     description="Name of the job",
401                     maxlen = 128,
402                     default = "[default]")
403     
404     NetRenderSettings.StringProperty( attr="job_category",
405                     name="Job category",
406                     description="Category of the job",
407                     maxlen = 128,
408                     default = "")
409     
410     NetRenderSettings.IntProperty( attr="chunks",
411                     name="Chunks",
412                     description="Number of frame to dispatch to each slave in one chunk",
413                     default = 5,
414                     min=1,
415                     max=65535)
416     
417     NetRenderSettings.IntProperty( attr="priority",
418                     name="Priority",
419                     description="Priority of the job",
420                     default = 1,
421                     min=1,
422                     max=10)
423     
424     NetRenderSettings.StringProperty( attr="job_id",
425                     name="Network job id",
426                     description="id of the last sent render job",
427                     maxlen = 64,
428                     default = "")
429     
430     NetRenderSettings.IntProperty( attr="active_slave_index",
431                     name="Index of the active slave",
432                     description="",
433                     default = -1,
434                     min= -1,
435                     max=65535)
436     
437     NetRenderSettings.IntProperty( attr="active_blacklisted_slave_index",
438                     name="Index of the active slave",
439                     description="",
440                     default = -1,
441                     min= -1,
442                     max=65535)
443     
444     NetRenderSettings.IntProperty( attr="active_job_index",
445                     name="Index of the active job",
446                     description="",
447                     default = -1,
448                     min= -1,
449                     max=65535)
450     
451     NetRenderSettings.EnumProperty(attr="mode",
452                             items=(
453                                             ("RENDER_CLIENT", "Client", "Act as render client"),
454                                             ("RENDER_MASTER", "Master", "Act as render master"),
455                                             ("RENDER_SLAVE", "Slave", "Act as render slave"),
456                                         ),
457                             name="Network mode",
458                             description="Mode of operation of this instance",
459                             default="RENDER_CLIENT")
460     
461     NetRenderSettings.CollectionProperty(attr="slaves", type=NetRenderSlave, name="Slaves", description="")
462     NetRenderSettings.CollectionProperty(attr="slaves_blacklist", type=NetRenderSlave, name="Slaves Blacklist", description="")
463     NetRenderSettings.CollectionProperty(attr="jobs", type=NetRenderJob, name="Job List", description="")
464     
465     NetRenderSlave.StringProperty( attr="name",
466                     name="Name of the slave",
467                     description="",
468                     maxlen = 64,
469                     default = "")
470     
471     NetRenderJob.StringProperty( attr="name",
472                     name="Name of the job",
473                     description="",
474                     maxlen = 128,
475                     default = "")