collab_v2.0.0 / app.py
Ramesh-vani's picture
Update app.py
e0997d1 verified
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
import uuid
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_message_chunks(websocket, message):
msg_id = str(uuid.uuid4())
message_json = json.dumps(message)
chunks = [message_json[i:i+10] for i in range(0, len(message_json), 10)]
for i, chunk in enumerate(chunks):
chunk_data = {
'msg_id': msg_id,
'part': chunk,
'end': i == len(chunks) - 1
}
await websocket.send(json.dumps(chunk_data))
print(f"Sent chunk: {chunk_data}")
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 send_message_chunks(websocket,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 send_message_chunks(websocket,event)
except Exception as e:
event = {
"type": "error",
"message": f"Failed to read file content: {str(e)}",
}
await send_message_chunks(websocket,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 send_message_chunks(websocket,event)
word = b''
print("line is completed")
event = {
"type": "terminal-newline",
"data": "",
}
await send_message_chunks(websocket,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 send_message_chunks(websocket,event)
word = b''
print("space is occurred")
event = {
"type": "terminal-data",
"data": " ",
}
print('sending data',3)
await send_message_chunks(websocket,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 send_message_chunks(websocket,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 send_message_chunks(websocket,event)
word = b''
print("line is completed")
event = {
"type": "terminal-newline",
"data": "",
}
await send_message_chunks(websocket,event)
elif char == b' ':
if word:
print(word.decode('utf-8'))
event = {
"type": "terminal-error",
"data": word.decode('utf-8'),
}
await send_message_chunks(websocket,event)
word = b''
print("space is occurred")
event = {
"type": "terminal-error",
"data": " ",
}
await send_message_chunks(websocket,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 send_message_chunks(websocket,event)
# async for line in process.stderr:
# # print(f'error:{line.strip()}')
# event = {
# "type": "terminal-error",
# "data": line.strip().decode('utf-8'),
# }
# await send_message_chunks(websocket,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 send_message_chunks(websocket,event)
else:
event = {
"type": "terminal-data-end",
}
await send_message_chunks(websocket,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 = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html>
"""
# 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 <body> 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 send_message_chunks(websocket,event)
async def error(websocket, message):
"""
Send an error message.
"""
event = {
"type": "error",
"message": message,
}
await send_message_chunks(websocket,event)
async def exe(websocket,connected,key,process_ids):
"""
Receive and process moves from a player.
"""
# print('in exe')
message_parts = {}
async for message in websocket:
# Parse a "play" event from the UI.
data = json.loads(message)
msg_id = data['msg_id']
part = data['part']
if msg_id not in message_parts:
message_parts[msg_id] = []
message_parts[msg_id].append(part)
if data['end']:
full_message = ''.join(message_parts[msg_id])
print(f"Received full message: {full_message}")
event = json.loads(full_message)
del message_parts[msg_id]
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 send_message_chunks(websocket,event)
else:
event = {
"type": "terminal-data-end",
}
await send_message_chunks(websocket,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 = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html>
"""
# 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 <body> 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 send_message_chunks(websocket,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_parts = {}
async for message in websocket:
data = json.loads(message)
msg_id = data['msg_id']
part = data['part']
if msg_id not in message_parts:
message_parts[msg_id] = []
message_parts[msg_id].append(part)
if data['end']:
full_message = ''.join(message_parts[msg_id])
print(f"Received full message: {full_message}")
event = json.loads(full_message)
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, full_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())