chatServer/clientBlaster.py
2021-04-09 23:46:19 +02:00

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()