Cleanup file and folder structure
This commit is contained in:
100
scripts/JobServer.gd
Normal file
100
scripts/JobServer.gd
Normal file
@@ -0,0 +1,100 @@
|
||||
extends HTTPRequest
|
||||
|
||||
var socket = WebSocketPeer.new()
|
||||
|
||||
var client_id
|
||||
var connected = false
|
||||
func InitWebsocket():
|
||||
print("Connecting websocket ")
|
||||
socket.max_queued_packets = 32768
|
||||
socket.outbound_buffer_size = 5000000
|
||||
socket.connect_to_url($"/root/Main".websocket_url, TLSOptions.client_unsafe())
|
||||
var timeout = 5
|
||||
while socket.get_ready_state() != WebSocketPeer.STATE_OPEN:
|
||||
socket.poll()
|
||||
await get_tree().create_timer(.25).timeout
|
||||
timeout -= 0.25
|
||||
if timeout <= 0:
|
||||
timeout = 5
|
||||
socket.connect_to_url($"/root/Main".websocket_url, TLSOptions.client_unsafe())
|
||||
|
||||
var init_message = {
|
||||
"register": {
|
||||
"version": 1,
|
||||
"auth_key": $"/root/Main".auth_key,
|
||||
"hostname": $"/root/Main".hostname
|
||||
}
|
||||
}
|
||||
socket.send_text(str(init_message))
|
||||
connected = true
|
||||
print("Connected")
|
||||
while connected:
|
||||
await PollWebsocket()
|
||||
RenderingServer.force_draw()
|
||||
DisplayServer.process_events()
|
||||
await get_tree().create_timer(0.1).timeout
|
||||
|
||||
|
||||
func PollWebsocket():
|
||||
var main = $"/root/Main"
|
||||
socket.poll()
|
||||
var state = socket.get_ready_state()
|
||||
if state == WebSocketPeer.STATE_OPEN:
|
||||
while socket.get_available_packet_count():
|
||||
var packet = socket.get_packet()
|
||||
var json = JSON.parse_string(packet.get_string_from_utf8())
|
||||
print("Packet: ", packet.slice(0,5), "...")
|
||||
if "welcome" in json:
|
||||
print("Registered as client %s" % json["welcome"]["clientId"])
|
||||
client_id = json["welcome"]["clientId"]
|
||||
if "job" in json:
|
||||
var job = json["job"]
|
||||
print("Recevied Job ", job["jobId"])
|
||||
main.rendering = true
|
||||
|
||||
var result_path = await $"../Renderer".RenderJob(job)
|
||||
var result_value = ""
|
||||
var result_type = "URL" if $"/root/Main".serve_mode == "local" else "B64:PNG"
|
||||
if $"/root/Main".serve_mode == "local":
|
||||
result_value = result_path
|
||||
if $"/root/Main".serve_mode == "remote":
|
||||
print("trying to open " + result_path)
|
||||
var resut_file = FileAccess.open(result_path,FileAccess.READ)
|
||||
result_value = "{path}:{data}".format({
|
||||
"path": result_path.get_file(),
|
||||
"data": Marshalls.raw_to_base64(resut_file.get_buffer(resut_file.get_length()))
|
||||
})
|
||||
var debugFile = FileAccess.open("user://debug.log", FileAccess.WRITE)
|
||||
debugFile.store_string(result_value)
|
||||
debugFile.flush()
|
||||
debugFile.close()
|
||||
var response = {
|
||||
"result": {
|
||||
"type": result_type,
|
||||
"jobId": job["jobId"],
|
||||
"value": result_value
|
||||
}
|
||||
}
|
||||
print("[%s] Sending result via wss..." % str(response).length())
|
||||
var time_start = Time.get_unix_time_from_system()
|
||||
socket.send_text(str(response))
|
||||
var time_elapsed = Time.get_unix_time_from_system() - time_start
|
||||
print("Sent result in %s \n" % time_elapsed, result_path)
|
||||
main.rendering = false
|
||||
elif state == WebSocketPeer.STATE_CLOSING:
|
||||
socket.poll()
|
||||
elif state == WebSocketPeer.STATE_CLOSED:
|
||||
print(socket.get_packet())
|
||||
var code = socket.get_close_code()
|
||||
var reason = socket.get_close_reason()
|
||||
print("WebSocket closed with code: %d, reason %s. Clean: %s" % [code, reason, code != -1])
|
||||
print("Attempting reconnect in 5")
|
||||
set_process(false) # Stop processing.
|
||||
connected = false
|
||||
await get_tree().create_timer(5).timeout
|
||||
InitWebsocket()
|
||||
|
||||
func _process(_delta):
|
||||
pass
|
||||
|
||||
|
||||
38
scripts/Main.gd
Normal file
38
scripts/Main.gd
Normal file
@@ -0,0 +1,38 @@
|
||||
extends Node2D
|
||||
|
||||
var config = ConfigFile.new()
|
||||
|
||||
var websocket_url
|
||||
var public_path
|
||||
var output_dir
|
||||
var serve_mode
|
||||
var cache_dir
|
||||
var auth_key
|
||||
var hostname
|
||||
var rendering = false
|
||||
signal finished_rendering
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
config.load("res://config.cfg")
|
||||
websocket_url = config.get_value("core", "websocket_url")
|
||||
public_path = config.get_value("core", "public_path")
|
||||
output_dir = config.get_value("core", "output_dir")
|
||||
serve_mode = config.get_value("core", "serve_mode")
|
||||
cache_dir = config.get_value("core", "cache_dir")
|
||||
auth_key = config.get_value("core", "auth_key")
|
||||
hostname = config.get_value("core", "hostname")
|
||||
|
||||
if OS.has_environment("USERNAME"):
|
||||
hostname = "%s/%s" % [OS.get_environment("USERNAME"), hostname]
|
||||
else:
|
||||
hostname = "%s/%s" % [OS.get_name(), hostname]
|
||||
|
||||
print("Starting render node")
|
||||
|
||||
DirAccess.make_dir_absolute(output_dir)
|
||||
DirAccess.make_dir_absolute(cache_dir)
|
||||
$JobServer.InitWebsocket()
|
||||
|
||||
func FinishedRendering():
|
||||
rendering = false
|
||||
37
scripts/RemoteLoader.gd
Normal file
37
scripts/RemoteLoader.gd
Normal file
@@ -0,0 +1,37 @@
|
||||
extends HTTPRequest
|
||||
|
||||
func GetRemoteImage(url):
|
||||
var image = Image.new()
|
||||
print("Fetching remote image %s" % url)
|
||||
var urlHash = str(url.hash())
|
||||
var outFile = "{dir}/{hash}-{fileName}.png".format({
|
||||
'dir': $"/root/Main".cache_dir,
|
||||
'hash': urlHash,
|
||||
'fileName': url.get_file().rsplit(".", true, 1)[0]
|
||||
})
|
||||
|
||||
if FileAccess.file_exists(outFile):
|
||||
image.load(outFile)
|
||||
print("Loaded image from cache. " + outFile)
|
||||
return image
|
||||
|
||||
timeout = 1000
|
||||
request(url)
|
||||
var res = await request_completed
|
||||
var magicBytes = res[3].slice(0,8)
|
||||
print(magicBytes)
|
||||
var fileType = url.get_extension()
|
||||
var error = null
|
||||
if fileType == "png" or magicBytes == PackedByteArray([137, 80, 78, 71, 13, 10, 26, 10]):
|
||||
print("Detected PNG File")
|
||||
error = image.load_png_from_buffer(res[3])
|
||||
if ["jpg", "jpeg"].has(fileType) or magicBytes == PackedByteArray([255, 216, 255, 224, 0, 16, 74, 70]):
|
||||
print("Detected JPG File")
|
||||
error = image.load_jpg_from_buffer(res[3])
|
||||
if error != OK:
|
||||
print("Error fetching image ", str(error))
|
||||
image = load("res://assets/fallback_card.png")
|
||||
else:
|
||||
image.save_png(outFile)
|
||||
print("Saved new image to cache. " + outFile)
|
||||
return image
|
||||
131
scripts/Renderer.gd
Normal file
131
scripts/Renderer.gd
Normal file
@@ -0,0 +1,131 @@
|
||||
extends Node2D
|
||||
|
||||
var counter = 1
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
pass
|
||||
"""
|
||||
var job = await $JobServer.GetJob()
|
||||
var jobHash = str([job["size"], job["elements"]]).sha1_text()
|
||||
print("Job hash %s" % jobHash)
|
||||
|
||||
var outFile = "output/%s_%s.png" % [job["type"],jobHash]
|
||||
if FileAccess.file_exists(outFile):
|
||||
print("Skipping, file exists")
|
||||
get_tree().quit()
|
||||
return
|
||||
"""
|
||||
|
||||
#DisplayServer.window_set_size(Vector2(job["size"]["width"], job["size"]["height"]))
|
||||
#await RenderComposition(job["elements"])
|
||||
#await RenderingServer.frame_post_draw
|
||||
|
||||
# Get rendered image
|
||||
#var img = get_viewport().get_texture().get_image()
|
||||
|
||||
#img.save_png(outFile)
|
||||
#get_tree().quit()
|
||||
|
||||
func RenderJob(job):
|
||||
print("Rendering ", job["jobId"])
|
||||
var renderContainer = $"/root/Main/RenderContainer"
|
||||
for node in renderContainer.get_children():
|
||||
renderContainer.remove_child(node)
|
||||
node.free()
|
||||
print("Cleared Render container")
|
||||
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
|
||||
DisplayServer.window_set_size(Vector2(job["size"]["width"], job["size"]["height"]))
|
||||
get_viewport().size = Vector2(job["size"]["width"], job["size"]["height"])
|
||||
print("Rendering with size ", get_viewport().size)
|
||||
|
||||
await RenderComposition(job["elements"])
|
||||
print("Rendered Composition")
|
||||
await RenderingServer.frame_post_draw
|
||||
|
||||
# Get rendered image
|
||||
var img = get_viewport().get_texture().get_image()
|
||||
var outFile = "{path}/{type}_{hash}.png".format({
|
||||
"path":$"/root/Main".output_dir,
|
||||
"type":job["type"],
|
||||
"hash": str(job["elements"]).hash()
|
||||
})
|
||||
img.save_png(outFile)
|
||||
|
||||
return outFile
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
func _process(_delta):
|
||||
pass
|
||||
|
||||
func run_test():
|
||||
if counter == 50:
|
||||
get_tree().quit()
|
||||
render()
|
||||
counter += 1
|
||||
|
||||
func RenderComposition(composition):
|
||||
var zIndex = 0
|
||||
for comp in composition:
|
||||
var type = comp["type"]
|
||||
if type == "text":
|
||||
print("Render label")
|
||||
await RenderLabel(comp, zIndex)
|
||||
if type == "image":
|
||||
print("Render image")
|
||||
await RenderImage(comp, zIndex)
|
||||
zIndex += 1
|
||||
|
||||
func RenderImage(def, zIndex):
|
||||
var imageNode = TextureRect.new()
|
||||
var image = Image.new()
|
||||
image = await $"../Remote".GetRemoteImage(def["asset"])
|
||||
var pos = Vector2(float(def["x"]), float(def["y"]))
|
||||
var texture = ImageTexture.new()
|
||||
texture = ImageTexture.create_from_image(image)
|
||||
texture.set_size_override(Vector2(def["width"], def["height"]))
|
||||
imageNode.texture = texture
|
||||
imageNode.name = def["asset"].right(15)
|
||||
imageNode.set_position(pos)
|
||||
imageNode.z_index = zIndex
|
||||
$"/root/Main/RenderContainer".add_child(imageNode)
|
||||
print("Image added at %s" % pos)
|
||||
|
||||
func RenderLabel(def, zIndex):
|
||||
var textNode = Label.new()
|
||||
var labelText = def["text"]
|
||||
labelText = labelText.replace('%nodeid%', "%s: %s" % [$"/root/Main".hostname , $"/root/Main/JobServer".client_id])
|
||||
labelText = labelText.replace('%servemode%', $"/root/Main".serve_mode)
|
||||
labelText = labelText.replace('%timestamp%', Time.get_datetime_string_from_system())
|
||||
textNode.text = labelText;
|
||||
var pos = Vector2(float(def["x"]), float(def["y"]))
|
||||
print("Rendering label '%s' at %s" % [def["text"], pos])
|
||||
|
||||
var labelSettings = LabelSettings.new()
|
||||
labelSettings = load("res://DefaultLabelSettings.tres").duplicate()
|
||||
|
||||
labelSettings.set("font_size", def["fontSize"])
|
||||
textNode.label_settings = labelSettings
|
||||
textNode.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
textNode.set_position(pos)
|
||||
textNode.set_size(Vector2(float(def["width"]), float(def["height"])))
|
||||
textNode.vertical_alignment = VERTICAL_ALIGNMENT_TOP
|
||||
if "horizontalAlignment" in def:
|
||||
var alignments = { "left": HORIZONTAL_ALIGNMENT_LEFT, "right": HORIZONTAL_ALIGNMENT_RIGHT, "center": HORIZONTAL_ALIGNMENT_CENTER, "fill": HORIZONTAL_ALIGNMENT_FILL }
|
||||
textNode.horizontal_alignment = alignments[def["horizontalAlignment"]]
|
||||
textNode.name = def["text"].substr(0,15)
|
||||
textNode.z_index = zIndex
|
||||
$"/root/Main/RenderContainer".add_child(textNode)
|
||||
print("Label added")
|
||||
|
||||
func render():
|
||||
print("Rendering frame %s" % counter)
|
||||
var tstamp_label = $"../Placeholder/tstamp"
|
||||
var tstamp = Time.get_ticks_usec()
|
||||
tstamp_label.text = str(tstamp) + "\n %s" % counter
|
||||
await RenderingServer.frame_post_draw
|
||||
|
||||
# Retrieve the captured image.
|
||||
var img = get_viewport().get_texture().get_image()
|
||||
|
||||
img.save_png("output/test%s.png" % counter)
|
||||
Reference in New Issue
Block a user