Project

General

Profile

Support #86 ยป IcarusVred.py

10.3 working submission file - Richard Levene, 12/05/2023 11:15 PM

 
import queue as Queue
import json
import os
import socket
import time

from Deadline.Plugins import *
from Deadline.Scripting import *
from FranticX.Processes import *
from System import *
from System.Diagnostics import *
from System.IO import *
from System.Text import *
from System.Text.RegularExpressions import *


######################################################################
## This is the function that Deadline calls to get an instance of the
## main DeadlinePlugin class.
######################################################################
def GetDeadlinePlugin():
return IcarusVredPlugin()


######################################################################
## This is the function that Deadline calls when the plugin is no
## longer in use so that it can get cleaned up.
######################################################################
def CleanupDeadlinePlugin(deadlinePlugin):
deadlinePlugin.Cleanup()


# Used to deal with my IDE clean up messing up my jam.
try:
p = Plugins()
except:
pass


######################################################################
## This is the main DeadlinePlugin class for IcarusVredPlugin.
######################################################################
class IcarusVredPlugin(DeadlinePlugin):
## Variable to hold the Managed Process object.
Process = None

## Hook up the callbacks in the constructor.
def __init__(self):
super().__init__()
self.InitializeProcessCallback += self.InitializeProcess
self.StartJobCallback += self.StartJob
self.RenderTasksCallback += self.RenderTasks
self.EndJobCallback += self.EndJob
self.mSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.mSocket.setblocking(True)
self.mReadSocket = True
self.mErrorSocketMessage = ""
self.mInitializedSockets = False
self.callback_queue = Queue.Queue()
self.readData = bytearray()
self.mFailedJob = False
self.mInitializeOK = False
self.mIcarusNodeStatus = ""
self.mIcarusNodeStatusCode = 0
self.renderTaskInProgress = False
self.mIcarusTaskId = ""
self.mJobId = ""
self.mJobPlugin = ""
self.mScenePath = ""
self.mTemplatePath = ""
self.mVredExePath = ""
self.mProjectId = ""
self.mRenderTaskDone = False
self.mForceRestartVred = False

## Clean up the plugin.
def Cleanup(self):
del self.InitializeProcessCallback
del self.StartJobCallback
del self.RenderTasksCallback
del self.EndJobCallback

# Clean up the managed process object.
if self.Process:
self.Process.Cleanup()
del self.Process
self.mInitializeOK = False

if self.mSocket:
if self.mRenderTaskDone:
self.sendMessage({"cmd": 190})
else:
self.sendMessage({"cmd": 195})
time.sleep(5)
self.mSocket.close()

self.mSocket = None
self.mReadSocket = False
self.mSocketWorker = None
self.mSocketInitializer = None

def getSocketData(self):
if self.mSocket is not None:
data = self.mSocket.recv(1024)
self.readData = self.readData + data
if len(data) == 0:
self.mErrorSocketMessage = "Lost connection to render node manager"
self.mFailedJob = True
self.FailRender(self.mErrorSocketMessage)
return self.getMessagesFromData(self.readData)
else:
self.mErrorSocketMessage = "Lost connection to render node manager"
self.mFailedJob = True
self.FailRender(self.mErrorSocketMessage)
return []

def getMessagesFromData(self, msgs):
okMesg = ""
msgList = []
m = str(msgs.decode())
c = 0
for letter in m:
c = c + 1
if letter != "|":
okMesg = okMesg + letter
else:
msgList.append(json.loads(okMesg))
okMesg = ""
if len(msgs) > 0:
if msgs[-1] != "|":
self.readData = okMesg.encode()
else:
self.readData = bytearray()
return msgList

def handleCreateSocket(self):
try:
self.mSocket.connect(("localhost", 35000))
except Exception as e:
self.mErrorSocketMessage = "Could not connect to Icarus Node, error : " + str(e)
self.mFailedJob = True
self.FailRender(self.mErrorSocketMessage)
# self.mSocketWorker.start()

