├── .gitignore ├── .jscsrc ├── .jshintrc ├── README.md ├── gulpfile.js ├── index.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /npm-debug.log 3 | /NO_GIT/ 4 | 5 | .idea/ 6 | -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "disallowDanglingUnderscores": null, 3 | "disallowMixedSpacesAndTabs": true, 4 | "disallowMultipleLineBreaks": true, 5 | "disallowMultipleSpaces": null, 6 | "disallowNamedUnassignedFunctions": true, 7 | "disallowOperatorBeforeLineBreak": null, 8 | "disallowSpaceBeforeSemicolon": true, 9 | "disallowSpacesInFunction": 10 | { 11 | "beforeOpeningRoundBrace": true 12 | }, 13 | "disallowSpacesInCallExpression": true, 14 | "disallowSpacesInsideParentheses": true, 15 | "disallowSpacesInsideParenthesizedExpression": true, 16 | "disallowTrailingComma": true, 17 | "disallowTrailingWhitespace": true, 18 | "disallowYodaConditions": true, 19 | "requireAlignedMultilineParams": "firstParam", 20 | "requireCamelCaseOrUpperCaseIdentifiers": false, 21 | "requireCommaBeforeLineBreak": true, 22 | "requireFunctionDeclarations": true, 23 | "requireNewlineBeforeBlockStatements": true, 24 | "requirePaddingNewLineAfterVariableDeclaration": true, 25 | "requireSemicolons": true, 26 | "requireSpaceAfterBinaryOperators": true, 27 | "requireSpaceAfterComma": true, 28 | "requireSpaceAfterKeywords": 29 | [ 30 | "do", 31 | "for", 32 | "if", 33 | "else", 34 | "switch", 35 | "case", 36 | "try", 37 | "void", 38 | "while", 39 | "with", 40 | "return", 41 | "typeof" 42 | ], 43 | "requireSpaceBeforeBinaryOperators": true, 44 | "requireSpaceBeforeBlockStatements": true, 45 | "requireSpaceBetweenArguments": true, 46 | "requireSpacesInConditionalExpression": true, 47 | "requireSpacesInForStatement": true, 48 | "requireSpacesInsideObjectBrackets": "allButNested", 49 | "requireVarDeclFirst": null, 50 | "validateIndentation": "\t", 51 | "validateParameterSeparator": ", ", 52 | "validateQuoteMarks": "'" 53 | } 54 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esnext": true, 3 | "bitwise": false, 4 | "curly": false, 5 | "eqeqeq": true, 6 | "forin": false, 7 | "freeze": true, 8 | "latedef": "function", 9 | "noarg": true, 10 | "nonbsp": true, 11 | "nonew": true, 12 | "plusplus": false, 13 | "undef": true, 14 | "unused": false, 15 | "strict": true, 16 | "maxparams": 6, 17 | "maxdepth": 4, 18 | "maxstatements": false, 19 | "maxlen": 300, 20 | "proto": true, 21 | "sub": false, 22 | "browser": false, 23 | "browserify": false, 24 | "devel": false, 25 | "jquery": false, 26 | "mocha": false, 27 | "node": true, 28 | "shelljs": false, 29 | "worker": false 30 | } 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## jssip-node-websocket 2 | 3 | `JsSIP.Socket` interface for Node.js based on the [websocket](https://www.npmjs.com/package/websocket) module. 4 | 5 | The aim of this module is to provide [JsSIP](http://jssip.net) with WebSocket support when running in Node.js. 6 | 7 | 8 | ## Installation 9 | 10 | ```bash 11 | $ npm install jssip-node-websocket --save 12 | ``` 13 | 14 | 15 | ## Requirements 16 | 17 | * [jssip](http://jssip.net) >= `v2.0.0` 18 | * Node.js >= `v4.0.0` < `v20.0.0` 19 | 20 | ### Node >= `v20.0.0` 21 | 22 | Since Node `v20.0.0` the API for parsing URL has changed. To be compatible with Node `v20.0.0` and previous versions you can use the following package: 23 | 24 | [@meecode/jssip-node-websocket](https://www.npmjs.com/package/@meecode/jssip-node-websocket) 25 | 26 | ## Usage 27 | 28 | ```javascript 29 | const JsSIP = require('jssip'); 30 | const NodeWebSocket = require('jssip-node-websocket'); 31 | 32 | let socket = new NodeWebSocket('wss://foo.example.com'); 33 | 34 | let ua = new JsSIP.UA( 35 | { 36 | uri : 'sip:alice@example.com', 37 | password : 'xxxxxxxx', 38 | display_name : 'Alice', 39 | sockets : [ socket ] 40 | }); 41 | ``` 42 | 43 | 44 | ## API 45 | 46 | The module exports a `NodeWebSocket` class conforming with the `JsSIP.Socket` interface. 47 | 48 | 49 | ### `var socket = new NodeWebSocket(url, [options])` 50 | 51 | * `url` (String): The WebSocket URL. 52 | * `options` (Object): An object with fields `origin`, `headers`, `requestOptions` and `clientConfig` matching the same meaning and format of the parameters given to the [websocket.W3CWebSocket](https://github.com/theturtle32/WebSocket-Node/blob/v1.0.23/docs/W3CWebSocket.md) class constructor. 53 | 54 | 55 | ## F.A.Q. 56 | 57 | ##### How to allow invalid TLS certificates? 58 | 59 | ```javascript 60 | var socket = new Socket('wss://foo.example.com', 61 | { 62 | origin : 'https://www.example.com', 63 | requestOptions : 64 | { 65 | agent : new https.Agent({ rejectUnauthorized: false }) 66 | } 67 | }); 68 | ``` 69 | 70 | 71 | ## Author 72 | 73 | Iñaki Baz Castillo ([@ibc](https://github.com/ibc/) at Github) 74 | 75 | 76 | ## License 77 | 78 | [ISC](./LICENSE) 79 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const gulp = require('gulp'); 4 | const jshint = require('gulp-jshint'); 5 | const jscs = require('gulp-jscs'); 6 | const stylish = require('gulp-jscs-stylish'); 7 | 8 | gulp.task('lint', () => 9 | { 10 | let src = [ 'gulpfile.js', 'index.js' ]; 11 | 12 | return gulp.src(src) 13 | .pipe(jshint('.jshintrc')) 14 | .pipe(jscs('.jscsrc')) 15 | .pipe(stylish.combineWithHintResults()) 16 | .pipe(jshint.reporter('jshint-stylish', { verbose: true })) 17 | .pipe(jshint.reporter('fail')); 18 | }); 19 | 20 | gulp.task('default', gulp.series('lint')); 21 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const debug = require('debug')('jssip-node-websocket'); 4 | const debugerror = require('debug')('jssip-node-websocket:ERROR'); 5 | const parse = require('url-parse'); 6 | const W3CWebSocket = require('websocket').w3cwebsocket; 7 | 8 | class NodeWebSocket 9 | { 10 | constructor(url, options) 11 | { 12 | debug('new() [url:"%s", options:%o]', url, options); 13 | 14 | this._url = url; 15 | this._options = options || {}; 16 | this._sipUri = null; 17 | this._viaTransport = null; 18 | this._ws = null; 19 | 20 | var u = parse(url, true); 21 | 22 | if (!u) 23 | throw new TypeError('wrong url'); 24 | 25 | var scheme = u.protocol.toLowerCase().replace(/:/, ''); 26 | 27 | if ([ 'ws', 'wss' ].indexOf(scheme) === -1) 28 | throw new TypeError('invalid WebSocket scheme'); 29 | 30 | this._sipUri = `sip:${u.hostname}${u.port ? ':' + u.port : ''};transport=ws`; 31 | this._viaTransport = scheme.toUpperCase(); 32 | } 33 | 34 | get url() 35 | { 36 | return this._url; 37 | } 38 | 39 | get sip_uri() 40 | { 41 | return this._sipUri; 42 | } 43 | 44 | get via_transport() 45 | { 46 | return this._viaTransport; 47 | } 48 | 49 | set via_transport(value) 50 | { 51 | this._viaTransport = value.toUpperCase(); 52 | } 53 | 54 | connect() 55 | { 56 | debug('connect()'); 57 | 58 | if (this.isConnected()) 59 | { 60 | debug('WebSocket already connected [url:"%s"]', this._url); 61 | 62 | return; 63 | } 64 | else if (this.isConnecting()) 65 | { 66 | debug('WebSocket already connecting [url:"%s"]', this._url); 67 | 68 | return; 69 | } 70 | 71 | if (this._ws) 72 | this._ws.close(); 73 | 74 | debug('WebSocket connecting [url:"%s"]', this._url); 75 | 76 | var options = this._options; 77 | 78 | this._ws = new W3CWebSocket(this._url, 'sip', 79 | options.origin, options.headers, options.requestOptions, options.clientConfig); 80 | 81 | this._ws.binaryType = 'arraybuffer'; 82 | 83 | this._ws.onopen = () => 84 | { 85 | debug('WebSocket open [url:"%s"]', this._url); 86 | 87 | this.onconnect(); 88 | }; 89 | 90 | this._ws.onclose = (event) => 91 | { 92 | debug('WebSocket closed [url:"%s", code:%s, reason:"%s", wasClean:%s]', 93 | this._url, event.code, event.reason, event.wasClean); 94 | 95 | this.ondisconnect(event.wasClean, event.code, event.reason); 96 | }; 97 | 98 | this._ws.onerror = () => 99 | { 100 | debug('WebSocket error [url:"%s"]', this._url); 101 | }; 102 | 103 | this._ws.onmessage = (event) => 104 | { 105 | debug('WebSocket message received'); 106 | 107 | this.ondata(event.data); 108 | }; 109 | } 110 | 111 | disconnect() 112 | { 113 | debug('disconnect()'); 114 | 115 | this._ws.close(); 116 | this._ws = null; 117 | } 118 | 119 | send(message) 120 | { 121 | debug('send()'); 122 | 123 | if (!this.isConnected()) 124 | { 125 | debugerror('send() | unable to send message, WebSocket is not open'); 126 | 127 | return false; 128 | } 129 | 130 | this._ws.send(message); 131 | 132 | return true; 133 | } 134 | 135 | isConnected() 136 | { 137 | return this._ws && this._ws.readyState === this._ws.OPEN; 138 | } 139 | 140 | isConnecting() 141 | { 142 | return this._ws && this._ws.readyState === this._ws.CONNECTING; 143 | } 144 | } 145 | 146 | module.exports = NodeWebSocket; 147 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jssip-node-websocket", 3 | "version": "3.0.0", 4 | "description": "JsSIP.Socket interface for the Node.js based on the websocket module", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/versatica/jssip-node-websocket.git" 9 | }, 10 | "author": "Iñaki Baz Castillo ", 11 | "license": "ISC", 12 | "bugs": { 13 | "url": "https://github.com/versatica/jssip-node-websocket/issues" 14 | }, 15 | "engines": { 16 | "node": ">=4.0.0" 17 | }, 18 | "dependencies": { 19 | "debug": "^2.2.0", 20 | "url-parse": "^1.5.10", 21 | "websocket": "^1.0.23" 22 | }, 23 | "devDependencies": { 24 | "gulp": "4.0.0", 25 | "gulp-jscs": "^3.0.2", 26 | "gulp-jscs-stylish": "^1.3.0", 27 | "gulp-jshint": "^2.0.1", 28 | "gulp-shell": "^0.5.2", 29 | "jshint": "^2.9.1", 30 | "jshint-stylish": "^2.2.0" 31 | }, 32 | "peerDependencies": { 33 | "jssip": "^3.0.0" 34 | } 35 | } 36 | --------------------------------------------------------------------------------