Skip to content
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
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,15 @@ main fields of the resource

### meta
meta fields of the resource, such as created\_at, created\_by


## TODO
- fix eslint (migrate to latest)
- explain it is middleware first architecture
- explain how to create a middleware
- explain module vs middleware
- explain how to create a modules
- explain create module to be use as middleware or in middleware
- explain how to branch
- explain how to detour (await next)
- how to handle error. define midduleware to handle route "ERR" and throw error by this.next(this.web.Error(status, message, headers))
23 changes: 15 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env node

// In case picos was installed globally
// In case picos was installed globally,
// dynamically updates where Node.js looks for modules without changing any permanent configuration
const NP = process.env.NODE_PATH || ''
process.env.NODE_PATH = (NP ? NP + ':' : NP) + process.cwd() + '/node_modules'
require('module').Module._initPaths()
Expand All @@ -18,14 +19,20 @@ function run(opt, cb){
// Is run from cmd?
if (require.main === module) {
const args = require('pico-args')
const opt = args.parse({
service: ['service/index', 'path to service script'],
const params = {
service: ['', 'path to the service script, e.g: "service/index.json"'],
s: '@service',
mod: ['mod/', 'module path'],
m: '@service',
ratelimit: [64, 'ratelimit'],
r: '@ratelimit'
})
mod: ['mod/', 'path to the module folder'],
m: '@mod',
ratelimit: [64, 'ratelimit the concurrent requests'],
r: '@ratelimit',
help: [false, 'Usage'],
h: '@help',
}
const opt = args.parse(params)
if (!opt.service || opt.help){
return args.usage(params)
}
run(opt, err => {
if (err) return console.error(err)
})
Expand Down
6 changes: 3 additions & 3 deletions mod/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ module.exports = {

routerByRSC: (rsc, prefix = '/i') => async function(method, params) {
const rs = rsc[params.rsc]
if (!rs) return this.next(`unsupprted resource: ${params.rsc}`)
if (!rs) return this.next(null, `ERR/RESOURCE-NOT-FOUND/${params.rsc}`)
const idx = params.i ? prefix : ''
const name = `${method}/${params.rsc}${idx}`
await this.next(null, name, Object.assign({
Expand All @@ -75,13 +75,13 @@ module.exports = {

input: spec => function(input, output, ext) {
const err = pObj.validate(spec, input, output, ext)
if (err) return this.next(`invalid params [${err}]`)
if (err) return this.next(null, `ERR/INVALID-INPUT/[${err}]`)
return this.next()
},

inputNoCurry(input, spec, output, ext) {
const err = pObj.validate(spec, input, output, ext)
if (err) return this.next(`invalid params [${err}]`)
if (err) return this.next(null, `ERR/INVALID-INPUT/[${err}]`)
return this.next()
},

Expand Down
14 changes: 8 additions & 6 deletions mod/web.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ const HAS_DATA = obj => obj && (Array.isArray(obj) || Object.keys(obj).length)
const CREATE_BODY = (body, meta) => JSON.stringify(Object.assign({}, meta, {body}))
const GET_CONTENT_TYPE = (value = '') => value.split(';')[0].trim().toLowerCase()

function Error(status, message, headers){
return {status, message, headers}
}

module.exports = {
setup(cfg, rsc, paths){
const cors = cfg.cors
Expand All @@ -33,6 +37,8 @@ module.exports = {
const url = URL.parse(req.url, 1)
this.go(url.pathname, {req, res, url})
}).listen(cfg.port, cfg.host, () => process.stdout.write(`listening to ${cfg.host}:${cfg.port}\n`))

return {Error}
},

queryParser(req, query){
Expand Down Expand Up @@ -126,15 +132,11 @@ module.exports = {
res.writeHead(head.status || 200, Object.assign(headers, head.headers))
res.end(createBody(output, meta))
} else {
res.writeHead(head.status || 200, head.headers)
res.writeHead(head.status || 204, head.headers)
res.end()
}
} catch(exp) {
if (exp.isAxiosError){
console.error(exp.toJSON())
} else {
console.error(exp)
}
console.error('web error', exp.isAxiosError ? exp.toJSON() : exp)
// exp in head format? {status, headers, message}
const status = exp.status || 500
res.writeHead(status, exp.headers)
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "picos",
"version": "0.10.9",
"version": "0.11.0",
"description": "pico api service",
"main": "index.js",
"bin": {
Expand All @@ -13,11 +13,11 @@
"randexp": "^0.5.3"
},
"scripts": {
"start": "node index.js -s okapi/index.js",
"start": "node index.js -s test/service.json",
"test": "node test/index.js",
"test:cp": "jscpd --ignore 'node_modules,test' .",
"lint": "eslint . --ext .js",
"lint:fix": "eslint . --ext .js --fix"
"lint": "eslint .",
"lint:fix": "eslint . --fix"
},
"repository": {
"type": "git",
Expand Down
34 changes: 16 additions & 18 deletions src/book.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@ pico.ajax = psUtil.ajax

const fopt = {encoding: 'utf8'}

let CWD
let PD

/**
* Get current working directory
* Get picos directory. the PD is a abs, none symbolic link and contains the picos index.js
*
* @param {Function} cb - call back
*
* @returns {void} - undefined
*/
function getWD(cb){
if (CWD) return cb(CWD)
fs.readlink(symPath, (err, realPath) => {
if (err) realPath = symPath
CWD = path.dirname(realPath)
cb(CWD)
function getPD(cb){
if (PD) return cb(PD)
fs.readlink(symPath, (err, relPath) => {
if (err) PD = symPath
else PD = path.resolve(symPath, realPath)
cb(path.dirname(PD))
})
}

Expand Down Expand Up @@ -76,22 +76,20 @@ function readBook(wd, index, cb){
readPages(wd, [index], [], (err, res) => {
if (err) return cb(err)
if (!res.length) return cb(`not found: ${index}`)
if (!res[0].charAt) return cb(null, res)
if (!Array.isArray(res[0])) return cb(null, res)
readPages(wd, res[0], [], cb)
})
}

module.exports = {
open(bname, cb){
getWD(cwd => {
const bpath = getPath(cwd, bname)
const wd = path.dirname(bpath)
const name = path.basename(bpath)
readBook(wd, name, (err, book) => {
if (err) return cb(err)
cb(null, pObj.extends({}, book, {flat: 1}))
})
const bpath = getPath('.', bname)
const wd = path.dirname(bpath)
const name = path.basename(bpath)
readBook(wd, name, (err, book) => {
if (err) return cb(err)
cb(null, pObj.extends({}, book, {flat: 1}))
})
},
getWD
getPD
}
10 changes: 7 additions & 3 deletions src/pipeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function _host(radix, libs, routes, threshold){
*/
async function next(err, named, data = this.data || {}){
if (err) {
overtime.decr(1)
overtime.decr()
throw err
}
if (null != named) {
Expand All @@ -53,15 +53,19 @@ function _host(radix, libs, routes, threshold){
let route = routes[key]
if (!route) {
route = named && routes[ERROR_ROUTE]
if (!route) return console.error(`route[${named}] not found`)
if (!route) {
// no console.error if named is an empty string
named && console.error(`route[${named}] not found`)
return
}
}
overtime.incr()
return next.call(Object.assign({}, libs, {named, params, next, route, data, ptr: 0}))
}

const middleware = this.route[this.ptr++]
if (!middleware) {
return overtime.decr(3)
return overtime.decr()
}

const args = middleware.slice(1).map(key => {
Expand Down
2 changes: 1 addition & 1 deletion test/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ module.exports = {
},
sayNow(out){
Object.assign(out, {now: Date.now()})
this.next()
return this.next()
}
}