diff options
Diffstat (limited to 'www')
| -rw-r--r-- | www/js/controllers.js | 2 | ||||
| -rw-r--r-- | www/lib/ng-websocket/.bower.json | 43 | ||||
| -rw-r--r-- | www/lib/ng-websocket/Gulpfile.js | 15 | ||||
| -rw-r--r-- | www/lib/ng-websocket/LICENSE | 21 | ||||
| -rw-r--r-- | www/lib/ng-websocket/README.md | 1010 | ||||
| -rw-r--r-- | www/lib/ng-websocket/bower.json | 32 | ||||
| -rw-r--r-- | www/lib/ng-websocket/ng-websocket.js | 370 | ||||
| -rw-r--r-- | www/lib/ng-websocket/package.json | 31 |
8 files changed, 1523 insertions, 1 deletions
diff --git a/www/js/controllers.js b/www/js/controllers.js index e6b1b9ce..80afa2fe 100644 --- a/www/js/controllers.js +++ b/www/js/controllers.js @@ -4,7 +4,7 @@ -angular.module('zmApp.controllers', ['ionic', 'ngCordova', 'ng-mfb','angularCircularNavigation', 'jett.ionic.content.banner', 'ionic-pullup' ]) +angular.module('zmApp.controllers', ['ionic', 'ngCordova', 'ng-mfb','angularCircularNavigation', 'jett.ionic.content.banner', 'ionic-pullup', 'ngWebsocket' ]) .controller('zmApp.BaseController', function($scope, $ionicSideMenuDelegate, $ionicPlatform, $timeout, $rootScope) { $scope.openMenu = function () { diff --git a/www/lib/ng-websocket/.bower.json b/www/lib/ng-websocket/.bower.json new file mode 100644 index 00000000..ce61f3c1 --- /dev/null +++ b/www/lib/ng-websocket/.bower.json @@ -0,0 +1,43 @@ +{ + "name": "ng-websocket", + "version": "0.2.1", + "authors": [ + "Vincenzo (Wilk) Ferrari <wilk3ert@gmail.com>" + ], + "description": "AngularJS HTML5 WebSocket powerful library", + "main": "ng-websocket.js", + "keywords": [ + "angular", + "angularjs", + "websocket", + "ng", + "html5", + "service", + "provider" + ], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": { + "angular": "~1.3.2" + }, + "devDependencies": { + "angular-mocks": "~1.3.2" + }, + "homepage": "https://github.com/wilk/ng-websocket", + "_release": "0.2.1", + "_resolution": { + "type": "version", + "tag": "v0.2.1", + "commit": "09f128e2bf3c485d016ab1f5d0c263b379862c9e" + }, + "_source": "git://github.com/wilk/ng-websocket.git", + "_target": "~0.2.1", + "_originalSource": "ng-websocket", + "_direct": true +}
\ No newline at end of file diff --git a/www/lib/ng-websocket/Gulpfile.js b/www/lib/ng-websocket/Gulpfile.js new file mode 100644 index 00000000..c3a248e2 --- /dev/null +++ b/www/lib/ng-websocket/Gulpfile.js @@ -0,0 +1,15 @@ +var gulp = require('gulp'), + karma = require('gulp-karma'); + +gulp.task('test', function () { + return gulp.src([ + 'bower_components/angular/angular.js', + 'bower_components/angular-mocks/angular-mocks.js', + 'ng-websocket.js', + 'test/unit/**/*.js' + ]) + .pipe(karma({ + configFile: 'test/karma.conf.js', + action: 'run' + })); +});
\ No newline at end of file diff --git a/www/lib/ng-websocket/LICENSE b/www/lib/ng-websocket/LICENSE new file mode 100644 index 00000000..f0042000 --- /dev/null +++ b/www/lib/ng-websocket/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Vincenzo Ferrari + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/www/lib/ng-websocket/README.md b/www/lib/ng-websocket/README.md new file mode 100644 index 00000000..946bea4c --- /dev/null +++ b/www/lib/ng-websocket/README.md @@ -0,0 +1,1010 @@ +ng-websocket +============ + +**AngularJS HTML5 WebSocket** powerful wrapper module to develop with ease and fun! + +# Index + + - [Introduction](#introduction) + - [Requirements](#requirements) + - [Installation](#installation) + - [Usage](#usage) + - [Tutorial](#tutorial) + - [Features](#features) + - [Lazy Initialization](#lazy) + - [Auto Reconnection](#reconnect) + - [Enqueue Unsent Messages](#enqueue) + - [Mock Websocket Server](#mock) + - [Testing](#testing) + - [API](#api) + - [$websocketProvider](#websocketProvider) + - [$setup](#setup) + - [$websocket](#websocket) + - [$new](#new) + - [$get](#get) + - [ngWebsocket](#ngWebsocket) + - [Constructor](#constructor) + - [Constants](#constants) + - [Events](#events) + - [$on](#on) + - [$un](#un) + - [$emit](#emit) + - [$open](#open) + - [$close](#close) + - [$status](#status) + - [$ready](#ready) + - [$mockup](#mockup) + - [$$mockWebsocket](#mockWebsocket) + - [Contribute](#contribute) + - [License](#license) + +# Introduction + +**ngWebsocket** is a library that provides a provider and a service to handle **HTML5 WebSocket** with ease +in pure **AngularJS** style! +The idea behind this module is to give four kinds of object to handle websockets: + + - **$websocketProvider**: the provider is on top of usage. In fact, you can setup a general configuration for each ngWebsocket you're going to create + - **$websocket**: following an Angular service that lets you to handle different websocket instance among your application + - **ngWebsocket**: an instance of the HTML5 WebSocket wrapper (this is actually the core of this module): it provides lots of feature to work with websockets + - **$$mockWebsocket**: this is a smart implementation of a websocket backend that lets you to developer and test your app without a real responding server + +For each of these objects an API is available and fully documented in this document. + +# Requirements + +The only requirement needed is [AngularJS](https://angularjs.org/) that you can install it via [Bower](http://bower.io/). + +# Installation + +Use [Bower](http://bower.io/) to install this module: + +```bash +$ bower install ng-websocket +``` + +Or simply `git clone` the repo and install the dependencies with [NPM](https://www.npmjs.org/): + +```bash +$ git clone https://github.com/wilk/ngWebsocket +$ cd ngWebsocket +$ npm install +``` + +# Usage + +After the [Installation](#installation), require it in your Angular application. + +Firstly, in your `index.html`: + +```html +<html> + <head> + <script src="bower_components/ng-websocket/ng-websocket.js"></script> + </head> +</html> +``` + +Then, in your Angular application definition (assumed `app.js`): + +```javascript + 'use strict'; + + angular.module('MyApp', ['ngWebsocket']); +``` + +Now, you're ready to use it! + +# Tutorial + +Need to use HTML5 WebSocket to build your cool web application, huh? +No problem, dude! Check this out! + +```javascript +'use strict'; + +angular.module('MyCoolWebApp', ['ngWebsocket']) + .run(function ($websocket) { + var ws = $websocket.$new('ws://localhost:12345'); // instance of ngWebsocket, handled by $websocket service + + ws.$on('$open', function () { + console.log('Oh my gosh, websocket is really open! Fukken awesome!'); + + ws.$emit('ping', 'hi listening websocket server'); // send a message to the websocket server + + var data = { + level: 1, + text: 'ngWebsocket rocks!', + array: ['one', 'two', 'three'], + nested: { + level: 2, + deeper: [{ + hell: 'yeah' + }, { + so: 'good' + }] + } + }; + + ws.$emit('pong', data); + }); + + ws.$on('pong', function (data) { + console.log('The websocket server has sent the following data:'); + console.log(data); + + ws.$close(); + }); + + ws.$on('$close', function () { + console.log('Noooooooooou, I want to have more fun with ngWebsocket, damn it!'); + }); + }); +``` + +Easy, right? + +Well, let's chain it! + +```javascript +'use strict'; + +angular.module('MyCoolChainedWebApp', ['ngWebsocket']) + .run(function ($websocket) { + var ws = $websocket.$new('ws://localhost:12345') + .$on('$open', function () { + console.log('Oh my gosh, websocket is really open! Fukken awesome!'); + + var data = { + level: 1, + text: 'ngWebsocket rocks!', + array: ['one', 'two', 'three'], + nested: { + level: 2, + deeper: [{ + hell: 'yeah' + }, { + so: 'good' + }] + } + }; + + ws.$emit('ping', 'hi listening websocket server') // send a message to the websocket server + .$emit('pong', data); + }) + .$on('pong', function (data) { + console.log('The websocket server has sent the following data:'); + console.log(data); + + ws.$close(); + }) + .$on('$close', function () { + console.log('Noooooooooou, I want to have more fun with ngWebsocket, damn it!'); + }); + }); +``` + +Your back-end team is lazy? No problem: we can do it on our own! + +```javascript +'use strict'; + +angular.module('MyIndipendentCoolWebApp', ['ngWebsocket']) + .run(function ($websocket) { + var ws = $websocket.$new({ + url: 'ws://localhost:12345', + mock: { + fixtures: { + 'custom event': { + data: 'websocket server mocked response' + }, + 'another event': { + data: { + damn: 'dude', + that: 'is awesome!' + } + } + } + } + }); + + ws.$on('$open', function () { + ws.$emit('an event', 'a parrot response') // by default it responde with the same incoming data + .$emit('custom event') // otherwise it uses the given fixtures + .$emit('another event'); // even for objects + }) + .$on('an event', function (message) { + console.log(message); // it prints 'a parrot response' + }) + .$on('custom event', function (message) { + console.log(message); // it prints 'websocket server mocked response' + }) + .$on('another event', function (message) { + console.log(message); // it prints the object {damn: 'dude', that: 'is awesome!'} + }); + }); +``` + +# Features + +ngWebsocket comes from Italy with lots of interesting stuff, folks! +Why not just a wrapper? Because we can do more with happiness and fun! + +So, let's discover the awesome features list! + +## Lazy + +Using basic HTML5 WebSocket object, you experienced that the connection is open immediately, just after the websocket is created with **new** constructor. +By default, the same behaviour is used by ngWebsocket but you can simply change it with this powerful feature: + +```javascript +angular.run(function ($websocket, $timeout) { + var ws = $websocket.$new({ + url: 'ws://localhost:12345', + lazy: true + }); + + ws.$on('$open', function () { + console.log('The ngWebsocket has open!'); // It will print after 5 (or more) seconds + }); + + $timeout(function () { + ws.$open(); // Open the connction only at this point. It will fire the '$open' event + }, 5000); +}); +``` + +With [$websocket.$open](#open) function, you can open the connection when you want, especially after the coffee break. + +**Default: disabled** + +## Reconnect + +Ok, your websocket connection went down due to a bad wifi connection and you don't want to make another connection +manually, right? +So, what about an automated feature that do this for you? + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new({ + url: 'ws://localhost:12345', + reconnect: true // it will reconnect after 2 seconds + }); + + ws.$on('$open', function () { + console.log('Here we are and I\'m pretty sure to get back here for another time at least!'); + }) + .$on('$close', function () { + console.log('Got close, damn you silly wifi!'); + }); +}); +``` + +With this feature, if the connection goes down, it will open again after 2 seconds by default. +If you need to get the connection back in fewer time, just use the **reconnectInterval** time slice: + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new({ + url: 'ws://localhost:12345', + reconnect: true, + reconnectInterval: 500 // it will reconnect after 0.5 seconds + }); + + ws.$on('$open', function () { + console.log('Here we are and I\'m pretty sure to get back here for another time at least!'); + }) + .$on('$close', function () { + console.log('Got close, damn you silly wifi!'); + }); +}); +``` + +**Pay attention, good sir**: if you close the ngWebsocket with the [**$close**](#close) method, it won't get the connection back +until the [**$open**](#open) is invoked! + +**Default: enabled** + +## Enqueue + +From great powers come great responsability. Keep this in mind while reading this feature. + +Sometimes, it would be useful if someone save our websocket communication, especially when the connection is down. +With this powerful feature, it's possible to store every unsent message in a queue and then flush them just the connection get up again. + +How? Enabling enqueue feature, of course! + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new({ + url: 'ws://localhost:12345', + lazy: true, + enqueue: true + }); + + ws.$emit('dude event', 'hi dude!'); // this message couldn't be forwarded because of the lazy property (the websocket is still closed) + + ws.$on('$open', function () { + console.log('I\'m sure the above message gets sent before this log is printed in the console ;)'); + }); + + ws.$open(); // when the websocket gets open, flushes every message stored in the internal queue +}); +``` + +**BUT** this means that each message is stored into a memory queue and it can get really big, especially if your application sends many messages in a short time slice. + +**Default: disabled** + +## Mock + +Dulcis in fundo, a websocket server implementation to use and test your application, without a real websocket server listening! +Yep, you well heard! + +Think about this situation: you're developing the front-end part of your company application and the backend team is lazy (because every developer is lazy), +so you couldn't start writing your section because you need to send/retrieve data to/from the server. + +No problem, you can! + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new({ + url: 'ws://localhost:12345', + mock: true + }); + + ws.$on('$open', function () { + ws.$emit('hi', 'dude'); + }) + .$on('hi', function (message) { + console.log(message); // it prints 'dude' + }); +}); +``` + +By default, the mock feature simulate a parrot websocket server: this means that every message sent with +a certain event, will have a response with the same structure, with the same event and the same data. + +However, you can setup some fixtures that simulate what your lazy back-end team is going to do after beer time: + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new({ + url: 'ws://localhost:12345', + mock: { + fixtures: { + hi: { + data: 'dude, this is a custom message!' + } + } + } + }); + + ws.$on('$open', function () { + ws.$emit('hi'); + }) + .$on('hi', function (message) { + console.log(message); // it prints 'dude, this is a custom message' + }); +}); +``` + +**Default: disabled** + +# Testing + +This module uses [Karma](http://karma-runner.github.io/0.12/index.html) with [Jasmine](http://jasmine.github.io/) for unit testing, so before launching any test check out if all dependencies are correctly installed: + +```bash +$ npm install +``` + +After that, launch the test: + +```bash +$ npm test +``` + +# API + +ngWebsocket APIs are composed by four different modules: + + - **$websocketProvider** + - **$websocket** + - **ngWebsocket** + - **$$mockWebsocket** (private but configurable) + +## $websocketProvider + +Following the API of ngWebsocket Provider + +### $setup + +If you need to setup your custom default configuration for each ngWebsocket istance, pass it to this method: + +```javascript +angular.config(function ($websocketProvider) { + $websocketProvider.$setup({ + lazy: false, + reconnect: true, + reconnectInterval: 2000, + mock: false, + enqueue: false + }); +}); +``` + +**Usage** + +```javascript +$setup(config) +``` + +**Arguments** + +| **Param** | **Type** | **Details** | +| --------- | -------- | ----------- | +| config | Object | default ngWebsocket configuration | + +**Returns** + +| **Type** | **Details** | +| -------- | ----------- | +| $websocketProvider | the $websocketProvider | + +## $websocket + +Following the API of the $websocket Service + +### $get + +Every ngWebsocket instance created with [$websocket.$new](#new) method are stored within the $websocket service. +To get one of them, you can use **$get** with the url of the websocket you're looking for: + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$get('ws://localhost:12345'); +}); +``` + +The url is needed because it is stored using the url as the key of an hashmap. + +**Usage** + +```javascript +$get(url) +``` + +**Arguments** + +| **Param** | **Type** | **Details** | +| --------- | -------- | ----------- | +| url | String | the websocket url | + +**Returns** + +| **Type** | **Details** | +| -------- | ----------- | +| ngWebsocket | an instance of ngWebsocket or undefined | + +### $new + +There are two ways to create a new instance of ngWebsocket: + +**string (url)** + +The url is always needed and it has to start with the websocket schema (ws:// or wss://): + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new('ws://localhost:12345'); +}); +``` + +A new instance is returned and the internal WebSocket has already started the connection with the websocket server on the backend. + +**object** + +All of the following configurations can be changed: + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new( + url: 'ws://localhost:12345', + lazy: false, + reconnect: true, + reconnectInterval: 2000, + mock: false, + enqueue: false + ); +}); +``` + +For more information see the [ngWebsocket Constructor section](#constructor). + +**Usage** + +```javascript +$new(url|config) +``` + +**Arguments** + +| **Param** | **Type** | **Details** | +| --------- | -------- | ----------- | +| url/config | String/Object | websocket url or a configuration set | + +**Returns** + +| **Type** | **Details** | +| -------- | ----------- | +| ngWebsocket | an instance of ngWebsocket | + +## ngWebsocket + +ngWebsocket is the core of this module. +In a few words, it's a wrapper for the HTML5 WebSocket object, extending it with different features. +It acts like an EventEmitter and it provides a common way to attach a handler for each fired event. + +Following the API in detail. + +### Constructor + +The constructor of the ngWebsocket accepts two kind of parameters: + + - String: the url starting with the WebSocket schema (ws:// or wss://) + plus an optional String/String[] containing the protocols (this matches + the WebSocket constructor API) + - Object: a configuration containing the websocket url + +The url is a requirement to create a new ngWebsocket. +An instance is always created with a factory method by the [$websocket](#websocket) service: in fact, +it lets to make different websockets that are pointing to different urls. + +Example of a basic instantiation: + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new('ws://localhost:12345', ['binary', 'base64']); +}); +``` + +Using Object configuration: + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new({ + url: 'ws://localhost:12345', + lazy: false, + reconnect: true, + reconnectInterval: 2000, + enqueue: false, + mock: false, + protocols: ['binary', 'base64'] + }); +}); +``` + +Following the explanation of the configuration object - {Type} PropertyName (default): + + - **{Boolean} lazy (false)**: lazy initialization. A websocket can open the connection when ngWebsocket is instantiated with [$websocket.$new](#new) (false) or afterwards with [$open](#open) (false). For more information see [Features - Lazy Initialization](#lazy) + - **{Boolean} reconnect (true)**: auto reconnect behaviour. A websocket can try to reopen the connection when is down (true) or stay closed (false). For more information see [Features - Auto Reconnect](#reconnect) + - **{Number} reconnectInterval (2000)**: auto reconnect interval. By default, a websocket try to reconnect after 2000 ms (2 seconds). For more information see [Features - Auto Reconnect](#reconnect) + - **{Boolean} enqueue (false)**: enqueue unsent messages. By default, a websocket discards messages when the connection is closed (false) but it can enqueue them and send afterwards the connection gets open back (true). For more information see [Features - Enqueue Unsent Messages](#enqueue) + - **{Boolean/Object} mock (false)**: mock a websocket server. By default, a websocket run only if the webserver socket is listening (false) but it can be useful to mock the backend to make the websocket working (true). For more information see [Features - Mock Websocket Server](#mock) + - **{String/String[]} (null)**: Either a single protocol string or an array of protocol strings. This is the same as the WebSocket protocols argument. + +### Constants + +Websocket status constants: + + - **$CONNECTING**: the websocket is trying to open the connection + - **$OPEN**: the websocket connection is open + - **$CLOSING**: the websocket connection is closing + - **$CLOSED**: the websocket connection is closed + +### Events + +There are custom events fired by ngWebsocket. +They are useful to setup a listener for certain situations and behaviours: + + - **$open**: the websocket gets open + - **$close**: the websocket gets closed + - **$error**: an error occurred (callback params: {Error} error) + - **$message**: the original message sent from the server (callback params: {String} message). Usually, it's a JSON encoded string containing the event to fire and the data to pass ({"event": "an event", "data": "some data"}) + +The other events are custom events, setup by the user itself. + +### $on + +Attach one or more handlers to a specific event. + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new('ws://localhost:12345'); + + // Single event handler + ws.$on('my event', function myHandler () {...}); + + // Different event handlers + ws.$on('another event', myHandler, mySecondHandler, myThirdHandler); + + // Different chained event handlers + ws.$on('third event', function myHandler () {...}) + .$on('third event', function mySecondHandler () {...}) + .$on('third event', function myThirdHandler () {...}); +}); +``` + +Now the websocket is listening for 'my event' event and the handler 'myHandler' will be called when that event +is sent by the websocket server. The same thing happens for the other two cases: each event handler is called +one by one, starting from the first one, ending with the last one. + +**Usage** + +```javascript +$on(event, handler|handlers) +``` + +**Arguments** + +| **Param** | **Type** | **Details** | +| --------- | -------- | ----------- | +| event | String | the event to attach a listener | +| handler/handlers | Function/Function[] | one or more handlers to invoke when the event is fired up | + +**Returns** + +| **Type** | **Details** | +| -------- | ----------- | +| ngWebsocket | the ngWebsocket | + +### $un + +Detach a handler from a specific event. + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new('ws://localhost:12345'); + + ws.$on('my event', function myHandler () {...}); + ws.$un('my event'); +}); +``` + +The above websocket has not listener attached at the end of the execution. + + +**Usage** + +```javascript +$un(event) +``` + +**Arguments** + +| **Param** | **Type** | **Details** | +| --------- | -------- | ----------- | +| event | String | the event to detach the listener | + +**Returns** + +| **Type** | **Details** | +| -------- | ----------- | +| ngWebsocket | the ngWebsocket | + +### $emit + +Send an event to the websocket server. + +It's possible to send a lonely event or attaching some data to it. + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new('ws://localhost:12345'); + + ws.$on('$open', function () { + ws.$emit('lonely event'); // the websocket server will receive only the event name + ws.$emit('event with data', 'some data'); // it will send the event with 'some data' string + ws.$emit('with object', {some: 'data'}); // it will send the event with the object JSONified + }); +}); +``` + +It's possible to send both simply (like strings and numbers) and complex data (like objects and arrays). + +**Usage** + +```javascript +$emit(event, [data]) +``` + +**Arguments** + +| **Param** | **Type** | **Details** | +| --------- | -------- | ----------- | +| event | String | the event to send | +| data (optional) | String/Number/Object | the data to send with the event | + +**Returns** + +| **Type** | **Details** | +| -------- | ----------- | +| ngWebsocket | the ngWebsocket | + +### $open + +Open the websocket connection if it's closed. + +```javascript +angular.run(function ($websocket, $timeout) { + var ws = $websocket.$new({ + url: 'ws://localhost:12345', + lazy: true + }); + + ws.$on('$open', function () { + console.log('The websocket now is open'); + }); + + $timeout(function () { + ws.$open(); // it will open the websocket after 5 seconds + }, 5000); +``` + +**Usage** + +```javascript +$open() +``` + +**Returns** + +| **Type** | **Details** | +| -------- | ----------- | +| ngWebsocket | the ngWebsocket | + +### $close + +It closes the websocket connection if it's open. + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new(url: 'ws://localhost:12345'); + + ws.$on('$open', function () { + ws.$close(); // it closes the websocket connection + }); + + ws.$on('$close', function () { + console.log('Connection closed!'); + }); +``` + +**Usage** + +```javascript +$close() +``` + +**Returns** + +| **Type** | **Details** | +| -------- | ----------- | +| ngWebsocket | the ngWebsocket | + +### $status + +It returns the current status of the websocket connection. +It's possible to use the [websocket constants](#constants) to make checks. + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new(url: 'ws://localhost:12345'); + + console.log(ws.$status()); // it prints ws.$CONNECTING + + ws.$on('$open', function () { + console.log(ws.$status()); // it prints ws.$OPEN + ws.$close(); // it closes the websocket connection + console.log(ws.$status()); // it prints ws.$CLOSING + }); + + ws.$on('$close', function () { + console.log(ws.$status()); // it prints ws.$CLOSED + console.log('Connection closed!'); + }); +``` + +**Usage** + +```javascript +$status() +``` + +**Returns** + +| **Type** | **Details** | +| -------- | ----------- | +| Number | a constant number representing the websocket connection readyState | + +### $ready + +It returns if the websocket connection is open or closed. + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new(url: 'ws://localhost:12345'); + + console.log(ws.$ready()); // it prints false + + ws.$on('$open', function () { + console.log(ws.$ready()); // it prints true + ws.$close(); // it closes the websocket connection + console.log(ws.$ready()); // it prints false + }); + + ws.$on('$close', function () { + console.log(ws.$ready()); // it prints false + console.log('Connection closed!'); + }); +``` + +**Usage** + +```javascript +$ready() +``` + +**Returns** + +| **Type** | **Details** | +| -------- | ----------- | +| Boolean | true if the connection is OPEN, false otherwise | + +### $mockup + +It returns if the websocket is mocked up or not. + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new(url: 'ws://localhost:12345'); + + console.log(ws.$mockup()); // it prints false + + var ws2 = $websocket.$new({ + url: 'ws://localhost:54321', + mock: true + }); + + console.log(ws.$mockup()); // it prints true +``` + +**Usage** + +```javascript +$mockup() +``` + +**Returns** + +| **Type** | **Details** | +| -------- | ----------- | +| Boolean | true if the ngWebsocket istance is mocked up, false otherwise | + +## $$mockWebsocket + +If you need to develop or test your application without a real websocket backend server, you can setup +a mockup of it with this feature. +The only thing to do is to pass a configuration object during the ngWebsocket initialization: + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new({ + url: 'ws://localhost:12345', + mock: { + openTimeout: 500, + closeTimeout: 1000, + messageInterval: 2000, + fixtures: {} + } + }); +``` + +Following the explanation of the configuration object - {Type} PropertyName (default):: + + - **{Boolean/Object} mock (false)**: could be either a Boolean (default to false) or an object + - **{Number} openTimeout (500)**: timeout to make the internal websocket to get open + - **{Number} closeTimeout (1000)**: timeout to make the internal websocket to get closed + - **{Number} messageInterval (2000)**: the internal websocket sends enqueued message with this interval time + - **{Object/String} fixtures ({})**: an object of fixtures, where the keys are the events and the values are the data to respond, or an url to retrieve remote fixtures via HTTP + +Fixtures can mock both custom events and data. +They can be added as a static object with the following structure: + +```javascript +fixtures: { + 'incoming event name': { + event: 'outgoing event name', + data: 'response data' + } +} +``` + +The *incoming event name* is the event fired by the websocket while the *outgoing event name* is the one sent by the mocked webserver. +So, it be useful to map events with a custom response. +By default, the mock feature acts like a parrot server, responding with the same data on the same received event. + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new({ + url: 'ws://localhost:12345', + mock: { + fixtures: { + 'mock data': { + data: { + hello: 'world' + } + }, + 'mock data and event': { + event: 'custom event', + data: { + hello: 'mocked world' + } + } + } + } + }); + + ws.$on('$open', function () { + ws.$emit('parrot event', 'parrot data') + .$emit('mock data') + .$emit('mock data and event'); + }) + .$on('parrot event', function (message) { + console.log(message); // it prints 'parrot data' + }) + .$on('mock data', function (message) { + console.log(message); // it prints '{hello: 'world'}' + }) + .$on('custom event', function (message) { + console.log(message); // it prints '{hello: 'mocked world'}' + }); +``` + +Fixtures can be loaded through an HTTP request. +In fact, it be useful to have those in a JSON file or created by the webserver: + +```javascript +angular.run(function ($websocket) { + var ws = $websocket.$new({ + url: 'ws://localhost:12345', + mock: { + fixtures: '/fixtures.json' // fixtures are located in a file or calculated at run-time by the web server + } + }); + + // Now you're ready to use fixtures because the websocket will be available only when the fixtures are loaded +}); +``` + +# Contribute + +Wanna contribute, fella? +That's the right place to find useful information! + +How? + + - improve and fix the documentation + - test it + - make some demos + - use it + - write new pieces of code + - optimize it + - find bugs + +And don't forget to make **pull requests**, damn it! + +# License + +Check out LICENSE file (MIT)
\ No newline at end of file diff --git a/www/lib/ng-websocket/bower.json b/www/lib/ng-websocket/bower.json new file mode 100644 index 00000000..3c3e89b6 --- /dev/null +++ b/www/lib/ng-websocket/bower.json @@ -0,0 +1,32 @@ +{ + "name": "ng-websocket", + "version": "0.2.1", + "authors": [ + "Vincenzo (Wilk) Ferrari <wilk3ert@gmail.com>" + ], + "description": "AngularJS HTML5 WebSocket powerful library", + "main": "ng-websocket.js", + "keywords": [ + "angular", + "angularjs", + "websocket", + "ng", + "html5", + "service", + "provider" + ], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": { + "angular": "~1.3.2" + }, + "devDependencies": { + "angular-mocks": "~1.3.2" + } +} diff --git a/www/lib/ng-websocket/ng-websocket.js b/www/lib/ng-websocket/ng-websocket.js new file mode 100644 index 00000000..92192c73 --- /dev/null +++ b/www/lib/ng-websocket/ng-websocket.js @@ -0,0 +1,370 @@ +'use strict'; + +(function () { + /** + * @ngdoc provider + * @name $websocketProvider + * @module ngWebsocket + * @description + * HTML5 WebSocket provider for AngularJS + */ + function $websocketProvider () { + var wsp = this; + + wsp.$$config = { + lazy: false, + reconnect: true, + reconnectInterval: 2000, + mock: false, + enqueue: false, + protocols: null + }; + + wsp.$setup = function (cfg) { + cfg = cfg || {}; + wsp.$$config = angular.extend({}, wsp.$$config, cfg); + + return wsp; + }; + + wsp.$get = ['$http', function ($http) { + return new $websocketService(wsp.$$config, $http); + }]; + } + + /** + * @ngdoc service + * @name $websocketService + * @module ngWebsocketService + * @description + * HTML5 Websocket service for AngularJS + */ + function $websocketService (cfg, $http) { + var wss = this; + + wss.$$websocketList = {}; + wss.$$config = cfg || {}; + + wss.$get = function (url) { + return wss.$$websocketList[url]; + }; + + wss.$new = function (cfg) { + cfg = cfg || {}; + + // Url or url + protocols initialization + if (typeof cfg === 'string') { + cfg = {url: cfg}; + + // url + protocols + if (arguments.length > 1) { + if (typeof arguments[1] === 'string' && arguments[1].length > 0) cfg.protocols = [arguments[1]]; + else if (typeof arguments[1] === 'object' && arguments[1].length > 0) cfg.protocols = arguments[1]; + } + } + + // If the websocket already exists, return that instance + var ws = wss.$get(cfg.url); + if (typeof ws === 'undefined') { + var wsCfg = angular.extend({}, wss.$$config, cfg); + + ws = new $websocket(wsCfg, $http); + wss.$$websocketList[wsCfg.url] = ws; + } + + return ws; + }; + } + + /** + * @ngdoc class + * @name $websocket + * @module ngWebsocket + * @description + * HTML5 Websocket wrapper class for AngularJS + */ + function $websocket (cfg, $http) { + var me = this; + + if (typeof cfg === 'undefined' || (typeof cfg === 'object' && typeof cfg.url === 'undefined')) throw new Error('An url must be specified for WebSocket'); + + me.$$eventMap = {}; + me.$$ws = undefined; + me.$$reconnectTask = undefined; + me.$$reconnectCopy = true; + me.$$queue = []; + me.$$config = { + url: undefined, + lazy: false, + reconnect: true, + reconnectInterval: 2000, + enqueue: false, + mock: false, + protocols: null + }; + + me.$$fireEvent = function () { + var args = []; + + Array.prototype.push.apply(args, arguments); + + var event = args.shift(), + handlers = me.$$eventMap[event]; + + if (typeof handlers !== 'undefined') { + for (var i = 0; i < handlers.length; i++) { + if (typeof handlers[i] === 'function') handlers[i].apply(me, args); + } + } + }; + + me.$$init = function (cfg) { + me.$$ws = cfg.mock ? new $$mockWebsocket(cfg.mock, $http) : new WebSocket(cfg.url, cfg.protocols); + + me.$$ws.onmessage = function (message) { + try { + var decoded = JSON.parse(message.data); + me.$$fireEvent(decoded.event, decoded.data); + me.$$fireEvent('$message', decoded); + } + catch (err) { + me.$$fireEvent('$message', message.data); + } + }; + + me.$$ws.onerror = function (error) { + me.$$fireEvent('$error', error); + }; + + me.$$ws.onopen = function () { + // Clear the reconnect task if exists + if (me.$$reconnectTask) { + clearInterval(me.$$reconnectTask); + delete me.$$reconnectTask; + } + + // Flush the message queue + if (me.$$config.enqueue && me.$$queue.length > 0) { + while (me.$$queue.length > 0) { + if (me.$ready()) me.$$send(me.$$queue.shift()); + else break; + } + } + + me.$$fireEvent('$open'); + }; + + me.$$ws.onclose = function () { + // Activate the reconnect task + if (me.$$config.reconnect) { + me.$$reconnectTask = setInterval(function () { + if (me.$status() === me.$CLOSED) me.$open(); + }, me.$$config.reconnectInterval); + } + + me.$$fireEvent('$close'); + }; + + return me; + }; + + me.$CONNECTING = 0; + me.$OPEN = 1; + me.$CLOSING = 2; + me.$CLOSED = 3; + + // TODO: it doesn't refresh the view (maybe $apply on something?) + /*me.$bind = function (event, scope, model) { + me.$on(event, function (message) { + model = message; + scope.$apply(); + }); + };*/ + + me.$on = function () { + var handlers = []; + + Array.prototype.push.apply(handlers, arguments); + + var event = handlers.shift(); + if (typeof event !== 'string' || handlers.length === 0) throw new Error('$on accept two parameters at least: a String and a Function or an array of Functions'); + + me.$$eventMap[event] = me.$$eventMap[event] || []; + for (var i = 0; i < handlers.length; i++) { + me.$$eventMap[event].push(handlers[i]); + } + + return me; + }; + + me.$un = function (event) { + if (typeof event !== 'string') throw new Error('$un needs a String representing an event.'); + + if (typeof me.$$eventMap[event] !== 'undefined') delete me.$$eventMap[event]; + + return me; + }; + + me.$$send = function (message) { + if (me.$ready()) me.$$ws.send(JSON.stringify(message)); + else if (me.$$config.enqueue) me.$$queue.push(message); + }; + + me.$emit = function (event, data) { + if (typeof event !== 'string') throw new Error('$emit needs two parameter: a String and a Object or a String'); + + var message = { + event: event, + data: data + }; + + me.$$send(message); + + return me; + }; + + me.$open = function () { + me.$$config.reconnect = me.$$reconnectCopy; + + if (me.$status() !== me.$OPEN) me.$$init(me.$$config); + return me; + }; + + me.$close = function () { + if (me.$status() !== me.$CLOSED) me.$$ws.close(); + + if (me.$$reconnectTask) { + clearInterval(me.$$reconnectTask); + delete me.$$reconnectTask; + } + + me.$$config.reconnect = false; + + return me; + }; + + me.$status = function () { + if (typeof me.$$ws === 'undefined') return me.$CLOSED; + else return me.$$ws.readyState; + }; + + me.$ready = function () { + return me.$status() === me.$OPEN; + }; + + me.$mockup = function () { + return me.$$config.mock; + }; + + // setup + me.$$config = angular.extend({}, me.$$config, cfg); + me.$$reconnectCopy = me.$$config.reconnect; + + if (!me.$$config.lazy) me.$$init(me.$$config); + + return me; + } + + function $$mockWebsocket (cfg, $http) { + cfg = cfg || {}; + + var me = this, + openTimeout = cfg.openTimeout || 500, + closeTimeout = cfg.closeTimeout || 1000, + messageInterval = cfg.messageInterval || 2000, + fixtures = cfg.fixtures || {}, + messageQueue = []; + + me.CONNECTING = 0; + me.OPEN = 1; + me.CLOSING = 2; + me.CLOSED = 3; + + me.readyState = me.CONNECTING; + + me.send = function (message) { + if (me.readyState === me.OPEN) { + messageQueue.push(message); + return me; + } + else throw new Error('WebSocket is already in CLOSING or CLOSED state.'); + }; + + me.close = function () { + if (me.readyState === me.OPEN) { + me.readyState = me.CLOSING; + + setTimeout(function () { + me.readyState = me.CLOSED; + + me.onclose(); + }, closeTimeout); + } + + return me; + }; + + me.onmessage = function () {}; + me.onerror = function () {}; + me.onopen = function () {}; + me.onclose = function () {}; + + setInterval(function () { + if (messageQueue.length > 0) { + var message = messageQueue.shift(), + msgObj = JSON.parse(message); + + switch (msgObj.event) { + case '$close': + me.close(); + break; + default: + // Check for a custom response + if (typeof fixtures[msgObj.event] !== 'undefined') { + msgObj.data = fixtures[msgObj.event].data || msgObj.data; + msgObj.event = fixtures[msgObj.event].event || msgObj.event; + } + + message = JSON.stringify(msgObj); + + me.onmessage({ + data: message + }); + } + } + }, messageInterval); + + var start = function (fixs) { + fixs = fixs || {}; + fixs = fixs instanceof Error ? {} : fixs; + + fixtures = fixs; + + setTimeout(function () { + me.readyState = me.OPEN; + me.onopen(); + }, openTimeout); + }; + + // Get fixtures from a server or a file if it's a string + if (typeof fixtures === 'string') { + $http.get(fixtures) + .success(start) + .error(start); + } + else start(fixtures); + + return me; + } + + /** + * @ngdoc module + * @name $websocket + * @module ngWebsocket + * @description + * HTML5 WebSocket module for AngularJS + */ + angular + .module('ngWebsocket', []) + .provider('$websocket', $websocketProvider); +})();
\ No newline at end of file diff --git a/www/lib/ng-websocket/package.json b/www/lib/ng-websocket/package.json new file mode 100644 index 00000000..292299d2 --- /dev/null +++ b/www/lib/ng-websocket/package.json @@ -0,0 +1,31 @@ +{ + "name": "ngWebSocket", + "version": "0.0.0", + "description": "AngularJS WebSocket wrapper", + "main": "ng-websocket.js", + "scripts": { + "postinstall": "bower install", + "test": "node_modules/gulp/bin/gulp.js test" + }, + "repository": "", + "keywords": [ + "angular", + "websocket", + "angularjs", + "hmlt5", + "ng" + ], + "author": "Vincenzo (Wilk) Ferrari <wilk3ert@gmail.com>", + "license": "MIT", + "readmeFilename": "README.md", + "gitHead": "3bb59ef67d27eff0e88e637d0999b3e2141ef398", + "devDependencies": { + "ws": "~0.4.32", + "karma": "~0.12.22", + "karma-jasmine": "~0.2.0", + "karma-mocha-reporter": "~0.3.1", + "karma-phantomjs-launcher": "~0.1.4", + "gulp-karma": "0.0.4", + "gulp": "~3.8.7" + } +} |
