diff options
author | Martin Poirier <theeth@yahoo.com> | 2009-09-23 05:59:57 +0400 |
---|---|---|
committer | Martin Poirier <theeth@yahoo.com> | 2009-09-23 05:59:57 +0400 |
commit | efa757fd8d57891f6feb3fc85fdd3e2ab88e7623 (patch) | |
tree | 80f8a4be7b9cb50abcf179120489d150d0e66524 | |
parent | d98700360838e5dbb52ac633d0a32c5558754eb7 (diff) |
netrender. first draft of html master details. Just point a browser at the master's address and port, et voila. Gives a list of jobs and slaves and well as per frame status for each job and access to slave output logs per frame
-rw-r--r-- | release/io/netrender/__init__.py | 1 | ||||
-rw-r--r-- | release/io/netrender/client.py | 2 | ||||
-rw-r--r-- | release/io/netrender/master.py | 10 | ||||
-rw-r--r-- | release/io/netrender/master_html.py | 119 | ||||
-rw-r--r-- | release/io/netrender/model.py | 5 | ||||
-rw-r--r-- | release/io/netrender/utils.py | 7 |
6 files changed, 139 insertions, 5 deletions
diff --git a/release/io/netrender/__init__.py b/release/io/netrender/__init__.py index b313d64ccbb..4a1dd2238e3 100644 --- a/release/io/netrender/__init__.py +++ b/release/io/netrender/__init__.py @@ -5,6 +5,7 @@ import operators import client import slave import master +import master_html import utils import balancing import ui diff --git a/release/io/netrender/client.py b/release/io/netrender/client.py index f445fe2f608..65b2937867f 100644 --- a/release/io/netrender/client.py +++ b/release/io/netrender/client.py @@ -1,5 +1,5 @@ import bpy -import sys, os +import sys, os, re import http, http.client, http.server, urllib import subprocess, shutil, time, hashlib diff --git a/release/io/netrender/master.py b/release/io/netrender/master.py index 1bff5f6340b..0e3c7063cab 100644 --- a/release/io/netrender/master.py +++ b/release/io/netrender/master.py @@ -5,6 +5,7 @@ import subprocess, shutil, time, hashlib from netrender.utils import * import netrender.model import netrender.balancing +import netrender.master_html class MRenderFile: def __init__(self, filepath, start, end): @@ -126,9 +127,9 @@ class MRenderFrame(netrender.model.RenderFrame): # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- class RenderHandler(http.server.BaseHTTPRequestHandler): - def send_head(self, code = http.client.OK, headers = {}): + def send_head(self, code = http.client.OK, headers = {}, content = "application/octet-stream"): self.send_response(code) - self.send_header("Content-type", "application/octet-stream") + self.send_header("Content-type", content) for key, value in headers.items(): self.send_header(key, value) @@ -342,7 +343,10 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): self.send_head() self.wfile.write(bytes(repr(message), encoding='utf8')) - + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + else: + # hand over the rest to the html section + netrender.master_html.get(self) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= diff --git a/release/io/netrender/master_html.py b/release/io/netrender/master_html.py new file mode 100644 index 00000000000..6a337c8d71d --- /dev/null +++ b/release/io/netrender/master_html.py @@ -0,0 +1,119 @@ +import re + +from netrender.utils import * + + +def get(handler): + def output(text): + handler.wfile.write(bytes(text, encoding='utf8')) + + def link(text, url): + return "<a href='%s'>%s</a>" % (url, text) + + def startTable(border=1): + output("<table border='%i'>" % border) + + def headerTable(*headers): + output("<thead><tr>") + + for c in headers: + output("<td>" + c + "</td>") + + output("</tr></thead>") + + def rowTable(*data): + output("<tr>") + + for c in data: + output("<td>" + str(c) + "</td>") + + output("</tr>") + + def endTable(): + output("</table>") + + handler.send_head(content = "text/html") + + if handler.path == "/html" or handler.path == "/": + output("<html><head><title>NetRender</title></head><body>") + + output("<h2>Master</h2>") + + output("<h2>Slaves</h2>") + + startTable() + headerTable("id", "name", "address", "stats") + + for slave in handler.server.slaves: + rowTable(slave.id, slave.name, slave.address[0], slave.stats) + + endTable() + + output("<h2>Jobs</h2>") + + startTable() + headerTable("id", "name", "length", "done", "dispatched", "error") + + for job in handler.server.jobs: + results = job.framesStatus() + rowTable(link(job.id, "/html/job" + job.id), job.name, len(job), results[DONE], results[DISPATCHED], results[ERROR]) + + endTable() + + output("</body></html>") + + elif handler.path.startswith("/html/job"): + job_id = handler.path[9:] + + output("<html><head><title>NetRender</title></head><body>") + + job = handler.server.getJobByID(job_id) + + if job: + output("<h2>Frames</h2>") + + startTable() + headerTable("no", "status", "render time", "slave", "log") + + for frame in job.frames: + rowTable(frame.number, frame.statusText(), "%.1fs" % frame.time, frame.slave.name if frame.slave else " ", link("view log", "/html/log%s_%i" % (job_id, frame.number)) if frame.log_path else " ") + + endTable() + else: + output("no such job") + + output("</body></html>") + + elif handler.path.startswith("/html/log"): + pattern = re.compile("([a-zA-Z0-9]+)_([0-9]+)") + + output("<html><head><title>NetRender</title></head><body>") + + match = pattern.match(handler.path[9:]) + if match: + job_id = match.groups()[0] + frame_number = int(match.groups()[1]) + + job = handler.server.getJobByID(job_id) + + if job: + frame = job[frame_number] + + if frame: + f = open(frame.log_path, 'rb') + + output("<pre>") + + shutil.copyfileobj(f, handler.wfile) + + output("</pre>") + + f.close() + else: + output("no such frame") + else: + output("no such job") + else: + output("malformed url") + + output("</body></html>") diff --git a/release/io/netrender/model.py b/release/io/netrender/model.py index e8046d7ac8c..9cacfb54a35 100644 --- a/release/io/netrender/model.py +++ b/release/io/netrender/model.py @@ -32,7 +32,7 @@ class RenderSlave: def __init__(self): self.id = "" self.name = "" - self.address = (0,0) + self.address = ("",0) self.stats = "" self.total_done = 0 self.total_error = 0 @@ -173,6 +173,9 @@ class RenderFrame: self.status = QUEUED self.slave = None + def statusText(self): + return STATUS_TEXT[self.status] + def serialize(self): return { "number": self.number, diff --git a/release/io/netrender/utils.py b/release/io/netrender/utils.py index 50ca08d1723..62288aecf94 100644 --- a/release/io/netrender/utils.py +++ b/release/io/netrender/utils.py @@ -19,6 +19,13 @@ DISPATCHED = 1 DONE = 2 ERROR = 3 +STATUS_TEXT = { + QUEUED: "Queued", + DISPATCHED: "Dispatched", + DONE: "Done", + ERROR: "Error" + } + def rnaType(rna_type): bpy.types.register(rna_type) return rna_type |