netrender. first draft of html master details. Just point a browser at the master...
authorMartin Poirier <theeth@yahoo.com>
Wed, 23 Sep 2009 01:59:57 +0000 (01:59 +0000)
committerMartin Poirier <theeth@yahoo.com>
Wed, 23 Sep 2009 01:59:57 +0000 (01:59 +0000)
release/io/netrender/__init__.py
release/io/netrender/client.py
release/io/netrender/master.py
release/io/netrender/master_html.py [new file with mode: 0644]
release/io/netrender/model.py
release/io/netrender/utils.py

index b313d64ccbb79959dd174e4344594fdfe6db571b..4a1dd2238e37c8c5db9194f6a62b835943b8abca 100644 (file)
@@ -5,6 +5,7 @@ import operators
 import client
 import slave
 import master
+import master_html
 import utils
 import balancing
 import ui
index f445fe2f608552e88e1230ed7b51649b23668b5c..65b2937867f0df95a9f2cc368a5b3bffeddff996 100644 (file)
@@ -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
 
index 1bff5f6340b4e1ca6fc19c52c649bf25850db774..0e3c7063cab8d6484abad75da520ac0d62bebd46 100644 (file)
@@ -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 (file)
index 0000000..6a337c8
--- /dev/null
@@ -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 "&nbsp;", link("view log", "/html/log%s_%i" % (job_id, frame.number)) if frame.log_path else "&nbsp;")
+                       
+                       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>")
index e8046d7ac8c5ab4cadeb78ab6e46a6b8a46ad134..9cacfb54a352d6400b8275354da4811add635d48 100644 (file)
@@ -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,
index 50ca08d1723bf783ebe3b6b60ff8b8ebe64bccf0..62288aecf9460501a1ad563fa945eadc5c313720 100644 (file)
@@ -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