iosignal 0.0.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +170 -0
  2. package/auth_file.json +13 -0
  3. package/auth_file.mjs +23 -0
  4. package/dist/iosignal.cjs +2 -0
  5. package/dist/iosignal.esm.js +3 -0
  6. package/dist/iosignal.esm.js.map +1 -0
  7. package/dist/iosignal.min.js +3 -0
  8. package/dist/iosignal.min.js.map +1 -0
  9. package/img/iosignal_stack.png +0 -0
  10. package/index.js +19 -0
  11. package/indexWebBrowser.js +13 -0
  12. package/package.json +48 -6
  13. package/rollup.config.js +69 -0
  14. package/src/api/RedisAPI.js +68 -0
  15. package/src/api/api_constant.js +7 -0
  16. package/src/api/api_reply.js +34 -0
  17. package/src/api/api_sudo.js +96 -0
  18. package/src/auth/Auth_Env.js +78 -0
  19. package/src/auth/Auth_File.js +75 -0
  20. package/src/auth/Auth_Redis.js +50 -0
  21. package/src/auth/BohoAuth.js +168 -0
  22. package/src/client/CongPacket.js +150 -0
  23. package/src/client/IOCongSocket.js +88 -0
  24. package/src/client/IOCore.js +959 -0
  25. package/src/client/IOWS.js +81 -0
  26. package/src/client/IOWebSocket.js +96 -0
  27. package/src/common/constants.js +159 -0
  28. package/src/common/quotaTable.js +61 -0
  29. package/src/common/util.js +61 -0
  30. package/src/server/FileLogger.js +30 -0
  31. package/src/server/Manager.js +521 -0
  32. package/src/server/Metric.js +154 -0
  33. package/src/server/Server.js +136 -0
  34. package/src/server/ServerRemote.js +235 -0
  35. package/src/server/ServerRemoteCore.js +467 -0
  36. package/src/server/serverOption.js +55 -0
  37. package/test-browser/favicon.ico +0 -0
  38. package/test-browser/index.html +93 -0
  39. package/test-browser/server.js +8 -0
  40. package/test-client-nodejs/client.cjs +17 -0
  41. package/test-client-nodejs/client.mjs +17 -0
  42. package/test-server/server-commonjs.cjs +8 -0
  43. package/test-server/server-esm.mjs +19 -0
  44. package/test-server/test-Auth_Env.js +17 -0
  45. package/test-server/test-Auth_File.js +9 -0
  46. package/test-server/test-api_reply.js +10 -0
  47. package/test-server/test-api_sudo.js +11 -0
