#! /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 os import re import pymysql from common import norm host = socket.gethostname() port = 12345 verbose = False dbuser = "" dbpw = "" dbname = "worldbuild" 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] == "-u" or sys.argv[i] == "--user": i += 1 dbuser = sys.argv[i] elif sys.argv[i] == "-p" or sys.argv[i] == "--password": i += 1 dbpw = sys.argv[i] elif sys.argv[i] == "-d" or sys.argv[i] == "--database": i += 1 dbname = sys.argv[i] elif sys.argv[i] == "-v": verbose = True 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(" -d, --database Database name") print(" -u, --user Database user") print(" -p, --password Database password") 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 if dbuser == "": print("ERROR: No database user given") sys.exit(1) if dbpw == "": print("ERROR: No database password given") sys.exit(1) db = pymysql.connect("localhost", dbuser, dbpw, dbname) cursor = db.cursor() def get_lock(): ret = 0 sql = "SELECT GET_LOCK('tile-status-lock', 10)" while ret == 0: cursor.execute(sql) ret = cursor.fetchone() return def rel_lock(): sql = "SELECT RELEASE_LOCK('tile-status-lock')" cursor.execute(sql) def set_state(name, status): if verbose: print(name + " set status to " + status) match = re.match(r"^[ew]\d{3}[ns]\d{2}|[0-9]{1,7}$", name) if match == None: print("WARNING: Recived status " + status + " from invalid tile '" + name + "'") else: if status != "started" and status != "done" and status != "rebuild" and status != "skip" and status != "pending" and status != "packaged": print("WARNING: Invalid status '" + status + "' recived from " + name) else: match = re.match(r"[ew]\d{3}[ns]\d{2}", name) get_lock() if match != None: sql ="SELECT id FROM secondLevel WHERE name = '" + name + "'" cursor.execute(sql) pid = cursor.fetchone() sql = "SELECT id FROM status WHERE name = '" + status + "'" cursor.execute(sql) sid = cursor.fetchone() sql = "UPDATE tile SET status_id = " + str(sid[0]) + " WHERE parent_id = " + str(pid[0]) cursor.execute(sql) sql = "UPDATE secondLevel SET status_id = " + str(sid[0]) + " WHERE name = '" + name + "'" cursor.execute(sql) else: sql = "UPDATE tile SET status_id = (SELECT id FROM status WHERE name = '" + status + "') WHERE id = " + name cursor.execute(sql) rel_lock() db.commit() 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() db.ping(reconnect=True) db.commit() match = re.match(r"(set) ([ew]\d{3}[ns]\d{2}|[0-9]{1,7}) (done|started|rebuild|skip|pending|packaged)", msg) if match != None: action = "set" name = match.group(2) status = match.group(3) set_state(name, status) else: match = re.match(r"(get) (started|rebuild|skip|pending|done)", msg) if match != None: if match.group(2) == "done": action = "get-done" else: action = "get-job" get = match.group(2) else: match = re.match(r"(status) ([ew]\d{3}[ns]\d{2}|[0-9]{1,7})", msg) if match != None: action = "status" name = match.group(2) else: print("WARNING: Recived invalid package") if action == "get-job": additional_type = "" if get != "pending": additional_type = "OR status_id = (SELECT id FROM status WHERE name = '" + get + "')" get_lock() sql = "SELECT id FROM tile WHERE status_id = (SELECT id FROM status WHERE name = 'pending') " + additional_type + " ORDER BY parent_id LIMIT 1" cursor.execute(sql) result = cursor.fetchone() if result == None: tile = "None" else: tile = result[0] sql = "UPDATE tile SET status_id = (SELECT id FROM status WHERE name = 'started') WHERE id = " + str(tile) cursor.execute(sql) db.commit() rel_lock() if verbose: print("Asigning job on tile " + str(tile)) c.send(str(tile).encode()) elif action == "get-done": sql = "SELECT name FROM secondLevel WHERE status_id = (SELECT id FROM status WHERE name = 'done') LIMIT 1" cursor.execute(sql) result = cursor.fetchone() if result == None: tile = "None" else: tile = result[0] c.send(str(tile).encode()) elif action == "status": match = re.match(r"([ew])(\d{3})([ns])(\d{2})", name) if match != None: sql = "SELECT name FROM status WHERE id = (SELECT status_id FROM secondLevel WHERE name = '" + name + "')" cursor.execute(sql) result = cursor.fetchone() c.send(str(result[0]).encode()) else: sql = "SELECT name FROM status WHERE id = (SELECT status_id FROM tile WHERE id = '" + name + "')" cursor.execute(sql) result = cursor.fetchone() c.send(str(result[0]).encode()) c.close() except IOError: print("WARNING: Recived invalid package") c.close() except KeyboardInterrupt: rel_lock() sock.close() db.close() print("Exiting...") sys.exit(0)