From 54cd56fa0155d1e3f5315a09023e199c94a03d82 Mon Sep 17 00:00:00 2001 From: apalamarchuk Date: Thu, 10 Oct 2019 11:14:22 +0300 Subject: [PATCH] http-server with data-structures is developed. --- .../assmass13/data-structures/README.md | 17 +++ .../data-structures/request-handler.js | 33 ++++++ .../routers/linked-list-router.js | 38 +++++++ .../data-structures/routers/stack-router.js | 38 +++++++ .../assmass13/data-structures/server.js | 22 ++++ .../data-structures/structures/linked-list.js | 100 ++++++++++++++++++ .../data-structures/structures/node.js | 6 ++ .../data-structures/structures/stack.js | 19 ++++ 8 files changed, 273 insertions(+) create mode 100644 submissions/assmass13/data-structures/README.md create mode 100644 submissions/assmass13/data-structures/request-handler.js create mode 100644 submissions/assmass13/data-structures/routers/linked-list-router.js create mode 100644 submissions/assmass13/data-structures/routers/stack-router.js create mode 100644 submissions/assmass13/data-structures/server.js create mode 100644 submissions/assmass13/data-structures/structures/linked-list.js create mode 100644 submissions/assmass13/data-structures/structures/node.js create mode 100644 submissions/assmass13/data-structures/structures/stack.js diff --git a/submissions/assmass13/data-structures/README.md b/submissions/assmass13/data-structures/README.md new file mode 100644 index 0000000..a64bf6b --- /dev/null +++ b/submissions/assmass13/data-structures/README.md @@ -0,0 +1,17 @@ +# Stack & LinkedList http-server implementation. +## Run server +`node server.js` creates server on `localhost:3000` +## Stack +1. Push: `POST /stack`\ + Accepts JSON: `{ "add": or }` +1. Pop: `DELETE /stack`\ + Removes item from the top and return its value. + +## LinkedList + +1. Show list: `GET /linked-list`\ + Shows current LinkedList values. +1. Insert/Remove: `PATCH /linked-list`\ + Accepts JSON: `{ "add": or , "successor": or , "remove": or }`\ + Inserts `'add'` before each `'successor'` if provided, appends to list's head otherwise.\ + Removes `'remove'` values. \ No newline at end of file diff --git a/submissions/assmass13/data-structures/request-handler.js b/submissions/assmass13/data-structures/request-handler.js new file mode 100644 index 0000000..45ea701 --- /dev/null +++ b/submissions/assmass13/data-structures/request-handler.js @@ -0,0 +1,33 @@ +const readBody = req => + new Promise(resolve => { + const chunks = []; + + req.on('data', chunk => { + chunks.push(chunk); + }); + + req.on('end', () => { + resolve(Buffer.concat(chunks)); + }); + }); + +const parseJson = async req => readBody(req).then(JSON.parse); + +const validValueCondition = value => + Number.isFinite(value) || typeof value === 'string'; + +const parsedBodyValues = req => + parseJson(req).then(body => + Object.keys(body).reduce((acc, key) => { + if (['add', 'successor', 'remove'].includes(key)) { + if (!validValueCondition(body[key])) + throw SyntaxError( + `'${body[key]}' should be of type 'string' or 'number'.` + ); + return { ...acc, [key]: body[key] }; + } + return acc; + }, {}) + ); + +module.exports = parsedBodyValues; diff --git a/submissions/assmass13/data-structures/routers/linked-list-router.js b/submissions/assmass13/data-structures/routers/linked-list-router.js new file mode 100644 index 0000000..d498e65 --- /dev/null +++ b/submissions/assmass13/data-structures/routers/linked-list-router.js @@ -0,0 +1,38 @@ +const LinkedList = require('../structures/linked-list'); +const parsedBodyValues = require('../request-handler'); + +class LinkedListRouter { + constructor() { + this.linkedList = new LinkedList(); + this.routes = { + 'GET /linked-list': this.getLinkedListRoute.bind(this), + 'PATCH /linked-list': this.patchLinkedListRoute.bind(this) + }; + } + + getLinkedListRoute(req, res) { + res.statusCode = 200; + res.end(this.linkedList.showList().toString()); + } + + patchLinkedListRoute(req, res) { + return parsedBodyValues(req, res) + .then(({ add, successor, remove }) => { + if (add && successor) { + this.linkedList.insertBeforeSuccessors(add, successor); + } else if (add) { + this.linkedList.unshift(add); + } else if (remove) { + this.linkedList.removeValue(remove); + } + res.statusCode = 200; + res.end(this.linkedList.showList().toString()); + }) + .catch(error => { + res.statusCode = 400; + res.end(error.toString()); + }); + } +} + +module.exports = LinkedListRouter; diff --git a/submissions/assmass13/data-structures/routers/stack-router.js b/submissions/assmass13/data-structures/routers/stack-router.js new file mode 100644 index 0000000..d983898 --- /dev/null +++ b/submissions/assmass13/data-structures/routers/stack-router.js @@ -0,0 +1,38 @@ +const Stack = require('../structures/stack'); +const parsedBodyValues = require('../request-handler'); + +class StackRouter { + constructor() { + this.stack = new Stack(); + this.routes = { + 'POST /stack': this.postStackRoute.bind(this), + 'DELETE /stack': this.deleteStackRoute.bind(this) + }; + } + + async postStackRoute(req, res) { + return parsedBodyValues(req) + .then(({ add }) => { + this.stack.push(add); + res.statusCode = 201; + res.end(this.stack.showStack().toString()); + }) + .catch(error => { + res.statusCode = 400; + res.end(error.toString()); + }); + } + + deleteStackRoute(req, res) { + const removedNode = this.stack.pop(); + if (removedNode) { + res.statusCode = 200; + res.end(removedNode.value.toString()); + } else { + res.statusCode = 404; + res.end('Stack is empty.'); + } + } +} + +module.exports = StackRouter; diff --git a/submissions/assmass13/data-structures/server.js b/submissions/assmass13/data-structures/server.js new file mode 100644 index 0000000..55a2836 --- /dev/null +++ b/submissions/assmass13/data-structures/server.js @@ -0,0 +1,22 @@ +const http = require('http'); + +const StackRouter = require('./routers/stack-router'); +const LinkedListRouter = require('./routers/linked-list-router'); + +const routes = { + ...new StackRouter().routes, + ...new LinkedListRouter().routes +}; + +const noRouteFound = (req, res) => { + res.statusCode = 404; + res.end('Requested resource not found.'); +}; + +const server = http.createServer((req, res) => { + const route = `${req.method} ${req.url}`; + const handler = routes[route] || noRouteFound; + handler(req, res); +}); + +server.listen(3000); diff --git a/submissions/assmass13/data-structures/structures/linked-list.js b/submissions/assmass13/data-structures/structures/linked-list.js new file mode 100644 index 0000000..96a2bd3 --- /dev/null +++ b/submissions/assmass13/data-structures/structures/linked-list.js @@ -0,0 +1,100 @@ +const Node = require('./node'); + +module.exports = class LinkedList { + constructor() { + this.head = null; + this.tail = null; + this.length = 0; + } + + pop() { + if (!this.head) return null; + let currentNode = this.head; + let newTail = currentNode; + while (currentNode.next) { + newTail = currentNode; + currentNode = currentNode.next; + } + this.tail = newTail; + this.tail.next = null; + this.length -= 1; + if (this.length === 0) { + this.head = null; + this.tail = null; + } + return currentNode; + } + + shift() { + if (!this.head) return null; + const oldHead = this.head; + this.head = oldHead.next; + this.length -= 1; + if (this.length === 0) { + this.tail = null; + } + return oldHead; + } + + unshift(value) { + const newNode = new Node(value); + if (!this.head) { + this.head = newNode; + this.tail = newNode; + } else { + newNode.next = this.head; + this.head = newNode; + } + this.length += 1; + return this; + } + + insertBeforeSuccessors(value, successor) { + let previousNode = null; + let currentNode = this.head; + + while (currentNode) { + if (currentNode.value === successor) { + const newNode = new Node(value); + if (previousNode) previousNode.next = newNode; + else this.head = newNode; + newNode.next = currentNode; + } + + previousNode = currentNode; + currentNode = currentNode.next; + } + } + + removeValue(removeValue) { + let previousNode = null; + let currentNode = this.head; + + while (currentNode) { + if (currentNode.value === removeValue) { + if (previousNode) { + currentNode = currentNode.next; + previousNode.next = currentNode; + } else { + this.head = currentNode.next; + currentNode = this.head; + } + } + + while (currentNode && currentNode.value !== removeValue) { + previousNode = currentNode; + currentNode = currentNode.next; + } + } + } + + showList() { + const values = []; + let currentNode = this.head; + while (currentNode) { + values.push(currentNode.value); + currentNode = currentNode.next; + } + return values; + } +}; diff --git a/submissions/assmass13/data-structures/structures/node.js b/submissions/assmass13/data-structures/structures/node.js new file mode 100644 index 0000000..b777e33 --- /dev/null +++ b/submissions/assmass13/data-structures/structures/node.js @@ -0,0 +1,6 @@ +module.exports = class Node { + constructor(value) { + this.value = value; + this.next = null; + } +}; diff --git a/submissions/assmass13/data-structures/structures/stack.js b/submissions/assmass13/data-structures/structures/stack.js new file mode 100644 index 0000000..3ae32be --- /dev/null +++ b/submissions/assmass13/data-structures/structures/stack.js @@ -0,0 +1,19 @@ +const LinkedList = require('./linked-list'); + +module.exports = class Stack { + constructor() { + this.linkedList = new LinkedList(); + } + + push(value) { + return this.linkedList.unshift(value); + } + + pop() { + return this.linkedList.shift(); + } + + showStack() { + return this.linkedList.showList().reverse(); + } +};