UNPKG

8.87 kBJavaScriptView Raw
1var q = require('q'),
2 _ = require('lodash'),
3 utils = require('../../utils'),
4 common = require('@screeps/common'),
5 config = common.configManager.config.backend,
6 db = common.storage.db,
7 env = common.storage.env;
8
9const USER_LIMIT = 2;
10
11const roomBuiltinUsers = {
12 '2': {_id: '2', username: 'Invader'},
13 '3': {_id: '3', username: 'Source Keeper'}
14};
15
16module.exports = function(listen, emit) {
17
18 var connectedToRooms = {}, m;
19
20 let usersLimit = {};
21
22 listen(/^roomsDone$/, _.throttle(() => {
23
24 usersLimit = {};
25
26 var roomNames = _.shuffle(_.keys(connectedToRooms));
27
28 roomNames.forEach(roomName => {
29
30 if(connectedToRooms[roomName].length > 0) {
31
32 var skip = true;
33
34 connectedToRooms[roomName].forEach((i) => {
35 usersLimit[i.user._id] = usersLimit[i.user._id] || 0;
36 usersLimit[i.user._id]++;
37 if (usersLimit[i.user._id] > USER_LIMIT) {
38 i._skip = true;
39 i.conn._writeEvent(`err@room:${roomName}`, 'subscribe limit reached');
40 return;
41 }
42 else {
43 i._skip = false;
44 skip = false;
45 }
46 });
47
48 if(skip) {
49 return;
50 }
51
52 var startTime = Date.now();
53
54 let promises = [
55 db['rooms.objects'].find({room: roomName}),
56 common.getGametime(),
57 db['rooms.flags'].find({room: roomName})
58 ];
59
60 q.all(promises).then(function(result) {
61
62 let roomObjects = result[0],
63 gameTime = parseInt(result[1]),
64 flags = result[2];
65
66 connectedToRooms[roomName].forEach((i) => {
67
68 if(i._skip) {
69 return;
70 }
71
72 let userFlagsData = _.find(flags, {user: ""+i.user._id});
73
74 let eventResult = {
75 objects: common.getDiff(i.objects, roomObjects),
76 flags: userFlagsData && userFlagsData.data,
77 gameTime
78 };
79
80 let eventResultPromises = [
81 env.mget([
82 env.keys.ROOM_VISUAL+`${i.user._id},,${gameTime-1}`,
83 env.keys.ROOM_VISUAL+`${i.user._id},${roomName},${gameTime-1}`
84 ]).then(data => {
85 eventResult.visual = "";
86 if(data[0]) {
87 eventResult.visual += data[0];
88 }
89 if(data[1]) {
90 eventResult.visual += data[1];
91 }
92 })
93 ];
94
95 i.objects = roomObjects;
96
97 let unknownUserIds = [];
98 roomObjects.forEach((object) => {
99 if(object.user && !i.users[object.user]) {
100 unknownUserIds.push(object.user);
101 }
102 if(object.reservation && !i.users[object.reservation.user]) {
103 unknownUserIds.push(object.reservation.user);
104 }
105 if(object.sign && !i.users[object.sign.user]) {
106 unknownUserIds.push(object.sign.user);
107 }
108 });
109 if(unknownUserIds.length) {
110
111 unknownUserIds = _.uniq(unknownUserIds);
112
113 eventResultPromises.push(
114 db.users.find({_id: {$in: unknownUserIds}},{ username: true, badge: true })
115 .then((unknownUsers) => {
116 unknownUsers.forEach((user) => i.users[user._id.toString()] = user);
117 unknownUsers = _.reduce(unknownUsers, (result, user) => {
118 result[user._id.toString()] = user;
119 return result;
120 }, {});
121 eventResult.users = unknownUsers;
122 })
123 );
124 }
125
126 if(/^(W|E)\d+(N|S)\d+$/.test(roomName)) {
127 eventResult.info = {
128 mode: 'world'
129 };
130 }
131
132 q.all(eventResultPromises).then(() => {
133 i.conn._writeEvent(`room:${roomName}`, eventResult);
134 });
135 });
136 });
137 }
138 });
139 }, config.socketUpdateThrottle));
140
141 return {
142 onSubscribe(channel, user, conn) {
143
144 if(!user) {
145 return false;
146 }
147
148 if(m = channel.match(/^room:([a-zA-Z0-9_-]+)$/)) {
149
150 let roomName = m[1], roomObjects;
151
152 db.rooms.findOne({_id: roomName})
153 .then((data) => {
154 if(!data) {
155 return q.reject('invalid room');
156 }
157
158 if(usersLimit[user._id] > USER_LIMIT) {
159 connectedToRooms[roomName] = connectedToRooms[roomName] || [];
160 connectedToRooms[roomName].push({
161 conn,
162 user,
163 objects: [],
164 users: _.cloneDeep(roomBuiltinUsers)
165 });
166 conn._writeEvent(`err@room:${roomName}`, 'subscribe limit reached');
167 return q.reject();
168 }
169 })
170 .then(() => db['rooms.objects'].find({room: roomName}))
171
172 .then((_roomObjects) => {
173 roomObjects = _roomObjects;
174 var userIds = _.reduce(roomObjects, (result, object) => {
175 if (object.user && object.user != '2' && object.user != '3') {
176 result.push(object.user);
177 }
178 return result;
179 }, []);
180 userIds = _.uniq(userIds);
181 return q.all([
182 db.users.find({_id: {$in: userIds}},{ username: true, badge: true }),
183 db['rooms.flags'].findOne({$and: [{room: roomName}, {user: ""+user._id}]})
184 ]);
185 })
186 .then((result) => {
187 let roomUsers = _.reduce(result[0], (result, i) => {
188 result[i._id.toString()] = i;
189 return result;
190 }, {});
191
192 let roomFlags = result[1];
193
194 _.extend(roomUsers, roomBuiltinUsers);
195
196 connectedToRooms[roomName] = connectedToRooms[roomName] || [];
197 connectedToRooms[roomName].push({
198 conn,
199 user,
200 objects: roomObjects,
201 users: roomUsers
202 });
203 conn._writeEvent(`room:${roomName}`, {
204 objects: common.getDiff([], roomObjects),
205 users: roomUsers,
206 flags: roomFlags && roomFlags.data,
207 info: {mode: 'world'}
208 });
209 })
210 .catch(console.error);
211
212 conn.on('close', () => {
213 if(connectedToRooms[roomName]) {
214 _.remove(connectedToRooms[roomName], (i) => i.conn === conn);
215 }
216 });
217
218 return true;
219 }
220
221 return false;
222 },
223
224 onUnsubscribe(channel, user, conn) {
225
226 if(m = channel.match(/^room:([a-zA-Z0-9_-]+)$/)) {
227 if(connectedToRooms[m[1]]) {
228 _.remove(connectedToRooms[m[1]], (i) => i.conn === conn);
229 }
230 }
231 }
232 };
233
234
235};
\No newline at end of file