0.1.3 basic working version with example using two service plugins (email and pushsafer)

master
David Kebler 2020-07-16 12:40:06 -07:00
commit 1fa512da93
9 changed files with 261 additions and 0 deletions

38
.eslintrc.js Normal file
View File

@ -0,0 +1,38 @@
module.exports = {
"ecmaFeatures": {
"modules": true,
"spread" : true,
"restParams" : true
},
// "plugins": [
// "unicorn"
// ],
"env": {
"es6": true,
"node": true,
"mocha": true
},
"parser": 'babel-eslint',
"parserOptions": {
"ecmaVersion": 2017,
"sourceType": "module"
},
"extends": "eslint:recommended",
"rules": {
"indent": [
"error",
2
],
// "unicorn/no-array-instanceof": "error",
"no-console": 0,
"semi": ["error", "never"],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
]
}
}

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/node_modules/
.yalc
/example/node_modules/
*.lock

5
.npmignore Normal file
View File

@ -0,0 +1,5 @@
tests/
test/
*.test.js
testing/
example/

18
LICENSE Normal file
View File

@ -0,0 +1,18 @@
/*
* Copyright (c) 2016 Appzer.de Kevin Siml
*
* Forked from and original created by: Copyright (c) 2012 Aaron Bieber <deftly@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

13
README.md Normal file
View File

@ -0,0 +1,13 @@
# UCI Notify
A live application notification system supporting notificaiton service plugins
## Quick Example App
* clone this repo
* cd to example folder
* `npm install` the pushsafter plugin and the email plugin (support smtp from gmail or aws/ses) will be loaded
* modify options of the two services and choose some default message to send by uncommenting
* `npm start`
## Usage

41
example/example.js Normal file
View File

@ -0,0 +1,41 @@
// import Notifier from '../src/notify.js'
import Notifier from '@uci-utils/notify'
;(async () => {
const notify = await Notifier.create({
// one could read a file for these environment variables or hard code them here.
services:{
pushsafer:{
module: '@uci-utils/notify-pushsafer-plugin',
k: process.env.PS_API_KEY,
d: process.env.PS_DEVICE_ID // device or group id
},
email:{
module: '@uci-utils/notify-email-plugin',
credentials:
{ user: process.env.GMAIL_SMTP_USER,
pass:process.env.GMAIL_SMTP_PW
},
to: process.env.NOTIFY_EMAIL_RECIPIENTS,
subject:'uci notification'
}
}
})
// console.log (notify._services.pushsafer._req)
// notify.disableService('pushsafer')
// notify.enableService('pushsafer')
// console.log(await notify.send('a test message','pushsafer'))
let res = await notify.send('simple message to all services')
// let res = await notify.send({subject:'subject as message',text:'this details'})
// if (res.error) console.log('errors',res)
// else console.log(res)
// res = await notify.send({subject:'object message',otherprop:'some object in body'})
if (res.error) console.log('errors',res)
// else console.log(res)
})().catch(err => {
console.log('FATAL: UNABLE TO START NOTIFER! \n',err)
process.exitCode = 1
process.kill(process.pid, 'SIGINT')
})

17
example/package.json Normal file
View File

@ -0,0 +1,17 @@
{
"name": "notify-example",
"version": "1.0.0",
"description": "notify example application",
"main": "example.js",
"scripts": {
"start": "node -r esm example.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"@uci-utils/notify": "^0.1.3",
"@uci-utils/notify-email-plugin": "^0.1.5",
"@uci-utils/notify-pushsafer-plugin": "^0.1.2",
"esm": "^3.2.25"
}
}

30
package.json Normal file
View File

@ -0,0 +1,30 @@
{
"name": "@uci-utils/notify",
"version": "0.1.3",
"description": "Integrated Notification System with service plugins",
"main": "src/notify",
"scripts": {
"example:dev": "./node_modules/.bin/nodemon -r esm ./examples/example.js",
"test": "./node_modules/.bin/mocha -r esm --timeout 30000"
},
"author": "David Kebler",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/uCOMmandIt/uci-utils.git"
},
"keywords": [
"node.js",
"notify",
"notifications"
],
"bugs": {
"url": "https://github.com/uCOMmandIt/uci-utils/issues"
},
"homepage": "https://github.com/uCOMmandIt/uci-utils#readme",
"dependencies": {
"app-root-path": "^3.0.0",
"await-to-js": "^2.1.1",
"jsonfile": "^6.0.1"
}
}

95
src/notify.js Normal file
View File

@ -0,0 +1,95 @@
// import RxClass from '@uci-utils/rx-class'
import path from 'path'
import { path as root } from 'app-root-path'
import json from 'jsonfile'
import to from 'await-to-js'
const internal = Symbol('token for Notifier Instance')
let inst
class Notifier {
constructor(token,opts={}){
if(token !== internal) {
throw new Error('\'new Notifer\' not supported. Use the \'await Notifier.create()\' async static method')
}
// super(opts)
this._services = {}
this._disabled = []
this.services = opts.services || {}
} // end constructor
static async create(opts){
inst = new Notifier(internal,opts)
console.log('notifcation service registrations:',
await Promise.all(
Object.entries(inst.services).map(async service => {
return await inst.registerService.call(inst,service[0],service[1])
}
)
)
)
return inst
}
async registerService(name,opts) {
let mod; let file
let dir = `${root}/node_modules/${opts.module || name}`
let [err,pkg] = await to(json.readFile(dir+'/package.json'))
if (!err) {
file = (dir + '/' + (pkg.main ? pkg.main : 'index.js'))
// eslint-disable-next-line
let [err,res] = await to(import(file))
if (err) return `${name} failed - no file at ${file}`
mod = res
} else {
// try in service directory for baked in plugins
console.log(opts.module||name, ': no plugin found in node_modules, looking for internal module')
let file = (`${path.dirname(__dirname)}/services/${name}.js`)
// eslint-disable-next-line
let [err,res] = await to(import(file))
if (err) return `${name} failed - no file at ${file}`
mod = res
}
// delete opts.module
const Service = mod.Service || mod.default
if (!Service.prototype.constructor) {
console.log('no default or "Service" class was exported from plugin')
return `${name} failed`
}
else this._services[name] = new Service(opts)
return `${name} registered`
}
disableService(name) {
this._disabled.push(name)
}
enableService(name) {
this._disabled= this._disabled.filter(service=>service!==name)
}
async send (msg,service,opts={}) {
if (service) {
if (this._services[service]) return await this._services[service].send(msg,opts)
}
let response = {}
await Promise.all(
Object.entries(this._services).map(async service => {
let res = this._disabled.includes(service[0]) ? 'disabled' : await service[1].send(msg,opts[service[0]])
if (res.error) response.error ? response.error[service[0]] = res.error : response = { error:{[service[0]]:res.error}}
response[service[0]]=res
}
)
)
return response
}
getService(name) { return this._services[name]}
} // end Notifier class
export default Notifier
export { Notifier }