more use of data structures for communication. begining support for more than one file per fob (external dependencies, point cache, ...)

This commit is contained in:
Martin Poirier 2009-09-01 01:09:05 +00:00
parent 47beb68a0f
commit 285d665d99
7 changed files with 223 additions and 157 deletions

@ -22,7 +22,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
def render_master(self, scene):
server_address = (scene.network_render.server_address, scene.network_render.server_port)
httpd = master.RenderMasterServer(server_address, master.RenderHandler)
httpd = master.RenderMasterServer(server_address, master.RenderHandler, scene.network_render.path)
httpd.timeout = 1
httpd.stats = self.update_stats
while not self.test_break():
@ -32,6 +32,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
slave.render_slave(self, scene)
def render_client(self, scene):
netsettings = scene.network_render
self.update_stats("", "Network render client initiation")
conn = clientConnection(scene)
@ -41,7 +42,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
self.update_stats("", "Network render exporting")
job_id = scene.network_render.job_id
job_id = netsettings.job_id
# reading back result
@ -51,10 +52,10 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
response = conn.getresponse()
if response.status == http.client.NO_CONTENT:
scene.network_render.job_id = clientSendJob(conn, scene)
netsettings.job_id = clientSendJob(conn, scene)
clientRequestResult(conn, scene, job_id)
while response.status == http.client.PROCESSING and not self.test_break():
while response.status == http.client.ACCEPTED and not self.test_break():
print("waiting")
time.sleep(1)
clientRequestResult(conn, scene, job_id)
@ -68,7 +69,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
x= int(r.resolution_x*r.resolution_percentage*0.01)
y= int(r.resolution_y*r.resolution_percentage*0.01)
f = open(PATH_PREFIX + "output.exr", "wb")
f = open(netsetting.path + "output.exr", "wb")
buf = response.read(1024)
while buf:
@ -78,7 +79,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
f.close()
result = self.begin_result(0, 0, x, y)
result.load_from_file(PATH_PREFIX + "output.exr", 0, 0)
result.load_from_file(netsettings.path + "output.exr", 0, 0)
self.end_result(result)
conn.close()

