diff --git a/submissions/AQuaZar/data-structures/README.md b/submissions/AQuaZar/data-structures/README.md new file mode 100644 index 0000000..797d8d1 --- /dev/null +++ b/submissions/AQuaZar/data-structures/README.md @@ -0,0 +1,90 @@ +# Data Structures API + +This application is my solution to practice part of data-structures task during Kottans-backend online course. [Link to the task.](https://github.com/kottans/backend/blob/master/tasks/data-structures.md) + +Role of this API is to provide means of interaction with two types of data-structures: stack and linked list. Client can work with data stored on the server's memory. Application accepts two types of requests PUT to change data and GET to receive full view of data-structure. To transfer data from client to server JSON format has to be used as a payload to request, response from server passed as a string. + +## Available Data Parameters + +### Stack + +| Name | Value | Description | +| ----------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| **PUT** | +| "data_type" | "stack" | Specifies that stack data-structure is used | +| "action" | "push", "pop" | Push - adds value specified in "Value" property on top of the stack, pop - removes value from top of the stack and returns it in body of response | +| "value" | alphanumeric value | Value that will be pushed to the stack | +| **GET** | +| "data_type" | "stack" | Specifies that stack data is shown | +| "action" | "show" | Full view of stack will be provided in body of server response | + +### Linked List + +| Name | Value | Description | +| ----------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | +| **PUT** | +| "data_type" | "linked_list" | Specifies that data from linked-list structure is affected | +| "action" | "insert", "remove" | Insert - value specified in "Value" property inserted as a head of the list and will point to successor, remove - removes value from the list | +| "successor" | alphanumeric value | Optional parameter, if member of list is provided, value specified in "Value" property will be inserted before specified successor | +| "value" | alphanumeric value | Value that will be inserted to the linked list | +| **GET** | +| "data_type" | "linked_list" | Specifies that linked-list data is shown | +| "action" | "show" | Full view of list will be provided in body of server response | + +## Examples + +For requests will be used 'requests' python library and 'json' library to serialize data. + + import requests + import json + + url = "http://localhost:8000/" + + data = {"data_type": "linked_list", "action": "insert", "value": "Jonathan"} + data = json.dumps(data) + r = requests.put(url, data) + +In this example the PUT request is performed. As a result of request string _"Jonathan"_ will be _inserted_ in _linked list_ hold in local server memory. + +To check state of our linked list we can use GET request: + + data = {"data_type": "linked_list", "action": "show"} + data = json.dumps(data) + r = requests.get(url, data=data) + print(r.content) + +To check the body of respond, 'content' field is used, as result we get: + +> b'head -> Jonathan -> None' + +In next example we will push values 1,2,3,4,5 to stack and pop last two + + for i in range(1, 6): + data = {"data_type": "stack", "action": "push", "value": str(i)} + data = json.dumps(data) + r = requests.put(url, data=data) + for i in range(1, 3): + data = {"data_type": "stack", "action": "pop"} + data = json.dumps(data) + r = requests.put(url, data=data) + print(r.content) + +Server responded with: + +> b'5' + +> b'4' + +Another feature of linked list insertion is to specify successor of inserted node. For example we have such list structure: + +> b'head -> Jonathan -> Joseph -> Jotaro -> None' + +And we want to insert value "Joske" before "Jotaro", so that "Jotaro" will be successor of "Joske", we have to add optional property "successor" to data. + + data = {"data_type": "linked_list", "action": "insert", "value": "Joske", "successor":"Jotaro"} + data = json.dumps(data) + r = requests.put(url, data) + +As result we get: + +> b'head -> Jonathan -> Joseph -> Joske -> Jotaro -> None' diff --git a/submissions/AQuaZar/data-structures/data_structure.py b/submissions/AQuaZar/data-structures/data_structure.py new file mode 100644 index 0000000..1c50af3 --- /dev/null +++ b/submissions/AQuaZar/data-structures/data_structure.py @@ -0,0 +1,66 @@ +class Stack: + def __init__(self, *args): + self.stack = list(args) + + def show(self): + return str(self.stack) + + def push(self, value): + self.stack.append(value) + + def pop(self): + return self.stack.pop() + + +class Node: + def __init__(self, data): + self.data = data + self.next = None + + +class Linked_list: + def __init__(self, head=None): + self.head = head + + def insert(self, data, successor=None): + if not successor or successor == self.head.data: + node = Node(data) + node.next = self.head + self.head = node + return True + current = self.head + while current: + if current.next.data == successor: + node = Node(data) + node.next = current.next + current.next = node + return True + current = current.next + # Successor not found + return False + + def show(self): + current = self.head + output = "head ->" + while current: + output += f" {current.data} ->" + current = current.next + output += " None" + return output + + def remove(self, data): + current = self.head + # if head element has to be removed + if current.data == data: + self.head = current.next + del current + return True + # if element in tail + while current.next: + if current.next.data == data: + current.next = current.next.next + return True + current = current.next + # Specified element not in a list + return False + diff --git a/submissions/AQuaZar/data-structures/main.py b/submissions/AQuaZar/data-structures/main.py new file mode 100644 index 0000000..cf839ae --- /dev/null +++ b/submissions/AQuaZar/data-structures/main.py @@ -0,0 +1,28 @@ +import requests +import json + +url = "http://localhost:8000/" + +data = {"data_type": "linked_list", "action": "insert", "value": "Jotaro"} +data = json.dumps(data) +r = requests.put(url, data) +data = {"data_type": "linked_list", "action": "insert", "value": "Joseph"} +data = json.dumps(data) +r = requests.put(url, data) +data = {"data_type": "linked_list", "action": "insert", "value": "Jonathan"} +data = json.dumps(data) +r = requests.put(url, data) +data = { + "data_type": "linked_list", + "action": "insert", + "value": "Joske", + "successor": "Jotaro", +} +data = json.dumps(data) +r = requests.put(url, data) + + +data = {"data_type": "linked_list", "action": "show"} +data = json.dumps(data) +r = requests.get(url, data=data) +print(r.content) diff --git a/submissions/AQuaZar/data-structures/server.py b/submissions/AQuaZar/data-structures/server.py new file mode 100644 index 0000000..8c780d3 --- /dev/null +++ b/submissions/AQuaZar/data-structures/server.py @@ -0,0 +1,105 @@ +import http.server +import socketserver +import json +from data_structure import Stack, Linked_list + + +PORT = 8000 + +myStack = Stack() +myList = Linked_list() + + +def ParseRequest(self): + if not self.headers["Content-Length"]: + SendResponse(self, 411, "No 'Content-Length' provided") + return + content_length = int(self.headers["Content-Length"]) + request = json.loads(self.rfile.read(content_length).decode("UTF-8")) + return request + + +def SendResponse(self, responseCode, responsebody=None): + if responsebody: + self.send_response(responseCode) + self.send_header("Content-type", "text/plain") + self.end_headers() + self.wfile.write(bytes(responsebody, "UTF-8")) + else: + self.send_response(responseCode) + self.end_headers() + return + + +class SimpleHTTPRequestHandler(http.server.BaseHTTPRequestHandler): + def do_GET(self): + request = ParseRequest(self) + if not request: + return + + if "data_type" in request and "action" in request: + if request["data_type"] == "stack" and request["action"] == "show": + SendResponse(self, 200, myStack.show()) + elif request["data_type"] == "linked_list" and request["action"] == "show": + SendResponse(self, 200, myList.show()) + else: + SendResponse( + self, 400, "Wrong value for 'data_type' or 'action' properties" + ) + else: + SendResponse(self, 400, "No 'data_type' or 'action' properties") + + def do_PUT(self): + request = ParseRequest(self) + if not request: + return + + if "data_type" in request and "action" in request: + if request["data_type"] == "stack": + if request["action"] == "push" and "value" in request: + if request["value"].isalnum(): + myStack.push(request["value"]) + SendResponse(self, 200) + else: + SendResponse(self, 400, "Value is not string or number") + + elif request["action"] == "pop": + if len(myStack.stack) >= 1: + SendResponse(self, 200, myStack.pop()) + else: + SendResponse(self, 409, "Can't pop from empty stack") + else: + SendResponse(self, 400, "Wrong 'action' value") + + elif request["data_type"] == "linked_list": + if request["action"] == "insert" and "value" in request: + if request["value"].isalnum(): + if "successor" in request: + try: + myList.insert(request["value"], request["successor"]) + SendResponse(self, 200) + except: + SendResponse(self, 409, "Successor not found") + else: + myList.insert(request["value"]) + SendResponse(self, 200) + else: + SendResponse(self, 400, "Value is not string or number") + + elif request["action"] == "remove" and "value" in request: + try: + myList.remove(request["value"]) + SendResponse(self, 200) + except: + SendResponse(self, 409, "Value not in list") + else: + SendResponse(self, 400, "Wrong 'action' value") + else: + SendResponse(self, 400, "Wrong 'data_type' value") + else: + SendResponse(self, 400, "No 'data_type' or 'action' in request") + + +with socketserver.TCPServer(("", PORT), SimpleHTTPRequestHandler) as httpd: + print("serving at port", PORT) + httpd.serve_forever()