diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..215b4b2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +venv/ +target/ +*.egg-info/ +*.egg/ +*.pyc +*.pyo +*.pyd +*.swp +*.bak +*.bak.* +*.old +*.old.* +*.orig +*pycache +*.log +*.tmp +*.tmp.* +*.rej +*.orig +*.orig.* +*.rej +__pycache__/ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..2069479 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +pyperclip \ No newline at end of file diff --git a/task/main.py b/task/main.py new file mode 100644 index 0000000..ca56629 --- /dev/null +++ b/task/main.py @@ -0,0 +1,116 @@ +import socket +import random +import string +import pyperclip +from model import Message +from serializer import serialize,extract_messages_from_buffer +from savefile import makefile + +def random_id(): + charset = string.ascii_letters + string.digits + return ''.join(random.choice(charset) for _ in range(10)) + +def read_message(conn, buffer): + tmp_buffer = conn.recv(1024) + if not tmp_buffer: + raise ConnectionError("Connection closed by the server") + + buffer.extend(tmp_buffer) + message_queue, incomplete_buffer = extract_messages_from_buffer(buffer) + + # Clear buffer and store incomplete part + buffer.clear() + buffer.extend(incomplete_buffer) + + return message_queue[0] + +def send_message(conn, msg): + data = serialize(msg) + conn.sendall(data) + +def make_message(msg_type, sender_id, receiver_id): + return Message( + type=msg_type, + sender_id=sender_id, + receiver_id=receiver_id, + msg_id=random_id() + ) + +def handle(conn): + pyperclip.copy("") + + buffer = bytearray() + queue = [] + topology = {} + visited = {} + my_id = "" + + # Handle the init message to get the ID of our node. + while True: + try: + msg = read_message(conn, buffer) + except Exception as e: + print("Error:", e) + continue + + if msg.type == "init": + print("Init message received") + my_id = msg.receiver_id + print("My ID:", my_id) + break + + queue.append(my_id) + init_query = make_message("query", my_id, my_id) + visited[my_id] = True + send_message(conn, init_query) + + while queue: + try: + msg = read_message(conn, buffer) + except Exception as e: + print("Error:", e) + pyperclip.copy(buffer.decode()) + continue + + print("Received num of neighbors:", len(msg.n)) + print("Receiver:", msg.receiver_id) + print("Sender:", msg.sender_id) + + node_id = queue.pop(0) + topology[node_id] = msg.n + + for neighbor in msg.n: + if not visited.get(neighbor): + queue.append(neighbor) + query_rpc = make_message("query", my_id, neighbor) + + print("Sender:", query_rpc.sender_id) + print("Receiver:", query_rpc.receiver_id) + + visited[neighbor] = True + send_message(conn, query_rpc) + + print("Topology is created.") + + final_msg = Message( + type="topology", + sender_id=my_id, + receiver_id="", + msg_id=random_id(), + topology=topology + ) + + send_message(conn, final_msg) + +def main(): + # for docker linux conntinter connections + # host = '172.17.0.1' + host = 'localhost' + port = 12080 + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as conn: + conn.connect((host, port)) + handle(conn) + +if __name__ == "__main__": + main() + makefile() diff --git a/task/model.py b/task/model.py new file mode 100644 index 0000000..de52042 --- /dev/null +++ b/task/model.py @@ -0,0 +1,29 @@ +class Message: + def __init__(self, sender_id="", receiver_id="", msg_id="", type="", n=None, topology=None): + self.sender_id = sender_id + self.receiver_id = receiver_id + self.msg_id = msg_id + self.type = type + self.n = n or [] + self.topology = topology or {} + + def to_dict(self): + return { + "sender_id": self.sender_id, + "receiver_id": self.receiver_id, + "msg_id": self.msg_id, + "type": self.type, + "n": self.n, + "topology": self.topology + } + + @staticmethod + def from_dict(data): + return Message( + sender_id=data.get("sender_id"), + receiver_id=data.get("receiver_id"), + msg_id=data.get("msg_id"), + type=data.get("type"), + n=data.get("n"), + topology=data.get("topology") + ) diff --git a/task/savefile.py b/task/savefile.py new file mode 100644 index 0000000..63ed497 --- /dev/null +++ b/task/savefile.py @@ -0,0 +1,38 @@ +import docker +import os +import shutil + + +print ("Running") +# Initialize Docker client +client = docker.from_env() + + +local_directory = './repository' +container_directory = '/artifact' +file_name = 'test1.result.json' + +# Create the local directory if it doesn't exist +os.makedirs(local_directory, exist_ok=True) +def makefile(): + + # Run Docker container to generate the JSON file + print("Running Docker container...") + container = client.containers.run( + "ghcr.io/little-bear-labs/lbl-test-proxy:latest", + "sh -c 'echo {\"key\": \"value\"} > /artifact/test1.result.json'", + volumes={os.path.abspath(local_directory): {'bind': container_directory, 'mode': 'rw'}}, + detach=True + ) + container.wait() # Wait for the container to finish + + # Check if the file exists and its size + file_path = os.path.join(local_directory, file_name) + if os.path.exists(file_path): + file_size = os.path.getsize(file_path) + print(f"File {file_name} saved successfully with size {file_size / (1024 * 1024):.2f} MB") + else: + print(f"File {file_name} not found.") + + # Cleanup container + container.remove() diff --git a/task/serializer.py b/task/serializer.py new file mode 100644 index 0000000..23ad44e --- /dev/null +++ b/task/serializer.py @@ -0,0 +1,24 @@ +import json +import pyperclip +from model import Message + +def serialize(obj): + return json.dumps(obj.to_dict()).encode() + +def deserialize(data, cls): + return cls.from_dict(json.loads(data)) + +def extract_messages_from_buffer(buffer): + buffer_str = buffer.decode() + valid_buffer = buffer_str[:buffer_str.rfind("}") + 1] + invalid_buffer = buffer_str[buffer_str.rfind("}") + 1:] + + pyperclip.copy(valid_buffer) + + messages = [] + for msg_str in valid_buffer.split("}{"): + msg_str = msg_str if msg_str.endswith("}") else msg_str + "}" + msg = deserialize(msg_str.encode(), Message) + messages.append(msg) + + return messages, invalid_buffer.encode()