UNPKG

7.14 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
5var express = require('express');
6var cookieParser = require('cookie-parser');
7var uuid = require('uuid');
8
9var app = express();
10
11app.use(express.json());
12app.use(express.urlencoded({
13 extended: false
14}));
15app.use(cookieParser());
16
17
18// mount the friend API under /antisocial
19var antisocial = require('./index');
20
21
22// Example database adaptor for persistant storage of users and friends
23// adapt these abstract methods to your application data storage scheme
24
25function dbHandler() {
26 var self = this;
27
28 self.collections = {
29 'users': {},
30 'friends': {},
31 'invitations': {},
32 'blocks': {}
33 };
34
35 // store an item after assigning an unique id
36 this.newInstance = function (collectionName, data, cb) {
37 data.id = uuid();
38 self.collections[collectionName][data.id] = data;
39 if (cb) {
40 cb(null, data);
41 }
42 else {
43 return data;
44 }
45 };
46
47 // get an item by matching some property
48 this.getInstances = function (collectionName, pairs, cb) {
49 var found = [];
50 for (var item in self.collections[collectionName]) {
51 if (self.collections[collectionName].hasOwnProperty(item)) {
52 var instance = self.collections[collectionName][item];
53
54 var match = 0;
55 for (var i = 0; i < pairs.length; i++) {
56 var prop = pairs[i].property;
57 var value = pairs[i].value;
58 if (instance[prop] === value) {
59 ++match;
60 }
61 }
62
63 if (match == pairs.length) {
64 found.push(instance);
65 }
66 }
67 }
68 if (cb) {
69 cb(null, found);
70 }
71 else {
72 return found;
73 }
74 };
75
76 // update item properties by id
77 this.updateInstance = function (collectionName, id, patch, cb) {
78 var item = self.collections[collectionName][id];
79 if (!item) {
80 if (cb) {
81 return cb('not found', null);
82 }
83 console.log('attempt to update a non existant instance %s.%s', collectionName, id);
84 return;
85 }
86 for (var prop in patch) {
87 if (patch.hasOwnProperty(prop)) {
88 item[prop] = patch[prop];
89 }
90 }
91 if (cb) {
92 cb(null, item);
93 }
94 else {
95 return item;
96 }
97 };
98
99 this.deleteInstance = function (collectionName, id, cb) {
100 var item = self.collections[collectionName][id];
101 if (!item) {
102 cb('not found', null);
103 }
104 delete self.collections[collectionName][id];
105 if (cb) {
106 cb(null);
107 }
108 };
109}
110
111var db = new dbHandler();
112
113
114/*
115 Example middleware adaptor to get the logged in user.
116 exposes the current user on req.antisocialUser
117 normally this would use a cookie via some sort of token
118 to find the user in this case we use the 'token' property
119 in the users collection
120*/
121
122function getAuthenticatedUser(req, res, next) {
123 var token;
124
125 if (req.cookies && req.cookies.access_token) {
126 token = req.cookies.access_token;
127 }
128
129 if (req.body && req.body.access_token) {
130 token = req.body.access_token;
131 }
132
133 if (!token) {
134 return next();
135 }
136
137 db.getInstances('users', [{
138 'property': 'token',
139 'value': token
140 }], function (err, userInstances) {
141 req.antisocialUser = userInstances[0];
142 next();
143 });
144}
145
146app.db = db;
147
148// user register route for tests
149var router = express.Router();
150router.all('/register', function (req, res) {
151 var params = req.method === 'GET' ? req.query : req.body;
152 app.db.newInstance('users', {
153 'name': params.name,
154 'username': params.username,
155 'token': uuid(),
156 'id': uuid()
157 }, function (err, user) {
158 res.cookie('access_token', user.token).send({
159 'status': 'ok',
160 'result': user
161 });
162 });
163});
164
165app.use(router);
166
167var server = null;
168
169app.start = function (port) {
170 var http = require('http');
171 server = http.createServer(app);
172 var listener = server.listen(port);
173
174
175 var config = {
176 'APIPrefix': '/antisocial',
177 'publicHost': 'http://127.0.0.1:3000',
178 'port': 3000
179 };
180
181 var antisocialApp = antisocial(app, config, db, getAuthenticatedUser);
182
183 app.postIdMap = {};
184 app.highwaterMap = {};
185
186 antisocialApp.on('new-friend-request', function (user, friend) {
187 console.log('antisocial new-friend-request %s %j', user.username, friend.remoteEndPoint);
188 });
189
190 antisocialApp.on('new-friend', function (user, friend) {
191 console.log('antisocial new-friend %s %j', user.username, friend.remoteEndPoint);
192
193 // simulate 10 'post' app items
194
195 if (!app.highwaterMap[friend.id]) {
196 app.highwaterMap[friend.id] = 0;
197 }
198 if (!app.postIdMap[user.id]) {
199 app.postIdMap[user.id] = 10;
200 }
201 });
202
203 antisocialApp.on('friend-updated', function (user, friend) {
204 console.log('antisocial friend-updated %s %s', user.username, friend.remoteEndPoint);
205 });
206
207 antisocialApp.on('friend-deleted', function (user, friend) {
208 console.log('antisocial friend-deleted %s %s', user.username, friend.remoteEndPoint);
209 });
210
211 antisocialApp.on('open-activity-connection', function (user, friend, emitter, info) {
212 console.log('antisocial open-activity-connection %s<-%s', user.username, friend.remoteEndPoint);
213 emitter('post', 'highwater', app.highwaterMap[friend.id] ? app.highwaterMap[friend.id] : 0);
214 });
215
216 antisocialApp.on('close-activity-connection', function (user, friend, reason) {
217 console.log('antisocial close-activity-connection %s<-%s %s', user.username, friend.remoteEndpoint, reason);
218 });
219
220 antisocialApp.on('open-notification-connection', function (user, emitter) {
221 console.log('antisocial open-notification-connection %s', user.username);
222 });
223
224 antisocialApp.on('close-notification-connection', function (user, reason) {
225 console.log('antisocial close-notification-connection %s %s', user.username, reason);
226 });
227
228 antisocialApp.on('activity-data-post', function (user, friend, data) {
229 console.log('antisocial activity-data-post user: %s friend: %s data: %j', user.name, friend.remoteEndPoint, data);
230 if (data.postId > app.highwaterMap[friend.id]) {
231 app.highwaterMap[friend.id] = data.postId;
232 }
233 });
234
235 antisocialApp.on('activity-backfill-post', function (user, friend, highwater, emitter) {
236 console.log('antisocial activity-backfill-post user: %s friend: %s highwater: %s', user.name, friend.remoteEndPoint, highwater);
237
238 // send posts from requested highwater to end of posts
239 for (var i = highwater + 1; i <= app.postIdMap[user.id]; i++) {
240 emitter('post', 'data', {
241 'backfill': true,
242 'postId': i,
243 'source': user.username
244 });
245 }
246 });
247
248 antisocialApp.on('notification-data-post', function (user, data) {
249 console.log('notification-data-post user: %s data: %j', user.name, data);
250 });
251
252 antisocialApp.on('notification-backfill-post', function (user, highwater, emitter) {
253 console.log('notification-backfill-post user: %s backfill: %s', user.username, highwater);
254 });
255
256 antisocialApp.listen(listener);
257};
258
259app.stop = function () {
260 server.close();
261};
262
263if (require.main === module) {
264 app.start(3000);
265}
266
267module.exports = app;