#!/usr/bin/env python3 import sys oldexcepthook = sys.excepthook def newexcepthook(type,value,traceback): oldexcepthook(type,value,traceback) input("Press ENTER to quit.") sys.excepthook = newexcepthook import os p = os.path.join pUp = os.path.dirname s = False if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'): s = os.path.realpath(sys.executable) else: s = os.path.realpath(__file__) sp = pUp(s) # script start import threading import socket import struct import time addr = ("127.0.0.1",21779) threads = {} threadId = 0 threadsLock = threading.Lock() close = False eventHandlers = {} eventHandlersLock = threading.Lock() def runCode(str, lcs = False, description = "loose-code"): if lcs == False: lcs = {} code = compile(str,description,"exec") exec(code,globals(),lcs) return lcs def runScript(sf, lcs = False): if lcs == False: lcs = {} with open(sf) as script: runCode(script.read(),lcs,sf) return lcs def getModlist(path): modList = [] for root,dirs,files in os.walk(path): for file in dirs: ffile = p(root,file) lfile = ffile.replace(path + os.path.sep,"",1) if lfile[0] == "-": continue if lfile[0] == "[" and lfile[-1] == "]": modList = modList + sorted(getModlist(ffile)) continue modList.append(ffile) break return modList def triggerEvent(event,*args,**kwargs): with eventHandlersLock: handlers = eventHandlers.copy() if not event in handlers: return for func in handlers[event]: cancel = func(event,*args,**kwargs) if cancel: return True return False def addEventHandler(event,func): with eventHandlersLock: if not event in eventHandlers: eventHandlers[event] = [] eventHandlers[event].append(func) def sendResponse(connection,data): connection.sendall(len(data).to_bytes(4,"big") + data) senderThreadSleepMin = 0.0333 senderThreadSleepMax = 1.0 senderThreadSleepIncr = 0.01 class senderThread(threading.Thread): def __init__(self,connectionThread): threading.Thread.__init__(self) self.lock = threading.Lock() with self.lock: self.connectionThread = connectionThread self.queue = [] self.newQueue = False self.sleep = senderThreadSleepMin def closeThread(self): with self.lock: self.queue = [["close"]] self.newQueue = True def addToQueue(self,entry): with self.lock: self.queue.append(entry) self.newQueue = True def run(self): sleepTime = 0 while True: with self.lock: sleepTime = self.sleep #print(sleepTime) time.sleep(sleepTime) with self.lock: if not self.newQueue: if self.sleep < senderThreadSleepMax: self.sleep += senderThreadSleepIncr * self.sleep if self.sleep > senderThreadSleepMax: self.sleep = senderThreadSleepMax continue for entry in self.queue: if entry[0] == "close": return entry[0](*entry[1],**entry[2]) self.queue = [] self.newQueue = False self.sleep = senderThreadSleepMin class connectionThread(threading.Thread): def __init__(self,threadId,connection,address): threading.Thread.__init__(self) self.lock = threading.Lock() with self.lock: self.threadId = threadId self.connection = connection self.address = address self.closed = False self.user = False self.senderThread = senderThread(self) self.senderThread.start() def closeThread(self): with self.lock, threadsLock: self.senderThread.closeThread() try: self.connection.close() except: print("failed to close connection, ignoring.") pass del threads[str(self.threadId)] print("thread closed: " +str(self.threadId)+ " (open: " +str(len(threads))+ ")") self.closed = True def sendResponse(self,data,lock = True): if lock == True: with self.lock: self.senderThread.addToQueue([sendResponse,[self.connection,data],{}]) else: self.senderThread.addToQueue([sendResponse,[self.connection,data],{}]) def run(self): with self.lock: print("thread opened: " +", ".join((str(self.threadId),str(self.address)))) while True: try: # get request length data = b'' data = self.connection.recv(4) if not data: self.closeThread() return requestLength = int.from_bytes(data,"big") # inform about request cancel = triggerEvent("onPreRequest",self,requestLength) with self.lock: if self.closed: return if cancel: continue # process request cancel = triggerEvent("onRequest",self,requestLength) with self.lock: if self.closed: return if cancel: continue except Exception as e: cancel = False try: cancel = triggerEvent("onException",self,e) except: self.closeThread() raise if cancel: continue self.closeThread() raise e modulesLoaded = [] modulePath = p(sp,"modules") def moduleRun(localModule): if not localModule in modulesLoaded: modulesLoaded.append(localModule) print("> " +localModule+ "...") runScript(p(modulePath,localModule,"module.py")) def moduleDepends(localModules): if type(localModules) == str: localModules = [localModules] for localModule in localModules: if localModule in modulesLoaded: return print("depend ",end="") moduleRun(localModule) def main(): print("Loading modules...") for path in getModlist(modulePath): if os.path.isfile(p(path,"module.py")): localModule = path.replace(modulePath + os.path.sep,"",1) if not localModule in modulesLoaded: moduleRun(localModule) print("\nServing on " +":".join(map(str,addr))+ "!") global socketServer socketServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM) socketServer.bind(addr) socketServer.listen(1000) global threadId global close while True: connection, address = socketServer.accept() # inform about connection with threadsLock: if close: break cancel = triggerEvent("onConnect",connection,address) if close: break if cancel: continue threadId += 1 while str(threadId) in threads: threadId += 1 thread = connectionThread(threadId,connection,address) threads[str(threadId)] = thread thread.start() if __name__ == '__main__': main()