Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Http server with data structures #13

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions submissions/assmass13/data-structures/README.md
Original file line number Diff line number Diff line change
@@ -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": <int> or <str> }`
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": <int> or <str>, "successor": <int> or <str>, "remove": <int> or <str> }`\
Inserts `'add'` before each `'successor'` if provided, appends to list's head otherwise.\
Removes `'remove'` values.
33 changes: 33 additions & 0 deletions submissions/assmass13/data-structures/request-handler.js
Original file line number Diff line number Diff line change
@@ -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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

async keyword is usually not needed when you don't use await.


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;
Original file line number Diff line number Diff line change
@@ -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;
38 changes: 38 additions & 0 deletions submissions/assmass13/data-structures/routers/stack-router.js
Original file line number Diff line number Diff line change
@@ -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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here: async keyword is redundant

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;
22 changes: 22 additions & 0 deletions submissions/assmass13/data-structures/server.js
Original file line number Diff line number Diff line change
@@ -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);
100 changes: 100 additions & 0 deletions submissions/assmass13/data-structures/structures/linked-list.js
Original file line number Diff line number Diff line change
@@ -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;
}
};
6 changes: 6 additions & 0 deletions submissions/assmass13/data-structures/structures/node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = class Node {
constructor(value) {
this.value = value;
this.next = null;
}
};
19 changes: 19 additions & 0 deletions submissions/assmass13/data-structures/structures/stack.js
Original file line number Diff line number Diff line change
@@ -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();
}
};