Skip to content

Instantly share code, notes, and snippets.

@lifehome
Last active October 16, 2019 03:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lifehome/a7e19d776edecaf685c0f7d39b633672 to your computer and use it in GitHub Desktop.
Save lifehome/a7e19d776edecaf685c0f7d39b633672 to your computer and use it in GitHub Desktop.
Jumbo API
const fs = require('fs'),
maths = require('mathjs'),
restify = require('restify'),
rp = require('request-promise'),
cheerio = require('cheerio'),
cheerioTableparser = require('cheerio-tableparser')
server = restify.createServer({
name: 'wrench-jumbo',
version: '1.0.1'
}),
server_socket = '/opt/httpd/it/hkno/apiserv.sock',
clist = require(__dirname + '/libs/categories.js')
server.use(restify.plugins.gzipResponse());
server.use(restify.plugins.acceptParser(["application/json"]))
// Promise: Get product JSON object
let getProductJSON = (cid = 3) => {
// Fetch and return JSON Object
return rp(`http://www.jumbo-computer.com/pricelist.aspx?id=${cid}&sort=1`).then(res=>{
if (res.match(/"gvProducts"/g) == null) return JSON.parse('{"error": "No data."}')
let $ = cheerio.load(res)
cheerioTableparser($)
let rawdata = $('table.gvProducts').parsetable(true, true, true)
// Remove garbages
delete rawdata[2]
// Process garbage
let pricing = rawdata[1].map(e=>{
return parseInt(e.replace('HK\$ ', ''))
}).sort()
// Construct statistic object
let stats = {
'min': maths.min(pricing),
'max': maths.max(pricing),
'mean': maths.round(maths.mean(pricing), 3),
'median': maths.median(pricing),
'std': maths.round(maths.std(pricing), 3)
}
// Return processed JSON object
let product = rawdata[0].reduce((arr, name, idx)=>{
arr.push({ name, price: pricing[idx] })
return arr
}, [])
return {
'merchants': product,
'statistic': stats
}
}).catch(e=>{
return JSON.parse(`{"error": ${e}}`)
})
}
// Promise: Search for product JSON object
let searchProduct = (cid, keyword) => {
// Fetch and return JSON object
return rp(`http://www.jumbo-computer.com/pricelist.aspx?id=${cid}&desc=${keyword}&sort=1`).then(res=>{
if (res.match(/"gvProducts"/g) == null) return JSON.parse('{"error": "No data."}')
let $ = cheerio.load(res)
cheerioTableparser($)
let rawdata = $('table.gvProducts').parsetable(true, true, true)
// Remove garbages
delete rawdata[2]
// Process garbage
let pricing = rawdata[1].map(e=>{
return parseInt(e.replace('HK\$ ', ''))
}).sort()
// Construct statistic object
let stats = {
'min': maths.min(pricing),
'max': maths.max(pricing),
'mean': maths.round(maths.mean(pricing), 3),
'median': maths.median(pricing),
'std': maths.round(maths.std(pricing), 3)
}
// Return processed JSON object
let product = rawdata[0].reduce((arr, name, idx)=>{
arr.push({ name, price: pricing[idx] })
return arr
}, [])
return {
'merchants': product,
'statistic': stats
}
}).catch(e=>{
return JSON.parse(`{"error": ${e}}`)
})
}
// GET request: Return price listing from Jumbo per category
let listingGETHandler = (req, res, next)=>{
if(Number(req.params.cid) && Number(req.params.cid) >= 1 && Number(req.params.cid) <= 136){
res.cache('public')
getProductJSON(req.params.cid).then(result => {
res.charSet('utf-8')
res.json(result)
})
} else res.json({"error": "Incorrect category ID.", "reference": "/jumbo/categories"})
}
// GET request: Return price listing from Jumbo per search query
let searchGETHandler = (req, res, next)=>{
res.cache('public')
searchProduct(req.params.cid, req.params.keyword).then(result =>{
res.charSet('utf-8')
res.json(result)
})
}
let emptylistingGETHandler = (req, res, next)=>{
res.json(JSON.parse('{"error": "Please input the category number followed by the endpoint.", "reference": "/jumbo/categories"}'))
}
let categoriesGETHandler = (req, res, next)=>{
res.charSet('utf-8')
res.json(clist.category)
}
server.get('/jumbo/categories', categoriesGETHandler)
server.get('/jumbo/search/:cid/:keyword', searchGETHandler)
server.get('/jumbo/listing', emptylistingGETHandler)
server.get('/jumbo/listing/:cid', listingGETHandler)
server.get('/ios/beta.mobileconfig', restify.plugins.serveStatic({
directory: './static',
file: 'ios11beta.mobileconfig'
})
)
fs.existsSync(server_socket) && fs.unlinkSync(server_socket)
server.listen(server_socket, ()=>{
fs.chmodSync(server_socket, '777');
console.log(`[*] Booting up at ${new Date()}\n[+] API server is now up, listening at: https://api.hkno.it`);
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment