netrender

Display job status in web interface
Better use of Reports api for errors and success notifications
Don't show some Client options if server address is default (hasn't been scanned or entered manually yet)
This commit is contained in:
2009-12-16 21:00:25 +00:00
parent c3401eb5cb
commit 383f29ff37
6 changed files with 108 additions and 57 deletions

View File

@@ -67,11 +67,13 @@ class MRenderJob(netrender.model.RenderJob):
if self.type == netrender.model.JOB_PROCESS:
self.chunks = 1
# Force WAITING status on creation
self.status = JOB_WAITING
# special server properties
self.last_update = 0
self.save_path = ""
self.files = [MRenderFile(rfile.filepath, rfile.index, rfile.start, rfile.end) for rfile in job_info.files]
self.status = JOB_WAITING
def save(self):
if self.save_path:

View File

@@ -94,6 +94,7 @@ def get(handler):
"priority",
"usage",
"wait",
"status",
"length",
"done",
"dispatched",
@@ -114,6 +115,7 @@ def get(handler):
job.priority,
"%0.1f%%" % (job.usage * 100),
"%is" % int(time.time() - job.last_dispatched),
job.statusText(),
len(job),
results[DONE],
results[DISPATCHED],

View File

@@ -132,6 +132,7 @@ class RenderJob:
self.type = JOB_BLENDER
self.name = ""
self.category = "None"
self.status = JOB_WAITING
self.files = []
self.chunks = 0
self.priority = 0
@@ -145,6 +146,7 @@ class RenderJob:
self.type = job_info.type
self.name = job_info.name
self.category = job_info.category
self.status = job_info.status
self.files = job_info.files
self.chunks = job_info.chunks
self.priority = job_info.priority
@@ -172,6 +174,9 @@ class RenderJob:
def countSlaves(self):
return len(set((frame.slave for frame in self.frames if frame.status == DISPATCHED)))
def statusText(self):
return JOB_STATUS_TEXT[self.status]
def framesStatus(self):
results = {
QUEUED: 0,
@@ -207,6 +212,7 @@ class RenderJob:
"type": self.type,
"name": self.name,
"category": self.category,
"status": self.status,
"files": [f.serialize() for f in self.files if f.start == -1 or not frames or (f.start <= max_frame and f.end >= min_frame)],
"frames": [f.serialize() for f in self.frames if not frames or f in frames],
"chunks": self.chunks,
@@ -226,6 +232,7 @@ class RenderJob:
job.type = data["type"]
job.name = data["name"]
job.category = data["category"]
job.status = data["status"]
job.files = [RenderFile.materialize(f) for f in data["files"]]
job.frames = [RenderFrame.materialize(f) for f in data["frames"]]
job.chunks = data["chunks"]
@@ -245,7 +252,7 @@ class RenderFrame:
self.command = command
def statusText(self):
return STATUS_TEXT[self.status]
return FRAME_STATUS_TEXT[self.status]
def serialize(self):
return {

View File

@@ -97,15 +97,12 @@ class RENDER_OT_netclientanim(bpy.types.Operator):
scene = context.scene
netsettings = scene.network_render
try:
conn = clientConnection(netsettings.server_address, netsettings.server_port)
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
# Sending file
scene.network_render.job_id = client.clientSendJob(conn, scene, True)
conn.close()
except Exception as err:
self.report('ERROR', str(err))
conn = None
bpy.ops.screen.render('INVOKE_AREA', animation=True)
@@ -128,12 +125,13 @@ class RENDER_OT_netclientsend(bpy.types.Operator):
netsettings = scene.network_render
try:
conn = clientConnection(netsettings.server_address, netsettings.server_port)
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
# Sending file
scene.network_render.job_id = client.clientSendJob(conn, scene, True)
conn.close()
self.report('INFO', "Job sent to master")
if conn:
# Sending file
scene.network_render.job_id = client.clientSendJob(conn, scene, True)
conn.close()
self.report('INFO', "Job sent to master")
except Exception as err:
self.report('ERROR', str(err))
@@ -154,7 +152,7 @@ class RENDER_OT_netclientstatus(bpy.types.Operator):
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port)
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
conn.request("GET", "/status")
@@ -255,7 +253,7 @@ class RENDER_OT_netclientslaves(bpy.types.Operator):
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port)
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
conn.request("GET", "/slaves")
@@ -301,7 +299,7 @@ class RENDER_OT_netclientcancel(bpy.types.Operator):
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port)
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
job = netrender.jobs[netsettings.active_job_index]
@@ -329,7 +327,7 @@ class RENDER_OT_netclientcancelall(bpy.types.Operator):
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port)
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
conn.request("POST", "/clear")
@@ -359,7 +357,7 @@ class netclientdownload(bpy.types.Operator):
netsettings = context.scene.network_render
rd = context.scene.render_data
conn = clientConnection(netsettings.server_address, netsettings.server_port)
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
job = netrender.jobs[netsettings.active_job_index]
@@ -400,7 +398,7 @@ class netclientscan(bpy.types.Operator):
return True
def execute(self, context):
address, port = clientScan()
address, port = clientScan(self.report)
if address:
scene = context.scene
@@ -427,7 +425,7 @@ class netclientweb(bpy.types.Operator):
# open connection to make sure server exists
conn = clientConnection(netsettings.server_address, netsettings.server_port)
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
conn.close()