Binary file
package/index.js ADDED
@@ -0,0 +1,19 @@
1
+ export { IOCongSocket } from './src/client/IOCongSocket.js'
2
+ export { IOWS as IO } from './src/client/IOWS.js'
3
+ export { pack, CongRx } from './src/client/CongPacket.js'
4
+ export { Server } from './src/server/Server.js'
5
+ export { serverOption } from './src/server/serverOption.js'
6
+ export { FileLogger } from './src/server/FileLogger.js'
7
+ export * from './src/common/constants.js'
8
+
9
+ // boho auth
10
+ export * from 'boho'
11
+ export { BohoAuth } from './src/auth/BohoAuth.js'
12
+ export { Auth_File } from './src/auth/Auth_File.js'
13
+ export { Auth_Env } from './src/auth/Auth_Env.js'
14
+ export { Auth_Redis } from './src/auth/Auth_Redis.js'
15
+
16
+ // api
17
+ export * as api_reply from './src/api/api_reply.js'
18
+ export * as api_sudo from './src/api/api_sudo.js'
19
+ export { RedisAPI } from './src/api/RedisAPI.js'
@@ -0,0 +1,13 @@
1
+ import { IO } from './src/client/IOWebSocket.js'
2
+ import { Boho, RAND, MBP, BohoMsg, Meta, MetaSize , sha256, Buffer } from 'boho'
3
+
4
+ Boho.RAND = RAND;
5
+ Boho.BohoMsg = BohoMsg;
6
+ Boho.Meta = Meta;
7
+ Boho.MetaSize = MetaSize;
8
+ Boho.sha256 = sha256;
9
+ IO.Boho = Boho;
10
+ IO.MBP = MBP;
11
+ IO.Buffer = Buffer;
12
+
13
+ export default IO;
package/package.json CHANGED
@@ -1,13 +1,55 @@
1
1
  {
2
2
  "name": "iosignal",
3
- "version": "0.0.1",
3
+ "version": "1.0.0",
4
4
  "description": "iosignal",
5
5
  "type": "module",
6
- "main": "index.js",
6
+ "main": "./dist/iosignal.cjs",
7
+ "exports": {
8
+ "import": "./index.js",
9
+ "require": "./dist/iosignal.cjs"
10
+ },
11
+ "browser": "./dist/iosignal.min.js",
12
+ "browser_esm": "./dist/iosignal.esm.js",
13
+ "esm": "./dist/iosignal.mjs",
14
+ "devDependencies": {
15
+ "@rollup/plugin-commonjs": "^17.1.0",
16
+ "@rollup/plugin-json": "^6.0.1",
17
+ "@rollup/plugin-node-resolve": "^11.2.1",
18
+ "@rollup/plugin-replace": "^4.0.0",
19
+ "@rollup/plugin-terser": "^0.4.4",
20
+ "mocha": "^9.2.2",
21
+ "redis": "^4.6.12",
22
+ "rollup": "^2.79.1"
23
+ },
7
24
  "scripts": {
8
- "test": "echo \"Error: no test specified\" && exit 1"
25
+ "build": "rollup -c",
26
+ "start": "node ./test-browser/server.js"
27
+ },
28
+ "engines": {
29
+ "node": ">=15.2.0"
30
+ },
31
+ "author": {
32
+ "name": "Lee Dongeun",
33
+ "email": "sixgen@gmail.com"
34
+ },
35
+ "license": "MIT",
36
+ "dependencies": {
37
+ "boho": "^0.8.2",
38
+ "commander": "^9.5.0",
39
+ "eventemitter3": "^5.0.1",
40
+ "meta-buffer-pack": "^1.3.1",
41
+ "ws": "^8.16.0"
42
+ },
43
+ "optionalDependencies": {
44
+ "bufferutil": "^4.0.8",
45
+ "utf-8-validate": "^6.0.3"
46
+ },
47
+ "repository": {
48
+ "type": "git",
49
+ "url": "git://github.com/remocons/iosignal.git"
9
50
  },
10
- "keywords": [],
11
- "author": "Lee Dongeun",
12
- "license": "MIT"
51
+ "homepage": "https://iosignal.net",
52
+ "keywords": [
53
+ "io","pubsub","arduino","iot","auth","signal"
54
+ ]
13
55
  }
