UNPKG

8.81 kBMarkdownView Raw
1# socket.io-rpc [![NPM version](https://badge.fury.io/js/socket.io-rpc.png)](http://badge.fury.io/js/socket.io-rpc)
2[![Build Status](https://travis-ci.org/capaj/socket.io-rpc.svg?tag=1.0.3)](https://travis-ci.org/capaj/socket.io-rpc)
3[![Dependency Status](https://david-dm.org/capaj/socket.io-rpc.svg)](https://david-dm.org/capaj/socket.io-rpc) [![devDependency Status](https://david-dm.org/capaj/socket.io-rpc/dev-status.svg)](https://david-dm.org/capaj/socket.io-rpc#info=devDependencies)
4
5It is a minimalistic remote procedure call(RPC/RMI) library bootstrapped on socket.io and bluebird.js.
6Main purpose is to make it more easier to structure your code for browser-server realtime interaction. Typical example is when you need to call a function on the server from client and get the return value from that function back to the client. With raw socket.io, you need to register few events and emit them at the right moment. This can get complicated quite easily, especially for async operations.
7
8With socket.io-rpc, you just expose a channel of functions and then call those as if they were regular async functions defined on your side, socket.io-rpc automatically resolves a promise on other side, when function returns or returned promise is resolved. It even propagates errors(thrown and returned), so you get error handling almost for free.
9
10Has three client libraries(which sit in separate [repo](https://github.com/capaj/socket.io-rpc-client)/[npm package](https://www.npmjs.com/package/socket.io-rpc-client)):
11* for browser
12* for AngularJS
13* for node
14
15#Simple example
16Folder with example can be run after installing all dependencies like this in the simple-example folder:
17
18 npm install //this runs jspm install too
19
20Then run it from git repo root:
21
22 node simple-example/server
23
24## Usage example
25
26###Serverside server
27```javascript
28 var io = require('socket.io').listen(server);
29 // you should be able to use any other http://promises-aplus.github.io/promises-spec/ compliant library, but I would greatly recommend using bluebird
30 var Promise = require('bluebird');
31 var rpc = require('socket.io-rpc');
32
33 var rpcMaster = rpc(io, {channelTemplates: true, expressApp: app})
34 //channelTemplates true is default, though you can change it, I would recommend leaving it to true,
35 // false is good only when your channels are dynamic so there is no point in caching
36 .expose('myChannel', {
37 //plain JS function
38 getTime: function () {
39 console.log('Client ID is: ' + this.id);
40 return new Date();
41 },
42 //returns a promise, which when resolved will resolve promise on client-side with the result(with the middle step in JSON over socket.io)
43 myAsyncTest: function (param) {
44 var deffered = Promise.defer();
45 setTimeout(function(){
46 deffered.resolve("String generated asynchronously serverside with " + param);
47 },1000);
48 return deffered.promise;
49 }
50 });
51
52
53 io.sockets.on('connection', function (socket) {
54 rpcMaster.loadClientChannel(socket,'clientChannel').then(function (fns) {
55 fns.fnOnClient("calling client ").then(function (ret) {
56 console.log("client returned: " + ret);
57 });
58 });
59
60 });
61```
62
63###In browser
64```html
65 //since it is desirable to be able to run the same code in node.js as in the browser, we use systemjs to load commonJS module into the browser
66 <script src="jspm_packages/system.js"></script>
67 <script src="config.js"></script> //needs to have bluebird and socket.io-client, look into simple_example folder
68 <script type="text/javascript">
69 //as commonJS module
70 System.import('rpc:myChannel').then(function(channel) {
71 channel.getTime().then(function (date) {
72 console.log('get time on module loaded as cjs module: ' + date);
73 });
74 });
75 //load manually with rpc client
76 System.import('rpc/rpc-client').then(function(channel) { /
77 console.log("rpc server channel loaded");
78 backend.loadChannel('myChannel')
79 .then(function (channel) {
80 channel.getTime().then(function (date) {
81 console.log('time on server is: ' + date);
82
83 });
84 channel.myAsyncTest('passing string as argument').then(function(retVal){
85 console.log('server returned: ' + retVal);
86 });
87 }, function (err) {
88 console.log(err + ' equals TypeError: Object #<Object> has no method nonExistentRemoteFn');
89 });
90
91 backend.expose('clientChannel', {
92 fnOnClient: function (param) {
93 return 'whatever you need from client returned ' + param;
94 }
95 }).then(function (channel) {
96 console.log(" client channel ready");
97 }, function (err) {
98 debugger;
99 }
100 );
101
102 function setText(elem, changeVal) {
103 if ((elem.textContent) && (typeof (elem.textContent) != "undefined")) {
104 elem.textContent = changeVal;
105 } else {
106 elem.innerText = changeVal;
107 }
108 }
109 }, function(e) {
110 setTimeout(function () {
111 console.error(e);
112 });
113 });
114 </script>
115```
116###In browser for AngularJS
117```html
118 <body>
119 <h1>Angular socket.io-rpc test/showcase</h1>
120 <!--You can also use regular ng-controller, but then you have to load channel yourself by calling $rpc.loadChannel('myChannel'); inside it-->
121 <div rpc-controller="testCtrl" rpc-channel="myChannel">
122 getTime: <span ng-bind="serverTime"></span><br>
123 asyncTest: {{ asyncTest }}
124 </div>
125
126 </body>
127 <script type="text/javascript" src="angular.js"></script>
128 <script src="jspm_packages/system.js"></script>
129 <script src="config.js"></script>
130 <script type="text/javascript">
131 System.import('rpc/rpc-client-angular').then(function(RPC) {
132 angular.module('app', ['RPC']).controller('testCtrl', function ($scope, myChannel) {
133
134 myChannel.getTime().then(function (date) {
135 console.log('time on server is: ' + date);
136 $scope.serverTime = date;
137 //no need to call $scope.$apply, because it is called in $rpc;
138 });
139 myChannel.myAsyncTest('passing string as argument').then(function (retVal) {
140 console.log('server returned: ' + retVal);
141 $scope.asyncTest = retVal;
142 });
143 console.log('ctr ' + new Date().toJSON());
144 }).run(
145 function ($rpc, $rootScope) {
146 var localRPC = $rpc('http://localhost:8080'); // don't forget port, if you are not on 80
147 console.log('run ' + new Date().toJSON());
148 localRPC.expose('clientChannel', {
149 fnOnClient: function (param) {
150 return 'whatever you need from client returned ' + param;
151 }
152 }).then(
153 function (channel) {
154 console.log(" client channel ready");
155 }
156 );
157 }
158 );
159
160 var injector = angular.bootstrap(document, ['app']);
161
162 </script>
163```
164
165###With authentication (server)
166
167Set authentication normally as you would with [socket.io](http://socket.io/docs/migrating-from-0-9/#authentication-differences).
168
169
170###With authentication (browser)
171
172Send your auth token with the backend connect method(the one that is exported from the module/angular factory).
173
174## Browser support
175 numbers are for both clients(vanilla and Angular):
176 IE FIREFOX SAFARI CHROME OPERA IPHONE ANDROID
177 9.0+ 3.5+ 4.0+ 4.0+ 10.5+ 2.0+ 2.0+
178
179
180## Internal callbacks on client
181There are 4 internal callbacks, which might help you in case you need to be notified of a request beginning and ending:
182
183 onBatchStarts //called when invocation counter equals 1
184 onBatchEnd //called when invocation counter equals endCounter
185 onCall //called when one call is made to server
186 onEnd //called when one call is returned
187
188