View File

@@ -85,7 +85,8 @@ class RENDER_PT_network_job(RenderButtonsPanel):
def poll(self, context):
scene = context.scene
return super().poll(context) and scene.network_render.mode == "RENDER_CLIENT"
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT")
def draw(self, context):
layout = self.layout
@@ -98,9 +99,10 @@ class RENDER_PT_network_job(RenderButtonsPanel):
split = layout.split()
col = split.column()
col.operator("render.netclientanim", icon='RENDER_ANIMATION')
col.operator("render.netclientsend", icon='FILE_BLEND')
col.operator("render.netclientweb", icon='QUESTION')
if scene.network_render.server_address != "[default]":
col.operator("render.netclientanim", icon='RENDER_ANIMATION')
col.operator("render.netclientsend", icon='FILE_BLEND')
col.operator("render.netclientweb", icon='QUESTION')
col.prop(scene.network_render, "job_name")
col.prop(scene.network_render, "job_category")
row = col.row()
@@ -114,7 +116,9 @@ class RENDER_PT_network_slaves(RenderButtonsPanel):
def poll(self, context):
scene = context.scene
return super().poll(context) and scene.network_render.mode == "RENDER_CLIENT"
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT"
and scene.network_render.server_address != "[default]")
def draw(self, context):
layout = self.layout
@@ -150,7 +154,9 @@ class RENDER_PT_network_slaves_blacklist(RenderButtonsPanel):
def poll(self, context):
scene = context.scene
return super().poll(context) and scene.network_render.mode == "RENDER_CLIENT"
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT"
and scene.network_render.server_address != "[default]")
def draw(self, context):
layout = self.layout
@@ -185,7 +191,9 @@ class RENDER_PT_network_jobs(RenderButtonsPanel):
def poll(self, context):
scene = context.scene
return super().poll(context) and scene.network_render.mode == "RENDER_CLIENT"
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT"
and scene.network_render.server_address != "[default]")
def draw(self, context):
layout = self.layout

View File

@@ -28,7 +28,7 @@ try:
except:
bpy = None
VERSION = b"0.7"
VERSION = bytes("0.7", encoding='utf8')
# Jobs status
JOB_WAITING = 0 # before all data has been entered
@@ -36,13 +36,21 @@ JOB_PAUSED = 1 # paused by user
JOB_FINISHED = 2 # finished rendering
JOB_QUEUED = 3 # ready to be dispatched
JOB_STATUS_TEXT = {
JOB_WAITING: "Waiting",
JOB_PAUSED: "Paused",
JOB_FINISHED: "Finished",
JOB_QUEUED: "Queued"
}
# Frames status
QUEUED = 0
DISPATCHED = 1
DONE = 2
ERROR = 3
STATUS_TEXT = {
FRAME_STATUS_TEXT = {
QUEUED: "Queued",
DISPATCHED: "Dispatched",
DONE: "Done",
@@ -57,40 +65,66 @@ def rnaOperator(rna_op):
if bpy: bpy.ops.add(rna_op)
return rna_op
def clientScan():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.settimeout(30)
def reporting(report, message, errorType = None):
if errorType:
t = 'ERROR'
else:
t = 'INFO'
if report:
report(t, message)
return None
elif errorType:
raise errorType(message)
else:
return None
s.bind(('', 8000))
buf, address = s.recvfrom(64)
print("received:", buf)
address = address[0]
port = int(str(buf, encoding='utf8'))
return (address, port)
except socket.timeout:
print("no server info")
return ("", 8000) # return default values
def clientScan(report = None):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.settimeout(30)
def clientConnection(address, port):
if address == "[default]":
s.bind(('', 8000))
buf, address = s.recvfrom(64)
address = address[0]
port = int(str(buf, encoding='utf8'))
reporting(report, "Master server found")
return (address, port)
except socket.timeout:
reporting(report, "No master server on network", IOError)
return ("", 8000) # return default values
def clientConnection(address, port, report = None):
if address == "[default]":
# calling operator from python is fucked, scene isn't in context
# if bpy:
# bpy.ops.render.netclientscan()
# else:
address, port = clientScan()
conn = http.client.HTTPConnection(address, port)
if clientVerifyVersion(conn):
return conn
else:
conn.close()
raise IOError("Wrong version on master")
address, port = clientScan()
if address == "":
return None
try:
conn = http.client.HTTPConnection(address, port)
if conn:
if clientVerifyVersion(conn):
return conn
else:
conn.close()
reporting(report, "Incorrect master version", ValueError)
except Exception as err:
if report:
report('ERROR', str(err))
return None
else:
raise
def clientVerifyVersion(conn):
conn.request("GET", "/version")
@@ -104,7 +138,7 @@ def clientVerifyVersion(conn):
if server_version != VERSION:
print("Incorrect server version!")
print("expected", VERSION, "received", server_version)
print("expected", str(VERSION, encoding='utf8'), "received", str(server_version, encoding='utf8'))
return False
return True