UNPKG

wechaty-puppet-service

Version:
1,123 lines 52.5 kB
import { chunkDecoder, chunkEncoder, StringValue, grpc, puppet as grpcPuppet, } from 'wechaty-grpc'; import * as PUPPET from 'wechaty-puppet'; import { timeoutPromise } from 'gerror'; import { packFileBoxToPb, unpackConversationIdFileBoxArgsFromPb, } from '../deprecated/mod.js'; import { timestampFromMilliseconds, } from '../pure-functions/timestamp.js'; import { normalizeFileBoxUuid, } from '../file-box-helper/mod.js'; import { log } from '../config.js'; import { grpcError } from './grpc-error.js'; import { EventStreamManager } from './event-stream-manager.js'; function puppetImplementation(puppet, FileBoxUuid) { /** * Save scan payload to send it to the puppet-service right after connected (if needed) * * TODO: clean the listeners if necessary */ let scanPayload; let readyPayload; let readyTimeout; puppet.on('scan', payload => { scanPayload = payload; }); puppet.on('ready', payload => { readyPayload = payload; }); puppet.on('logout', _ => { readyPayload = undefined; if (readyTimeout) { clearTimeout(readyTimeout); } }); puppet.on('login', _ => { scanPayload = undefined; readyTimeout = setTimeout(() => { // Huan(202110): should we emit ready event here? readyPayload && eventStreamManager.grpcEmit(grpcPuppet.EventType.EVENT_TYPE_READY, readyPayload); }, 5 * 1000); }); const eventStreamManager = new EventStreamManager(puppet); const serializeFileBox = async (fileBox) => { /** * 1. if the fileBox is one of type `Url`, `QRCode`, `Uuid`, etc, * then it can be serialized by `fileBox.toString()` * 2. if the fileBox is one of type `Stream`, `Buffer`, `File`, etc, * then it need to be convert to type `Uuid` * before serialized by `fileBox.toString()` */ const normalizedFileBox = await normalizeFileBoxUuid(FileBoxUuid)(fileBox); return JSON.stringify(normalizedFileBox); }; const puppetServerImpl = { contactAlias: async (call, callback) => { log.verbose('PuppetServiceImpl', 'contactAlias()'); const id = call.request.getId(); /** * Set */ if (call.request.hasAlias()) { try { await puppet.contactAlias(id, call.request.getAlias()); return callback(null, new grpcPuppet.ContactAliasResponse()); } catch (e) { return grpcError('contactAlias', e, callback); } } /** * Get */ try { const alias = await puppet.contactAlias(id); const response = new grpcPuppet.ContactAliasResponse(); response.setAlias(alias); return callback(null, response); } catch (e) { return grpcError('contactAlias', e, callback); } }, contactAvatar: async (call, callback) => { log.verbose('PuppetServiceImpl', 'contactAvatar()'); const id = call.request.getId(); /** * Set */ try { if (call.request.hasFileBox()) { const fileBox = FileBoxUuid.fromJSON(call.request.getFileBox()); await puppet.contactAvatar(id, fileBox); return callback(null, new grpcPuppet.ContactAvatarResponse()); } } catch (e) { return grpcError('contactAvatar', e, callback); } /** * Get */ try { const fileBox = await puppet.contactAvatar(id); const serializedFileBox = await serializeFileBox(fileBox); const response = new grpcPuppet.ContactAvatarResponse(); response.setFileBox(serializedFileBox); return callback(null, response); } catch (e) { return grpcError('contactAvatar', e, callback); } }, contactCorporationRemark: async (call, callback) => { log.verbose('PuppetServiceImpl', 'contactCorporationRemark()'); const contactId = call.request.getContactId(); try { await puppet.contactCorporationRemark(contactId, call.request.getCorporationRemark() || null); return callback(null, new grpcPuppet.ContactCorporationRemarkResponse()); } catch (e) { return grpcError('contactCorporationRemark', e, callback); } }, contactDescription: async (call, callback) => { log.verbose('PuppetServiceImpl', 'contactDescription()'); const contactId = call.request.getContactId(); try { const description = call.request.getDescription(); await puppet.contactDescription(contactId, description || null); return callback(null, new grpcPuppet.ContactDescriptionResponse()); } catch (e) { return grpcError('contactDescription', e, callback); } }, contactList: async (call, callback) => { log.verbose('PuppetServiceImpl', 'contactList()'); void call; // empty request try { const idList = await puppet.contactList(); const response = new grpcPuppet.ContactListResponse(); response.setIdsList(idList); return callback(null, response); } catch (e) { return grpcError('contactList', e, callback); } }, contactPayload: async (call, callback) => { log.verbose('PuppetServiceImpl', 'contactPayload()'); const id = call.request.getId(); try { const payload = await puppet.contactPayload(id); const response = new grpcPuppet.ContactPayloadResponse(); response.setAddress(payload.address || ''); response.setAlias(payload.alias || ''); response.setAvatar(payload.avatar); response.setCity(payload.city || ''); response.setFriend(payload.friend || false); response.setGender(payload.gender); response.setId(payload.id); response.setName(payload.name); response.setProvince(payload.province || ''); response.setSignature(payload.signature || ''); response.setStar(payload.star || false); response.setType(payload.type); response.setWeixin(payload.weixin || ''); response.setPhonesList(payload.phone); response.setCoworker(payload.coworker || false); response.setCorporation(payload.corporation || ''); response.setTitle(payload.title || ''); response.setDescription(payload.description || ''); return callback(null, response); } catch (e) { return grpcError('contactPayload', e, callback); } }, contactPhone: async (call, callback) => { log.verbose('PuppetServiceImpl', 'contactPhone()'); try { const contactId = call.request.getContactId(); const phoneList = call.request.getPhonesList(); await puppet.contactPhone(contactId, phoneList); return callback(null, new grpcPuppet.ContactPhoneResponse()); } catch (e) { return grpcError('contactPhone', e, callback); } }, contactSelfName: async (call, callback) => { log.verbose('PuppetServiceImpl', 'contactSelfName()'); try { const name = call.request.getName(); await puppet.contactSelfName(name); return callback(null, new grpcPuppet.ContactSelfNameResponse()); } catch (e) { return grpcError('contactSelfName', e, callback); } }, contactSelfQRCode: async (call, callback) => { log.verbose('PuppetServiceImpl', 'contactSelfName()'); void call; try { const qrcode = await puppet.contactSelfQRCode(); const response = new grpcPuppet.ContactSelfQRCodeResponse(); response.setQrcode(qrcode); return callback(null, response); } catch (e) { return grpcError('contactSelfQRCode', e, callback); } }, contactSelfSignature: async (call, callback) => { log.verbose('PuppetServiceImpl', 'contactSelfSignature()'); try { const signature = call.request.getSignature(); await puppet.contactSelfSignature(signature); return callback(null, new grpcPuppet.ContactSelfSignatureResponse()); } catch (e) { return grpcError('contactSelfSignature', e, callback); } }, ding: async (call, callback) => { log.verbose('PuppetServiceImpl', 'ding()'); try { const data = call.request.getData(); await puppet.ding(data); return callback(null, new grpcPuppet.DingResponse()); } catch (e) { return grpcError('ding', e, callback); } }, dirtyPayload: async (call, callback) => { log.verbose('PuppetServiceImpl', 'dirtyPayload()'); try { const id = call.request.getId(); const type = call.request.getType(); await puppet.dirtyPayload(type, id); return callback(null, new grpcPuppet.DirtyPayloadResponse()); } catch (e) { return grpcError('puppet.dirtyPayload() rejection: ', e, callback); } }, /** * * Bridge Event Emitter Events * */ event: (streamingCall) => { log.verbose('PuppetServiceImpl', 'event()'); if (eventStreamManager.busy()) { log.error('PuppetServiceImpl', 'event() there is another event() call not end when receiving a new one.'); const error = { ...new Error('GrpcServerImpl.event() can not call twice.'), code: grpc.status.ALREADY_EXISTS, details: 'GrpcServerImpl.event() can not call twice.', metadata: streamingCall.metadata, }; /** * Send error from gRPC server stream: * https://github.com/grpc/grpc-node/issues/287#issuecomment-383218225 * * Streaming RPCs * - https://grpc.io/docs/tutorials/basic/node/ * Only one of 'error' or 'end' will be emitted. Finally, the 'status' event fires when the server sends the status. */ streamingCall.emit('error', error); return; } eventStreamManager.start(streamingCall); /** * If `scanPayload` is not undefined, then we emit it to downstream immediatelly */ if (scanPayload) { eventStreamManager.grpcEmit(grpcPuppet.EventType.EVENT_TYPE_SCAN, scanPayload); } }, friendshipAccept: async (call, callback) => { log.verbose('PuppetServiceImpl', 'friendshipAccept()'); try { const id = call.request.getId(); await puppet.friendshipAccept(id); return callback(null, new grpcPuppet.FriendshipAcceptResponse()); } catch (e) { return grpcError('friendshipAccept', e, callback); } }, friendshipAdd: async (call, callback) => { log.verbose('PuppetServiceImpl', 'friendshipAdd()'); try { const contactId = call.request.getContactId(); // FIXME: for backward compatibility, need to be removed after all puppet has updated. const hello = call.request.getHello(); const referrer = call.request.getReferrer(); const friendshipAddOptions = { hello, ...referrer, }; { // Deprecated: will be removed after Dec 31, 2022 const sourceContactId = call.request.getSourceContactIdStringValueDeprecated()?.getValue(); const sourceRoomId = call.request.getSourceRoomIdStringValueDeprecated()?.getValue(); if (sourceContactId) { friendshipAddOptions['contactId'] = sourceContactId; } if (sourceRoomId) { friendshipAddOptions['roomId'] = sourceRoomId; } } await puppet.friendshipAdd(contactId, friendshipAddOptions); return callback(null, new grpcPuppet.FriendshipAddResponse()); } catch (e) { return grpcError('friendshipAdd', e, callback); } }, friendshipPayload: async (call, callback) => { log.verbose('PuppetServiceImpl', 'friendshipPayload()'); try { const id = call.request.getId(); const payload = await puppet.friendshipPayload(id); const payloadReceive = payload; const response = new grpcPuppet.FriendshipPayloadResponse(); response.setContactId(payload.contactId); response.setHello(payload.hello || ''); response.setId(payload.id); response.setScene(payloadReceive.scene || PUPPET.types.FriendshipScene.Unknown); response.setStranger(payloadReceive.stranger || ''); response.setTicket(payloadReceive.ticket); response.setType(payload.type); return callback(null, response); } catch (e) { return grpcError('friendshipPayload', e, callback); } }, friendshipSearchPhone: async (call, callback) => { log.verbose('PuppetServiceImpl', 'friendshipSearchPhone()'); try { const phone = call.request.getPhone(); const contactId = await puppet.friendshipSearchPhone(phone); const response = new grpcPuppet.FriendshipSearchPhoneResponse(); if (contactId) { response.setContactId(contactId); } return callback(null, response); } catch (e) { return grpcError('friendshipSearchPhone', e, callback); } }, friendshipSearchWeixin: async (call, callback) => { log.verbose('PuppetServiceImpl', 'friendshipSearchWeixin()'); try { const weixin = call.request.getWeixin(); const contactId = await puppet.friendshipSearchWeixin(weixin); const response = new grpcPuppet.FriendshipSearchWeixinResponse(); if (contactId) { response.setContactId(contactId); } return callback(null, response); } catch (e) { return grpcError('friendshipSearchWeixin', e, callback); } }, logout: async (call, callback) => { log.verbose('PuppetServiceImpl', 'logout()'); void call; // empty arguments try { await puppet.logout(); return callback(null, new grpcPuppet.LogoutResponse()); } catch (e) { return grpcError('logout', e, callback); } }, messageContact: async (call, callback) => { log.verbose('PuppetServiceImpl', 'messageContact()'); try { const id = call.request.getId(); const contactId = await puppet.messageContact(id); const response = new grpcPuppet.MessageContactResponse(); response.setId(contactId); return callback(null, response); } catch (e) { return grpcError('messageContact', e, callback); } }, messageFile: async (call, callback) => { log.verbose('PuppetServiceImpl', 'messageFile()'); try { const id = call.request.getId(); const fileBox = await puppet.messageFile(id); const serializedFileBox = await serializeFileBox(fileBox); const response = new grpcPuppet.MessageFileResponse(); response.setFileBox(serializedFileBox); return callback(null, response); } catch (e) { return grpcError('messageFile', e, callback); } }, /** * @deprecated will be removed after Dec 31, 2022 */ messageFileStream: async (call) => { log.verbose('PuppetServiceImpl', 'messageFileStream()'); try { const id = call.request.getId(); const fileBox = await puppet.messageFile(id); const response = await packFileBoxToPb(grpcPuppet.MessageFileStreamResponse)(fileBox); response.on('error', e => call.destroy(e)); response.pipe(call); // Huan(202203): FIXME: as unknown as } catch (e) { log.error('PuppetServiceImpl', 'grpcError() messageFileStream() rejection: %s', e && e.message); call.destroy(e); } }, messageForward: async (call, callback) => { log.verbose('PuppetServiceImpl', 'messageForward()'); try { const conversationId = call.request.getConversationId(); const messageId = call.request.getMessageId(); const id = await puppet.messageForward(conversationId, messageId); const response = new grpcPuppet.MessageForwardResponse(); if (id) { response.setId(id); { /** * Huan(202110): Deprecated: will be removed after Dec 31, 2022 */ const idWrapper = new StringValue(); idWrapper.setValue(id); response.setIdStringValueDeprecated(idWrapper); } } return callback(null, response); } catch (e) { return grpcError('messageForward', e, callback); } }, messageImage: async (call, callback) => { log.verbose('PuppetServiceImpl', 'messageImage()'); try { const id = call.request.getId(); const type = call.request.getType(); const fileBox = await puppet.messageImage(id, type); const serializedFileBox = await serializeFileBox(fileBox); const response = new grpcPuppet.MessageImageResponse(); response.setFileBox(serializedFileBox); return callback(null, response); } catch (e) { return grpcError('messageImage', e, callback); } }, /** * @deprecated will be removed after Dec 31, 2022 */ messageImageStream: async (call) => { log.verbose('PuppetServiceImpl', 'messageImageStream()'); try { const id = call.request.getId(); const type = call.request.getType(); const fileBox = await puppet.messageImage(id, type); // as number as PUPPET.types.Image const response = await packFileBoxToPb(grpcPuppet.MessageImageStreamResponse)(fileBox); response.on('error', e => call.destroy(e)); response.pipe(call); // Huan(202203) FIXME: as unknown as } catch (e) { log.error('PuppetServiceImpl', 'grpcError() messageImageStream() rejection: %s', e.message); call.destroy(e); } }, messageLocation: async (call, callback) => { log.verbose('PuppetServiceImpl', 'messageLocation()'); try { const id = call.request.getId(); const payload = await puppet.messageLocation(id); const response = new grpcPuppet.MessageLocationResponse(); const pbLocationPayload = new grpcPuppet.LocationPayload(); pbLocationPayload.setLatitude(payload.latitude); pbLocationPayload.setLongitude(payload.longitude); pbLocationPayload.setAccuracy(payload.accuracy); pbLocationPayload.setAddress(payload.address); pbLocationPayload.setName(payload.name); response.setLocation(pbLocationPayload); return callback(null, response); } catch (e) { return grpcError('messageLocation', e, callback); } }, messageMiniProgram: async (call, callback) => { log.verbose('PuppetServiceImpl', 'messageMiniProgram()'); try { const id = call.request.getId(); const payload = await puppet.messageMiniProgram(id); const response = new grpcPuppet.MessageMiniProgramResponse(); const pbMiniProgramPayload = new grpcPuppet.MiniProgramPayload(); if (payload.appid) { pbMiniProgramPayload.setAppid(payload.appid); } if (payload.description) { pbMiniProgramPayload.setDescription(payload.description); } if (payload.iconUrl) { pbMiniProgramPayload.setIconUrl(payload.iconUrl); } if (payload.pagePath) { pbMiniProgramPayload.setPagePath(payload.pagePath); } if (payload.shareId) { pbMiniProgramPayload.setShareId(payload.shareId); } if (payload.thumbKey) { pbMiniProgramPayload.setThumbKey(payload.thumbKey); } if (payload.thumbUrl) { pbMiniProgramPayload.setThumbUrl(payload.thumbUrl); } if (payload.title) { pbMiniProgramPayload.setTitle(payload.title); } if (payload.username) { pbMiniProgramPayload.setUsername(payload.username); } response.setMiniProgram(pbMiniProgramPayload); // Deprecated after Dec 31, 2022 response.setMiniProgramDeprecated(JSON.stringify(payload)); return callback(null, response); } catch (e) { return grpcError('messageMiniProgram', e, callback); } }, messagePayload: async (call, callback) => { log.verbose('PuppetServiceImpl', 'messagePayload()'); try { const id = call.request.getId(); const payload = await puppet.messagePayload(id); const mentionIdList = ('mentionIdList' in payload) ? payload.mentionIdList || [] : []; const response = new grpcPuppet.MessagePayloadResponse(); response.setFilename(payload.filename || ''); /** * Huan(202203):`payload.fromId` is deprecated, will be removed in v2.0 */ response.setTalkerId(payload.talkerId || payload.fromId || ''); response.setId(payload.id); response.setMentionIdsList(mentionIdList); response.setRoomId(payload.roomId || ''); response.setText(payload.text || ''); response.setReceiveTime(timestampFromMilliseconds(payload.timestamp)); // Deprecated: will be removed after Dec 31, 2022 response.setTimestampDeprecated(Math.floor(payload.timestamp)); /** * Huan(202203):`payload.toId` is deprecated, will be removed in v2.0 */ response.setListenerId(payload.listenerId || payload.toId || ''); response.setType(payload.type); return callback(null, response); } catch (e) { return grpcError('messagePayload', e, callback); } }, messageRecall: async (call, callback) => { log.verbose('PuppetServiceImpl', 'messageRecall()'); try { const id = call.request.getId(); const success = await puppet.messageRecall(id); const response = new grpcPuppet.MessageRecallResponse(); response.setSuccess(success); return callback(null, response); } catch (e) { return grpcError('messageRecall', e, callback); } }, messageSendContact: async (call, callback) => { log.verbose('PuppetServiceImpl', 'messageSendContact()'); try { const conversationId = call.request.getConversationId(); const contactId = call.request.getContactId(); const messageId = await puppet.messageSendContact(conversationId, contactId); const response = new grpcPuppet.MessageSendContactResponse(); if (messageId) { response.setId(messageId); { /** * Huan(202110): Deprecated: will be removed after Dec 31, 2022 */ const idWrapper = new StringValue(); idWrapper.setValue(messageId); response.setIdStringValueDeprecated(idWrapper); } } return callback(null, response); } catch (e) { return grpcError('messageSendContact', e, callback); } }, messageSendFile: async (call, callback) => { log.verbose('PuppetServiceImpl', 'messageSendFile()'); try { const conversationId = call.request.getConversationId(); const jsonText = call.request.getFileBox(); const fileBox = FileBoxUuid.fromJSON(jsonText); const messageId = await puppet.messageSendFile(conversationId, fileBox); const response = new grpcPuppet.MessageSendFileResponse(); if (messageId) { response.setId(messageId); { /** * Huan(202110): Deprecated: will be removed after Dec 31, 2022 */ const idWrapper = new StringValue(); idWrapper.setValue(messageId); response.setIdStringValueDeprecated(idWrapper); } } return callback(null, response); } catch (e) { return grpcError('messageSendFile', e, callback); } }, /** * @deprecated will be removed after Dec 31, 2022 */ messageSendFileStream: async (call, callback) => { log.verbose('PuppetServiceImpl', 'messageSendFileStream()'); try { const requestArgs = await unpackConversationIdFileBoxArgsFromPb(call); const conversationId = requestArgs.conversationId; const fileBox = requestArgs.fileBox; const messageId = await puppet.messageSendFile(conversationId, fileBox); const response = new grpcPuppet.MessageSendFileStreamResponse(); if (messageId) { response.setId(messageId); { /** * Huan(202110): Deprecated: will be removed after Dec 31, 2022 */ const idWrapper = new StringValue(); idWrapper.setValue(messageId); response.setIdStringValueDeprecated(idWrapper); } } return callback(null, response); } catch (e) { return grpcError('messageSendFileStream', e, callback); } }, messageSendLocation: async (call, callback) => { log.verbose('PuppetServiceImpl', 'messageSendLocation()'); try { const conversationId = call.request.getConversationId(); const pbLocationPayload = call.request.getLocation(); const payload = { accuracy: 0, address: 'NOADDRESS', latitude: 0, longitude: 0, name: 'NONAME', ...pbLocationPayload, }; const messageId = await puppet.messageSendLocation(conversationId, payload); const response = new grpcPuppet.MessageSendLocationResponse(); if (messageId) { response.setId(messageId); } return callback(null, response); } catch (e) { return grpcError('messageSendLocation', e, callback); } }, messageSendMiniProgram: async (call, callback) => { log.verbose('PuppetServiceImpl', 'messageSendMiniProgram()'); try { const conversationId = call.request.getConversationId(); let pbMiniProgramPayload = call.request.getMiniProgram()?.toObject(); if (!pbMiniProgramPayload) { // Deprecated: will be removed after Dec 31, 2022 const jsonText = call.request.getMiniProgramDeprecated(); pbMiniProgramPayload = JSON.parse(jsonText); } const payload = { ...pbMiniProgramPayload, }; const messageId = await puppet.messageSendMiniProgram(conversationId, payload); const response = new grpcPuppet.MessageSendMiniProgramResponse(); if (messageId) { response.setId(messageId); { /** * Huan(202110): Deprecated: will be removed after Dec 31, 2022 */ const idWrapper = new StringValue(); idWrapper.setValue(messageId); response.setIdStringValueDeprecated(idWrapper); } } return callback(null, response); } catch (e) { return grpcError('messageSendMiniProgram', e, callback); } }, messageSendText: async (call, callback) => { log.verbose('PuppetServiceImpl', 'messageSendText()'); try { const conversationId = call.request.getConversationId(); const text = call.request.getText(); const mentionIdList = call.request.getMentionalIdsList(); const messageId = await puppet.messageSendText(conversationId, text, mentionIdList); const response = new grpcPuppet.MessageSendTextResponse(); if (messageId) { response.setId(messageId); { /** * Huan(202110): Deprecated: will be removed after Dec 31, 2022 */ const idWrapper = new StringValue(); idWrapper.setValue(messageId); response.setIdStringValueDeprecated(idWrapper); } } return callback(null, response); } catch (e) { return grpcError('messageSendText', e, callback); } }, messageSendUrl: async (call, callback) => { log.verbose('PuppetServiceImpl', 'messageSendUrl()'); try { const conversationId = call.request.getConversationId(); let pbUrlLinkPayload = call.request.getUrlLink()?.toObject(); if (!pbUrlLinkPayload) { // Deprecated: will be removed after Dec 31, 2022 const jsonText = call.request.getUrlLinkDeprecated(); pbUrlLinkPayload = JSON.parse(jsonText); } const payload = { title: 'NOTITLE', url: 'NOURL', ...pbUrlLinkPayload, }; const messageId = await puppet.messageSendUrl(conversationId, payload); const response = new grpcPuppet.MessageSendUrlResponse(); if (messageId) { response.setId(messageId); { /** * Huan(202110): Deprecated: will be removed after Dec 31, 2022 */ const idWrapper = new StringValue(); idWrapper.setValue(messageId); response.setIdStringValueDeprecated(idWrapper); } } return callback(null, response); } catch (e) { return grpcError('messageSendUrl', e, callback); } }, messageUrl: async (call, callback) => { log.verbose('PuppetServiceImpl', 'messageUrl()'); try { const id = call.request.getId(); const payload = await puppet.messageUrl(id); const response = new grpcPuppet.MessageUrlResponse(); const pbUrlLinkPayload = new grpcPuppet.UrlLinkPayload(); pbUrlLinkPayload.setTitle(payload.title); pbUrlLinkPayload.setUrl(payload.url); if (payload.thumbnailUrl) { pbUrlLinkPayload.setThumbnailUrl(payload.thumbnailUrl); } if (payload.description) { pbUrlLinkPayload.setDescription(payload.description); } response.setUrlLink(pbUrlLinkPayload); // Deprecated: will be removed after Dec 31, 2022 response.setUrlLinkDeprecated(JSON.stringify(payload)); return callback(null, response); } catch (e) { return grpcError('messageUrl', e, callback); } }, roomAdd: async (call, callback) => { log.verbose('PuppetServiceImpl', 'roomAdd()'); try { const roomId = call.request.getId(); const contactId = call.request.getContactId(); const inviteOnly = call.request.getInviteOnly(); await puppet.roomAdd(roomId, contactId, inviteOnly); return callback(null, new grpcPuppet.RoomAddResponse()); } catch (e) { return grpcError('roomAdd', e, callback); } }, roomAnnounce: async (call, callback) => { log.verbose('PuppetServiceImpl', 'roomAnnounce()'); try { const roomId = call.request.getId(); /** * Set */ if (call.request.hasText()) { await puppet.roomAnnounce(roomId, call.request.getText()); return callback(null, new grpcPuppet.RoomAnnounceResponse()); } /** * Get */ const text = await puppet.roomAnnounce(roomId); const response = new grpcPuppet.RoomAnnounceResponse(); response.setText(text); return callback(null, response); } catch (e) { return grpcError('roomAnnounce', e, callback); } }, roomAvatar: async (call, callback) => { log.verbose('PuppetServiceImpl', 'roomAvatar()'); try { const roomId = call.request.getId(); const fileBox = await puppet.roomAvatar(roomId); const serializedFileBox = await serializeFileBox(fileBox); const response = new grpcPuppet.RoomAvatarResponse(); response.setFileBox(serializedFileBox); return callback(null, response); } catch (e) { return grpcError('roomAvatar', e, callback); } }, roomCreate: async (call, callback) => { log.verbose('PuppetServiceImpl', 'roomCreate()'); try { const contactIdList = call.request.getContactIdsList(); const topic = call.request.getTopic(); const roomId = await puppet.roomCreate(contactIdList, topic); const response = new grpcPuppet.RoomCreateResponse(); response.setId(roomId); return callback(null, response); } catch (e) { return grpcError('roomCreate', e, callback); } }, roomDel: async (call, callback) => { log.verbose('PuppetServiceImpl', 'roomDel()'); try { const roomId = call.request.getId(); const contactId = call.request.getContactId(); await puppet.roomDel(roomId, contactId); return callback(null, new grpcPuppet.RoomDelResponse()); } catch (e) { return grpcError('roomDel', e, callback); } }, roomInvitationAccept: async (call, callback) => { log.verbose('PuppetServiceImpl', 'roomInvitationAccept()'); try { const id = call.request.getId(); await puppet.roomInvitationAccept(id); return callback(null, new grpcPuppet.RoomInvitationAcceptResponse()); } catch (e) { return grpcError('roomInvitationAccept', e, callback); } }, roomInvitationPayload: async (call, callback) => { log.verbose('PuppetServiceImpl', 'roomInvitationPayload()'); try { const roomInvitationId = call.request.getId(); /** * Set */ { const jsonText = call.request.getPayload(); if (jsonText) { const payload = JSON.parse(jsonText); await puppet.roomInvitationPayload(roomInvitationId, payload); return callback(null, new grpcPuppet.RoomInvitationPayloadResponse()); } { /** * Huan(202110): Deprecated: will be removed after Dec 31, 2022 */ const payloadWrapper = call.request.getPayloadStringValueDeprecated(); if (payloadWrapper) { const jsonText = payloadWrapper.getValue(); const payload = JSON.parse(jsonText); await puppet.roomInvitationPayload(roomInvitationId, payload); return callback(null, new grpcPuppet.RoomInvitationPayloadResponse()); } } } /** * Get */ const payload = await puppet.roomInvitationPayload(roomInvitationId); const response = new grpcPuppet.RoomInvitationPayloadResponse(); response.setAvatar(payload.avatar); response.setId(payload.id); response.setInvitation(payload.invitation); response.setInviterId(payload.inviterId); response.setReceiverId(payload.receiverId); response.setMemberCount(payload.memberCount); response.setMemberIdsList(payload.memberIdList); response.setReceiveTime(timestampFromMilliseconds(payload.timestamp)); { // Deprecated: will be removed after Dec 31, 2022 const deprecated = true; void deprecated; response.setTimestampUint64Deprecated(Math.floor(payload.timestamp)); } response.setTopic(payload.topic); return callback(null, response); } catch (e) { return grpcError('roomInvitationPayload', e, callback); } }, roomList: async (call, callback) => { log.verbose('PuppetServiceImpl', 'roomList()'); void call; try { const roomIdList = await puppet.roomList(); const response = new grpcPuppet.RoomListResponse(); response.setIdsList(roomIdList); return callback(null, response); } catch (e) { return grpcError('roomList', e, callback); } }, roomMemberList: async (call, callback) => { log.verbose('PuppetServiceImpl', 'roomMemberList()'); try { const roomId = call.request.getId(); const roomMemberIdList = await puppet.roomMemberList(roomId); const response = new grpcPuppet.RoomMemberListResponse(); response.setMemberIdsList(roomMemberIdList); return callback(null, response); } catch (e) { return grpcError('roomMemberList', e, callback); } }, roomMemberPayload: async (call, callback) => { log.verbose('PuppetServiceImpl', 'roomMemberPayload()'); try { const roomId = call.request.getId(); const memberId = call.request.getMemberId(); const payload = await puppet.roomMemberPayload(roomId, memberId); const response = new grpcPuppet.RoomMemberPayloadResponse(); response.setAvatar(payload.avatar); response.setId(payload.id); response.setInviterId(payload.inviterId || ''); response.setName(payload.name); response.setRoomAlias(payload.roomAlias || ''); return callback(null, response); } catch (e) { return grpcError('roomMemberPayload', e, callback); } }, roomPayload: async (call, callback) => { log.verbose('PuppetServiceImpl', 'roomPayload()'); try { const roomId = call.request.getId(); const payload = await puppet.roomPayload(roomId); const response = new grpcPuppet.RoomPayloadResponse(); response.setAdminIdsList(payload.adminIdList); response.setAvatar(payload.avatar || ''); response.setId(payload.id); response.setMemberIdsList(payload.memberIdList); response.setOwnerId(payload.ownerId || ''); response.setTopic(payload.topic); return callback(null, response); } catch (e) { return grpcError('roomPayload', e, callback); } }, roomQRCode: async (call, callback) => { log.verbose('PuppetServiceImpl', 'roomQRCode()'); try { const roomId = call.request.getId(); const qrcode = await puppet.roomQRCode(roomId); const response = new grpcPuppet.RoomQRCodeResponse(); response.setQrcode(qrcode); return callback(null, response); } catch (e) { return grpcError('roomQRCode', e, callback); } }, roomQuit: async (call, callback) => { log.verbose('PuppetServiceImpl', 'roomQuit()'); try { const roomId = call.request.getId(); await puppet.roomQuit(roomId); return callback(null, new grpcPuppet.RoomQuitResponse()); } catch (e) { return grpcError('roomQuit', e, callback); } }, roomTopic: async (call, callback) => { log.verbose('PuppetServiceImpl', 'roomTopic()'); try { const roomId = call.request.getId(); /** * Set */ if (call.request.hasTopic()) { await puppet.roomTopic(roomId, call.request.getTopic()); return callback(null, new grpcPuppet.RoomTopicResponse()); } /** * Get */ const topic = await puppet.roomTopic(roomId); const response = new grpcPuppet.RoomTopicResponse(); response.setTopic(topic); return callback(null, response); } catch (e) { return grpcError('roomTopic', e, callback); } }, start: async (call, callback) => { log.verbose('PuppetServiceImpl', 'start()'); void call; try { await timeoutPromise(puppet.start(), 15 * 1000); return callback(null, new grpcPuppet.StartResponse()); } catch (e) { return grpcError('start', e, callback); } }, stop: async (call, callback) => { log.verbose('PuppetServiceImpl', 'stop()'); void call; try { if (eventStreamManager.busy()) { eventStreamManager.stop(); } else { log.error('PuppetServiceImpl', 'stop() eventStreamManager is not busy?'); } readyPayload = undefined; await timeoutPromise(puppet.stop(), 15 * 1000); return callback(null, new grpcPuppet.StopResponse()); } catch (e) { return grpcError('stop', e, callback); } }, tagContactAdd: async (call, callback) => { log.verbose('PuppetServiceImpl', 'tagContactAdd()'); try { const tagId = call.request.getId(); const contactId = call.request.getContactId(); await puppet.tagContactAdd(tagId, contactId); return callback(null, new grpcPuppet.TagContactAddResponse()); } catch (e) { return grpcError('tagContactAdd', e, callback); } }, tagContactDelete: async (call, callback) => { log.verbose('PuppetServiceImpl', 'tagContactDelete()'); try { const tagId = call.request.getId(); await puppet.tagContactDelete(tagId); return callback(null, new grpcPuppet.TagContactDeleteResponse()); } catch (e) { return grpcError('tagContactDelete', e, callback); } }, tagContactList: async (call, callback) => { log.verbose('PuppetServiceImpl', 'tagContactList()'); try { const contactId = call.request.getContactId(); /** * for a specific contact */ if (contactId) { const tagIdList = await puppet.tagContactList(contactId); const response = new grpcPuppet.TagContactListResponse(); response.setIdsList(tagIdList); return callback(null, new grpcPuppet.TagContactListResponse()); } { /** * Huan(202110): Deprecated: will be removed after Dec 31, 2022 */ const contactIdWrapper = call.request.getContactIdStringValueDeprecated(); if (contactIdWrapper) { const contactId = contactIdWrapper.getValue(); const tagIdList = await puppet.tagContactList(contactId); const response = new grpcPuppet.TagContactListResponse(); response.setIdsList(tagIdList);