@eleven-am/pondsocket 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,141 @@
1
+
2
+ # PondSocket
3
+
4
+ PondSocket is a fast, minimalist and bidirectional socket framework for NodeJS. Pond allows you to think of each action during a sockets lifetime as a request instead of a huge callback that exists inside the connection event.
5
+ ## Documentation
6
+
7
+ This is a Node.js module available through the npm registry.
8
+
9
+ ```bash
10
+ npm install @eleven-am/pondsocket
11
+ ```
12
+
13
+ PondSocket usage depends on the environment in which it is being used.
14
+
15
+ #### On the server
16
+
17
+ When using PondSocket, an endpoint is created. The endpoint is the gateway by which sockets actually connect to the server.
18
+ Multiple endpoints can be created but every endpoint is independent of the other, ie sockets on one endpoint cannot communicate with sockets on another endpoint.
19
+
20
+ ```js
21
+ import { PondSocket } from "@eleven-am/pondsocket";
22
+ import parse from "url";
23
+
24
+ const pond = new PondSocket();
25
+
26
+ const endpoint = pond.createEndpoint('/api/socket', (req, res, _endpoint) => {
27
+ const { query } = parse(req.url || '');
28
+ const { token } = query;
29
+ if (!token)
30
+ return res.reject('No token provided');
31
+ res.accept({
32
+ assign: {
33
+ token
34
+ }
35
+ });
36
+ })
37
+ ```
38
+
39
+ While sockets connect through the endpoint, communication between sockets cannot occur on the endpoint level. Sockets have to join a channel to communicate
40
+ between themselves.
41
+
42
+ ```js
43
+ const channel = endpoint.createChannel(/^channel(.*?)/, (req, res, channel) => {
44
+ const isAdmin = req.clientAssigns.admin;
45
+ if (!isAdmin)
46
+ return res.reject('You are not an admin');
47
+
48
+ res.accept({
49
+ assign: {
50
+ admin: true,
51
+ joinedDate: new Date()
52
+ },
53
+ presence: {
54
+ state: 'online'
55
+ },
56
+ channelData: {
57
+ locked: true,
58
+ numberOfUsers: channel.presence.length
59
+ }
60
+ });
61
+ });
62
+ ```
63
+
64
+ A user goes through the createChannel function to join a channel.
65
+ When a user joins a channel, some private information can be assigned to the user. This assign could be viewed as a cookie that is only available serverside.
66
+ The presence is the current state of the user. When you reassign a new presence information to a user, all other users connected to the same channel are informed of the change.
67
+ This could be used as *user is typing*, *user is away*, etc. The channelData is information that is stored on the channel and accessible from anywhere the channel is available.
68
+ It can be anything from a boolean to an instance of a class. This data cannot be accessed from another channel as it is private to the channel.
69
+
70
+ ```js
71
+ channel.on('hello', (req, res, channel) => {
72
+ const users = channel.getPresence();
73
+ res.assign({
74
+ assign: {
75
+ pingDate: new Date(),
76
+ users: users.length
77
+ }
78
+ });
79
+
80
+ // res.reject('curse words are not allowed on a child friendly channel')
81
+ // channel.closeFromChannel(req.client.clientId);
82
+ })
83
+ ```
84
+
85
+ When a message is sent on a channel by a user, an event is triggered. The *on* function can be used to listen for these events. If the function is specified, it is called when the message is received.
86
+ You can choose to decline the message being sent, or you can allow the message to be sent as usual. You can also do all the normal assigns to the channel, or user.
87
+ In case there is no *on* function, the message will be sent without any action being taken.
88
+
89
+ #### On the browser
90
+
91
+ ```js
92
+ import { PondClient } from "@eleven-am/pondsocket/client";
93
+
94
+ export const socket = new PondClientSocket('/api/socket', {});
95
+ socket.connect();
96
+ ```
97
+
98
+ The browser compatible package can be imported from @eleven-am/pondsocket/client.
99
+ AN url string is provided to the class along with other url params, like token.
100
+
101
+ Multiple classes can be created, but it is advised to use a single class throughout the application.
102
+ You can just create multiple channels and maintain the single socket connection.
103
+
104
+ ```js
105
+ const channelTopic = 'channel:one';
106
+ const options = {
107
+ username: 'eleven-am'
108
+ }
109
+
110
+ export const channel = socket.createChannel(channelTopic, options);
111
+ channel.join();
112
+ ```
113
+
114
+ When connected to the channel you can subscribe to the events from the channel.
115
+
116
+ ```js
117
+ const subscriptionPresence = channel.onPresenceUpdate(presence => {
118
+ // handle the presence changes of the channel
119
+ });
120
+
121
+ const subscriptionMessage = channel.onMessage((event, data) => {
122
+ // handle the message being received
123
+ });
124
+
125
+ // When done with the channel remember to unsubscribe from these listeners
126
+ subscriptionPresence.unsubscribe();
127
+ subscriptionMessage.unsubscribe();
128
+ ```
129
+
130
+ There are many other features available on the channel object. Since the application is completely typed,
131
+ suggestions should be provided by your IDE.
132
+
133
+ ```js
134
+ channel.broadcast('hello', {
135
+ name: 'eleven-am',
136
+ message: 'I am the man, man'
137
+ })
138
+
139
+ // channel.broadcastFrom broadcasts a message to everyone but the client that emitted the message
140
+ // channel.sendMessage sends a message to clients specified in the function
141
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eleven-am/pondsocket",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "PondSocket is a fast simple socket server",
5
5
  "keywords": [
6
6
  "socket",
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Channel = void 0;
4
- const rxjs_1 = require("rxjs");
5
- const operators_1 = require("rxjs/operators");
6
- const pondSocket_1 = require("../pondSocket");
7
- const pondBase_1 = require("../pondBase");
8
- class Channel {
9
- constructor(channel, params, socket) {
4
+ var rxjs_1 = require("rxjs");
5
+ var operators_1 = require("rxjs/operators");
6
+ var pondSocket_1 = require("../pondSocket");
7
+ var pondBase_1 = require("../pondBase");
8
+ var Channel = /** @class */ (function () {
9
+ function Channel(channel, params, socket) {
10
10
  this._subscriptions = [];
11
11
  this._presenceSubject = new rxjs_1.Subject();
12
12
  this.channel = channel;
@@ -15,138 +15,149 @@ class Channel {
15
15
  this._subject = new rxjs_1.Subject();
16
16
  this._connectedSubject = new pondBase_1.Subject(false);
17
17
  }
18
- get isActive() {
19
- return this._connectedSubject.value;
20
- }
18
+ Object.defineProperty(Channel.prototype, "isActive", {
19
+ get: function () {
20
+ return this._connectedSubject.value;
21
+ },
22
+ enumerable: false,
23
+ configurable: true
24
+ });
21
25
  /**
22
26
  * @desc Connects to the channel.
23
27
  */
24
- join() {
28
+ Channel.prototype.join = function () {
29
+ var _this = this;
25
30
  if (this._connectedSubject.value)
26
31
  return this;
27
- const observable = this._init();
28
- const subscription = observable
29
- .subscribe(message => {
30
- this._connectedSubject.publish(true);
32
+ var observable = this._init();
33
+ var subscription = observable
34
+ .subscribe(function (message) {
35
+ _this._connectedSubject.publish(true);
31
36
  if (message.action === "PRESENCE")
32
- this._presenceSubject.next(message.payload.presence);
37
+ _this._presenceSubject.next(message.payload.presence);
33
38
  else if (message.action === "MESSAGE")
34
- this._subject.next(message);
39
+ _this._subject.next(message);
35
40
  else if (message.event === "KICKED_FROM_CHANNEL")
36
- this.leave();
41
+ _this.leave();
37
42
  });
38
43
  this._subscriptions.push(subscription);
39
44
  return this;
40
- }
45
+ };
41
46
  /**
42
47
  * @desc Disconnects from the channel.
43
48
  */
44
- leave() {
49
+ Channel.prototype.leave = function () {
45
50
  void this._connectedSubject.publish(false);
46
51
  this._presenceSubject.complete();
47
- this._subscriptions.forEach(subscription => subscription.unsubscribe());
52
+ this._subscriptions.forEach(function (subscription) { return subscription.unsubscribe(); });
48
53
  this._subscriptions = [];
49
54
  this._subject.complete();
50
- }
55
+ };
51
56
  /**
52
57
  * @desc Monitors the presence state of the channel.
53
58
  * @param callback - The callback to call when the presence state changes.
54
59
  */
55
- onPresenceUpdate(callback) {
56
- const sub = this._presenceSubject.subscribe(callback);
60
+ Channel.prototype.onPresenceUpdate = function (callback) {
61
+ var sub = this._presenceSubject.subscribe(callback);
57
62
  this._subscriptions.push(sub);
58
63
  return sub;
59
- }
64
+ };
60
65
  /**
61
66
  * @desc Monitors the channel for messages.
62
67
  * @param callback - The callback to call when a message is received.
63
68
  */
64
- onMessage(callback) {
65
- const sub = this._subject
66
- .pipe((0, operators_1.filter)((message) => message.action === "MESSAGE"))
67
- .subscribe(message => callback(message.event, message.payload));
69
+ Channel.prototype.onMessage = function (callback) {
70
+ var sub = this._subject
71
+ .pipe((0, operators_1.filter)(function (message) { return message.action === "MESSAGE"; }))
72
+ .subscribe(function (message) { return callback(message.event, message.payload); });
68
73
  this._subscriptions.push(sub);
69
74
  return sub;
70
- }
75
+ };
71
76
  /**
72
77
  * @desc Broadcasts a message to the channel, including yourself.
73
78
  * @param event - The event to send.
74
79
  * @param payload - The message to send.
75
80
  */
76
- broadcast(event, payload) {
77
- const message = {
81
+ Channel.prototype.broadcast = function (event, payload) {
82
+ var message = {
78
83
  channelName: this.channel,
79
- payload, event,
84
+ payload: payload,
85
+ event: event,
80
86
  action: pondSocket_1.ClientActions.BROADCAST
81
87
  };
82
88
  this._socket.next(message);
83
- }
89
+ };
84
90
  /**
85
91
  * @desc Broadcasts a message to every other client in the channel except yourself.
86
92
  * @param event - The event to send.
87
93
  * @param payload - The message to send.
88
94
  */
89
- broadcastFrom(event, payload) {
90
- const message = {
95
+ Channel.prototype.broadcastFrom = function (event, payload) {
96
+ var message = {
91
97
  channelName: this.channel,
92
- payload, event,
98
+ payload: payload,
99
+ event: event,
93
100
  action: pondSocket_1.ClientActions.BROADCAST_FROM
94
101
  };
95
102
  this._socket.next(message);
96
- }
103
+ };
97
104
  /**
98
105
  * @desc Updates the presence state of the current client in the channel.
99
106
  * @param presence - The presence state to update.
100
107
  */
101
- updatePresence(presence) {
108
+ Channel.prototype.updatePresence = function (presence) {
102
109
  this._socket.next({
103
110
  action: pondSocket_1.ClientActions.UPDATE_PRESENCE,
104
111
  channelName: this.channel,
105
112
  event: "PRESENCE",
106
113
  payload: presence
107
114
  });
108
- }
115
+ };
109
116
  /**
110
117
  * @desc Sends a message to specific clients in the channel.
111
118
  * @param event - The event to send.
112
119
  * @param payload - The message to send.
113
120
  * @param recipient - The clients to send the message to.
114
121
  */
115
- sendMessage(event, payload, recipient) {
116
- const addresses = Array.isArray(recipient) ? recipient : [recipient];
117
- const message = {
122
+ Channel.prototype.sendMessage = function (event, payload, recipient) {
123
+ var addresses = Array.isArray(recipient) ? recipient : [recipient];
124
+ var message = {
118
125
  channelName: this.channel,
119
- payload, event, addresses,
126
+ payload: payload,
127
+ event: event,
128
+ addresses: addresses,
120
129
  action: pondSocket_1.ClientActions.SEND_MESSAGE_TO_USER
121
130
  };
122
131
  this._socket.next(message);
123
- }
132
+ };
124
133
  /**
125
134
  * @desc Listens for the connections state of the channel.
126
135
  * @param callback - The callback to call when the connection state changes.
127
136
  */
128
- onConnectionChange(callback) {
129
- const sub = this._connectedSubject.subscribe(callback);
137
+ Channel.prototype.onConnectionChange = function (callback) {
138
+ var sub = this._connectedSubject.subscribe(callback);
130
139
  this._subscriptions.push(sub);
131
140
  return sub;
132
- }
141
+ };
133
142
  /**
134
143
  * @desc Initializes the channel.
135
144
  * @private
136
145
  */
137
- _init() {
138
- const observable = this._socket.multiplex(() => ({
146
+ Channel.prototype._init = function () {
147
+ var _this = this;
148
+ var observable = this._socket.multiplex(function () { return ({
139
149
  action: "JOIN_CHANNEL",
140
- channelName: this.channel,
150
+ channelName: _this.channel,
141
151
  event: "JOIN_CHANNEL",
142
- payload: this._params
143
- }), () => ({
152
+ payload: _this._params
153
+ }); }, function () { return ({
144
154
  action: "LEAVE_CHANNEL",
145
- channelName: this.channel,
155
+ channelName: _this.channel,
146
156
  event: "LEAVE_CHANNEL",
147
- payload: this._params
148
- }), message => message.channelName === this.channel);
157
+ payload: _this._params
158
+ }); }, function (message) { return message.channelName === _this.channel; });
149
159
  return observable;
150
- }
151
- }
160
+ };
161
+ return Channel;
162
+ }());
152
163
  exports.Channel = Channel;
@@ -1,29 +1,48 @@
1
1
  "use strict";
2
+ var __read = (this && this.__read) || function (o, n) {
3
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
4
+ if (!m) return o;
5
+ var i = m.call(o), r, ar = [], e;
6
+ try {
7
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
8
+ }
9
+ catch (error) { e = { error: error }; }
10
+ finally {
11
+ try {
12
+ if (r && !r.done && (m = i["return"])) m.call(i);
13
+ }
14
+ finally { if (e) throw e.error; }
15
+ }
16
+ return ar;
17
+ };
2
18
  Object.defineProperty(exports, "__esModule", { value: true });
3
19
  exports.PondClient = void 0;
4
- const webSocket_1 = require("rxjs/webSocket");
5
- const rxjs_1 = require("rxjs");
6
- const channel_1 = require("./channel");
7
- const operators_1 = require("rxjs/operators");
8
- const pondBase_1 = require("../pondBase");
9
- class PondClient {
10
- constructor(endpoint, params) {
20
+ var webSocket_1 = require("rxjs/webSocket");
21
+ var rxjs_1 = require("rxjs");
22
+ var channel_1 = require("./channel");
23
+ var operators_1 = require("rxjs/operators");
24
+ var pondBase_1 = require("../pondBase");
25
+ var PondClient = /** @class */ (function () {
26
+ function PondClient(endpoint, params) {
11
27
  this.socketState = "CLOSED";
12
28
  /**
13
29
  * @desc A retry strategy for the socket.
14
30
  * @param maxTries - The maximum number of retries.
15
31
  * @param ms - The number of milliseconds to wait before retrying.
16
32
  */
17
- this._retryStrategy = (maxTries, ms) => {
18
- return (0, rxjs_1.pipe)((0, operators_1.retryWhen)(attempts => {
19
- const observableForRetries = (0, rxjs_1.zip)((0, rxjs_1.range)(1, maxTries), attempts)
20
- .pipe((0, operators_1.map)(([elemFromRange]) => elemFromRange), (0, operators_1.map)(i => i * i), (0, rxjs_1.switchMap)(i => (0, rxjs_1.timer)(i * ms)));
21
- const observableForFailure = (0, rxjs_1.throwError)(new Error("Could not connect to server"))
33
+ this._retryStrategy = function (maxTries, ms) {
34
+ return (0, rxjs_1.pipe)((0, operators_1.retryWhen)(function (attempts) {
35
+ var observableForRetries = (0, rxjs_1.zip)((0, rxjs_1.range)(1, maxTries), attempts)
36
+ .pipe((0, operators_1.map)(function (_a) {
37
+ var _b = __read(_a, 1), elemFromRange = _b[0];
38
+ return elemFromRange;
39
+ }), (0, operators_1.map)(function (i) { return i * i; }), (0, rxjs_1.switchMap)(function (i) { return (0, rxjs_1.timer)(i * ms); }));
40
+ var observableForFailure = (0, rxjs_1.throwError)(new Error("Could not connect to server"))
22
41
  .pipe((0, rxjs_1.materialize)(), (0, rxjs_1.delay)(1000), (0, rxjs_1.dematerialize)());
23
42
  return (0, rxjs_1.concat)(observableForRetries, observableForFailure);
24
43
  }));
25
44
  };
26
- let address;
45
+ var address;
27
46
  try {
28
47
  address = new URL(endpoint);
29
48
  }
@@ -31,9 +50,9 @@ class PondClient {
31
50
  address = new URL(window.location.toString());
32
51
  address.pathname = endpoint;
33
52
  }
34
- const query = new URLSearchParams(params);
53
+ var query = new URLSearchParams(params);
35
54
  address.search = query.toString();
36
- const protocol = address.protocol === "https:" ? "wss:" : "ws:";
55
+ var protocol = address.protocol === "https:" ? "wss:" : "ws:";
37
56
  if (address.protocol !== "wss:" && address.protocol !== "ws:")
38
57
  address.protocol = protocol;
39
58
  this.address = address;
@@ -42,75 +61,72 @@ class PondClient {
42
61
  /**
43
62
  * @desc Connects to the server and returns the socket.
44
63
  */
45
- connect() {
64
+ PondClient.prototype.connect = function () {
65
+ var _this = this;
46
66
  if (this.socketState !== "CLOSED")
47
67
  return;
48
68
  this.socketState = "CONNECTING";
49
- const socket = (0, webSocket_1.webSocket)({
69
+ var socket = (0, webSocket_1.webSocket)({
50
70
  url: this.address.toString(),
51
71
  openObserver: {
52
- next: () => {
53
- this.socketState = "OPEN";
72
+ next: function () {
73
+ _this.socketState = "OPEN";
54
74
  }
55
75
  },
56
76
  closeObserver: {
57
- next: () => {
58
- this.socketState = "CLOSED";
77
+ next: function () {
78
+ _this.socketState = "CLOSED";
59
79
  }
60
80
  },
61
81
  closingObserver: {
62
- next: () => {
63
- this.socketState = "CLOSING";
82
+ next: function () {
83
+ _this.socketState = "CLOSING";
64
84
  }
65
85
  }
66
86
  });
67
87
  this.socket = socket;
68
88
  this.subscription = socket.pipe(this._retryStrategy(100, 1000)).subscribe();
69
89
  return this;
70
- }
90
+ };
71
91
  /**
72
92
  * @desc Returns the current state of the socket.
73
93
  */
74
- getState() {
94
+ PondClient.prototype.getState = function () {
75
95
  return this.socketState;
76
- }
96
+ };
77
97
  /**
78
98
  * @desc Creates a channel with the given name and params.
79
99
  * @param channel - The name of the channel.
80
100
  * @param params - The params to send to the server.
81
101
  */
82
- createChannel(channel, params) {
83
- const channelDoc = this.channels.get(channel);
84
- if (channelDoc)
85
- return channelDoc.doc;
86
- if (this.socket) {
87
- const newChannel = new channel_1.Channel(channel, params || {}, this.socket);
88
- this.channels.set(channel, newChannel);
89
- return newChannel;
90
- }
91
- return null;
92
- }
102
+ PondClient.prototype.createChannel = function (channel, params) {
103
+ var _this = this;
104
+ return this.channels.getOrCreate(channel, function () {
105
+ return new channel_1.Channel(channel, params || {}, _this.socket);
106
+ }).doc;
107
+ };
93
108
  /**
94
109
  * @desc An event that is triggered when the socket receives a message.
95
110
  * @param callback - The callback to be called when the event is triggered.
96
111
  */
97
- onMessage(callback) {
112
+ PondClient.prototype.onMessage = function (callback) {
98
113
  var _a;
99
- (_a = this.socket) === null || _a === void 0 ? void 0 : _a.subscribe(data => {
114
+ (_a = this.socket) === null || _a === void 0 ? void 0 : _a.subscribe(function (data) {
100
115
  if (data.event)
101
116
  callback(data.event, data.payload);
102
117
  });
103
- }
118
+ };
104
119
  /**
105
120
  * @desc Disconnects the socket from the server.
106
121
  */
107
- disconnect() {
122
+ PondClient.prototype.disconnect = function () {
108
123
  var _a, _b, _c;
109
124
  (_a = this.socket) === null || _a === void 0 ? void 0 : _a.complete();
110
125
  (_b = this.socket) === null || _b === void 0 ? void 0 : _b.unsubscribe();
111
126
  (_c = this.subscription) === null || _c === void 0 ? void 0 : _c.unsubscribe();
112
127
  this.socket = undefined;
113
128
  this.channels = new pondBase_1.PondBase();
114
- }
115
- }
129
+ };
130
+ return PondClient;
131
+ }());
116
132
  exports.PondClient = PondClient;
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="JavaScriptLibraryMappings">
4
- <includedPredefinedLibrary name="Node.js Core" />
5
- </component>
6
- </project>
package/.idea/modules.xml DELETED
@@ -1,8 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="ProjectModuleManager">
4
- <modules>
5
- <module fileurl="file://$PROJECT_DIR$/.idea/pondsocket.iml" filepath="$PROJECT_DIR$/.idea/pondsocket.iml" />
6
- </modules>
7
- </component>
8
- </project>
@@ -1,12 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <module type="WEB_MODULE" version="4">
3
- <component name="NewModuleRootManager">
4
- <content url="file://$MODULE_DIR$">
5
- <excludeFolder url="file://$MODULE_DIR$/temp" />
6
- <excludeFolder url="file://$MODULE_DIR$/.tmp" />
7
- <excludeFolder url="file://$MODULE_DIR$/tmp" />
8
- </content>
9
- <orderEntry type="inheritedJdk" />
10
- <orderEntry type="sourceFolder" forTests="false" />
11
- </component>
12
- </module>