├── dependencies ├── readme.md ├── server.py └── client.py /dependencies: -------------------------------------------------------------------------------- 1 | websockets 2 | asyncio 3 | json -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # SocketCloud 2 | ## Description 3 | SocketCloud is a server-client program where the server provides the clients with files and folders, and where the client can store/modify its own files 4 | 5 | We use WebSockets tech: 6 | It is a bidirectional client-server communication protocol, the transmitted data needs to be protected with SSL/TLS encryption. 7 | 8 | ## How to Use 9 | 10 | - add - adds a new empty file to the server 11 | example: add [file name] 12 | 13 | - mkdir - adds a new empty folder into the server 14 | example: mkdir [folder name] 15 | 16 | - read - retrieves a given file from the server and prints it to the terminal 17 | example: read [file name] 18 | 19 | - readc - retrieves a given file from the client and prints it to the terminal 20 | 21 | - write - it executes the nano command once the file is opened in the terminal 22 | example: write [file name] 23 | 24 | - commit - stores local temp file in the server 25 | example: commit [file name] 26 | 27 | - ls - list all the files and folders in the server 28 | example: ls 29 | 30 | - help - show all the commands descriptions 31 | example: help 32 | 33 | - exit - finish the client execution 34 | example: exit 35 | ## Technologies used (Modules) 36 | 37 | ### Asyncio 38 | 39 | It is a library for writing concurrent code using async/await syntax, provides high-performance networking and web servers, database connection libraries, distributed task queues, etc. 40 | 41 | ### Websockets 42 | 43 | It is a library for creating WebSocket servers and clients in Python, focusing on correctness, simplicity, robustness and performance. 44 | 45 | ## How to install 46 | First of all intall python 3.12.0 forward, then clone the repository and run the following command to install all the dependencies: 47 | ``` 48 | # pip install -r dependencies 49 | ``` 50 | ## How to run 51 | 52 | ### Server 53 | ``` 54 | # python server.py 55 | ``` 56 | 57 | ### Client 58 | ``` 59 | # python client.py 60 | ``` 61 | 62 | ## Credits 63 | - Sanchez Pastor Bautista - @unwxnted 64 | - Mendez Pricila - @mendezprisci 65 | - Marcozzi Lucio - @Gvmbler 66 | - Oteiza Santiago - @l0l0C1337 67 | - Buera Jazmin - @buerajaaz 68 | -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import json 3 | import os 4 | from websockets.server import serve 5 | 6 | class Server: 7 | def __init__(self): 8 | self.address = "localhost" 9 | self.port = 8765 10 | 11 | async def read_command(self, command): 12 | try: 13 | params = command.split() 14 | if(not os.path.exists("./server_files/"+params[1]) or "../" in params[1]): return "File not found" 15 | with open("./server_files/"+params[1], "r") as archivo: 16 | return archivo.read() 17 | except: 18 | return "Error, cannot read/write to a folder" 19 | 20 | async def add_command(self, command): 21 | try: 22 | filename = command.split() 23 | filename = filename[1] 24 | with open("./server_files/"+filename, 'w') as file: 25 | file.write("") 26 | return "Successfully added new file" 27 | except: 28 | return "Error, cannot add a file with the same folder name" 29 | 30 | async def list_command(self, command): 31 | directory = ".\\server_files" 32 | response = "" 33 | stack = [] 34 | 35 | for item in os.listdir(directory): 36 | item_path = os.path.join(directory, item) 37 | if os.path.isdir(item_path): 38 | stack.append(item) 39 | else: 40 | response += f"File: {item}\n" 41 | 42 | while stack: 43 | item = stack.pop() 44 | response += f"Folder: {item}\n" 45 | folder_path = os.path.join(directory, item) 46 | for file_item in os.listdir(folder_path): 47 | file_path = os.path.join(folder_path, file_item) 48 | if os.path.isdir(file_path): 49 | stack.append(os.path.join(item, file_item)) 50 | else: 51 | response += f" File: {file_item}\n" 52 | return response 53 | 54 | async def mkdir_command(self, command): 55 | filename = command.split() 56 | filename = filename[1] 57 | os.makedirs("server_files/"+filename) 58 | return "Succesfully created new directory" 59 | 60 | async def commit_command(self, command): 61 | json_data = json.loads(command) 62 | file = open("./server_files/"+json_data["filename"], "w") 63 | file.write(json_data["data"]) 64 | file.close() 65 | return "Successfully committed" 66 | 67 | async def serve_command(self, command): 68 | cmd = command.split()[0] 69 | if ("read" in cmd) or ("write" in cmd): 70 | return await self.read_command(command) 71 | if("commit" in command.split(",")[0] and "," in command): return await self.commit_command(command) 72 | if("ls" in cmd): return await self.list_command(command) 73 | if("add" in cmd): return await self.add_command(command) 74 | if("mkdir" in cmd): return await self.mkdir_command(command) 75 | 76 | async def echo(self, websocket, path): 77 | async for command in websocket: 78 | response = await self.serve_command(command) 79 | await websocket.send(response) 80 | 81 | def run(self): 82 | try: 83 | os.path.exists("./server_files") or os.mkdir("./server_files") 84 | async def server_loop(): 85 | async with serve(self.echo, self.address, self.port): 86 | await asyncio.Future() 87 | 88 | asyncio.run(server_loop()) 89 | except: 90 | print("\nExiting...") 91 | 92 | if __name__ == "__main__": 93 | sv = Server() 94 | sv.run() 95 | -------------------------------------------------------------------------------- /client.py: -------------------------------------------------------------------------------- 1 | import os 2 | import asyncio 3 | import json 4 | from websockets.sync.client import connect 5 | 6 | class Client: 7 | def __init__(self): 8 | self.websocket = None 9 | self.last_update = {} 10 | 11 | def connect_to_server(self): 12 | self.websocket = connect("ws://localhost:8765") 13 | 14 | def send_command(self, command): 15 | if self.websocket is not None: 16 | self.websocket.send(command) 17 | response = self.websocket.recv() 18 | params = command.split() 19 | if(params[0] != "add" and params[0] != "ls"): self.last_update[params[1]] = response 20 | return response if response else "" 21 | else: 22 | print("Error, no websocket connection") 23 | 24 | def write_command(self, response, command): 25 | if(response == "File not found"): return print("File not found") 26 | if(response == "Error, cannot read/write to a folder"): return print("Error, cannot write to a folder") 27 | params = command.split() 28 | self.last_update[params[1]] = response 29 | temp = open("temp_" + params[1].replace("/", "_"), "w") 30 | temp.write(response) 31 | temp.close() 32 | os.system("nano " + temp.name) 33 | 34 | def commit_command(self, command): 35 | params = command.split() 36 | name_parsed = params[1].replace("/", "_") 37 | if(not os.path.exists("temp_" + name_parsed)): return "No changes maded to commit" 38 | file = open("temp_"+ name_parsed, "r") 39 | content = file.read() 40 | file.close() 41 | os.remove("temp_"+ name_parsed) 42 | data = {"command": "commit", "filename": params[1],"data": content} 43 | data_str = json.dumps(data) 44 | if(params[1] not in self.last_update): return self.send_command(data_str) 45 | if(self.last_update[params[1]] != self.send_command("read "+ params[1])): 46 | return "Some changes were made during the file modification, the server file is not the same, please get the new file and try again." 47 | return self.send_command(data_str) 48 | 49 | def readc_command(self, command): 50 | params = command.split() 51 | filename = "temp_" + params[1].replace("/", "_") 52 | if(not os.path.exists(filename) or "../" in params[1]): return "File not found" 53 | with open(filename, "r") as archivo: 54 | return archivo.read() 55 | 56 | def help_command(self, comment): 57 | print(comment + "\nadd - adds a new empty file to the server\n example: add [filename]\n\nmkdir - creates a new directory\n example: mkdir [dirname]\n\nread - retrieves a given file from the server and prints it to the terminal\n example: read [filename]\n\nreadc - prints a given file's temporary file\n example: readc [filename]\n\nwrite - retrieves a given file from the server and open nano to write changes on the file\n example: write [filename]\n\ncommit - push the changes from the write command to the server\n example: commit [filename]\n\nls - list existing server files\n example: ls [filename]\n\nexit - finish the client process\n example: exit\n\n") 58 | 59 | def checker(self, command): 60 | params = command.split() 61 | if len(params) > 2 or (len(params)==1 and (params[0] != "help") and (params[0] != "exit") and (params[0] != "ls")): # add command check here 62 | self.help_command("Command syntax not valid, check the commands below: ") 63 | return False 64 | commands = ["read", "add", "commit", "write", "help", "exit", "ls", "readc", "mkdir"] # add the command in the list 65 | for cmd in commands: 66 | if cmd == params[0]: 67 | return True 68 | self.help_command("Command not found. Please check the commands below: ") 69 | return False 70 | 71 | def close_connection(self): 72 | if self.websocket is not None: 73 | self.websocket.close() 74 | 75 | def run(self): 76 | self.connect_to_server() 77 | while True: 78 | try: 79 | command = input("[cmd]: ") 80 | except KeyboardInterrupt: 81 | print("\nExiting...") 82 | break 83 | 84 | if not self.checker(command): continue 85 | # add the command below 86 | cmd = command.split()[0] 87 | if "commit" in cmd: print(self.commit_command(command)) 88 | if "readc" in cmd: print(self.readc_command(command)) 89 | else: 90 | if "read" in cmd: print(self.send_command(command)) 91 | if "add" in cmd: print(self.send_command(command)) 92 | if "write" in cmd: self.write_command(self.send_command(command), command) 93 | if "ls" in cmd: print(self.send_command(command)) 94 | if "mkdir" in cmd: print(self.send_command(command)) 95 | if "help" in cmd: self.help_command("") 96 | if "exit" in cmd: break 97 | 98 | 99 | self.close_connection() 100 | 101 | if __name__ == "__main__": 102 | cli = Client() 103 | cli.run() 104 | --------------------------------------------------------------------------------