├── sample └── resources │ ├── ringtone.wav │ ├── ringbacktone.wav │ ├── video_camera.png │ ├── video_camera_big.png │ └── css │ ├── videoAdvanced.css │ ├── video.css │ └── rtcomm.css ├── tests ├── unit │ ├── all.js │ └── util │ │ └── util.js ├── support │ ├── testConfig.template │ ├── testConfig.json │ ├── server.js │ ├── mqttws31_shim.js │ ├── config.js │ └── rtcommFatUtils.js ├── functional │ ├── junk │ │ ├── sampletest.js │ │ ├── scott.js │ │ └── iTest.js │ ├── all_with_server.js │ ├── all.js │ ├── connection │ │ └── MqttConnection.js │ ├── PresenceMonitor.js │ ├── GenericMessageEndpoint.js │ ├── MqttEndpoint.js │ ├── SessionQueue.js │ └── SessionEndpoint.js ├── manual │ ├── old │ │ ├── scripts │ │ │ ├── main.js │ │ │ └── junk.js │ │ ├── dojoTutorial.html │ │ ├── NodeConnectorTest.html │ │ ├── RtcommTest.html │ │ ├── manualTest.css │ │ ├── junk.html │ │ ├── fancy.css │ │ └── deprecated │ │ │ ├── testClient.html │ │ │ ├── client1.html │ │ │ └── devTestClient.html │ ├── localTest.html │ ├── pc_test.html │ ├── test1.html │ ├── presenceUnit.html │ ├── presence100.html │ ├── test.html │ └── sessioneptest.html ├── rtcommTestTemplate.js ├── README.md ├── intern.js ├── intern_stress.js ├── intern_local.js └── stress │ └── stressTest.js ├── CONTRIBUTING.md ├── .gitignore ├── src ├── rtcomm │ ├── EndpointProvider │ │ ├── protocols │ │ │ ├── README.md │ │ │ ├── ChatProtocol.js │ │ │ └── GenericMessageProtocol.js │ │ ├── endpoints │ │ │ ├── MessageEndpoint.js │ │ │ ├── MqttEndpoint.js │ │ │ └── RtcommEndpoint.js │ │ ├── ModuleGlobals.js │ │ ├── Queues.js │ │ └── EndpointRegistry.js │ ├── util │ │ ├── RtcommError.js │ │ ├── RtcommEvent.js │ │ ├── Sound.js │ │ └── RtcommBaseObject.js │ ├── main.js │ └── connection │ │ ├── ModuleGlobals.js │ │ ├── Transaction.js │ │ └── MessageFactory.js └── mock │ └── MockRtcommServer.js ├── bower.json ├── package.json ├── server.js ├── docs ├── sample.md └── rtcomm_and_liberty_setup.md └── README.md /sample/resources/ringtone.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WASdev/lib.rtcomm.clientjs/HEAD/sample/resources/ringtone.wav -------------------------------------------------------------------------------- /sample/resources/ringbacktone.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WASdev/lib.rtcomm.clientjs/HEAD/sample/resources/ringbacktone.wav -------------------------------------------------------------------------------- /sample/resources/video_camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WASdev/lib.rtcomm.clientjs/HEAD/sample/resources/video_camera.png -------------------------------------------------------------------------------- /sample/resources/video_camera_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WASdev/lib.rtcomm.clientjs/HEAD/sample/resources/video_camera_big.png -------------------------------------------------------------------------------- /tests/unit/all.js: -------------------------------------------------------------------------------- 1 | define([ 2 | './connection/connection.js', 3 | './util/util.js', 4 | './EndpointProvider.js' 5 | ], function () {}); 6 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | If you'd like to contribute to this project, see our [contributor guidelines](https://github.com/WASdev/wasdev.github.io/blob/master/CONTRIBUTING.md). 2 | -------------------------------------------------------------------------------- /tests/support/testConfig.template: -------------------------------------------------------------------------------- 1 | { 2 | "mqttServers" : ["@MQTT1@", "@MQTT2@"], 3 | "managementTopicName" : "@TOPICNAME@", 4 | "rtcommTopicPath" : "/rtcomm/" 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | /node_modules 3 | /bower_components 4 | /tmp 5 | **/__* 6 | .project 7 | .settings 8 | /dist/jsdoc 9 | /dist/mock 10 | /dist/umd/ 11 | lcov.info 12 | -------------------------------------------------------------------------------- /src/rtcomm/EndpointProvider/protocols/README.md: -------------------------------------------------------------------------------- 1 | You can rename files here to confirm load order. 1SubProtocol needs to be loaded first so Other protocol objects can be created. 2 | 3 | -------------------------------------------------------------------------------- /tests/support/testConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "mqttServers" : ["127.0.0.1:8080"], 3 | "useSSL": false, 4 | "managementTopicName" : "management", 5 | "rtcommTopicPath" : "/rtcomm/" 6 | } 7 | -------------------------------------------------------------------------------- /tests/functional/junk/sampletest.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'intern!object', 3 | 'intern/chai!assert', 4 | // 'app/hello' 5 | ], function (registerSuite, assert) { 6 | registerSuite({ 7 | name: 'hello', 8 | 9 | greet: function () { 10 | console.log('************ greet **************'); 11 | } 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /tests/functional/all_with_server.js: -------------------------------------------------------------------------------- 1 | var REQUIRE_RTCOMM_SERVER = true; 2 | define([ 3 | './connection/MqttConnection.js', 4 | './connection/EndpointConnection.js', 5 | './EndpointProvider.js', 6 | './PresenceMonitor.js', 7 | './RtcommEndpoint.js', 8 | './RtcommEndpoint.chat.js', 9 | './MqttEndpoint.js', 10 | './SessionQueue.js' 11 | ], function () {}); 12 | -------------------------------------------------------------------------------- /tests/functional/all.js: -------------------------------------------------------------------------------- 1 | define([ 2 | './connection/MqttConnection.js', 3 | './connection/EndpointConnection.js', 4 | './EndpointProvider.js', 5 | './PresenceMonitor.js', 6 | './RtcommEndpoint.js', 7 | './RtcommEndpoint.chat.js', 8 | './MqttEndpoint.js', 9 | './SessionEndpoint.js', 10 | './GenericMessageEndpoint.js', 11 | './SessionQueue.js' 12 | ], function() {}); 13 | -------------------------------------------------------------------------------- /src/rtcomm/util/RtcommError.js: -------------------------------------------------------------------------------- 1 | var RtcommError = function RtcommError(/*string*/ message, /*array*/ subs) { 2 | this.name = "RtcommError"; 3 | this.message = message || "RTCOMM: Default error message"; 4 | 5 | }; 6 | 7 | RtcommError.prototype = Object.create(Error.prototype); 8 | RtcommError.prototype.constructor = RtcommError; 9 | /*globals exports:false*/ 10 | exports.RtcommError = RtcommError; 11 | 12 | 13 | -------------------------------------------------------------------------------- /sample/resources/css/videoAdvanced.css: -------------------------------------------------------------------------------- 1 | .remoteView { 2 | position: relative; 3 | min-width: 320px; 4 | min-height: 160px; 5 | max-height: 100%; 6 | width:100%; 7 | z-index: 1; 8 | } 9 | 10 | #selfView { 11 | position: relative; 12 | padding:0px; 13 | width: 100%; 14 | max-width:100%; 15 | margin-right:auto; 16 | margin-left:auto; 17 | } 18 | 19 | .hidden { 20 | display: none 21 | } 22 | .show { 23 | display: block 24 | } 25 | -------------------------------------------------------------------------------- /tests/manual/old/scripts/main.js: -------------------------------------------------------------------------------- 1 | require(["ibmrtc/RtcService/RtcMessageUMD"], function(RtcMessage) { 2 | //This function is called when scripts/helper/util.js is loaded. 3 | //If util.js calls define(), then this function is not fired until 4 | //util's dependencies have loaded, and the util argument will hold 5 | //the module value for "helper/util". 6 | msg = new RtcMessage(); 7 | console.log(msg); 8 | 9 | }); 10 | -------------------------------------------------------------------------------- /tests/manual/old/dojoTutorial.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tutorial: Hello Dojo! 6 | 7 | 8 |

Hello

9 | 10 | 12 | 13 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/rtcomm/util/RtcommEvent.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 IBM Corp. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | var RtcommEvent = function RtcommEvent() { 17 | this.name = ""; 18 | this.message = ""; 19 | this.object = ""; 20 | }; 21 | -------------------------------------------------------------------------------- /tests/support/server.js: -------------------------------------------------------------------------------- 1 | // This script acts as an HTTP server in node.js, serving filesw/ the directory passed in. 2 | // 3 | 4 | var connect = require('connect'); 5 | var serveStatic = require('serve-static'); 6 | var util = require('util'); 7 | 8 | var defaultPort = 3000; 9 | var defaultDir = '.'; 10 | 11 | var app = connect(); 12 | var directory = ""; 13 | 14 | process.argv.forEach( function(val, index, array) { 15 | console.log(index + ":" + val); 16 | }); 17 | 18 | var directory = (typeof process.argv[2] !== 'undefined') ? process.argv[2] : defaultDir; 19 | var port = (typeof process.argv[3] !== 'undefined') ? process.argv[3] : defaultPort; 20 | 21 | console.log('Using Directory: '+ directory); 22 | console.log('Using port: '+ port); 23 | 24 | app.use(serveStatic(directory)); 25 | app.listen(port); 26 | 27 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rtcomm", 3 | "homepage": "https://github.com/WASdev/lib.rtcomm.clientjs", 4 | "version": "1.0.9", 5 | "authors": [ 6 | "Scott W Graham " 7 | ], 8 | "description": "RealTime Communications library implement WebRTC using MQTT for signaling", 9 | "main": "dist/rtcomm.js", 10 | "moduleType": [ 11 | "amd", 12 | "globals" 13 | ], 14 | "keywords": [ 15 | "rtcomm", 16 | "ibm", 17 | "webrtc", 18 | "mqtt" 19 | ], 20 | "license": "Apache-2.0", 21 | "ignore": [ 22 | "CONTRIBUTING.md", 23 | "dist/umd", 24 | "dist/jsdoc", 25 | "dist/release", 26 | "sample", 27 | "lib", 28 | "bin", 29 | "config", 30 | "src", 31 | "rtcomm.signaling.proto.spec.md", 32 | "Gruntfile.js", 33 | "**/.*", 34 | "build_resources", 35 | "node_modules", 36 | "persistence", 37 | "bower_components", 38 | "tests" 39 | ], 40 | "dependencies": { 41 | "bower-mqttws": "~1.0.0", 42 | "webrtc-adapter": "~0" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/rtcomm/EndpointProvider/endpoints/MessageEndpoint.js: -------------------------------------------------------------------------------- 1 | var MessageEndpoint = (function(config) { 2 | 3 | var MessageEndpoint = function MessageEndpoint(config) { 4 | 5 | function addGenericMessageHandlers(ep) { 6 | ep.createEvent('onetimemessage'); 7 | ep.createEvent('generic_message:message'); 8 | ep.generic_message.on('message', function(event_obj) { 9 | console.log('eventObject?', event_obj); 10 | // This shoudl be deprecated (onetimemessage) that is. 11 | var deprecatedEvent = { 12 | 'onetimemessage': event_obj.message 13 | }; 14 | ep.emit('onetimemessage', deprecatedEvent); 15 | ep.emit('generic_message:message', event_obj); 16 | }); 17 | }; 18 | SessionEndpoint.call(this, config); 19 | this.addProtocol(new GenericMessageProtocol()); 20 | addGenericMessageHandlers(this); 21 | // Enabled by default 22 | this.config.generic_message = true; 23 | this.generic_message.enable(); 24 | } 25 | 26 | MessageEndpoint.prototype = Object.create(SessionEndpoint.prototype); 27 | MessageEndpoint.prototype.constructor = MessageEndpoint; 28 | 29 | return MessageEndpoint; 30 | })(); 31 | -------------------------------------------------------------------------------- /src/rtcomm/EndpointProvider/ModuleGlobals.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 IBM Corp. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | // rtcservice & util should be defined here: 17 | /*jshint -W030*/ 18 | /*global util:false*/ 19 | var logging = new util.Log(), 20 | setLogLevel = logging.s, 21 | getLogLevel = logging.g, 22 | l = logging.l, 23 | generateUUID = util.generateUUID, 24 | generateRandomBytes = util.generateRandomBytes, 25 | validateConfig = util.validateConfig, 26 | applyConfig = util.applyConfig, 27 | setConfig = util.setConfig, 28 | /*global log: false */ 29 | log = logging.log; 30 | -------------------------------------------------------------------------------- /src/rtcomm/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 IBM Corp. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | /** 17 | * @module rtcomm 18 | * @requires {@link http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt.javascript.git/tree/src|mqttws31.js} 19 | * @requires {@link https://github.com/webrtc/adapter | webrtc-adapter.js} 20 | * 21 | */ 22 | /*global l:false*/ 23 | var rtcomm= (function rtcomm() { 24 | 25 | var Rtcomm = function Rtcomm() { 26 | this.EndpointProvider= EndpointProvider; 27 | this.connection= connection; 28 | this.util= util; 29 | }; 30 | Rtcomm.prototype = util.RtcommBaseObject.extend({}); 31 | return new Rtcomm(); 32 | })(); 33 | 34 | 35 | -------------------------------------------------------------------------------- /tests/manual/localTest.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebRTC rtcomm.* test 6 | 7 | 8 | --> 9 | 10 | 11 | 12 | 13 | 14 |

MOCK MQTT Testing

15 |
16 |

17 | 18 | 19 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lib.rtcomm.clientjs", 3 | "version": "1.0.9", 4 | "license": "Apache-2.0", 5 | "homepage": "https://github.com/WASdev/lib.rtcomm.clientjs", 6 | "authors": [ 7 | "Scott W Graham " 8 | ], 9 | "main": "dist/rtcomm.js", 10 | "private": true, 11 | "description": "RealTime Communications library implement WebRTC using MQTT for signaling", 12 | "repository": { 13 | "type": "git", 14 | "url": "http://github.com/WASdev/lib.rtcomm.clientjs.git" 15 | }, 16 | "scripts": { 17 | "test": "grunt test" 18 | }, 19 | "devDependencies": { 20 | "connect": "^3.4.0", 21 | "grunt": "^0.4.5", 22 | "grunt-contrib-clean": "^1.0.0", 23 | "grunt-contrib-compress": "^1.0.0", 24 | "grunt-contrib-concat": "^1.0.0", 25 | "grunt-contrib-jshint": "^1.0.0", 26 | "grunt-contrib-uglify": "^0.11.1", 27 | "grunt-contrib-watch": "^0.6.1", 28 | "grunt-jsdoc": "^1.0.0", 29 | "grunt-serve": "^0.1.6", 30 | "grunt-sg-release": "^1.0.0", 31 | "grunt-shell-spawn": "^0.3.10", 32 | "grunt-umd": "^2.3.5", 33 | "http": "0.0.0", 34 | "intern": "^3.0.6", 35 | "jshint-stylish": "^2.1.0", 36 | "load-grunt-tasks": "^3.4.0", 37 | "node-localstorage": "^1.1.2", 38 | "serve-static": "^1.10.2", 39 | "websocket": "^1.0.14" 40 | }, 41 | "dependencies": {} 42 | } 43 | -------------------------------------------------------------------------------- /tests/manual/pc_test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebRTC rtcomm.* test 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |

EndPoint Provider Testing

15 |
16 |

