UNPKG

3.65 kBJavaScriptView Raw
1'use strict'
2
3const Promise = require('bluebird')
4const _ = require('lodash')
5
6/**
7 * Service infrastructure failures recovery.
8 *
9 * @mixin
10 * @memberof chat-service
11 * @see chat-service.ChatService.event:storeConsistencyFailure
12 */
13class RecoveryAPI {
14
15 constructor (state, transport, execUserCommand, instanceUID) {
16 this.state = state
17 this.transport = transport
18 this.instanceUID = instanceUID
19 this.execUserCommand = execUserCommand
20 }
21
22 checkUserSockets (user) {
23 let { userName } = user
24 return user.userState.getSocketsToInstance().then(sockets => {
25 return Promise.each(_.toPairs(sockets), ([socket, instance]) => {
26 if (instance === this.instanceUID) {
27 if (!this.transport.getSocket(socket)) {
28 return user.userState.removeSocket(socket)
29 }
30 }
31 return Promise.resolve()
32 })
33 }).then(() => {
34 return user.userState.getSocketsToRooms()
35 }).then(data => {
36 let args = _.values(data)
37 return _.intersection(...args)
38 }).then(rooms => {
39 return Promise.each(rooms, roomName => {
40 return this.state.getRoom(roomName)
41 .then(room => room.roomState.hasInList('userlist', userName))
42 .then(isPresent =>
43 isPresent ? Promise.resolve() : user.removeFromRoom(roomName))
44 .catchReturn()
45 })
46 })
47 }
48
49 checkRoomJoined (room) {
50 let { roomName } = room
51 return room.getList(null, 'userlist', true).then(userlist => {
52 return Promise.each(userlist, userName => {
53 return this.state.getUser(userName).then(user => {
54 return user.userState.getRoomToSockets(roomName).then(sockets => {
55 if (!sockets || !sockets.length) {
56 return user.removeFromRoom(roomName)
57 } else {
58 return Promise.resolve()
59 }
60 }).catchReturn()
61 .then(() => room.checkAcess(userName))
62 .catch(() => user.removeFromRoom(roomName))
63 }).catchReturn()
64 })
65 })
66 }
67
68 /**
69 * Sync user to sockets associations.
70 *
71 * @param {string} userName User name.
72 * @param {callback} [cb] Optional callback.
73 *
74 * @return {Promise<undefined>} Promise that resolves without any data.
75 */
76 userStateSync (userName, cb) {
77 return this.state.getUser(userName)
78 .then(user => this.checkUserSockets(user))
79 .asCallback(cb)
80 }
81
82 /**
83 * Sync room to users associations.
84 *
85 * @param {string} roomName Room name.
86 * @param {callback} [cb] Optional callback.
87 *
88 * @return {Promise<undefined>} Promise that resolves without any data.
89 */
90 roomStateSync (roomName, cb) {
91 return this.state.getRoom(roomName)
92 .then(room => this.checkRoomJoined(room))
93 .asCallback(cb)
94 }
95
96 /**
97 * Fixes an instance data after an incorrect service shutdown.
98 *
99 * @param {string} id Instance id.
100 * @param {callback} [cb] Optional callback.
101 *
102 * @return {Promise<undefined>} Promise that resolves without any data.
103 */
104 instanceRecovery (id, cb) {
105 return this.state.getInstanceSockets(id).then(sockets => {
106 return Promise.each(_.toPairs(sockets), ([id, userName]) => {
107 return this.state.getUser(userName)
108 .then(user => user.removeSocket(id))
109 .catchReturn()
110 })
111 }).asCallback(cb)
112 }
113
114 /**
115 * Gets an instance heartbeat.
116 *
117 * @param {string} id Instance id.
118 * @param {callback} [cb] Optional callback.
119 *
120 * @return {Promise<number>} Heartbeat timestamp.
121 */
122 getInstanceHeartbeat (id, cb) {
123 return this.state.getInstanceHeartbeat(id).asCallback(cb)
124 }
125
126}
127
128module.exports = RecoveryAPI