1 | var 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 |
|
9 | const USER_LIMIT = 2;
|
10 |
|
11 | const roomBuiltinUsers = {
|
12 | '2': {_id: '2', username: 'Invader'},
|
13 | '3': {_id: '3', username: 'Source Keeper'}
|
14 | };
|
15 |
|
16 | module.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 |