Merge from trunk -r 24182:24247. Skipped change 24182 (merge of this branch into...
[blender-staging.git] / release / scripts / io / netrender / operators.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 import bpy
20 import sys, os
21 import http, http.client, http.server, urllib, socket
22 import webbrowser
23
24 from netrender.utils import *
25 import netrender.client as client
26 import netrender.model
27
28 @rnaOperator
29 class RENDER_OT_netclientanim(bpy.types.Operator):
30         '''Start rendering an animation on network'''
31         bl_idname = "render.netclientanim"
32         bl_label = "Animation on network"
33         
34         def poll(self, context):
35                 return True
36         
37         def execute(self, context):
38                 scene = context.scene
39                 
40                 conn = clientConnection(scene)
41                 
42                 if conn:
43                         # Sending file
44                         scene.network_render.job_id = client.clientSendJob(conn, scene, True)
45                         conn.close()
46                 
47                 bpy.ops.screen.render('INVOKE_AREA', animation=True)
48                 
49                 return ('FINISHED',)
50         
51         def invoke(self, context, event):
52                 return self.execute(context)
53
54 @rnaOperator
55 class RENDER_OT_netclientsend(bpy.types.Operator):
56         '''Send Render Job to the Network'''
57         bl_idname = "render.netclientsend"
58         bl_label = "Send job"
59         
60         def poll(self, context):
61                 return True
62         
63         def execute(self, context):
64                 scene = context.scene
65                 
66                 conn = clientConnection(scene)
67                 
68                 if conn:
69                         # Sending file
70                         scene.network_render.job_id = client.clientSendJob(conn, scene, True)
71                         conn.close()
72                 
73                 return ('FINISHED',)
74         
75         def invoke(self, context, event):
76                 return self.execute(context)
77
78 @rnaOperator
79 class RENDER_OT_netclientstatus(bpy.types.Operator):
80         '''Refresh the status of the current jobs'''
81         bl_idname = "render.netclientstatus"
82         bl_label = "Client Status"
83         
84         def poll(self, context):
85                 return True
86         
87         def execute(self, context):
88                 netsettings = context.scene.network_render
89                 conn = clientConnection(context.scene)
90
91                 if conn:
92                         conn.request("GET", "/status")
93                         
94                         response = conn.getresponse()
95                         print( response.status, response.reason )
96                         
97                         jobs = (netrender.model.RenderJob.materialize(j) for j in eval(str(response.read(), encoding='utf8')))
98                         
99                         while(len(netsettings.jobs) > 0):
100                                 netsettings.jobs.remove(0)
101                         
102                         bpy.netrender_jobs = []
103                         
104                         for j in jobs:
105                                 bpy.netrender_jobs.append(j)
106                                 netsettings.jobs.add()
107                                 job = netsettings.jobs[-1]
108                                 
109                                 j.results = j.framesStatus() # cache frame status
110                                 
111                                 job.name = j.name
112                 
113                 return ('FINISHED',)
114         
115         def invoke(self, context, event):
116                 return self.execute(context)
117
118 @rnaOperator
119 class RENDER_OT_netclientblacklistslave(bpy.types.Operator):
120         '''Operator documentation text, will be used for the operator tooltip and python docs.'''
121         bl_idname = "render.netclientblacklistslave"
122         bl_label = "Client Blacklist Slave"
123         
124         def poll(self, context):
125                 return True
126         
127         def execute(self, context):
128                 netsettings = context.scene.network_render
129                 
130                 if netsettings.active_slave_index >= 0:
131                         
132                         # deal with data
133                         slave = bpy.netrender_slaves.pop(netsettings.active_slave_index)
134                         bpy.netrender_blacklist.append(slave)
135                         
136                         # deal with rna
137                         netsettings.slaves_blacklist.add()
138                         netsettings.slaves_blacklist[-1].name = slave.name
139                         
140                         netsettings.slaves.remove(netsettings.active_slave_index)
141                         netsettings.active_slave_index = -1
142                 
143                 return ('FINISHED',)
144         
145         def invoke(self, context, event):
146                 return self.execute(context)
147
148 @rnaOperator
149 class RENDER_OT_netclientwhitelistslave(bpy.types.Operator):
150         '''Operator documentation text, will be used for the operator tooltip and python docs.'''
151         bl_idname = "render.netclientwhitelistslave"
152         bl_label = "Client Whitelist Slave"
153         
154         def poll(self, context):
155                 return True
156         
157         def execute(self, context):
158                 netsettings = context.scene.network_render
159                 
160                 if netsettings.active_blacklisted_slave_index >= 0:
161                         
162                         # deal with data
163                         slave = bpy.netrender_blacklist.pop(netsettings.active_blacklisted_slave_index)
164                         bpy.netrender_slaves.append(slave)
165                         
166                         # deal with rna
167                         netsettings.slaves.add()
168                         netsettings.slaves[-1].name = slave.name
169                         
170                         netsettings.slaves_blacklist.remove(netsettings.active_blacklisted_slave_index)
171                         netsettings.active_blacklisted_slave_index = -1
172                 
173                 return ('FINISHED',)
174         
175         def invoke(self, context, event):
176                 return self.execute(context)
177
178
179 @rnaOperator
180 class RENDER_OT_netclientslaves(bpy.types.Operator):
181         '''Refresh status about available Render slaves'''
182         bl_idname = "render.netclientslaves"
183         bl_label = "Client Slaves"
184         
185         def poll(self, context):
186                 return True
187         
188         def execute(self, context):
189                 netsettings = context.scene.network_render
190                 conn = clientConnection(context.scene)
191                 
192                 if conn:
193                         conn.request("GET", "/slaves")
194                         
195                         response = conn.getresponse()
196                         print( response.status, response.reason )
197                         
198                         slaves = (netrender.model.RenderSlave.materialize(s) for s in eval(str(response.read(), encoding='utf8')))
199                         
200                         while(len(netsettings.slaves) > 0):
201                                 netsettings.slaves.remove(0)
202                         
203                         bpy.netrender_slaves = []
204                         
205                         for s in slaves:
206                                 for i in range(len(bpy.netrender_blacklist)):
207                                         slave = bpy.netrender_blacklist[i]
208                                         if slave.id == s.id:
209                                                 bpy.netrender_blacklist[i] = s
210                                                 netsettings.slaves_blacklist[i].name = s.name
211                                                 break
212                                 else:
213                                         bpy.netrender_slaves.append(s)
214                                         
215                                         netsettings.slaves.add()
216                                         slave = netsettings.slaves[-1]
217                                         slave.name = s.name
218                 
219                 return ('FINISHED',)
220         
221         def invoke(self, context, event):
222                 return self.execute(context)
223
224 @rnaOperator
225 class RENDER_OT_netclientcancel(bpy.types.Operator):
226         '''Cancel the selected network rendering job.'''
227         bl_idname = "render.netclientcancel"
228         bl_label = "Client Cancel"
229         
230         def poll(self, context):
231                 netsettings = context.scene.network_render
232                 return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0
233                 
234         def execute(self, context):
235                 netsettings = context.scene.network_render
236                 conn = clientConnection(context.scene)
237                 
238                 if conn:
239                         job = bpy.netrender_jobs[netsettings.active_job_index]
240                         
241                         conn.request("POST", "/cancel", headers={"job-id":job.id})
242                         
243                         response = conn.getresponse()
244                         print( response.status, response.reason )
245
246                         netsettings.jobs.remove(netsettings.active_job_index)
247                 
248                 return ('FINISHED',)
249         
250         def invoke(self, context, event):
251                 return self.execute(context)
252         
253 @rnaOperator
254 class RENDER_OT_netclientcancelall(bpy.types.Operator):
255         '''Cancel all running network rendering jobs.'''
256         bl_idname = "render.netclientcancelall"
257         bl_label = "Client Cancel All"
258         
259         def poll(self, context):
260                 return True
261                 
262         def execute(self, context):
263                 netsettings = context.scene.network_render
264                 conn = clientConnection(context.scene)
265                 
266                 if conn:
267                         conn.request("POST", "/clear")
268                         
269                         response = conn.getresponse()
270                         print( response.status, response.reason )
271                 
272                         while(len(netsettings.jobs) > 0):
273                                 netsettings.jobs.remove(0)
274
275                 return ('FINISHED',)
276         
277         def invoke(self, context, event):
278                 return self.execute(context)
279
280 @rnaOperator
281 class netclientdownload(bpy.types.Operator):
282         '''Download render results from the network'''
283         bl_idname = "render.netclientdownload"
284         bl_label = "Client Download"
285         
286         def poll(self, context):
287                 netsettings = context.scene.network_render
288                 return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0
289                 
290         def execute(self, context):
291                 netsettings = context.scene.network_render
292                 rd = context.scene.render_data
293                 
294                 conn = clientConnection(context.scene)
295                 
296                 if conn:
297                         job = bpy.netrender_jobs[netsettings.active_job_index]
298                         
299                         for frame in job.frames:
300                                 client.requestResult(conn, job.id, frame.number)
301                                 response = conn.getresponse()
302                 
303                                 if response.status != http.client.OK:
304                                         print("missing", frame.number)
305                                         continue
306                                 
307                                 print("got back", frame.number)
308                                 
309                                 f = open(netsettings.path + "%06d" % frame.number + ".exr", "wb")
310                                 buf = response.read(1024)
311                                 
312                                 while buf:
313                                         f.write(buf)
314                                         buf = response.read(1024)
315                                 
316                                 f.close()
317                         
318                         conn.close()
319                 
320                 return ('FINISHED',)
321         
322         def invoke(self, context, event):
323                 return self.execute(context)
324
325 @rnaOperator
326 class netclientscan(bpy.types.Operator):
327         '''Operator documentation text, will be used for the operator tooltip and python docs.'''
328         bl_idname = "render.netclientscan"
329         bl_label = "Client Scan"
330         
331         def poll(self, context):
332                 return True
333                 
334         def execute(self, context):
335                 netsettings = context.scene.network_render
336                 
337                 try:
338                         s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
339                         s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
340                         s.settimeout(30)
341         
342                         s.bind(('', 8000))
343                         
344                         buf, address = s.recvfrom(64)
345                         
346                         print("received:", buf)
347                         
348                         netsettings.server_address = address[0]
349                         netsettings.server_port = int(str(buf, encoding='utf8'))
350                 except socket.timeout:
351                         print("no server info")
352                 
353                 return ('FINISHED',)
354         
355         def invoke(self, context, event):
356                 return self.execute(context)
357
358 @rnaOperator
359 class netclientweb(bpy.types.Operator):
360         '''Open new window with information about running rendering jobs'''
361         bl_idname = "render.netclientweb"
362         bl_label = "Open Master Monitor"
363         
364         def poll(self, context):
365                 return True
366                 
367         def execute(self, context):
368                 netsettings = context.scene.network_render
369                 
370                 
371                 # open connection to make sure server exists
372                 conn = clientConnection(context.scene)
373                 
374                 if conn:
375                         conn.close()
376                         
377                         webbrowser.open("http://%s:%i" % (netsettings.server_address, netsettings.server_port))
378                 
379                 return ('FINISHED',)
380         
381         def invoke(self, context, event):
382                 return self.execute(context)