import asyncio import json import os import secrets import signal import subprocess import websockets import shutil from connect4 import PLAYER1, PLAYER2, Connect4 from user import User import requests from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler from bs4 import BeautifulSoup from urllib.parse import urlparse, urljoin import math def is_absolute(url): return bool(urlparse(url).netloc) def handle_protocol_relative(url, base_url): if url.startswith("//"): parsed_base_url = urlparse(base_url) return f"{parsed_base_url.scheme}:{url}" return url def inline_resources(soup, base_url): # Inline CSS for link_tag in soup.find_all('link', rel='stylesheet'): href = link_tag.get('href') if href: href = handle_protocol_relative(href, base_url) full_url = urljoin(base_url, href) if not is_absolute(href) else href css_response = requests.get(full_url) if css_response.status_code == 200: style_tag = soup.new_tag('style') style_tag.string = css_response.text link_tag.replace_with(style_tag) # Inline JavaScript for script_tag in soup.find_all('script', src=True): src = script_tag.get('src') if src: src = handle_protocol_relative(src, base_url) full_url = urljoin(base_url, src) if not is_absolute(src) else src js_response = requests.get(full_url) if js_response.status_code == 200: script_tag.string = js_response.text del script_tag['src'] return soup async def send_html_chunks(websocket, soup): # Convert the BeautifulSoup object back to a string and split into lines html_str = str(soup) lines = html_str.split('\n') # Send each line as a separate chunk for line in lines: line = line.strip() if line: # Send non-empty lines await websocket.send(json.dumps({"type": "chunk", "content": line})) await websocket.send(json.dumps({"type": "end",})) # async def send_html_chunks(ws, html_data, chunk_size=1024): # # Split the HTML data into chunks # total_chunks = math.ceil(len(html_data) / chunk_size) # for i in range(total_chunks): # start = i * chunk_size # end = min(start + chunk_size, len(html_data)) # chunk = html_data[start:end] # # Send the chunk with chunk number and total chunks information # chunk_message = f"chunk_{i+1}/{total_chunks}:{chunk}" # await ws.send(chunk_message.encode()) # # Wait for a short interval before sending the next chunk # await asyncio.sleep(0.1) # Adjust as needed def auto_detect_mode(content): if isinstance(content, str): return 'w' # If content is a string, it's text elif isinstance(content, bytes): return 'wb' # If content is bytes, it's binary else: raise ValueError("Unsupported content type. Expected str or bytes.") class FileHandler(FileSystemEventHandler): def __init__(self, websocket,connected): super().__init__() self.websocket = websocket self.connected = connected def on_modified(self, event): if event.is_directory: return with open(event.src_path, 'r', encoding='utf-8') as file: content = file.read() print(f'File {event.src_path} has been modified.') new_event = { "type": "file-modifie", "content": content, "path": event.src_path, } websockets.broadcast(self.connected,json.dumps(new_event)) # websockets.broadcast(self.connected,f'File {event.src_path} has been modified.') def on_created(self, event): if event.is_directory: new_event = { "type": "folder-create", "path": event.src_path, "name": event.src_path.split('/')[-1] } # print(new_event) websockets.broadcast(self.connected,json.dumps(new_event)) else: with open(event.src_path, 'r', encoding='utf-8') as file: content = file.read() print(f'File {event.src_path} has been created.') new_event = { "type": "file-create", "content": content, "path": event.src_path, "name": event.src_path.split('/')[-1] } # print(new_event) websockets.broadcast(self.connected,json.dumps(new_event)) # websockets.broadcast(self.connected,f'File {event.src_path} has been created.') def on_deleted(self, event): if event.is_directory: new_event = { "type": "delete", "path": event.src_path, "name": event.src_path.split('/')[-1], } websockets.broadcast(self.connected,json.dumps(new_event)) else: print(f'File {event.src_path} has been deleted.') new_event = { "type": "delete", "name": event.src_path.split('/')[-1], "path": event.src_path, } print(event.src_path) websockets.broadcast(self.connected,json.dumps(new_event)) def on_moved(self, event): if event.is_directory: new_event = { "type": "rename", "OldPath": event.src_path, "oldname": event.src_path.split('/')[-1], "NewPath": event.dest_path, "newname": event.dest_path.split('/')[-1], } websockets.broadcast(self.connected,json.dumps(new_event)) else: # print(f'File {event.src_path} has been renamed to {event.dest_path}.') new_event = { "type": "rename", "OldPath": event.src_path, "oldname": event.src_path.split('/')[-1], "NewPath": event.dest_path, "newname": event.dest_path.split('/')[-1], } websockets.broadcast(self.connected,json.dumps(new_event)) JOIN = {} WATCH = {} async def generate_file_structure(path, encoding='utf-8'): file_structure = {'name': os.path.basename(path), 'type': 'folder', 'path': path, 'children': []} try: entries = os.listdir(path) except FileNotFoundError: return file_structure # Return an empty structure for non-existing directories for entry in entries: entry_path = os.path.join(path, entry) if os.path.isdir(entry_path): child_structure =await generate_file_structure(entry_path, encoding) file_structure['children'].append(child_structure) elif os.path.isfile(entry_path): try: with open(entry_path, 'r', encoding=encoding) as file: content = file.read() except UnicodeDecodeError: content = 'Unable to read content' file_structure['children'].append({'name': entry, 'type': 'file', 'path': entry_path, 'content': content}) return file_structure async def rename_item(websocket, key,project_name, path,rpath,new_name,root, connected): old_path = os.path.join(os.getcwd(),'projects', key,project_name, rpath) new_name = new_name new_path = os.path.join(os.path.dirname(old_path), new_name) try: if os.path.exists(old_path): # Determine the new path # Rename the file or folder os.rename(old_path, new_path) websockets.broadcast(connected,'success') event = { "type": "rename-success", "data": f'{old_path}-->{new_path}', "path": path, "new_rpath":rpath, "name": new_name, "root":root, } websockets.broadcast(connected,json.dumps(event)) else: event = { "type": "rename-failed", "data": f'{old_path}-->{new_path} failed Item not found', "old_path": path, "new_name": new_name, } websockets.broadcast(connected,json.dumps(event)) except Exception as e: websockets.broadcast(connected,str(e)) async def delete_item(websocket, key,project_name, path,rpath,targetElementData, connected): try: item_path = os.path.join(os.getcwd(), 'projects', key,project_name, rpath) if os.path.exists(item_path): if os.path.isdir(item_path): shutil.rmtree(item_path) # Remove the directory and its contents elif os.path.isfile(item_path): os.remove(item_path) # Remove the file event = { "type": "delete-success", "data": path, "path":path, "targetElementData":targetElementData, } # print(event) websockets.broadcast(connected,json.dumps(event)) # websockets.broadcast(connected,'success') else: event = { "type": "delete-failed", "data": f'{item_path} Item not found', } websockets.broadcast(connected,json.dumps(event)) except Exception as e: # print(e) websockets.broadcast(connected,str(e)) async def get_file_content(websocket, key,project_name, path,rpath,name,connected): file_path = os.path.join(os.getcwd(), 'projects', key,project_name, rpath) try: try: with open(file_path, 'r') as file: content = file.read() event = { "type": "content", "content": content, 'fileName':name, 'rfilePath':rpath, 'filePath':path, } await websocket.send(json.dumps(event)) except UnicodeDecodeError: with open(file_path, 'rb') as file: content = file.read() event = { "type": "content", "content": content, 'fileName':name, 'rfilePath':rpath, 'filePath':path, } await websocket.send(json.dumps(event)) except Exception as e: event = { "type": "error", "message": f"Failed to read file content: {str(e)}", } await websocket.send(json.dumps(event)) async def create_file(websocket, key,project_name, path,name,root,targetElementData,rpath, connected): file_path = os.path.join(os.getcwd(), 'projects', key,project_name, rpath,name) # Create the file with open(file_path, 'w'): pass event = { "type": "file-created", "data": file_path, "path": path, "name": name, "root":root, "targetElementData":targetElementData, } websockets.broadcast(connected,json.dumps(event)) async def create_folder(websocket, key,project_name, path,name,root,targetElementData,rpath, connected): folder_path = os.path.join(os.getcwd(), 'projects', key,project_name, rpath,name) # Create the folder os.makedirs(folder_path) event = { "type": "folder-created", "data": folder_path, "path": path, "name": name, "root":root, "targetElementData":targetElementData, } # print(folder_path,'created') websockets.broadcast(connected,json.dumps(event)) async def wirte_file(websocket, key,project_name, path, content, connected): try: file_path = os.path.join(os.getcwd(), 'projects', key,project_name, path) file_content = content mode = auto_detect_mode(content) with open(file_path, mode) as file: file.write(file_content) event = { "type": "write-success", "data": file_path, "path": path, "content": content, } # websockets.broadcast(connected,json.dumps(event)) except FileNotFoundError as e: event = { "type": "write-error", "data": e, } websockets.broadcast(connected,json.dumps(event)) async def read_process_output(process, websocket): # Read the output and error byte by byte and print word by word word = b'' while True: char = await process.stdout.read(1) if char == b'\n': if word: print(word.decode('utf-8'),1) event = { "type": "terminal-data", "data": word.decode('utf-8'), } print('sending data',1) await websocket.send(json.dumps(event)) word = b'' print("line is completed") event = { "type": "terminal-newline", "data": "", } await websocket.send(json.dumps(event)) elif char == b' ': if word: print(word.decode('utf-8'),2) event = { "type": "terminal-data", "data": word.decode('utf-8'), } print('sending data',2) await websocket.send(json.dumps(event)) word = b'' print("space is occurred") event = { "type": "terminal-data", "data": " ", } print('sending data',3) await websocket.send(json.dumps(event)) elif char == b'': if word: print(word.decode('utf-8'),3) event = { "type": "terminal-data", "data": word.decode('utf-8'), } print('sending data',4) await websocket.send(json.dumps(event)) break else: word += char while True: char = await process.stderr.read(1) if char == b'\n': if word: print(word.decode('utf-8')) event = { "type": "terminal-error", "data": word.decode('utf-8'), } await websocket.send(json.dumps(event)) word = b'' print("line is completed") event = { "type": "terminal-newline", "data": "", } await websocket.send(json.dumps(event)) elif char == b' ': if word: print(word.decode('utf-8')) event = { "type": "terminal-error", "data": word.decode('utf-8'), } await websocket.send(json.dumps(event)) word = b'' print("space is occurred") event = { "type": "terminal-error", "data": " ", } await websocket.send(json.dumps(event)) elif char == b'': if word: print(word.decode('utf-8')) break else: word += char # async for line in process.stdout: # # print('sending line') # event = { # "type": "terminal-data", # "data": line.strip().decode('utf-8'), # } # await websocket.send(json.dumps(event)) # async for line in process.stderr: # # print(f'error:{line.strip()}') # event = { # "type": "terminal-error", # "data": line.strip().decode('utf-8'), # } # await websocket.send(json.dumps(event)) async def handle_user_input(websocket,key, process, connected,process_ids): while True: try: await asyncio.sleep(0.1) if process.returncode is not None: break # message = await websocket.recv() async for message in websocket: # user_input = json.loads(message) # print(user_input) # print(f'Received user input: {user_input["command"]["command"]}') # process_input(user_input["command"]["command"], process) event = json.loads(message) assert event["type"] == "cmd" # command = event["command"] print(f'Received user input: {event}') try: if event["command"]["type"]=="shell": await asyncio.sleep(0.1) if process.returncode is not None: base_path = os.path.join(os.getcwd(), 'projects', key,event["project_name"]) directory_path = base_path event_handler = FileHandler(websocket,connected) observer = Observer() observer.schedule(event_handler, path=directory_path, recursive=True) observer.start() try: # await execute_command(websocket, key,event["project_name"], event["command"]["command"], connected) # base_path = os.path.join(os.getcwd(), 'projects', key,event["project_name"]) print(base_path) mod_command = f'cd {base_path} && {event["command"]["command"]}' print(mod_command) try: process = await asyncio.create_subprocess_shell( mod_command, # cwd=base_path, stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, # text=True, ) id=process.pid process_ids.append(id) async def send_message(message): # print('sending msg') # await websocket.send(f'data: {message}') websockets.broadcast(connected,json.dumps(message) ) await asyncio.gather( handle_user_input(websocket,key, process, connected,process_ids), read_process_output(process, websocket) ) return_code = await process.wait() if return_code == 0: event = { "type": "terminal-data-end", } await websocket.send(json.dumps(event)) else: event = { "type": "terminal-data-end", } await websocket.send(json.dumps(event)) process_ids.remove(id) except Exception as e: await error(websocket, str(e)) except KeyboardInterrupt: pass # Handle KeyboardInterrupt to gracefully stop the observer observer.stop() observer.join() else: await process_input(event["command"]["command"], process) elif event["command"]["type"]=="write": await wirte_file(websocket, key,event["project_name"], event["path"], event["content"], connected) elif event["command"]["type"] == "curl": method = event.get("method", "GET") url = event["url"] body = event.get("data", "") headers = event.get("headers", {}) if method.upper() == "GET": response = requests.get(url, headers=headers) elif method.upper() == "POST": response = requests.post(url, data=body, headers=headers) else: response = {"error": "Unsupported method"} if isinstance(response, dict): response_data = { "type": "error", "data": response, } await websocket.send(json.dumps(response_data)) return # Parse HTML content souptmp = BeautifulSoup(response.text, "html.parser") # Step 1: Define the initial HTML string html_str = """

Hello, World!

""" # Step 2: Parse the initial HTML content soup = BeautifulSoup(html_str, 'html.parser') # Step 3: Replace the existing body content with the new content from souptmp if soup.body: soup.body.clear() soup.body.append(souptmp) else: print("No tag found in the HTML") # Inline CSS and JavaScript soup = inline_resources(soup, url) response_data = { "type": "web-data", "data": str(soup), } await websocket.send(json.dumps(response_data)) # Convert the final soup to a string elif event["command"]["type"]=="create": if event["item"]=="folder": await create_folder(websocket, key,event["project_name"], event["path"],event["name"],event['root'],event['targetElementData'],event["rpath"], connected) else: await create_file(websocket, key,event["project_name"], event["path"],event["name"],event['root'],event['targetElementData'],event["rpath"], connected) elif event["command"]["type"]=="delete": await delete_item(websocket, key,event["project_name"], event["path"],event['rpath'],event['targetElementData'], connected) elif event["command"]["type"]=="get_content": await get_file_content(websocket, key,event["project_name"],event["filePath"], event["rfilePath"],event["fileName"] ,connected) elif event["command"]["type"]=="rename": await rename_item(websocket, key,event["project_name"], event["path"],event['rpath'], event["name"], event["root"], connected) elif event["command"]["type"]=="join": await join(websocket, event["join"]) elif event["command"]["type"]=="sendDir": data=json.loads(event["file_structure"]) event = { "type": "createDir", "path": data, "root":event['root'], } # websockets.broadcast(connected,json.dumps(event)) websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="createItemUI": event = { "type": "createItemUI", 'targetElementData':event['targetElementData'], 'data':event['data'] } # websockets.broadcast(connected,json.dumps(event)) websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="renameItemInUI": event = { "type": "renameItemInUI", 'path':event['path'], 'new_path':event['new_path'], 'name':event['name'], 'new_rpath':event['new_rpath'], } # websockets.broadcast(connected,json.dumps(event)) websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="createFolderUI": event = { "type": "createFolderUI", 'targetElementData':event['targetElementData'], 'data':event['data'] } # websockets.broadcast(connected,json.dumps(event)) websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="removeItemFromUI": event = { "type": "removeItemFromUI", 'targetElementData':event['targetElementData'], 'path':event['path'] } # websockets.broadcast(connected,json.dumps(event)) websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="project": base_path = os.path.join(os.getcwd(), 'projects',key, event["project_name"]) data=json.loads(event["file_structure"]) await create_file_structure(websocket,data, base_path=base_path) # await rename_item(websocket, key,event["project_name"], event["path"], event["name"], connected) elif event["command"]["type"]=="collabration": event = { "type": "collabration", 'name': event["name"], 'line': event["cursorPos-line"], 'ch': event["cursorPos-ch"], 'file':event["file"], 'content': event["content"], 'color':event["color"] } websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="cursor": event = { "type": "cursor", 'offset': event["offset"], 'userid': event["userid"], 'userlabel': event["userlabel"], 'usercolor': event["usercolor"], 'fileName':event["fileName"], } websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="select": event = { "type": "select", 'id': event["id"], 'startOffset': event["startOffset"], 'endOffset': event["endOffset"], 'userid': event["userid"], 'userlabel': event["userlabel"], 'usercolor': event["usercolor"], 'fileName':event["fileName"], } websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="addselection": event = { "type": "addselection", 'userid': event["userid"], 'userlabel': event["userlabel"], 'usercolor': event["usercolor"], } websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="insert": event = { "type": "insert", 'index': event["index"], 'text': event["text"], 'userid': event["userid"], 'userlabel': event["userlabel"], 'usercolor': event["usercolor"], 'fileName':event["fileName"], } websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="replace": event = { "type": "replace", 'index': event["index"], 'length': event["length"], 'text': event["text"], 'userid': event["userid"], 'userlabel': event["userlabel"], 'usercolor': event["usercolor"], 'fileName':event["fileName"], } websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="edelelte": event = { "type": "edelelte", 'index': event["index"], 'length': event["length"], 'userid': event["userid"], 'userlabel': event["userlabel"], 'usercolor': event["usercolor"], 'fileName':event["fileName"], } websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="keep-alive": event = { "type": "keep-alive", } websockets.broadcast(connected, json.dumps(event)) else: # First player starts a new game. pass except Exception as exc: # Send an "error" event if the move was illegal. await error(websocket, str(exc)) continue break except websockets.ConnectionClosed: print("WebSocket connection closed") break except Exception as e: print(f"Error in input thread: {str(e)}") pass async def process_input(user_input, process): if process: try: if user_input == 'Ctrl+C': print('Stopping process') # Send Ctrl+C signal to the subprocess process.send_signal(signal.SIGINT) os.killpg(os.getpgid(process.pid), signal.SIGTERM) # Read output and error asynchronously # os.kill(int(process.pid), signal.CTRL_C_EVENT) print('stoping signal sent') else: print(user_input) process.stdin.write(user_input.encode('utf-8') + b'\n') # process.stdin.flush() except Exception as e: print(f"Error writing to process stdin: {str(e)}") else: print("No process available to write to.") async def create_file_structure(websocket, data, base_path='.'): if data['type'] == 'folder': folder_path = os.path.join(base_path, data['name']) os.makedirs(folder_path, exist_ok=True) for child in data['children']: await create_file_structure(websocket,child, base_path=folder_path) elif data['type'] == 'file': mode = auto_detect_mode(data['content']) file_path = os.path.join(base_path, data['name']) with open(file_path,mode) as file: file.write(data['content']) event = { "type": "msg", "message": "project created", } await websocket.send(json.dumps(event)) async def error(websocket, message): """ Send an error message. """ event = { "type": "error", "message": message, } await websocket.send(json.dumps(event)) async def exe(websocket,connected,key,process_ids): """ Receive and process moves from a player. """ # print('in exe') async for message in websocket: # Parse a "play" event from the UI. print(message) event = json.loads(message) print(event,1) print(type(event),1) assert event["type"] == "cmd" # command = event["command"] print(event,2) try: if event["command"]["type"]=="shell": base_path = os.path.join(os.getcwd(), 'projects', key,event["project_name"]) directory_path = base_path event_handler = FileHandler(websocket,connected) observer = Observer() observer.schedule(event_handler, path=directory_path, recursive=True) observer.start() try: # await execute_command(websocket, key,event["project_name"], event["command"]["command"], connected) # base_path = os.path.join(os.getcwd(), 'projects', key,event["project_name"]) print(base_path) mod_command = f'cd {base_path} && {event["command"]["command"]}' print(mod_command) try: process = await asyncio.create_subprocess_shell( mod_command, # cwd=base_path, stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, # text=True, ) id=process.pid process_ids.append(id) async def send_message(message): # print('sending msg') # await websocket.send(f'data: {message}') websockets.broadcast(connected,json.dumps(message) ) await asyncio.gather( handle_user_input(websocket,key, process, connected,process_ids), read_process_output(process, websocket) ) return_code = await process.wait() if return_code == 0: event = { "type": "terminal-data-end", } await websocket.send(json.dumps(event)) else: event = { "type": "terminal-data-end", } await websocket.send(json.dumps(event)) process_ids.remove(id) except Exception as e: await error(websocket, str(e)) except KeyboardInterrupt: pass # Handle KeyboardInterrupt to gracefully stop the observer observer.stop() observer.join() elif event["command"]["type"]=="write": await wirte_file(websocket, key,event["project_name"], event["path"], event["content"], connected) elif event["command"]["type"] == "curl": method = event.get("method", "GET") url = event["url"] body = event.get("data", "") headers = event.get("headers", {}) if method.upper() == "GET": response = requests.get(url, headers=headers) elif method.upper() == "POST": response = requests.post(url, data=body, headers=headers) else: response = {"error": "Unsupported method"} if isinstance(response, dict): response_data = { "type": "error", "data": response, } await websocket.send(json.dumps(response_data)) return # Parse HTML content souptmp = BeautifulSoup(response.text, "html.parser") # Step 1: Define the initial HTML string html_str = """