@ -9,12 +9,22 @@ JOB_WAITING = 0 # before all data has been entered
JOB_PAUSED = 1 # paused by user
JOB_QUEUED = 2 # ready to be dispatched
class MRenderFile:
def __init__(self, filepath):
self.filepath = filepath
self.found = False
def test(self):
self.found = os.path.exists(self.filepath)
return self.found
class MRenderSlave(netrender.model.RenderSlave):
def __init__(self, name, adress, stats):
def __init__(self, name, address, stats):
super().__init__()
self.id = hashlib.md5(bytes(repr(name) + repr(adress), encoding='utf8')).hexdigest()
self.id = hashlib.md5(bytes(repr(name) + repr(address), encoding='utf8')).hexdigest()
self.name = name
self.adress = adress
self.address = address
self.stats = stats
self.last_seen = time.time()
@ -31,11 +41,12 @@ def groupKey(job):
return (job.status, job.framesLeft() > 0, job.priority, job.credits)
class MRenderJob(netrender.model.RenderJob):
def __init__(self, job_id, name, path, chunks = 1, priority = 1, credits = 100.0, blacklist = []):
def __init__(self, job_id, name, files, chunks = 1, priority = 1, credits = 100.0, blacklist = []):
super().__init__()
self.id = job_id
self.name = name
self.path = path
self.files = files
self.render_files = [MRenderFile(path) for path in files]
self.status = JOB_WAITING
self.frames = []
self.chunks = chunks
@ -44,6 +55,14 @@ class MRenderJob(netrender.model.RenderJob):
self.blacklist = blacklist
self.last_dispatched = time.time()
def testStart(self):
for f in self.render_files:
if not f.test():
return False
self.start()
return True
def start(self):
self.status = JOB_QUEUED
@ -75,7 +94,7 @@ class MRenderJob(netrender.model.RenderJob):
if f.status == QUEUED:
self.update()
frames.append(f)
if len(frames) == self.chunks:
if len(frames) >= self.chunks:
break
return frames
@ -162,10 +181,10 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
if frame:
if frame.status in (QUEUED, DISPATCHED):
self.send_head(http.client.PROCESSING)
self.send_head(http.client.ACCEPTED)
elif frame.status == DONE:
self.server.stats("", "Sending result back to client")
f = open(PATH_PREFIX + job_id + "%04d" % job_frame + ".exr", 'rb')
f = open(self.server.path + job_id + "%04d" % job_frame + ".exr", 'rb')
self.send_head()
@ -173,13 +192,13 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
f.close()
elif frame.status == ERROR:
self.send_head(http.client.NO_CONTENT)
self.send_head(http.client.PARTIAL_CONTENT)
else:
# no such frame
self.send_head(http.client.NOT_FOUND)
self.send_head(http.client.NO_CONTENT)
else:
# no such job id
self.send_head(http.client.NOT_FOUND)
self.send_head(http.client.NO_CONTENT)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "log":
job_id = self.headers['job-id']
@ -194,23 +213,21 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
if frame:
if frame.status in (QUEUED, DISPATCHED):
self.send_head(http.client.PROCESSING)
elif frame.status == DONE:
else:
self.server.stats("", "Sending log back to client")
f = open(PATH_PREFIX + job_id + "%04d" % job_frame + ".log", 'rb')
f = open(self.server.path + job_id + "%04d" % job_frame + ".log", 'rb')
self.send_head()
shutil.copyfileobj(f, self.wfile)
f.close()
elif frame.status == ERROR:
self.send_head(http.client.NO_CONTENT)
else:
# no such frame
self.send_head(http.client.NOT_FOUND)
self.send_head(http.client.NO_CONTENT)
else:
# no such job id
self.send_head(http.client.NOT_FOUND)
self.send_head(http.client.NO_CONTENT)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "status":
job_id = self.headers.get('job-id', "")
@ -228,13 +245,13 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
message = frame.serialize()
else:
# no such frame
self.send_heat(http.client.NOT_FOUND)
self.send_heat(http.client.NO_CONTENT)
return
else:
message = job.serialize()
else:
# no such job id
self.send_head(http.client.NOT_FOUND)
self.send_head(http.client.NO_CONTENT)
return
else: # status of all jobs
message = []
@ -262,6 +279,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
if job and frames:
for f in frames:
print("dispatch", f.number)
f.status = DISPATCHED
f.slave = slave
@ -274,9 +292,9 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
self.server.stats("", "Sending job frame to render node")
else:
# no job available, return error code
self.send_head(http.client.NO_CONTENT)
self.send_head(http.client.ACCEPTED)
else: # invalid slave id
self.send_head(http.client.NOT_FOUND)
self.send_head(http.client.NO_CONTENT)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "file":
job_id = self.headers['job-id']
@ -288,14 +306,14 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
self.send_head(headers={"job-id": job.id})
self.server.stats("", "Sending file to render node")
f = open(PATH_PREFIX + job.id + ".blend", 'rb')
f = open(self.server.path + job.id + ".blend", 'rb')
shutil.copyfileobj(f, self.wfile)
f.close()
else:
# no such job id
self.send_head(http.client.NOT_FOUND)
self.send_head(http.client.NO_CONTENT)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "slave":
message = []
@ -322,33 +340,25 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
self.server.stats("", "Receiving job")
length = int(self.headers['content-length'])
job_frame_string = self.headers['job-frame']
job_name = self.headers.get('job-name', "")
job_chunks = int(self.headers.get('job-chunks', "1"))
blacklist = self.headers.get('slave-blacklist', '').split()
job_path = str(self.rfile.read(length), encoding='utf8')
job_info = netrender.model.RenderJob.materialize(eval(str(self.rfile.read(length), encoding='utf8')))
if os.path.exists(job_path):
job_id = self.server.nextJobID()
job_id = self.server.nextJobID()
print("chunks", job_info.chunks)
job = MRenderJob(job_id, job_info.name, job_info.files, chunks = job_info.chunks, priority = job_info.priority, blacklist = job_info.blacklist)
self.server.addJob(job)
for frame in job_info.frames:
frame = job.addFrame(frame.number)
job = MRenderJob(job_id, job_name, job_path, chunks = job_chunks, blacklist = blacklist)
self.server.addJob(job)
if ":" in job_frame_string:
frame_start, frame_end = [int(x) for x in job_frame_string.split(":")]
for job_frame in range(frame_start, frame_end + 1):
frame = job.addFrame(job_frame)
else:
job_frame = int(job_frame_string)
frame = job.addFrame(job_frame)
job.start()
self.send_head(headers={"job-id": job_id})
headers={"job-id": job_id}
if job.testStart():
self.send_head(headers=headers)
else:
self.send_head(http.client.NOT_FOUND)
self.send_head(http.client.ACCEPTED, headers=headers)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "cancel":
job_id = self.headers.get('job-id', "")
@ -375,7 +385,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
self.send_head()
else: # job not found
self.send_head(http.client.NOT_FOUND)
self.send_head(http.client.NO_CONTENT)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "slave":
length = int(self.headers['content-length'])
@ -412,7 +422,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
job_path = job_id + ".blend"
f = open(PATH_PREFIX + job_path, "wb")
f = open(self.server.path + job_path, "wb")
f.write(buf)
f.close()
del buf
@ -445,7 +455,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
if job_result == DONE:
length = int(self.headers['content-length'])
buf = self.rfile.read(length)
f = open(PATH_PREFIX + job_id + "%04d" % job_frame + ".exr", 'wb')
f = open(self.server.path + job_id + "%04d" % job_frame + ".exr", 'wb')
f.write(buf)
f.close()
@ -471,7 +481,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
print("log length:", length)
buf = self.rfile.read(length)
f = open(PATH_PREFIX + job_id + "%04d" % job_frame + ".log", 'wb')
f = open(self.server.path + job_id + "%04d" % job_frame + ".log", 'wb')
f.write(buf)
f.close()
@ -483,20 +493,21 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
class RenderMasterServer(http.server.HTTPServer):
def __init__(self, address, handler_class):
def __init__(self, address, handler_class, path):
super().__init__(address, handler_class)
self.jobs = []
self.jobs_map = {}
self.slaves = []
self.slaves_map = {}
self.job_id = 0
self.path = path
def nextJobID(self):
self.job_id += 1
return str(self.job_id)
def addSlave(self, name, adress, stats):
slave = MRenderSlave(name, adress, stats)
def addSlave(self, name, address, stats):
slave = MRenderSlave(name, address, stats)
self.slaves.append(slave)
self.slaves_map[slave.id] = slave

