w-serv-hapi
v1.0.13
Published
A wrapper hapi for data control and synchronization between nodejs and browser.
Downloads
25
Maintainers
Readme
w-serv-hapi
A wrapper hapi for data control and synchronization between nodejs and browser.
Documentation
To view documentation or get support, visit docs.
Parts
w-serv-hapi
includes 2 parts:
w-serv-hapi-server
: for nodejs serverw-serv-hapi-client
: for nodejs and browser client
Installation
Using npm(ES6 module):
Note:
w-serv-hapi-server
andw-serv-hapi-client
is mainly dependent onlodash-es
,w-serv-webdata
,w-converhp
andwsemi
.
npm i w-serv-hapi
Example for w-serv-hapi-server:
Link: [dev source code]
import fs from 'fs'
import _ from 'lodash-es'
import WOrm from 'w-orm-mongodb/src/WOrmMongodb.mjs'
import WServHapiServer from './src/WServHapiServer.mjs'
async function run() {
//optWOrm
let optWOrm = {
url: 'mongodb://username:[email protected]:27017',
db: 'servhapi',
cl: '',
}
//tableNamesExec, tableNamesSync
let tableNamesExec = ['tabA', 'tabB']
let tableNamesSync = ['tabA']
//woItems
let woItems = {}
for (let k in tableNamesExec) {
let v = tableNamesExec[k]
let opt = { ...optWOrm, cl: v }
let wo = new WOrm(opt)
woItems[v] = wo
}
async function saveData(cl, r) {
//w
let w = woItems[cl] //一定要由woItems操作, 否則傳woItems進去WServHapiServer會無法收到change事件
//save
await w.save(r, { atomic: true }) //autoInsert: false
.then(function(msg) {
console.log('save then', cl, msg)
})
.catch(function(msg) {
console.log('save catch', cl, msg)
})
}
let r
r = [
{
id: 'id-tabA-peter',
name: 'peter',
value: 123,
},
{
id: 'id-tabA-rosemary',
name: 'rosemary',
value: 123.456,
},
{
id: 'id-tabA-kettle',
name: 'kettle',
value: 456,
},
]
await saveData('tabA', r)
r = [
{
id: 'id-tabB-peter',
name: 'peter',
value: 123,
},
{
id: 'id-tabB-rosemary',
name: 'rosemary',
value: 123.456,
},
]
await saveData('tabB', r)
let n = 0
let tn = setInterval(() => {
n++
console.log('update tabA', n)
r = {
id: 'id-tabA-peter',
name: 'peter',
value: Math.random(),
}
saveData('tabA', r)
if (n >= 5) {
clearInterval(tn)
}
}, 3000)
let procCommon = async (userId, tableName, methodName, input) => {
// console.log('procCommon call', tableName, methodName, input)
let r = await woItems[tableName][methodName](input)
// console.log('procCommon result', r)
return r
}
let uploadFile = async (userId, { name, u8a }) => {
console.log('uploadFile', userId, name, _.size(u8a))
fs.writeFileSync(name, Buffer.from(u8a))
console.log('uploadFile writeFileSync finish')
return 'finish'
}
//WServHapiServer
let instWServHapiServer = new WServHapiServer({
port: 8080,
apis: [],
getUserIDFromToken: async (token) => { //可使用async或sync函數
return 'id-for-admin'
},
useDbORM: true,
dbORMs: woItems,
operORM: procCommon, //procCommon的輸入為: userId, tableName, methodName, input
tableNamesExec,
methodsExec: ['select', 'insert', 'save', 'del'],
tableNamesSync,
extFuncs: { //接收參數第1個為userId, 之後才是前端給予參數
uploadFile,
// getUserFromID,
// downloadFileFromID,
// saveTableAndData,
//...
},
hookBefores: null,
hookAfters: null,
// fnTableTags: 'tableTags-serv-hapi.json',
})
instWServHapiServer.on('error', (err) => {
console.log(err)
})
}
run()
// save then tabA [
// { n: 1, nModified: 1, ok: 1 },
// { n: 1, nModified: 1, ok: 1 },
// { n: 1, nModified: 1, ok: 1 }
// ]
// save then tabB [ { n: 1, nModified: 1, ok: 1 }, { n: 1, nModified: 1, ok: 1 } ]
// Server running at: http://DESKTOP-5UNLNF8:8080
// Server[port:8080]: open
// update tabA 1
// save then tabA [ { n: 1, nModified: 1, ok: 1 } ]
// update tabA 2
// save then tabA [ { n: 1, nModified: 1, ok: 1 } ]
// update tabA 3
// save then tabA [ { n: 1, nModified: 1, ok: 1 } ]
// update tabA 4
// save then tabA [ { n: 1, nModified: 1, ok: 1 } ]
// update tabA 5
// save then tabA [ { n: 1, nModified: 1, ok: 1 } ]
Example for w-serv-hapi-client:
Link: [dev source code]
import FormData from 'form-data'
import WServHapiClient from './src/WServHapiClient.mjs'
async function client() {
//WServHapiClient
let instWServHapiClient = new WServHapiClient({
FormData,
getUrl: () => {
//return window.location.origin + window.location.pathname
return 'http://localhost:8080'
},
useWaitToken: false,
getToken: () => {
return '' //Vue.prototype.$store.state.userToken
},
getServerMethods: (r) => {
console.log('getServerMethods', r)
//Vue.prototype.$fapi = r
//select tabA
r.tabA.select(({ prog, p, m }) => {
console.log('select tabA', prog, p, m)
})
.then((res) => {
console.log('r.tabA.select then', res)
})
.catch((err) => {
console.log('r.tabA.select catch', err)
})
//select tabB
r.tabB.select(({ prog, p, m }) => {
console.log('select tabB', prog, p, m)
})
.then((res) => {
console.log('r.tabB.select then', res)
})
.catch((err) => {
console.log('r.tabB.select catch', err)
})
//uploadFile
r.uploadFile({
name: 'zdata.b1',
u8a: new Uint8Array([66, 97, 115]),
// u8a: new Uint8Array(fs.readFileSync('../_data/500mb.7z')), //最多500mb, 因測試使用w-converhp, 其依賴新版@hapi/pez無法處理1g檔案, 會出現: Invalid string length
}, ({ prog, p, m }) => {
console.log('uploadFile', prog, p, m)
})
},
recvData: (r) => {
console.log('recvData', r)
//Vue.prototype.$store.commit(Vue.prototype.$store.types.UpdateTableData, r)
},
getRefreshState: (r) => {
console.log('getRefreshState', 'needToRefresh', r.needToRefresh)
},
getRefreshTable: (r) => {
console.log('getRefreshTable', 'tableName', r.tableName, 'timeTag', r.timeTag)
},
getBeforeUpdateTableTags: (r) => {
console.log('getBeforeUpdateTableTags', 'needToRefresh', JSON.stringify(r.oldTableTags) !== JSON.stringify(r.newTableTags))
},
getAfterUpdateTableTags: (r) => {
console.log('getAfterUpdateTableTags', 'needToRefresh', JSON.stringify(r.oldTableTags) !== JSON.stringify(r.newTableTags))
},
getBeforePollingTableTags: () => {
console.log('getBeforePollingTableTags')
},
getAfterPollingTableTags: () => {
console.log('getAfterPollingTableTags')
},
})
instWServHapiClient.on('error', (err) => {
console.log(err)
})
}
client()
// getServerMethods {
// tabA: {
// select: [AsyncFunction: f],
// insert: [AsyncFunction: f],
// save: [AsyncFunction: f],
// del: [AsyncFunction: f]
// },
// tabB: {
// select: [AsyncFunction: f],
// insert: [AsyncFunction: f],
// save: [AsyncFunction: f],
// del: [AsyncFunction: f]
// },
// uploadFile: [AsyncFunction: f]
// }
// r.tabA.select then [
// { id: 'id-tabA-peter', name: 'peter', value: 123 },
// { id: 'id-tabA-rosemary', name: 'rosemary', value: 123.456 },
// { id: 'id-tabA-kettle', name: 'kettle', value: 456 }
// ]
// r.tabB.select then [
// { id: 'id-tabB-peter', name: 'peter', value: 123 },
// { id: 'id-tabB-rosemary', name: 'rosemary', value: 123.456 }
// ]
// getBeforeUpdateTableTags needToRefresh true
// getRefreshState needToRefresh true
// getRefreshTable tableName tabA timeTag kFv3W1
// recvData {
// tableName: 'tabA',
// timeTag: 'kFv3W1',
// data: [
// { id: 'id-tabA-peter', name: 'peter', value: 123 },
// { id: 'id-tabA-rosemary', name: 'rosemary', value: 123.456 }, { id: 'id-tabA-kettle', name: 'kettle', value: 456 }
// ]
// }
// getAfterUpdateTableTags needToRefresh false
// getBeforeUpdateTableTags needToRefresh true
// getRefreshState needToRefresh true
// getRefreshTable tableName tabA timeTag 2022-03-02T17:05:39+08:00|Mkmsfo
// recvData {
// tableName: 'tabA',
// timeTag: '2022-03-02T17:05:39+08:00|Mkmsfo',
// data: [
// { id: 'id-tabA-peter', name: 'peter', value: 0.2695575980174958 },
// { id: 'id-tabA-rosemary', name: 'rosemary', value: 123.456 }, { id: 'id-tabA-kettle', name: 'kettle', value: 456 }
// ]
// }
// getAfterUpdateTableTags needToRefresh false
// getBeforeUpdateTableTags needToRefresh true
// getRefreshState needToRefresh true
// getRefreshTable tableName tabA timeTag 2022-03-02T17:05:42+08:00|hqCtKH
// recvData {
// tableName: 'tabA',
// timeTag: '2022-03-02T17:05:42+08:00|hqCtKH',
// data: [
// { id: 'id-tabA-peter', name: 'peter', value: 0.5347793912758274 },
// { id: 'id-tabA-rosemary', name: 'rosemary', value: 123.456 }, { id: 'id-tabA-kettle', name: 'kettle', value: 456 }
// ]
// }
// getAfterUpdateTableTags needToRefresh false
// getBeforeUpdateTableTags needToRefresh true
// getRefreshState needToRefresh true
// getRefreshTable tableName tabA timeTag 2022-03-02T17:05:45+08:00|FA4NPZ
// recvData {
// tableName: 'tabA',
// timeTag: '2022-03-02T17:05:45+08:00|FA4NPZ',
// data: [
// { id: 'id-tabA-peter', name: 'peter', value: 0.5995958376378325 },
// { id: 'id-tabA-rosemary', name: 'rosemary', value: 123.456 }, { id: 'id-tabA-kettle', name: 'kettle', value: 456 }
// ]
// }
// getAfterUpdateTableTags needToRefresh false
// getBeforeUpdateTableTags needToRefresh true
// getRefreshState needToRefresh true
// getRefreshTable tableName tabA timeTag 2022-03-02T17:05:48+08:00|8Q88uv
// recvData {
// tableName: 'tabA',
// timeTag: '2022-03-02T17:05:48+08:00|8Q88uv',
// data: [
// { id: 'id-tabA-peter', name: 'peter', value: 0.45049512863192986 },
// { id: 'id-tabA-rosemary', name: 'rosemary', value: 123.456 }, { id: 'id-tabA-kettle', name: 'kettle', value: 456 }
// ]
// }
// getAfterUpdateTableTags needToRefresh false
// getBeforeUpdateTableTags needToRefresh true
// getRefreshState needToRefresh true
// getRefreshTable tableName tabA timeTag 2022-03-02T17:05:51+08:00|1k3U1P
// recvData {
// tableName: 'tabA',
// timeTag: '2022-03-02T17:05:51+08:00|1k3U1P',
// data: [
// { id: 'id-tabA-peter', name: 'peter', value: 0.07134333448641317 },
// { id: 'id-tabA-rosemary', name: 'rosemary', value: 123.456 }, { id: 'id-tabA-kettle', name: 'kettle', value: 456 }
// ]
// }
// getAfterUpdateTableTags needToRefresh false
In a browser(UMD module):
Note:
w-serv-hapi-client
does't depend on any package.
[Necessary] Add script for w-serv-hapi-client.
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/w-serv-hapi-client.umd.js"></script>
Example for w-serv-hapi-client:
Link: [dev source code]
let $fapi = null
async function client() {
//WServHapiClient
let WServHapiClient = window['w-serv-hapi-client']
let wshc = new WServHapiClient({
// FormData,
getUrl: () => {
//return window.location.origin + window.location.pathname
return 'http://localhost:8080'
},
useWaitToken: false,
getToken: () => {
return '' //Vue.prototype.$store.state.userToken
},
getServerMethods: (r) => {
console.log('getServerMethods', r)
//save
//Vue.prototype.$fapi = r
$fapi = r
//select tabA
r.tabA.select(({ prog, p, m }) => {
console.log('select tabA', prog, p, m)
})
.then((res) => {
console.log('r.tabA.select then', res)
})
.catch((err) => {
console.log('r.tabA.select catch', err)
})
//select tabB
r.tabB.select(({ prog, p, m }) => {
console.log('select tabB', prog, p, m)
})
.then((res) => {
console.log('r.tabB.select then', res)
})
.catch((err) => {
console.log('r.tabB.select catch', err)
})
//uploadFile
r.uploadFile({
name: 'zdata.b1',
u8a: new Uint8Array([66, 97, 115]),
// u8a: new Uint8Array(fs.readFileSync('../_data/500mb.7z')), //最多500mb, 因測試使用w-converhp, 其依賴新版@hapi/pez無法處理1g檔案, 會出現: Invalid string length
}, ({ prog, p, m }) => {
console.log('uploadFile', prog, p, m)
})
},
recvData: (r) => {
console.log('recvData', r)
//Vue.prototype.$store.commit(Vue.prototype.$store.types.UpdateTableData, r)
},
})
return wshc
}
client()
.catch((err) => {
console.log(err)
})
// getServerMethods {tabA: {…}, tabB: {…}, uploadFile: ƒ}
// weba.html:51 select tabA 100 339 upload
// weba.html:51 select tabA 100 310 donwload
// weba.html:54 r.tabA.select then (3) [{…}, {…}, {…}]
// weba.html:62 select tabB 100 339 upload
// weba.html:62 select tabB 100 258 donwload
// weba.html:65 r.tabB.select then (2) [{…}, {…}]
// weba.html:77 uploadFile 100 386 upload
// weba.html:77 uploadFile 100 154 donwload
// weba.html:82 recvData {tableName: 'tabA', timeTag: 'g1vSkQ', data: Array(3)}
// weba.html:82 recvData {tableName: 'tabA', timeTag: '2022-01-28T14:32:24+08:00|16nHaJ', data: Array(3)}
// repeat...