def InitializeProcess(self):
# Set the plugin specific settings.
self.SingleFramesOnly = False
self.PluginType = PluginType.Advanced
# self.mSocketInitializer.start()
self.handleCreateSocket()

def remapPaths(self, value):
self.LogInfo("Remapping path before : " + value)
for a in RepositoryUtils.GetPathMappings():
#self.LogInfo("Remap Values : : " +a[0]+"----"+a[1])
value = value.replace(a[0], a[1])
value = value.replace("\\","/")
self.LogInfo("Remapping path after : " + value)
return value

def StartJob(self):
self.mJobInitializationBegin = True
job = self.GetJob()

#### First we get vred exe and validate that it exists
ver = self.GetPluginInfoEntryWithDefault("Version", "Pro_2021_0")
exe = self.GetConfigEntryWithDefault("Vred_Executables" + ver, "-1")
self.LogInfo("Searching for Exe : " + "Vred_Executables"+ver)
vredExe = FileUtils.SearchFileList(exe)

if vredExe == "":
self.mErrorSocketMessage = "Could not find vred Executable on This system : " + exe + " \n Version : " + ver
self.mFailedJob = True
self.FailRender(self.mErrorSocketMessage)

if exe == "-1":
self.mErrorSocketMessage = "Could not get Valid Vred executable from repository : " + ver
self.mFailedJob = True
self.FailRender(self.mErrorSocketMessage)
return

if not os.path.isfile(vredExe):
self.mErrorSocketMessage = "Vred appear to not exist on disk : " + str(vredExe)
self.mFailedJob = True
self.FailRender(self.mErrorSocketMessage)

#### Then we get scene
scene = self.GetPluginInfoEntryWithDefault("SceneFile", "-1")
scene = self.remapPaths(scene)
if scene == "-1":
self.mErrorSocketMessage = "Could not get Valid Vred Scene File"
self.mFailedJob = True
self.FailRender(self.mErrorSocketMessage)
if not os.path.isfile(scene):
self.mErrorSocketMessage = "Scene appear to not exist on disk : " + str(scene)
self.mFailedJob = True
self.FailRender(self.mErrorSocketMessage)

#### Then we get Template
templatePath = "-1"
for entry in self.GetAuxiliaryFilenames():
templatePath = str(entry)
break

templatePath = self.remapPaths(templatePath)

if templatePath == "-1":
self.mErrorSocketMessage = "Could not get valid template path"
self.mFailedJob = True
self.FailRender(self.mErrorSocketMessage)

if not os.path.isfile(templatePath):
# self.mErrorSocketMessage = "Template appear to not exist on disk : " + str(templatePath)
# self.mFailedJob = True
# self.FailRender(self.mErrorSocketMessage)
self.LogInfo("Template appear to not exist on disk : " + str(templatePath))

#### Then we send initial request to node with command list and details of job
self.mJobId = self.GetPluginInfoEntryWithDefault("icProjectId", str(job.JobId))
self.mJobPlugin = job.JobPlugin
self.mScenePath = scene
self.mTemplatePath = templatePath

self.mForceRestartVred = self.GetPluginInfoEntryWithDefault("icForceRestart", "False")
if self.mForceRestartVred == "False":
self.mForceRestartVred = False
else:
self.mForceRestartVred = True

self.sendMessage({
"cmd": 5,
"icJobType": "IcarusVred",
"icId": self.mJobId,
"icSender": "deadline",
"icDeadlinePlugin": self.mJobPlugin,
"icExtraFiles": [], # extraFiles,
"icAppExecutablePath": vredExe,
"icScenePath": scene,
"icTemplatePath": templatePath
})
jobStartupDone = False
c = 0
while not jobStartupDone:
c = c + 1
msg = ""
msgList = self.getSocketData()
for inx, data in enumerate(msgList):
cmd = data["cmd"]
if cmd == 6:
self.mErrorSocketMessage = "Render node refused this project, error : " + str(data["icIcarusNodeReply"])
self.mFailedJob = True
self.FailRender(self.mErrorSocketMessage)
break
elif cmd == 7:
msgList.pop(inx)
self.LogInfo("----")
self.LogInfo("Icarus Node has accepted this project")
self.LogInfo("----")
if len(msgList) > 0:
self.handleMessages(msgList)
self.mInitializeOK = True
c = 500
jobStartupDone = True
break
else:
self.handleMessages([data])

