154 lines
5.6 KiB
Python
154 lines
5.6 KiB
Python
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]
|
|
if len(ips) > 1:
|
|
for ip in ips:
|
|
if ip.split(".")[2] == "1":
|
|
return ip
|
|
return ips[0]
|