wspromisify
Advanced tools
Comparing version 0.0.3 to 0.0.4
{ | ||
"_from": "wspromisify@0.0.3", | ||
"_id": "wspromisify@0.0.3", | ||
"_from": "wspromisify@0.0.201", | ||
"_id": "wspromisify@0.0.201", | ||
"_inBundle": false, | ||
@@ -11,6 +11,6 @@ "_integrity": "sha512-wWSjaaNK9B3wOYyw5DWhPq+AGRFx+4qBs0bbazPkNPwWwXnNLBcthnEBSZdyhqx8SGulRzV8DzH8IcUd9DbYsw==", | ||
"registry": true, | ||
"raw": "wspromisify@0.0.201", | ||
"raw": "wspromisify@0.0.4", | ||
"name": "wspromisify", | ||
"escapedName": "wspromisify", | ||
"rawSpec": "0.0.201", | ||
"rawSpec": "0.0.4", | ||
"saveSpec": null, | ||
@@ -25,3 +25,3 @@ "fetchSpec": "0.0.201" | ||
"_spec": "wspromisify@0.0.201", | ||
"_where": "C:\\Users\\m.akiliev\\Documents\\node", | ||
"_where": "C:\\Users\\m.akiliev\\Music\\WebsocketPromisify", | ||
"author": { | ||
@@ -33,3 +33,3 @@ "name": "Michael Akiliev" | ||
}, | ||
"bundleDependencies": false, | ||
"bundleDependencies": [], | ||
"deprecated": false, | ||
@@ -60,3 +60,3 @@ "description": "Makes it easier to handle different data via WebSockets.", | ||
}, | ||
"version": "0.0.3" | ||
"version": "0.0.4" | ||
} |
# WebsocketPromisify | ||
Makes websocket's API just like REST with Promise-like API, with native Promises. | ||
Makes a Promise-like WebSocket connection. | ||
If something sent before connection is es | ||
Default constructor config is | ||
```{ | ||
// You can also use plain text and blobs in future. | ||
data_type: 'json', | ||
// Debug features. Not required. | ||
log: ((event, time, message) => null), | ||
// Will count milliseconds for responses and put them to log function above. | ||
timer: false, | ||
// Set up. | ||
// Required. URL to connect. | ||
url: 'localhost', | ||
// Timeout after sending a message before it dropes with error. | ||
timeout: 1400, | ||
// Reconnect timeout in seconds or null. | ||
reconnect: 2, | ||
// You can set your own middleware here. | ||
adapter: ((host, protocols) => new WebSocket(host, protocols)), | ||
// WebSocket constructor's protocol field. | ||
protocols: [], | ||
// Unique id's and data keys to negotiate with back-end. | ||
server: { | ||
id_key: 'id', | ||
data_key: 'data' | ||
} | ||
}``` | ||
Methods: ``` | ||
send(message), | ||
close() | ||
``` | ||
Example: ``` | ||
import * as WSP from 'wspromisify' // Temporary. Will be regular esm. | ||
const somehost = 'example.com:8080' | ||
const someFunction = async () => { | ||
const ws = new WSP({ | ||
url: `${somehost}/ws`, | ||
timeout: 2e3, | ||
timer: true, | ||
log(event, time, message = '') { | ||
if(time !== null) { | ||
console.log(event, `in ${time}ms`, message) | ||
} else { | ||
console.log(event, message) | ||
} | ||
} | ||
}) | ||
try { | ||
const data = await ws.send({catSaid: 'Meow!'}) | ||
console.log({data}) | ||
} catch(error) { | ||
console.error('Cannot send a message due to ', error) | ||
} | ||
} | ||
someFunction() | ||
``` |
@@ -0,0 +0,0 @@ |
176
WS.js
@@ -14,5 +14,11 @@ | ||
data_type: 'json', // ToDo some other stuff maybe. | ||
// Debug features. | ||
log: ((event, time, message) => null), | ||
timer: false, | ||
// Set up. | ||
url: 'localhost', | ||
timeout: 1400, | ||
adapter: (host => new WebSocket(host)), | ||
reconnect: 2, // Reconnect timeout in seconds or null. | ||
adapter: ((host, protocols) => new WebSocket(host, protocols)), | ||
protocols: [], | ||
server: { | ||
@@ -27,2 +33,21 @@ id_key: 'id', | ||
init_flush() { | ||
this.queue = {} // data queuse | ||
this.messages = [] // send() queue | ||
} | ||
log(event, message, time = null) { | ||
const config = this.config | ||
event = `WSP: ${event}` | ||
if(time !== null) { | ||
config.log(event, time, message) | ||
} else { | ||
if(config.timer) { | ||
config.log(event, null, message) | ||
} else { | ||
config.log(event, message) | ||
} | ||
} | ||
} | ||
on(event_name, handler, predicate) { | ||
@@ -37,17 +62,21 @@ return add_event(this.ws, event_name, event => { | ||
close() { | ||
delete this.queue // Free up memory. | ||
delete this.messages | ||
this.init_flush() | ||
this.open = null | ||
return this.ws.close() | ||
this.ws.close() | ||
this.ws = null | ||
this.forcibly_closed = true | ||
return null | ||
} | ||
async send(user_message, opts = {}) { | ||
const message = {} | ||
const id_key = this.config.server.id_key | ||
const data_key = this.config.server.data_key | ||
const is_json = typeof opts.json == 'boolean' ? opts.data_type=='json' : this.config.json | ||
this.log('Send.', user_message) | ||
const config = this.config | ||
const message = {} | ||
const id_key = config.server.id_key | ||
const data_key = config.server.data_key | ||
const data_type = opts.data_type || config.data_type | ||
message[data_key] = user_message // is_json ? JSON.stringify(user_message | ||
message[id_key] = SHA1(user_message + '' + ((Math.random()*1e5)|0)).slice(0, 20) | ||
if(typeof opts.top == 'object') { | ||
message[id_key] = SHA1('' + ((Math.random()*1e5)|0)).slice(0, 20) | ||
if(typeof opts.top === 'object') { | ||
if(opts.top[data_key]) { | ||
@@ -70,7 +99,8 @@ throw new Error('Attempting to set data key/token via send() options!') | ||
ff, | ||
data_type: this.config.data_type, | ||
timeout: sett(this.config.timeout, () => { | ||
data_type: config.data_type, | ||
sent_time: config.timer ? Date.now() : null, | ||
timeout: sett(config.timeout, () => { | ||
if(this.queue[message[id_key]]) { | ||
rj({ | ||
'Websocket timeout expired: ': this.config.timeout, | ||
'Websocket timeout expired: ': config.timeout, | ||
'for the message': message | ||
@@ -85,38 +115,96 @@ }) | ||
async connect() { // returns status if won't open or null if ok. | ||
return new Promise((ff, rj) => { | ||
if(this.open === true) { | ||
return ff(1) | ||
} | ||
const config = this.config | ||
const ws = config.adapter(`ws://${config.url}`, config.protocols) | ||
this.ws = ws | ||
add_event(ws, 'error', (e) => { | ||
this.ws = null | ||
this.log('Error status 3.') | ||
// Some network error: Connection refused or so. | ||
return ff(3) | ||
}) | ||
add_event(ws, 'open', (e) => { | ||
this.log('Opened.') | ||
this.open = true | ||
const {id_key, data_key} = config.server | ||
// Send all pending messages. | ||
this.messages.forEach((message) => message.send()) | ||
// It's reconnecting. | ||
if(this.reconnect_timeout !== null) { | ||
clearInterval(this.reconnect_timeout) | ||
this.reconnect_timeout = null | ||
} | ||
add_event(ws, 'close', async (e) => { | ||
this.log('Closed.') | ||
this.open = false | ||
// Auto reconnect. | ||
const reconnect = config.reconnect | ||
if( | ||
typeof reconnect === 'number' && | ||
!isNaN(reconnect) && | ||
!this.forcibly_closed | ||
) { | ||
const reconnectFunc = async () => { | ||
this.log('Trying to reconnect...') | ||
if(this.ws !== null) { | ||
this.ws.close() | ||
this.ws = null | ||
} | ||
// If some error occured, try again. | ||
const status = await this.connect() | ||
if(status !== null) { | ||
this.reconnect_timeout = setTimeout(reconnectFunc, reconnect * 1000) | ||
} | ||
} | ||
// No need for await. | ||
reconnectFunc() | ||
} else { | ||
this.ws = null | ||
this.open = null | ||
} | ||
// reset the flag to reuse. | ||
this.forcibly_closed = false | ||
}) | ||
add_event(ws, 'message', (e) => { | ||
try { | ||
const data = JSON.parse(e.data) | ||
if(data[id_key]) { | ||
const q = this.queue[data[id_key]] | ||
if(q) { | ||
// Debug, Log. | ||
const time = q.sent_time ? (Date.now() - q.sent_time) : null | ||
this.log('Message.', data[data_key], time) | ||
// Play. | ||
q.ff(data[data_key]) | ||
clearTimeout(q.timeout) | ||
delete this.queue[data[id_key]] | ||
} | ||
} | ||
} catch (err) { | ||
console.error(err, `JSON.parse error. Got: ${e.data}`) | ||
} | ||
}) | ||
return ff(null) | ||
}) | ||
}) | ||
} | ||
constructor(user_config = {}) { | ||
// Config. | ||
const config = {} | ||
Object.assign(config, default_config) | ||
Object.assign(config, user_config) | ||
const id_key = config.server.id_key | ||
const data_key = config.server.data_key | ||
const ws = config.adapter(`ws://${config.url}`) | ||
this.ws = ws | ||
this.queue = {} // data queuse | ||
this.messages = [] // send() queue | ||
this.config = config | ||
add_event(ws, 'open', (e) => { | ||
this.open = true | ||
this.messages.forEach((message) => message.send()) | ||
}) | ||
add_event(ws, 'close', (e) => { | ||
this.ws = null | ||
this.open = false | ||
}) | ||
add_event(ws, 'message', (e) => { | ||
try { | ||
const data = JSON.parse(e.data) | ||
if(data[id_key]) { | ||
const q = this.queue[data[id_key]] | ||
if(q) { | ||
q.ff(data[data_key]) | ||
clearTimeout(q.timeout) | ||
delete this.queue[data[id_key]] | ||
} | ||
} | ||
} catch (err) { | ||
console.error(`JSON.parse error. Got: ${e.data}`) | ||
} | ||
}) | ||
this.config = config | ||
// Init. | ||
this.init_flush() | ||
// Flags. | ||
this.open = false | ||
this.reconnect_timeout = null | ||
this.forcibly_closed = false | ||
this.connect() | ||
} | ||
@@ -123,0 +211,0 @@ } |
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
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
11924
226
73