obs-websocket-js
Advanced tools
Comparing version 0.4.0 to 0.5.0
100
CHANGELOG.md
@@ -1,24 +0,80 @@ | ||
# 0.4.0 | ||
- Rewrite. | ||
- Implement Promises and Event Emitter. | ||
- Events are now emit using `on('EventName', callback)` | ||
- Events can also be referenced `onEventName(callback)` | ||
- Requests now use the syntax `send('RequestName', {args}, callback) returns Promise` | ||
- Requests can also be referenced `EventName({args}, callback) returns Promise` | ||
- In both cases `callback(err, data)` | ||
- Stop trying to marshal the response data. | ||
- Aside from CamelCasing all the response data, no other actions are taken on the response at the moment. | ||
- No marshaling is done on the request objects at the moment. | ||
- Note that some method names have changed. Please reference [obs-websocket](https://github.com/Palakis/obs-websocket) for the API. | ||
# Change Log | ||
# 0.3.3 | ||
- Fix NPM Registration | ||
## [v0.5.0](https://github.com/haganbmj/obs-websocket-js/tree/v0.5.0) (2017-04-27) | ||
[Full Changelog](https://github.com/haganbmj/obs-websocket-js/compare/v0.4.0...v0.5.0) | ||
# 0.3.0 | ||
- Add .disconnect | ||
- Fix .onSceneListChanged | ||
- Fix .setSourceVisibility | ||
- API changes to .onStreamStatus to match obs-websocket API. | ||
- response.numberOfFrames => response.numTotalFrames | ||
- response.numberOfDroppedFrames => response.numDroppedFrames | ||
- Extend documentation. | ||
**Implemented enhancements:** | ||
- \[API\] Refactor \#connect\(\) to accept both an address and password [\#29](https://github.com/haganbmj/obs-websocket-js/issues/29) | ||
- \[Style\] Consider using ESlint instead of jshint [\#27](https://github.com/haganbmj/obs-websocket-js/issues/27) | ||
- \[Test\] Basic Unit Testing [\#22](https://github.com/haganbmj/obs-websocket-js/issues/22) | ||
- \[Docs\] Update Readme and Code Samples [\#19](https://github.com/haganbmj/obs-websocket-js/issues/19) | ||
**Fixed bugs:** | ||
- Fix webpack distributable [\#38](https://github.com/haganbmj/obs-websocket-js/pull/38) ([haganbmj](https://github.com/haganbmj)) | ||
- \[API\] Fix errors caused when .disconnect is called at the wrong time [\#37](https://github.com/haganbmj/obs-websocket-js/pull/37) ([Lange](https://github.com/Lange)) | ||
**Closed issues:** | ||
- \[Log\] Silence logging by default [\#32](https://github.com/haganbmj/obs-websocket-js/issues/32) | ||
- \[CI\] Update Travis Scripts to Ensure updated Distributable [\#24](https://github.com/haganbmj/obs-websocket-js/issues/24) | ||
**Merged pull requests:** | ||
- Small README fixes [\#39](https://github.com/haganbmj/obs-websocket-js/pull/39) ([Lange](https://github.com/Lange)) | ||
- \[Tests\] Add basic connection & authentication tests [\#36](https://github.com/haganbmj/obs-websocket-js/pull/36) ([Lange](https://github.com/Lange)) | ||
- Several fixes and refactors [\#33](https://github.com/haganbmj/obs-websocket-js/pull/33) ([Lange](https://github.com/Lange)) | ||
- \[Docs\] Add agdq17-layouts to projects list [\#31](https://github.com/haganbmj/obs-websocket-js/pull/31) ([Lange](https://github.com/Lange)) | ||
- \[Style\] Adopt eslint-config-xo-space/esnext [\#30](https://github.com/haganbmj/obs-websocket-js/pull/30) ([Lange](https://github.com/Lange)) | ||
- \[CI\] Update Travis Scripts to Ensure updated Distributable [\#28](https://github.com/haganbmj/obs-websocket-js/pull/28) ([haganbmj](https://github.com/haganbmj)) | ||
## [v0.4.0](https://github.com/haganbmj/obs-websocket-js/tree/v0.4.0) (2017-04-23) | ||
[Full Changelog](https://github.com/haganbmj/obs-websocket-js/compare/v0.3.3...v0.4.0) | ||
**Implemented enhancements:** | ||
- Implement individual Start and Stop Recording/Streaming methods [\#3](https://github.com/haganbmj/obs-websocket-js/issues/3) | ||
- Update API for obs-websocket 4.0.0 development additions [\#15](https://github.com/haganbmj/obs-websocket-js/issues/15) | ||
- Support ".on\(" style event emissions. [\#14](https://github.com/haganbmj/obs-websocket-js/issues/14) | ||
- \[Build\] Switch to Browserify/Webpack for Builds [\#13](https://github.com/haganbmj/obs-websocket-js/issues/13) | ||
- \[Protocol\] Rewrite with Versioning obs-websocket in Mind [\#12](https://github.com/haganbmj/obs-websocket-js/issues/12) | ||
- \[Protocol\] Implement Set/GetVolume methods [\#11](https://github.com/haganbmj/obs-websocket-js/issues/11) | ||
**Fixed bugs:** | ||
- OBSWebSocket is not a constructor error [\#17](https://github.com/haganbmj/obs-websocket-js/issues/17) | ||
**Merged pull requests:** | ||
- Rewrite. Fix \#3, Fix \#11, Fix \#12, Fix \#13, Fix \#14, Fix \#15 [\#16](https://github.com/haganbmj/obs-websocket-js/pull/16) ([haganbmj](https://github.com/haganbmj)) | ||
## [v0.3.3](https://github.com/haganbmj/obs-websocket-js/tree/v0.3.3) (2017-02-17) | ||
[Full Changelog](https://github.com/haganbmj/obs-websocket-js/compare/v0.2.0...v0.3.3) | ||
**Implemented enhancements:** | ||
- Expand documentation to include params and response objects [\#2](https://github.com/haganbmj/obs-websocket-js/issues/2) | ||
**Closed issues:** | ||
- Disconnect function [\#8](https://github.com/haganbmj/obs-websocket-js/issues/8) | ||
- setSourceVisbility not working [\#7](https://github.com/haganbmj/obs-websocket-js/issues/7) | ||
- onSceneListChanged not working [\#5](https://github.com/haganbmj/obs-websocket-js/issues/5) | ||
- Fix Node dependency [\#4](https://github.com/haganbmj/obs-websocket-js/issues/4) | ||
**Merged pull requests:** | ||
- Travis-CI Test + Update .gitignore [\#10](https://github.com/haganbmj/obs-websocket-js/pull/10) ([haganbmj](https://github.com/haganbmj)) | ||
## [v0.2.0](https://github.com/haganbmj/obs-websocket-js/tree/v0.2.0) (2016-12-02) | ||
[Full Changelog](https://github.com/haganbmj/obs-websocket-js/compare/v0.1.0...v0.2.0) | ||
## [v0.1.0](https://github.com/haganbmj/obs-websocket-js/tree/v0.1.0) (2016-11-26) | ||
**Implemented enhancements:** | ||
- Marshal callback params to OBSScene and OBSSource objects [\#1](https://github.com/haganbmj/obs-websocket-js/issues/1) | ||
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* |
@@ -1,7 +0,4 @@ | ||
module.exports = function(grunt) { | ||
module.exports = function (grunt) { | ||
'use strict'; | ||
var webpack = require('webpack'); | ||
const path = require('path'); | ||
grunt.util.linefeed = '\n'; | ||
@@ -13,5 +10,5 @@ grunt.initConfig({ | ||
' * Author: <%= pkg.author %>\n' + | ||
' * Repo: <%= pkg.repository.url %>\n' + | ||
' * SHA: <%= pkg.sha %>\n' + | ||
' * Timestamp: <%= pkg.timestamp %>\n' + | ||
' * Repository: <%= pkg.repoUrl %>\n' + | ||
' * Build SHA: <%= pkg.sha %>\n' + | ||
' * Build Timestamp: <%= pkg.timestamp %>\n' + | ||
' */\n\n', | ||
@@ -22,28 +19,5 @@ | ||
obswebsocket: { | ||
target: "web", | ||
entry: './lib/OBSWebSocket.js', | ||
output: { | ||
path: path.resolve(__dirname, 'dist'), | ||
filename: 'obs-websocket.js', | ||
library: 'OBSWebSocket' | ||
}, | ||
externals: { | ||
'ws': 'WebSocket' | ||
}, | ||
failOnError: false/*, | ||
plugins: [ | ||
new webpack.optimize.UglifyJsPlugin() | ||
]*/ | ||
failOnError: false | ||
}, | ||
obswebsocket_watch: { | ||
target: "web", | ||
entry: './lib/OBSWebSocket.js', | ||
output: { | ||
path: path.resolve(__dirname, 'dist'), | ||
filename: 'obs-websocket.js', | ||
library: 'OBSWebSocket' | ||
}, | ||
externals: { | ||
'ws': 'WebSocket' | ||
}, | ||
obswebsocketWatch: { | ||
failOnError: false, | ||
@@ -53,8 +27,8 @@ watch: true | ||
}, | ||
jsdoc2md: { | ||
docs: { | ||
src: ['lib/OBSWebSocket.js', 'lib/OBSScene.js', 'lib/OBSSource.js', 'lib/Core.js', 'lib/Socket.js', 'lib/Requests.js', 'lib/Events.js'], | ||
dest: 'dist/DOCUMENTATION.md' | ||
} | ||
}, | ||
// Jsdoc2md: { | ||
// docs: { | ||
// src: ['lib/OBSWebSocket.js', 'lib/OBSScene.js', 'lib/OBSSource.js', 'lib/Core.js', 'lib/Socket.js', 'lib/Requests.js', 'lib/Events.js'], | ||
// dest: 'dist/DOCUMENTATION.md' | ||
// } | ||
// }, | ||
clean: { | ||
@@ -75,7 +49,7 @@ dist: 'dist' | ||
require('load-grunt-tasks')(grunt, { scope: 'devDependencies' }); | ||
require('load-grunt-tasks')(grunt, {scope: 'devDependencies'}); | ||
grunt.registerTask('build', ['clean:dist', 'webpack:obswebsocket', 'concat']); | ||
grunt.registerTask('watch', ['webpack:obswebsocket_watch']); | ||
grunt.registerTask('default', ['build', /*'jsdoc2md'*/]); | ||
grunt.registerTask('watch', ['webpack:obswebsocketWatch']); | ||
grunt.registerTask('default', ['build']); | ||
}; |
// Last Updated: April 22, 2017 | ||
var API = { | ||
const API = { | ||
availableMethods: [ | ||
@@ -30,2 +30,2 @@ 'GetVersion', 'GetAuthRequired', | ||
module.exports = exports = API; | ||
module.exports = API; |
@@ -1,23 +0,24 @@ | ||
var SHA256 = require('sha.js/sha256'); | ||
const SHA256 = require('sha.js/sha256'); | ||
var AuthHashing = function(salt, challenge) { | ||
this.salt = salt || ''; | ||
this.challenge = challenge || ''; | ||
class AuthHashing { | ||
constructor(salt, challenge) { | ||
this.salt = salt || ''; | ||
this.challenge = challenge || ''; | ||
this.hash = function(msg) { | ||
this.hash = function (msg) { | ||
const hash = new SHA256() | ||
.update(msg) | ||
.update(this.salt) | ||
.digest('base64'); | ||
var hash = new SHA256() | ||
.update(msg) | ||
.update(this.salt) | ||
.digest('base64'); | ||
const resp = new SHA256() | ||
.update(hash) | ||
.update(challenge) | ||
.digest('base64'); | ||
var resp = new SHA256() | ||
.update(hash) | ||
.update(challenge) | ||
.digest('base64'); | ||
return resp; | ||
}; | ||
} | ||
} | ||
return resp; | ||
}; | ||
}; | ||
module.exports = exports = AuthHashing; | ||
module.exports = AuthHashing; |
@@ -1,14 +0,79 @@ | ||
var Core = require('./Core'); | ||
const Socket = require('./Socket'); | ||
const Status = require('./Status'); | ||
const debug = require('debug')('obs-websocket-js:Core'); | ||
class OBSWebSocket extends Core { | ||
constructor(address, password) { | ||
address = address || 'localhost'; | ||
password = password || ''; | ||
let requestCounter = 0; | ||
super(address, password); | ||
function generateMessageId() { | ||
return String(requestCounter++); | ||
} | ||
class OBSWebSocket extends Socket { | ||
constructor() { | ||
super(); | ||
// Bind all event emissions from the socket such that they are marshaled an re-emit at the base OBSWebSocket scope. | ||
this.on('obs:internal:event', this._handleEvent); | ||
} | ||
// Internal generic Socket request method. Returns a promise, handles callbacks. | ||
// Generates a messageId internally and will override any passed in the args. | ||
// Note that the requestType here is pre-marshaling and currently must match exactly what the websocket plugin is expecting. | ||
send(requestType, args = {}, callback) { | ||
args = args || {}; | ||
return new Promise((resolve, reject) => { | ||
if (!this._connected) { | ||
debug('[send] %s', Status.NOT_CONNECTED.description); | ||
this._doCallback(callback, Status.NOT_CONNECTED, null); | ||
reject(Status.NOT_CONNECTED); | ||
return; | ||
} | ||
if (!requestType) { | ||
debug('[send] %s', Status.REQUEST_TYPE_NOT_SPECIFIED.description); | ||
this._doCallback(callback, Status.REQUEST_TYPE_NOT_SPECIFIED, null); | ||
reject(Status.REQUEST_TYPE_NOT_SPECIFIED); | ||
return; | ||
} | ||
// Assign the core message details. | ||
args['request-type'] = requestType; | ||
const messageId = args['message-id'] = generateMessageId(); // eslint-disable-line no-multi-assign | ||
// Submit the request to the websocket. | ||
debug('[send] %s %s %o', messageId, requestType, args); | ||
try { | ||
this._socket.send(JSON.stringify(args)); | ||
} catch (e) { | ||
reject(e); | ||
} | ||
// Assign a temporary event listener for this particular messageId to uniquely identify the response. | ||
this.once('obs:internal:message:id-' + messageId, message => { | ||
// TODO: Do additional stuff with the msg to determine errors, marshaling, etc. | ||
// message = API.marshalResponse(requestType, message); | ||
if (message.status === 'error') { | ||
debug('[send:reject] %o', message); | ||
this._doCallback(callback, message, null); | ||
reject(message); | ||
} else { | ||
debug('[send:resolve] %o', message); | ||
this._doCallback(callback, null, message); | ||
resolve(message); | ||
} | ||
}); | ||
}); | ||
} | ||
// TODO: Marshal to use the API defined eventType rather than the obs-websocket defined one. | ||
// Perform some logic them re-emit the event to the public name. | ||
_handleEvent(message) { | ||
this.emit(message.updateType, message); | ||
} | ||
} | ||
require('./MethodBinding')(OBSWebSocket); | ||
require('./methodBinding')(OBSWebSocket); | ||
module.exports = exports = OBSWebSocket; | ||
module.exports = OBSWebSocket; |
@@ -1,13 +0,13 @@ | ||
var WebSocket = require('ws'); | ||
var EventEmitter = require('events'); | ||
var AuthHashing = require('./AuthHashing'); | ||
var url = require('url'); | ||
var log = require('loglevel'); | ||
log.setLevel('info'); | ||
const WebSocket = require('ws'); | ||
const EventEmitter = require('events'); | ||
const AuthHashing = require('./AuthHashing'); | ||
const Status = require('./Status'); | ||
const debug = require('debug')('obs-websocket-js:Socket'); | ||
const logAmbiguousError = require('./util/logAmbiguousError'); | ||
var NOP = function() {}; | ||
const NOP = function () {}; | ||
var DEFAULT_PORT = 4444; | ||
const DEFAULT_PORT = 4444; | ||
var AUTH = { | ||
let AUTH = { | ||
required: true, | ||
@@ -20,7 +20,11 @@ salt: undefined, | ||
obj = obj || {}; | ||
for (var key in obj) { | ||
if (obj.hasOwnProperty(key)) { | ||
var camelCasedKey = key.replace( /-([a-z])/gi, function ( $0, $1 ) { return $1.toUpperCase(); } ); | ||
obj[camelCasedKey] = obj[key]; | ||
for (const key in obj) { | ||
if (!{}.hasOwnProperty.call(obj, key)) { | ||
continue; | ||
} | ||
const camelCasedKey = key.replace(/-([a-z])/gi, ($0, $1) => { | ||
return $1.toUpperCase(); | ||
}); | ||
obj[camelCasedKey] = obj[key]; | ||
} | ||
@@ -32,3 +36,3 @@ | ||
class Socket extends EventEmitter { | ||
constructor(address = 'localhost', password = '') { | ||
constructor() { | ||
super(); | ||
@@ -38,58 +42,43 @@ this._connected = false; | ||
var originalEmit = this.emit; | ||
this.emit = function() { | ||
log.debug('[Socket:emit]', arguments[0], arguments[1]); | ||
const originalEmit = this.emit; | ||
this.emit = function () { | ||
debug('[emit] %s %o', arguments[0], arguments[1]); | ||
originalEmit.apply(this, arguments); | ||
} | ||
this.connect({ address: address }) | ||
.then(() => { this.authenticate({ 'password': password }); }) | ||
.catch((err) => { log.error('Connection or Authentication failed.', err); }); | ||
}; | ||
} | ||
// TODO: Break this up a bit. | ||
// TODO: Clean up callbacks. | ||
connect(args, callback) { | ||
args = args || {}; | ||
var address = args.address; | ||
_doCallback(callback, err, data) { | ||
callback = callback || NOP; | ||
if (!url.parse(address).port) { | ||
address += ':' + DEFAULT_PORT; | ||
try { | ||
callback(err, data); | ||
} catch (e) { | ||
logAmbiguousError(debug, 'Unable to resolve callback:', e); | ||
this.emit('error', e); // Forward the error so that we're not completely swallowing it. | ||
} | ||
} | ||
if (this._connected) { | ||
this._socket.close(); | ||
this._connected = false; | ||
} | ||
async connect(args = {}, callback) { | ||
try { | ||
args = args || {}; | ||
let address = args.address || 'localhost'; | ||
return new Promise((resolve, reject) => { | ||
log.info('Attempting to connect to:', address); | ||
this._socket = new WebSocket('ws://' + address); | ||
// If no port was provided, add the default port. | ||
if (!/(?::\d{2,4})/.test(address)) { | ||
address += ':' + DEFAULT_PORT; | ||
} | ||
this._socket.onopen = () => { | ||
log.info('Connection opened:', address); | ||
this.emit('obs:internal:event', { updateType: 'ConnectionOpened' }); | ||
this._connected = true; | ||
try { callback(null, true); } catch (e) { } | ||
resolve(); | ||
}; | ||
this._socket.onclose = () => { | ||
log.info('Connection closed:', address); | ||
this.emit('obs:internal:event', { updateType: 'ConnectionClosed' }); | ||
if (this._connected) { | ||
this._socket.close(); | ||
this._connected = false; | ||
}; | ||
} | ||
this._socket.onerror = (evt) => { | ||
log.error('Connected failed.', evt.code); | ||
this._connected = false; | ||
try { callback(true, null); } catch (e) { } | ||
reject(evt); | ||
}; | ||
await this._connect(address); | ||
this._connected = true; | ||
this._socket.onmessage = (msg) => { | ||
log.debug('[Socket:OnMessage]', msg); | ||
// This handler must be present before we can call _authenticate. | ||
this._socket.onmessage = msg => { | ||
debug('[OnMessage]: %o', msg); | ||
const data = camelCaseKeys(JSON.parse(msg.data)); | ||
var data = camelCaseKeys(JSON.parse(msg.data)); | ||
// Emit the message with ID if available, otherwise default to a non-messageId driven event. | ||
@@ -102,12 +91,71 @@ if (data.messageId) { | ||
}; | ||
await this._authenticate(args.password); | ||
this._socket.onclose = () => { | ||
this._connected = false; | ||
debug('Connection closed: %s', address); | ||
this.emit('obs:internal:event', {updateType: 'ConnectionClosed'}); | ||
}; | ||
debug('Connection opened: %s', address); | ||
this.emit('obs:internal:event', {updateType: 'ConnectionOpened'}); | ||
this._doCallback(callback); | ||
} catch (err) { | ||
this._connected = false; | ||
logAmbiguousError(debug, 'Connection failed:', err); | ||
this._socket.close(); | ||
this._doCallback(callback, err); | ||
return Promise.reject(err); | ||
} | ||
} | ||
/** | ||
* Opens a WebSocket connection to an obs-websocket server, but does not attempt any authentication. | ||
* @param address {String} | ||
* @returns {Promise} | ||
* @private | ||
*/ | ||
_connect(address) { | ||
return new Promise((resolve, reject) => { | ||
let settled = false; | ||
debug('Attempting to connect to: %s', address); | ||
this._socket = new WebSocket('ws://' + address); | ||
// We only handle initial connection errors. | ||
// Beyond that, the consumer is responsible for adding their own `error` event listener. | ||
this._socket.onerror = error => { | ||
if (settled) { | ||
return; | ||
} | ||
settled = true; | ||
reject(error); | ||
}; | ||
this._socket.onopen = () => { | ||
if (settled) { | ||
return; | ||
} | ||
settled = true; | ||
resolve(); | ||
}; | ||
}); | ||
} | ||
authenticate(args, callback) { | ||
args = args || {}; | ||
args.password = args.password || ''; | ||
callback = callback || NOP; | ||
/** | ||
* Authenticates to an obs-websocket server. Must already have an active connection before calling this method. | ||
* @param [password=''] {String} | ||
* @returns {Promise} | ||
* @private | ||
*/ | ||
_authenticate(password = '') { | ||
if (!this._connected) { | ||
return Promise.reject(Status.NOT_CONNECTED); | ||
} | ||
return this.GetAuthRequired() | ||
.then((data) => { | ||
return this.getAuthRequired() | ||
.then(data => { | ||
AUTH = { | ||
@@ -121,25 +169,12 @@ required: data.authRequired, | ||
if (!AUTH.required) { | ||
log.debug('Authentication Not Required.'); | ||
this.emit('obs:internal:event', { updateType: 'AuthenticationSuccess' }); | ||
try { callback(null, true); } catch (e) { } | ||
return Promise.resolve(); | ||
this.emit('obs:internal:event', {updateType: 'AuthenticationSuccess'}); | ||
return Promise.resolve(Status.AUTH_NOT_REQUIRED); | ||
} | ||
var params = { | ||
'auth': new AuthHashing(AUTH.salt, AUTH.challenge).hash(args.password) | ||
}; | ||
return this.send('Authenticate', params, callback) | ||
.then(() => { | ||
log.debug('Authentification Success.'); | ||
this.emit('obs:internal:event', { updateType: 'AuthenticationSuccess' }); | ||
try { callback(null, true); } catch (e) { } | ||
return Promise.resolve(); | ||
}) | ||
.catch(() => { | ||
log.error('Authentication Failure.'); | ||
this.emit('obs:internal:event', { updateType: 'AuthenticationFailure' }); | ||
try { callback(true, null); } catch (e) { } | ||
return Promise.reject('Authentication Failure'); | ||
}); | ||
return this.send('Authenticate', { | ||
auth: new AuthHashing(AUTH.salt, AUTH.challenge).hash(password) | ||
}).then(() => { | ||
debug('Authentication Success.'); | ||
this.emit('obs:internal:event', {updateType: 'AuthenticationSuccess'}); | ||
}); | ||
}); | ||
@@ -155,4 +190,6 @@ } | ||
disconnect() { | ||
log.debug('Disconnect requested.'); | ||
this._socket.close(); | ||
debug('Disconnect requested.'); | ||
if (this._socket) { | ||
this._socket.close(); | ||
} | ||
} | ||
@@ -159,0 +196,0 @@ } |
{ | ||
"name": "obs-websocket-js", | ||
"version": "0.4.0", | ||
"version": "0.5.0", | ||
"description": "OBS Websocket API in Javascript", | ||
"main": "lib/index.js", | ||
"main": "index.js", | ||
"repository": "haganbmj/obs-websocket-js", | ||
"repoUrl": "https://github.com/haganbmj/obs-websocket-js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"test": "npm run static && nyc ava", | ||
"report": "nyc report --reporter=html", | ||
"grunt": "grunt", | ||
"build": "grunt", | ||
"watch": "grunt watch" | ||
"watch": "grunt watch", | ||
"static": "eslint ." | ||
}, | ||
@@ -24,3 +26,3 @@ "keywords": [ | ||
"dependencies": { | ||
"loglevel": "^1.4.1", | ||
"debug": "^2.6.4", | ||
"sha.js": "^2.4.8", | ||
@@ -30,2 +32,6 @@ "ws": "^1.1.1" | ||
"devDependencies": { | ||
"ava": "^0.19.1", | ||
"eslint": "^3.19.0", | ||
"eslint-config-xo-space": "^0.16.0", | ||
"eslint-plugin-ava": "^4.2.0", | ||
"grunt": "^1.0.1", | ||
@@ -37,2 +43,3 @@ "grunt-contrib-clean": "^1.0.0", | ||
"load-grunt-tasks": "^3.5.2", | ||
"nyc": "^10.2.0", | ||
"webpack": "^2.2.1" | ||
@@ -44,4 +51,7 @@ }, | ||
"homepage": "https://github.com/haganbmj/obs-websocket-js#readme", | ||
"sha": "local build", | ||
"timestamp": "local build" | ||
"sha": "5380d20831fa2d05c3044e939a2fcb729777ce87", | ||
"timestamp": "2017-04-27 06:21:54+00:00", | ||
"eslintConfig": { | ||
"extends": "xo-space/esnext" | ||
} | ||
} |
172
README.md
# obs-websocket-js | ||
*OBSWebSocket.JS allows Javascript-based connections to [obs-websocket](https://github.com/Palakis/obs-websocket).* | ||
*OBSWebSocket.JS allows Javascript-based connections to [obs-websocket][link-obswebsocket].* | ||
[![Build Status][badge-build-status]](https://travis-ci.org/haganbmj/obs-websocket-js) [![Latest release][badge-release]][Releases] [![Latest Tag][badge-tag]][Tags] | ||
[![Build Status][badge-build-status]][link-Travis-CI] [![Latest release][badge-release]][link-releases] [![Latest Tag][badge-tag]][link-tags] | ||
###### [Download](https://haganbmj.github.io/obs-websocket-js/dist/obs-websocket.js) | ~~[Documentation](https://github.com/haganbmj/obs-websocket-js/blob/gh-pages/dist/DOCUMENTATION.md)~~ | ~~[Examples](https://github.com/haganbmj/obs-websocket-js/blob/gh-pages/samples)~~ | ||
##### [Download][link-download] | [Samples][link-samples] | [Changelog][link-changelog] | ||
## In Development | ||
In the middle of a rewrite. | ||
TODOs include... | ||
- Travis auto deployments of pre-release and release versions, generation of documentation to gh-pages. | ||
- Clean up method/event binding. | ||
- Organize API versioning more efficiently to better allow backwards compatibility. | ||
- Generate documentation based on API versioning. | ||
- Unit testing / Socket mocking. | ||
## Installation | ||
```sh | ||
npm install obs-websocket-js --save | ||
``` | ||
```html | ||
<script type='text/javascript' src='./dist/obs-websocket.js'></script> | ||
``` | ||
If you can help with any of this please do. | ||
## Usage | ||
#### Instantiation | ||
The web distributable exposes a global named `OBSWebSocket`. | ||
In node.js, import the project using the following. | ||
## Contributing | ||
- Install [node.js](http://nodejs.org). | ||
- Clone the repo. | ||
- Go nuts. | ||
- Generate the concatenated Javascript file and API documentation by running the following... | ||
```sh | ||
npm install | ||
npm install --only=dev | ||
npm run build | ||
```js | ||
const OBSWebSocket = require('obs-websocket-js'); | ||
``` | ||
- Run grunt watch using the following. Note that this will only update the distribution js file, not the markdown. | ||
```sh | ||
npm run watch | ||
Create a new WebSocket connection using the following. | ||
- Address is optional; defaults to `localhost` with a default port of `4444`. | ||
- Password is optional. | ||
```js | ||
const obs = new OBSWebSocket(); | ||
obs.connect({ address: 'localhost:4444', password: '$up3rSecretP@ssw0rd' }); | ||
``` | ||
#### Formatting Guidelines | ||
- 2 spaces rather than tabs. | ||
#### Sending Requests | ||
All requests support the following two Syntax options where both `err` and `data` will contain the raw response from the WebSocket plugin. | ||
_Note that all response objects will supply both the original [obs-websocket][link-obswebsocket] response items in their original format (ex: `'response-item'`), but also camelCased (ex: `'responseItem'`) for convenience._ | ||
- RequestName must exactly match what is defined by the [obs-websocket][link-obswebsocket] plugin. | ||
- When calling a method directly (instead of via `.send`), you may also use the `lowerCamelCase` version of the request, i.e. `requestName` instead of `RequestName`. This may be preferred if you use a linter such as [ESlint](http://eslint.org/). | ||
- {args} are optional. Note that both `request-type` and `message-id` will be bound automatically. | ||
- callback(err, data) is optional. | ||
```js | ||
// These three options are equivalent for every available request. | ||
obs.send('RequestName', {args}, callback(err, data)) returns Promise | ||
obs.RequestName({args}, callback(err, data)) returns Promise | ||
obs.requestName({args}, callback(err, data)) returns Promise | ||
// The following are additional supported requests. | ||
obs.connect({ address: 'address', password: 'password' }, callback(err, data)) returns Promise | ||
``` | ||
[Releases]: https://github.com/haganbmj/obs-websocket-js/releases "obs-websocket-js Releases" | ||
[Tags]: https://github.com/haganbmj/obs-websocket-js/tags "obs-websocket-js Tags" | ||
#### Receiving Events | ||
All events support the following two Syntax options where both `err` and `data` will contain the raw response from the WebSocket plugin. | ||
_Note that all response objects will supply both the original [obs-websocket][link-obswebsocket] response items in their original format (ex: `'response-item'`), but also camelCased (ex: `'responseItem'`) for convenience._ | ||
- EventName must exactly match what is defined by the [obs-websocket][link-obswebsocket] plugin. | ||
```js | ||
obs.on('EventName', callback(err, data)); | ||
obs.onEventName(callback(err, data)); | ||
// The following are additional supported requests. | ||
obs.on('ConnectionOpened', callback(err, data)); | ||
obs.on('ConnectionClosed', callback(err, data)); | ||
obs.on('AuthenticationSuccess', callback(err, data)); | ||
obs.on('AuthenticationFailure', callback(err, data)); | ||
``` | ||
#### Handling Errors | ||
By default, certain types of WebSocket errors will be thrown as uncaught exceptions. | ||
To ensure that you are handling every error, you must do the following: | ||
1. Add a `.catch()` handler to every returned Promise. | ||
2. Add a `error` event listener to the `OBSWebSocket` object. | ||
#### Example | ||
```js | ||
const OBSWebSocket = require('obs-websocket-js'); | ||
const obs = new OBSWebSocket(); | ||
obs.connect({ address: 'localhost:4444', password: '$up3rSecretP@ssw0rd' }) | ||
.then(() => { | ||
console.log('Success! We\'re connected & authenticated.'); | ||
return obs.getSceneList({}); | ||
}) | ||
.then(data => { | ||
console.log(`${data.scenes.length} Available Scenes!`); | ||
data.scenes.forEach(scene => { | ||
if (scene.name !== data.currentScene) { | ||
console.log('Found a different scene! Switching to Scene:', scene.name); | ||
obs.setCurrentScene({'scene-name': scene.name}); | ||
} | ||
}); | ||
}) | ||
.catch(err => { // Ensure that you add a catch handler to every Promise chain. | ||
console.log(err); | ||
}); | ||
obs.onSwitchScenes((err, data) => { | ||
console.log('New Active Scene:', data.sceneName); | ||
}); | ||
// You must add this handler to avoid uncaught exceptions. | ||
obs.on('error', err => { | ||
console.error('socket error:', err); | ||
}); | ||
``` | ||
#### Debugging | ||
To enable debug logging, set the `DEBUG` environment variable: | ||
```bash | ||
# Enables debug logging for all modules of osb-websocket-js | ||
DEBUG=obs-websocket-js:* | ||
# on Windows | ||
set DEBUG=obs-websocket-js:* | ||
``` | ||
If you have multiple libraries or application which use the `DEBUG` environment variable, they can be joined with commas: | ||
```bash | ||
DEBUG=foo,bar:*,obs-websocket-js:* | ||
# on Windows | ||
set DEBUG=foo,bar:*,obs-websocket-js:* | ||
``` | ||
Browser debugging uses `localStorage` | ||
``` | ||
localStorage.debug = 'obs-websocket-js:*'; | ||
localStorage.debug = 'foo,bar:*,obs-websocket-js:*'; | ||
``` | ||
For more information, see the [`debug`][link-debug] documentation. | ||
## TODOs | ||
- Unit testing / Socket mocking. | ||
- More examples. | ||
## Projects Using **obs-websocket-js** | ||
_To add your project to this list, submit a Pull Request._ | ||
- [GamesDoneQuick/agdq17-layouts](https://github.com/GamesDoneQuick/agdq17-layouts) | ||
## [Contributing Guidelines][link-contributing] | ||
[link-obswebsocket]: https://github.com/Palakis/obs-websocket "OBS WebSocket Plugin" | ||
[link-Travis-CI]: https://travis-ci.org/haganbmj/obs-websocket-js "Travis CI" | ||
[badge-build-status]: https://img.shields.io/travis/haganbmj/obs-websocket-js/master.svg?style=flat "Travis Status" | ||
[badge-tag]: https://img.shields.io/github/tag/haganbmj/obs-websocket-js.svg?style=flat "Latest Tag" | ||
[badge-release]: https://img.shields.io/github/release/haganbmj/obs-websocket-js.svg?style=flat "Latest Release" | ||
[link-releases]: https://github.com/haganbmj/obs-websocket-js/releases "obs-websocket-js Releases" | ||
[link-tags]: https://github.com/haganbmj/obs-websocket-js/tags "obs-websocket-js Tags" | ||
[link-download]: https://github.com/haganbmj/obs-websocket-js/blob/gh-pages/dist/obs-websocket.js "Download" | ||
[link-documentation]: https://github.com/haganbmj/obs-websocket-js/blob/gh-pages/DOCUMENTATION.md "Documentation" | ||
[link-samples]: https://github.com/haganbmj/obs-websocket-js/tree/master/samples "Samples" | ||
[link-changelog]: https://github.com/haganbmj/obs-websocket-js/blob/gh-pages/CHANGELOG.md "Changelog" | ||
[link-contributing]: .github/CONTRIBUTING.md "Contributing" | ||
[link-debug]: https://github.com/visionmedia/debug "Debug Documentation" |
@@ -0,15 +1,17 @@ | ||
const path = require('path'); | ||
module.exports = { | ||
target: "web", | ||
target: 'web', | ||
entry: { | ||
"obs-websocket": "./lib/OBSWebSocket.js" | ||
'obs-websocket': './index.js' | ||
}, | ||
output: { | ||
"path": __dirname + "/dist", | ||
"filename": "[name].js", | ||
"library": "OBSWebSocket" | ||
path: path.join(__dirname, '/dist'), | ||
filename: '[name].js', | ||
library: 'OBSWebSocket' | ||
}, | ||
externals: { | ||
"ws": "WebSocket" | ||
ws: 'WebSocket' | ||
}, | ||
devtool: false | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
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
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
161102
18
1
161
0
12
3695
+ Addeddebug@^2.6.4
+ Addeddebug@2.6.9(transitive)
+ Addedms@2.0.0(transitive)
- Removedloglevel@^1.4.1
- Removedloglevel@1.9.2(transitive)