@ -10,7 +10,7 @@ class RenderSlave:
def __init__(self):
self.id = ""
self.name = ""
self.adress = (0,0)
self.address = (0,0)
self.stats = ""
self.total_done = 0
self.total_error = 0
@ -20,7 +20,7 @@ class RenderSlave:
return {
"id": self.id,
"name": self.name,
"adress": self.adress,
"address": self.address,
"stats": self.stats,
"total_done": self.total_done,
"total_error": self.total_error,
@ -40,7 +40,7 @@ class RenderSlave:
slave = RenderSlave()
slave.id = slave_id
slave.name = data["name"]
slave.adress = data["adress"]
slave.address = data["address"]
slave.stats = data["stats"]
slave.total_done = data["total_done"]
slave.total_error = data["total_error"]
@ -54,7 +54,7 @@ class RenderJob:
def __init__(self):
self.id = ""
self.name = ""
self.path = ""
self.files = []
self.frames = []
self.chunks = 0
self.priority = 0
@ -62,6 +62,11 @@ class RenderJob:
self.blacklist = []
self.last_dispatched = 0.0
def addFrame(self, frame_number):
frame = RenderFrame(frame_number)
self.frames.append(frame)
return frame
def __len__(self):
return len(self.frames)
@ -96,8 +101,9 @@ class RenderJob:
return {
"id": self.id,
"name": self.name,
"path": self.path,
"files": self.files,
"frames": [f.serialize() for f in self.frames if not frames or f in frames],
"chunks": self.chunks,
"priority": self.priority,
"credits": self.credits,
"blacklist": self.blacklist,
@ -112,8 +118,9 @@ class RenderJob:
job = RenderJob()
job.id = data["id"]
job.name = data["name"]
job.path = data["path"]
job.files = data["files"]
job.frames = [RenderFrame.materialize(f) for f in data["frames"]]
job.chunks = data["chunks"]
job.priority = data["priority"]
job.credits = data["credits"]
job.blacklist = data["blacklist"]
@ -122,8 +129,8 @@ class RenderJob:
return job
class RenderFrame:
def __init__(self):
self.number = 0
def __init__(self, number = 0):
self.number = number
self.time = 0
self.status = QUEUED
self.slave = None

@ -48,7 +48,7 @@ class RENDER_OT_netclientstatus(bpy.types.Operator):
return True
def execute(self, context):
netprops = context.scene.network_render
netsettings = context.scene.network_render
conn = clientConnection(context.scene)
if conn:
@ -59,12 +59,12 @@ class RENDER_OT_netclientstatus(bpy.types.Operator):
jobs = (netrender.model.RenderJob.materialize(j) for j in eval(str(response.read(), encoding='utf8')))
while(len(netprops.jobs) > 0):
netprops.jobs.remove(0)
while(len(netsettings.jobs) > 0):
netsettings.jobs.remove(0)
for j in jobs:
netprops.jobs.add()
job = netprops.jobs[-1]
netsettings.jobs.add()
job = netsettings.jobs[-1]
job_results = j.framesStatus()
@ -93,22 +93,22 @@ class RENDER_OT_netclientblacklistslave(bpy.types.Operator):
return True
def execute(self, context):
netprops = context.scene.network_render
netsettings = context.scene.network_render
if netprops.active_slave_index >= 0:
if netsettings.active_slave_index >= 0:
slave = netrender.slaves[netprops.active_slave_index]
slave = netrender.slaves[netsettings.active_slave_index]
netprops.slaves_blacklist.add()
netsettings.slaves_blacklist.add()
netprops.slaves_blacklist[-1].id = slave.id
netprops.slaves_blacklist[-1].name = slave.name
netprops.slaves_blacklist[-1].adress = slave.adress
netprops.slaves_blacklist[-1].last_seen = slave.last_seen
netprops.slaves_blacklist[-1].stats = slave.stats
netsettings.slaves_blacklist[-1].id = slave.id
netsettings.slaves_blacklist[-1].name = slave.name
netsettings.slaves_blacklist[-1].address = slave.address
netsettings.slaves_blacklist[-1].last_seen = slave.last_seen
netsettings.slaves_blacklist[-1].stats = slave.stats
netprops.slaves.remove(netprops.active_slave_index)
netprops.active_slave_index = -1
netsettings.slaves.remove(netsettings.active_slave_index)
netsettings.active_slave_index = -1
return ('FINISHED',)
@ -129,22 +129,22 @@ class RENDER_OT_netclientwhitelistslave(bpy.types.Operator):
return True
def execute(self, context):
netprops = context.scene.network_render
netsettings = context.scene.network_render
if netprops.active_blacklisted_slave_index >= 0:
if netsettings.active_blacklisted_slave_index >= 0:
slave = netprops.slaves_blacklist[netprops.active_blacklisted_slave_index]
slave = netsettings.slaves_blacklist[netsettings.active_blacklisted_slave_index]
netprops.slaves.add()
netsettings.slaves.add()
netprops.slaves[-1].id = slave.id
netprops.slaves[-1].name = slave.name
netprops.slaves[-1].adress = slave.adress
netprops.slaves[-1].last_seen = slave.last_seen
netprops.slaves[-1].stats = slave.stats
netsettings.slaves[-1].id = slave.id
netsettings.slaves[-1].name = slave.name
netsettings.slaves[-1].address = slave.address
netsettings.slaves[-1].last_seen = slave.last_seen
netsettings.slaves[-1].stats = slave.stats
netprops.slaves_blacklist.remove(netprops.active_blacklisted_slave_index)
netprops.active_blacklisted_slave_index = -1
netsettings.slaves_blacklist.remove(netsettings.active_blacklisted_slave_index)
netsettings.active_blacklisted_slave_index = -1
return ('FINISHED',)
@ -166,7 +166,7 @@ class RENDER_OT_netclientslaves(bpy.types.Operator):
return True
def execute(self, context):
netprops = context.scene.network_render
netsettings = context.scene.network_render
conn = clientConnection(context.scene)
if conn:
@ -177,21 +177,21 @@ class RENDER_OT_netclientslaves(bpy.types.Operator):
slaves = (netrender.model.RenderSlave.materialize(s) for s in eval(str(response.read(), encoding='utf8')))
while(len(netprops.slaves) > 0):
netprops.slaves.remove(0)
while(len(netsettings.slaves) > 0):
netsettings.slaves.remove(0)
for s in slaves:
for slave in netprops.slaves_blacklist:
for slave in netsettings.slaves_blacklist:
if slave.id == s.id:
break
netprops.slaves.add()
slave = netprops.slaves[-1]
netsettings.slaves.add()
slave = netsettings.slaves[-1]
slave.id = s.id
slave.name = s.name
slave.stats = s.stats
slave.adress = s.adress[0]
slave.address = s.address[0]
slave.last_seen = time.ctime(s.last_seen)
return ('FINISHED',)
@ -210,15 +210,15 @@ class RENDER_OT_netclientcancel(bpy.types.Operator):
__props__ = []
def poll(self, context):
netprops = context.scene.network_render
return netprops.active_job_index >= 0 and len(netprops.jobs) > 0
netsettings = context.scene.network_render
return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0
def execute(self, context):
netprops = context.scene.network_render
netsettings = context.scene.network_render
conn = clientConnection(context.scene)
if conn:
job = netprops.jobs[netprops.active_job_index]
job = netsettings.jobs[netsettings.active_job_index]
conn.request("POST", "cancel", headers={"job-id":job.id})

@ -21,17 +21,50 @@ def testCancel(conn, job_id):
response = conn.getresponse()
# cancelled if job isn't found anymore
if response.status == http.client.NOT_FOUND:
if response.status == http.client.NO_CONTENT:
return True
else:
return False
def render_slave(engine, scene):
NODE_PREFIX = PATH_PREFIX + "node" + os.sep
timeout = 1
def testFile(conn, JOB_PREFIX, file_path, main_path = None):
if os.path.isabs(file_path):
# if an absolute path, make sure path exists, if it doesn't, use relative local path
job_full_path = file_path
if not os.path.exists(job_full_path):
p, n = os.path.split(job_full_path)
if main_path and p.startswith(main_path):
directory = JOB_PREFIX + p[len(main_path):]
job_full_path = directory + n
if not os.path.exists(directory):
os.mkdir(directory)
else:
job_full_path = JOB_PREFIX + n
else:
job_full_path = JOB_PREFIX + file_path
if not os.path.exists(NODE_PREFIX):
os.mkdir(NODE_PREFIX)
if not os.path.exists(job_full_path):
conn.request("GET", "file", headers={"job-id": job.id, "slave-id":slave_id})
response = conn.getresponse()
if response.status != http.client.OK:
return None # file for job not returned by server, need to return an error code to server
f = open(job_full_path, "wb")
buf = response.read(1024)
while buf:
f.write(buf)
buf = response.read(1024)
f.close()
return job_full_path
def render_slave(engine, scene):
netsettings = scene.network_render
timeout = 1
engine.update_stats("", "Network render node initiation")
@ -43,6 +76,10 @@ def render_slave(engine, scene):
slave_id = response.getheader("slave-id")
NODE_PREFIX = netsettings.path + "node_" + slave_id + os.sep
if not os.path.exists(NODE_PREFIX):
os.mkdir(NODE_PREFIX)
while not engine.test_break():
conn.request("GET", "job", headers={"slave-id":slave_id})
@ -53,41 +90,30 @@ def render_slave(engine, scene):
job = netrender.model.RenderJob.materialize(eval(str(response.read(), encoding='utf8')))
print("File:", job.path)
engine.update_stats("", "Render File", job.path, "for job", job.id)
JOB_PREFIX = NODE_PREFIX + "job_" + job.id + os.sep
if not os.path.exists(JOB_PREFIX):
os.mkdir(JOB_PREFIX)
if os.path.isabs(job.path):
# if an absolute path, make sure path exists, if it doesn't, use relative local path
job_full_path = job.path
if not os.path.exists(job_full_path):
job_full_path = NODE_PREFIX + job.id + ".blend"
else:
job_full_path = NODE_PREFIX + job.path
job_path = job.files[0]
main_path, main_file = os.path.split(job_path)
if not os.path.exists(job_full_path):
conn.request("GET", "file", headers={"job-id": job.id, "slave-id":slave_id})
response = conn.getresponse()
if response.status != http.client.OK:
break # file for job not returned by server, need to return an error code to server
f = open(job_full_path, "wb")
buf = response.read(1024)
while buf:
f.write(buf)
buf = response.read(1024)
f.close()
job_full_path = testFile(conn, JOB_PREFIX, job_path)
print("Fullpath", job_full_path)
print("File:", main_file, "and %i other files" % (len(job.files) - 1,))
engine.update_stats("", "Render File", main_file, "for job", job.id)
for file_path in job.files[1:]:
testFile(conn, JOB_PREFIX, file_path, main_path)
frame_args = []
for frame in job.frames:
print("frame", frame.number)
frame_args += ["-f", str(frame.number)]
start_t = time.time()
process = subprocess.Popen([sys.argv[0], "-b", job_full_path, "-o", NODE_PREFIX + job.id, "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
process = subprocess.Popen([sys.argv[0], "-b", job_full_path, "-o", JOB_PREFIX + "######", "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
cancelled = False
stdout = bytes()
@ -120,7 +146,7 @@ def render_slave(engine, scene):
for frame in job.frames:
headers["job-frame"] = str(frame.number)
# send result back to server
f = open(NODE_PREFIX + job.id + "%04d" % frame.number + ".exr", 'rb')
f = open(JOB_PREFIX + "%06d" % frame.number + ".exr", 'rb')
conn.request("PUT", "render", f, headers=headers)
f.close()
response = conn.getresponse()

@ -48,9 +48,11 @@ class SCENE_PT_network_settings(RenderButtonsPanel):
col.itemR(scene.network_render, "mode")
col.itemR(scene.network_render, "server_address")
col.itemR(scene.network_render, "server_port")
col.itemR(scene.network_render, "path")
if scene.network_render.mode == "RENDER_CLIENT":
col.itemR(scene.network_render, "chunks")
col.itemR(scene.network_render, "priority")
col.itemR(scene.network_render, "job_name")
col.itemO("render.netclientsend", text="send job to server")
bpy.types.register(SCENE_PT_network_settings)
@ -84,7 +86,7 @@ class SCENE_PT_network_slaves(RenderButtonsPanel):
slave = netrender.slaves[netrender.active_slave_index]
layout.itemL(text="Name: " + slave.name)
layout.itemL(text="Adress: " + slave.adress)
layout.itemL(text="Address: " + slave.address)
layout.itemL(text="Seen: " + slave.last_seen)
layout.itemL(text="Stats: " + slave.stats)
@ -119,7 +121,7 @@ class SCENE_PT_network_slaves_blacklist(RenderButtonsPanel):
slave = netrender.slaves_blacklist[netrender.active_blacklisted_slave_index]
layout.itemL(text="Name: " + slave.name)
layout.itemL(text="Adress: " + slave.adress)
layout.itemL(text="Address: " + slave.address)
layout.itemL(text="Seen: " + slave.last_seen)
layout.itemL(text="Stats: " + slave.stats)
@ -189,6 +191,12 @@ NetRenderSettings.IntProperty( attr="server_port",
min=1,
max=65535)
NetRenderSettings.StringProperty( attr="path",
name="Path",
description="Path for temporary files",
maxlen = 128,
default = "/tmp/")
NetRenderSettings.StringProperty( attr="job_name",
name="Job name",
description="Name of the job",
@ -202,6 +210,13 @@ NetRenderSettings.IntProperty( attr="chunks",
min=1,
max=65535)
NetRenderSettings.IntProperty( attr="priority",
name="Priority",
description="Priority of the job",
default = 1,
min=1,
max=10)
NetRenderSettings.StringProperty( attr="job_id",
name="Network job id",
description="id of the last sent render job",
@ -249,8 +264,8 @@ NetRenderSlave.StringProperty( attr="name",
maxlen = 64,
default = "")
NetRenderSlave.StringProperty( attr="adress",
name="Adress of the slave",
NetRenderSlave.StringProperty( attr="address",
name="Address of the slave",
description="",
maxlen = 64,
default = "")

@ -3,9 +3,9 @@ import sys, os
import http, http.client, http.server, urllib
import subprocess, shutil, time, hashlib
VERSION = b"0.3"
import netrender.model
PATH_PREFIX = "/tmp/"
VERSION = b"0.3"
QUEUED = 0
DISPATCHED = 1
@ -41,40 +41,46 @@ def clientVerifyVersion(conn):
return True
def clientSendJob(conn, scene, anim = False, chunks = 5):
netsettings = scene.network_render
job = netrender.model.RenderJob()
if anim:
job_frame = "%i:%i" % (scene.start_frame, scene.end_frame)
for f in range(scene.start_frame, scene.end_frame + 1):
job.addFrame(f)
else:
job_frame = "%i" % (scene.current_frame, )
blacklist = []
job.addFrame(scene.current_frame)
filename = bpy.data.filename
job.files.append(filename)
name = scene.network_render.job_name
name = netsettings.job_name
if name == "[default]":
path, name = os.path.split(filename)
for slave in scene.network_render.slaves_blacklist:
blacklist.append(slave.id)
blacklist = " ".join(blacklist)
job.name = name
headers = {"job-frame":job_frame, "job-name":name, "job-chunks": str(chunks), "slave-blacklist": blacklist}
for slave in scene.network_render.slaves_blacklist:
job.blacklist.append(slave.id)
job.chunks = netsettings.chunks
job.priority = netsettings.priority
# try to send path first
conn.request("POST", "job", filename, headers=headers)
conn.request("POST", "job", repr(job.serialize()))
response = conn.getresponse()
job_id = response.getheader("job-id")
# if not found, send whole file
if response.status == http.client.NOT_FOUND:
f = open(bpy.data.filename, "rb")
conn.request("PUT", "file", f, headers=headers)
conn.request("PUT", "file", f, headers={"job-id": job_id})
f.close()
response = conn.getresponse()
return response.getheader("job-id")
# server will reply with NOT_FOUD until all files are found
return job_id
def clientRequestResult(conn, scene, job_id):
conn.request("GET", "render", headers={"job-id": job_id, "job-frame":str(scene.current_frame)})