2009-08-29 17:25:22 +00:00
|
|
|
import sys, os
|
|
|
|
import http, http.client, http.server, urllib
|
|
|
|
import subprocess, shutil, time, hashlib
|
|
|
|
|
|
|
|
from netrender.utils import *
|
|
|
|
import netrender.model
|
|
|
|
|
2009-08-30 02:40:42 +00:00
|
|
|
JOB_WAITING = 0 # before all data has been entered
|
|
|
|
JOB_PAUSED = 1 # paused by user
|
|
|
|
JOB_QUEUED = 2 # ready to be dispatched
|
|
|
|
|
2009-09-01 01:09:05 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2009-08-29 17:25:22 +00:00
|
|
|
class MRenderSlave(netrender.model.RenderSlave):
|
2009-09-01 01:09:05 +00:00
|
|
|
def __init__(self, name, address, stats):
|
2009-08-29 17:25:22 +00:00
|
|
|
super().__init__()
|
2009-09-01 01:09:05 +00:00
|
|
|
self.id = hashlib.md5(bytes(repr(name) + repr(address), encoding='utf8')).hexdigest()
|
2009-08-29 17:25:22 +00:00
|
|
|
self.name = name
|
2009-09-01 01:09:05 +00:00
|
|
|
self.address = address
|
2009-08-29 17:25:22 +00:00
|
|
|
self.stats = stats
|
|
|
|
self.last_seen = time.time()
|
|
|
|
|
|
|
|
self.job = None
|
|
|
|
self.frame = None
|
|
|
|
|
|
|
|
netrender.model.RenderSlave._slave_map[self.id] = self
|
|
|
|
|
|
|
|
def seen(self):
|
|
|
|
self.last_seen = time.time()
|
|
|
|
|
|
|
|
# sorting key for jobs
|
|
|
|
def groupKey(job):
|
2009-08-30 02:40:42 +00:00
|
|
|
return (job.status, job.framesLeft() > 0, job.priority, job.credits)
|
2009-08-29 17:25:22 +00:00
|
|
|
|
|
|
|
class MRenderJob(netrender.model.RenderJob):
|
2009-09-01 01:09:05 +00:00
|
|
|
def __init__(self, job_id, name, files, chunks = 1, priority = 1, credits = 100.0, blacklist = []):
|
2009-08-29 17:25:22 +00:00
|
|
|
super().__init__()
|
|
|
|
self.id = job_id
|
|
|
|
self.name = name
|
2009-09-01 01:09:05 +00:00
|
|
|
self.files = files
|
2009-08-29 17:25:22 +00:00
|
|
|
self.frames = []
|
|
|
|
self.chunks = chunks
|
|
|
|
self.priority = priority
|
|
|
|
self.credits = credits
|
|
|
|
self.blacklist = blacklist
|
|
|
|
self.last_dispatched = time.time()
|
|
|
|
|
2009-09-02 00:07:55 +00:00
|
|
|
# special server properties
|
|
|
|
self.save_path = ""
|
|
|
|
self.files_map = {path: MRenderFile(path) for path in files}
|
|
|
|
self.status = JOB_WAITING
|
|
|
|
|
|
|
|
def save(self):
|
|
|
|
if self.save_path:
|
|
|
|
f = open(self.save_path + "job.txt", "w")
|
|
|
|
f.write(repr(self.serialize()))
|
|
|
|
f.close()
|
|
|
|
|
2009-09-01 01:09:05 +00:00
|
|
|
def testStart(self):
|
2009-09-02 00:07:55 +00:00
|
|
|
for f in self.files_map.values():
|
2009-09-01 01:09:05 +00:00
|
|
|
if not f.test():
|
|
|
|
return False
|
|
|
|
|
|
|
|
self.start()
|
|
|
|
return True
|
|
|
|
|
2009-08-30 02:40:42 +00:00
|
|
|
def start(self):
|
|
|
|
self.status = JOB_QUEUED
|
|
|
|
|
2009-08-29 17:25:22 +00:00
|
|
|
def update(self):
|
|
|
|
self.credits -= 5 # cost of one frame
|
|
|
|
self.credits += (time.time() - self.last_dispatched) / 60
|
|
|
|
self.last_dispatched = time.time()
|
|
|
|
|
|
|
|
def addFrame(self, frame_number):
|
|
|
|
frame = MRenderFrame(frame_number)
|
|
|
|
self.frames.append(frame)
|
|
|
|
return frame
|
|
|
|
|
|
|
|
def framesLeft(self):
|
|
|
|
total = 0
|
|
|
|
for j in self.frames:
|
|
|
|
if j.status == QUEUED:
|
|
|
|
total += 1
|
|
|
|
|
|
|
|
return total
|
|
|
|
|
|
|
|
def reset(self, all):
|
|
|
|
for f in self.frames:
|
|
|
|
f.reset(all)
|
|
|
|
|
|
|
|
def getFrames(self):
|
|
|
|
frames = []
|
|
|
|
for f in self.frames:
|
|
|
|
if f.status == QUEUED:
|
|
|
|
self.update()
|
|
|
|
frames.append(f)
|
2009-09-01 01:09:05 +00:00
|
|
|
if len(frames) >= self.chunks:
|
2009-08-29 17:25:22 +00:00
|
|
|
break
|
|
|
|
|
|
|
|
return frames
|
|
|
|
|
|
|
|
class MRenderFrame(netrender.model.RenderFrame):
|
|
|
|
def __init__(self, frame):
|
|
|
|
super().__init__()
|
|
|
|
self.number = frame
|
|
|
|
self.slave = None
|
|
|
|
self.time = 0
|
|
|
|
self.status = QUEUED
|
|
|
|
|
|
|
|
def reset(self, all):
|
|
|
|
if all or self.status == ERROR:
|
|
|
|
self.slave = None
|
|
|
|
self.time = 0
|
|
|
|
self.status = QUEUED
|
|
|
|
|
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
|
|
|
|
class RenderHandler(http.server.BaseHTTPRequestHandler):
|
|
|
|
def send_head(self, code = http.client.OK, headers = {}):
|
|
|
|
self.send_response(code)
|
|
|
|
self.send_header("Content-type", "application/octet-stream")
|
|
|
|
|
|
|
|
for key, value in headers.items():
|
|
|
|
self.send_header(key, value)
|
|
|
|
|
|
|
|
self.end_headers()
|
|
|
|
|
|
|
|
def do_HEAD(self):
|
|
|
|
print(self.path)
|
|
|
|
|
|
|
|
if self.path == "status":
|
|
|
|
job_id = self.headers.get('job-id', "")
|
|
|
|
job_frame = int(self.headers.get('job-frame', -1))
|
|
|
|
|
|
|
|
if job_id:
|
|
|
|
print("status:", job_id, "\n")
|
|
|
|
|
|
|
|
job = self.server.getJobByID(job_id)
|
|
|
|
if job:
|
|
|
|
if job_frame != -1:
|
|
|
|
frame = job[frame]
|
|
|
|
|
|
|
|
if not frame:
|
|
|
|
# no such frame
|
|
|
|
self.send_heat(http.client.NOT_FOUND)
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
# no such job id
|
|
|
|
self.send_head(http.client.NOT_FOUND)
|
|
|
|
return
|
|
|
|
|
|
|
|
self.send_head()
|
|
|
|
|
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
|
|
|
|
def do_GET(self):
|
|
|
|
print(self.path)
|
|
|
|
|
|
|
|
if self.path == "version":
|
|
|
|
self.send_head()
|
|
|
|
self.server.stats("", "New client connection")
|
|
|
|
self.wfile.write(VERSION)
|
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
elif self.path == "render":
|
|
|
|
job_id = self.headers['job-id']
|
|
|
|
job_frame = int(self.headers['job-frame'])
|
|
|
|
print("render:", job_id, job_frame)
|
|
|
|
|
|
|
|
job = self.server.getJobByID(job_id)
|
|
|
|
|
|
|
|
if job:
|
|
|
|
frame = job[job_frame]
|
|
|
|
|
|
|
|
if frame:
|
|
|
|
if frame.status in (QUEUED, DISPATCHED):
|
2009-09-01 01:09:05 +00:00
|
|
|
self.send_head(http.client.ACCEPTED)
|
2009-08-29 17:25:22 +00:00
|
|
|
elif frame.status == DONE:
|
|
|
|
self.server.stats("", "Sending result back to client")
|
2009-09-02 00:07:55 +00:00
|
|
|
f = open(job.save_path + "%04d" % job_frame + ".exr", 'rb')
|
2009-08-29 17:25:22 +00:00
|
|
|
|
|
|
|
self.send_head()
|
|
|
|
|
|
|
|
shutil.copyfileobj(f, self.wfile)
|
|
|
|
|
|
|
|
f.close()
|
|
|
|
elif frame.status == ERROR:
|
2009-09-01 01:09:05 +00:00
|
|
|
self.send_head(http.client.PARTIAL_CONTENT)
|
2009-08-29 17:25:22 +00:00
|
|
|
else:
|
|
|
|
# no such frame
|
2009-09-01 01:09:05 +00:00
|
|
|
self.send_head(http.client.NO_CONTENT)
|
2009-08-29 17:25:22 +00:00
|
|
|
else:
|
|
|
|
# no such job id
|
2009-09-01 01:09:05 +00:00
|
|
|
self.send_head(http.client.NO_CONTENT)
|
2009-08-29 17:25:22 +00:00
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
elif self.path == "log":
|
|
|
|
job_id = self.headers['job-id']
|
|
|
|
job_frame = int(self.headers['job-frame'])
|
|
|
|
print("log:", job_id, job_frame)
|
|
|
|
|
|
|
|
job = self.server.getJobByID(job_id)
|
|
|
|
|
|
|
|
if job:
|
|
|
|
frame = job[job_frame]
|
|
|
|
|
|
|
|
if frame:
|
|
|
|
if frame.status in (QUEUED, DISPATCHED):
|
|
|
|
self.send_head(http.client.PROCESSING)
|
2009-09-01 01:09:05 +00:00
|
|
|
else:
|
2009-08-29 17:25:22 +00:00
|
|
|
self.server.stats("", "Sending log back to client")
|
2009-09-02 00:07:55 +00:00
|
|
|
f = open(job.save_path + "%04d" % job_frame + ".log", 'rb')
|
2009-08-29 17:25:22 +00:00
|
|
|
|
|
|
|
self.send_head()
|
|
|
|
|
|
|
|
shutil.copyfileobj(f, self.wfile)
|
|
|
|
|
|
|
|
f.close()
|
|
|
|
else:
|
|
|
|
# no such frame
|
2009-09-01 01:09:05 +00:00
|
|
|
self.send_head(http.client.NO_CONTENT)
|
2009-08-29 17:25:22 +00:00
|
|
|
else:
|
|
|
|
# no such job id
|
2009-09-01 01:09:05 +00:00
|
|
|
self.send_head(http.client.NO_CONTENT)
|
2009-08-29 17:25:22 +00:00
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
elif self.path == "status":
|
|
|
|
job_id = self.headers.get('job-id', "")
|
|
|
|
job_frame = int(self.headers.get('job-frame', -1))
|
|
|
|
|
|
|
|
if job_id:
|
|
|
|
print("status:", job_id, "\n")
|
|
|
|
|
|
|
|
job = self.server.getJobByID(job_id)
|
|
|
|
if job:
|
|
|
|
if job_frame != -1:
|
|
|
|
frame = job[frame]
|
|
|
|
|
|
|
|
if frame:
|
|
|
|
message = frame.serialize()
|
|
|
|
else:
|
|
|
|
# no such frame
|
2009-09-01 01:09:05 +00:00
|
|
|
self.send_heat(http.client.NO_CONTENT)
|
2009-08-29 17:25:22 +00:00
|
|
|
return
|
|
|
|
else:
|
|
|
|
message = job.serialize()
|
|
|
|
else:
|
|
|
|
# no such job id
|
2009-09-01 01:09:05 +00:00
|
|
|
self.send_head(http.client.NO_CONTENT)
|
2009-08-29 17:25:22 +00:00
|
|
|
return
|
|
|
|
else: # status of all jobs
|
|
|
|
message = []
|
|
|
|
|
|
|
|
for job in self.server:
|
|
|
|
message.append(job.serialize())
|
|
|
|
|
|
|
|
self.send_head()
|
|
|
|
self.wfile.write(bytes(repr(message), encoding='utf8'))
|
|
|
|
|
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
elif self.path == "job":
|
|
|
|
self.server.update()
|
|
|
|
|
|
|
|
slave_id = self.headers['slave-id']
|
|
|
|
|
|
|
|
print("slave-id", slave_id)
|
|
|
|
|
|
|
|
slave = self.server.updateSlave(slave_id)
|
|
|
|
|
|
|
|
if slave: # only if slave id is valid
|
|
|
|
job, frames = self.server.getNewJob(slave_id)
|
|
|
|
|
|
|
|
if job and frames:
|
|
|
|
for f in frames:
|
2009-09-01 01:09:05 +00:00
|
|
|
print("dispatch", f.number)
|
2009-08-29 17:25:22 +00:00
|
|
|
f.status = DISPATCHED
|
|
|
|
f.slave = slave
|
|
|
|
|
|
|
|
self.send_head(headers={"job-id": job.id})
|
|
|
|
|
|
|
|
message = job.serialize(frames)
|
|
|
|
|
|
|
|
self.wfile.write(bytes(repr(message), encoding='utf8'))
|
|
|
|
|
|
|
|
self.server.stats("", "Sending job frame to render node")
|
|
|
|
else:
|
|
|
|
# no job available, return error code
|
2009-09-01 01:09:05 +00:00
|
|
|
self.send_head(http.client.ACCEPTED)
|
2009-08-29 17:25:22 +00:00
|
|
|
else: # invalid slave id
|
2009-09-01 01:09:05 +00:00
|
|
|
self.send_head(http.client.NO_CONTENT)
|
2009-08-29 17:25:22 +00:00
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
elif self.path == "file":
|
2009-09-02 00:07:55 +00:00
|
|
|
slave_id = self.headers['slave-id']
|
2009-08-29 17:25:22 +00:00
|
|
|
|
2009-09-02 00:07:55 +00:00
|
|
|
slave = self.server.updateSlave(slave_id)
|
2009-08-29 17:25:22 +00:00
|
|
|
|
2009-09-02 00:07:55 +00:00
|
|
|
if slave: # only if slave id is valid
|
|
|
|
job_id = self.headers['job-id']
|
|
|
|
job_file = self.headers['job-file']
|
|
|
|
print("job:", job_id, "\n")
|
|
|
|
print("file:", job_file, "\n")
|
2009-08-29 17:25:22 +00:00
|
|
|
|
2009-09-02 00:07:55 +00:00
|
|
|
job = self.server.getJobByID(job_id)
|
2009-08-29 17:25:22 +00:00
|
|
|
|
2009-09-02 00:07:55 +00:00
|
|
|
if job:
|
|
|
|
render_file = job.files_map.get(job_file, None)
|
|
|
|
|
|
|
|
if render_file:
|
|
|
|
self.server.stats("", "Sending file to render node")
|
|
|
|
f = open(render_file.path, 'rb')
|
|
|
|
|
|
|
|
shutil.copyfileobj(f, self.wfile)
|
|
|
|
|
|
|
|
f.close()
|
|
|
|
else:
|
|
|
|
# no such file
|
|
|
|
self.send_head(http.client.NO_CONTENT)
|
|
|
|
else:
|
|
|
|
# no such job id
|
|
|
|
self.send_head(http.client.NO_CONTENT)
|
|
|
|
else: # invalid slave id
|
2009-09-01 01:09:05 +00:00
|
|
|
self.send_head(http.client.NO_CONTENT)
|
2009-08-29 17:25:22 +00:00
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
elif self.path == "slave":
|
|
|
|
message = []
|
|
|
|
|
|
|
|
for slave in self.server.slaves:
|
|
|
|
message.append(slave.serialize())
|
|
|
|
|
|
|
|
self.send_head()
|
|
|
|
|
|
|
|
self.wfile.write(bytes(repr(message), encoding='utf8'))
|
|
|
|
|
|
|
|
|
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
def do_POST(self):
|
|
|
|
print(self.path)
|
|
|
|
|
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
if self.path == "job":
|
|
|
|
print("posting job info")
|
|
|
|
self.server.stats("", "Receiving job")
|
|
|
|
|
|
|
|
length = int(self.headers['content-length'])
|
|
|
|
|
2009-09-01 01:09:05 +00:00
|
|
|
job_info = netrender.model.RenderJob.materialize(eval(str(self.rfile.read(length), encoding='utf8')))
|
2009-08-29 17:25:22 +00:00
|
|
|
|
2009-09-01 01:09:05 +00:00
|
|
|
job_id = self.server.nextJobID()
|
|
|
|
|
2009-09-02 00:07:55 +00:00
|
|
|
print(job_info.files)
|
2009-09-01 01:09:05 +00:00
|
|
|
|
|
|
|
job = MRenderJob(job_id, job_info.name, job_info.files, chunks = job_info.chunks, priority = job_info.priority, blacklist = job_info.blacklist)
|
|
|
|
|
|
|
|
for frame in job_info.frames:
|
|
|
|
frame = job.addFrame(frame.number)
|
2009-09-02 00:07:55 +00:00
|
|
|
|
|
|
|
self.server.addJob(job)
|
|
|
|
|
2009-09-01 01:09:05 +00:00
|
|
|
headers={"job-id": job_id}
|
|
|
|
|
|
|
|
if job.testStart():
|
|
|
|
self.send_head(headers=headers)
|
2009-08-29 17:25:22 +00:00
|
|
|
else:
|
2009-09-01 01:09:05 +00:00
|
|
|
self.send_head(http.client.ACCEPTED, headers=headers)
|
2009-08-29 17:25:22 +00:00
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
elif self.path == "cancel":
|
|
|
|
job_id = self.headers.get('job-id', "")
|
|
|
|
if job_id:
|
|
|
|
print("cancel:", job_id, "\n")
|
|
|
|
self.server.removeJob(job_id)
|
|
|
|
else: # cancel all jobs
|
|
|
|
self.server.clear()
|
|
|
|
|
|
|
|
self.send_head()
|
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
elif self.path == "reset":
|
|
|
|
job_id = self.headers.get('job-id', "")
|
|
|
|
job_frame = int(self.headers.get('job-frame', "-1"))
|
|
|
|
all = bool(self.headers.get('reset-all', "False"))
|
|
|
|
|
|
|
|
job = self.server.getJobByID(job_id)
|
|
|
|
|
|
|
|
if job:
|
|
|
|
if job_frame != -1:
|
|
|
|
job[job_frame].reset(all)
|
|
|
|
else:
|
|
|
|
job.reset(all)
|
|
|
|
|
|
|
|
self.send_head()
|
|
|
|
else: # job not found
|
2009-09-01 01:09:05 +00:00
|
|
|
self.send_head(http.client.NO_CONTENT)
|
2009-08-29 17:25:22 +00:00
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
elif self.path == "slave":
|
|
|
|
length = int(self.headers['content-length'])
|
|
|
|
job_frame_string = self.headers['job-frame']
|
|
|
|
|
2009-08-30 02:40:42 +00:00
|
|
|
slave_info = netrender.model.RenderSlave.materialize(eval(str(self.rfile.read(length), encoding='utf8')))
|
2009-08-29 17:25:22 +00:00
|
|
|
|
2009-08-30 02:40:42 +00:00
|
|
|
slave_id = self.server.addSlave(slave_info.name, self.client_address, slave_info.stats)
|
2009-08-29 17:25:22 +00:00
|
|
|
|
|
|
|
self.send_head(headers = {"slave-id": slave_id})
|
|
|
|
|
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
def do_PUT(self):
|
|
|
|
print(self.path)
|
|
|
|
|
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
if self.path == "file":
|
|
|
|
print("writing blend file")
|
|
|
|
self.server.stats("", "Receiving job")
|
|
|
|
|
|
|
|
length = int(self.headers['content-length'])
|
2009-09-02 00:07:55 +00:00
|
|
|
job_id = self.headers['job-id']
|
|
|
|
job_file = self.headers['job-file']
|
2009-08-29 17:25:22 +00:00
|
|
|
|
2009-09-02 00:07:55 +00:00
|
|
|
job = self.server.getJobByID(job_id)
|
2009-08-29 17:25:22 +00:00
|
|
|
|
2009-09-02 00:07:55 +00:00
|
|
|
if job:
|
2009-08-29 17:25:22 +00:00
|
|
|
|
2009-09-02 00:07:55 +00:00
|
|
|
render_file = job.files_map.get(job_file, None)
|
2009-08-29 17:25:22 +00:00
|
|
|
|
2009-09-02 00:07:55 +00:00
|
|
|
if render_file:
|
|
|
|
main_file = job.files[0]
|
|
|
|
|
|
|
|
main_path, main_name = os.path.split(main_file)
|
|
|
|
|
|
|
|
if job_file != main_file:
|
|
|
|
file_path = prefixPath(job.save_path, job_file, main_path)
|
|
|
|
else:
|
|
|
|
file_path = job.save_path + main_name
|
|
|
|
|
|
|
|
buf = self.rfile.read(length)
|
|
|
|
|
|
|
|
f = open(file_path, "wb")
|
|
|
|
f.write(buf)
|
|
|
|
f.close()
|
|
|
|
del buf
|
|
|
|
|
|
|
|
render_file.path = file_path # set the new path
|
|
|
|
|
|
|
|
if job.testStart():
|
|
|
|
self.send_head(headers=headers)
|
|
|
|
else:
|
|
|
|
self.send_head(http.client.ACCEPTED, headers=headers)
|
|
|
|
else: # invalid file
|
|
|
|
self.send_head(http.client.NO_CONTENT)
|
|
|
|
else: # job not found
|
|
|
|
self.send_head(http.client.NO_CONTENT)
|
2009-08-29 17:25:22 +00:00
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
elif self.path == "render":
|
|
|
|
print("writing result file")
|
|
|
|
self.server.stats("", "Receiving render result")
|
|
|
|
|
|
|
|
job_id = self.headers['job-id']
|
|
|
|
|
|
|
|
job = self.server.getJobByID(job_id)
|
|
|
|
|
2009-09-02 00:07:55 +00:00
|
|
|
if job:
|
|
|
|
job_frame = int(self.headers['job-frame'])
|
|
|
|
job_result = int(self.headers['job-result'])
|
|
|
|
job_time = float(self.headers['job-time'])
|
|
|
|
|
|
|
|
if job_result == DONE:
|
|
|
|
length = int(self.headers['content-length'])
|
|
|
|
buf = self.rfile.read(length)
|
|
|
|
f = open(job.save_path + "%04d" % job_frame + ".exr", 'wb')
|
|
|
|
f.write(buf)
|
|
|
|
f.close()
|
|
|
|
|
|
|
|
del buf
|
|
|
|
|
|
|
|
job = self.server.getJobByID(job_id)
|
|
|
|
frame = job[job_frame]
|
|
|
|
frame.status = job_result
|
|
|
|
frame.time = job_time
|
|
|
|
|
|
|
|
self.server.updateSlave(self.headers['slave-id'])
|
|
|
|
|
|
|
|
self.send_head()
|
|
|
|
else: # job not found
|
|
|
|
self.send_head(http.client.NO_CONTENT)
|
2009-08-29 17:25:22 +00:00
|
|
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
elif self.path == "log":
|
|
|
|
print("writing log file")
|
|
|
|
self.server.stats("", "Receiving log file")
|
|
|
|
|
|
|
|
job_id = self.headers['job-id']
|
|
|
|
|
2009-09-02 00:07:55 +00:00
|
|
|
job = self.server.getJobByID(job_id)
|
2009-08-29 17:25:22 +00:00
|
|
|
|
2009-09-02 00:07:55 +00:00
|
|
|
if job:
|
|
|
|
length = int(self.headers['content-length'])
|
|
|
|
job_frame = int(self.headers['job-frame'])
|
2009-08-29 17:25:22 +00:00
|
|
|
|
2009-09-02 00:07:55 +00:00
|
|
|
buf = self.rfile.read(length)
|
|
|
|
f = open(job.save_path + "%04d" % job_frame + ".log", 'wb')
|
|
|
|
f.write(buf)
|
|
|
|
f.close()
|
|
|
|
|
|
|
|
del buf
|
|
|
|
|
|
|
|
self.server.updateSlave(self.headers['slave-id'])
|
|
|
|
|
|
|
|
self.send_head()
|
|
|
|
else: # job not found
|
|
|
|
self.send_head(http.client.NO_CONTENT)
|
2009-08-29 17:25:22 +00:00
|
|
|
|
|
|
|
class RenderMasterServer(http.server.HTTPServer):
|
2009-09-01 01:09:05 +00:00
|
|
|
def __init__(self, address, handler_class, path):
|
2009-08-29 17:25:22 +00:00
|
|
|
super().__init__(address, handler_class)
|
|
|
|
self.jobs = []
|
|
|
|
self.jobs_map = {}
|
|
|
|
self.slaves = []
|
|
|
|
self.slaves_map = {}
|
2009-08-30 02:40:42 +00:00
|
|
|
self.job_id = 0
|
2009-09-02 00:07:55 +00:00
|
|
|
self.path = path + "master_" + str(os.getpid()) + os.sep
|
|
|
|
|
|
|
|
if not os.path.exists(self.path):
|
|
|
|
os.mkdir(self.path)
|
2009-08-30 02:40:42 +00:00
|
|
|
|
|
|
|
def nextJobID(self):
|
|
|
|
self.job_id += 1
|
|
|
|
return str(self.job_id)
|
2009-08-29 17:25:22 +00:00
|
|
|
|
2009-09-01 01:09:05 +00:00
|
|
|
def addSlave(self, name, address, stats):
|
|
|
|
slave = MRenderSlave(name, address, stats)
|
2009-08-29 17:25:22 +00:00
|
|
|
self.slaves.append(slave)
|
|
|
|
self.slaves_map[slave.id] = slave
|
|
|
|
|
|
|
|
return slave.id
|
|
|
|
|
|
|
|
def getSlave(self, slave_id):
|
|
|
|
return self.slaves_map.get(slave_id, None)
|
|
|
|
|
|
|
|
def updateSlave(self, slave_id):
|
|
|
|
slave = self.getSlave(slave_id)
|
|
|
|
if slave:
|
|
|
|
slave.seen()
|
|
|
|
|
|
|
|
return slave
|
|
|
|
|
|
|
|
def clear(self):
|
|
|
|
self.jobs_map = {}
|
|
|
|
self.jobs = []
|
|
|
|
|
|
|
|
def update(self):
|
|
|
|
self.jobs.sort(key = groupKey)
|
|
|
|
|
|
|
|
def removeJob(self, id):
|
|
|
|
job = self.jobs_map.pop(id)
|
|
|
|
|
|
|
|
if job:
|
|
|
|
self.jobs.remove(job)
|
|
|
|
|
|
|
|
def addJob(self, job):
|
|
|
|
self.jobs.append(job)
|
|
|
|
self.jobs_map[job.id] = job
|
2009-09-02 00:07:55 +00:00
|
|
|
|
|
|
|
# create job directory
|
|
|
|
job.save_path = self.path + "job_" + job.id + os.sep
|
|
|
|
if not os.path.exists(job.save_path):
|
|
|
|
os.mkdir(job.save_path)
|
|
|
|
|
|
|
|
job.save()
|
2009-08-29 17:25:22 +00:00
|
|
|
|
|
|
|
def getJobByID(self, id):
|
|
|
|
return self.jobs_map.get(id, None)
|
|
|
|
|
|
|
|
def __iter__(self):
|
|
|
|
for job in self.jobs:
|
|
|
|
yield job
|
|
|
|
|
|
|
|
def getNewJob(self, slave_id):
|
|
|
|
if self.jobs:
|
|
|
|
for job in reversed(self.jobs):
|
2009-08-30 02:40:42 +00:00
|
|
|
if job.status == JOB_QUEUED and job.framesLeft() > 0 and slave_id not in job.blacklist:
|
2009-08-29 17:25:22 +00:00
|
|
|
return job, job.getFrames()
|
|
|
|
|
|
|
|
return None, None
|