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

Router Improvements - Add support for deep nested routers + Session storage fixes #25

Open
wants to merge 49 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
d575e21
Add mongo and redis in package.json
amalshehu Apr 17, 2018
ae71224
Modify store database config
amalshehu Apr 17, 2018
1fe4568
Merge branch 'master' of https://github.com/geekskool/turbo-server in…
amalshehu Apr 17, 2018
b998268
Fix storage database config (#1)
amalshehu Apr 17, 2018
5e5eebb
Fix merge conflict
amalshehu Apr 17, 2018
d56fec3
Remove test file
amalshehu Apr 17, 2018
c650c4a
Modify session database config
amalshehu Apr 17, 2018
4834c4b
Fix expiry timeout for MemoryStore
amalshehu Apr 17, 2018
f16b2e7
Set expiry time for MongoStore
amalshehu Apr 17, 2018
acf84cc
Merge branch 'master' into dev
amalshehu Apr 17, 2018
cb807b4
Fix expiry timeout for MongoStore and MemoryStore (#2)
amalshehu Apr 17, 2018
bed0ce5
Modify getHandler method
amalshehu Apr 18, 2018
ead51b4
Add tests for url with params
amalshehu Apr 18, 2018
310ae01
Reformat code
amalshehu Apr 18, 2018
5b1224f
Modify getHandler
amalshehu Apr 19, 2018
9979d87
Fix typos
amalshehu Apr 19, 2018
5ab44c4
Relocate param logic
amalshehu Apr 19, 2018
2fae8d8
Add param parser
amalshehu Apr 19, 2018
bf6266f
Update routes with param tests
amalshehu Apr 19, 2018
e9acca0
Fix routes with params
amalshehu Apr 19, 2018
a208508
Add more tests
amalshehu Apr 19, 2018
9be55ee
Fix merge conflict
amalshehu Apr 19, 2018
6b9dc38
Add temporary session variable to config
amalshehu Apr 19, 2018
4906f8b
Temporary config for session store
amalshehu Apr 19, 2018
afe1dae
Rename file stores/config -> stores/store
amalshehu Apr 19, 2018
f8a3d15
Fix merge conflict
amalshehu Apr 19, 2018
c738034
Set session store default values
amalshehu Apr 19, 2018
25def34
Modify store config
amalshehu Apr 19, 2018
85948a0
Add tests for url with param.
amalshehu Apr 19, 2018
d02108f
Fix mongo indexing issue.
amalshehu Apr 19, 2018
49c7cda
Remove paramHandler
amalshehu Apr 23, 2018
123d47d
Create settingsRouter stub
amalshehu Apr 23, 2018
3c2d78b
Created nested routers
amalshehu Apr 24, 2018
7a871a4
Modify getRouter method
amalshehu Apr 24, 2018
cec42f7
Code cleanup
amalshehu Apr 24, 2018
9ea881e
Implemented option to add nested router
amalshehu Apr 25, 2018
161af67
Fix typos
amalshehu Apr 25, 2018
a1f2530
Add tests
amalshehu Apr 25, 2018
8d3a49a
Add recursive route handler.
amalshehu Apr 25, 2018
b254eb4
Modify tests
amalshehu Apr 25, 2018
b09da71
Add another nested route
amalshehu Apr 25, 2018
6c05a0c
Modify findRouter method
amalshehu Apr 25, 2018
2f3b3b6
Merge pull request #4 from amalshehu/dev
amalshehu Apr 25, 2018
f51ae1f
Add tokenize url method
amalshehu Apr 25, 2018
7310f3f
Fix Routes chaining issue
amalshehu Apr 25, 2018
fd0d8f8
Add tests
amalshehu Apr 25, 2018
c1fd8f7
Merge pull request #5 from amalshehu/dev
amalshehu Apr 25, 2018
4fe0e12
Update tests
amalshehu Apr 25, 2018
d44802d
Fix typos
amalshehu Apr 25, 2018
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
11 changes: 10 additions & 1 deletion lib/config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@ import fs from 'fs'
const ROOT = process.cwd()
const configPath = path.join(ROOT, 'turbo-serv.json')

const configDefault = {static: {dir: 'public'}}
const configDefault = { static: { dir: 'public' } }
const sessionDefault = {
store: 'memory',
options: {
host: '0.0.0.0',
port: 0,
expire: 120
}
}

let config
try {
Expand All @@ -13,6 +21,7 @@ try {
} catch (e) {
console.log('Parser Error in config file')
config = configDefault
config.session = sessionDefault
}

config.ROOT = ROOT
Expand Down
30 changes: 10 additions & 20 deletions lib/handlers/session.mjs
Original file line number Diff line number Diff line change
@@ -1,22 +1,12 @@
import uid from 'uid-safe'
import signature from 'cookie-signature'
import MemoryStore from '../stores/memory'
// import RedisStore from '../stores/redis'
// import MongoStore from '../stores/mongo'
import { DataBase, dbOptions } from './../../lib/stores/store'

let options = {
// host: '127.0.0.2',
// port: 5432,
// expire: 120, // 2 min
// database: RedisStore
// database: MongoStore
}
let DB = options.database || MemoryStore
let sessionStoreDB = new DB()
let sessionStore = sessionStoreDB.init(options)
let sessionStoreDB = new DataBase()
let sessionStore = sessionStoreDB.init(dbOptions)

class Session {
async init (req, res) {
async init(req, res) {
let data
const SECRET = 'session'
if (req.cookies && req.cookies.sess_id) {
Expand All @@ -34,33 +24,33 @@ class Session {
this.sess_id = data.id
this.data = data
res.setCookie('sess_id', signature.sign(this.sess_id, SECRET), {
maxAge: options.expire || 60 * 60 * 24 * 7 // 1 week
maxAge: dbOptions.expire
})
}

async set (key, value) {
async set(key, value) {
let data = sessionStore.get(this.sess_id)
if (data instanceof Promise) {
data = await data
}
if (!data) {
data = {sess_id: this.sess_id}
data = { sess_id: this.sess_id }
}
data[key] = value
await sessionStore.set(this.sess_id, data)
}

get (key) {
get(key) {
let result = sessionStore.get(this.sess_id)
return result
}

delete () {
delete() {
sessionStore.delete(this.sess_id)
}
}

export default async function () {
export default async function() {
if (sessionStore instanceof Promise) {
sessionStore = await sessionStore
}
Expand Down
46 changes: 39 additions & 7 deletions lib/router.mjs
Original file line number Diff line number Diff line change
@@ -1,20 +1,52 @@

export default class Router {
constructor (path = '/') {
this.routes = {GET: {}, POST: {}}
constructor(path = '/') {
this.routes = { GET: {}, POST: {} }
this.path = path
this.isRouter = true
this.routers = []
}

get (path, fn) {
get(path, fn) {
this.routes.GET[path] = fn
}

post (path, fn) {
post(path, fn) {
this.routes.POST[path] = fn
}

getHandler (method, path) {
return this.routes[method][path]
addRouter(router) {
this.routers.push(router)
}

getHandler(method, path) {
const handler = this.routes[method][path]
return typeof handler == 'function'
? handler
: this.findRouter(method, path, this.routers)
}

findRouter(method, path, routers) {
if (!Array.isArray(routers)) routers = [routers]
for (const router of routers) {
if (path.startsWith(router.path)) {
path = path.slice(router.path.length)
const deepRouter = this.hasDeepRouter(
router,
path
.slice(1)
.split('/')
.map(token => `/${token}`)
.shift()
)
return deepRouter
? this.findRouter(method, path, deepRouter)
: router.routes[method][path]
}
}
}

hasDeepRouter(router, pathToken) {
const route = router.routers.filter(route => route.path === pathToken)
return route ? route[0] : null
}
}
31 changes: 13 additions & 18 deletions lib/server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,55 +8,50 @@ import finalHandler from './handlers/final'
import Router from './router'
import sessionHandler from './handlers/session'

const HANDLERS = [
staticHandler,
cookieParser,
sessionHandler,
bodyParser
]
const HANDLERS = [staticHandler, cookieParser, sessionHandler, bodyParser]

export default class App {
constructor () {
this.server = turbo.createServer(function (req, res) {
constructor() {
this.server = turbo.createServer(function(req, res) {
Object.assign(req, Request)
Object.assign(res, Response)
req.res = res
req._handlers = HANDLERS
res.req = req
})
this.addRouter(new Router())
this.addRoute(new Router())
}

addRouter (router) {
addRoute(router) {
if (!this.router) {
this.router = router
HANDLERS.push(function () {
HANDLERS.push(function() {
const handler = router.getHandler(this.method, this.url)
if (handler) {
return this.callHandlers(handler)
}
return null
},
finalHandler)
}, finalHandler)
}
}

getRouter () {
getRouter() {
return this.router
}

listen (port) {
listen(port) {
this.PORT = process.env.PORT || port || 5000
this.server.listen(this.PORT)
console.log('Server running on PORT ' + this.PORT)
}

close () {
close() {
this.server.close(_ => {
console.log('Shutting down App!')
process.exit()
})
}

static get Router () { return Router }
static get Router() {
return Router
}
}
13 changes: 9 additions & 4 deletions lib/stores/memory.mjs
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
export default class MemoryStore {
init () {
init(options) {
this.store = {}
this.expiryTime = options.expire
return this
}
set (key, value) {
set(key, value) {
this.store[key] = value

setTimeout(() => {
this.delete(key)
}, this.expiryTime * 1000)
}
get (key) {
get(key) {
return this.store[key]
}
delete (key) {
delete(key) {
delete this.store[key]
}
}
33 changes: 21 additions & 12 deletions lib/stores/mongo.mjs
Original file line number Diff line number Diff line change
@@ -1,30 +1,39 @@
import mongo from 'mongodb'

export default class mongoStore {
async init (options) {
let url = options.url || 'mongodb://localhost:27017/'
async init(options) {
let url = `mongodb://${options.host}:${options.port}/`
this.client = mongo.MongoClient
let db = await this.client.connect(url)
console.log('mongo db connected...')
console.log('Connected to mongo...')
this.store = db.db('session-data')
this.store
.collection('sessions')
.createIndex({ createdAt: -1 }, { expireAfterSeconds: options.expire })
return this
}

set (hash, value) {
set(hash, value) {
let data = {}
data['sess_id'] = hash
data['data'] = value
let obj = {}
obj['sess_id'] = hash
this.store.collection('sessions').replaceOne(obj, { $set: data }, { upsert: true }, (err, res) => {
if (err) {
console.log(err)
}
})
obj['createdAt'] = new Date()
this.store
.collection('sessions')
.replaceOne(obj, { $set: data }, { upsert: true }, (err, res) => {
if (err) {
console.log(err)
}
})
}

async get (key) {
let result = await this.store.collection('sessions').find({ sess_id: key }).toArray()
async get(key) {
let result = await this.store
.collection('sessions')
.find({ sess_id: key })
.toArray()
if (result.length >= 1) {
result = result[0]
if (result) {
Expand All @@ -34,7 +43,7 @@ export default class mongoStore {
return null
}

delete (key) {
delete(key) {
this.store.collection('sessions').remove({ sess_id: key })
}
}
19 changes: 19 additions & 0 deletions lib/stores/store.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import MemoryStore from './memory'
import RedisStore from './redis'
import MongoStore from './mongo'

import config from './../config'

// Available storage types: In-Memory, Redis, Mongo

let storeConfig = {
memory: MemoryStore,
redis: RedisStore,
mongo: MongoStore
}
// Set prefered DB by setting dbConfig['mongo' | 'redis' | memory]

const DataBase = storeConfig[config.session.store]
const dbOptions = config.session.options

export { DataBase, dbOptions }
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@
"cookie-signature": "^1.1.0",
"formidable": "^1.2.1",
"mime": "^2.2.0",
"mongodb": "^3.0.6",
"node-fetch": "^2.0.0",
"querystring": "^0.2.0",
"redis": "^2.8.0",
"turbo-http": "^0.3.0",
"uid-safe": "^2.1.5"
},
Expand Down
Loading