osm2city-scripts/worldbuild-manager.py
fly d05795a023 Facepalm
Signed-off-by: fly <merspieler@airmail.cc>
2020-01-18 06:34:21 +00:00

270 lines
7.7 KiB
Python
Executable file

#! /usr/bin/python3
# Copyright (C) 2018-2020 Merspieler, merspieler _at_ airmail.cc
#
# 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 3 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.
import socket
import sys
import json
import os
import re
host = socket.gethostname()
port = 12345
verbose = False
sfile = "projects/worldbuild/status"
argc = len(sys.argv)
i = 1
while i < argc:
if sys.argv[i] == "--port":
i += 1
port = int(sys.argv[i])
elif sys.argv[i] == "--host":
i += 1
host = sys.argv[i]
elif sys.argv[i] == "-v":
verbose = True
elif sys.argv[i] == "-f" or sys.argv[i] == "--file":
i += 1
sfile = sys.argv[i]
elif sys.argv[i] == "-h" or sys.argv[i] == "--help":
print("usage: worldbuild-manager.py [OPTIONS]")
print("Handles job asignments and keeps track of the status")
print("")
print("OPTIONS")
print(" -f, --file Status file to use")
print(" -v, --verbose Verbose printouts")
print(" , --host hostname or interface to bind to")
print(" , --port Port to bind to")
print(" -h, --help Shows this help and exit")
sys.exit(0)
else:
print("Unknown option " + sys.argv[i])
sys.exit(1)
i += 1
def norm(num, length):
num = str(num)
while len(num) < length:
num = "0" + num
return num
def save_state(state):
try:
with open(sfile, 'w') as f:
json.dump(state, f, indent=4)
except IOError:
print("WARNING: Failed to write to file")
def set_state(state, name, status):
if verbose:
print(name + " set status to " + status)
if status == "started" or status == "done" or status == "rebuild" or status == "skip" or status == "pending":
if name == "n-pole" or name == "s-pole":
if not name in state:
state[name] = {}
state[name]["status"] = status
else:
match = re.match(r"([ew])(\d{3})([ns])(\d{2})", name)
if match == None:
print("WARNING: Recived status " + status + " from invalid tile '" + name + "'")
else:
ew = match.group(1)
ew_val = int(match.group(2))
ns = match.group(3)
ns_val = int(match.group(4))
ew_val_major = int(ew_val / 10) * 10
if ew == "w":
if ew_val_major != ew_val:
ew_val_major += 10
ns_val_major = int(ns_val / 10) * 10
if ns == "s":
if ns_val_major != ns_val:
ns_val_major += 10
name_major = ew + norm(ew_val_major, 3) + ns + norm(ns_val_major, 2)
if not name_major in state:
state[name_major] = {}
if not name in state[name_major]:
state[name_major][name] = {}
state[name_major][name]["status"] = status
state[name_major]["done"] = 0
state[name_major]["started"] = 0
state[name_major]["rebuild"] = 0
state[name_major]["skip"] = 0
state[name_major]["pending"] = 0
for tile in state[name_major]:
# Filter status of name_major
if tile != "done" and tile != "started" and tile != "pending" and tile != "status" and tile != "rebuild" and tile != "skip":
state[name_major][state[name_major][tile]["status"]] += 1
if state[name_major]["done"] == 100:
state[name_major]["status"] = "done"
elif state[name_major]["started"] > 0:
state[name_major]["status"] = "started"
elif state[name_major]["rebuild"] > 0:
state[name_major]["status"] = "rebuild"
elif state[name_major]["skip"] > 0:
state[name_major]["status"] = "skip"
else:
state[name_major]["status"] = "pending"
save_state(state)
else:
print("WARNING: Invalid status '" + status + "' recived from " + name)
return state
if os.path.isfile(sfile):
try:
with open(sfile) as json_data:
state = json.load(json_data)
except ValueError:
print("ERROR: Invalid status file")
sys.exit(1)
else:
state = {}
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((host, port))
sock.listen(5)
print("Up and running...")
try:
while True:
try:
c, addr = sock.accept()
msg = c.recv(128)
msg = msg.decode()
match = re.match(r"(set) (n-pole|s-pole|[ew]\d{3}[ns]\d{2}) (done|started|rebuild|skip|pending)", msg)
if match != None:
action = "set"
name = match.group(2)
status = match.group(3)
else:
match = re.match(r"(get) (started|rebuild|skip|pending)", msg)
if match != None:
action = "get"
get = match.group(2)
else:
match = re.match(r"(status) (n-pole|s-pole|[ew]\d{3}[ns]\d{2})", msg)
if match != None:
action = "status"
name = match.group(2)
else:
print("WARNING: Recived invalid package")
if action == "set":
state = set_state(state, name, status)
elif action == "get":
tile = ""
# Build poles first
if not "n-pole" in state or ("n-pole" in state and state["n-pole"]["status"] == get):
tile = "n-pole"
state = set_state(state, "n-pole", "started")
elif not "s-pole" in state or ("s-pole" in state and state["s-pole"]["status"] == get):
tile = "s-pole"
state = set_state(state, "n-pole", "started")
else:
ii = -8
while ii < 8 and tile == "":
i = ii * 10
jj = -18
while jj < 18 and tile == "":
j = jj * 10
if i >= 0:
ns = "n"
else:
ns = "s"
if j >= 0:
ew = "e"
else:
ew = "w"
name = ew + norm(abs(j), 3) + ns + norm(abs(i), 2)
if not name in state or (name in state and state[name]["status"] != "done" and (state[name]["status"] != "skip" or get == "skip")):
if ns == "s":
ns_step = -1
else:
ns_step = 1
if ew == "w":
ew_step = -1
else:
ew_step = 1
j = abs(j)
for k in range(0, 10):
if tile != "":
break
iii = abs(i)
for l in range(0, 10):
name_minor = ew + norm(j, 3) + ns + norm(iii, 2)
if not name in state or (not name_minor in state[name] or (name_minor in state[name] and (state[name][name_minor]["status"] == get or state[name][name_minor]["status"] == "pending"))):
tile = name_minor
state = set_state(state, name_minor, "started")
break
iii += ns_step
j += ew_step
jj += 1
ii += 1
if tile == "":
tile = "None"
if verbose:
print("Asigning job on tile " + tile)
c.send(tile.encode())
elif action == "status":
if name == "n-pole" or name == "s-pole":
c.send(state[name]["status"].encode())
else:
match = re.match(r"([ew])(\d{3})([ns])(\d{2})", name)
ew = match.group(1)
ew_val = int(match.group(2))
ns = match.group(3)
ns_val = int(match.group(4))
ew_val_major = int(ew_val / 10) * 10
if ew == "w":
if ew_val_major != ew_val:
ew_val_major += 10
ns_val_major = int(ns_val / 10) * 10
if ns == "s":
if ns_val_major != ns_val:
ns_val_major += 10
name_major = ew + norm(ew_val_major, 3) + ns + norm(ns_val_major, 2)
if not name_major in state:
c.send("pending".encode())
elif not name in state[name_major]:
c.send("pending".encode())
else:
c.send(state[name_major][name]["status"].encode())
c.close()
except IOError:
print("WARNING: Recived invalid package")
c.close()
except KeyboardInterrupt:
save_state(state)
sock.close()
print("Exiting...")
sys.exit(0)