diff --git a/src/cli/config.py b/src/cli/config.py new file mode 100644 index 0000000..ee2b122 --- /dev/null +++ b/src/cli/config.py @@ -0,0 +1,208 @@ +import math +import json +from multiprocessing import Pool +import os + +from data import set_database_config, get_database_config +from interface import stderr, stdout, INF, ERR + +config_path = "config.json" + +sample_json = """{ + "persistent":{ + "key":{ + "database":"", + "tba":"" + }, + "config-preference":"local", + "synchronize-config":false + }, + "variable":{ + + "max-threads":0.5, + + "competition":"", + "team":"", + + "event-delay":false, + "loop-delay":0, + "reportable":true, + + "teams":[], + + "modules":{ + + "match":{ + "tests":{ + "balls-blocked":["basic_stats","historical_analysis","regression_linear","regression_logarithmic","regression_exponential","regression_polynomial","regression_sigmoidal"], + "balls-collected":["basic_stats","historical_analysis","regression_linear","regression_logarithmic","regression_exponential","regression_polynomial","regression_sigmoidal"], + "balls-lower-teleop":["basic_stats","historical_analysis","regression_linear","regression_logarithmic","regression_exponential","regression_polynomial","regression_sigmoidal"], + "balls-lower-auto":["basic_stats","historical_analysis","regression_linear","regression_logarithmic","regression_exponential","regression_polynomial","regression_sigmoidal"], + "balls-started":["basic_stats","historical_analyss","regression_linear","regression_logarithmic","regression_exponential","regression_polynomial","regression_sigmoidal"], + "balls-upper-teleop":["basic_stats","historical_analysis","regression_linear","regression_logarithmic","regression_exponential","regression_polynomial","regression_sigmoidal"], + "balls-upper-auto":["basic_stats","historical_analysis","regression_linear","regression_logarithmic","regression_exponential","regression_polynomial","regression_sigmoidal"] + } + + }, + + "metric":{ + "tests":{ + "elo":{ + "score":1500, + "N":400, + "K":24 + }, + "gl2":{ + "score":1500, + "rd":250, + "vol":0.06 + }, + "ts":{ + "mu":25, + "sigma":8.33 + } + } + }, + + "pit":{ + "tests":{ + "wheel-mechanism":true, + "low-balls":true, + "high-balls":true, + "wheel-success":true, + "strategic-focus":true, + "climb-mechanism":true, + "attitude":true + } + } + } + } +}""" + +class ConfigurationError (Exception): + code = None + def __init__(self, str, code): + super().__init__(str) + self.code = code + +def parse_config_persistent(send, config): + + try: + apikey = config["persistent"]["key"]["database"] + except: + raise ConfigurationError("persistent/key/database field is invalid or missing", 111) + try: + tbakey = config["persistent"]["key"]["tba"] + except: + raise ConfigurationError("persistent/key/tba field is invalid or missing", 112) + try: + preference = config["persistent"]["config-preference"] + except: + raise ConfigurationError("persistent/config-preference field is invalid or missing", 113) + try: + sync = config["persistent"]["synchronize-config"] + except: + raise ConfigurationError("persistent/synchronize-config field is invalid or missing", 114) + + if apikey == None or apikey == "": + raise ConfigurationError("persistent/key/database field is empty", 115) + if tbakey == None or tbakey == "": + raise ConfigurationError("persistent/key/tba field is empty", 116) + if preference == None or preference == "": + raise ConfigurationError("persistent/config-preference field is empty", 117) + if sync != True and sync != False: + raise ConfigurationError("persistent/synchronize-config field is empty", 118) + + return apikey, tbakey, preference, sync + +def parse_config_variable(send, config): + + sys_max_threads = os.cpu_count() + try: + cfg_max_threads = config["variable"]["max-threads"] + except: + raise ConfigurationError("variable/max-threads field is invalid or missing, refer to documentation for configuration options", 109) + if cfg_max_threads > -sys_max_threads and cfg_max_threads < 0 : + alloc_processes = sys_max_threads + cfg_max_threads + elif cfg_max_threads > 0 and cfg_max_threads < 1: + alloc_processes = math.floor(cfg_max_threads * sys_max_threads) + elif cfg_max_threads > 1 and cfg_max_threads <= sys_max_threads: + alloc_processes = cfg_max_threads + elif cfg_max_threads == 0: + alloc_processes = sys_max_threads + else: + raise ConfigurationError("variable/max-threads must be between -" + str(sys_max_threads) + " and " + str(sys_max_threads) + ", but got " + cfg_max_threads, 110) + try: + exec_threads = Pool(processes = alloc_processes) + except Exception as e: + send(stderr, INF, e) + raise ConfigurationError("unable to start threads", 200) + send(stdout, INF, "successfully initialized " + str(alloc_processes) + " threads") + + try: + competition = config["variable"]["competition"] + except: + raise ConfigurationError("variable/competition field is invalid or missing", 101) + try: + modules = config["variable"]["modules"] + except: + raise ConfigurationError("variable/modules field is invalid or missing", 102) + + if competition == None or competition == "": + raise ConfigurationError("variable/competition field is empty", 105) + if modules == None: + raise ConfigurationError("variable/modules field is empty", 106) + + send(stdout, INF, "found and loaded competition, match, metrics, pit from config") + + return exec_threads, competition, modules + +def resolve_config_conflicts(send, client, config, preference, sync): + + if sync: + if preference == "local" or preference == "client": + send(stdout, INF, "config-preference set to local/client, loading local config information") + remote_config = get_database_config(client) + if remote_config != config["variable"]: + set_database_config(client, config["variable"]) + send(stdout, INF, "database config was different and was updated") + return config + elif preference == "remote" or preference == "database": + send(stdout, INF, "config-preference set to remote/database, loading remote config information") + remote_config= get_database_config(client) + if remote_config != config["variable"]: + config["variable"] = remote_config + if save_config(config_path, config): + raise ConfigurationError("local config was different but could not be updated", 121) + send(stdout, INF, "local config was different and was updated") + return config + else: + raise ConfigurationError("persistent/config-preference field must be \"local\"/\"client\" or \"remote\"/\"database\"", 120) + else: + if preference == "local" or preference == "client": + send(stdout, INF, "config-preference set to local/client, loading local config information") + return config + elif preference == "remote" or preference == "database": + send(stdout, INF, "config-preference set to remote/database, loading database config information") + config["variable"] = get_database_config(client) + return config + else: + raise ConfigurationError("persistent/config-preference field must be \"local\"/\"client\" or \"remote\"/\"database\"", 120) + +def load_config(path, config_vector): + try: + f = open(path, "r") + config_vector.update(json.load(f)) + f.close() + return 0 + except: + f = open(path, "w") + f.write(sample_json) + f.close() + return 1 + +def save_config(path, config_vector): + f = open(path, "w+") + json.dump(config_vector, f, ensure_ascii=False, indent=4) + f.close() + return 0 \ No newline at end of file diff --git a/src/cli/superscript.py b/src/cli/superscript.py index 755b3b5..e3f138f 100644 --- a/src/cli/superscript.py +++ b/src/cli/superscript.py @@ -152,8 +152,7 @@ __all__ = [ # imports: import json -import math -from multiprocessing import Pool, freeze_support +from multiprocessing import freeze_support import os import pymongo import sys @@ -162,87 +161,12 @@ import traceback import warnings import zmq +from config import parse_config_persistent, parse_config_variable, resolve_config_conflicts, load_config, save_config, ConfigurationError +from data import get_previous_time, set_current_time, check_new_database_matches from interface import splash, log, ERR, INF, stdout, stderr -from data import get_previous_time, set_current_time, get_database_config, set_database_config, check_new_database_matches from module import Match, Metric, Pit -class ConfigurationError (Exception): - code = None - def __init__(self, str, code): - super().__init__(str) - self.code = code - config_path = "config.json" -sample_json = """{ - "persistent":{ - "key":{ - "database":"", - "tba":"" - }, - "config-preference":"local", - "synchronize-config":false - }, - "variable":{ - - "max-threads":0.5, - - "competition":"", - "team":"", - - "event-delay":false, - "loop-delay":0, - "reportable":true, - - "teams":[], - - "modules":{ - - "match":{ - "tests":{ - "balls-blocked":["basic_stats","historical_analysis","regression_linear","regression_logarithmic","regression_exponential","regression_polynomial","regression_sigmoidal"], - "balls-collected":["basic_stats","historical_analysis","regression_linear","regression_logarithmic","regression_exponential","regression_polynomial","regression_sigmoidal"], - "balls-lower-teleop":["basic_stats","historical_analysis","regression_linear","regression_logarithmic","regression_exponential","regression_polynomial","regression_sigmoidal"], - "balls-lower-auto":["basic_stats","historical_analysis","regression_linear","regression_logarithmic","regression_exponential","regression_polynomial","regression_sigmoidal"], - "balls-started":["basic_stats","historical_analyss","regression_linear","regression_logarithmic","regression_exponential","regression_polynomial","regression_sigmoidal"], - "balls-upper-teleop":["basic_stats","historical_analysis","regression_linear","regression_logarithmic","regression_exponential","regression_polynomial","regression_sigmoidal"], - "balls-upper-auto":["basic_stats","historical_analysis","regression_linear","regression_logarithmic","regression_exponential","regression_polynomial","regression_sigmoidal"] - } - - }, - - "metric":{ - "tests":{ - "elo":{ - "score":1500, - "N":400, - "K":24 - }, - "gl2":{ - "score":1500, - "rd":250, - "vol":0.06 - }, - "ts":{ - "mu":25, - "sigma":8.33 - } - } - }, - - "pit":{ - "tests":{ - "wheel-mechanism":true, - "low-balls":true, - "high-balls":true, - "wheel-success":true, - "strategic-focus":true, - "climb-mechanism":true, - "attitude":true - } - } - } - } -}""" def main(send, verbose = False, profile = False, debug = False): @@ -355,128 +279,6 @@ def main(send, verbose = False, profile = False, debug = False): return exit_code -def parse_config_persistent(send, config): - - try: - apikey = config["persistent"]["key"]["database"] - except: - raise ConfigurationError("persistent/key/database field is invalid or missing", 111) - try: - tbakey = config["persistent"]["key"]["tba"] - except: - raise ConfigurationError("persistent/key/tba field is invalid or missing", 112) - try: - preference = config["persistent"]["config-preference"] - except: - raise ConfigurationError("persistent/config-preference field is invalid or missing", 113) - try: - sync = config["persistent"]["synchronize-config"] - except: - raise ConfigurationError("persistent/synchronize-config field is invalid or missing", 114) - - if apikey == None or apikey == "": - raise ConfigurationError("persistent/key/database field is empty", 115) - if tbakey == None or tbakey == "": - raise ConfigurationError("persistent/key/tba field is empty", 116) - if preference == None or preference == "": - raise ConfigurationError("persistent/config-preference field is empty", 117) - if sync != True and sync != False: - raise ConfigurationError("persistent/synchronize-config field is empty", 118) - - return apikey, tbakey, preference, sync - -def parse_config_variable(send, config): - - sys_max_threads = os.cpu_count() - try: - cfg_max_threads = config["variable"]["max-threads"] - except: - raise ConfigurationError("variable/max-threads field is invalid or missing, refer to documentation for configuration options", 109) - if cfg_max_threads > -sys_max_threads and cfg_max_threads < 0 : - alloc_processes = sys_max_threads + cfg_max_threads - elif cfg_max_threads > 0 and cfg_max_threads < 1: - alloc_processes = math.floor(cfg_max_threads * sys_max_threads) - elif cfg_max_threads > 1 and cfg_max_threads <= sys_max_threads: - alloc_processes = cfg_max_threads - elif cfg_max_threads == 0: - alloc_processes = sys_max_threads - else: - raise ConfigurationError("variable/max-threads must be between -" + str(sys_max_threads) + " and " + str(sys_max_threads) + ", but got " + cfg_max_threads, 110) - try: - exec_threads = Pool(processes = alloc_processes) - except Exception as e: - send(stderr, INF, e) - raise ConfigurationError("unable to start threads", 200) - send(stdout, INF, "successfully initialized " + str(alloc_processes) + " threads") - - try: - competition = config["variable"]["competition"] - except: - raise ConfigurationError("variable/competition field is invalid or missing", 101) - try: - modules = config["variable"]["modules"] - except: - raise ConfigurationError("variable/modules field is invalid or missing", 102) - - if competition == None or competition == "": - raise ConfigurationError("variable/competition field is empty", 105) - if modules == None: - raise ConfigurationError("variable/modules field is empty", 106) - - send(stdout, INF, "found and loaded competition, match, metrics, pit from config") - - return exec_threads, competition, modules - -def resolve_config_conflicts(send, client, config, preference, sync): - - if sync: - if preference == "local" or preference == "client": - send(stdout, INF, "config-preference set to local/client, loading local config information") - remote_config = get_database_config(client) - if remote_config != config["variable"]: - set_database_config(client, config["variable"]) - send(stdout, INF, "database config was different and was updated") - return config - elif preference == "remote" or preference == "database": - send(stdout, INF, "config-preference set to remote/database, loading remote config information") - remote_config= get_database_config(client) - if remote_config != config["variable"]: - config["variable"] = remote_config - if save_config(config_path, config): - raise ConfigurationError("local config was different but could not be updated", 121) - send(stdout, INF, "local config was different and was updated") - return config - else: - raise ConfigurationError("persistent/config-preference field must be \"local\"/\"client\" or \"remote\"/\"database\"", 120) - else: - if preference == "local" or preference == "client": - send(stdout, INF, "config-preference set to local/client, loading local config information") - return config - elif preference == "remote" or preference == "database": - send(stdout, INF, "config-preference set to remote/database, loading database config information") - config["variable"] = get_database_config(client) - return config - else: - raise ConfigurationError("persistent/config-preference field must be \"local\"/\"client\" or \"remote\"/\"database\"", 120) - -def load_config(path, config_vector): - try: - f = open(path, "r") - config_vector.update(json.load(f)) - f.close() - return 0 - except: - f = open(path, "w") - f.write(sample_json) - f.close() - return 1 - -def save_config(path, config_vector): - f = open(path, "w+") - json.dump(config_vector, f, ensure_ascii=False, indent=4) - f.close() - return 0 - def start(pid_path, verbose = False, profile = False, debug = False): if profile: