collab_v2.0.0 / app.py
Ramesh-vani's picture
Update app.py
47ba2b1 verified
raw
history blame
50.6 kB
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
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,
}
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-data",
"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-data",
"data": word.decode('utf-8'),
}
await websocket.send(json.dumps(event))
word = b''
print("space is occurred")
event = {
"type": "terminal-data",
"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"}
# Parse HTML content
soup = BeautifulSoup(response.text, "html.parser")
# Get base URL
base_url = url
# base_host = base_url.netloc.rstrip("/")
# Function to join relative URLs with base URL
def join_url_with_base(url_arg):
if url_arg.startswith('/'):
# print(url+url_arg)
return url+url_arg
elif url_arg.startswith('http'):
# print(here)
# print(url_arg)
return url_arg
else:
# print(url_arg)
return url+url_arg
# Find and modify CSS links
for link in soup.find_all("link", rel="stylesheet", href=True):
link['href'] = join_url_with_base(link['href'])
# Find and modify JS links
for script in soup.find_all("script", src=True):
script['src'] = join_url_with_base(script['src'])
# Find and modify regular anchor links
for anchor in soup.find_all("a", href=True):
anchor['href'] = join_url_with_base(anchor['href'])
# Find and modify CSS links
for link in soup.find_all("link", rel="stylesheet", href=True):
if link['href'].startswith('/'):
css_url = url + link['href']
css_response = requests.get(css_url)
css_content = css_response.text
style_tag = soup.new_tag("style")
style_tag.string = css_content
link.replace_with(style_tag)
# Find and modify JS links
for script in soup.find_all("script", src=True):
if script['src'].startswith('/'):
js_url = url + script['src']
js_response = requests.get(js_url)
js_content = js_response.text
script_tag = soup.new_tag("script")
script_tag.string = js_content
script.replace_with(script_tag)
response_data = {
"type": "web-data",
"data": str(soup),
}
await websocket.send(json.dumps(response_data))
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)
assert event["type"] == "cmd"
# command = event["command"]
print(event)
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"}
# Parse HTML content
soup = BeautifulSoup(response.text, "html.parser")
# Get base URL
base_url = url
# base_host = base_url.netloc.rstrip("/")
# Function to join relative URLs with base URL
def join_url_with_base(url_arg):
if url_arg.startswith('/'):
# print(url+url_arg)
return url+url_arg
elif url_arg.startswith('http'):
# print(here)
# print(url_arg)
return url_arg
else:
# print(url_arg)
return url+url_arg
# Find and modify CSS links
for link in soup.find_all("link", rel="stylesheet", href=True):
link['href'] = join_url_with_base(link['href'])
# Find and modify JS links
for script in soup.find_all("script", src=True):
script['src'] = join_url_with_base(script['src'])
# Find and modify regular anchor links
for anchor in soup.find_all("a", href=True):
anchor['href'] = join_url_with_base(anchor['href'])
# Find and modify CSS links
for link in soup.find_all("link", rel="stylesheet", href=True):
if link['href'].startswith('/'):
css_url = url + link['href']
css_response = requests.get(css_url)
css_content = css_response.text
style_tag = soup.new_tag("style")
style_tag.string = css_content
link.replace_with(style_tag)
# Find and modify JS links
for script in soup.find_all("script", src=True):
if script['src'].startswith('/'):
js_url = url + script['src']
js_response = requests.get(js_url)
js_content = js_response.text
script_tag = soup.new_tag("script")
script_tag.string = js_content
script.replace_with(script_tag)
response_data = {
"type": "web-data",
"data": str(soup),
}
await websocket.send(json.dumps(response_data))
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())