import os import json import logging import threading import toml import websocket import queue from colorama import Fore, Back, Style, init as colorama_init, ansi as colorama_ansi import app contentapi = app.loadmod("contentapi") utils = app.loadmod("utils") def appInit(): # This is ran after all modules are loaded global frontend frontend = app.mod["frontend"] VERSION=(0,2,0) # Arbitrary but whatever CONFIGFILE="config.toml" # The entire config object with all defaults config = { "api" : "http://localhost:5000/api", "default_loglevel" : "WARNING", "websocket_trace" : False, "default_room" : 0, # Zero means it will ask you for a room "default_markup" : "plaintext", "expire_seconds" : 31536000, # 365 days in seconds, expiration for token "appear_in_global" : False, "print_status_after_insert" : True, "output_buffer_timeout" : 0.05, # 50 milliseconds "default_history" : 100, "fixed_width" : 76, # Need room for the pre-message decoration "tokenfile" : ".qcstoken" } # Loads the config from file into the global config var. If the file # doesn't exist, the file is created from the defaults in config. # The function returns nothing def load_or_create_global_config(): global config # Check if the config file exists if os.path.isfile(CONFIGFILE): # Read and deserialize the config file with open(CONFIGFILE, 'r', encoding='utf-8') as f: temp_config = toml.load(f) utils.merge_dictionary(temp_config, config) else: # Serialize and write the config dictionary to the config file logging.warn("No config found at " + CONFIGFILE + ", creating now") with open(CONFIGFILE, 'w', encoding='utf-8') as f: toml.dump(config, f) utils.set_logging_level(config["default_loglevel"]) def main(): print("Program start: %s" % ".".join(map(str,VERSION))) colorama_init() # colorama init load_or_create_global_config() logging.info("Config: " + json.dumps(config, indent = 2)) # Let users debug the websocket if they want I guess if config["websocket_trace"]: websocket.enableTrace(True) context = contentapi.ApiContext(config["api"], logging) frontend.main(config,context) authenticate(config, context) ws = websocket.WebSocketApp(context.websocket_endpoint()) # Might as well reuse the websocket object for my websocket context data (oops, is that bad?) ws.context = context ws.user_info = context.user_me() ws.main_config = config ws.ignored = {} # Just a tracking list for fun stats # Output from the websocket can only get truly printed to the screen when this lock is released. # We grab the lock when the user is in some kind of "input" mode, which blocks the websocket printing # thread from processing the queue (if it has anything anyway) ws.output_lock = threading.Lock() # Output from the websocket is ALWAYS buffered, and we use a thread-safe queue to add and remove # output safely. We buffer all messages to ensure the order is preserved; if we SOMETIMES queued and # SOMETIMES did not, we would need to be very careful about whether the queue was empty, which requires # additional locking and etc. ws.output_buffer = queue.Queue() # Note that the current_room stuff is set on open if you've supplied a default room in config ws.current_room = 0 ws.current_room_data = False # set the callback functions ws.on_open = app.mod["frontend"].ws_onopen ws.on_close = app.mod["frontend"].ws_onclose ws.on_message = app.mod["frontend"].ws_onmessage ws.run_forever() print("Program end") # Either pull the token from a file, or get the login from the command # line if that doesn't work. WILL test your token against the real API # even if it's pulled from file! def authenticate(config, context: contentapi.ApiContext): message = "No token file found" if os.path.isfile(config["tokenfile"]): with open(config["tokenfile"], 'r') as f: token = f.read() logging.debug("Token from file: " + token) context.token = token if context.is_token_valid(): logging.info("Logged in using token file " + config["tokenfile"]) return else: message = "Token file expired" message += ", Please enter login for " + config["api"] frontend.authenticate(context,message)