def handleMessages(self, msgList):
for msg in msgList:
if "cmd" in msg:
cmd = msg["cmd"]
if cmd == 100:
for data in msg["icIcarusNodeReply"]:
self.LogStdout("Application Status Update : " + data)
elif cmd == 10:
self.mIcarusNodeStatus = msg["icIcarusNodeReply"]
self.mIcarusNodeStatusCode = msg["icIcarusNodeProjectCode"]
self.LogInfo("Icarus Node Status : " + self.mIcarusNodeStatus)
self.SetStatusMessage(self.mIcarusNodeStatus)
if self.mIcarusNodeStatusCode > 5000:
self.mFailedJob = True
self.mErrorSocketMessage = "Failed job, error :" + self.mIcarusNodeStatus
self.FailRender(self.mErrorSocketMessage)
elif self.mIcarusNodeStatusCode == 1400:
self.mRenderTaskDone = True
elif cmd == 205 or cmd == 210 or cmd == 215:
self.mFailedJob = True
self.mErrorSocketMessage = "Failed job, error :" + msg["icIcarusNodeReply"]
self.FailRender(self.mErrorSocketMessage)
elif cmd == 2000:
self.LogInfo(msg["icIcarusNodeReply"])
elif cmd == 1310:
self.SetProgress(float(msg["icIcarusNodeReply"]))

return None

def sendMessage(self, msg):
# Make generic consistent message
data = {
"cmd": 0,
"icJobType": "IcarusVred",
"icId": self.mJobId,
"icSender": "deadline",
"icLayerId": self.mIcarusTaskId,
"icDeadlinePlugin": self.mJobPlugin,
"icExtraFiles": [],
"icAppExecutablePath": self.mVredExePath,
"icScenePath": self.mScenePath,
"icTemplatePath": self.mTemplatePath
}
# Add extra/change existing
data.update(msg)
data = json.dumps(data) + "|"
data = data.encode()

try:
self.mSocket.send(data)
except Exception as e:
self.mFailedJob = True
self.mErrorSocketMessage = "Error communicating with Icarus Node : " + str(e)
self.FailRender(self.mErrorSocketMessage)

## Called by Deadline for each task the Slave renders.
def RenderTasks(self):
if self.mFailedJob:
self.FailRender(self.mErrorSocketMessage)
if self.mInitializeOK:
self.mRenderTaskDone = False
self.renderTaskInProgress = True
self.mIcarusTaskId = str(self.GetPluginInfoEntryWithDefault("icLayerId", "-1"))
if self.mIcarusTaskId == "-1":
self.FailRender("Invalid Icarus Task id")
if self.mIcarusNodeStatus == "":
pass
remaps = []
for a in RepositoryUtils.GetPathMappings():
remaps.append([a[0], a[1]])
self.sendMessage({"cmd": 200, "icLayerId": self.mIcarusTaskId, "icRemapPathMapping": remaps})
while self.renderTaskInProgress:
time.sleep(0.1)
self.handleMessages(self.getSocketData())
if self.mRenderTaskDone:
self.renderTaskInProgress = False
else:
self.FailRender(self.mErrorSocketMessage)

## Called by Deadline when the job ends.
def EndJob(self):
if self.mForceRestartVred:
self.mInitializeOK = False
self.sendMessage({"cmd": 195})

def printSpace(self):
self.LogInfo(" ")
self.LogInfo(" ")
self.LogInfo(" ")
self.LogInfo(" ")
    (1-1/1)