@@ -0,0 +1,69 @@
1
+ import replace from '@rollup/plugin-replace'
2
+ import resolve from '@rollup/plugin-node-resolve'
3
+ import commonjs from '@rollup/plugin-commonjs'
4
+ import terser from '@rollup/plugin-terser'
5
+ import json from '@rollup/plugin-json'
6
+ import pkg from './package.json'
7
+
8
+ export default [
9
+ {
10
+ input: './indexWebBrowser.js',
11
+ output: [
12
+ {
13
+ file: pkg.browser,
14
+ format: 'iife',
15
+ name: 'IO',
16
+ sourcemap: true,
17
+ }
18
+
19
+ ],
20
+ plugins: [
21
+ replace({
22
+ crypto: '',
23
+ delimiters: ['import { webcrypto } from \'', '\''],
24
+ preventAssignment: true
25
+ }),
26
+ resolve(),
27
+ commonjs()
28
+ ,terser()
29
+ ]
30
+ }
31
+ ,{
32
+ input: './src/client/IOWebSocket.js',
33
+ output: [
34
+ {
35
+ file: pkg.browser_esm,
36
+ format: 'es', //
37
+ sourcemap: true,
38
+ }
39
+ ],
40
+ plugins: [
41
+ replace({
42
+ crypto: '',
43
+ delimiters: ['import { webcrypto } from \'', '\''],
44
+ preventAssignment: true
45
+ }),
46
+ resolve(),
47
+ commonjs()
48
+ ,terser()
49
+ ]
50
+ }
51
+
52
+ ,{
53
+ input: './index.js',
54
+ output: [
55
+ { file: pkg.main,
56
+ format: 'cjs'
57
+ }
58
+ ],
59
+ plugins: [
60
+ resolve({
61
+ preferBuiltins: true
62
+ }),
63
+ json(),
64
+ commonjs()
65
+ ,terser()
66
+ ]
67
+ }
68
+
69
+ ]
@@ -0,0 +1,68 @@
1
+ import { STATUS } from './api_constant.js'
2
+
3
+ const MIN_LEVEL = 200;
4
+ const COMMANDS = [
5
+ 'GET', 'SET',
6
+ 'HGETALL', 'HGET',
7
+ 'HSET', 'SADD',
8
+ 'SISMEMBER', 'SMEMBERS',
9
+ 'EXISTS', 'SREM',
10
+ 'DEL', 'KEYS',
11
+ 'SAVE'
12
+ ]
13
+
14
+ export class RedisAPI{
15
+ constructor( redisClient, _minLevel ){
16
+ if( !redisClient ){
17
+ throw new Error("RedisAPI constructor: no redisClient")
18
+ }
19
+ this.redisClient = redisClient
20
+ this.minLevel = _minLevel ? _minLevel : MIN_LEVEL
21
+ this.commands = COMMANDS
22
+ }
23
+
24
+
25
+ checkPermission(remote ,req){
26
+ console.log('checkPermission', remote.level , 'vs', this.minLevel )
27
+ if( remote.level >= this.minLevel ){
28
+ return true
29
+ }else{
30
+ return false
31
+ }
32
+ }
33
+
34
+
35
+ async request(remote, req ){
36
+
37
+ let result;
38
+ let status = STATUS.OK; // *0~127: ok , 128~*255 :error
39
+ try {
40
+ // console.log(req)
41
+ let cmd = req.topic
42
+ cmd = cmd.toUpperCase()
43
+ if( COMMANDS.includes(cmd)){
44
+ console.log('RedisAPI call:', cmd, req.args)
45
+
46
+ if( req.args.length > 0 ){
47
+ result = await this.redisClient[cmd]( ...req.args )
48
+ }else{
49
+ result = await this.redisClient[cmd]()
50
+ }
51
+
52
+ // console.log('RedisAPI: result:', result)
53
+
54
+ }else{
55
+ // result = 'RedisAPI: no such a cmd '+ cmd;
56
+ status = STATUS.ERROR;
57
+ }
58
+ remote.response( req.mid, status , result)
59
+ } catch (e) {
60
+ remote.response( req.mid, STATUS.ERROR ,e.message )
61
+ }
62
+
63
+ }
64
+
65
+ }
66
+
67
+
68
+
@@ -0,0 +1,7 @@
1
+
2
+ export const STATUS = {
3
+ OK: 0,
4
+ //0~127: success
5
+ //128~255: fail
6
+ ERROR: 255
7
+ }
@@ -0,0 +1,34 @@
1
+
2
+
3
+ import { STATUS } from './api_constant.js'
4
+
5
+ const MIN_LEVEL = 0;
6
+
7
+ export function checkPermission(remote){
8
+ if( remote.level >= MIN_LEVEL ){
9
+ return true
10
+ }else{
11
+ return false
12
+ }
13
+ }
14
+
15
+ export async function echo( remote , req)
16
+ {
17
+ if( !req.args)
18
+ remote.response( req.mid, STATUS.ERROR , 'no message to echo' )
19
+ else
20
+ remote.response( req.mid, STATUS.OK , req.args )
21
+ }
22
+
23
+ export async function date( remote , req)
24
+ {
25
+ let r = new Date().toUTCString()
26
+ remote.response( req.mid, STATUS.OK , r)
27
+ }
28
+
29
+ export async function unixtime( remote , req)
30
+ {
31
+ let r = Math.floor( Date.now() /1000)
32
+ remote.response( req.mid, STATUS.OK , r)
33
+ }
34
+
@@ -0,0 +1,96 @@
1
+ import { STATUS } from './api_constant.js'
2
+
3
+ const MIN_LEVEL = 255;
4
+
5
+ export const commands = [
6
+ 'cid','remotes','clients',
7
+ 'channels','subscribers',
8
+ 'remote', 'client', 'close',
9
+ 'addauth' , 'getauth' ,'delauth',
10
+ 'getauthidlist', 'getdevicelist',
11
+ 'adddevice' ,'getdevice','deldevice'
12
+ ]
13
+
14
+
15
+ export function checkPermission(remote){
16
+ if( remote.level >= MIN_LEVEL ){
17
+ return true
18
+ }else{
19
+ return false
20
+ }
21
+ }
22
+
23
+ export async function request( remote, req) {
24
+ // console.log(req )
25
+ let result;
26
+ let status = 0;
27
+ try {
28
+ let cmd = req.topic;
29
+ cmd = cmd.toLowerCase()
30
+ if (cmd == 'cid') {
31
+ result = remote.manager.metric.getCIdList()
32
+ } else if (cmd == 'remotes' || cmd == 'clients') {
33
+ result = remote.manager.metric.getRemotes()
34
+ } else if (cmd == 'channels') {
35
+ result = remote.manager.metric.getChannelList()
36
+ } else if (cmd == 'subscribers') {
37
+ let ch = req.$[0]
38
+ if (ch) result = remote.manager.metric.getSubscribers(ch)
39
+ } else if (cmd == 'remote' || cmd == 'client') {
40
+ let cid = req.$[0]
41
+ let mode = req.$[1]
42
+ if (cid) result = remote.manager.metric.getRemoteByCId(cid, mode)
43
+
44
+ } else if (cmd == 'close') {
45
+ if (req.$[0]) result = remote.manager.closeRemoteByCId(req.$[0])
46
+
47
+ } else if (cmd == 'addauth' || cmd == 'adddevice') {
48
+ // console.log('## api_sudo: addauth ', remote.manager.authManager , req.$.length)
49
+ if (remote.manager.authManager && req.$.length == 4) {
50
+ if (remote.manager.authManager.addAuth) {
51
+ let did = req.$[0]
52
+ let dkey = req.$[1]
53
+ let cid = req.$[2]
54
+ let level = req.$[3]
55
+ // console.log('###### did,dkey,cid,level: ', did,dkey,cid,level)
56
+ result = await remote.manager.authManager.addAuth(did, dkey, cid, level)
57
+ }
58
+
59
+ }
60
+ } else if (cmd == 'delauth' || cmd == 'deldevice') {
61
+ if (remote.manager.authManager && req.$.length == 1) {
62
+ if (remote.manager.authManager.delAuth) {
63
+ let did = req.$[0]
64
+ result = await remote.manager.authManager.delAuth(did)
65
+ }
66
+ }
67
+ } else if (cmd == 'getauth' || cmd == 'getdevice') {
68
+ if (remote.manager.authManager && req.$.length == 1) {
69
+ if (remote.manager.authManager.getAuth) {
70
+ let did = req.$[0]
71
+ result = await remote.manager.authManager.getAuth(did)
72
+ }
73
+ }
74
+ } else if (cmd == 'getauthidlist' || cmd == 'getdevicelist') {
75
+ if (remote.manager.authManager ) {
76
+ if (remote.manager.authManager.getAuthIdList ) {
77
+ result = await remote.manager.authManager.getAuthIdList()
78
+ }
79
+ }
80
+ } else{
81
+ status = STATUS.ERROR;
82
+ result = "api sudo: no such a cmd: " + cmd
83
+ }
84
+
85
+ // console.log('req_sudo: result', result)
86
+ remote.response(req.mid, status, result)
87
+
88
+ } catch (e) {
89
+ // console.log('req_sudo err:',e.message)
90
+ remote.response(req.mid, STATUS.ERROR , e.message )
91
+ }
92
+
93
+ }
94
+
95
+
96
+
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Auth_Env.js
3
+ *
4
+ * You can use environment variable BOHO_AUTH.
5
+ *
6
+ * BOHO_AUTH=id1.key1.level,id2:key2.level
7
+ *
8
+ * or constructor parameter.
9
+ *
10
+ *
11
+ * [ authInfo ]
12
+ * id: <String> max 8chars
13
+ * key: <String>
14
+ * level: <Numbrer> range: 0~255
15
+ * separator: ','
16
+ *
17
+ * example => process.env.BOHO_AUTH=id1.key1.255,id2.key2.200
18
+ */
19
+
20
+ import { BohoAuth } from './BohoAuth.js';
21
+ import { sha256 } from 'boho'
22
+
23
+ export class Auth_Env extends BohoAuth {
24
+ constructor( authInfo) {
25
+ super()
26
+ let id_keys;
27
+ if( authInfo ){
28
+ id_keys = authInfo.split(',')
29
+ }else if ( process.env.BOHO_AUTH) {
30
+ authInfo = process.env.BOHO_AUTH
31
+ id_keys = process.env.BOHO_AUTH.split(',')
32
+ }else{
33
+ console.log("Auth_Env: None of process.env.BOHO_AUTH or authInfo")
34
+ process.exit()
35
+ }
36
+
37
+ this.AUTH = new Map();
38
+
39
+ if (id_keys.length >= 1) {
40
+ id_keys.forEach(v => {
41
+
42
+ let did = v.split('.')[0]
43
+ let key = v.split('.')[1]
44
+ let level = v.split('.')[2]
45
+ level = parseInt(level)
46
+
47
+ // console.log('typeof level', level, typeof level)
48
+
49
+ if (did && key && typeof level =='number') {
50
+ let cid = did;
51
+ this.addAuth(did, key, cid, level)
52
+ } else {
53
+ console.log("Wrong process.env.BOHO_AUTH authentication value.", id, key, level)
54
+ process.exit();
55
+ }
56
+ })
57
+
58
+ } else {
59
+ console.log("Wrong process.env.BOHO_AUTH authentication value.")
60
+ process.exit();
61
+ }
62
+
63
+ }
64
+
65
+ async getAuth(id) {
66
+ return this.AUTH.get(id)
67
+ }
68
+ async getAuthIdList() {
69
+ return Array.from( this.AUTH.keys() )
70
+ }
71
+
72
+ addAuth(id, keyStr, cid, level = 0) {
73
+ let Base64hashKey = Buffer.from(sha256.hash(keyStr)).toString('base64')
74
+ this.AUTH.set(id, { key: Base64hashKey, cid: cid, level: level })
75
+ }
76
+
77
+ }
78
+
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Auth_File
3
+ */
4
+ import { BohoAuth } from './BohoAuth.js';
5
+ import { readFileSync } from 'fs'
6
+ import { sha256 } from 'boho'
7
+ import path from 'path'
8
+
9
+ export class Auth_File extends BohoAuth{
10
+ constructor( _path ){
11
+ super()
12
+ this.AUTH = new Map();
13
+ let pathObj = path.parse(_path)
14
+ this.path = path.resolve(_path)
15
+ console.log('auth from file path:', this.path )
16
+ let ext = pathObj.ext;
17
+ if( ext.toLowerCase() == '.js' || ext.toLowerCase() == '.mjs'){
18
+ // Read auth data from file
19
+ console.log( "#JS path:", this.path );
20
+ this.loadAuthInfoFile_JS( this.path)
21
+ }else if( ext.toLowerCase() == '.json') {
22
+ console.log( "#JSON path:", this.path );
23
+ this.loadAuthInfoFile_JSON(this.path)
24
+ }else{
25
+ console.log('no authinfofile path.')
26
+ }
27
+ }
28
+
29
+
30
+ async getAuth( id ){
31
+ return this.AUTH.get( id )
32
+ }
33
+
34
+ async getAuthIdList() {
35
+ return Array.from( this.AUTH.keys() )
36
+ }
37
+
38
+ //loaded when server start.
39
+ loadAuthInfoFile_JS(path){
40
+
41
+ import( path ).then(( file ) => {
42
+
43
+ console.log( file.authInfo );
44
+ file.authInfo.forEach( item =>{
45
+ this.addAuth(...item )
46
+ })
47
+ console.log('total AUTH INFO size: ', this.AUTH.size )
48
+ }).catch(e=>{
49
+ console.log(e)
50
+ })
51
+
52
+
53
+ }
54
+
55
+ loadAuthInfoFile_JSON(path){
56
+ let file = readFileSync( path )
57
+ file = new TextDecoder().decode( file )
58
+ // console.log(file )
59
+ let list = JSON.parse( file )
60
+ list.forEach( item =>{
61
+ this.addAuth(...item )
62
+ })
63
+ console.log('total AUTH INFO size: ', this.AUTH.size )
64
+
65
+ }
66
+
67
+ addAuth( id, keyStr , cid , level = 0){
68
+ let Base64hashKey = Buffer.from( sha256.hash(keyStr)).toString('base64')
69
+ this.AUTH.set( id, { key: Base64hashKey, cid: cid, level: level } )
70
+ }
71
+
72
+
73
+
74
+ }
75
+
@@ -0,0 +1,50 @@
1
+
2
+ /**
3
+ * Auth_Redis
4
+ */
5
+ import { BohoAuth } from './BohoAuth.js';
6
+ import { sha256 } from 'boho'
7
+ const DEVICE_PREFIX = "device:"
8
+
9
+ export class Auth_Redis extends BohoAuth{
10
+ constructor( redisClient ){
11
+ super()
12
+ if( !redisClient ){
13
+ throw new Error("AuthRedis constructor: no redisClient")
14
+ }
15
+ this.redis = redisClient
16
+ }
17
+
18
+ // get device key from DB. (for Boho auth.)
19
+ async getAuth( id ){
20
+ let result = await this.redis.hGetAll(DEVICE_PREFIX + id)
21
+ // console.log('Auth_Redis: getAuth req id result',id, result)
22
+ if(result.key) return result
23
+ }
24
+
25
+
26
+ async getAuthIdList() {
27
+ let result = await this.redis.keys( DEVICE_PREFIX + '*')
28
+ result = result.map( v=> {
29
+ return v.split(':')[1]
30
+ })
31
+ if(result) return result
32
+ }
33
+
34
+ // add device auth info
35
+ async addAuth( id, keyStr , cid = '', level = 0){
36
+ // console.log('addAuth', id, keyStr, cid, level)
37
+ let Base64hashKey = Buffer.from( sha256.hash( keyStr)).toString('base64')
38
+ return this.redis.hSet( DEVICE_PREFIX + id, {'key': Base64hashKey, 'cid': cid ,'level': level} )
39
+ }
40
+
41
+ async delAuth( id ){
42
+ return this.redis.del( DEVICE_PREFIX + id )
43
+ }
44
+
45
+ async save( id ){
46
+ return this.redis.save()
47
+ }
48
+
49
+ }
50
+