UNPKG

10.2 kBJavaScriptView Raw
1'use strict'
2
3const ChatServiceError = require('./ChatServiceError')
4const Promise = require('bluebird')
5const _ = require('lodash')
6const { checkNameSymbols, possiblyCallback } = require('./utils')
7
8/**
9 * Server side operations.
10 *
11 * @mixin
12 * @memberof chat-service
13 * @see chat-service.ChatService
14 */
15class ServiceAPI {
16
17 constructor (state, makeUser, clusterBus) {
18 this.state = state
19 this.makeUser = makeUser
20 this.clusterBus = clusterBus
21 }
22
23 /**
24 * Executes {@link rpc.clientRequests} handlers.
25 *
26 * @param {string|boolean|Object} context Is a `userName` if
27 * `string`, or a `bypassPermissions` if `boolean`, or an options
28 * object if `Object`.
29 * @param {string} command Command name.
30 * @param {...*} args Command arguments.
31 * @param {callback} [cb] Optional callback.
32 *
33 * @property {string} [context.userName] User name.
34 * @property {string} [context.id] Socket id, it is required for
35 * {@link rpc.clientRequests.roomJoin} and {@link
36 * rpc.clientRequests.roomLeave} commands.
37 * @property {boolean} [context.bypassHooks=false] If `false`
38 * executes command without before and after hooks.
39 * @property {boolean} [context.bypassPermissions=false] If `true`
40 * executes command (except {@link rpc.clientRequests.roomJoin})
41 * bypassing built-in permissions checking.
42 *
43 * @return {Promise<Array>} Array of command results.
44 *
45 * @see rpc.clientRequests
46 */
47 execUserCommand (context, command, ...args) {
48 if (_.isObject(context)) {
49 var { userName } = context
50 context = _.clone(context)
51 } else if (_.isBoolean(context)) {
52 context = {bypassPermissions: context}
53 } else {
54 userName = context
55 context = {}
56 }
57 context.isLocalCall = true
58 let [nargs, cb] = possiblyCallback(args)
59 return Promise.try(() => {
60 if (userName) {
61 return this.state.getUser(userName)
62 } else {
63 return this.makeUser()
64 }
65 }).then(user => user.exec(command, context, nargs))
66 .asCallback(cb, { spread: true })
67 }
68
69 /**
70 * Adds an user with a state.
71 *
72 * @param {string} userName User name.
73 * @param {Object} [state] User state.
74 * @param {callback} [cb] Optional callback.
75 *
76 * @property {Array<string>} [state.whitelist=[]] User direct messages
77 * whitelist.
78 * @property {Array<string>} [state.blacklist=[]] User direct messages
79 * blacklist.
80 * @property {boolean} [state.whitelistOnly=false] User direct
81 * messages whitelistOnly mode.
82 *
83 * @return {Promise<undefined>} Promise that resolves without any data.
84 */
85 addUser (userName, state, cb) {
86 return checkNameSymbols(userName)
87 .then(() => this.state.addUser(userName, state))
88 .return()
89 .asCallback(cb)
90 }
91
92 /**
93 * Deletes an offline user. Will raise an error if a user has online
94 * sockets.
95 *
96 * @param {string} userName User name.
97 * @param {callback} [cb] Optional callback.
98 *
99 * @return {Promise<undefined>} Promise that resolves without any data.
100 */
101 deleteUser (userName, cb) {
102 return this.state.getUser(userName).then(user => {
103 return user.listOwnSockets().then(sockets => {
104 if (sockets && _.size(sockets) > 0) {
105 return Promise.reject(new ChatServiceError('userOnline', userName))
106 } else {
107 return Promise.all([
108 user.removeState(),
109 this.state.removeUser(userName)
110 ])
111 }
112 })
113 }).return().asCallback(cb)
114 }
115
116 /**
117 * Checks for an user existence.
118 *
119 * @param {string} userName User name.
120 * @param {callback} [cb] Optional callback.
121 *
122 * @return {Promise<boolean>} Predicate result.
123 */
124 hasUser (userName, cb) {
125 return this.state.getUser(userName, true)
126 .then(user => Boolean(user))
127 .asCallback(cb)
128 }
129
130 /**
131 * Checks for a name existence in a direct messaging list.
132 *
133 * @param {string} userName User name.
134 * @param {string} listName List name.
135 * @param {string} item List element.
136 * @param {callback} [cb] Optional callback.
137 *
138 * @return {Promise<boolean>} Predicate result.
139 */
140 userHasInList (userName, listName, item, cb) {
141 return this.state.getUser(userName)
142 .then(user => user.directMessaging.hasInList(listName, item))
143 .asCallback(cb)
144 }
145
146 /**
147 * Checks for a direct messaging permission.
148 *
149 * @param {string} recipient Recipient name.
150 * @param {string} sender Sender name.
151 * @param {callback} [cb] Optional callback.
152 *
153 * @return {Promise<boolean>} Predicate result.
154 */
155 hasDirectAccess (recipient, sender, cb) {
156 return this.state.getUser(recipient)
157 .then(user => user.directMessaging.checkAcess(sender))
158 .return(true)
159 .catchReturn(ChatServiceError, false)
160 .asCallback(cb)
161 }
162
163 /**
164 * Disconnects user's sockets for all service instances. Method is
165 * asynchronous, returns without waiting for the completion.
166 *
167 * @param {string} userName User name.
168 *
169 * @return {undefined} Returns no data.
170 */
171 disconnectUserSockets (userName) {
172 this.clusterBus.emit('disconnectUserSockets', userName)
173 }
174
175 /**
176 * Adds a room with a state.
177 *
178 * @param {string} roomName Room name.
179 * @param {Object} [state] Room state.
180 * @param {callback} [cb] Optional callback.
181 *
182 * @property {Array<string>} [state.whitelist=[]] Room whitelist.
183 * @property {Array<string>} [state.blacklist=[]] Room blacklist
184 * @property {Array<string>} [state.adminlist=[]] Room adminlist.
185 * @property {boolean} [state.whitelistOnly=false] Room
186 * whitelistOnly mode.
187 * @property {string} [state.owner] Room owner.
188 * @property {number} [state.historyMaxSize] Room history maximum
189 * size. Defalut value is {@link chat-service.config.options}
190 * `historyMaxSize`.
191 * @property {boolean} [state.enableAccessListsUpdates] Room enable
192 * access lists updates. Defalut value is {@link
193 * chat-service.config.options} `enableAccessListsUpdates`.
194 * @property {boolean} [state.enableUserlistUpdates] Room enable
195 * userlist updates. Defalut value is {@link
196 * chat-service.config.options} `enableUserlistUpdates`.
197 *
198 * @return {Promise<undefined>} Promise that resolves without any data.
199 */
200 addRoom (roomName, state, cb) {
201 return checkNameSymbols(roomName)
202 .then(() => this.state.addRoom(roomName, state))
203 .return()
204 .asCallback(cb)
205 }
206
207 /**
208 * Removes all joined users from the room and removes all room data.
209 *
210 * @param {string} roomName Room name.
211 * @param {callback} [cb] Optional callback.
212 *
213 * @return {Promise<undefined>} Promise that resolves without any data.
214 */
215 deleteRoom (roomName, cb) {
216 return this.execUserCommand(true, 'roomDelete', roomName)
217 .return()
218 .asCallback(cb)
219 }
220
221 /**
222 * Checks for a room existence.
223 *
224 * @param {string} roomName Room name.
225 * @param {callback} [cb] Optional callback.
226 *
227 * @return {Promise<boolean>} Predicate result.
228 */
229 hasRoom (roomName, cb) {
230 return this.state.getRoom(roomName, true)
231 .then(room => Boolean(room))
232 .asCallback(cb)
233 }
234
235 /**
236 * Checks for a name existence in a room list.
237 *
238 * @param {string} roomName Room name.
239 * @param {string} listName List name.
240 * @param {string} item List element.
241 * @param {callback} [cb] Optional callback.
242 *
243 * @return {Promise<boolean>} Predicate result.
244 */
245 roomHasInList (roomName, listName, item, cb) {
246 return this.state.getRoom(roomName)
247 .then(room => room.roomState.hasInList(listName, item))
248 .asCallback(cb)
249 }
250
251 /**
252 * Checks for a room access permission.
253 *
254 * @param {string} roomName Room name.
255 * @param {string} userName User name.
256 * @param {callback} [cb] Optional callback.
257 *
258 * @return {Promise<boolean>} Predicate result.
259 */
260 hasRoomAccess (roomName, userName, cb) {
261 return this.state.getRoom(roomName)
262 .then(room => room.checkAcess(userName))
263 .return(true)
264 .catchReturn(ChatServiceError, false)
265 .asCallback(cb)
266 }
267
268 /**
269 * Changes the room owner.
270 *
271 * @param {string} roomName Room name.
272 * @param {string} owner Owner user name.
273 * @param {callback} [cb] Optional callback.
274 *
275 * @return {Promise<undefined>} Promise that resolves without any data.
276 */
277 changeRoomOwner (roomName, owner, cb) {
278 return this.state.getRoom(roomName)
279 .then(room => room.roomState.ownerSet(owner))
280 .return()
281 .asCallback(cb)
282 }
283
284 /**
285 * Changes the room history size.
286 *
287 * @param {string} roomName Room name.
288 * @param {number} size Room history size.
289 * @param {callback} [cb] Optional callback.
290 *
291 * @return {Promise<undefined>} Promise that resolves without any data.
292 */
293 changeRoomHistoryMaxSize (roomName, size, cb) {
294 return this.state.getRoom(roomName)
295 .then(room => room.roomState.historyMaxSizeSet(size))
296 .return()
297 .asCallback(cb)
298 }
299
300 /**
301 * Enables or disables access lists updates for the room.
302 *
303 * @param {string} roomName Room name.
304 * @param {boolean} mode Enable or disable.
305 * @param {callback} [cb] Optional callback.
306 *
307 * @return {Promise<undefined>} Promise that resolves without any data.
308 *
309 * @see rpc.serverNotifications.roomAccessListAdded
310 * @see rpc.serverNotifications.roomAccessListRemoved
311 * @see rpc.serverNotifications.roomModeChanged
312 */
313 changeAccessListsUpdates (roomName, mode, cb) {
314 return this.state.getRoom(roomName)
315 .then(room => room.roomState.accessListsUpdatesSet(mode))
316 .return()
317 .asCallback(cb)
318 }
319
320 /**
321 * Enables or disables user list updates for the room.
322 *
323 * @param {string} roomName Room name.
324 * @param {boolean} mode Enable or disable.
325 * @param {callback} [cb] Optional callback.
326 *
327 * @return {Promise<undefined>} Promise that resolves without any data.
328 *
329 * @see rpc.serverNotifications.roomUserJoined
330 * @see rpc.serverNotifications.roomUserLeft
331 */
332 changeUserlistUpdates (roomName, mode, cb) {
333 return this.state.getRoom(roomName)
334 .then(room => room.roomState.userlistUpdatesSet(mode))
335 .return()
336 .asCallback(cb)
337 }
338
339}
340
341module.exports = ServiceAPI