(socket:any, message: ClientReadyMessage)
| 1121 | * @param message the message from the client |
| 1122 | */ |
| 1123 | const handleClientReady = async (socket:any, message: ClientReadyMessage) => { |
| 1124 | const sessionInfo = sessioninfos[socket.id]; |
| 1125 | if (sessionInfo == null) throw new Error('client disconnected'); |
| 1126 | assert(sessionInfo.author); |
| 1127 | |
| 1128 | await hooks.aCallAll('clientReady', message); // Deprecated due to awkward context. |
| 1129 | |
| 1130 | let {colorId: authorColorId, name: authorName} = message.userInfo || {}; |
| 1131 | if (authorColorId && !/^#(?:[0-9A-F]{3}){1,2}$/i.test(authorColorId as string)) { |
| 1132 | messageLogger.warn(`Ignoring invalid colorId in CLIENT_READY message: ${authorColorId}`); |
| 1133 | // @ts-ignore |
| 1134 | authorColorId = null; |
| 1135 | } |
| 1136 | await Promise.all([ |
| 1137 | authorName && authorManager.setAuthorName(sessionInfo.author, authorName), |
| 1138 | authorColorId && authorManager.setAuthorColorId(sessionInfo.author, authorColorId), |
| 1139 | ]); |
| 1140 | ({colorId: authorColorId, name: authorName} = await authorManager.getAuthor(sessionInfo.author)); |
| 1141 | |
| 1142 | const padExisted = await padManager.doesPadExist(sessionInfo.padId); |
| 1143 | // load the pad-object from the database |
| 1144 | const pad = await padManager.getPad(sessionInfo.padId, null, sessionInfo.author); |
| 1145 | if (settings.enablePadWideSettings && !padExisted && message.padSettingsDefaults) { |
| 1146 | pad.setPadSettings(message.padSettingsDefaults); |
| 1147 | await pad.saveToDatabase(); |
| 1148 | } |
| 1149 | |
| 1150 | // these db requests all need the pad object (timestamp of latest revision, author data) |
| 1151 | const authors = pad.getAllAuthors(); |
| 1152 | |
| 1153 | // get timestamp of latest revision needed for timeslider |
| 1154 | const currentTime = await pad.getRevisionDate(pad.getHeadRevisionNumber()); |
| 1155 | |
| 1156 | // get all author data out of the database (in parallel) |
| 1157 | const historicalAuthorData:MapArrayType<{ |
| 1158 | name: string; |
| 1159 | colorId: string; |
| 1160 | }> = {}; |
| 1161 | await Promise.all(authors.map(async (authorId: string) => { |
| 1162 | const author = await authorManager.getAuthor(authorId); |
| 1163 | if (!author) { |
| 1164 | messageLogger.error(`There is no author for authorId: ${authorId}. ` + |
| 1165 | 'This is possibly related to https://github.com/ether/etherpad-lite/issues/2802'); |
| 1166 | } else { |
| 1167 | // Filter author attribs (e.g. don't send author's pads to all clients) |
| 1168 | historicalAuthorData[authorId] = {name: author.name, colorId: author.colorId}; |
| 1169 | } |
| 1170 | })); |
| 1171 | |
| 1172 | // glue the clientVars together, send them and tell the other clients that a new one is there |
| 1173 | |
| 1174 | // Check if the user has disconnected during any of the above awaits. |
| 1175 | if (sessionInfo !== sessioninfos[socket.id]) throw new Error('client disconnected'); |
| 1176 | |
| 1177 | const {session: {user} = {}} = socket.client.request as SocketClientRequest; |
| 1178 | |
| 1179 | // The duplicate-author kick exists because cookie-derived authorIDs are |
| 1180 | // per-browser, so "same authorID, same pad" historically meant "stale tab in |
no test coverage detected