diff options
Diffstat (limited to 'netrender/model.py')
-rw-r--r-- | netrender/model.py | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/netrender/model.py b/netrender/model.py new file mode 100644 index 00000000..5fc0bc2a --- /dev/null +++ b/netrender/model.py @@ -0,0 +1,360 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +import sys, os +import http, http.client, http.server, urllib +import subprocess, shutil, time, hashlib + +import netrender.versioning as versioning +from netrender.utils import * + +class LogFile: + def __init__(self, job_id = 0, slave_id = 0, frames = []): + self.job_id = job_id + self.slave_id = slave_id + self.frames = frames + + def serialize(self): + return { + "job_id": self.job_id, + "slave_id": self.slave_id, + "frames": self.frames + } + + @staticmethod + def materialize(data): + if not data: + return None + + logfile = LogFile() + logfile.job_id = data["job_id"] + logfile.slave_id = data["slave_id"] + logfile.frames = data["frames"] + + return logfile + +class RenderSlave: + _slave_map = {} + + def __init__(self): + self.id = "" + self.name = "" + self.address = ("",0) + self.stats = "" + self.total_done = 0 + self.total_error = 0 + self.last_seen = 0.0 + + def serialize(self): + return { + "id": self.id, + "name": self.name, + "address": self.address, + "stats": self.stats, + "total_done": self.total_done, + "total_error": self.total_error, + "last_seen": self.last_seen + } + + @staticmethod + def materialize(data, cache = True): + if not data: + return None + + slave_id = data["id"] + + if cache and slave_id in RenderSlave._slave_map: + return RenderSlave._slave_map[slave_id] + + slave = RenderSlave() + slave.id = slave_id + slave.name = data["name"] + slave.address = data["address"] + slave.stats = data["stats"] + slave.total_done = data["total_done"] + slave.total_error = data["total_error"] + slave.last_seen = data["last_seen"] + + if cache: + RenderSlave._slave_map[slave_id] = slave + + return slave + +JOB_BLENDER = 1 +JOB_PROCESS = 2 +JOB_VCS = 3 + +JOB_TYPES = { + JOB_BLENDER: "Blender", + JOB_PROCESS: "Process", + JOB_VCS: "Versioned", + } + +class VersioningInfo: + def __init__(self, info = None): + self._system = None + self.wpath = "" + self.rpath = "" + self.revision = "" + + @property + def system(self): + return self._system + + @system.setter + def system(self, value): + self._system = versioning.SYSTEMS[value] + + def update(self): + self.system.update(self) + + def serialize(self): + return { + "wpath": self.wpath, + "rpath": self.rpath, + "revision": self.revision, + "system": self.system.name + } + + @staticmethod + def generate(system, path): + vs = VersioningInfo() + vs.wpath = path + vs.system = system + + vs.rpath = vs.system.path(path) + vs.revision = vs.system.revision(path) + + return vs + + + @staticmethod + def materialize(data): + if not data: + return None + + vs = VersioningInfo() + vs.wpath = data["wpath"] + vs.rpath = data["rpath"] + vs.revision = data["revision"] + vs.system = data["system"] + + return vs + + +class RenderFile: + def __init__(self, filepath = "", index = 0, start = -1, end = -1, signature=0): + self.filepath = filepath + self.original_path = filepath + self.signature = signature + self.index = index + self.start = start + self.end = end + + def serialize(self): + return { + "filepath": self.filepath, + "original_path": self.original_path, + "index": self.index, + "start": self.start, + "end": self.end, + "signature": self.signature + } + + @staticmethod + def materialize(data): + if not data: + return None + + rfile = RenderFile(data["filepath"], data["index"], data["start"], data["end"], data["signature"]) + rfile.original_path = data["original_path"] + + return rfile + +class RenderJob: + def __init__(self, job_info = None): + self.id = "" + self.type = JOB_BLENDER + self.name = "" + self.category = "None" + self.status = JOB_WAITING + self.files = [] + self.chunks = 0 + self.priority = 0 + self.blacklist = [] + + self.version_info = None + + self.resolution = None + + self.usage = 0.0 + self.last_dispatched = 0.0 + self.frames = [] + + if job_info: + 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 + self.blacklist = job_info.blacklist + self.version_info = job_info.version_info + + def hasRenderResult(self): + return self.type in (JOB_BLENDER, JOB_VCS) + + def rendersWithBlender(self): + return self.type in (JOB_BLENDER, JOB_VCS) + + def addFile(self, file_path, start=-1, end=-1, signed=True): + if signed: + signature = hashFile(file_path) + else: + signature = None + self.files.append(RenderFile(file_path, len(self.files), start, end, signature)) + + def addFrame(self, frame_number, command = ""): + frame = RenderFrame(frame_number, command) + self.frames.append(frame) + return frame + + def __len__(self): + return len(self.frames) + + def countFrames(self, status=QUEUED): + total = 0 + for f in self.frames: + if f.status == status: + total += 1 + + return total + + 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, + DISPATCHED: 0, + DONE: 0, + ERROR: 0 + } + + for frame in self.frames: + results[frame.status] += 1 + + return results + + def __contains__(self, frame_number): + for f in self.frames: + if f.number == frame_number: + return True + else: + return False + + def __getitem__(self, frame_number): + for f in self.frames: + if f.number == frame_number: + return f + else: + return None + + def serialize(self, frames = None): + min_frame = min((f.number for f in frames)) if frames else -1 + max_frame = max((f.number for f in frames)) if frames else -1 + return { + "id": self.id, + "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, + "priority": self.priority, + "usage": self.usage, + "blacklist": self.blacklist, + "last_dispatched": self.last_dispatched, + "version_info": self.version_info.serialize() if self.version_info else None, + "resolution": self.resolution + } + + @staticmethod + def materialize(data): + if not data: + return None + + job = RenderJob() + job.id = data["id"] + 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"] + job.priority = data["priority"] + job.usage = data["usage"] + job.blacklist = data["blacklist"] + job.last_dispatched = data["last_dispatched"] + job.resolution = data["resolution"] + + version_info = data.get("version_info", None) + if version_info: + job.version_info = VersioningInfo.materialize(version_info) + + return job + +class RenderFrame: + def __init__(self, number = 0, command = ""): + self.number = number + self.time = 0 + self.status = QUEUED + self.slave = None + self.command = command + + def statusText(self): + return FRAME_STATUS_TEXT[self.status] + + def serialize(self): + return { + "number": self.number, + "time": self.time, + "status": self.status, + "slave": None if not self.slave else self.slave.serialize(), + "command": self.command + } + + @staticmethod + def materialize(data): + if not data: + return None + + frame = RenderFrame() + frame.number = data["number"] + frame.time = data["time"] + frame.status = data["status"] + frame.slave = RenderSlave.materialize(data["slave"]) + frame.command = data["command"] + + return frame |