Comparing version 0.0.0 to 0.1.0-alpha.0
'use strict'; | ||
const Client = function() { | ||
const http = require('http'); | ||
const path = require('path'); | ||
const MIME_TYPES = { | ||
html: 'text/html; charset=UTF-8', | ||
json: 'application/json; charset=UTF-8', | ||
js: 'application/javascript; charset=UTF-8', | ||
css: 'text/css', | ||
png: 'image/png', | ||
ico: 'image/x-icon', | ||
svg: 'image/svg+xml', | ||
}; | ||
const client = () => new Client(); | ||
const HEADERS = { | ||
'X-XSS-Protection': '1; mode=block', | ||
'X-Content-Type-Options': 'nosniff', | ||
'Strict-Transport-Security': 'max-age=31536000; includeSubdomains; preload', | ||
'Access-Control-Allow-Origin': '*', | ||
}; | ||
module.exports = { | ||
client | ||
}; | ||
class Client { | ||
constructor(req, res, connection, application) { | ||
this.req = req; | ||
this.res = res; | ||
this.ip = req.socket.remoteAddress; | ||
this.connection = connection; | ||
this.application = application; | ||
} | ||
static() { | ||
const { req, res, ip, application } = this; | ||
const { url, method } = req; | ||
const filePath = url === '/' ? '/index.html' : url; | ||
const fileExt = path.extname(filePath).substring(1); | ||
const mimeType = MIME_TYPES[fileExt] || MIME_TYPES.html; | ||
res.writeHead(200, { ...HEADERS, 'Content-Type': mimeType }); | ||
if (res.writableEnded) return; | ||
const data = application.getStaticFile(filePath); | ||
if (data) { | ||
res.end(data); | ||
application.logger.access(`${ip}\t${method}\t${url}`); | ||
return; | ||
} | ||
this.error(404); | ||
} | ||
redirect(location) { | ||
const { res } = this; | ||
if (res.headersSent) return; | ||
res.writeHead(302, { Location: location }); | ||
res.end(); | ||
} | ||
error(code, err, callId = err) { | ||
const { req, res, connection, ip, application } = this; | ||
const { url, method } = req; | ||
const status = http.STATUS_CODES[code]; | ||
if (typeof err === 'number') err = undefined; | ||
const reason = err ? err.stack : status; | ||
application.logger.error(`${ip}\t${method}\t${url}\t${code}\t${reason}`); | ||
if (connection) { | ||
const packet = { callback: callId, error: { code, message: status } }; | ||
connection.send(JSON.stringify(packet)); | ||
return; | ||
} | ||
if (res.writableEnded) return; | ||
res.writeHead(status, { 'Content-Type': MIME_TYPES.json }); | ||
const packet = { code, error: status }; | ||
res.end(JSON.stringify(packet)); | ||
} | ||
message(data) { | ||
let packet; | ||
try { | ||
packet = JSON.parse(data); | ||
} catch (err) { | ||
this.error(500, new Error('JSON parsing error')); | ||
return; | ||
} | ||
const [callType, target] = Object.keys(packet); | ||
const callId = packet[callType]; | ||
const args = packet[target]; | ||
if (callId && args) { | ||
const [interfaceName, methodName] = target.split('/'); | ||
this.rpc(callId, interfaceName, methodName, args); | ||
return; | ||
} | ||
this.error(500, new Error('Packet structure error')); | ||
} | ||
async rpc(callId, interfaceName, methodName, args) { | ||
const { res, connection, ip, application } = this; | ||
const { semaphore } = application.server; | ||
try { | ||
await semaphore.enter(); | ||
} catch { | ||
this.error(504, callId); | ||
return; | ||
} | ||
const [iname, ver = '*'] = interfaceName.split('.'); | ||
try { | ||
let session = await application.auth.restore(this); | ||
const proc = application.getMethod(iname, ver, methodName, session); | ||
if (!proc) { | ||
this.error(404, callId); | ||
return; | ||
} | ||
if (!session && proc.access !== 'public') { | ||
this.error(403, callId); | ||
return; | ||
} | ||
const result = await proc.method(args); | ||
const userId = result ? result.userId : undefined; | ||
if (!session && userId && proc.access === 'public') { | ||
session = application.auth.start(this, userId); | ||
result.token = session.token; | ||
} | ||
const data = JSON.stringify({ callback: callId, result }); | ||
if (connection) connection.send(data); | ||
else res.end(data); | ||
const token = session ? session.token : 'anonymous'; | ||
const record = `${ip}\t${token}\t${interfaceName}/${methodName}`; | ||
application.logger.access(record); | ||
} catch (err) { | ||
this.error(500, err, callId); | ||
} finally { | ||
semaphore.leave(); | ||
} | ||
} | ||
} | ||
module.exports = Client; |
'use strict'; | ||
const submodules = [ | ||
'client' // Metacom client | ||
].map(path => require('./lib/' + path)); | ||
const { client } = submodules[0]; | ||
module.exports = Object.assign(client, ...submodules); | ||
module.exports = { | ||
Server: require('./lib/server.js'), | ||
}; |
{ | ||
"name": "metacom", | ||
"version": "0.0.0", | ||
"version": "0.1.0-alpha.0", | ||
"author": "Timur Shemsedinov <timur.shemsedinov@gmail.com>", | ||
@@ -14,2 +14,3 @@ "description": "Communication protocol for Metarhia stack with rpc, events, binary streams, memory and db access", | ||
"socket", | ||
"websocket", | ||
"rpc", | ||
@@ -29,15 +30,22 @@ "events", | ||
"scripts": { | ||
"test": "npm run lint", | ||
"lint": "eslint ." | ||
"test": "npm run lint && node ./test/unit.js && node ./test/integration.js ", | ||
"lint": "eslint . && prettier -c \"**/*.js\" \"**/*.json\" \"**/*.md\" \"**/*.yml\"", | ||
"fmt": "prettier --write \"**/*.js\" \"**/*.json\" \"**/*.md\" \"**/*.yml\"" | ||
}, | ||
"engines": { | ||
"node": ">=6.0.0" | ||
"node": ">=12.9.0" | ||
}, | ||
"dependencies": { | ||
"metarhia-common": "^0.0.26" | ||
"@metarhia/common": "^2.2.0", | ||
"ws": "^7.3.1" | ||
}, | ||
"devDependencies": { | ||
"eslint": "^4.19.1", | ||
"tap": "^11.1.3" | ||
"eslint": "^7.7.0", | ||
"eslint-config-metarhia": "^7.0.1", | ||
"eslint-config-prettier": "^6.11.0", | ||
"eslint-plugin-prettier": "^3.1.4", | ||
"eslint-plugin-import": "^2.22.0", | ||
"metatests": "^0.7.2", | ||
"prettier": "^2.0.5" | ||
} | ||
} |
@@ -1,2 +0,7 @@ | ||
# metacom | ||
Communication protocol for Metarhia stack with rpc, events, binary streams, memory and db access | ||
# Metacom Communication Protocol for Metarhia stack | ||
[![CI Status](https://github.com/metarhia/metacom/workflows/Testing%20CI/badge.svg)](https://github.com/metarhia/metacom/actions?query=workflow%3A%22Testing+CI%22+branch%3Amaster) | ||
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/80885bfdb4bd411da51f31a7593c1f65)](https://www.codacy.com/app/metarhia/metacom) | ||
[![NPM Version](https://badge.fury.io/js/metacom.svg)](https://badge.fury.io/js/metacom) | ||
[![NPM Downloads/Month](https://img.shields.io/npm/dm/metacom.svg)](https://www.npmjs.com/package/metacom) | ||
[![NPM Downloads](https://img.shields.io/npm/dt/metacom.svg)](https://www.npmjs.com/package/metacom) |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
12507
17
292
8
2
7
4
+ Added@metarhia/common@^2.2.0
+ Addedws@^7.3.1
+ Added@metarhia/common@2.2.2(transitive)
+ Addedws@7.5.10(transitive)
- Removedmetarhia-common@^0.0.26
- Removedmetarhia-common@0.0.26(transitive)