Recent attempts at actual locking

This commit is contained in:
Carlos Sanchez 2023-05-01 18:44:14 -04:00
parent 4f3c0fe8cd
commit 8d9771a715

32
main.py
View File

@ -18,10 +18,9 @@ from colorama import Fore, Back, Style, init as colorama_init
import contentapi
import myutils
VERSION="0.1.0" # Arbitrary but whatever
VERSION="0.1.1" # Arbitrary but whatever
CONFIGFILE="config.toml"
MAXTITLE=25
MAXMESSAGEWIDTH=80 # May instead check the console window
MSGPREFIX=Back.GREEN + " " + Back.RESET + " "
# The entire config object with all defaults
@ -34,6 +33,8 @@ config = {
"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
"fixed_width" : 78, # Need room for the pre-message decoration
"tokenfile" : ".qcstoken"
}
@ -71,7 +72,7 @@ def main():
# 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.pause_output = False # Whether all output from the websocket should be paused (including status updates)
ws.output_lock = threading.Lock()
ws.output_buffer = [] # Individual print statements buffered from output.
ws.main_config = config
ws.current_room = 0
@ -109,10 +110,8 @@ def ws_onopen(ws):
# The infinite input loop! Or something!
while True:
ws.pause_output = False # Allow arbitrary output again. Do this BEFORE other stuff for race conditions
# We can be certain that at this point, there is no user input (because this loop is all there is)
# As such, just dump the buffer
# Dump the buffer, if there is any, since we're outside of user input
with ws.output_lock:
for output in ws.output_buffer:
printr(output)
@ -123,6 +122,8 @@ def ws_onopen(ws):
printstatus = False # Assume we are not printing the status every time (it's kinda annoying)
# Listen for a key. The implementation of 'readkey()' on this version of python and windows makes the CPU spike
# to 100%, so we switch to getch() if we detect windows.
if platform.system().startswith("Windows"):
import msvcrt
logging.debug("on windows, using msvcrt.getch")
@ -130,8 +131,9 @@ def ws_onopen(ws):
else:
key = readchar.readkey()
ws.pause_output = True # Disable output for the duration of input handling
# We get exclusive access to output while we're handling user input. This allows us to "pause/buffer" the
# output that might come from websocket events
with ws.output_lock:
if key == "h":
print(" -- Help menu / Controls --")
for key, value in commands.items():
@ -211,7 +213,7 @@ def ws_onmessage(ws, message):
user = contentapi.get_user_or_default(objects["user"], message["createUserId"])
ws_print(ws, MSGPREFIX + Fore.CYAN + Style.BRIGHT + user["username"] + " " + Style.DIM + "#%d" % user["id"] +
Fore.MAGENTA + " " + message["createDate"] + " [%d]" % message["id"])
for t in textwrap.wrap(message["text"], width = MAXMESSAGEWIDTH):
for t in textwrap.wrap(message["text"], width = ws.main_config["fixed_width"]):
ws_print(ws, MSGPREFIX + t)
# Track ignored data
@ -223,10 +225,14 @@ def ws_onmessage(ws, message):
# Printing websocket event output is tricky because we don't want to interrupt user input (we don't have
# curses). As such, we must buffer our output IF we are asked to pause
def ws_print(ws, output):
if ws.pause_output:
ws.output_buffer.append(output)
else:
# We can't block output for too long, so we need to only try to acquire the lock for a very short time
if ws.output_lock.acquire(timeout=ws.main_config["output_buffer_timeout"]):
try:
printr(output)
finally:
ws.output_lock.release()
else:
ws.output_buffer.append(output)
# Loads the config from file into the global config var. If the file