Hello, World!

""" # Step 2: Parse the initial HTML content soup = BeautifulSoup(html_str, 'html.parser') # Step 3: Replace the existing body content with the new content from souptmp if soup.body: soup.body.clear() soup.body.append(souptmp) else: print("No tag found in the HTML") # Inline CSS and JavaScript soup = inline_resources(soup, url) response_data = { "type": "web-data", "data": str(soup), } # await websocket.send(json.dumps(response_data)) await send_html_chunks(websocket, soup) elif event["command"]["type"]=="create": if event["item"]=="folder": await create_folder(websocket, key,event["project_name"], event["path"],event["name"],event['root'],event['targetElementData'],event["rpath"], connected) else: await create_file(websocket, key,event["project_name"], event["path"],event["name"],event['root'],event['targetElementData'],event["rpath"], connected) elif event["command"]["type"]=="delete": await delete_item(websocket, key,event["project_name"], event["path"],event['rpath'],event['targetElementData'], connected) elif event["command"]["type"]=="get_content": await get_file_content(websocket, key,event["project_name"],event["filePath"], event["rfilePath"],event["fileName"] ,connected) elif event["command"]["type"]=="rename": await rename_item(websocket, key,event["project_name"], event["path"],event['rpath'], event["name"], event["root"], connected) elif event["command"]["type"]=="join": await join(websocket, event["join"]) elif event["command"]["type"]=="sendDir": data=json.loads(event["file_structure"]) event = { "type": "createDir", "path": data, "root":event['root'], } # websockets.broadcast(connected,json.dumps(event)) websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="createItemUI": event = { "type": "createItemUI", 'targetElementData':event['targetElementData'], 'data':event['data'] } # websockets.broadcast(connected,json.dumps(event)) websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="renameItemInUI": event = { "type": "renameItemInUI", 'path':event['path'], 'new_path':event['new_path'], 'name':event['name'], 'new_rpath':event['new_rpath'], } # websockets.broadcast(connected,json.dumps(event)) websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="createFolderUI": event = { "type": "createFolderUI", 'targetElementData':event['targetElementData'], 'data':event['data'] } # websockets.broadcast(connected,json.dumps(event)) websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="removeItemFromUI": event = { "type": "removeItemFromUI", 'targetElementData':event['targetElementData'], 'path':event['path'] } # websockets.broadcast(connected,json.dumps(event)) websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="project": base_path = os.path.join(os.getcwd(), 'projects',key, event["project_name"]) data=json.loads(event["file_structure"]) await create_file_structure(websocket,data, base_path=base_path) # await rename_item(websocket, key,event["project_name"], event["path"], event["name"], connected) elif event["command"]["type"]=="collabration": event = { "type": "collabration", 'name': event["name"], 'line': event["cursorPos-line"], 'ch': event["cursorPos-ch"], 'file':event["file"], 'content': event["content"], 'color':event["color"] } websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="cursor": event = { "type": "cursor", 'offset': event["offset"], 'userid': event["userid"], 'userlabel': event["userlabel"], 'usercolor': event["usercolor"], 'fileName':event["fileName"], } websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="select": event = { "type": "select", 'id': event["id"], 'startOffset': event["startOffset"], 'endOffset': event["endOffset"], 'userid': event["userid"], 'userlabel': event["userlabel"], 'usercolor': event["usercolor"], 'fileName':event["fileName"], } websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="addselection": event = { "type": "addselection", 'userid': event["userid"], 'userlabel': event["userlabel"], 'usercolor': event["usercolor"], } websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="insert": event = { "type": "insert", 'index': event["index"], 'text': event["text"], 'userid': event["userid"], 'userlabel': event["userlabel"], 'usercolor': event["usercolor"], 'fileName':event["fileName"], 'tabStatus':event['tabStatus'], } websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="replace": event = { "type": "replace", 'index': event["index"], 'length': event["length"], 'text': event["text"], 'userid': event["userid"], 'userlabel': event["userlabel"], 'usercolor': event["usercolor"], 'fileName':event["fileName"], 'tabStatus':event['tabStatus'], } websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="edelelte": event = { "type": "edelelte", 'index': event["index"], 'length': event["length"], 'userid': event["userid"], 'userlabel': event["userlabel"], 'usercolor': event["usercolor"], 'fileName':event["fileName"], } websockets.broadcast(connected, json.dumps(event)) elif event["command"]["type"]=="keep-alive": event = { "type": "keep-alive", } else: # First player starts a new game. pass except Exception as exc: # Send an "error" event if the move was illegal. await error(websocket, str(exc)) continue async def start(websocket,events): user = User() connected = {websocket} process_ids = [] join_key = secrets.token_urlsafe(12) JOIN[join_key] = user, connected try: # Send the secret access tokens to the browser of the first player, # where they'll be used for building "join" and "watch" links. event = { "type": "init", "join": join_key, } await websocket.send(json.dumps(event)) await exe(websocket,connected,join_key,process_ids) finally: del JOIN[join_key] project_path = os.path.join(os.getcwd(), 'projects', JOIN[join_key]) shutil.rmtree(project_path) for id in process_ids: os.killpg(os.getpgid(id), signal.SIGTERM) async def join(websocket, key): """ Handle a connection from the second player: join an existing game. """ # Find the Connect Four game. try: user, connected = JOIN[key] except KeyError: await error(websocket, "collabration not found.") return # Register to receive moves from this game. connected.add(websocket) try: event = { "type": "sendDir", } websockets.broadcast(connected,json.dumps(event)) await exe(websocket,connected,key) finally: connected.remove(websocket) async def handler(websocket): """ Handle a connection and dispatch it according to who is connecting. """ # Receive and parse the "init" event from the UI. message = await websocket.recv() event = json.loads(message) # print(event) # project_name = event["project_name"] # assert event["type"] == "init" if event["type"] == "init": if "join" in event: # Second player joins an existing game. await join(websocket, event["join"]) else: # First player starts a new game. await start(websocket, message) elif event["type"] == "cmd": # print('executing commad') # Execute a command in the project folder. await execute_command(websocket, event["project_name"], event["command"]) async def main(): # Set the stop condition when receiving SIGTERM. loop = asyncio.get_running_loop() stop = loop.create_future() loop.add_signal_handler(signal.SIGTERM, stop.set_result, None) port = int(os.environ.get("PORT", "7860")) async with websockets.serve(handler, "0.0.0.0", port): await stop if __name__ == "__main__": asyncio.run(main())