UNPKG

4.47 kBJavaScriptView Raw
1// Copyright Michael Rhodes. 2017,2018. All Rights Reserved.
2// This file is licensed under the MIT License.
3// License text available at https://opensource.org/licenses/MIT
4
5/*
6 establish a connection to a friend and subscribe to antisocial events
7*/
8
9var debug = require('debug')('antisocial-friends-feeds');
10var url = require('url');
11var IOClient = require('socket.io-client');
12var cryptography = require('antisocial-encryption');
13var moment = require('moment');
14
15module.exports.connect = function activityFeedSubscribeConnect(antisocialApp, currentUser, friend) {
16 var config = antisocialApp.config;
17 var db = antisocialApp.db;
18 var authUserMiddleware = antisocialApp.authUserMiddleware;
19
20 if (!antisocialApp.openActivityListeners) {
21 antisocialApp.openActivityListeners = {};
22 }
23
24 var key = currentUser.username + '<-' + friend.remoteEndPoint;
25
26 if (antisocialApp.openActivityListeners[key]) {
27 debug('activityFeedSubscribeConnect abort already connected %s', key);
28 return;
29 }
30
31 var remoteEndPoint = url.parse(friend.remoteEndPoint);
32 var endpoint = remoteEndPoint.protocol === 'https:' ? 'wss' : 'ws';
33 endpoint += '://' + remoteEndPoint.host;
34
35 debug('attempting to subscribe to ' + endpoint + '/antisocial-activity');
36
37 // open websocket connection
38 var socket = IOClient(endpoint, {
39 'path': '/antisocial-activity',
40 'reconnection': false
41 });
42
43 socket.on('reconnecting', function (attempt) {
44 debug('attempting reconnect %s %s', endpoint, attempt);
45 });
46
47 socket.on('reconnect_error', function () {
48 debug('reconnect attempt failed %s', endpoint);
49 });
50
51 socket.on('reconnect_failed', function () {
52 debug('reconnect failed %s', endpoint);
53 });
54
55 // once connected hookup events and authenticate
56 socket.on('connect', function () {
57 debug('client connected');
58
59 socket.on('unauthorized', function (err) {
60 debug('client unauthorized', err.message);
61 });
62
63 socket.on('error', function () {
64 debug('client error');
65 });
66
67 socket.on('authenticated', function () {
68 debug('client authenticated');
69
70 socket.antisocial = {
71 'key': key,
72 'friend': friend,
73 'user': currentUser,
74 'setDataHandler': function setDataHandler(handler) {
75 socket.antisocial.dataHandler = handler;
76 }
77 };
78
79 antisocialApp.openActivityListeners[socket.antisocial.key] = socket;
80
81 antisocialApp.emit('open-activity-connection', {
82 'info': socket.antisocial,
83 'socket': socket
84 });
85
86 socket.on('highwater', function (highwater) {
87 debug('got highwater from %s %j', socket.antisocial.friend.id, highwater);
88 antisocialApp.emit('activity-backfill', {
89 'info': socket.antisocial,
90 'socket': socket,
91 'highwater': highwater
92 });
93 });
94
95 socket.on('data', function (data) {
96 var decrypted = cryptography.decrypt(socket.antisocial.friend.remotePublicKey, socket.antisocial.friend.keys.private, data);
97 if (!decrypted.valid) { // could not validate signature
98 console.log('WatchNewsFeedItem decryption signature validation error:', decrypted.invalidReason);
99 return;
100 }
101
102 try {
103 data = JSON.parse(decrypted.data);
104 }
105 catch (e) {
106 data = decrypted.data;
107 }
108
109 if (socket.antisocial.dataHandler) {
110 socket.antisocial.dataHandler(data);
111 }
112 });
113
114 socket.on('disconnect', function (reason) {
115 antisocialApp.emit('close-activity-connection', {
116 'info': socket.antisocial,
117 'reason': reason
118 });
119
120 db.updateInstance('friends', socket.antisocial.friend.id, {
121 'online': false
122 });
123
124 delete antisocialApp.openActivityListeners[socket.antisocial.key];
125 });
126
127 socket.emit('highwater', socket.antisocial.friend.highWater ? socket.antisocial.friend.highWater : moment().subtract(7, 'd').toISOString());
128
129 db.updateInstance('friends', socket.antisocial.friend.id, {
130 'online': true
131 });
132 });
133
134 // perform authentication protocol
135 debug('authenticating');
136 socket.emit('authentication', {
137 'username': friend.remoteUsername,
138 'friendAccessToken': friend.remoteAccessToken
139 });
140 });
141};
142
143module.exports.disconnect = function activityFeedSubscribeDisconnect(antisocialApp, config, dbAdaptor, currentUser, friend) {
144 for (var key in antisocialApp.openActivityListeners) {
145 var socket = antisocialApp.openActivityListeners[key];
146 if (socket.data.friend.id.toString() === friend.id.toString()) {
147 debug('disconnect %s', socket.data.connectionKey);
148 socket.disconnect(true);
149 delete antisocialApp.openActivityListeners[key];
150 }
151 }
152};