17 | 18 | 19 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /sample/resources/css/video.css: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | } 4 | 5 | body { 6 | height: 100%; 7 | width: 100%; 8 | background-color: #ccc; 9 | font-family: HelveticaNeue-Light, Arial, sans-serif; 10 | } 11 | 12 | .mainContentContainer { 13 | width: 100vw; 14 | height: 100vh; 15 | } 16 | 17 | #topContainer { 18 | position: absolute; 19 | top:0; 20 | left:0; 21 | width: 100%; 22 | height: 50px; 23 | background: #333; 24 | color: white; 25 | } 26 | #mainAlert { 27 | position: relative; 28 | top:50px; 29 | } 30 | 31 | #videoContainer { 32 | position: relative; 33 | top: 50px; 34 | width: 95%; 35 | height:90%; 36 | margin-left: auto; 37 | margin-right:auto; 38 | } 39 | 40 | .selfView { 41 | position:absolute; 42 | top: 3%; 43 | left: 75%; 44 | width: 20%; 45 | height:20%; 46 | padding:0px; 47 | z-index: 5; 48 | } 49 | .remoteView { 50 | position: relative; 51 | min-width: 320px; 52 | min-height: 160px; 53 | max-height: 100%; 54 | width:100%; 55 | z-index: 1; 56 | } 57 | 58 | .video-controls { 59 | position: absolute; 60 | padding-left: 25px; 61 | bottom: 0; 62 | left: 0; 63 | width: 100%; 64 | height: 50px; 65 | z-index: 5; 66 | background: #333; 67 | color: white; 68 | } 69 | 70 | .blue { 71 | padding: 0 3px; 72 | color: rgb(20,230,255); 73 | } 74 | .logo { padding-left: 25px; font-size: 28px; line-height: 50px; } 75 | -------------------------------------------------------------------------------- /tests/functional/junk/scott.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 IBM Corp. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | var config= {server: 'svt-msd1.rtp.raleigh.ibm.com', port: 1883, connectorTopicPath: '/rtcommfvt/' }; 18 | define([ 19 | 'intern!object', 20 | 'intern/chai!assert', 21 | // './mock/mqttws31_shim.js', 22 | // 'lib/mqttws31' 23 | ], function (registerSuite, assert) { 24 | if (typeof window === 'undefined' && global) { 25 | require(['intern/dojo/node!./tests_intern/mock/rtcomm_node'], function(globals) { 26 | console.log('globals returned: ', globals); 27 | }); 28 | } 29 | var ep = null; 30 | registerSuite({ 31 | name: 'hello', 32 | 'Paho exists': function () { 33 | console.log('************ Paho **************', Paho); 34 | console.log(typeof Paho); 35 | assert.isObject(Paho); 36 | } 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /tests/manual/old/NodeConnectorTest.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebRTC rtcomm.* test 6 | 7 | 8 | 9 | 10 | 11 |

Single NodeConnector web test.

12 |
13 |

14 | 15 | 16 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /tests/manual/old/RtcommTest.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebRTC rtcomm.* test 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Single web test of one RTCOMM service to another in same page.

13 |
14 |

This test runs locally, but uses the MQTT Server to pass an RTCOMM 'MESSAGE' (no channel or session involved.)

15 | 16 | 17 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /tests/manual/test1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebRTC rtcomm.* test 6 | 7 | 8 | 9 | 10 | 11 | 12 |

EndPoint Provider Testing

13 |
14 |

15 | 16 | 17 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | /*eslint-env node*/ 2 | 3 | //------------------------------------------------------------------------------ 4 | // Mosca app for node.js 5 | //------------------------------------------------------------------------------ 6 | // cfenv provides access to your Cloud Foundry environment 7 | // for more info, see: https://www.npmjs.com/package/cfenv 8 | var cfenv = require('cfenv'); 9 | var mosca = require('mosca'); 10 | var bunyan = require('bunyan'); 11 | 12 | var log = bunyan.createLogger({name: 'MqttServer', level: 'info'}); 13 | var port = cfenv.getAppEnv().port; 14 | var host = cfenv.getAppEnv().bind; 15 | 16 | // We are using Memory for peristence 17 | var settings = { 18 | persistence: { 19 | factory: mosca.persistence.Memory 20 | }, 21 | host: host, 22 | logger: {level: 'info'}, 23 | http: { 24 | port: port, 25 | static: './' 26 | }, 27 | }; 28 | 29 | var server = new mosca.Server(settings, function(error) { 30 | log.debug("Started on " + cfenv.getAppEnv().url + " message: " +error); 31 | }); 32 | 33 | server.on('clientConnected', function(client) { 34 | log.debug('client connected', client.id); 35 | }); 36 | 37 | // fired when a message is received 38 | server.on('published', function(packet, client) { 39 | //console.log('Published', packet); 40 | log.debug('Published', packet.payload.toString()); 41 | }); 42 | 43 | // fired when a message is received 44 | server.on('subscribed', function(topic, client) { 45 | log.debug('Subscribed: ' + topic + ' client:'+client); 46 | }); 47 | 48 | server.on('ready', setup); 49 | 50 | // fired when the mqtt server is ready 51 | function setup() { 52 | log.info('Mosca server is up and running'); 53 | } 54 | 55 | 56 | -------------------------------------------------------------------------------- /tests/manual/old/manualTest.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | body, html { 4 | width:100%; 5 | height:100%; 6 | margin:0; 7 | padding:0; 8 | overflow:hidden; 9 | font-family: Arial; 10 | } 11 | 12 | 13 | #eventLog { 14 | position: relative; 15 | width: 400px ; 16 | height: 200px ; 17 | margin-left: auto ; 18 | margin-right: auto ; 19 | 20 | } 21 | 22 | #securelogin { 23 | position: relative; 24 | top: 200px; 25 | width: 400px ; 26 | margin-left: auto ; 27 | margin-right: auto ; 28 | 29 | } 30 | 31 | 32 | 33 | 34 | 35 | .impact_background { 36 | background: transparent url(images/impact_swatch_small.png) center right; 37 | } 38 | 39 | .title { 40 | background: white; 41 | 42 | float: right; 43 | font-size: 3em; 44 | font-family: Arial; 45 | font-weight: bold; 46 | } 47 | 48 | .realmMember { 49 | font-size: 1em; 50 | font-family: Arial; 51 | 52 | } 53 | 54 | .active { 55 | color: greenyellow; 56 | padding-left: 20px; 57 | background: transparent url(images/mobile_video_pal16.gif) no-repeat center left; 58 | cursor: pointer; cursor: hand; 59 | } 60 | 61 | .self { 62 | color: gray; 63 | padding-left: 20px; 64 | } 65 | 66 | .login { 67 | font-size: 1em; 68 | border: 1px solid #d3d3d3; 69 | padding: 3px; 70 | width: 240px; 71 | 72 | } 73 | .session { 74 | font-size: 1em; 75 | border: 1px solid #d3d3d3; 76 | padding: 3px; 77 | width: 240px; 78 | } 79 | 80 | 81 | .login_text { 82 | width: 130px; 83 | white-space: nowrap; 84 | padding 0px 10px 0px 10px; 85 | } 86 | 87 | .login_status { 88 | font-size: .75em; 89 | text-align: center; 90 | font-style: italic; 91 | padding: 3px; 92 | } 93 | .login_button { 94 | display: inline; 95 | } -------------------------------------------------------------------------------- /tests/manual/old/junk.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Development IBMRTC Test Page 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Test 15 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /tests/rtcommTestTemplate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 IBM Corp. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | define([ 17 | 'intern', 18 | 'intern!object', 19 | 'intern/chai!assert', 20 | 'intern/node_modules/dojo/Promise', 21 | (typeof window === 'undefined' && global) 22 | ?'intern/dojo/node!../support/mqttws31_shim': 23 | 'bower_components/bower-mqttws/mqttws31', 24 | 'support/config', 25 | 'bower_components/webrtc-adapter/adapter', 26 | 'umd/rtcomm/EndpointProvider', 27 | 'support/rtcommFatUtils' 28 | ], function (intern, registerSuite, assert, Deferred, globals, config, adapter, EndpointProvider,Fat) { 29 | var suiteName = Fat.createSuiteName("FVT: SomeSuiteName"); 30 | var DEBUG = (intern.args.DEBUG === 'true')? true: false; 31 | 32 | registerSuite({ 33 | name: suiteName, 34 | setup: function() { 35 | console.log('****************** SETUP: '+this.name+' ***********************'); 36 | }, 37 | teardown: function() { 38 | console.log('****************** TearDown: '+this.name+'***********************'); 39 | }, 40 | beforeEach: function() { 41 | }, 42 | 'test name ': function() { 43 | console.log('***************************** '+this.name+' ***************************'); 44 | } 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /tests/unit/util/util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 IBM Corp. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | define([ 17 | 'intern!object', 18 | 'intern/chai!assert', 19 | 'umd/rtcomm/util' 20 | ], function (registerSuite, assert,util) { 21 | registerSuite({ 22 | name: "Unit Tests - util module", 23 | "Evented Object Test" : function(){ 24 | var Obj = function Obj() { 25 | this.events = 26 | { 'event1': [], 27 | 'event2': [] 28 | }; 29 | }; 30 | Obj.prototype = util.RtcommBaseObject.extend(); 31 | var o = new Obj(); 32 | var cb1 = false; 33 | var cb2 = false; 34 | var cb3 = false; 35 | 36 | o.on('event1', function(message) { 37 | console.log('callback 1 on event1 called'); 38 | cb1=true; 39 | }); 40 | 41 | o.on('event1', function(message) { 42 | console.log('callback 2 on event1 called'); 43 | cb3=true; 44 | }); 45 | 46 | o.on('event2', function(message) { 47 | console.log('callback 1 called on event2'); 48 | cb2=true; 49 | }); 50 | o.emit('event1'); 51 | o.emit('event2'); 52 | assert.ok(cb1); 53 | assert.ok(cb2); 54 | assert.ok(cb3); 55 | } 56 | }); // End of Tests 57 | }); 58 | -------------------------------------------------------------------------------- /src/rtcomm/EndpointProvider/protocols/ChatProtocol.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This is the implementation of a Chat Protocol. This sends and receives chat messages 3 | * The message is in form: {message: message, from: fromid} 4 | * 5 | */ 6 | 7 | /** 8 | * @memberof module:rtcomm.SubProtocol 9 | * 10 | * @description 11 | * A Chat is a connection from one peer to another to pass text back and forth 12 | * 13 | * @constructor 14 | * @extends module:rtcomm.SubProtocol 15 | */ 16 | 17 | var ChatProtocol = function ChatProtocol() { 18 | // Call superconstructor 19 | // Define the Protocol 20 | // 21 | function getStartMessage(callback) { 22 | l('DEBUG') && console.log(this + '.getStartMessage() entry'); 23 | callback && callback(true, this.createMessage.call(this, this.dependencies.parent.userid + ' has initiated a Chat with you')); 24 | } 25 | 26 | function getStopMessage(callback) { 27 | callback && callback(true, this.createMessage.call(this, this.dependencies.parent.userid + ' has left the chat')); 28 | } 29 | 30 | function constructMessage(message) { 31 | l('DEBUG') && console.log(this + '.constructMessage() MESSAGE: ', message); 32 | return { 33 | 'message': message, 34 | 'from': this.dependencies.parent.userid 35 | }; 36 | } 37 | 38 | function handleMessage(message) { 39 | l('DEBUG') && console.log(this + '.handleMessage() MESSAGE: ', message); 40 | var parent = this.dependencies.parent; 41 | // In chat, we emit messages no matter what. 42 | this.emit('message', message); 43 | } 44 | 45 | var protocolDefinition = { 46 | 'name': 'chat', 47 | 'getStartMessage': getStartMessage, 48 | 'getStopMessage': getStopMessage, 49 | 'constructMessage': constructMessage, 50 | 'handleMessage': handleMessage 51 | } 52 | 53 | SubProtocol.call(this, protocolDefinition); 54 | } 55 | ChatProtocol.prototype = Object.create(SubProtocol.prototype); 56 | ChatProtocol.prototype.constructor = ChatProtocol; 57 | -------------------------------------------------------------------------------- /tests/manual/old/scripts/junk.js: -------------------------------------------------------------------------------- 1 | /* 2 | * IBM Confidential 3 | * 4 | * OCO Source Materials 5 | * 6 | * WLP Copyright IBM Corp. 2014 7 | * 8 | * The source code for this program is not published or otherwise divested 9 | * of its trade secrets, irrespective of what has been deposited with the 10 | * U.S. Copyright Office. 11 | */ 12 | 13 | var Junk = (function invocation() { 14 | 15 | console.log("RTCIceCandidate", RTCIceCandidate); 16 | console.log("Setting RTCSessionDescription", RTCSessionDescription); 17 | 18 | 19 | 20 | var RTCPeerConnection_ibm = (function() { 21 | if (navigator.mozGetUserMedia) { 22 | return mozRTCPeerConnection; 23 | } else if (navigator.webkitGetUserMedia) { 24 | return webkitRTCPeerConnection; 25 | } else { 26 | throw new Error("Unsupported Browser"); 27 | } 28 | })(); 29 | 30 | var RTCSessionDescription_ibm = (function() { 31 | if (navigator.mozGetUserMedia) { 32 | return mozRTCSessionDescription; 33 | } 34 | console.log("Setting RTCSessionDescription", RTCSessionDescription); 35 | return RTCSessionDescription; 36 | })(); 37 | 38 | console.log("Setting RTCSessionDescription", RTCSessionDescription_ibm); 39 | 40 | console.log("RTCIceCandidate", RTCIceCandidate); 41 | // WHY IS THIS FAILING? 42 | var RTCIceCandidate_ibm = (function() { 43 | console.log("RTCIceCandidate", RTCIceCandidate); 44 | 45 | if (navigator.mozGetUserMedia) { 46 | return mozRTCIceCandidate; 47 | } else { 48 | return RTCIceCandidate; 49 | } 50 | })(); 51 | 52 | var getBrowser = function() { 53 | if (navigator.mozGetUserMedia) { 54 | // firefox 55 | return("firefox", parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10)); 56 | } else if (navigator.webkitGetUserMedia) { 57 | return("chrome", parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2], 10)); 58 | } else { 59 | return("Unknown","Unknown"); 60 | } 61 | }; 62 | 63 | })(); -------------------------------------------------------------------------------- /tests/manual/presenceUnit.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebRTC rtcomm.* test 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Presence EndPoints Provider Testing

13 |
14 |

15 | 16 | 17 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /tests/manual/presence100.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebRTC rtcomm.* test 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Create 100 Presence EndPoints Provider Testing

13 |
14 |

15 | 16 | 17 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/rtcomm/EndpointProvider/Queues.js: -------------------------------------------------------------------------------- 1 | var Queues = function Queues(availableQueues) { 2 | var Queue = function Queue(queue) { 3 | var self = this; 4 | Object.keys(queue).forEach(function(key){ 5 | queue.hasOwnProperty(key) && (self[key] = queue[key]); 6 | }); 7 | // fix the topic, make sure it has a # 8 | if (/#$/.test(queue.topic)) { 9 | this.topic = queue.topic; 10 | } else if (/\/$/.test(queue.topic)) { 11 | this.topic = queue.topic + "#"; 12 | } else { 13 | this.topic = queue.topic + "/#"; 14 | } 15 | // Augment the passed in queue. 16 | this.active= false; 17 | this.callback= null; 18 | this.paused= false; 19 | this.regex= null; 20 | this.autoPause = false; 21 | }; 22 | var queues = {}; 23 | 24 | this.add = function(availableQueues) { 25 | availableQueues.forEach( function(queue) { 26 | // Only overwrite a queue if it doesn't exist 27 | if(!queues.hasOwnProperty[queue.endpointID]) { 28 | queues[queue.endpointID] = new Queue(queue); 29 | } 30 | }); 31 | }; 32 | 33 | this.get = function(queueid) { 34 | return queues[queueid] || null; 35 | }; 36 | this.findByTopic = function(topic) { 37 | // Typically used on an inbound topic, will iterate through queue and return it. 38 | var matches = []; 39 | //console.log(Object.keys(queues)); 40 | Object.keys(queues).forEach(function(queue) { 41 | l('DEBUG') && console.log('Queues.findByTopic testing '+topic+' against regex: '+queues[queue].regex); 42 | queues[queue].regex && queues[queue].regex.test(topic) && matches.push(queues[queue]); 43 | }); 44 | if (matches.length === 1 ) { 45 | return matches[0]; 46 | } else { 47 | throw new Error('Multiple Queue matches for topic('+topic+')- should not be possible'); 48 | } 49 | }; 50 | this.all = function() { 51 | return queues; 52 | }; 53 | this.list = function(){ 54 | return Object.keys(queues); 55 | }; 56 | }; 57 | 58 | Queues.prototype.toString = function() { 59 | this.list(); 60 | }; 61 | -------------------------------------------------------------------------------- /docs/sample.md: -------------------------------------------------------------------------------- 1 | ##Quickstart with the Sample 2 | 3 | This references the simple sample which shows how to create a basic Video client. An Advanced client is also included `videoClient-adv.html` which shows how to use Chat and Presence. 4 | 5 | 1. Clone the repository: 6 | ``` 7 | git clone https://github.com/WASdev/lib.rtcomm.clientjs.git 8 | ``` 9 | 2. Install node.js and npm (http://nodejs.org/download/) 10 | 11 | 3. Install necessary dependencies via npm from the repository directory (assuming lib.rtcomm.clientjs) 12 | ``` 13 | lib.rtcomm.clientjs/ # npm install 14 | ``` 15 | 4. Install the grunt-cli (globally if not installed) 16 | ``` 17 | npm install -g grunt-cli 18 | ``` 19 | 5. Build the library: 20 | ``` 21 | grunt 22 | ``` 23 | 6. Install the Bower dependencies 24 | ``` 25 | bower install 26 | ``` 27 | 7. Install an MQTT Server (or use `messagesight.demos.ibm.com`) 28 | We are using 'Mosca' here -- you can also download an IBM MessageSight virtual appliance. 29 | ``` 30 | npm install mosca bunyan -g 31 | ``` 32 | 8. Edit the file 'WebContent/sample/videoClient.html'. Find the creation of the `providerConfig` object: 33 | 34 | ```javascript 35 | var providerConfig = { 36 | server: 'messagesight.demos.ibm.com', 37 | port: 1883, 38 | appContext: "videosample", 39 | rtcommTopicPath: "/rtcommVideoSample/", 40 | createEndpoint: true 41 | }; 42 | ``` 43 | Change this to match your MQTT Broker. If you are using the `messagesight.demos.ibm.com` server, *make sure your rtcommTopicPath is unique!* 44 | If you are using Mosca on a local machine, the configuration will look like: 45 | 46 | ```javascript 47 | var providerConfig = { 48 | server: 'localhost', 49 | port: 8080, 50 | appContext: "videosample", 51 | rtcommTopicPath: "/rtcommVideoSample/", 52 | createEndpoint: true 53 | }; 54 | ``` 55 | 9. Start Mosca (if using it) (from project lib.rtcomm.clientjs root) 56 | 57 | ``` 58 | mosca -v --http-port 8080 --http-static ./ | bunyan 59 | ``` 60 | 61 | 10. Access your page: http://localhost:8080/samples/videoClient.html 62 | -------------------------------------------------------------------------------- /tests/support/mqttws31_shim.js: -------------------------------------------------------------------------------- 1 | // File used for config of node.js to rtcomm and test it 2 | if (typeof window === 'undefined' && global) { 3 | console.log('************* It is Node.js, applying shim for mqttws31 ************************'); 4 | var window = global; 5 | var navigator = null; 6 | // Setup WebSocket for mqtt 7 | var WebSocketClient = require('websocket').client; 8 | var WebSocket = function(wsurl,protocol) { 9 | var ws = new WebSocketClient(); 10 | var connection; 11 | var obj = { 12 | send: function(msg) { 13 | var nodeBuf = new Buffer(new Uint8Array(msg)); 14 | connection.send(nodeBuf); 15 | }, 16 | get readyState() { return ws.readyState; } 17 | }; 18 | ws.binaryType = 'arraybuffer'; 19 | ws.on("connect", function(conn) { 20 | connection = conn; 21 | conn.on("error", function (error) { 22 | console.log("socket error ",error); 23 | if (obj.onerror) { 24 | obj.onerror(); 25 | } 26 | }); 27 | conn.on("close", function(reasonCode, description) { 28 | console.log("socket closed ",description); 29 | }) 30 | conn.on("message", function (message) { 31 | if (message.type === "binary") { 32 | if (obj.onmessage) { 33 | obj.onmessage({data:message.binaryData}); 34 | } 35 | } 36 | }); 37 | if (obj.onopen) { 38 | obj.onopen(); 39 | } 40 | }); 41 | ws.on('connectFailed', function(error) { 42 | console.log('Connect Error: ' + error.toString()); 43 | if (obj.onerror) { 44 | obj.onerror(error); 45 | } 46 | }); 47 | ws.connect(wsurl, protocol); 48 | return obj; 49 | } 50 | 51 | var LocalStorage = require('node-localstorage').LocalStorage; 52 | var localStorage = new LocalStorage('./persistence'); 53 | global.window = window; 54 | global.navigator = navigator; 55 | global.WebSocket = WebSocket; 56 | global.localStorage= localStorage; 57 | require('../../bower_components/bower-mqttws/mqttws31.js'); 58 | }; 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/rtcomm/EndpointProvider/protocols/GenericMessageProtocol.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @memberof module:rtcomm.SubProtocol 3 | * 4 | * @description 5 | * This is the implementation of a Generic Message protocol. You can send anything you want to 6 | * another endpoint at the other end of a session using this protocol. 7 | * 8 | * @constructor 9 | * @extends module:rtcomm.SubProtocol 10 | */ 11 | 12 | var GenericMessageProtocol= function GenericMessageProtocol(){ 13 | // Call superconstructor 14 | // Define the Protocol 15 | // 16 | function getStartMessage(callback) { 17 | l('DEBUG') && console.log(this+'.getStartMessage() entry'); 18 | callback && callback(true,null); 19 | } 20 | 21 | function getStopMessage(callback) { 22 | callback && callback(true, null); 23 | } 24 | 25 | function constructMessage(message) { 26 | l('DEBUG') && console.log(this+'.constructMessage() MESSAGE: ', message); 27 | return {'message': message} 28 | } 29 | 30 | function handleMessage(message) { 31 | l('DEBUG') && console.log(this+'.handleMessage() MESSAGE: ', message); 32 | var parent = this.dependencies.parent; 33 | if (this.state === 'connected') { 34 | this.emit('message', message); 35 | } else if (this.state === 'alerting') { 36 | // dropping message, not in a state to receive it. 37 | l('DEBUG') && console.log(this+ '.handleMessage() Dropping message -- unable to receive in alerting state'); 38 | } else { 39 | // If we aren't stopped, then we should pranswer it and alert. 40 | if (!parent.sessionStopped()) { 41 | // Parent should pranswer, not us... 42 | // parent._.activeSession && parent._.activeSession.pranswer(); 43 | this._setState('alerting', message); 44 | } 45 | } 46 | } 47 | var protocolDefinition = { 48 | 'name' : 'generic_message', 49 | 'getStartMessage': getStartMessage, 50 | 'getStopMessage' : getStopMessage, 51 | 'constructMessage':constructMessage, 52 | 'handleMessage': handleMessage 53 | }; 54 | SubProtocol.call(this, protocolDefinition); 55 | }; 56 | GenericMessageProtocol.prototype= Object.create(SubProtocol.prototype); 57 | GenericMessageProtocol.prototype.constructor = GenericMessageProtocol; 58 | -------------------------------------------------------------------------------- /tests/manual/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebRTC rtcomm.* test 6 | 7 | 8 | 9 | 10 | 11 | 12 |

EndPoint Provider Testing

13 |
14 |

15 | 16 | 17 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /tests/manual/sessioneptest.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebRTC session endpoint test 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |

EndPoint Provider Testing( Session Endpoint)

14 |
15 |

16 | 17 | 18 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /tests/manual/old/fancy.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | body, html { 4 | width:100%; 5 | height:100%; 6 | margin:0; 7 | padding:0; 8 | overflow:hidden; 9 | font-family: Arial; 10 | } 11 | 12 | fieldset { 13 | padding: 1em; 14 | font:80%/1 sans-serif; 15 | font-size: .75em; 16 | height: 75px; 17 | } 18 | 19 | label { 20 | width:25%; 21 | margin-right:0.5em; 22 | padding-top:0.2em; 23 | text-align:right; 24 | } 25 | 26 | #MainContainer { 27 | width: 700px; 28 | height: 640px; 29 | margin: 0 auto; 30 | 31 | 32 | } 33 | .fs { 34 | float: left; 35 | top: 3px; 36 | width:20%; 37 | } 38 | 39 | .subContainer { 40 | font-size: 1em; 41 | border: 1px solid #d3d3d3; 42 | padding: 3px; 43 | width: 95%; 44 | margin-left: auto ; 45 | margin-right: auto ; 46 | } 47 | 48 | 49 | .description { 50 | font-size: .75em; 51 | width: 80%; 52 | float: right; 53 | border: 1px solid; 54 | margin: 10px 0px; 55 | padding:15px 10px 15px 50px; 56 | background-repeat: no-repeat; 57 | background-position: 10px center; 58 | color: #00529B; 59 | background-color: #BDE5F8; 60 | } 61 | 62 | } 63 | 64 | #eventLog { 65 | position: relative; 66 | width: 100% ; 67 | height: 75px ; 68 | margin-left: auto ; 69 | margin-right: auto ; 70 | disabled: true; 71 | 72 | 73 | } 74 | 75 | .messageBox { 76 | font-size: .75em; 77 | border: 1px solid #d3d3d3; 78 | padding: 3px; 79 | height: 2em; 80 | } 81 | 82 | 83 | 84 | .impact_background { 85 | background: transparent url(images/impact_swatch_small.png) center right; 86 | } 87 | 88 | .title { 89 | background: lightgray; 90 | font-size: 1em; 91 | height: 1em; 92 | font-family: Arial; 93 | font-weight: bold; 94 | } 95 | 96 | .realmMember { 97 | font-size: 1em; 98 | font-family: Arial; 99 | 100 | } 101 | .failure { 102 | border: 1px solid red; 103 | 104 | } 105 | 106 | .success { 107 | border: 1px solid greenyellow; 108 | } 109 | 110 | .self { 111 | color: gray; 112 | padding-left: 20px; 113 | } 114 | 115 | .login { 116 | font-size: 1em; 117 | border: 1px solid #d3d3d3; 118 | padding: 3px; 119 | width: 240px; 120 | 121 | } 122 | .session { 123 | font-size: 1em; 124 | border: 1px solid #d3d3d3; 125 | padding: 3px; 126 | width: 240px; 127 | } 128 | 129 | 130 | .login_text { 131 | width: 130px; 132 | white-space: nowrap; 133 | padding 0px 10px 0px 10px; 134 | } 135 | 136 | .login_status { 137 | font-size: .75em; 138 | text-align: center; 139 | font-style: italic; 140 | padding: 3px; 141 | } 142 | .login_button { 143 | display: inline; 144 | } -------------------------------------------------------------------------------- /tests/functional/junk/iTest.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 IBM Corp. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | var config= {server: 'svt-msd1.rtp.raleigh.ibm.com', port: 1883, connectorTopicPath: '/rtcommfvt/' }; 18 | 19 | define([ 20 | 'intern!object', 21 | 'intern/chai!assert', 22 | 'intern/dojo/node!./mock/rtcomm_node', 23 | 'ibm/rtcomm' 24 | ], function (registerSuite, assert, globals, rtcomm) { 25 | var ep = null; 26 | 27 | registerSuite({ 28 | name: 'EndpointProvider Tests', 29 | setup: function() { 30 | ep = new rtcomm.RtcommEndpointProvider(); 31 | ep.setLogLevel('DEBUG'); 32 | }, 33 | teardown: function() { 34 | ep.destroy(); 35 | ep = null; 36 | }, 37 | 'init': function () { 38 | var dfd = this.async(5000); 39 | config.userid = 'scott'; 40 | config.register = true; 41 | var error; 42 | var finish = dfd.callback( function(obj) { 43 | assert.isTrue(obj.ready, "The endpointConnection is ready"); 44 | assert.isTrue(obj.registered, "The endpoint is registered"); 45 | assert.isTrue(obj.endpoint.registered, "The endpoint is registered"); 46 | 47 | assert.equal(1, Object.keys(ep.endpoints()).length, 'There is only one endpoint'); 48 | console.log('Callback called!'); 49 | }); 50 | try { 51 | console.log('INITIALIZING PROVIDER'); 52 | ep.init(config, 53 | function(object) { 54 | console.log('SUCCESS!!!!!!!!!!!!!!!!!',object); 55 | finish(object); 56 | }, function(e) { 57 | error = e 58 | }); 59 | } catch(e) { 60 | error=e; 61 | console.log(error); 62 | } 63 | 64 | // assert.equal(error.message, 'RtcommEndpointProvider initialization requires a minimum configuration: {"server":"string","port":"number","userid":"string"}'); 65 | }, 66 | 'createRtcommEndpoint': function() { 67 | var endpoint=ep.createRtcommEndpoint(); 68 | // console.log(endpoint); 69 | } 70 | 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | * Tests for the rtcomm clienjs project 2 | 3 | ** Configure the tests 4 | 5 | Access the file 'tests/support/testConfig.json': 6 | ``` 7 | { 8 | "mqttServers" : ["messagesight.demos.ibm.com:1883"], 9 | "managementTopicName" : "management", 10 | "rtcommTopicPath" : "/rtcomm/" 11 | } 12 | ``` 13 | 14 | Change the contents of this file to match the configuration of your liberty server. 15 | 16 | ** Running the tests 17 | 18 | 1. Setup the Prereqs: 19 | 20 | ``` 21 | # from the project directory lib.rtcomm.clientjs 22 | # Install prereqs (one time only) via the package.json devDependencies 23 | npm install -g grunt-cli 24 | npm install 25 | ``` 26 | 27 | 2. Build the library 28 | ``` 29 | grunt lite 30 | ``` 31 | 32 | These tests can be run in several ways: 33 | 34 | 1. Via a Browser: With an http server pointing at the project directory, access the link http://localhost:/node_modules/intern/client.html?config=tests/intern via a Browser. This will run the tests and display the results in the browser. 35 | 36 | If you have node.js installed, you can quickly launch a local browser to test: 37 | 38 | ``` 39 | # Launch the server 40 | grunt serve 41 | ``` 42 | Now you should be able to access http://localhost:9000/node_modules/intern/client.html?config=tests/intern 43 | 44 | 2. Via ** grunt **: 45 | 46 | ``` 47 | # Change to your project directory 48 | cd lib.rtcomm.clientjs 49 | # run the tests [ run them all] 50 | grunt test 51 | ``` 52 | 53 | * Additional Tests & options 54 | 55 | ** Run just the unit tests: 56 | ``` 57 | grunt intern:unit 58 | ``` 59 | ** Run just the functional tests: 60 | ``` 61 | grunt intern:fat 62 | ``` 63 | ** Run just the functional tests (with an rtcomm-1.0 server): 64 | ``` 65 | grunt intern:fat_with_server 66 | ``` 67 | ** Run the Stress Test: 68 | ``` 69 | grunt intern:stress 70 | ``` 71 | For the Stress test, you can also run it via the browser: 72 | 73 | http://localhost:9000/node_modules/intern/client.html?config=tests/intern&suites=tests/stress/stressTest 74 | 75 | At the end of the above, you can specify MAX_CONNS & duration as follows: 76 | 77 | http://localhost:9000/node_modules/intern/client.html?config=tests/intern&suites=tests/stress/stressTest&MAX_CONNS=50&duration=30000 78 | 79 | MAX_CONNS defaults to 50 80 | duration defaults to 20000 (20 Seconds) 81 | 82 | These can be configured by running intern as follows: 83 | 84 | ``` 85 | $ node_modules/intern/bin/intern-client.js config=tests/intern suites=tests/stress/stressTest MAX_CONNS=1 duration=10000 86 | ``` 87 | 88 | * Turning on Debug 89 | You can turn on debug logging for rtcomm for all tests when run from the command line or from the browser: 90 | 91 | http://localhost:9000/node_modules/intern/client.html?config=tests/intern&DEBUG=true 92 | 93 | ``` 94 | $ node_modules/intern/bin/intern-client.js config=tests/intern DEBUG=true 95 | ``` 96 | 97 | At the moment, I don't know how to do it via grunt 98 | 99 | 100 | -------------------------------------------------------------------------------- /src/rtcomm/util/Sound.js: -------------------------------------------------------------------------------- 1 | var Sound = (function invocation(url) { 2 | 3 | /* global AudioContext:false */ 4 | var context = null; 5 | 6 | if (typeof navigator !== 'undefined' && typeof window !== 'undefined') { 7 | window.AudioContext = window.AudioContext || window.webkitAudioContext; 8 | context = context || (window.AudioContext) ? new AudioContext(): null; 9 | } 10 | 11 | var Sound = function Sound(url) { 12 | if (!(this instanceof Sound)) { 13 | return new Sound(url); 14 | } 15 | this.context = context; 16 | this.url = url; 17 | this.buffer = null; 18 | this.loaded = false; 19 | this.playing = null; 20 | }; 21 | 22 | /* global l:false */ 23 | Sound.prototype = (function () { 24 | var load = function load(callback) { 25 | var self = this; 26 | if (self.url && self.context) { 27 | var request = new XMLHttpRequest(); 28 | request.open('GET', self.url, true); 29 | request.responseType= 'arraybuffer'; 30 | request.onload = function() { 31 | self.context.decodeAudioData(request.response, 32 | function(buffer) { 33 | l('DEBUG') && console.log('Sound: successfully loaded buffer '+ self.url); 34 | self.buffer = buffer; 35 | callback && callback(); 36 | }, 37 | function(error) { /* onError */ 38 | console.error('Unable to load the url: ', error); 39 | }); 40 | }; 41 | request.send(); 42 | } else { 43 | l('DEBUG') && console.log('Sound.play() Unsupported in this environment'); 44 | } 45 | return self; 46 | }; 47 | var play = function play() { 48 | var self = this; 49 | var _play = function _play() { 50 | if (self.context) { 51 | if (!self.playing) { 52 | var sound = self.context.createBufferSource(); 53 | sound.buffer = self.buffer; 54 | sound.connect(self.context.destination); 55 | sound.loop= true; 56 | sound.start(0); 57 | self.playing = sound; 58 | } else { 59 | l('DEBUG') && console.log('Sound.play() Already playing...'); 60 | } 61 | } else { 62 | l('DEBUG') && console.log('Sound.play() Unsupported in this environment'); 63 | } 64 | }; 65 | 66 | if (self.buffer) { 67 | _play(); 68 | } else { 69 | // Try again in 500 milliseconds 70 | l('DEBUG') && console.log('Sound: Unable to play, Load is not complete -- will try 1 time in .5 seconds:',self); 71 | setTimeout(_play, 500); 72 | } 73 | return self; 74 | }; 75 | 76 | var stop= function stop() { 77 | console.log('Sound.stop() stop called, are we playing?', this.playing); 78 | if (this.playing) { 79 | this.playing.stop(); 80 | this.playing = null; 81 | } else { 82 | console.log('Sound.stop() -- Nothing playing'); 83 | } 84 | return this; 85 | }; 86 | return { 87 | load: load, 88 | play: play, 89 | stop: stop 90 | }; 91 | })(); 92 | 93 | return Sound; 94 | })(); 95 | 96 | /*globals exports:false*/ 97 | exports.Sound= Sound; 98 | 99 | 100 | -------------------------------------------------------------------------------- /src/rtcomm/EndpointProvider/endpoints/MqttEndpoint.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014,2015 IBM Corp. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | /** 17 | * @memberof module:rtcomm 18 | * @description 19 | * This object should only be created with the {@link module:rtcomm.EndpointProvider#getMqttEndpoint|getRtcommEndpoint} function. 20 | *

21 | * The MqttEndpoint object provides an interface to directly subscribe and publish MQTT messages. 22 | * 23 | * @constructor 24 | * 25 | * @extends module:rtcomm.util.RtcommBaseObject 26 | */ 27 | var MqttEndpoint = function MqttEndpoint(config) { 28 | 29 | this.dependencies = { 30 | connection: null, 31 | }; 32 | /* Object storing subscriptions */ 33 | this.subscriptions = {}; 34 | this.dependencies.connection = config && config.connection; 35 | this.events = {'message': []}; 36 | }; 37 | /*global util:false*/ 38 | /*global: l:false*/ 39 | MqttEndpoint.prototype = util.RtcommBaseObject.extend( 40 | /** @lends module:rtcomm.MqttEndpoint.prototype */ 41 | { 42 | /** 43 | * subscribe to a topic 44 | * @param {string} topic - A string that represents an MQTT topic 45 | */ 46 | subscribe: function(topic) { 47 | // Add it 48 | this.subscriptions[topic] = null; 49 | var mqttEP = this; 50 | mqttEP.dependencies.connection.subscribe(topic, function(message) { 51 | l('DEBUG') && console.log('MqttEndpoint.subscribe() Received message['+message+'] on topic: '+topic); 52 | mqttEP.emit('message', message); 53 | }); 54 | }, 55 | 56 | /** 57 | * unsubscribe from a topic 58 | * @param {string} topic - A string that represents an MQTT topic 59 | */ 60 | unsubscribe: function(topic) { 61 | var mqttEP = this; 62 | if (this.subscriptions.hasOwnProperty(topic)) { 63 | delete this.subscriptions[topic]; 64 | mqttEP.dependencies.connection.unsubscribe(topic); 65 | } else { 66 | throw new Error("Topic not found:"+topic); 67 | } 68 | }, 69 | /** 70 | * publish a message to topic 71 | * @param {string} topic - A string that represents an MQTT topic 72 | * @param {string} message - a String that is a message to be published 73 | */ 74 | publish: function(topic,message) { 75 | this.dependencies.connection.publish(topic, message); 76 | }, 77 | /** 78 | * Destroy the MqttEndpoint 79 | */ 80 | destroy: function() { 81 | l('DEBUG') && console.log('Destroying mqtt(unsubscribing everything... '); 82 | var mqttEP = this; 83 | Object.keys(this.subscriptions).forEach( function(key) { 84 | mqttEP.unsubscribe(key); 85 | }); 86 | } 87 | }); 88 | -------------------------------------------------------------------------------- /tests/support/config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * IBM Confidential 3 | * 4 | * OCO Source Materials 5 | * 6 | * WLP Copyright IBM Corp. 2014 7 | * 8 | * The source code for this program is not published or otherwise divested 9 | * of its trade secrets, irrespective of what has been deposited with the 10 | * U.S. Copyright Office. 11 | */ 12 | define(['intern/node_modules/dojo/text!./testConfig.json'], function(testconfig) { 13 | var configdata = JSON.parse(testconfig); 14 | console.log('testconfig', configdata ); 15 | var mqArray = /(\S+)\:(\d+)/.exec(configdata.mqttServers[0]); 16 | var 17 | mqttServer= mqArray[1], 18 | mqttPort = parseInt(mqArray[2]), 19 | managementTopicName= configdata.managementTopicName, 20 | rtcommTopicPath= configdata.rtcommTopicPath; 21 | 22 | var generateRandomBytes = function(pattern) { 23 | var d = new Date().getTime(); 24 | var bytes = pattern.replace(/[xy]/g, function(c) { 25 | // Take the date + a random number times 16 (so it will be between 0 & 16), get modulus 26 | // we then get the remainder of dividing by 16 (modulus) and the | 0 converts to an integer. 27 | // r will be between 0 & 16 (0000 & 1111) 28 | var r = (d + Math.random()*16)%16 | 0; 29 | d = Math.floor(d/16); 30 | // if it is x, just return the random number (0 to 16) 31 | // if it is not x, then return a value between 8 & 16 (mainly to ctonrol values in a UUID); 32 | return (c==='x' ? r : (r&0x7|0x8)).toString(16); 33 | }); 34 | return bytes; 35 | }; 36 | 37 | // defined for case where we have don't have a server 38 | var alternateRtcommTopicPath = '/'+generateRandomBytes('xxxxxxxxxxxxxxxxxxx')+'/'; 39 | 40 | function randomID(pattern) { 41 | pattern = pattern || "xxxxxxxxxxxx"; 42 | var id = generateRandomBytes(pattern); 43 | return id+"@us.ibm.com"; 44 | }; 45 | return { 46 | // Not used yet... 47 | IBMRTC_TEST_TYPE: "normal", 48 | managementTopicName: managementTopicName, 49 | mqttServer : mqttServer, 50 | mqttPort : mqttPort, 51 | rtcommTopicPath: rtcommTopicPath, 52 | _ServerConfig : function(userid, Topic) { 53 | var config = { 54 | server: mqttServer, 55 | port: mqttPort, 56 | userid: userid || null, 57 | managementTopicName: Topic || managementTopicName, 58 | rtcommTopicPath:rtcommTopicPath 59 | }; 60 | // If REQUIRE_RTCOMM_SERVER is set globally, we will use its value. 61 | // The default is to NOT require a server in the library. 62 | // 63 | if (typeof REQUIRE_RTCOMM_SERVER !== 'undefined') { 64 | config.requireRtcommServer = REQUIRE_RTCOMM_SERVER; 65 | } 66 | // By default this should be false, we need to keep to a random topic we picked (vs. picking a new one for each instantiation) 67 | // 68 | if (!config.hasOwnProperty('requireRtcommServer') && !config.requireRtcommServer) { 69 | config.rtcommTopicPath = alternateRtcommTopicPath; 70 | } 71 | return config; 72 | }, 73 | clientConfig: function(pattern) { 74 | return new this._ServerConfig( 75 | randomID(pattern) 76 | ); 77 | }, 78 | 79 | clientConfig1 : function() { 80 | return new this._ServerConfig( 81 | randomID() 82 | ); 83 | }, 84 | 85 | clientConfig2 : function() { 86 | return new this._ServerConfig( 87 | randomID() 88 | ); 89 | } 90 | 91 | 92 | 93 | 94 | 95 | }; 96 | 97 | }); 98 | 99 | -------------------------------------------------------------------------------- /tests/intern.js: -------------------------------------------------------------------------------- 1 | // Learn more about configuring this file at . 2 | // These default settings work OK for most people. The options that *must* be changed below are the 3 | // packages, suites, excludeInstrumentation, and (if you want functional tests) functionalSuites. 4 | define({ 5 | // The port on which the instrumenting proxy will listen 6 | proxyPort: 9000, 7 | 8 | // A fully qualified URL to the Intern proxy 9 | proxyUrl: 'http://localhost:9000/', 10 | 11 | // Default desired capabilities for all environments. Individual capabilities can be overridden by any of the 12 | // specified browser environments in the `environments` array below as well. See 13 | // https://code.google.com/p/selenium/wiki/DesiredCapabilities for standard Selenium capabilities and 14 | // https://saucelabs.com/docs/additional-config#desired-capabilities for Sauce Labs capabilities. 15 | // Note that the `build` capability will be filled in with the current commit ID from the Travis CI environment 16 | // automatically 17 | capabilities: { 18 | 'selenium-version': '2.41.0' 19 | }, 20 | 21 | // Browsers to run integration testing against. Note that version numbers must be strings if used with Sauce 22 | // OnDemand. Options that will be permutated are browserName, version, platform, and platformVersion; any other 23 | // capabilities options specified for an environment will be copied as-is 24 | environments: [ 25 | { browserName: 'internet explorer', version: '11', platform: 'Windows 8.1' }, 26 | { browserName: 'internet explorer', version: '10', platform: 'Windows 8' }, 27 | { browserName: 'internet explorer', version: '9', platform: 'Windows 7' }, 28 | { browserName: 'firefox', version: '28', platform: [ 'OS X 10.9', 'Windows 7', 'Linux' ] }, 29 | { browserName: 'chrome', version: '34', platform: [ 'OS X 10.9', 'Windows 7', 'Linux' ] }, 30 | { browserName: 'safari', version: '6', platform: 'OS X 10.8' }, 31 | { browserName: 'safari', version: '7', platform: 'OS X 10.9' } 32 | ], 33 | 34 | // Maximum number of simultaneous integration tests that should be executed on the remote WebDriver service 35 | maxConcurrency: 3, 36 | 37 | // Name of the tunnel class to use for WebDriver tests 38 | tunnel: 'SauceLabsTunnel', 39 | 40 | // The desired AMD loader to use when running unit tests (client.html/client.js). Omit to use the default Dojo 41 | // loader 42 | //useLoader: { 43 | // 'host-node': 'dojo/dojo', 44 | // 'host-browser': 'node_modules/dojo/dojo.js' 45 | //}, 46 | //reporters: ['console','junit'], 47 | 48 | // Configuration options for the module loader; any AMD configuration options supported by the specified AMD loader 49 | // can be used here 50 | loaderOptions: { 51 | // Packages that should be registered with the loader in each testing environment 52 | 53 | packages: [ { name: 'umd', location: 'dist/umd'}, 54 | { name: 'unit', location: 'tests/unit'}, 55 | { name: 'functional', location: 'tests/functional'}, 56 | { name: 'mock', location: 'dist/mock'}, 57 | { name: 'support', location: 'tests/support'}], 58 | }, 59 | 60 | // Non-functional test suite(s) to run in each browser 61 | suites: [ 'unit/all.js', 62 | 'functional/all.js', 63 | // All with rtcomm server 64 | // 'functional/all_with_server.js', 65 | ], 66 | //suites: [ ], 67 | 68 | // Functional test suite(s) to run in each browser once non-functional tests are completed 69 | functionalSuites: [ /* 'myPackage/tests/functional' */ ], 70 | 71 | // A regular expression matching URLs to files that should not be included in code coverage analysis 72 | excludeInstrumentation: /^(?:tests|tests|node_modules|bower_components)\// 73 | }); 74 | -------------------------------------------------------------------------------- /sample/resources/css/rtcomm.css: -------------------------------------------------------------------------------- 1 | #endpointContainer { 2 | background-color: #ccc; 3 | border: 1px solid #428bca; 4 | border-radius: 4px; 5 | } 6 | 7 | /* Video window related css */ 8 | #videoContainer { 9 | width: 100%; 10 | height:100%; 11 | margin-left: auto; 12 | margin-right:auto; 13 | background-color: #ccc; 14 | } 15 | 16 | #selfViewContainer { 17 | position:absolute; 18 | top: 3%; 19 | left: 75%; 20 | width: 20%; 21 | height:20%; 22 | padding:0px; 23 | z-index: 5; 24 | } 25 | 26 | .selfView { 27 | width: 100%; 28 | height: 100%; 29 | } 30 | 31 | .remoteView { 32 | position: relative; 33 | min-width: 160px; 34 | min-height: 120px; 35 | max-height: 100%; 36 | width:100%; 37 | z-index: 1; 38 | } 39 | 40 | /* Chat related css */ 41 | .presence 42 | { 43 | list-style: none; 44 | margin: 0; 45 | padding: 0; 46 | } 47 | 48 | .presence li 49 | { 50 | margin-bottom: 10px; 51 | /*padding-bottom: 5px;*/ 52 | /*border-bottom: 1px dotted #B3A9A9;*/ 53 | } 54 | 55 | .presence li .presence-body p 56 | { 57 | margin: 0; 58 | color: #777777; 59 | } 60 | 61 | .panel-presence 62 | { 63 | margin: 0; 64 | height: 100%; 65 | border: 1px solid #428bca; 66 | border-radius: 4px; 67 | } 68 | 69 | .panel-presence-body 70 | { 71 | overflow-y: scroll; 72 | height: 350px; 73 | background-color: white; 74 | margin: 1; 75 | border-radius: 4px; 76 | } 77 | 78 | /* Chat related css */ 79 | .chat 80 | { 81 | list-style: none; 82 | margin: 0; 83 | padding: 0; 84 | } 85 | 86 | .chat li 87 | { 88 | margin-bottom: 10px; 89 | padding-bottom: 5px; 90 | border-bottom: 1px dotted #B3A9A9; 91 | } 92 | 93 | .chat li .chat-body p 94 | { 95 | margin: 0; 96 | color: #777777; 97 | } 98 | 99 | /*.slidedown .glyphicon, .chat .glyphicon*/ 100 | 101 | .panel 102 | { 103 | /*margin-right: 1px;*/ 104 | height: 100%; 105 | } 106 | 107 | .panel-body 108 | { 109 | overflow-y: scroll; 110 | height: 400px; 111 | /* height: 80%; */ 112 | background-color: white; 113 | margin: 5px; 114 | } 115 | 116 | .panel-footer 117 | { 118 | margin: 5px; 119 | } 120 | 121 | ::-webkit-scrollbar-track 122 | { 123 | -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); 124 | background-color: #F5F5F5; 125 | } 126 | 127 | ::-webkit-scrollbar 128 | { 129 | width: 12px; 130 | background-color: #F5F5F5; 131 | } 132 | 133 | ::-webkit-scrollbar-thumb 134 | { 135 | -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); 136 | background-color: #555; 137 | } 138 | 139 | .endpoint-controls { 140 | width: 100%; 141 | height: 54px; 142 | z-index: 5; 143 | background: #333; 144 | color: white; 145 | border-radius: 4px; 146 | } 147 | 148 | .endpoint-controls .glyphicon{ 149 | margin-right: 1px; 150 | } 151 | 152 | .session-manager-title { 153 | font-size: large; 154 | } 155 | 156 | .session-manager { 157 | width: 100%; 158 | height: 54px; 159 | z-index: 5; 160 | background: #333; 161 | color: white; 162 | } 163 | 164 | .session-manager-title { 165 | font-size: large; 166 | } 167 | 168 | .session-mgr-container{ 169 | border: 1px solid black; 170 | padding: 5px; 171 | } 172 | 173 | 174 | .queueContainer { 175 | padding-top: 2px; 176 | padding-bottom: 2px; 177 | padding-left: 2px; 178 | padding-right: 2px; 179 | } 180 | 181 | .nopadding-left { 182 | padding-left: 0 !important; 183 | margin-left: 0 !important; 184 | } 185 | 186 | .nopadding-right { 187 | padding-right: 0 !important; 188 | margin-right: 0 !important; 189 | } 190 | 191 | .vertical-stretch 192 | { 193 | top: 0; 194 | bottom: 0; 195 | } 196 | -------------------------------------------------------------------------------- /tests/functional/connection/MqttConnection.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 IBM Corp. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | define([ 17 | 'intern', 18 | 'intern!object', 19 | 'intern/chai!assert', 20 | (typeof window === 'undefined' && global) 21 | ?'intern/dojo/node!../../support/mqttws31_shim': 22 | 'bower_components/bower-mqttws/mqttws31', 23 | 'support/config', 24 | 'umd/rtcomm/connection' 25 | ], function (intern, registerSuite, assert, globals, config, connection) { 26 | 27 | var DEBUG = (intern.args.DEBUG === 'true')? true: false; 28 | // MQTT ServerConfig 29 | // client1 Config 30 | var config1 = config.clientConfig1(); 31 | delete config1.managementTopicName; 32 | delete config1.userid; 33 | delete config1.requireRtcommServer; 34 | // client2 Config 35 | var config2 = config.clientConfig2(); 36 | delete config2.managementTopicName; 37 | delete config2.userid; 38 | delete config2.requireRtcommServer; 39 | 40 | var client1 = null; 41 | var client2 = null; 42 | console.log('CONFIG 1', config1); 43 | console.log('CONFIG 2', config2); 44 | 45 | var T1 = 5000; // How long we wait to setup, before sending messages. 46 | var T2 = T1 + 2000; // How long we wait to check results 47 | var T3 = T2 +2000; // How long we wait to timeout test. 48 | 49 | registerSuite({ 50 | name: "FVT - connection/MqttConnection", 51 | setup: function() { 52 | var p = new Promise( 53 | function(resolve, reject) { 54 | client1 = new connection.MqttConnection(config1); 55 | client2 = new connection.MqttConnection(config2); 56 | DEBUG && client1.setLogLevel('DEBUG'); 57 | DEBUG && client2.setLogLevel('DEBUG'); 58 | client1.connect({ 59 | onSuccess: function(){ 60 | client2.connect({ 61 | onSuccess: function() { 62 | resolve(); 63 | }, 64 | onFailure: function(error) { 65 | reject(error); 66 | } 67 | }); 68 | }, 69 | onFailure: function(error) { 70 | dfd.reject(error); 71 | } 72 | }); 73 | }); 74 | return p; 75 | }, 76 | teardown: function() { 77 | client1.destroy(); 78 | client1 = null; 79 | client2.destroy(); 80 | client2 = null; 81 | }, 82 | "Send and Receive a Simple Message via the EndpointConnection [without rtcomm]" : function() { 83 | var dfd = this.async(T1); 84 | var message1, message2 = null; 85 | var finish = dfd.callback(function(message){ 86 | assert.ok(message); 87 | assert.equal(msgToSend2.toString(), message.content.toString()); 88 | }); 89 | client1.on('message',finish); 90 | var msgToSend2 = "Hello from client2"; 91 | // Wait 2 seconds to ensure client is appropriately created, send the message 92 | client2.send({message: msgToSend2, toTopic: client1.config.myTopic}, 1000); 93 | } 94 | }); // End of Tests 95 | }); 96 | -------------------------------------------------------------------------------- /tests/intern_stress.js: -------------------------------------------------------------------------------- 1 | // Learn more about configuring this file at . 2 | // These default settings work OK for most people. The options that *must* be changed below are the 3 | // packages, suites, excludeInstrumentation, and (if you want functional tests) functionalSuites. 4 | define({ 5 | // The port on which the instrumenting proxy will listen 6 | proxyPort: 9000, 7 | 8 | // A fully qualified URL to the Intern proxy 9 | proxyUrl: 'http://localhost:9000/', 10 | 11 | // Default desired capabilities for all environments. Individual capabilities can be overridden by any of the 12 | // specified browser environments in the `environments` array below as well. See 13 | // https://code.google.com/p/selenium/wiki/DesiredCapabilities for standard Selenium capabilities and 14 | // https://saucelabs.com/docs/additional-config#desired-capabilities for Sauce Labs capabilities. 15 | // Note that the `build` capability will be filled in with the current commit ID from the Travis CI environment 16 | // automatically 17 | capabilities: { 18 | 'selenium-version': '2.41.0' 19 | }, 20 | 21 | // Browsers to run integration testing against. Note that version numbers must be strings if used with Sauce 22 | // OnDemand. Options that will be permutated are browserName, version, platform, and platformVersion; any other 23 | // capabilities options specified for an environment will be copied as-is 24 | environments: [ 25 | { browserName: 'internet explorer', version: '11', platform: 'Windows 8.1' }, 26 | { browserName: 'internet explorer', version: '10', platform: 'Windows 8' }, 27 | { browserName: 'internet explorer', version: '9', platform: 'Windows 7' }, 28 | { browserName: 'firefox', version: '28', platform: [ 'OS X 10.9', 'Windows 7', 'Linux' ] }, 29 | { browserName: 'chrome', version: '34', platform: [ 'OS X 10.9', 'Windows 7', 'Linux' ] }, 30 | { browserName: 'safari', version: '6', platform: 'OS X 10.8' }, 31 | { browserName: 'safari', version: '7', platform: 'OS X 10.9' } 32 | ], 33 | 34 | // Maximum number of simultaneous integration tests that should be executed on the remote WebDriver service 35 | maxConcurrency: 3, 36 | 37 | // Name of the tunnel class to use for WebDriver tests 38 | tunnel: 'SauceLabsTunnel', 39 | 40 | // The desired AMD loader to use when running unit tests (client.html/client.js). Omit to use the default Dojo 41 | // loader 42 | //useLoader: { 43 | // 'host-node': 'dojo/dojo', 44 | // 'host-browser': 'node_modules/dojo/dojo.js' 45 | //}, 46 | //reporters: ['console','junit'], 47 | 48 | // Configuration options for the module loader; any AMD configuration options supported by the specified AMD loader 49 | // can be used here 50 | loader: { 51 | // Packages that should be registered with the loader in each testing environment 52 | packages: [ { name: 'umd', location: 'dist/umd'}, 53 | { name: 'unit', location: 'tests/unit'}, 54 | { name: 'stress', location: 'tests/stress'}, 55 | { name: 'functional', location: 'tests/functional'}, 56 | { name: 'mock', location: 'dist/mock'}, 57 | { name: 'support', location: 'tests/support'}], 58 | shim: { 59 | 'lib/mqttws31': { 60 | exports: 'Paho' 61 | }, 62 | 'mock/mockMqtt': { 63 | exports: 'Paho' 64 | } 65 | } 66 | }, 67 | 68 | // Non-functional test suite(s) to run in each browser 69 | suites: [ 'stress/stressTest.js', 70 | ], 71 | //suites: [ ], 72 | 73 | // Functional test suite(s) to run in each browser once non-functional tests are completed 74 | functionalSuites: [ /* 'myPackage/tests/functional' */ ], 75 | 76 | // A regular expression matching URLs to files that should not be included in code coverage analysis 77 | excludeInstrumentation: /^(?:tests|tests|node_modules)\// 78 | }); 79 | -------------------------------------------------------------------------------- /tests/intern_local.js: -------------------------------------------------------------------------------- 1 | // Learn more about configuring this file at . 2 | // These default settings work OK for most people. The options that *must* be changed below are the 3 | // packages, suites, excludeInstrumentation, and (if you want functional tests) functionalSuites. 4 | define({ 5 | // The port on which the instrumenting proxy will listen 6 | proxyPort: 9000, 7 | 8 | // A fully qualified URL to the Intern proxy 9 | proxyUrl: 'http://localhost:9000/', 10 | 11 | // Default desired capabilities for all environments. Individual capabilities can be overridden by any of the 12 | // specified browser environments in the `environments` array below as well. See 13 | // https://code.google.com/p/selenium/wiki/DesiredCapabilities for standard Selenium capabilities and 14 | // https://saucelabs.com/docs/additional-config#desired-capabilities for Sauce Labs capabilities. 15 | // Note that the `build` capability will be filled in with the current commit ID from the Travis CI environment 16 | // automatically 17 | capabilities: { 18 | 'selenium-version': '2.41.0' 19 | }, 20 | 21 | // Browsers to run integration testing against. Note that version numbers must be strings if used with Sauce 22 | // OnDemand. Options that will be permutated are browserName, version, platform, and platformVersion; any other 23 | // capabilities options specified for an environment will be copied as-is 24 | environments: [ 25 | { browserName: 'internet explorer', version: '11', platform: 'Windows 8.1' }, 26 | { browserName: 'internet explorer', version: '10', platform: 'Windows 8' }, 27 | { browserName: 'internet explorer', version: '9', platform: 'Windows 7' }, 28 | { browserName: 'firefox', version: '28', platform: [ 'OS X 10.9', 'Windows 7', 'Linux' ] }, 29 | { browserName: 'chrome', version: '34', platform: [ 'OS X 10.9', 'Windows 7', 'Linux' ] }, 30 | { browserName: 'safari', version: '6', platform: 'OS X 10.8' }, 31 | { browserName: 'safari', version: '7', platform: 'OS X 10.9' } 32 | ], 33 | 34 | // Maximum number of simultaneous integration tests that should be executed on the remote WebDriver service 35 | maxConcurrency: 3, 36 | 37 | // Name of the tunnel class to use for WebDriver tests 38 | tunnel: 'SauceLabsTunnel', 39 | 40 | // The desired AMD loader to use when running unit tests (client.html/client.js). Omit to use the default Dojo 41 | // loader 42 | //useLoader: { 43 | // 'host-node': 'dojo/dojo', 44 | // 'host-browser': 'node_modules/dojo/dojo.js' 45 | //}, 46 | //reporters: ['console','junit'], 47 | 48 | // Configuration options for the module loader; any AMD configuration options supported by the specified AMD loader 49 | // can be used here 50 | loader: { 51 | // Packages that should be registered with the loader in each testing environment 52 | packages: [ { name: 'umd', location: 'dist/umd'}, 53 | { name: 'unit', location: 'tests/unit'}, 54 | { name: 'functional', location: 'tests/functional'}, 55 | {name : 'mock', location: 'dist/mock'}, 56 | { name: 'support', location: 'tests/support'}], 57 | map: { 58 | '*' : { 'lib/mqttws31' : 'mock/mockMqtt'} 59 | }, 60 | shim: { 'mock/mockMqtt': { 61 | exports: 'Paho' 62 | } 63 | } 64 | }, 65 | 66 | // Non-functional test suite(s) to run in each browser 67 | suites: [ 'unit/connection/connection.js', 68 | 'unit/util/util.js', 69 | 'unit/EndpointProvider.js', 70 | 'functional/connection/MqttConnection.js', 71 | 'functional/connection/EndpointConnection.js', 72 | 'functional/EndpointProvider.js', 73 | 'functional/RtcommEndpoint.js', 74 | 'functional/RtcommEndpoint.chat.js', 75 | 'functional/MqttEndpoint.js', 76 | 'functional/SessionQueue.js' 77 | ], 78 | //suites: [ ], 79 | 80 | // Functional test suite(s) to run in each browser once non-functional tests are completed 81 | functionalSuites: [ /* 'myPackage/tests/functional' */ ], 82 | 83 | // A regular expression matching URLs to files that should not be included in code coverage analysis 84 | excludeInstrumentation: /^(?:tests|tests|node_modules)\// 85 | }); 86 | -------------------------------------------------------------------------------- /docs/rtcomm_and_liberty_setup.md: -------------------------------------------------------------------------------- 1 | #lib.rtcomm.clientjs and Liberty 2 | 3 | The rtcomm.js library is a JavaScript Universal Module Description(UMD) formatted module that provides an API for client side web application developers to enable WebRTC functionality. This module handles signaling and creation of WebRTC PeerConnections between endpoints in a simple and flexible way. This library can utilize the 'rtcomm-1.0' feature in WebSphere Liberty Profile server for advanced funtionality. 4 | 5 | ##Requirements 6 | 7 | 1. An MQTT Server such as [IBM MessageSite](https://developer.ibm.com/messaging/messagesight/) or [Mosca](https://github/mcollina/mosca). For prototyping and development, it is possible to use `messagesight.demos.ibm.com`. 8 | 2. A web browsers that support WebRTC (tested w/ Chrome and Firefox) 9 | 3. A Liberty Profile server that runs with the `rtcomm-1.0` feature enabled. 10 | 1. Grab Liberty https://developer.ibm.com/wasdev/downloads/liberty-profile-using-non-eclipse-environments/ 11 | 2. Make sure you install rtcomm-1.0: 12 | ``` 13 | bin/installUtility install rtcomm-1.0 14 | ``` 15 | 16 | ##Dependencies 17 | 18 | The rtcomm.js library is dependent on the following libraries (which will be installed via bower). If you do not use bower, then you can get the files in the links below: 19 | 20 | 1. Paho MQTT JavaScript client [link](http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt.javascript.git/tree/src/mqttws31.js) 21 | 2. WebRTC Adapter [link] (https://github.com/webrtc/adapter) 22 | 23 | 24 | ##Installation 25 | 26 | ###Bower 27 | 28 | 'rtcomm' is now a registered bower module and can be installed using bower. 29 | ``` 30 | bower install rtcomm 31 | ``` 32 | This will handle installing the `mqttws31` and `webrtc-adapter` dependencies as well as the rtcomm library. Once installed, the scripts still need to be loaded in the application html file based on where bower installed the libraries. 33 | 34 | ### Inclusion in Browser 35 | 36 | Add the following you your html file: 37 | 38 | ```html 39 | 40 | 41 | 42 | ``` 43 | 44 | ##Quickstart with the Sample 45 | 46 | This references the simple sample which shows how to create a basic Video client. An Advanced client is also included `videoClient-adv.html` which shows how to use Chat and Presence. 47 | 48 | ###Using a WAR file sample videoClient and Bower 49 | 50 | Given the directory structure: 51 | ``` 52 | WebContent/ 53 | /WEB-INF/ 54 | /META-INF/ 55 | ``` 56 | 57 | Download the latest 'lib.rtcomm.clientjs-sample-.zip' from this [link](https://github.com/WASdev/lib.rtcomm.clientjs/releases/latest) This library contains the sample and API documentation. 58 | 59 | Unzip the file into your WebContent directory: 60 | 61 | ``` 62 | cd WebContent 63 | unzip .zip> 64 | ``` 65 | 66 | The WebContent directory should look like: 67 | 68 | ``` 69 | WebContent/ 70 | /WEB-INF/ 71 | /META-INF/ 72 | /jsdocs/ 73 | /dist/ 74 | /sample/ 75 | bower.json 76 | index.html 77 | ``` 78 | 79 | Install the dependencies with Bower (from the WebContent directory): 80 | 81 | ``` 82 | $ bower install 83 | ``` 84 | 85 | Edit the file 'WebContent/sample/videoClient.html'. Find the creation of the `providerConfig` object: 86 | ```javascript 87 | var providerConfig = { 88 | server: 'messagesight.demos.ibm.com', 89 | port: 1883, 90 | appContext: "videosample", 91 | rtcommTopicPath: "/rtcommVideoSample/", 92 | createEndpoint: true 93 | }; 94 | ``` 95 | The above are the defaults and need to be changed to match the rtcomm-1.0 feature configuration in the server.xml for the liberty profile server you are using. This is documented [here](http://www-01.ibm.com/support/knowledgecenter/was_beta_liberty/com.ibm.websphere.wlp.nd.multiplatform.doc/ae/twlp_config_rtcomm.html) 96 | 97 | Once the above configuration has been changed, you should be able to DEPLOY your WAR file to the Liberty Server. You can either place the WAR file in the **dropins** directory for your server or configure it in the server.xml and place it in the **apps** directory. 98 | 99 | Access your server url and the 'index.html' page should be displayed with links to the sample Client you have configured and the documentation for the library. 100 | -------------------------------------------------------------------------------- /tests/functional/PresenceMonitor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 IBM Corp. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | define([ 17 | 'intern', 18 | 'intern!object', 19 | 'intern/chai!assert', 20 | /* Use the Mock (in browser mqtt) */ 21 | (typeof window === 'undefined' && global) 22 | ?'intern/dojo/node!../support/mqttws31_shim': 23 | 'bower_components/bower-mqttws/mqttws31', 24 | 'support/config', 25 | 'bower_components/webrtc-adapter/adapter', 26 | 'umd/rtcomm/EndpointProvider', 27 | 'support/rtcommFatUtils' 28 | ], function (intern, registerSuite, assert, globals, config, adapter, EndpointProvider,Fat) { 29 | var suiteName = Fat.createSuiteName("FVT: PresenceMonitor"); 30 | var DEBUG = (intern.args.DEBUG === 'true')? true: false; 31 | /* 32 | * Create a Mock message, needs to look like: 33 | * {topic: where the message was received, 34 | * content: a DOCUMENT message 35 | * fromEndpointID: .... 36 | * 37 | */ 38 | var cfg = config.clientConfig(); 39 | var createPresenceMessage = function(id) { 40 | /* 41 | * rtcommVer: "v1.0.0", 42 | * method: "DOCUMENT", fromTopic: null, 43 | * type: "ENDPOINT", 44 | * addressTopic: "/rtcomm-scottgraham/QOU0S5O0QKA7X3ENVHKXAK" 45 | * alias: null 46 | * appContext: "default" 47 | * fromEndpointID: "scott123" 48 | * fromTopic: null 49 | * method: "DOCUMENT" 50 | * rtcommVer: "v1.0.0"state: "available"type: "ENDPOINT"userDefines: Array[0]__proto__: Object 51 | */ 52 | var DOCUMENT = { 53 | 'rtcommVer': 'v1.0.0', 54 | 'method': 'DOCUMENT', 55 | 'type': 'ENDPOINT', 56 | 'addressTopic':null, 57 | 'appContext':null, 58 | 'state': 'available', 59 | 'alias': null, 60 | 'userDefines':[] 61 | }; 62 | var rootTopic = cfg.rtcommTopicPath; 63 | DOCUMENT.appContext = 'interntest'; 64 | DOCUMENT.addressTopic = rootTopic + 'clients/'+ id; 65 | 66 | return { 67 | topic: rootTopic + "sphere/default/" + id, 68 | content: DOCUMENT, 69 | } 70 | }; 71 | 72 | var endpointProvider = null; 73 | var mockLength = 10; 74 | var presenceMonitor = null; 75 | 76 | registerSuite({ 77 | name: suiteName, 78 | beforeEach: function() { 79 | }, 80 | setup: function() { 81 | console.log('******** '+this.name+ ' *********'); 82 | var p = new Promise( 83 | function(resolve, reject) { 84 | Fat.createProvider(cfg).then( 85 | function(EP) { 86 | endpointProvider = EP; 87 | setTimeout(resolve,1000); 88 | }) 89 | .catch(function(reason) { 90 | reject(reason); 91 | }); 92 | }); 93 | return p; 94 | }, 95 | teardown: function() { 96 | console.log('******** TEARDOWN: '+this.name+ ' *********'); 97 | endpointProvider.destroy(); 98 | }, 99 | "Load and validate PresenceMonitor data": function() { 100 | console.log('******** '+this.name+ ' *********'); 101 | presenceMonitor = endpointProvider.getPresenceMonitor(); 102 | var mockData = []; 103 | for (var i=0;i PresenceMonitor", presenceMonitor); 110 | // Always use the 0 data... 111 | var data = presenceMonitor.getPresenceData()[0]; 112 | var f = data.flatten(); 113 | // We should have our OWN record plus the loaded mock data (mockLength+1); 114 | assert.equal(f.length, mockLength+1, 'loaded data correctly'); 115 | }, 116 | "findNodeByName": function() { 117 | console.log('******** '+this.name+ ' *********'); 118 | var data=presenceMonitor.getPresenceData()[0]; 119 | console.log('data is?', data); 120 | 121 | var node = data.findNodeByName('mockid-1'); 122 | assert.isObject(node, 'Found a PresenceNode Object'); 123 | assert.equal(node.name, 'mockid-1', 'Found CORRECT PresenceNode Object'); 124 | } 125 | }); 126 | }); 127 | -------------------------------------------------------------------------------- /src/rtcomm/connection/ModuleGlobals.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 IBM Corp. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | // rtcservice & util should be defined here: 17 | /*jshint -W030*/ 18 | /*global util:false*/ 19 | 20 | var exports = {}; 21 | var connection = exports; 22 | 23 | var logging = new util.Log(), 24 | setLogLevel = logging.s, 25 | getLogLevel = logging.g, 26 | l = logging.l, 27 | generateUUID = util.generateUUID, 28 | generateRandomBytes= util.generateRandomBytes, 29 | validateConfig = util.validateConfig, 30 | applyConfig = util.applyConfig, 31 | setConfig = util.setConfig, 32 | /*global log: false */ 33 | log = function log() { 34 | // I want to log CallingObject[id].method Message [possibly an object] 35 | 36 | var object = {}, 37 | method = '', 38 | message = null, 39 | remainder = null, 40 | logMessage = ""; 41 | 42 | var args = [].slice.call(arguments); 43 | 44 | if (args.length === 0 ) { 45 | return; 46 | } else if (args.length === 1 ) { 47 | // Just a Message, log it... 48 | message = args[0]; 49 | } else if (args.length === 2) { 50 | object = args[0]; 51 | message = args[1]; 52 | } else if (args.length === 3 ) { 53 | object = args[0]; 54 | method = args[1]; 55 | message = args[2]; 56 | } else { 57 | object = args.shift(); 58 | method = args.shift(); 59 | message = args.shift(); 60 | remainder = args; 61 | } 62 | 63 | if (object) { 64 | logMessage = object.toString() + "." + method + ' ' + message; 65 | } else { 66 | logMessage = "" + "." + method + ' ' + message; 67 | } 68 | // Ignore Colors... 69 | if (object && object.color) {object.color = null;} 70 | 71 | var css = ""; 72 | if (object && object.color) { 73 | logMessage = '%c ' + logMessage; 74 | css = 'color: ' + object.color; 75 | if (remainder) { 76 | l('TRACE') && console.log(logMessage, css, remainder); 77 | } else { 78 | l('TRACE') && console.log(logMessage,css); 79 | } 80 | } else { 81 | if (remainder) { 82 | l('TRACE') && console.log(logMessage, remainder); 83 | } else { 84 | l('TRACE') && console.log(logMessage); 85 | } 86 | } 87 | }; // end of log/ 88 | var uidRoute = function(userid) { 89 | l('TRACE') && console.log('uidRoute called w/ id '+userid); 90 | var returnObj = { 91 | route:null , 92 | userid: null 93 | }; 94 | // Matches a WORD for the route and a NON-SPACE for the userid 95 | var r = new RegExp(/(\w+)\:(\S+)/); 96 | var a = r.exec(userid); 97 | if (a) { 98 | if (a.length === 3) { 99 | // We matched correctly 100 | returnObj.route= a[1]; 101 | returnObj.userid = a[2]; 102 | } else { 103 | throw new Error('Unable to process userid: '+ userid); 104 | } 105 | } else { 106 | returnObj.userid = a; 107 | } 108 | l('TRACE') && console.log('uidRoute returning ',returnObj); 109 | return returnObj; 110 | }; 111 | 112 | var routeLookup = function(services, scheme) { 113 | // should be something like [sips, sip, tel ] for the SIP CONNECTOR SERVICE 114 | l('TRACE') && console.log('routeLookup() finding scheme: '+scheme); 115 | var topic = null; 116 | for(var key in services) { 117 | l('TRACE') && console.log('routeLookup() searching key: '+key); 118 | if (services.hasOwnProperty(key)){ 119 | l('TRACE') && console.log('routeLookup() searching key: ',services[key]); 120 | if (typeof services[key].schemes !== 'undefined' && 121 | typeof services[key].topic !== 'undefined') { 122 | if (services[key].schemes.indexOf(scheme) >= 0) { 123 | topic = services[key].topic; 124 | break; 125 | } 126 | } 127 | } 128 | } 129 | l('TRACE') && console.log('routeLookup() returing topic: '+topic); 130 | return topic; 131 | }; 132 | -------------------------------------------------------------------------------- /tests/support/rtcommFatUtils.js: -------------------------------------------------------------------------------- 1 | define([ 2 | (typeof window === 'undefined' && global) ?'intern/dojo/node!../support/mqttws31_shim': 'bower_components/bower-mqttws/mqttws31', 3 | 'support/config', 4 | 'bower_components/webrtc-adapter/adapter', 5 | 'umd/rtcomm/EndpointProvider' 6 | ], function ( globals, config, adapter, EndpointProvider) { 7 | /* 8 | * create an Endpoint Provider and init it in a promise-like fashion 9 | * Passes endpoint provider into promise; 10 | */ 11 | var createProvider = function createProvider(cfg,appContext, DEBUG) { 12 | var p = new Promise( 13 | function(resolve,reject) { 14 | var EP = new EndpointProvider(); 15 | if(typeof appContext !== 'undefined') { 16 | if (typeof appContext === 'boolean') { 17 | // It is DEBUG level 18 | if (appContext) { 19 | EP.setLogLevel('DEBUG'); 20 | } 21 | } else { 22 | EP.setAppContext(appContext); 23 | DEBUG && EP.setLogLevel('DEBUG'); 24 | } 25 | }; 26 | EP.init(cfg, 27 | function(message) { 28 | console.log('Fat Utils Created and init Provider: ', EP); 29 | resolve(EP); 30 | }, 31 | function(message) { console.error('init failed', message); reject(message);} 32 | ); 33 | }); 34 | return p; 35 | }; 36 | 37 | /* 38 | * create a PeerConnection between two endpoints in a promise-like way.. 39 | * Resolve promise when the connection is established. 40 | * 41 | * pass object w/ two endnpoints { ep1: endpoint, ep2: endpoint} 42 | */ 43 | var createConnection = function createConnection(EP1, EP2) { 44 | 45 | var p = new Promise( 46 | function(resolve, reject) { 47 | var readyToResolve = 0; 48 | var epEvents = { 49 | 'session:alerting': function(eventObject) { 50 | // Auto-accept 51 | eventObject && eventObject.endpoint && eventObject.endpoint.accept(); 52 | }, 53 | 'session:started': function(eventObject) { 54 | if ( eventObject && eventObject.endpoint) { 55 | console.log('SESSION STARTED -- EndpointID '+eventObject.endpoint.getUserID()); 56 | } 57 | resolvePromise(); 58 | }, 59 | 'session:failed': function(eventObject) { 60 | if ( eventObject && eventObject.endpoint) { 61 | console.log('SESSION FAILED -- EndpointID '+eventObject.endpoint.getUserID()); 62 | } 63 | reject(); 64 | }, 65 | 'session:stopped': function(eventObject) { 66 | if ( eventObject && eventObject.endpoint) { 67 | console.log('SESSION STOPPED -- EndpointID '+eventObject.endpoint.getUserID()); 68 | } 69 | }, 70 | 'webrtc:connected': function(eventObject) { 71 | resolvePromise(); 72 | } 73 | }; 74 | 75 | var resolvePromise = function() { 76 | var timer = null; 77 | console.log('ep1.getState() === '+ep1.getState()); 78 | console.log('ep2.getState() === '+ep2.getState()); 79 | console.log('ep1.webrtc.getState() === '+ep1.webrtc.getState()); 80 | console.log('ep2.webrtc.getState() === '+ep2.webrtc.getState()); 81 | if (ep2.getState() === 'session:started' && 82 | ep1.getState() === 'session:started' && 83 | ep1.webrtc.getState() === 'connected' && 84 | ep2.webrtc.getState() === 'connected' ) { 85 | console.log('createConnection resolving callback...in 5 seconds...'); 86 | timer = timer || setTimeout(function() { 87 | console.log('st ep1:', ep1); 88 | console.log('st ep2:', ep2); 89 | resolve({ep1: ep1,ep2: ep2}); 90 | }, 5000); 91 | } 92 | }; 93 | 94 | EP1.setRtcommEndpointConfig(epEvents); 95 | EP2.setRtcommEndpointConfig(epEvents); 96 | var ep1 = EP1.createRtcommEndpoint({webrtc: true, chat:true}); 97 | var ep2 = EP2.createRtcommEndpoint({webrtc: true, chat:true}); 98 | ep2.webrtc.enable(); 99 | ep1.webrtc.enable(); 100 | ep1.connect(ep2.getUserID()); 101 | }); 102 | return p ; 103 | }; 104 | // Require RTCOMM Server is set globally. 105 | requireServer: function requireServer() { 106 | // Default to false. 107 | return (typeof REQUIRE_RTCOMM_SERVER !== 'undefined') ? REQUIRE_RTCOMM_SERVER : false; 108 | }; 109 | 110 | createSuiteName: function createSuiteName(name) { 111 | return (requireServer()) ? name : name + '[no_rtcomm_server]'; 112 | }; 113 | 114 | return { 115 | createProvider: createProvider, 116 | createConnection: createConnection, 117 | requireServer: requireServer, 118 | createSuiteName: createSuiteName 119 | }; 120 | }); 121 | 122 | 123 | -------------------------------------------------------------------------------- /src/rtcomm/EndpointProvider/EndpointRegistry.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a private EndpointRegistry object that 3 | * can be used to manage endpoints. 4 | * 5 | * We create an object like: { 'appContext'}: { uuid1: Endpoint1, 6 | * uuid2: Endpoint2} 7 | */ 8 | 9 | /* global l:false */ 10 | 11 | var EndpointRegistry = function EndpointRegistry(options) { 12 | var singleEndpoint = (options && options.singleEndpoint) ? options.singleEndpoint : false; 13 | // {options.singleEndpoint = true} There can only be 1 endpoint per context. 14 | // 15 | var registry = {}; 16 | // used to search for endpoints by these values. 17 | var properties = []; 18 | /* get an endpoint based on a key 19 | * if it is ambiguous, return them all in an Array. 20 | */ 21 | function get(key) { 22 | var a = []; 23 | // Key should be an ID 24 | if (key) { 25 | a = findByProperty('id', key); 26 | } else { 27 | // create a list of all endpoints. 28 | a = this.list(); 29 | } 30 | return a; 31 | } 32 | 33 | function getOneAvailable() { 34 | var a = []; 35 | this.list().forEach(function(item){ 36 | item.available() && a.push(item); 37 | }); 38 | // Return the last one found 39 | if(a.length > 0 ) { 40 | return a[a.length-1]; 41 | } else { 42 | return null; 43 | } 44 | } 45 | 46 | // Return array of all enpdoints that match the query 47 | function findByProperty(property, value) { 48 | if (properties.indexOf(property) > -1) { 49 | // Two special cases - property is id or appContext: 50 | var a = []; 51 | switch(property) { 52 | case 'appContext': 53 | if (registry.hasOwnProperty(value)) { 54 | Object.keys(registry[value]).forEach(function(key){ 55 | a.push(registry[value][key]); 56 | }); 57 | } 58 | break; 59 | case 'id' : 60 | Object.keys(registry).forEach(function(appContext){ 61 | if (registry[appContext].hasOwnProperty(value)) { 62 | a.push(registry[appContext][value]); 63 | } 64 | }); 65 | break; 66 | default: 67 | this.list().forEach(function(obj) { 68 | if (obj.hasOwnProperty(property) && obj[property] === value ){ 69 | a.push(obj); 70 | } 71 | }); 72 | break; 73 | } 74 | return a; 75 | } else { 76 | l('DEBUG') && console.log('EndpointRegistry.findByProperty '+property+' not valid '); 77 | return []; 78 | } 79 | } 80 | /* add an endpoint, if a key for that 81 | * endpoint already exists, return it. 82 | * Otherwise, return null if nothing passed 83 | */ 84 | function add(object) { 85 | var appContext = null; 86 | var uuid = null; 87 | if (object) { 88 | properties = Object.keys(object); 89 | appContext= object.appContext; 90 | uuid = object.id; 91 | if (registry.hasOwnProperty(appContext)) { 92 | var eps = Object.keys(registry[appContext]); 93 | if (eps.length === 1 && singleEndpoint) { 94 | return registry[appContext][eps[0]]; 95 | } else { 96 | registry[appContext][uuid] = object; 97 | return registry[appContext][uuid]; 98 | } 99 | } else { 100 | // Create context, add endpoint 101 | registry[appContext] = {}; 102 | registry[appContext][uuid] = object; 103 | return registry[appContext][uuid]; 104 | } 105 | } else { 106 | return null; 107 | } 108 | } 109 | /* 110 | * Remove an object from the registry 111 | */ 112 | function remove(object) { 113 | var key = null; 114 | var uuid = null; 115 | if (object && list().length > 0 ) { 116 | key = object.appContext; 117 | uuid = object.id; 118 | l('DEBUG') && console.log('EndpointRegistry.remove() Trying to remove object', object); 119 | if (registry.hasOwnProperty(key) ) { 120 | if (registry[key].hasOwnProperty(uuid)) { 121 | delete registry[key][uuid]; 122 | // If this was the last entry in the appContext, delete it too. 123 | if (Object.keys(registry[key]).length === 0 ) { 124 | delete registry[key]; 125 | } 126 | return true; 127 | } else { 128 | l('DEBUG') && console.log('EndpointRegistry.remove() object not found', list()); 129 | return false; 130 | } 131 | } else { 132 | l('DEBUG') && console.log('EndpointRegistry.remove() object not found', list()); 133 | return false; 134 | } 135 | } else { 136 | return false; 137 | } 138 | } 139 | /* 140 | * Destroy the registry and all objects in it 141 | * calls .destroy() on contained objects if 142 | * they have that method 143 | */ 144 | function destroy() { 145 | // call destroy on all objects, remove them. 146 | list().forEach(function(obj){ 147 | if (typeof obj.destroy === 'function') { 148 | obj.destroy(); 149 | } 150 | remove(obj); 151 | }); 152 | } 153 | 154 | function length() { 155 | return this.list().length; 156 | } 157 | 158 | /* 159 | * return the registry object for perusal. 160 | */ 161 | function list() { 162 | var a = []; 163 | Object.keys(registry).forEach(function(appContext){ 164 | Object.keys(registry[appContext]).forEach(function(uuid){ 165 | a.push(registry[appContext][uuid]); 166 | }); 167 | }); 168 | return a; 169 | } 170 | 171 | return { 172 | add: add, 173 | get: get, 174 | getOneAvailable: getOneAvailable, 175 | findByProperty: findByProperty, 176 | remove: remove, 177 | destroy: destroy, 178 | length: length, 179 | list: list 180 | }; 181 | 182 | }; 183 | -------------------------------------------------------------------------------- /src/rtcomm/connection/Transaction.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 IBM Corp. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | /** 17 | * @class 18 | * @memberof module:rtcomm.connector 19 | * 20 | * @classdesc 21 | * A Transaction is a conversation that requires a response. 22 | * /** 23 | * @param options message: message, timeout: timeout 24 | * @param {callback} cbSuccess called when transaction is successful 25 | * @param {callback} cbFailure 26 | * 27 | * @event finished Emitted when complete... can also use onSuccess. 28 | * @event message 29 | * 30 | * 31 | * @private 32 | */ 33 | var Transaction = function Transaction(options, cbSuccess, cbFailure) { 34 | var message, timeout, toTopic; 35 | 36 | this.defaultTimeout = 5000; 37 | if (options) { 38 | message = options.message || null; 39 | timeout = options.timeout || null; 40 | toTopic = options.toTopic || null; 41 | } 42 | /* Instance Properties */ 43 | this.objName = "Transaction"; 44 | this.events = {'message': [], 45 | 'timeout_changed':[], 46 | 'canceled':[], 47 | 'finished':[]}; 48 | this.timeout = timeout || this.defaultTimeout; 49 | this.outbound = (message && message.transID) ? false : true; 50 | /*global generateUUID:false*/ 51 | this.id = (message && message.transID) ? message.transID : generateUUID(); 52 | this.method = (message && message.method) ? message.method : 'UNKNOWN'; 53 | 54 | this.toTopic = toTopic || ((message && message.fromTopic) ? message.fromTopic : null); 55 | this.message = message; 56 | this.onSuccess = cbSuccess || function(object) { 57 | l('DEBUG') && console.log(this+' Response for Transaction received, requires callback for more information:', object); 58 | }; 59 | this.onFailure = cbFailure || function(object) { 60 | l('DEBUG') && console.log(this+' Transaction failed, requires callback for more information:', object); 61 | }; 62 | 63 | l('DEBUG') && console.log(this+ '.constructor Are we outbound?', this.outbound); 64 | }; 65 | /*global util:false*/ 66 | Transaction.prototype = util.RtcommBaseObject.extend( 67 | /** @lends module:rtcomm.connector.Transaction.prototype */ 68 | { 69 | /* 70 | * A Transaction is something that may require a response, but CAN receive messages w/ the same transaction ID 71 | * until the RESPONSE is received closing the transaction. 72 | * 73 | * The types of transactions correlate with the types of Messages with the Session being the most complicated. 74 | * 75 | * Transaction management... 76 | * 77 | * TODO: Inbound Starts... 78 | * 79 | * 80 | */ 81 | /* 82 | * Instance Methods 83 | */ 84 | setTimeout: function(timeout) { 85 | this.timeout = timeout || this.defaultTimeout; 86 | this.emit('timeout_changed', this.timeout); 87 | }, 88 | 89 | getInbound: function() { 90 | return !(this.outbound); 91 | }, 92 | /** 93 | * Start a transaction 94 | * @param [timeout] can set a timeout for the transaction 95 | */ 96 | start: function(timeout) { 97 | /*global l:false*/ 98 | l('TRACE') && console.log(this+'.start() Starting Transaction for ID: '+this.id); 99 | if (this.outbound) { 100 | this.message.transID = this.id; 101 | this.send(this.message); 102 | } else { 103 | l('TRACE') && console.log(this+'.start() Inbound Transaction '); 104 | } 105 | }, 106 | /** 107 | * send a message over the transaction 108 | */ 109 | send: function(message) { 110 | l('TRACE') && console.log(this+'.send() sending message: '+message); 111 | if(message) { 112 | message.transID = message.transID || this.id; 113 | l('DEBUG') && console.log('Transaction.send() ids...'+message.transID +' this.id '+ this.id+'toTopic: '+this.toTopic); 114 | if (message.transID === this.id) { 115 | this.endpointconnector.send({message: message, toTopic:this.toTopic}); 116 | } else { 117 | l('DEBUG') && console.log(this+'.send() Message is not part of our tranaction, dropping!', message); 118 | } 119 | } else { 120 | console.error('Transaction.send() requires a message to be passed'); 121 | } 122 | }, 123 | /** 124 | * Finish the transaction, message should be a RESPONSE. 125 | */ 126 | finish: function(rtcommMessage) { 127 | // Is this message for THIS transaction? 128 | l('DEBUG') && console.log(this+'.finish() Finishing transction with message:',rtcommMessage); 129 | // if there isn't an id here, add it. 130 | rtcommMessage.transID = rtcommMessage.transID || this.id; 131 | if (this.id === rtcommMessage.transID && 132 | rtcommMessage.method === 'RESPONSE' && 133 | this.method === rtcommMessage.orig) { 134 | if (this.outbound) { 135 | if (rtcommMessage.result === 'SUCCESS' && this.onSuccess ) { 136 | this.onSuccess(rtcommMessage); 137 | } else if (rtcommMessage.result === 'FAILURE' && this.onFailure) { 138 | this.onFailure(rtcommMessage); 139 | } else { 140 | console.error('Unknown result for RESPONSE:', rtcommMessage); 141 | } 142 | } else { 143 | // If we are inbound, then send the message we have and finish the transaction 144 | this.send(rtcommMessage); 145 | } 146 | this.emit('finished'); 147 | } else { 148 | console.error('Message not for this transaction: ', rtcommMessage); 149 | } 150 | }, 151 | cancel: function() { 152 | this.emit('canceled'); 153 | } 154 | }); 155 | -------------------------------------------------------------------------------- /tests/manual/old/deprecated/testClient.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | Signaling Service 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | 24 |

ibmrtc.webrtc & ibmrtc.rtcomm manual test client

25 |
26 |

This test creates an ibm webrtc Signaling Client (does not do the audio video portion yet)

27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 |
MQTT: TopicName:
1.
2. 48 |
3.
Connected to:
83 | 84 | 85 | 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /tests/manual/old/deprecated/client1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | Signaling Service 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | 24 |

ibmrtc.webrtc & ibmrtc.rtcomm manual test client

25 |
26 |

This test creates an ibm webrtc Signaling Client (does not do the audio video portion yet)

27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 |
MQTT: TopicName:
1.
2. 48 |
3.
Connected to:
83 | 84 | 85 | 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /tests/stress/stressTest.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 IBM Corp. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | 18 | define([ 19 | 'intern', 20 | 'intern!object', 21 | 'intern/chai!assert', 22 | 'intern/node_modules/dojo/Deferred', 23 | (typeof window === 'undefined' && global) 24 | ?'intern/dojo/node!../support/mqttws31_shim': 25 | 'lib/mqttws31', 26 | 'support/config', 27 | 'umd/rtcomm/EndpointProvider' 28 | ], function (intern, registerSuite, assert, Deferred, globals,config, EndpointProvider) { 29 | 30 | var DEBUG = (intern.args.DEBUG === 'true')? true: false; 31 | 32 | var MAX_CONNS = parseInt(intern.args.MAX_CONNS) || 50; 33 | var duration = parseInt(intern.args.duration) || 20000; 34 | 35 | var createProvider = function createProvider(cfg,appContext) { 36 | var dfd = new Deferred(); 37 | var EP = new EndpointProvider(); 38 | DEBUG && EP.setLogLevel('DEBUG'); 39 | EP.setAppContext(appContext); 40 | EP.init(cfg, 41 | function(message) { 42 | dfd.resolve(EP); 43 | }, 44 | function(message) { console.error('init failed', message); dfd.reject(message);} 45 | ); 46 | return dfd.promise; 47 | }; 48 | 49 | var createAutoConnectEP = function createAutoConnectEP(provider) { 50 | var ep = provider.createRtcommEndpoint(); 51 | //ep.on('session:started', function() {}); 52 | // ep.on('session:trying', function() {}); 53 | //ep.on('session:ringing', function() {}); 54 | ep.on('session:alerting', function() { 55 | ep.accept(); 56 | }); 57 | //ep.on('chat:connected', function() {}); 58 | //ep.on('chat:disconnected', function() {}); 59 | //ep.on('chat:message', function() {}); 60 | return ep; 61 | }; 62 | 63 | var createConnection= function createConnection(EP1,EP2,duration) { 64 | var dfd = new Deferred(); 65 | var ep1 = createAutoConnectEP(EP1); 66 | var ep2 = createAutoConnectEP(EP2); 67 | 68 | function failure(message) { 69 | console.log('>>>> createConnection FAILURE '+message); 70 | dfd.reject(false); 71 | } 72 | 73 | ep1.on('session:started', function() { 74 | // set a timer and wait... 75 | setTimeout(function(){ 76 | ep1.disconnect(); 77 | dfd.resolve(true); 78 | },duration); 79 | }); 80 | 81 | ep1.on('session:failed', failure); 82 | ep2.on('session:failed', failure); 83 | 84 | ep1.connect(EP2.getUserID()); 85 | return dfd.promise; 86 | }; 87 | 88 | var cfg= config.clientConfig1(); 89 | var appContext = 'internChatTest'; 90 | var callers= {}; 91 | var callees= {}; 92 | registerSuite({ 93 | name: 'Stress Test - '+MAX_CONNS, 94 | setup: function() { 95 | console.log('*************setup!**************'); 96 | var setupDfd = new Deferred(); 97 | /* init the EndpointProvider */ 98 | var resolved = 0; 99 | 100 | function resolve() { 101 | if (resolved === 2*MAX_CONNS) { 102 | console.log('******** Finished Setup '+resolved); 103 | if (Object.keys(callers).length === MAX_CONNS && 104 | Object.keys(callees).length === MAX_CONNS ) { 105 | // Wait 5 seconds to ensure everything is completed. 106 | setTimeout(function() { 107 | setupDfd.resolve() 108 | },5000);; 109 | } else { 110 | console.log('CALLERS? '+Object.keys(callers).length); 111 | console.log('CALLEES? '+Object.keys(callees).length); 112 | setupDfd.reject("All Callers & Clients not actually created"); 113 | } 114 | } 115 | } 116 | 117 | for(var i=0; i>>>TEST accepting call'); 121 | setTimeout(function() { 122 | ep2.accept(); 123 | }, 1000); 124 | }); 125 | ep1.connect(cfg2.userid); 126 | }); 127 | }, 128 | "GenericMessagEndpoint() A calls B - sends messages": function() { 129 | console.log('************* ' + this.name + ' **************'); 130 | // SKIP_ALL && this.skip(false); 131 | var dfd = this.async(T2); 132 | 133 | // Our endpoints 134 | var ep1; 135 | var ep2; 136 | 137 | var finish = dfd.callback(function(object) { 138 | console.log("******************Asserting now...***********************"); 139 | console.log(object); 140 | // Object should be an event_object 141 | assert.ok(ep1.sessionStarted(), "Endpoint 1 is Session Started"); 142 | assert.ok(ep2.sessionStarted(), "Endpoint2 is session Started"); 143 | assert.equal(object.message, "Hello!", "Received the message"); 144 | }); 145 | 146 | var cfg1 = getConfig('testuser1'); 147 | var cfg2 = getConfig('testuser2'); 148 | 149 | createAndInitTwoProviders(cfg1, cfg2) 150 | .then(function(obj) { 151 | // Save the providers 152 | var EP1 = g.EP1 = obj.provider1; 153 | var EP2 = g.EP2 = obj.provider2; 154 | // create Endpoints 155 | ep1 = EP1.getMessageEndpoint(); 156 | ep2 = EP2.getMessageEndpoint(); 157 | 158 | ep1.on('session:ringing', function() { 159 | ep1_ringing = true 160 | }) 161 | ep1.on('session:trying', function() { 162 | ep1_trying = true 163 | }) 164 | ep1.on('session:started', function() { 165 | ep1.generic_message.send("Hello!"); 166 | }); 167 | 168 | // We will finish when we receive a generic_message 169 | ep2.on('generic_message:message', finish); 170 | 171 | ep2.on('session:alerting', function(obj) { 172 | ep2_alerting = true; 173 | console.log('>>>>TEST accepting call'); 174 | setTimeout(function() { 175 | ep2.accept(); 176 | }, 1000); 177 | }); 178 | ep1.connect(cfg2.userid); 179 | }); 180 | } 181 | }) 182 | }) 183 | -------------------------------------------------------------------------------- /tests/functional/MqttEndpoint.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 IBM Corp. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | define([ 17 | 'intern', 18 | 'intern!object', 19 | 'intern/chai!assert', 20 | (typeof window === 'undefined' && global) 21 | ?'intern/dojo/node!../support/mqttws31_shim': 22 | 'bower_components/bower-mqttws/mqttws31', 23 | 'support/config', 24 | 'bower_components/webrtc-adapter/adapter', 25 | 'umd/rtcomm/EndpointProvider', 26 | 'support/rtcommFatUtils' 27 | 28 | ], function (intern, registerSuite, assert, globals,config, adapter, EndpointProvider, Fat) { 29 | var suiteName = Fat.createSuiteName("FVT: MqttEndpoint"); 30 | var DEBUG = (intern.args.DEBUG === 'true')? true: false; 31 | /* if (typeof window === 'undefined' && global) { 32 | require(['intern/dojo/node!./tests_intern/mock/mqttws31_shim'], function(globals) { 33 | console.log('********** Paho should now be defined **********'); 34 | }); 35 | } else { 36 | require(['lib/mqttws31'], function(globals) { 37 | console.log('Paho? ', Paho); 38 | console.log('********** Paho should now be defined **********'); 39 | }); 40 | } */ 41 | var cfg = config.clientConfig1(); 42 | var ep = null; 43 | var mq1 = null; 44 | var mq2 = null; 45 | var globals = null; 46 | 47 | var mqttPublish = function(topic, message, ms) { 48 | // publish 'message' from mq1 to mq2 on topic 49 | // pass means we expect it to work or not. 50 | ms = ms || 1000; 51 | var p = new Promise( 52 | function(resolve, reject) { 53 | var msgrecv1 = null; 54 | var msgrecv2 = null; 55 | // Wait to publish 56 | mq1.clearEventListeners(); 57 | setTimeout(function() { 58 | mq1.on('message', function(msg) { 59 | console.log('MQ1 Received Message: '+msg.content); 60 | // Should not receive message; 61 | resolve(false); 62 | }); 63 | mq2.on('message', function(msg) { 64 | console.log('MQ2 Received Message: '+msg.content); 65 | if (msg.content === message) { 66 | // Should not receive message; 67 | resolve(true); 68 | } else { 69 | console.log('Received Weird Message:' + msg.content); 70 | resolve(false); 71 | } 72 | }); 73 | mq1.publish(topic, message); 74 | }, ms); 75 | setTimeout(function() { 76 | resolve(false); 77 | },ms+1000); 78 | }); 79 | return p; 80 | }; 81 | 82 | registerSuite({ 83 | name: suiteName, 84 | setup: function() { 85 | console.log('************* SETUP: '+this.name+' **************'); 86 | var p = new Promise( 87 | function(resolve, reject) { 88 | Fat.createProvider(cfg, 'mqttEndpoint').then( 89 | function(endpointProvider) { 90 | console.log('*** Creating MqttEndpoints ***'); 91 | ep = endpointProvider; 92 | mq1 = ep.getMqttEndpoint(); 93 | mq2 = ep.getMqttEndpoint(); 94 | mq1.subscribe('/test1'); 95 | mq2.subscribe('/test2/#'); 96 | console.log('*** mq1 ***', mq1); 97 | resolve(); 98 | }); 99 | }); 100 | return p; 101 | }, 102 | teardown: function() { 103 | console.log('************* TEARDOWN: '+this.name+' **************'); 104 | ep.destroy(); 105 | ep = null; 106 | }, 107 | 'mqtt /test2 topic':function() { 108 | console.log('************* '+this.name+' **************'); 109 | var dfd = this.async(3000); 110 | mqttPublish('/test2', '1 - Hello from 1').then( 111 | dfd.callback(function(pass) { 112 | assert.isTrue(pass,'messsage was received'); 113 | }) 114 | ); 115 | }, 116 | 'mqtt /test3 topic':function() { 117 | console.log('************* '+this.name+' **************'); 118 | var dfd = this.async(3000); 119 | mqttPublish('/test3', '2 - Hello from 1').then( 120 | dfd.callback(function(pass) { 121 | assert.isFalse(pass,'Message should not be received'); 122 | }) 123 | ); 124 | }, 125 | 'mqtt /test2/something topic':function() { 126 | console.log('************* '+this.name+' **************'); 127 | var dfd = this.async(3000); 128 | mqttPublish('/test2/something', '3 - Hello from 1').then( 129 | dfd.callback(function(pass) { 130 | assert.isTrue(pass,'Message should be received'); 131 | }) 132 | ); 133 | }, 134 | 'mqtt /test2something topic':function() { 135 | console.log('************* '+this.name+' **************'); 136 | var dfd = this.async(3000); 137 | mqttPublish('/test2something', '4 - Hello from 1').then( 138 | dfd.callback(function(pass) { 139 | assert.isFalse(pass,'Message should not be received'); 140 | }) 141 | ); 142 | }, 143 | 'mqtt /test2something -> /test2 topic':function() { 144 | console.log('************* '+this.name+' **************'); 145 | var dfd = this.async(3000); 146 | // Overwrite the mq2 stuff (clean out, start over); 147 | mq2 = null; 148 | mq2 = ep.getMqttEndpoint(); 149 | mq2.subscribe('/test2'); 150 | mqttPublish('/test2something', '5 - Hello from 1').then( 151 | dfd.callback(function(pass) { 152 | assert.isFalse(pass,'Message should not be received'); 153 | }) 154 | ); 155 | }, 156 | 157 | 'mqtt /test2/something -> /test2 topic':function() { 158 | console.log('************* '+this.name+' **************'); 159 | var dfd = this.async(3000); 160 | // Overwrite the mq2 stuff (clean out, start over); 161 | mq2 = null; 162 | mq2 = ep.getMqttEndpoint(); 163 | mq2.subscribe('/test2'); 164 | mqttPublish('/test2/something', '6 - Hello from 1').then( 165 | dfd.callback(function(pass) { 166 | assert.isFalse(pass,'Message should not be received'); 167 | }) 168 | ); 169 | } 170 | }); 171 | }); 172 | -------------------------------------------------------------------------------- /tests/manual/old/deprecated/devTestClient.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | Signaling Service 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | 24 |

ibmrtc.webrtc & ibmrtc.rtcomm manual test client

25 |
26 |

This test creates an ibm webrtc Signaling Client (does not do the audio video portion yet)

27 |
28 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 |
32 | 33 | 34 | MQTT: TopicName:
44 | 45 |
1.
2. 61 |
3.
Connected to:
96 | 97 | 98 | 229 | 230 | 231 | 232 | -------------------------------------------------------------------------------- /src/rtcomm/util/RtcommBaseObject.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 IBM Corp. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | /** Base Rtcomm class that provides event functionality 17 | * @class 18 | * @memberof module:rtcomm.util 19 | */ 20 | var RtcommBaseObject = { 21 | /** @lends module:rtcomm.util.RtcommBaseObject.prototype */ 22 | /* 23 | * Properties 24 | 25 | objName : 'Base', 26 | id : 'unknown', 27 | config: {}, 28 | dependencies: {}, 29 | ready: false, 30 | state: 'unknown', 31 | states: {}, 32 | events: {}, 33 | */ 34 | /* 35 | * Methods 36 | */ 37 | setState : function(value, object) { 38 | if (typeof this.state !== 'undefined') { 39 | if (this.state !== value) { 40 | this.state = value; 41 | this.emit(value,object); 42 | } else { 43 | l('DEBUG') && console.log(this + '.setState(): State already set, ignoring '+value ); 44 | } 45 | } else { 46 | this.emit(value,object); 47 | } 48 | }, 49 | listEvents : function() { 50 | 51 | console.log('******* ' + this+' Configured events ***********'); 52 | /*jslint forin: true */ 53 | for(var event in this.events) { 54 | if (this.events.hasOwnProperty(event)) { 55 | console.log('******* ['+event+'] has '+this.events[event].length+' listeners registered'); 56 | } 57 | 58 | } 59 | }, 60 | clearEventListeners : function() { 61 | for(var event in this.events) { 62 | if (this.events.hasOwnProperty(event)) { 63 | this.events[event] = []; 64 | } 65 | } 66 | }, 67 | createEvent: function(event) { 68 | if (this.hasOwnProperty('events')){ 69 | this.events[event] = []; 70 | } else { 71 | throw new Error('createEvent() requires an events property to store the events'); 72 | } 73 | }, 74 | removeEvent: function(event) { 75 | if (event in this.events) { 76 | delete this.events[event]; 77 | } 78 | }, 79 | 80 | hasEventListener: function(event){ 81 | return (event in this.events) && (this.events[event].length > 0); 82 | }, 83 | /** Establish a listener for an event */ 84 | on : function(event,callback) { 85 | //console.log('on -- this.events is: '+ JSON.stringify(this.events)); 86 | // This function requires an events object on whatever object is attached to. and event needs to be defined there. 87 | if (this.events) { 88 | if(typeof event === 'object') { 89 | // this is an object of events: 90 | for (var key in event) { 91 | if (event.hasOwnProperty(key)) { 92 | if (this.events[key] && Array.isArray(this.events[key])) { 93 | l('EVENT', this) && console.log(this+' Adding a listener callback for event['+key+']'); 94 | l('TRACE', this) && console.log(this+' Callback for event['+key+'] is', event[key]); 95 | this.events[key].push(event[key]); 96 | } 97 | } 98 | } 99 | } else { 100 | if (this.events[event] && Array.isArray(this.events[event])) { 101 | l('EVENT', this) && console.log(this+' Adding a listener callback for event['+event+']'); 102 | l('TRACE', this) && console.log(this+' Callback for event['+event+'] is', callback); 103 | this.events[event].push(callback); 104 | } 105 | } 106 | } else { 107 | throw new Error("on() requires an events property listing the events. this.events["+event+"] = [];"); 108 | } 109 | }, 110 | /** attach a callback to ALL events */ 111 | bubble : function(callback) { 112 | if (this.events) { 113 | for(var event in this.events) { 114 | if (this.events.hasOwnProperty(event) ) { 115 | this.events[event].push(callback); 116 | } 117 | } 118 | } 119 | }, 120 | // Clear callbacks for a particular event. 121 | off : function(event) { 122 | if (this.events && this.events[event]) { 123 | l('EVENT', this) && console.log(this+' Removing listeners for event['+event+']'); 124 | this.events[event] = []; 125 | } 126 | }, 127 | /** emit an event from the object */ 128 | emit : function(event, object) { 129 | var event_object = object || {}; 130 | var self = this; 131 | // We have an event format specified, normalize the event before emitting. 132 | if (this._Event && typeof this._Event === 'function') { 133 | event_object = this._Event(event, event_object); 134 | } 135 | // event_object.name = (event_object.name) ? event_object.name : event; 136 | if (this.events && this.events[event] ) { 137 | // console.log('>>>>>>>> Firing event '+event); 138 | l('EVENT', this) && console.log(this+".emit() for event["+event+"]", self.events[event].length); 139 | // Save the event 140 | if (typeof self.lastEvent !== 'undefined') { 141 | self.lastEvent = event; 142 | }; 143 | // Event exists, call all callbacks 144 | self.events[event].forEach(function(callback) { 145 | if (typeof callback === 'function') { 146 | l('EVENT', self) && console.log(self+".emit() executing callback for event["+event+"]"); 147 | try { 148 | callback(event_object); 149 | } catch(e) { 150 | var m = 'Event['+event+'] callback failed with message: '+e.message; 151 | throw new Error(m); 152 | } 153 | } else { 154 | l('EVENT', self) && console.log(self+' Emitting, but no callback for event['+event+']'); 155 | } 156 | }); 157 | } else { 158 | throw new Error('emit() requires an events property listing the events. this.events['+event+'] = [];'); 159 | } 160 | }, 161 | extend: function(props) { 162 | var prop, obj; 163 | obj = Object.create(this); 164 | for (prop in props) { 165 | if (props.hasOwnProperty(prop)) { 166 | obj[prop] = props[prop]; 167 | } 168 | } 169 | return obj; 170 | }, 171 | // Test Function 172 | _l: function(level){ 173 | if (typeof l === 'function') { 174 | return l(level,this); 175 | } else { 176 | return 'unknown'; 177 | } 178 | }, 179 | toString: function() { 180 | var name = (this._ && this._.objName)? this._.objName : this.objName || this.name || 'Unknown'; 181 | var id = (this._ && this._.id)? this._.id: this.id || 'Unknown'; 182 | return name + '['+id+']'; 183 | } 184 | }; 185 | 186 | exports.RtcommBaseObject = RtcommBaseObject; 187 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #lib.rtcomm.clientjs 2 | 3 | The rtcomm.js library is a JavaScript Universal Module Description(UMD) formatted module that provides an API for client side web application developers to enable WebRTC functionality. This module handles signaling and creation of WebRTC PeerConnections between endpoints in a simple and flexible way. The only requirement for peer-to-peer calling is an MQTT Broker that supports MQTT protocol version 3.1 or higher. A nice open source MQTT broker solution if your a fan of Node.js is [Mosca](https://github.com/mcollina/mosca). 4 | 5 | If you need additional capabilities like SIP federation, a backend programming model for services (e.g media server integration for record/playback), a registry, third party call control and call queues, the Liberty profile of the WebSphere Application Server comes with the 'rtcomm-1.0' feature which can be configured to connect with the same broker used for peer-to-peer calling. This page provides additional details on how to setup Liberty to work with your MQTT broker:[Using Liberty and rtcomm](docs/rtcomm_and_liberty_setup.md) 6 | 7 | ##Requirements 8 | 9 | 1. An MQTT Server such as [IBM MessageSite](https://developer.ibm.com/messaging/messagesight/) or [Mosca](https://github/mcollina/mosca). For prototyping and development, it is possible to use `messagesight.demos.ibm.com`. 10 | 2. A web browsers that support WebRTC (tested w/ Chrome and Firefox) 11 | 12 | ##Dependencies 13 | 14 | The rtcomm.js library is dependent on the following libraries (which will be installed via bower). If you do not use bower, then you can get the files in the links below: 15 | 16 | 1. Paho MQTT JavaScript client [link](http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt.javascript.git/tree/src/mqttws31.js) 17 | 2. WebRTC Adapter [link] (https://github.com/webrtc/adapter) 18 | 19 | ** Regarding SSL & WebRTC [BEHAVIOR CHANGE]** 20 | 21 | As of Chrome 47([WebRTC Release Notes](https://developers.google.com/web/updates/2015/10/chrome-47-webrtc)) `getUserMedia` will fail with a permissions error unless the site is served over SSL. This has the side effect of requiring a secure connection to the MQTT Server as well. By default, when served over `https` the client will attempt to connect to the `sslport` if configured or the `port` if not. Make sure your MQTT Server supports SSL. 22 | 23 | ##Installation 24 | 25 | ###Bower 26 | 27 | *`rtcomm`* is a registered bower module and can be installed using bower. 28 | ``` 29 | bower install rtcomm 30 | ``` 31 | This will handle installing the `mqttws31` and `webrtc-adapter` dependencies as well as the rtcomm library. Once installed, the scripts still need to be loaded in the application html file based on where bower installed the libraries. 32 | 33 | ### Inclusion in Browser 34 | 35 | Add the following you your html file: 36 | 37 | ```html 38 | 39 | 40 | 41 | ``` 42 | 43 | ### Write some HTML 44 | 45 | ```html 46 | 47 |
48 | 49 | 50 |
51 | 52 | 53 | ``` 54 | ### Add some JavaScript 55 | 56 | Define the configuration to connect to an MQTT Server. 57 | 58 | ```javascript 59 | 117 | ``` 118 | 119 | ## More information 120 | To get started with a sample, checkout the [Getting Started with the Sample](docs/sample.md). 121 | 122 | For more detailed information on the API, see an [extended explanation](docs/extended_explanation.md). 123 | 124 | Further information on the RtcommEndpoint API is located in the *jsdoc* which is available in the sample zip file or when you clone and build the project using `grunt`. 125 | 126 | #Building the code 127 | 128 | If you want to clone the repository and build this yourself, you will need to: 129 | 130 | 1. Clone the repository: 131 | ``` 132 | git clone https://github.com/WASdev/lib.rtcomm.clientjs.git 133 | ``` 134 | 2. Install node.js and npm (http://nodejs.org/download/) 135 | 3. Install necessary dependencies via npm from the repository directory (assuming lib.rtcomm.clientjs) 136 | ``` 137 | lib.rtcomm.clientjs/ # npm install 138 | ``` 139 | 4. Install the grunt-cli (globally if not installed) 140 | ``` 141 | npm install -g grunt-cli 142 | ``` 143 | 5. Build the library: 144 | ``` 145 | grunt 146 | ``` 147 | This will create a **dist** directory with the following contents: 148 | ``` 149 | |-jsdoc 150 | |--rtcomm.js 151 | |--rtcomm.min.js 152 | |-umd 153 | |--rtcomm.js 154 | |--rtcomm 155 | |---connection.js 156 | |---util.js 157 | ``` 158 | 159 | 6. Download the Bower dependencies(necessary for tests) 160 | ``` 161 | bower install 162 | ``` 163 | # Running the tests 164 | 165 | Reference the [README.md](tests/README.md) file in the tests/ directory. 166 | 167 | -------------------------------------------------------------------------------- /tests/functional/SessionQueue.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 IBM Corp. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | define([ 17 | 'intern', 18 | 'intern!object', 19 | 'intern/chai!assert', 20 | (typeof window === 'undefined' && global) ? 21 | 'intern/dojo/node!../support/mqttws31_shim': 22 | 'bower_components/bower-mqttws/mqttws31', 23 | 'support/config', 24 | 'bower_components/webrtc-adapter/adapter', 25 | 'umd/rtcomm/EndpointProvider', 26 | 'support/rtcommFatUtils' 27 | ], function (intern, registerSuite, assert, globals, config, adapter, EndpointProvider,Fat) { 28 | var suiteName = Fat.createSuiteName("FVT: Session Queue"); 29 | 30 | var DEBUG = (intern.args.DEBUG === 'true')? true: false; 31 | // endpointProvider 32 | var ep = null; 33 | // Endpoint 34 | var rtcommEP = null; 35 | var mqtt = null; 36 | var cfg = config.clientConfig1(); 37 | 38 | var noQueuesConfigured = true; 39 | var START_SESSION = { 40 | 'rtcommVer': 'v1.0.0', 41 | 'method': 'START_SESSION', 42 | 'fromTopic': null, 43 | 'protocols': ['chat'], 44 | 'sigSessID':'1111-fake-test-1111', 45 | 'transID':'2222-fake-test-2222', 46 | 'toEndpointID': 'queueid', 47 | 'payload': { type: 'offer' }, 48 | 'appContext': 'rtcommTest' 49 | }; 50 | function getPublishTopic(sharedTopic) { 51 | console.log('**********'+sharedTopic); 52 | return sharedTopic.replace(/^\$SharedSubscription.+\/\//,'\/') 53 | .replace(/\/#$/g,'\/'); 54 | } 55 | registerSuite({ 56 | name: suiteName, 57 | setup: function() { 58 | console.log('************* SETUP: '+this.name+' **************'); 59 | var p = new Promise( 60 | function(resolve, reject) { 61 | ep = new EndpointProvider(); 62 | DEBUG && ep.setLogLevel('DEBUG'); 63 | cfg.userid = 'intern'; 64 | cfg.appContext = 'rtcommTest'; 65 | ep.init(cfg, 66 | function() { 67 | console.log('***** Setup Complete *****'); 68 | }, 69 | function(error){ 70 | console.log('**** Setup Failed *****', error); 71 | reject(error); 72 | }); 73 | ep.on('queueupdate', function(queues) { 74 | noQueuesConfigured = false; 75 | console.log('*******QUEUES!', queues); 76 | clearTimeout(timer); 77 | resolve(); 78 | }); 79 | 80 | var timer = setTimeout(function(){ 81 | console.log('******* Resolving -- no Queues Configured'); 82 | resolve(); 83 | },5000); 84 | }); 85 | return p; 86 | }, 87 | beforeEach: function() { 88 | // Destroy the endpoint. 89 | console.log('>>>>>>>>>>>> Reset the rtcommEP[New Test] <<<<<<<<<<<<<<<'); 90 | rtcommEP && rtcommEP.destroy(); 91 | rtcommEP = ep.createRtcommEndpoint({chat:true, webrtc: false}); 92 | console.log('reset the mqtt'); 93 | mqtt && mqtt.destroy(); 94 | mqtt = ep.getMqttEndpoint(); 95 | }, 96 | teardown: function() { 97 | console.log('************* TEARDOWN: '+this.name+' **************'); 98 | ep.destroy(); 99 | ep = null; 100 | }, 101 | 102 | 'Init of EndpointProvider creates Queues' : function() { 103 | console.log('************* '+this.name+' **************'); 104 | noQueuesConfigured && this.skip("There are no Queues configured on the server"); 105 | console.log('queues: ', ep.listQueues()); 106 | assert.ok(ep.listQueues().length > 0 , 'queues is defined'); 107 | }, 108 | 109 | 'Join bad queue throws exception': function () { 110 | console.log('************* '+this.name+' **************'); 111 | var error; 112 | try { 113 | ep.joinQueue('/TestTopic/#'); 114 | } catch(e) { 115 | error = e; 116 | console.log(e); 117 | } 118 | assert.isDefined(error, 'An error was thrown correctly'); 119 | }, 120 | "Join/Leave queue": function() { 121 | console.log('************* '+this.name+' **************'); 122 | noQueuesConfigured && this.skip("There are no Queues configured on the server"); 123 | var dfd = this.async(); 124 | var endpoint = ep.createRtcommEndpoint({webrtc: false, chat:true}); 125 | var initObj = null; 126 | var success = false; 127 | var self = this; 128 | var testConfig = config.clientConfig(); 129 | testConfig.userid = 'Agent'; 130 | var finish = dfd.callback(function(object) { 131 | console.log('************ Finish called w/ OBJECT: ',object); 132 | var e = false; 133 | try{ 134 | if (ep.listQueues().length > 0) { 135 | ep.joinQueue(ep.listQueues()[0]); 136 | } 137 | } catch(error) { 138 | e= true; 139 | } 140 | ep.leaveQueue(ep.listQueues()[0]); 141 | console.log('TEST -> userid: ' + endpoint.userid); 142 | assert.ok(/^Agent/.test(endpoint.userid)); 143 | console.log("TEST => ready: "+ endpoint); 144 | assert.ok(endpoint); 145 | console.log("JoinQueue was successful: "+ endpoint); 146 | assert.notOk(e); 147 | }); 148 | ep.init(testConfig,finish, finish); 149 | }, 150 | 151 | 'Send a start session to a queue': function () { 152 | console.log('************* '+this.name+' **************'); 153 | noQueuesConfigured && this.skip("There are no Queues configured on the server"); 154 | var dfd = this.async(5000); 155 | var error; 156 | var queue = ep.getAllQueues()[ep.listQueues()[0]]; 157 | console.log('>>>>>>> queue', queue.endpointID); 158 | ep.joinQueue(queue.endpointID); 159 | var publishTopic = getPublishTopic(queue.topic); 160 | console.log('publishTopic: ', publishTopic); 161 | var finish = dfd.callback( function(obj) { 162 | var endpoint = obj.endpoint; 163 | //obj should be a WebRTCConnection 164 | // and Source should match our topic we know... 165 | console.log('FINISH Called!', obj); 166 | assert.equal(endpoint._.activeSession.source, publishTopic+'/intern', 'source topic is right'); 167 | }); 168 | rtcommEP.on('session:alerting', finish); 169 | // Create a Message 170 | var msg = ep.dependencies.endpointConnection.createMessage('START_SESSION'); 171 | msg.protocols = ['chat']; 172 | msg.fromTopic = '/scott'; 173 | msg.sigSessID = '1111-fake-test-1111'; 174 | msg.transID = '2222-fake-test-2222'; 175 | msg.toEndpointID = 'queueid'; 176 | msg.appContext='rtcommTest' ; 177 | mqtt.publish(publishTopic+'/intern', msg); 178 | }, 179 | }); 180 | }); 181 | -------------------------------------------------------------------------------- /src/mock/MockRtcommServer.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a Paho Client and Mock Rtcomm Server for testing purposes only. It ONLY handles registration and 3 | * forwarding messages to another user. It does not fail gracefully yet. 4 | * 5 | */ 6 | 7 | var Paho = (function(){ 8 | console.log('************** Loading Mock Paho Client *****************'); 9 | var l = function(level) { 10 | return true; 11 | }; 12 | /*global mockMqtt:false*/ 13 | var mockMqtt = (function () { 14 | // This is a fake to make sure everythign is logged 15 | 16 | /* build a regular expression to match the topic */ 17 | var buildTopicRegex= function(topic) { 18 | // If it starts w/ a $ its a Shared subscription. Essentially: 19 | // $SharedSubscription/something// 20 | // We need to Remove the $-> // 21 | // /^\$.+\/\//, '' 22 | var regex = topic.replace(/^\$SharedSubscription.+\/\//, '\\/') 23 | .replace(/\/\+/g,'\\/.+') 24 | .replace(/\/#$/g,'($|\\/.+$)') 25 | .replace(/(\\)?\//g, function($0, $1){ 26 | return $1 ? $0 : '\\/'; 27 | }); 28 | 29 | // The ^ at the beginning in the return ensures that it STARTS w/ the topic passed. 30 | return new RegExp('^'+regex+'$'); 31 | }; 32 | 33 | var mqtt_clients = {}; 34 | var topics = {}; 35 | 36 | var findTopic = function(topic) { 37 | for (var t in topics) { 38 | //console.log('findTopic looking for '+topic+' against :'+t); 39 | if (buildTopicRegex(t).test(topic)){ 40 | // console.log('returning : ',t); 41 | return t; 42 | } 43 | } 44 | }; 45 | return { 46 | add : function(client) { 47 | mqtt_clients[client._.clientid] = client; 48 | return mqtt_clients[client._.clientid]; 49 | }, 50 | subscribe : function(topic, mqttClient) { 51 | // only one client is subscribed to a topic in this case... which is wrong... 52 | topics[topic] = mqttClient; 53 | }, 54 | send : function(message) { 55 | var topic = message.destinationName; 56 | console.log('mockMqtt.send() topic: '+topic +' message: '+ message); 57 | var matchedTopic = findTopic(topic); 58 | if (matchedTopic) { 59 | //console.log('mockMqtt.send() emitting on ', topics[matchedTopic]); 60 | // console.log('mockMqtt.send() message is', message); 61 | topics[matchedTopic].emit('message', message); 62 | } 63 | }, 64 | _getClients : function() { 65 | return mqtt_clients; 66 | }, 67 | _getSubscriptions : function () { 68 | return topics; 69 | } 70 | }; 71 | 72 | })(); 73 | 74 | 75 | var MockMqttClient = function MockMqttClient(server, port, clientid) { 76 | 77 | this._ = { 78 | server: server, 79 | port: port, 80 | clientid: clientid }; 81 | console.log('***************** Using a Mock MQTT Client *****************', this._); 82 | 83 | this.events = { 84 | 'message': [] 85 | }; 86 | 87 | this.onMessageArrived = function(message) { 88 | console.log('Not Defined', message); 89 | }; 90 | 91 | function connect(options){ 92 | l('DEBUG') && console.log('MockMqttClient.connect()', options); 93 | // Add to the server. 94 | mockMqtt.add(this); 95 | var self = this; 96 | var onSuccess = (options && options.onSuccess) ? options.onSuccess : function(){ console.log('MockMqttClient.connect onSuccess not defined');}; 97 | var onFailure = (options && options.onFailure) ? options.onFailure: function(){ console.log('MockMqttClient.connect onFailure not defined');}; 98 | self.on('message', self.onMessageArrived); 99 | onSuccess(); 100 | }; 101 | 102 | function send(message) { 103 | l('DEBUG') && console.log('MockMqttClient.send()', message); 104 | mockMqtt.send(message); 105 | }; 106 | 107 | function subscribe(topic) { 108 | l('DEBUG') && console.log('MockMqttClient.subscribe()', topic); 109 | var self = this; 110 | mockMqtt.subscribe(topic, self); 111 | }; 112 | 113 | function unsubscribe(topic) { 114 | l('DEBUG') && console.log('MockMqttClient.unsubscribe()', topic); 115 | }; 116 | 117 | function disconnect(topic) { 118 | l('DEBUG') && console.log('MockMqttClient.disconnect()', topic); 119 | }; 120 | 121 | this.connect= connect; 122 | this.subscribe= subscribe; 123 | this.unsubscribe= unsubscribe; 124 | this.send= send; 125 | this.disconnect= disconnect; 126 | }; 127 | 128 | /*global util:false */ 129 | MockMqttClient.prototype = util.RtcommBaseObject.extend({}); 130 | 131 | var MockMqttMessage = function MockMqttMessage(message) { 132 | return {destinationName: null, payloadString: message}; 133 | }; 134 | 135 | var MockRtcommServer = (function MockRtcommServer() { 136 | 137 | var rtcommTopicPath = "/rtcomm/"; 138 | var topics = { 139 | // Just the SERVICE_QUERY topic 140 | management: "", 141 | // The presence Topic 142 | sphere: "", 143 | // The main topic (connector) 144 | connector: "" 145 | // 146 | }; 147 | var registry = {}; 148 | var conn = null; 149 | 150 | function setTopics(rootTopic) { 151 | for (var key in topics) { 152 | topics[key] = rootTopic + key + "/#"; 153 | } 154 | } 155 | return { 156 | 157 | /** 158 | * config.rtcommTopicPath is only option 159 | */ 160 | 161 | init : function init(config) { 162 | console.log('********** Using a Mock Rtcomm Server ****************'); 163 | rtcommTopicPath = (config && config.rtcommTopicPath) ? config.rtcommTopicPath : rtcommTopicPath; 164 | setTopics(rtcommTopicPath); 165 | conn = new connection.MqttConnection({server:'localhost', port: 1883, 'rtcommTopicPath': rtcommTopicPath}); 166 | conn.setLogLevel('DEBUG'); 167 | conn.connect(); 168 | conn.subscribe(topics.management); 169 | conn.subscribe(topics.sphere); 170 | conn.subscribe(topics.connector); 171 | conn.on('message', function(message) { 172 | console.log('MockRtcommServer --> Received a message!', message); 173 | if (message) { 174 | if (message.content === '') { 175 | // If it is an empty message, its a unregister LWT, remove the entry. 176 | if (message.fromEndpoint) { 177 | delete registry[message.fromEndpointID]; 178 | } 179 | } else { 180 | var rtcommMessage = (typeof message.content === 'string')? JSON.parse(message.content): message.content; 181 | switch(rtcommMessage.method) { 182 | case 'DOCUMENT': 183 | console.log('DOCUMENT received'); 184 | registry[message.fromEndpointID] = rtcommMessage.addressTopic; 185 | break; 186 | case 'SERVICE_QUERY': 187 | console.log('SERVICE QUERY!'); 188 | // We should actually respond to this w/ mock data. 189 | break; 190 | default: 191 | console.log('DEFAULT: ', rtcommMessage); 192 | if(rtcommMessage.toEndpointID in registry) { 193 | conn.publish(registry[rtcommMessage.toEndpointID] +'/'+message.fromEndpointID, rtcommMessage); 194 | } else { 195 | console.error('toEndpointID not found, should send a Failure response'); 196 | } 197 | break; 198 | } 199 | } 200 | } 201 | }); 202 | }, 203 | getRegistry: function() { 204 | return registry; 205 | } 206 | }; 207 | })(); 208 | 209 | return { 210 | MQTT: { 211 | Client: MockMqttClient, 212 | Message: MockMqttMessage 213 | }, 214 | MockRtcommServer: MockRtcommServer 215 | }; 216 | })(); 217 | 218 | 219 | -------------------------------------------------------------------------------- /src/rtcomm/connection/MessageFactory.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 IBM Corp. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | /** @class 17 | * @memberof module:rtcomm.connector 18 | * @private 19 | */ 20 | /* Constructor */ 21 | 22 | var MessageFactory = (function (){ 23 | // base Template used for everything. 24 | var _baseHeaders = { 25 | 'rtcommVer': 'v1.0.0', 26 | 'method' : null, 27 | 'fromTopic': null 28 | }; 29 | 30 | var _optionalHeaders = { 31 | 'sigSessID':null, 32 | 'transID':null, 33 | 'reason': null, 34 | 'toEndpointID': null, 35 | 'appContext': null, 36 | 'holdTimeout': null, 37 | 'queuePosition': null 38 | }; 39 | 40 | // Override base headers and add new headers for the OUTBOUND message 41 | // If it is a transaction, it will have a transID 42 | 43 | var _messageTemplates = { 44 | 'SERVICE_QUERY' : { 45 | 'method': 'SERVICE_QUERY', 46 | 'transID': null, 47 | }, 48 | 'START_SESSION' : { 49 | 'method': 'START_SESSION', 50 | 'protocols': [], 51 | 'sigSessID':null, 52 | 'transID':null, 53 | 'toEndpointID': null, 54 | 'payload': null, 55 | }, 56 | 'REFER' : { 57 | 'method': 'REFER', 58 | 'transID':null, 59 | 'toEndpointID': null, 60 | 'details': null, 61 | }, 62 | 'STOP_SESSION' : { 63 | 'method': 'STOP_SESSION', 64 | 'sigSessID':null, 65 | 'payload': null, 66 | }, 67 | 'PRANSWER': { 68 | 'method': 'PRANSWER', 69 | 'protocols': [], 70 | 'payload': null 71 | }, 72 | // Message is generic and could be anything... 73 | 'MESSAGE':{ 74 | 'method':'MESSAGE', 75 | 'payload': null 76 | }, 77 | 'DOCUMENT': { 78 | 'method': 'DOCUMENT', 79 | 'type': 'ENDPOINT', 80 | 'addressTopic':null, 81 | 'appContext':null, 82 | 'state': null, 83 | 'alias': null, 84 | 'userDefines':[] 85 | }, 86 | 'DOCUMENT_REPLACED': { 87 | 'method': 'DOCUMENT_REPLACED' 88 | } 89 | }; 90 | 91 | var _baseResponseTemplate = { 92 | 'RESPONSE' : { 93 | 'method': 'RESPONSE', 94 | 'orig': null, 95 | 'transID': null, 96 | 'result': null, 97 | } 98 | }; 99 | 100 | var _responseTemplates = { 101 | 'SERVICE_QUERY' : { 102 | 'orig': 'SERVICE_QUERY', 103 | 'services':null 104 | }, 105 | 'START_SESSION' : { 106 | 'orig': 'START_SESSION', 107 | 'protocols': [], 108 | 'sigSessID': null, 109 | 'result': null, 110 | 'payload': null, 111 | 'transID': null, 112 | }, 113 | 'REFER' : { 114 | 'orig': 'REFER', 115 | 'transID':null, 116 | 'result': null, 117 | } 118 | }; 119 | 120 | function getMessageTemplate(type) { 121 | var template = {}; 122 | objMerge(template,_baseHeaders); 123 | if (_messageTemplates.hasOwnProperty(type)) { 124 | objMerge(template,_messageTemplates[type]); 125 | return template; 126 | } else { 127 | console.error('Message Type: '+type+' Not found!'); 128 | return null; 129 | } 130 | } 131 | 132 | function getResponseTemplate(type) { 133 | var template = {}; 134 | objMerge(template,_baseHeaders); 135 | objMerge(template, _baseResponseTemplate.RESPONSE); 136 | if (_responseTemplates.hasOwnProperty(type)) { 137 | objMerge(template,_responseTemplates[type]); 138 | return template; 139 | } else { 140 | console.error('Message Type: '+type+' Not found!'); 141 | return null; 142 | } 143 | } 144 | 145 | function objMerge(obj1,obj2) { 146 | // Take Right Object and place on top of left object. 147 | for (var key in obj2) { 148 | if (obj2.hasOwnProperty(key)) { 149 | obj1[key] = obj2[key]; 150 | } 151 | } 152 | } 153 | 154 | var SigMessage = function SigMessage(template) { 155 | if (template) { 156 | for (var key in template) { 157 | if (template.hasOwnProperty(key)) { 158 | this[key] = template[key]; 159 | } 160 | } 161 | } 162 | }; 163 | 164 | SigMessage.prototype = { 165 | /** Convert message to a specific JSON object 166 | * 167 | * @returns {JSON} 168 | * 169 | */ 170 | toJSON: function() { 171 | var obj = {}; 172 | for (var key in this) { 173 | if (this.hasOwnProperty(key)) { 174 | obj[key] = this[key]; 175 | } 176 | } 177 | return obj; 178 | }, 179 | /* Override */ 180 | toString: function() { 181 | // When converted to a string, we return a SPECIFIC object content that matches the Message Template 182 | return JSON.stringify(this.toJSON()); 183 | } 184 | }; 185 | 186 | function createResponse(type) { 187 | var message = null; 188 | var template = getResponseTemplate(type); 189 | if (template) { 190 | message = new SigMessage(template); 191 | } else { 192 | throw new TypeError('Invalid Message type:'+type+', should be one of: '+ Object.keys(_messageTemplates)); 193 | } 194 | return message; 195 | } 196 | 197 | function createMessage(type) { 198 | type = type || 'MESSAGE'; 199 | var message = null; 200 | var template = getMessageTemplate(type); 201 | if (template) { 202 | message = new SigMessage(template); 203 | } else { 204 | throw new TypeError('Invalid Message type:'+type+', should be one of: '+ Object.keys(_messageTemplates)); 205 | } 206 | return message; 207 | } 208 | 209 | function isValid(message) { 210 | try { 211 | var tmpmsg = cast(message); 212 | } catch(e) { 213 | // unable to cast, not a good message. 214 | return false; 215 | } 216 | return true; 217 | } 218 | 219 | function cast(obj) { 220 | /*global l:false*/ 221 | l('TRACE') && console.log('MessageFactory.cast() Attempting to cast message: ', obj); 222 | 223 | if ( typeof obj === 'string') { 224 | l('TRACE') && console.log('MessageFactory.cast() It is a string... ', obj); 225 | /* if its a 'STRING' then convert to a object */ 226 | try { 227 | obj = JSON.parse(obj); 228 | } catch (e) { 229 | throw new TypeError('Unable to cast object as a SigMessage'); 230 | } 231 | l('TRACE') && console.log('MessageFactory.cast() After JSON.parse... ', obj); 232 | } 233 | var template = null; 234 | if (obj.method) { 235 | template = (obj.method === 'RESPONSE') ? getResponseTemplate(obj.orig):getMessageTemplate(obj.method); 236 | } else { 237 | throw new TypeError('Unable to cast object as a SigMessage'); 238 | } 239 | var castedMessage = new SigMessage(template); 240 | for (var prop in obj){ 241 | // console.log("key:" + prop + " = " + obj[prop]); 242 | if (template.hasOwnProperty(prop) || _optionalHeaders.hasOwnProperty(prop)){ 243 | // console.log("key:" + prop + " = " + obj[prop]); 244 | castedMessage[prop] = obj[prop]; 245 | } else { 246 | l('DEBUG') && console.log('MessageFactory.cast() dropped header: '+prop); 247 | } 248 | } 249 | l('TRACE') && console.log('MessageFactory.cast() returning casted message:', castedMessage); 250 | return castedMessage; 251 | } 252 | 253 | return { 254 | createMessage: createMessage, 255 | createResponse: createResponse, 256 | cast : cast 257 | }; 258 | })(); 259 | 260 | exports.MessageFactory = MessageFactory; 261 | -------------------------------------------------------------------------------- /tests/functional/SessionEndpoint.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 IBM Corp. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | define([ 17 | 'intern', 18 | 'intern!object', 19 | 'intern/chai!assert', 20 | 'intern/node_modules/dojo/Promise', 21 | (typeof window === 'undefined' && global) 22 | ?'intern/dojo/node!../support/mqttws31_shim': 23 | 'bower_components/bower-mqttws/mqttws31', 24 | 'support/config', 25 | 'bower_components/webrtc-adapter/adapter', 26 | 'umd/rtcomm/EndpointProvider', 27 | 'support/rtcommFatUtils' 28 | ], function (intern, registerSuite, assert, Deferred, globals, config, adapter, EndpointProvider,Fat) { 29 | var suiteName = Fat.createSuiteName("FVT: SessionEndpoint"); 30 | var DEBUG = (intern.args.DEBUG === 'true')? true: false; 31 | var SKIP_ALL=false; 32 | // anything in here will get destroyed (but not recreated) in beforeEach; 33 | var g ={}; 34 | var destroy = function() { 35 | Object.keys(g).forEach(function(key) { 36 | if (typeof g[key].destroy === 'function' ) { 37 | g[key].destroy(); 38 | delete g[key]; 39 | } 40 | }); 41 | }; 42 | // used to run this Suite 2 times (one w/ rtcomm server & 1 w/out) 43 | var getConfig = function getConfig(id) { 44 | var c = config.clientConfig(id); 45 | return c; 46 | } 47 | // Timings 48 | var T1 = 3000; // How long we wait to setup, before sending messages. 49 | var T2 = T1 + 3000; // How long we wait to check results 50 | var T3 = T2 +3000; // How long we wait to timeout test. 51 | 52 | var createAndInitTwoProviders = function createAndInitTwoProviders(cfg1, cfg2) { 53 | var p = new Promise( 54 | function(resolve, reject){ 55 | Fat.createProvider(cfg1, DEBUG).then( function(EP) { 56 | Fat.createProvider(cfg2, DEBUG) 57 | .then( function(EP2) { 58 | // Wait 1 second to resolve 59 | setTimeout(function() { 60 | resolve({provider1: EP, provider2: EP2}); 61 | },T1); 62 | }) 63 | .catch(function(message){ 64 | reject(message); 65 | }); 66 | }).catch(function(message){ 67 | reject(message); 68 | }); 69 | }); 70 | return p; 71 | }; 72 | 73 | registerSuite({ 74 | name: suiteName, 75 | setup: function() { 76 | console.log('************* SETUP: '+this.name+' **************'); 77 | }, 78 | teardown: function() { 79 | console.log('************* TEARDOWN: '+this.name+' **************'); 80 | destroy(); 81 | }, 82 | beforeEach: function() { 83 | destroy(); 84 | }, 85 | "SessionEndpoint(No protocols) A calls B": function() { 86 | console.log('************* '+this.name+' **************'); 87 | // SKIP_ALL && this.skip(false); 88 | var dfd = this.async(T2); 89 | // Our endpoints 90 | var ep1; 91 | var ep2; 92 | var finish = dfd.callback(function(object){ 93 | console.log("******************Asserting now...***********************"); 94 | console.log('endpoint1: ',ep1); 95 | console.log('endpoint2: ',ep2); 96 | assert.ok(ep1_trying, 'Caller generated trying event'); 97 | assert.ok(ep1_ringing, 'Caller generated ringing event'); 98 | assert.ok(ep2_alerting, 'Callee generated alerting event'); 99 | assert.ok(ep1.sessionStarted()); 100 | assert.ok(ep2.sessionStarted()); 101 | }); 102 | 103 | var ep1_trying = false; 104 | var ep1_ringing= false; 105 | var ep2_alerting= false; 106 | // receive PRANSWER --> ringing 107 | // receive ANSWER --> started 108 | // ep2(callee) 109 | // receive call --> alerting 110 | // send ANSWER --> started 111 | var cfg1 = getConfig('testuser1'); 112 | var cfg2 = getConfig('testuser2'); 113 | createAndInitTwoProviders(cfg1,cfg2) 114 | .then(function(obj){ 115 | var EP1 = g.EP1 = obj.provider1; 116 | var EP2 = g.EP2 = obj.provider2; 117 | DEBUG && EP1.setLogLevel('DEBUG'); 118 | DEBUG && EP2.setLogLevel('DEBUG'); 119 | console.log('>>>> EP1:', EP1.currentState()); 120 | console.log('>>>> EP2:', EP2.currentState()); 121 | ep1 = EP1.getSessionEndpoint(); 122 | ep2 = EP2.getSessionEndpoint(); 123 | ep1.on('session:ringing', function() { ep1_ringing = true}); 124 | ep1.on('session:trying', function() { ep1_trying = true}); 125 | ep1.on('session:started', finish); 126 | ep2.on('session:alerting', function(obj) { 127 | ep2_alerting = true; 128 | console.log('>>>>TEST accepting call'); 129 | setTimeout(function() { 130 | ep2.accept(); 131 | },1000); 132 | }); 133 | ep1.connect(cfg2.userid); 134 | }); 135 | }, 136 | "in Browser A calls B(disconnect while ringing)": function() { 137 | console.log('************* '+this.name+' **************'); 138 | // SKIP_ALL && this.skip(false); 139 | var dfd = this.async(T2); 140 | // Our endpoints 141 | var ep1; 142 | var ep2; 143 | 144 | var finish = dfd.callback(function(object){ 145 | console.log("******************Asserting now...***********************"); 146 | console.log('endpoint1: ',ep1); 147 | console.log('endpoint2: ',ep2); 148 | assert.notOk(ep1_failed, 'Caller generated failed event'); 149 | assert.notOk(ep2_failed, 'Callee generated failed event'); 150 | assert.notOk(ep1_started, 'Caller generated started event'); 151 | assert.notOk(ep2_started, 'Callee generated started event'); 152 | assert.ok(ep1_ringing, 'Caller generated ringing event'); 153 | assert.ok(ep2_alerting, 'Callee generated alerting event'); 154 | }); 155 | 156 | var ep1_trying = false; 157 | var ep1_ringing= false; 158 | var ep2_stopped= false; 159 | var ep1_stopped = false; 160 | var ep2_alerting= false; 161 | var ep1_failed= false; 162 | var ep2_failed= false; 163 | var ep1_started= false; 164 | var ep2_started= false; 165 | 166 | 167 | var cfg1 = getConfig('testuser1'); 168 | var cfg2 = getConfig('testuser2'); 169 | createAndInitTwoProviders(cfg1,cfg2) 170 | .then(function(obj){ 171 | var EP1 = g.EP1 = obj.provider1; 172 | var EP2 = g.EP2 = obj.provider2; 173 | ep1 = EP1.getSessionEndpoint(); 174 | ep2 = EP2.getSessionEndpoint(); 175 | // receive PRANSWER --> ringing // 176 | // // receive ANSWER --> started 177 | // ep2(callee) 178 | // receive call --> alerting 179 | // send ANSWER --> started 180 | // 181 | ep1.on('session:ringing', function() { 182 | console.log('>>> ep1 session:ringing'); 183 | ep1_ringing = true;}); 184 | ep1.on('session:failed', function() { ep1_failed= true}); 185 | ep2.on('session:failed', function() { ep2_failed= true}); 186 | ep1.on('session:trying', function() { ep1_trying = true}); 187 | ep1.on('session:started', function() { ep1_started = true}); 188 | ep2.on('session:started', function() { ep2_started = true}); 189 | ep1.on('session:stopped', function() {console.log('EP1 ***session:stopped'); ep1_stopped = true;}); 190 | ep2.on('session:stopped', finish ); 191 | ep2.on('session:alerting', function(obj) { 192 | // At this state, cancel the call. 193 | ep2_alerting = true; 194 | setTimeout(function() { 195 | console.log('********* Disconnecting call **************'); 196 | ep1.disconnect(); 197 | },1000); 198 | }); 199 | ep1.connect(cfg2.userid); 200 | }); 201 | }, 202 | }); 203 | }); 204 | 205 | 206 | -------------------------------------------------------------------------------- /src/rtcomm/EndpointProvider/endpoints/RtcommEndpoint.js: -------------------------------------------------------------------------------- 1 | var RtcommEndpoint = (function invocation() { 2 | /** 3 | * @memberof module:rtcomm.EndpointProvider 4 | * @description 5 | * This object can only be created with the {@link module:rtcomm.EndpointProvider#getRtcommEndpoint|getRtcommEndpoint} function. 6 | *

7 | * The RtcommEndpoint object provides an interface for the UI Developer to attach 8 | * Video and Audio input/output. Essentially mapping a broadcast stream(a MediaStream that 9 | * is intended to be sent) to a RTCPeerConnection output stream. When an inbound stream 10 | * is added to a RTCPeerConnection, then this also informs the RTCPeerConnection 11 | * where to send that stream in the User Interface. 12 | *

13 | * See the example under {@link module:rtcomm.EndpointProvider#getRtcommEndpoint|getRtcommEndpoint} 14 | * @constructor 15 | * 16 | * @extends module:rtcomm.SessionEndpoint 17 | */ 18 | var RtcommEndpoint = function RtcommEndpoint(config) { 19 | /** 20 | * @typedef {object} module:rtcomm.RtcommEndpoint~config 21 | * 22 | * @property {boolean} [autoEnable=false] Automatically enable webrtc/chat upon connect if feature is supported (webrtc/chat = true); 23 | * @property {string} [userid=null] UserID the endpoint will use (generally provided by the EndpointProvider 24 | * @property {string} [appContext=null] UI Component to attach outbound media stream 25 | * @property {string} [ringtone=null] Path to a ringtone to play when we are ringing on inbound callh 26 | * @property {string} [ringbacktone=null] path to a ringbacktone to play on outbound call 27 | * @property {boolean} [webrtc=true] Whether the endpoint supports webrtc 28 | * @property {module:rtcomm.RtcommEndpoint.WebRTCConnection~webrtcConfig} webrtcConfig - Object to configure webrtc with (rather than on enable) 29 | * @property {boolean} [chat=true] Whether the endpoint supports chat 30 | * @property {module:rtcomm.RtcommEndpoint.WebRTCConnection~chatConfig} chatConfig - object to pre-configure chat with (rather than on enable) 31 | * @property {module:rtcomm.EndpointProvider} [parent] - set the parent Should be done automatically. 32 | * 33 | */ 34 | var defaultConfig = { 35 | // if a feature is supported, enable by default. 36 | autoEnable: false, 37 | ignoreAppContext: true, 38 | appContext: null, 39 | userid: null, 40 | ringtone: null, 41 | ringbacktone: null, 42 | // Always shold be true 43 | generic_message: true, 44 | chat: true, 45 | chatConfig: {}, 46 | webrtc: true, 47 | webrtcConfig: {} 48 | }; 49 | 50 | 51 | function addChatHandlers(ep) { 52 | var chat = ep.chat; 53 | // Configure chat event handling... 54 | // 55 | chat.on('ringing', function(event_obj) { 56 | (ep.lastEvent !== 'session:ringing') && ep.emit('session:ringing'); 57 | }); 58 | ep.createEvent('chat:message'); 59 | chat.on('message', function(message) { 60 | // Should be '{message: blah, from: blah}' 61 | // This is for backward compatibility 62 | ep.emit('chat:message', {'message':message}); 63 | }); 64 | chat.on('alerting', function(message) { 65 | l('DEBUG') && console.log('RtcommEndpoint emitting session:alerting event'); 66 | var obj = {}; 67 | obj.message = message; 68 | obj.protocols = 'chat'; 69 | // Have to do setState here because the ep state needs to change. 70 | (ep.lastEvent !== 'session:alerting') && ep.setState('session:alerting', obj); 71 | }); 72 | ep.createEvent('chat:connected'); 73 | chat.on('connected', function() { 74 | ep.emit('chat:connected'); 75 | }); 76 | ep.createEvent('chat:disconnected'); 77 | chat.on('disconnected', function() { 78 | ep.emit('chat:disconnected'); 79 | }); 80 | }; 81 | 82 | function addWebrtcHandlers(ep) { 83 | // Webrtc protocol... 84 | var webrtc = ep.webrtc; 85 | 86 | webrtc.on('ringing', function(event_obj) { 87 | l('DEBUG') && console.log("on ringing - play a ringback tone ", ep._.ringbackTone); 88 | ep._playRingback(); 89 | (ep.lastEvent !== 'session:ringing') && ep.emit('session:ringing'); 90 | }); 91 | 92 | webrtc.on('trying', function(event_obj) { 93 | l('DEBUG') && console.log("on trying - play a ringback tone ", ep._.ringbackTone); 94 | ep._playRingback(); 95 | (ep.lastEvent !== 'session:trying') && ep.emit('session:trying'); 96 | }); 97 | 98 | webrtc.on('alerting', function(event_obj) { 99 | ep._playRingtone(); 100 | (ep.lastEvent !== 'session:alerting') && ep.emit('session:alerting', { protocols: 'webrtc'}); 101 | }); 102 | 103 | ep.createEvent('webrtc:connecting'); 104 | webrtc.on('connecting', function(event_obj) { 105 | l('DEBUG') && console.log(ep+" webrtc.connecting - stop ringing "); 106 | ep._stopRing(); 107 | ep.emit('webrtc:connecting'); 108 | }); 109 | 110 | ep.createEvent('webrtc:connected'); 111 | webrtc.on('connected', function(event_obj) { 112 | l('DEBUG') && console.log("on connected - stop ringing "); 113 | ep._stopRing(); 114 | ep.emit('webrtc:connected'); 115 | }); 116 | ep.createEvent('webrtc:disconnected'); 117 | webrtc.on('disconnected', function(event_obj) { 118 | l('DEBUG') && console.log("on disconnected - stop ringing "); 119 | ep._stopRing(); 120 | ep.emit('webrtc:disconnected'); 121 | }); 122 | ep.createEvent('webrtc:remotemuted'); 123 | webrtc.on('remotemuted', function(event_obj) { 124 | ep.emit('webrtc:remotemuted', event_obj); 125 | }); 126 | }; 127 | 128 | function addGenericMessageHandlers(ep) { 129 | ep.createEvent('onetimemessage'); 130 | ep.createEvent('generic_message:message'); 131 | ep.generic_message.on('message', function(event_obj) { 132 | console.log('eventObject?', event_obj); 133 | // This shoudl be deprecated (onetimemessage) that is. 134 | var deprecatedEvent = { 135 | 'onetimemessage': event_obj.message 136 | }; 137 | ep.emit('onetimemessage', deprecatedEvent); 138 | ep.emit('generic_message:message', event_obj); 139 | }); 140 | }; 141 | 142 | config = util.combineObjects(config, defaultConfig); 143 | // Call the Super Constructor 144 | SessionEndpoint.call(this, config); 145 | // Add the protocols 146 | this.addProtocol(new ChatProtocol()); 147 | this.addProtocol(new WebRTCConnection(this)); 148 | this.addProtocol(new GenericMessageProtocol()); 149 | // Add the handlers to the protocols; 150 | addChatHandlers(this); 151 | addWebrtcHandlers(this); 152 | addGenericMessageHandlers(this); 153 | if (this.config.autoEnable) { 154 | this.config.chat && this.chat.enable(); 155 | this.config.webrtc && this.webrtc.enable(); 156 | }; 157 | 158 | this.config.generic_message && this.generic_message.enable(); 159 | this.config.chat && this.chat.enable(); 160 | 161 | // WebRTC Specific configuration. 162 | // TODO: MOve to the webrtc protocol 163 | this._.ringTone = (this.config.ringtone) ? util.Sound(this.config.ringtone).load() : null; 164 | this._.ringbackTone = (this.config.ringbacktone) ? util.Sound(this.config.ringbacktone).load() : null; 165 | this._.inboundMedia = null; 166 | this._.attachMedia = false; 167 | this._.localStream = null; 168 | this._.media = { 169 | In: null, 170 | Out: null 171 | }; 172 | 173 | } // End of Constructor 174 | 175 | RtcommEndpoint.prototype = Object.create(SessionEndpoint.prototype); 176 | RtcommEndpoint.prototype.constructor = RtcommEndpoint; 177 | 178 | // RtcommEndpoint Specific additions to the SessioNEndpoint 179 | RtcommEndpoint.prototype._playRingtone = function() { 180 | this._.ringTone && this._.ringTone.play(); 181 | }; 182 | RtcommEndpoint.prototype._playRingback = function() { 183 | this._.ringbackTone && this._.ringbackTone.play(); 184 | }; 185 | 186 | RtcommEndpoint.prototype._stopRing = function() { 187 | l('DEBUG') && console.log(this + '._stopRing() should stop ring if ringing... ', this._.ringbackTone); 188 | l('DEBUG') && console.log(this + '._stopRing() should stop ring if ringing... ', this._.ringTone); 189 | this._.ringbackTone && this._.ringbackTone.playing && this._.ringbackTone.stop(); 190 | this._.ringTone && this._.ringTone.playing && this._.ringTone.stop(); 191 | }; 192 | 193 | /* deprecated , use RtcommEndpoint.generic-message.send(message) instead */ 194 | RtcommEndpoint.prototype.sendOneTimeMessage = function sendOneTimeMessage(message) { 195 | this.generic_message.send(message); 196 | }; 197 | 198 | return RtcommEndpoint; 199 | })(); 200 | --------------------------------------------------------------------------------