diff --git a/.eslintrc.json b/.eslintrc.json index f82bef2..6b30f1a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -9,14 +9,8 @@ "ecmaVersion": 2020 }, "rules": { - "indent": [ - "error", - 2 - ], - "linebreak-style": [ - "error", - "unix" - ], + "indent": ["error", 2], + "linebreak-style": ["error", "unix"], "quotes": [ "error", "single", @@ -24,28 +18,12 @@ "allowTemplateLiterals": true } ], - "semi": [ - "error", - "always" - ], - "no-loop-func": [ - "error" - ], - "block-spacing": [ - "error", - "always" - ], - "camelcase": [ - "error" - ], - "eqeqeq": [ - "error", - "always" - ], - "strict": [ - "error", - "global" - ], + "semi": ["error", "always"], + "no-loop-func": ["error"], + "block-spacing": ["error", "always"], + "camelcase": ["error"], + "eqeqeq": ["error", "always"], + "strict": ["error", "global"], "brace-style": [ "error", "1tbs", @@ -53,10 +31,7 @@ "allowSingleLine": true } ], - "comma-style": [ - "error", - "last" - ], + "comma-style": ["error", "last"], "comma-spacing": [ "error", { @@ -64,13 +39,8 @@ "after": true } ], - "eol-last": [ - "error" - ], - "func-call-spacing": [ - "error", - "never" - ], + "eol-last": ["error"], + "func-call-spacing": ["error", "never"], "key-spacing": [ "error", { @@ -112,33 +82,14 @@ "properties": true } ], - "new-parens": [ - "error" - ], - "no-lonely-if": [ - "error" - ], - "no-trailing-spaces": [ - "error" - ], - "no-unneeded-ternary": [ - "error" - ], - "no-whitespace-before-property": [ - "error" - ], - "object-curly-spacing": [ - "error", - "always" - ], - "operator-assignment": [ - "error", - "always" - ], - "operator-linebreak": [ - "error", - "after" - ], + "new-parens": ["error"], + "no-lonely-if": ["error"], + "no-trailing-spaces": ["error"], + "no-unneeded-ternary": ["error"], + "no-whitespace-before-property": ["error"], + "object-curly-spacing": ["error", "always"], + "operator-assignment": ["error", "always"], + "operator-linebreak": ["error", "after"], "semi-spacing": [ "error", { @@ -146,10 +97,7 @@ "after": true } ], - "space-before-blocks": [ - "error", - "always" - ], + "space-before-blocks": ["error", "always"], "space-before-function-paren": [ "error", { @@ -158,13 +106,8 @@ "asyncArrow": "always" } ], - "space-in-parens": [ - "error", - "never" - ], - "space-infix-ops": [ - "error" - ], + "space-in-parens": ["error", "never"], + "space-infix-ops": ["error"], "space-unary-ops": [ "error", { @@ -175,94 +118,45 @@ } } ], - "no-unreachable": [ - "error" - ], - "no-global-assign": [ - "error" - ], - "no-self-compare": [ - "error" - ], - "no-unmodified-loop-condition": [ - "error" - ], + "no-unreachable": ["error"], + "no-global-assign": ["error"], + "no-self-compare": ["error"], + "no-unmodified-loop-condition": ["error"], "no-constant-condition": [ "error", { "checkLoops": false } ], - "no-console": [ - "off" - ], - "no-useless-concat": [ - "error" - ], - "no-useless-escape": [ - "error" - ], - "no-shadow-restricted-names": [ - "error" - ], + "no-console": ["off"], + "no-useless-concat": ["error"], + "no-useless-escape": ["error"], + "no-shadow-restricted-names": ["error"], "no-use-before-define": [ "error", { "functions": false } ], - "arrow-parens": [ - "error", - "as-needed" - ], - "arrow-body-style": [ - "error", - "as-needed" - ], - "arrow-spacing": [ - "error" - ], + "arrow-parens": ["error", "as-needed"], + "arrow-body-style": ["error", "as-needed"], + "arrow-spacing": ["error"], "no-confusing-arrow": [ "error", { "allowParens": true } ], - "no-useless-computed-key": [ - "error" - ], - "no-useless-rename": [ - "error" - ], - "no-var": [ - "error" - ], - "object-shorthand": [ - "error", - "always" - ], - "prefer-arrow-callback": [ - "error" - ], - "prefer-const": [ - "error" - ], - "prefer-numeric-literals": [ - "error" - ], - "prefer-rest-params": [ - "error" - ], - "prefer-spread": [ - "error" - ], - "rest-spread-spacing": [ - "error", - "never" - ], - "template-curly-spacing": [ - "error", - "never" - ] + "no-useless-computed-key": ["error"], + "no-useless-rename": ["error"], + "no-var": ["error"], + "object-shorthand": ["error", "always"], + "prefer-arrow-callback": ["error"], + "prefer-const": ["error"], + "prefer-numeric-literals": ["error"], + "prefer-rest-params": ["error"], + "prefer-spread": ["error"], + "rest-spread-spacing": ["error", "never"], + "template-curly-spacing": ["error", "never"] } } diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..74d3eb4 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "singleQuote": true, + "trailingComma": "es5", + "overrides": [ + { + "files": ".prettierrc", + "options": { "parser": "json" } + } + ] +} diff --git a/application/api/auth.1/signIn.js b/application/api/auth.1/signIn.js index a8c63f1..0331920 100644 --- a/application/api/auth.1/signIn.js +++ b/application/api/auth.1/signIn.js @@ -7,5 +7,5 @@ if (!user || !valid) throw new Error('Incorrect login or password'); console.log(`Logged user: ${login}`); return { result: 'success', userId: user.id }; - } + }, }); diff --git a/application/api/cms.1/.eslintrc.json b/application/api/cms.1/.eslintrc.json index d1e6a44..25a2ad5 100644 --- a/application/api/cms.1/.eslintrc.json +++ b/application/api/cms.1/.eslintrc.json @@ -1,9 +1,6 @@ { "rules": { - "strict": [ - "error", - "never" - ] + "strict": ["error", "never"] }, "globals": { "application": "readonly", diff --git a/application/api/cms.1/about.js b/application/api/cms.1/about.js index 65ea0be..6eea683 100644 --- a/application/api/cms.1/about.js +++ b/application/api/cms.1/about.js @@ -24,5 +24,5 @@ async () => [ 'programming including C, C++, JavaScript, Rust, Go, Swift, Java,', 'Objective-C, Kotlin, C#, Delphi, Assembler, Python, Haskell, etc.', 'We provide solutions for Unix/Linux, Windows, OSX, Android, Internet', - 'solutions and Embedded systems.' + 'solutions and Embedded systems.', ]; diff --git a/application/api/example.1/remoteMethod.js b/application/api/example.1/remoteMethod.js index 0ea0279..39dc334 100644 --- a/application/api/example.1/remoteMethod.js +++ b/application/api/example.1/remoteMethod.js @@ -3,5 +3,5 @@ method: async ({ ...args }) => { console.debug({ remoteMethod: args }); return { result: 'success' }; - } + }, }); diff --git a/application/api/example.1/wait.js b/application/api/example.1/wait.js index 132277e..ee2c122 100644 --- a/application/api/example.1/wait.js +++ b/application/api/example.1/wait.js @@ -1,3 +1,4 @@ -async ({ delay }) => new Promise(resolve => { - setTimeout(resolve, delay, 'done'); -}); +async ({ delay }) => + new Promise((resolve) => { + setTimeout(resolve, delay, 'done'); + }); diff --git a/application/api/example.1/webHook.js b/application/api/example.1/webHook.js index 9af71e7..57b99ba 100644 --- a/application/api/example.1/webHook.js +++ b/application/api/example.1/webHook.js @@ -3,5 +3,5 @@ method: async ({ ...args }) => { console.debug({ webHook: args }); return { result: 'success' }; - } + }, }); diff --git a/application/api/system.1/introspect.js b/application/api/system.1/introspect.js index c307e61..d055e57 100644 --- a/application/api/system.1/introspect.js +++ b/application/api/system.1/introspect.js @@ -1,4 +1,4 @@ ({ access: 'public', - method: application.introspect + method: application.introspect, }); diff --git a/application/config/.eslintrc.json b/application/config/.eslintrc.json index 6aeb0d2..22afafd 100644 --- a/application/config/.eslintrc.json +++ b/application/config/.eslintrc.json @@ -1,8 +1,5 @@ { "rules": { - "strict": [ - "error", - "never" - ] + "strict": ["error", "never"] } } diff --git a/application/domain/.eslintrc.json b/application/domain/.eslintrc.json index 4cb85e1..1198765 100644 --- a/application/domain/.eslintrc.json +++ b/application/domain/.eslintrc.json @@ -1,9 +1,6 @@ { "rules": { - "strict": [ - "error", - "never" - ] + "strict": ["error", "never"] }, "globals": { "application": "readonly", diff --git a/application/domain/database/start.js b/application/domain/database/start.js index 80a2b6e..60ffab9 100644 --- a/application/domain/database/start.js +++ b/application/domain/database/start.js @@ -1,4 +1,4 @@ -(async () => { +async () => { console.debug('Connect to pg'); domain.database.example = new lib.pg.Database(config.database); -}); +}; diff --git a/application/lib/.eslintrc.json b/application/lib/.eslintrc.json index 4cb85e1..1198765 100644 --- a/application/lib/.eslintrc.json +++ b/application/lib/.eslintrc.json @@ -1,9 +1,6 @@ { "rules": { - "strict": [ - "error", - "never" - ] + "strict": ["error", "never"] }, "globals": { "application": "readonly", diff --git a/application/lib/example/cache.js b/application/lib/example/cache.js index 644ce3b..ddb4b2b 100644 --- a/application/lib/example/cache.js +++ b/application/lib/example/cache.js @@ -11,5 +11,5 @@ const res = this.values.get(key); console.log({ return: res }); return res; - } + }, }); diff --git a/application/lib/example/doSomething.js b/application/lib/example/doSomething.js index 69710ab..f235df5 100644 --- a/application/lib/example/doSomething.js +++ b/application/lib/example/doSomething.js @@ -1,3 +1,3 @@ -(() => { +() => { console.debug('Call method: example.doSomething'); -}); +}; diff --git a/application/lib/example/start.js b/application/lib/example/start.js index ed5eac9..25acef7 100644 --- a/application/lib/example/start.js +++ b/application/lib/example/start.js @@ -6,5 +6,5 @@ this.parent.cache.set({ key: 'keyName', val: this.privateField }); const res = lib.example.cache.get({ key: 'keyName' }); console.log({ res, cache: this.parent.cache.values }); - } + }, }); diff --git a/application/lib/example/stop.js b/application/lib/example/stop.js index a386621..eb4214d 100644 --- a/application/lib/example/stop.js +++ b/application/lib/example/stop.js @@ -1,3 +1,3 @@ -(async () => { +async () => { console.debug('Stop example plugin'); -}); +}; diff --git a/application/lib/example/storage/set.js b/application/lib/example/storage/set.js index b66f5ad..38f06c8 100644 --- a/application/lib/example/storage/set.js +++ b/application/lib/example/storage/set.js @@ -9,5 +9,5 @@ const res = this.values.get(key); console.log({ return: { res } }); return res; - } + }, }); diff --git a/application/lib/example/submodule1/method1.js b/application/lib/example/submodule1/method1.js index 82bda04..d15af25 100644 --- a/application/lib/example/submodule1/method1.js +++ b/application/lib/example/submodule1/method1.js @@ -1,3 +1,3 @@ -(() => { +() => { console.debug('Call method: example.submodule1.method1'); -}); +}; diff --git a/application/lib/example/submodule1/method2.js b/application/lib/example/submodule1/method2.js index e16524d..ffb07c3 100644 --- a/application/lib/example/submodule1/method2.js +++ b/application/lib/example/submodule1/method2.js @@ -1,3 +1,3 @@ -(() => { +() => { console.debug('Call method: example.submodule1.method2'); -}); +}; diff --git a/application/lib/example/submodule2/method1.js b/application/lib/example/submodule2/method1.js index cb99f42..f0eeef3 100644 --- a/application/lib/example/submodule2/method1.js +++ b/application/lib/example/submodule2/method1.js @@ -1,3 +1,3 @@ -(() => { +() => { console.debug('Call method: example.submodule2.method1'); -}); +}; diff --git a/application/lib/example/submodule2/method2.js b/application/lib/example/submodule2/method2.js index 58e0df7..137e5fd 100644 --- a/application/lib/example/submodule2/method2.js +++ b/application/lib/example/submodule2/method2.js @@ -1,3 +1,3 @@ -(() => { +() => { console.debug('Call method: example.submodule2.method2'); -}); +}; diff --git a/application/lib/example/submodule2/nested1/method1.js b/application/lib/example/submodule2/nested1/method1.js index 19036d1..4de48a2 100644 --- a/application/lib/example/submodule2/nested1/method1.js +++ b/application/lib/example/submodule2/nested1/method1.js @@ -1,3 +1,3 @@ -(() => { +() => { console.debug('Call method: example.submodule2.nested1.method1'); -}); +}; diff --git a/application/lib/example/submodule3/nested2/method1.js b/application/lib/example/submodule3/nested2/method1.js index c640472..a272364 100644 --- a/application/lib/example/submodule3/nested2/method1.js +++ b/application/lib/example/submodule3/nested2/method1.js @@ -1,3 +1,3 @@ -(() => { +() => { console.debug('Call method: example.submodule3.nested2.method1'); -}); +}; diff --git a/application/lib/pg/constants.js b/application/lib/pg/constants.js index 362dd39..9838153 100644 --- a/application/lib/pg/constants.js +++ b/application/lib/pg/constants.js @@ -1,3 +1,3 @@ ({ - OPERATORS: ['>=', '<=', '<>', '>', '<'] + OPERATORS: ['>=', '<=', '<>', '>', '<'], }); diff --git a/application/lib/pg/updates.js b/application/lib/pg/updates.js index 2d6492a..b2786d2 100644 --- a/application/lib/pg/updates.js +++ b/application/lib/pg/updates.js @@ -1,4 +1,4 @@ -((delta, firstArgIndex = 1) => { +(delta, firstArgIndex = 1) => { const clause = []; const args = []; let i = firstArgIndex; @@ -9,4 +9,4 @@ args.push(value); } return { clause: clause.join(', '), args }; -}); +}; diff --git a/application/lib/pg/where.js b/application/lib/pg/where.js index 8a9c606..27b1a89 100644 --- a/application/lib/pg/where.js +++ b/application/lib/pg/where.js @@ -1,4 +1,4 @@ -((conditions, firstArgIndex = 1) => { +(conditions, firstArgIndex = 1) => { const clause = []; const args = []; let i = firstArgIndex; @@ -23,4 +23,4 @@ args.push(value); } return { clause: clause.join(' AND '), args }; -}); +}; diff --git a/application/lib/resmon/getStatistics.js b/application/lib/resmon/getStatistics.js index 447c7db..ade429d 100644 --- a/application/lib/resmon/getStatistics.js +++ b/application/lib/resmon/getStatistics.js @@ -1,7 +1,7 @@ -(() => { +() => { const { heapTotal, heapUsed, external } = node.process.memoryUsage(); const hs = node.v8.getHeapStatistics(); const contexts = hs.number_of_native_contexts; const detached = hs.number_of_detached_contexts; return { heapTotal, heapUsed, external, contexts, detached }; -}); +}; diff --git a/application/lib/resmon/start.js b/application/lib/resmon/start.js index b0fc39e..dfb1f29 100644 --- a/application/lib/resmon/start.js +++ b/application/lib/resmon/start.js @@ -1,4 +1,4 @@ -(async () => { +async () => { if (config.resmon.active) { setInterval(() => { const stats = lib.resmon.getStatistics(); @@ -10,4 +10,4 @@ console.debug(`Contexts: ${contexts}, detached: ${detached}`); }, config.resmon.interval); } -}); +}; diff --git a/application/lib/utils/bytesToSize.js b/application/lib/utils/bytesToSize.js index 5ecc9f7..fa0e831 100644 --- a/application/lib/utils/bytesToSize.js +++ b/application/lib/utils/bytesToSize.js @@ -1,4 +1,4 @@ -(bytes => { +(bytes) => { const UNITS = ['', ' Kb', ' Mb', ' Gb', ' Tb', ' Pb', ' Eb', ' Zb', ' Yb']; if (bytes === 0) return '0'; const exp = Math.floor(Math.log(bytes) / Math.log(1000)); @@ -6,4 +6,4 @@ const short = Math.round(size, 2); const unit = UNITS[exp]; return short + unit; -}); +}; diff --git a/application/static/.eslintrc.json b/application/static/.eslintrc.json index 2f25734..0f3da67 100644 --- a/application/static/.eslintrc.json +++ b/application/static/.eslintrc.json @@ -3,8 +3,6 @@ "sourceType": "module" }, "rules": { - "id-denylist": [ - 0 - ] + "id-denylist": [0] } } diff --git a/application/static/console.js b/application/static/console.js index 90ee62c..10b03be 100644 --- a/application/static/console.js +++ b/application/static/console.js @@ -14,11 +14,34 @@ const TIME_LINE = 300; const TIME_CHAR = 20; const KEY_CODE = { - BACKSPACE: 8, TAB: 9, ENTER: 13, PAUSE: 19, ESC: 27, SPACE: 32, - PGUP: 33, PGDN: 34, END: 35, HOME: 36, - LT: 37, UP: 38, RT: 39, DN: 40, INS: 45, DEL: 46, - F1: 112, F2: 113, F3: 114, F4: 115, F5: 116, F6: 117, - F7: 118, F8: 119, F9: 120, F10: 121, F11: 122, F12: 123, + BACKSPACE: 8, + TAB: 9, + ENTER: 13, + PAUSE: 19, + ESC: 27, + SPACE: 32, + PGUP: 33, + PGDN: 34, + END: 35, + HOME: 36, + LT: 37, + UP: 38, + RT: 39, + DN: 40, + INS: 45, + DEL: 46, + F1: 112, + F2: 113, + F3: 114, + F4: 115, + F5: 116, + F6: 117, + F7: 118, + F8: 119, + F9: 120, + F10: 121, + F11: 122, + F12: 123, ACCENT: 192, }; @@ -32,15 +55,14 @@ const pad = (padChar, length) => new Array(length + 1).join(padChar); const { userAgent } = navigator; -const isMobile = () => ( +const isMobile = () => userAgent.match(/Android/i) || userAgent.match(/webOS/i) || userAgent.match(/iPhone/i) || userAgent.match(/iPad/i) || userAgent.match(/iPod/i) || userAgent.match(/BlackBerry/i) || - userAgent.match(/Windows Phone/i) -); + userAgent.match(/Windows Phone/i); let viewportHeight, viewableRatio; let contentHeight, scrollHeight; @@ -52,7 +74,7 @@ const refreshScroll = () => { viewableRatio = viewportHeight / contentHeight; scrollHeight = panelScroll.offsetHeight; thumbHeight = scrollHeight * viewableRatio; - thumbPosition = controlBrowse.scrollTop * thumbHeight / viewportHeight; + thumbPosition = (controlBrowse.scrollTop * thumbHeight) / viewportHeight; controlScroll.style.top = thumbPosition + 'px'; controlScroll.style.height = thumbHeight + 'px'; }; @@ -76,15 +98,14 @@ const showKeyboard = () => { controlBrowse.style.bottom = controlKeyboard.offsetHeight + 'px'; }; -const inputSetValue = value => { +const inputSetValue = (value) => { controlInput.inputValue = value; if (controlInput.inputType === 'masked') { value = pad('*', value.length); } value = value.replace(/ /g, ' '); - controlInput.innerHTML = ( - controlInput.inputPrompt + value + '' - ); + controlInput.innerHTML = + controlInput.inputPrompt + value + ''; }; const input = (type, prompt, callback) => { @@ -109,7 +130,7 @@ const clear = () => { } }; -const print = s => { +const print = (s) => { const list = Array.isArray(s); let line = list ? s.shift() : s; if (!line) line = ''; @@ -158,15 +179,16 @@ const inputKeyboardEvents = { controlKeyboard.className = 'caps'; } }, - KEY(char) { // Alpha or Digit + KEY(char) { + // Alpha or Digit if (controlKeyboard.className === 'caps') { char = char.toUpperCase(); } inputSetValue(controlInput.inputValue + char); - } + }, }; -const keyboardClick = e => { +const keyboardClick = (e) => { let char = e.target.inputChar; if (char === '_') char = ' '; let keyName = 'KEY'; @@ -186,7 +208,7 @@ const initKeyboard = () => { '1234567890', 'qwertyuiop', 'asdfghjkl<', - '^zxcvbnm_>' + '^zxcvbnm_>', ]; for (let i = 0; i < KEYBOARD_LAYOUT.length; i++) { const keyboardLine = KEYBOARD_LAYOUT[i]; @@ -199,7 +221,7 @@ const initKeyboard = () => { elementKey.innerHTML = char; elementKey.inputChar = char; elementKey.className = 'key'; - elementKey.style.opacity = ((i + j) % 2) ? 0.8 : 1; + elementKey.style.opacity = (i + j) % 2 ? 0.8 : 1; elementKey.addEventListener('click', keyboardClick); elementLine.appendChild(elementKey); } @@ -207,7 +229,7 @@ const initKeyboard = () => { controlBrowse.style.bottom = controlKeyboard.offsetHeight + 'px'; }; -document.onkeydown = event => { +document.onkeydown = (event) => { if (controlInput.inputActive) { const keyName = KEY_NAME[event.keyCode]; const fn = inputKeyboardEvents[keyName]; @@ -218,7 +240,7 @@ document.onkeydown = event => { } }; -document.onkeypress = event => { +document.onkeypress = (event) => { if (controlInput.inputActive) { const fn = inputKeyboardEvents['KEY']; const char = String.fromCharCode(event.keyCode); @@ -229,10 +251,10 @@ document.onkeypress = event => { } }; -const blobToBase64 = blob => { +const blobToBase64 = (blob) => { const reader = new FileReader(); reader.readAsDataURL(blob); - return new Promise(resolve => { + return new Promise((resolve) => { reader.onloadend = () => { resolve(reader.result); }; @@ -240,11 +262,10 @@ const blobToBase64 = blob => { }; const uploadFile = (file, done) => { - blobToBase64(file) - .then(url => { - const data = url.substring(url.indexOf(',') + 1); - api.example.uploadFile({ name: file.name, data }).then(done); - }); + blobToBase64(file).then((url) => { + const data = url.substring(url.indexOf(',') + 1); + api.example.uploadFile({ name: file.name, data }).then(done); + }); }; const upload = () => { @@ -275,7 +296,7 @@ const upload = () => { }; }; -const exec = async line => { +const exec = async (line) => { const args = line.split(' '); if (args[0] === 'upload') { upload(); @@ -301,7 +322,7 @@ const signIn = async () => { await api.auth.signIn({ login: 'marcus', password: 'marcus' }); } await metacom.load('example'); - api.example.on('resmon', data => print(JSON.stringify(data))); + api.example.on('resmon', (data) => print(JSON.stringify(data))); api.example.subscribe(); }; diff --git a/application/static/metacom.js b/application/static/metacom.js index 9b5fede..550e4c4 100644 --- a/application/static/metacom.js +++ b/application/static/metacom.js @@ -69,7 +69,7 @@ export class Metacom { } ready() { - return new Promise(resolve => { + return new Promise((resolve) => { if (this.socket.readyState === WebSocket.OPEN) resolve(); else this.socket.addEventListener('open', resolve); }); @@ -93,37 +93,39 @@ export class Metacom { } httpCall(iname, ver) { - return methodName => (args = {}) => { - const callId = ++this.callId; - const interfaceName = ver ? `${iname}.${ver}` : iname; - const target = interfaceName + '/' + methodName; - const packet = { call: callId, [target]: args }; - const dest = new URL(this.url); - const protocol = dest.protocol === 'ws:' ? 'http' : 'https'; - const url = `${protocol}://${dest.host}/api`; - return fetch(url, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(packet), - }).then(res => { - const { status } = res; - if (status === 200) return res.json().then(({ result }) => result); - throw new Error(`Status Code: ${status}`); - }); - }; + return (methodName) => + (args = {}) => { + const callId = ++this.callId; + const interfaceName = ver ? `${iname}.${ver}` : iname; + const target = interfaceName + '/' + methodName; + const packet = { call: callId, [target]: args }; + const dest = new URL(this.url); + const protocol = dest.protocol === 'ws:' ? 'http' : 'https'; + const url = `${protocol}://${dest.host}/api`; + return fetch(url, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(packet), + }).then((res) => { + const { status } = res; + if (status === 200) return res.json().then(({ result }) => result); + throw new Error(`Status Code: ${status}`); + }); + }; } socketCall(iname, ver) { - return methodName => async (args = {}) => { - const callId = ++this.callId; - const interfaceName = ver ? `${iname}.${ver}` : iname; - const target = interfaceName + '/' + methodName; - await this.ready(); - return new Promise((resolve, reject) => { - this.calls.set(callId, [resolve, reject]); - const packet = { call: callId, [target]: args }; - this.socket.send(JSON.stringify(packet)); - }); - }; + return (methodName) => + async (args = {}) => { + const callId = ++this.callId; + const interfaceName = ver ? `${iname}.${ver}` : iname; + const target = interfaceName + '/' + methodName; + await this.ready(); + return new Promise((resolve, reject) => { + this.calls.set(callId, [resolve, reject]); + const packet = { call: callId, [target]: args }; + this.socket.send(JSON.stringify(packet)); + }); + }; } } diff --git a/lib/application.js b/lib/application.js index 531ac46..8d50dce 100644 --- a/lib/application.js +++ b/lib/application.js @@ -37,7 +37,7 @@ class Application extends events.EventEmitter { await this.loadPlace('domain', this.domainPath); })(), ]); - await Promise.allSettled(this.starts.map(fn => fn())); + await Promise.allSettled(this.starts.map((fn) => fn())); this.starts = null; this.initialization = true; } @@ -60,7 +60,7 @@ class Application extends events.EventEmitter { createSandbox() { const { config, namespaces, server: { host, port, protocol } = {} } = this; - const introspect = async interfaces => this.introspect(interfaces); + const introspect = async (interfaces) => this.introspect(interfaces); const worker = { id: 'W' + node.worker.threadId.toString() }; const server = { host, port, protocol }; const application = { security, introspect, worker, server }; @@ -69,10 +69,24 @@ class Application extends events.EventEmitter { const domain = {}; for (const name of namespaces) application[name] = this[name]; const sandbox = { - Buffer, URL, URLSearchParams, Error: this.Error, console: this.logger, - application, node, npm, api, lib, domain, config, - setTimeout, setImmediate, setInterval, - clearTimeout, clearImmediate, clearInterval, + Buffer, + URL, + URLSearchParams, + Error: this.Error, + console: this.logger, + application, + node, + npm, + api, + lib, + domain, + config, + setTimeout, + setImmediate, + setInterval, + clearTimeout, + clearImmediate, + clearInterval, }; this.sandbox = vm.createContext(sandbox); } @@ -86,7 +100,7 @@ class Application extends events.EventEmitter { try { const code = await fsp.readFile(fileName, 'utf8'); if (!code) return null; - const src = '\'use strict\';\ncontext => ' + code; + const src = "'use strict';\ncontext => " + code; const options = { filename: fileName, lineOffset: -1 }; const script = new vm.Script(src, options); return script.runInContext(this.sandbox, SCRIPT_OPTIONS); @@ -239,7 +253,7 @@ class Application extends events.EventEmitter { const version = ver === '*' ? iface.default : parseInt(ver); const methods = iface[version.toString()]; const methodNames = Object.keys(methods); - const interfaceMethods = intro[iname] = {}; + const interfaceMethods = (intro[iname] = {}); for (const methodName of methodNames) { const exp = methods[methodName](EMPTY_CONTEXT); const fn = typeof exp === 'object' ? exp.method : exp; @@ -249,7 +263,7 @@ class Application extends events.EventEmitter { interfaceMethods[methodName] = []; continue; } - const args = signature.split(',').map(s => s.trim()); + const args = signature.split(',').map((s) => s.trim()); interfaceMethods[methodName] = args; } } diff --git a/lib/auth.js b/lib/auth.js index c5d3d73..b366ba8 100644 --- a/lib/auth.js +++ b/lib/auth.js @@ -5,7 +5,7 @@ const { crypto } = node; const { common } = npm; const application = require('./application.js'); -const BYTE = 256; +const BYTE = 256; const TOKEN = 'token'; const TOKEN_LENGTH = 32; const ALPHA_UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; @@ -33,7 +33,7 @@ const generateToken = () => { return key; }; -const parseCookies = cookie => { +const parseCookies = (cookie) => { const values = {}; const items = cookie.split(';'); for (const item of items) { @@ -64,7 +64,7 @@ module.exports = () => { const res = Reflect.set(data, key, value); save(token, this.data); return res; - } + }, }; this.token = token; this.data = contextData; @@ -86,7 +86,7 @@ module.exports = () => { return session; }; - const restore = async client => { + const restore = async (client) => { const cachedSession = cache.get(client.req); if (cachedSession) return cachedSession; const { cookie } = client.req.headers; @@ -119,9 +119,10 @@ module.exports = () => { db.insert('SystemUser', { login, password, fullName }); }; - const getUser = login => db - .select('SystemUser', ['Id', 'Password'], { login }) - .then(([user]) => user); + const getUser = (login) => + db + .select('SystemUser', ['Id', 'Password'], { login }) + .then(([user]) => user); return Object.freeze({ start, restore, remove, save, registerUser, getUser }); }; diff --git a/lib/common.js b/lib/common.js index 06c9301..b5e1a28 100644 --- a/lib/common.js +++ b/lib/common.js @@ -1,17 +1,17 @@ 'use strict'; -const parseHost = host => { +const parseHost = (host) => { const portOffset = host.indexOf(':'); if (portOffset > -1) return host.substr(0, portOffset); return host; }; -const timeout = msec => - new Promise(resolve => { +const timeout = (msec) => + new Promise((resolve) => { setTimeout(resolve, msec); }); -const sample = arr => arr[Math.floor(Math.random() * arr.length)]; +const sample = (arr) => arr[Math.floor(Math.random() * arr.length)]; const between = (s, prefix, suffix) => { let i = s.indexOf(prefix); diff --git a/lib/logger.js b/lib/logger.js index 1684b42..deea3af 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -22,7 +22,7 @@ class Logger { } close() { - return new Promise(resolve => this.stream.end(resolve)); + return new Promise((resolve) => this.stream.end(resolve)); } write(level = 'info', s) { diff --git a/lib/security.js b/lib/security.js index d3b184e..0824f39 100644 --- a/lib/security.js +++ b/lib/security.js @@ -4,20 +4,21 @@ const { crypto } = require('./dependencies.js').node; const serializeHash = (hash, salt, params) => { const paramString = Object.entries(params) - .map(([key, value]) => `${key}=${value}`).join(','); + .map(([key, value]) => `${key}=${value}`) + .join(','); const saltString = salt.toString('base64').split('=')[0]; const hashString = hash.toString('base64').split('=')[0]; return `$scrypt$${paramString}$${saltString}$${hashString}`; }; -const deserializeHash = phcString => { +const deserializeHash = (phcString) => { const parsed = phcString.split('$'); parsed.shift(); if (parsed[0] !== 'scrypt') { throw new Error('Node.js crypto module only supports scrypt'); } const params = Object.fromEntries( - parsed[1].split(',').map(p => { + parsed[1].split(',').map((p) => { const kv = p.split('='); kv[1] = Number(kv[1]); return kv; @@ -39,24 +40,25 @@ const SCRYPT_PARAMS = { maxmem: 64 * 1024 * 1024, }; -const hashPassword = password => new Promise((resolve, reject) => { - crypto.randomBytes(SALT_LEN, (err, salt) => { - if (err) { - reject(err); - return; - } - crypto.scrypt(password, salt, KEY_LEN, SCRYPT_PARAMS, (err, hash) => { +const hashPassword = (password) => + new Promise((resolve, reject) => { + crypto.randomBytes(SALT_LEN, (err, salt) => { if (err) { reject(err); return; } - resolve(serializeHash(hash, salt, SCRYPT_PARAMS)); + crypto.scrypt(password, salt, KEY_LEN, SCRYPT_PARAMS, (err, hash) => { + if (err) { + reject(err); + return; + } + resolve(serializeHash(hash, salt, SCRYPT_PARAMS)); + }); }); }); -}); let defaultHash; -hashPassword('').then(hash => { +hashPassword('').then((hash) => { defaultHash = hash; }); @@ -64,7 +66,11 @@ const validatePassword = (password, hash = defaultHash) => new Promise((resolve, reject) => { const parsedHash = deserializeHash(hash); const len = parsedHash.hash.length; - crypto.scrypt(password, parsedHash.salt, len, parsedHash.params, + crypto.scrypt( + password, + parsedHash.salt, + len, + parsedHash.params, (err, hashedPassword) => { if (err) { reject(err); diff --git a/lib/server.js b/lib/server.js index 8cda6c7..592be42 100644 --- a/lib/server.js +++ b/lib/server.js @@ -10,7 +10,7 @@ const SHUTDOWN_TIMEOUT = 5000; const SHORT_TIMEOUT = 500; const LONG_RESPONSE = 30000; -const receiveBody = async req => { +const receiveBody = async (req) => { const buffers = []; for await (const chunk of req) { buffers.push(chunk); @@ -36,7 +36,7 @@ class Server { this.ws = new ws.Server({ server: this.server }); this.ws.on('connection', async (connection, req) => { const channel = await new Channel(req, null, connection, application); - connection.on('message', data => { + connection.on('message', (data) => { channel.message(data); }); }); @@ -90,18 +90,18 @@ class Server { } const body = receiveBody(req); if (req.url === '/api') { - body.then(data => { + body.then((data) => { channel.message(data); }); } else { - body.then(data => { + body.then((data) => { const { pathname, searchParams } = new URL('http://' + req.url); const [, interfaceName, methodName] = pathname.split('/'); const args = data ? JSON.parse(data) : Object.fromEntries(searchParams); channel.rpc(-1, interfaceName, methodName, args); }); } - body.catch(err => { + body.catch((err) => { channel.error(500, err); }); } @@ -116,7 +116,7 @@ class Server { } async close() { - this.server.close(err => { + this.server.close((err) => { if (err) this.application.logger.error(err.stack); }); if (this.channels.size === 0) { diff --git a/lib/worker.js b/lib/worker.js index 006243a..8e0f35f 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -19,7 +19,7 @@ const initAuth = require('./auth.js'); const logger = await new Logger(logPath, worker.threadId); Object.assign(application, { config, logger }); - const logError = err => { + const logError = (err) => { logger.error(err ? err.stack : 'No exception stack available'); }; @@ -52,7 +52,7 @@ const initAuth = require('./auth.js'); await application.init(); logger.system(`Application started in worker ${threadId}`); - worker.parentPort.on('message', async message => { + worker.parentPort.on('message', async (message) => { if (message.name === 'stop') { if (application.finalization) return; logger.system(`Graceful shutdown in worker ${threadId}`); @@ -60,5 +60,4 @@ const initAuth = require('./auth.js'); process.exit(0); } }); - })(); diff --git a/package-lock.json b/package-lock.json index e0f2aba..e7978ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -826,6 +826,12 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "prettier": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.0.tgz", + "integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==", + "dev": true + }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", diff --git a/package.json b/package.json index 53cc1d7..e9f5381 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "main": "server.js", "scripts": { "test": "npm run -s lint && node test/all.js", - "lint": "eslint .", + "lint": "eslint . --fix && prettier --write \"**/*.js\" \"**/*.json\"", "install": "application/cert/generate.sh" }, "repository": { @@ -47,7 +47,8 @@ "node": ">=12.9.0" }, "devDependencies": { - "eslint": "^7.27.0" + "eslint": "^7.27.0", + "prettier": "^2.3.0" }, "dependencies": { "pg": "^8.6.0", diff --git a/server.js b/server.js index 09da7d9..414351a 100644 --- a/server.js +++ b/server.js @@ -17,10 +17,10 @@ const options = { trackUnmanagedFds: true }; let active = count; const threads = new Array(count); - const start = id => { + const start = (id) => { const worker = new Worker('./lib/worker.js', options); threads[id] = worker; - worker.on('exit', code => { + worker.on('exit', (code) => { if (code !== 0) start(id); else if (--active === 0) process.exit(0); }); diff --git a/test/system.js b/test/system.js index b0dfdac..354bd93 100644 --- a/test/system.js +++ b/test/system.js @@ -25,15 +25,15 @@ const tasks = [ { post: '/api', method: 'auth/signIn', - args: { login: 'marcus', password: 'marcus' } - } + args: { login: 'marcus', password: 'marcus' }, + }, ]; -const getRequest = task => { +const getRequest = (task) => { const request = { host: HOST, port: task.port || PORT, - agent: false + agent: false, }; if (task.get) { request.method = 'GET'; @@ -47,25 +47,25 @@ const getRequest = task => { task.data = JSON.stringify(packet); request.headers = { 'Content-Type': 'application/json', - 'Content-Length': task.data.length + 'Content-Length': task.data.length, }; } return request; }; setTimeout(() => { - tasks.forEach(task => { + tasks.forEach((task) => { const name = task.get || task.post; console.log('HTTP request ' + name); const request = getRequest(task); const req = http.request(request); - req.on('response', res => { + req.on('response', (res) => { const expectedStatus = task.status || 200; setTimeout(() => { assert.equal(res.statusCode, expectedStatus); }, TEST_DELAY); }); - req.on('error', err => { + req.on('error', (err) => { console.log(err.stack); }); if (task.data) req.write(task.data); diff --git a/test/unit.security.js b/test/unit.security.js index 69e423c..54ceb14 100644 --- a/test/unit.security.js +++ b/test/unit.security.js @@ -9,16 +9,20 @@ assert(security); const password = 'correct horse battery staple'; const wrongPassword = 'password'; -security.hashPassword(password).then(hash => { - assert(hash); - assert.equal(typeof hash, 'string'); - return Promise.all([ - security.validatePassword(password, hash), - security.validatePassword(wrongPassword, hash), - ]); -}).then(result => { - assert.deepEqual(result, [true, false]); -}).catch(err => { - console.log(err.stack); - process.exit(1); -}); +security + .hashPassword(password) + .then((hash) => { + assert(hash); + assert.equal(typeof hash, 'string'); + return Promise.all([ + security.validatePassword(password, hash), + security.validatePassword(wrongPassword, hash), + ]); + }) + .then((result) => { + assert.deepEqual(result, [true, false]); + }) + .catch((err) => { + console.log(err.stack); + process.exit(1); + }); diff --git a/test/unit.semaphore.js b/test/unit.semaphore.js index bc0d7b3..574bff2 100644 --- a/test/unit.semaphore.js +++ b/test/unit.semaphore.js @@ -4,11 +4,12 @@ const assert = require('assert').strict; const Semaphore = require('../lib/semaphore.js'); -const sleep = msec => new Promise(resolve => { - setTimeout(() => { - resolve(); - }, msec); -}); +const sleep = (msec) => + new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, msec); + }); assert(Semaphore); const semaphore = new Semaphore(2, 10, 1000);