Skip to content

Commit

Permalink
initial load
Browse files Browse the repository at this point in the history
  • Loading branch information
steveww committed Jan 10, 2018
0 parents commit ae1a16f
Show file tree
Hide file tree
Showing 33 changed files with 1,647 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.*.swp
.DS_Store

14 changes: 14 additions & 0 deletions cart/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM node:8

EXPOSE 8080

WORKDIR /opt/server

COPY package.json /opt/server/

RUN npm install

COPY server.js /opt/server/

CMD ["node", "server.js"]

18 changes: 18 additions & 0 deletions cart/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "catalogue",
"version": "1.0.0",
"description": "product catalogue REST API",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "SteveW",
"license": "Apache-2.0",
"dependencies": {
"body-parser": "^1.18.1",
"express": "^4.15.4",
"redis": "^2.8.0",
"request": "^2.83.0",
"instana-nodejs-sensor": "^1.28.0"
}
}
234 changes: 234 additions & 0 deletions cart/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
const instana = require('instana-nodejs-sensor');
const redis = require('redis');
const request = require('request');
const bodyParser = require('body-parser');
const express = require('express');

// init tracing
instana({
tracing: {
enabled: true
}
});

var redisConnected = false;

const app = express();

app.use((req, res, next) => {
res.set('Timing-Allow-Origin', '*');
res.set('Access-Control-Allow-Origin', '*');
next();
});

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

app.get('/health', (req, res) => {
var stat = {
app: 'OK',
redis: redisConnected
};
res.json(stat);
});


// get cart with id
app.get('/cart/:id', (req, res) => {
redisClient.get(req.params.id, (err, data) => {
if(err) {
console.log('ERROR', err);
res.status(500).send(err);
} else {
if(data == null) {
res.status(404).send('cart not found');
} else {
res.set('Content-Type', 'application/json');
res.send(data);
}
}
});
});

// update/create cart
app.get('/add/:id/:sku/:qty', (req, res) => {
// check quantity
var qty = parseInt(req.params.qty);
if(isNaN(qty)) {
res.status(400).send('quantity must be a number');
return;
} else if(qty < 1) {
res.status(400).send('negative quantity not allowed');
return;
}

// look up product details
getProduct(req.params.sku).then((product) => {
console.log('got product', product);
// is the product in stock?
if(product.instock == 0) {
res.status(404).send('out of stock');
return;
}
// does the cart already exist?
redisClient.get(req.params.id, (err, data) => {
if(err) {
console.log('ERROR', err);
res.status(500).send(err);
} else {
var cart;
if(data == null) {
// create new cart
cart = {
total: 0,
tax: 0,
items: []
};
} else {
cart = JSON.parse(data);
}
console.log('got cart', cart);
// add sku to cart
var item = {
qty: qty,
sku: req.params.sku,
name: product.name,
price: product.price,
subtotal: qty * product.price
};
var list = mergeList(cart.items, item, qty);
cart.items = list;
cart.total = calcTotal(cart.items);
// work out tax @ 20%
cart.tax = (cart.total - (cart.total / 1.2)).toFixed(2);

// save the new cart
saveCart(req.params.id, cart);
res.json(cart);
}
});
}).catch((err) => {
res.status(500).send(err);
});
});

// update quantity - remove item when qty == 0
app.get('/update/:id/:sku/:qty', (req, res) => {
// check quantity
var qty = parseInt(req.params.qty);
if(isNaN(qty)) {
res.status(400).send('quantity must be a number');
return;
}

// get the cart
redisClient.get(req.params.id, (err, data) => {
if(err) {
console.log('ERROR', err);
res.status(500).send(err);
} else {
if(data == null) {
res.status(404).send('cart not found');
} else {
var cart = JSON.parse(data);
var idx;
var len = cart.items.length;
for(idx = 0; idx < len; idx++) {
if(cart.items[idx].sku == req.params.sku) {
break;
}
}
if(idx == len) {
// not in list
res.status(404).send('not in cart');
} else {
if(qty == 0) {
cart.items.splice(idx, 1);
} else {
cart.items[idx].qty = qty;
cart.items[idx].subtotal = cart.items[idx].price * qty;
}
cart.total = calcTotal(cart.items);
// work out tax @ 20%
cart.tax = (cart.total - (cart.total / 1.2)).toFixed(2);
saveCart(req.params.id, cart);
res.json(cart);
}
}
}
});
});

function mergeList(list, product, qty) {
var inlist = false;
// loop through looking for sku
var idx;
var len = list.length;
for(idx = 0; idx < len; idx++) {
if(list[idx].sku == product.sku) {
inlist = true;
break;
}
}

if(inlist) {
list[idx].qty += qty;
list[idx].subtotal = list[idx].price * list[idx].qty;
} else {
list.push(product);
}

return list;
}

function calcTotal(list) {
var total = 0;
for(var idx = 0, len = list.length; idx < len; idx++) {
total += list[idx].subtotal;
}

return total;
}

function getProduct(sku) {
return new Promise((resolve, reject) => {
request('http://catalogue:8080/product/' + sku, (err, res, body) => {
if(err) {
reject(err);
} else if(res.statusCode != 200) {
reject(res.statusCode);
} else {
// return object - body is a string
resolve(JSON.parse(body));
}
});
});
}

function saveCart(id, cart) {
console.log('saving cart', cart);
redisClient.setex(id, 3600, JSON.stringify(cart), (err, data) => {
if(err) {
console.log('saveCart ERROR', err);
}
});
}

// connect to Redis
var redisClient = redis.createClient({
host: 'redis'
});

redisClient.on('error', (e) => {
console.log('Redis ERROR', e);
});
redisClient.on('ready', (r) => {
console.log('Redis READY', r);
redisConnected = true;
});

// fire it up!
const port = process.env.CART_SERVER_PORT || '8080';
app.listen(port, () => {
console.log('Started on port', port);
});
14 changes: 14 additions & 0 deletions catalogue/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM node:8

EXPOSE 8080

WORKDIR /opt/server

COPY package.json /opt/server/

RUN npm install

COPY server.js /opt/server/

CMD ["node", "server.js"]

17 changes: 17 additions & 0 deletions catalogue/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "catalogue",
"version": "1.0.0",
"description": "product catalogue REST API",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "SteveW",
"license": "Apache-2.0",
"dependencies": {
"body-parser": "^1.18.1",
"express": "^4.15.4",
"mongodb": "^2.2.33",
"instana-nodejs-sensor": "^1.28.0"
}
}
Loading

0 comments on commit ae1a16f

Please sign in to comment.