255 lines
6.0 KiB
Python
255 lines
6.0 KiB
Python
#!/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() |