from pickle import dumps from random import choice from time import sleep from twisted.internet import reactor, tksupport, defer from twisted.internet.endpoints import TCP4ServerEndpoint, TCP4ClientEndpoint from structures.protocol import TCPFactory from structures.input_handling import InputHandling from structures.handling_recieve import MouseKeyboardHandler from structures.share_screen_handler import ScreenShareHandler from .auth_handler import AuthHandler from .file_handler import FileHandler from socket import gethostname, gethostbyname_ex from io import BytesIO class App: def __init__(self): self.debug = False self.mode = None self.protocol = None self.screen_share_protocol = None self._handlers = {} self._listeners = [] self._delisteners = [] self.host = self.get_host() self.port = 5005 self.screen_share_port = 5006 self.running = False self.pass_code = None self.authenticated = False self.auth_handler = AuthHandler(self) self.screen_share_handler = ScreenShareHandler(self) self.file_handler = FileHandler(self) def setMode(self, mode): if mode == "server" or mode == "client": self.mode = mode else: raise Exception(f"Invalid mode: {mode}") def handlerManagerReceive(self, message): if message == "file_dialog_open": self.screen_share_handler.active = False elif message == "file_dialog_close": self.screen_share_handler.active = True def addHandler(self, event_name, fn): self._handlers[event_name] = fn def useHandler(self, event_name, *args): self._handlers[event_name](*args) def getHandlerNames(self): return self._handlers.keys() def addListener(self, listener): self._listeners.append(listener) def addDelistener(self, delistener): self._delisteners.append(delistener) def listen(self): for listener in self._listeners: reactor.callInThread(listener) def startGUI(self, gui): tksupport.install(gui.server_root if self.mode == "server" else gui.client_root) def send(self, event, *args): MAX_MSG_SIZE = 1024 # Assuming MAX_MSG_SIZE is defined elsewhere data = dumps({"event": event, "args": args}) if len(data) <= MAX_MSG_SIZE: # Message fits within limit, send directly prefix = f"##HEAD{event:<10}{0:<4}{1:<4}##" msg = prefix.encode() + data + b"##FRAMEEND##" self.protocol.transport.write(msg) else: # Message exceeds limit, fragment and send num_chunks = (len(data) // MAX_MSG_SIZE) + 1 # Calculate number of chunks for chunk_num in range(num_chunks): start = chunk_num * MAX_MSG_SIZE end = min(start + MAX_MSG_SIZE, len(data)) chunk = data[start:end] # Prefix with event name and chunk number for reassembly prefix = f"##HEAD{event:<10}{chunk_num:<4}{num_chunks:<4}##" msg = prefix.encode() + chunk + b"##FRAMEEND##" self.protocol.transport.write(msg) def start(self): self.running = True if self.mode == "server": mouse_keyboard_handler = MouseKeyboardHandler() self.addHandler("HANDLER", self.handlerManagerReceive) self.addHandler("MOUSE", mouse_keyboard_handler.mouse) self.addHandler("KEYBOARD", mouse_keyboard_handler.keyboard) self.addHandler("FILE", self.file_handler.receive_file) self.addListener(self.screen_share_handler.capture_and_send) endpoint = TCP4ServerEndpoint(reactor, self.port) endpoint.listen(TCPFactory(self)) screen_share_endpoint = TCP4ServerEndpoint(reactor, self.screen_share_port) screen_share_endpoint.listen(TCPFactory(self, True)) if self.debug: print("DEBUG: Started TCP Server") elif self.mode == "client": inputhandling = InputHandling(self) self.addListener(inputhandling.start) self.addDelistener(inputhandling.stopListening) self.addHandler("SCREEN", self.screen_share_handler.receive) endpoint = TCP4ClientEndpoint(reactor, self.host, self.port) endpoint.connect(TCPFactory(self)) screen_share_endpoint = TCP4ClientEndpoint(reactor, self.host, self.screen_share_port) screen_share_endpoint.connect(TCPFactory(self, True)) if self.debug: print("DEBUG: Started TCP Client") else: raise Exception(f"Invalid mode: {self.mode}") self.listen() reactor.run() def stop(self): if self.running: for delistener in self._delisteners: delistener() # reactor.getThreadPool().stop() # self.protocol.transport.loseConnection() # self.screen_share_protocol.transport.loseConnection() reactor.stop() self.running = False exit() def generate_pass_code(self): digits = "0123456789abcdef" code = "" for _ in range(6): code += choice(digits) self.pass_code = code return code def get_link(self): return f"{self.host}?p={self.pass_code}" def get_host(self): ips = gethostbyname_ex(gethostname())[2] for ip in ips: if ip.split(".")[2] == "1": return ip return ips[1]