Skip to content

Commit

Permalink
feat(lark): receive message quote
Browse files Browse the repository at this point in the history
  • Loading branch information
XxLittleCxX committed Apr 7, 2024
1 parent 89030ee commit c26f7e8
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 13 deletions.
23 changes: 20 additions & 3 deletions adapters/lark/src/bot.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Bot, Context, h, Quester, Schema } from '@satorijs/satori'
import { Bot, Context, h, Quester, Schema, Universal } from '@satorijs/satori'

import { HttpServer } from './http'
import { LarkMessageEncoder } from './message'
Expand All @@ -15,6 +15,8 @@ export class LarkBot<C extends Context = Context> extends Bot<C, LarkBot.Config>
assetsQuester: Quester
internal: Internal

public openId: string

constructor(ctx: C, config: LarkBot.Config) {
super(ctx, config, 'lark')

Expand All @@ -35,6 +37,18 @@ export class LarkBot<C extends Context = Context> extends Bot<C, LarkBot.Config>

async initialize() {
await this.refreshToken()
const { bot } = await this.http.get<{
bot: {
activate_status: number
app_name: string
avatar_url: string
ip_white_list: any[]
open_id: string
}
}>('/bot/v3/info')
this.openId = bot.open_id
this.user.avatar = bot.avatar_url
this.user.name = bot.app_name
this.online()
}

Expand Down Expand Up @@ -72,9 +86,12 @@ export class LarkBot<C extends Context = Context> extends Bot<C, LarkBot.Config>
await this.internal.deleteImMessage(messageId)
}

async getMessage(channelId: string, messageId: string) {
async getMessage(channelId: string, messageId: string, recursive = true) {
const data = await this.internal.getImMessage(messageId)
return await Utils.decodeMessage(this, data.data.items[0])
const message = await Utils.decodeMessage(this, data.data.items[0], recursive)
const im = await this.internal.getImChat(channelId)
message.channel.type = im.data.chat_mode === 'p2p' ? Universal.Channel.Type.DIRECT : Universal.Channel.Type.TEXT
return message
}

async getMessageList(channelId: string, before?: string) {
Expand Down
5 changes: 3 additions & 2 deletions adapters/lark/src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export class HttpServer<C extends Context = Context> extends Adapter<C, FeishuBo

// dispatch message
bot.logger.debug('received decryped event: %o', body)
// @TODO: need await?
this.dispatchSession(body)

// Lark requires 200 OK response to make sure event is received
Expand All @@ -97,13 +98,13 @@ export class HttpServer<C extends Context = Context> extends Adapter<C, FeishuBo
})
}

dispatchSession(body: AllEvents): void {
async dispatchSession(body: AllEvents) {
const { header } = body
if (!header) return
const { app_id, event_type } = header
body.type = event_type // add type to body to ease typescript type narrowing
const bot = this.bots.find((bot) => bot.selfId === app_id)
const session = adaptSession(bot, body)
const session = await adaptSession(bot, body)
bot.dispatch(session)
}

Expand Down
3 changes: 2 additions & 1 deletion adapters/lark/src/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ export class LarkMessageEncoder<C extends Context = Context> extends MessageEnco
session.messageId = resp.data.message_id
session.timestamp = Number(resp.data.create_time) * 1000
session.userId = resp.data.sender.id
session.channelId = this.channelId
session.guildId = this.guildId
session.app.emit(session, 'send', session)
console.log(session)
this.results.push(session.event.message)
} catch (e) {
// try to extract error message from Lark API
Expand Down
15 changes: 14 additions & 1 deletion adapters/lark/src/types/message/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,21 @@ declare module '../event' {
sender_type?: string
tenant_key: string
}
message: Lark.Message & {
message: {
message_id: string
root_id: string
parent_id: string
create_time: string
chat_id: string
chat_type: string
message_type: MessageType
content: string
mentions: {
key: string
id: Lark.UserIds
name: string
tenant_key: string
}[]
}
}>
/**
Expand Down
25 changes: 19 additions & 6 deletions adapters/lark/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function adaptSender(sender: Sender, session: Session): Session {
return session
}

export function adaptMessage(bot: FeishuBot, data: Events['im.message.receive_v1']['event'], session: Session): Session {
export async function adaptMessage(bot: FeishuBot, data: Events['im.message.receive_v1']['event'], session: Session, details = true): Promise<Session> {
const json = JSON.parse(data.message.content) as MessageContentType<MessageType>
const assetEndpoint = trimSlash(bot.config.selfUrl ?? bot.ctx.server.config.selfUrl) + bot.config.path + '/assets'
const content: (string | h)[] = []
Expand All @@ -38,7 +38,9 @@ export function adaptMessage(bot: FeishuBot, data: Events['im.message.receive_v1
text.split(' ').forEach((word) => {
if (word.startsWith('@')) {
const mention = data.message.mentions.find((mention) => mention.key === word)
content.push(h.at(mention.id.open_id, { name: mention.name }))
let id = mention.id.open_id
if (id === bot.openId) id = bot.selfId
content.push(h.at(id, { name: mention.name }))
} else {
content.push(word)
}
Expand All @@ -65,10 +67,13 @@ export function adaptMessage(bot: FeishuBot, data: Events['im.message.receive_v1
session.guildId = data.message.chat_id
session.content = content.map((c) => c.toString()).join(' ')

if (data.message.parent_id && details) {
session.quote = await bot.getMessage(session.channelId, data.message.parent_id, false)
}
return session
}

export function adaptSession<C extends Context>(bot: FeishuBot<C>, body: AllEvents) {
export async function adaptSession<C extends Context>(bot: FeishuBot<C>, body: AllEvents) {
const session = bot.session()
session.setInternal('lark', body)

Expand All @@ -79,14 +84,14 @@ export function adaptSession<C extends Context>(bot: FeishuBot<C>, body: AllEven
if (session.subtype === 'p2p') session.subtype = 'private'
session.isDirect = session.subtype === 'private'
adaptSender(body.event.sender, session)
adaptMessage(bot, body.event, session)
await adaptMessage(bot, body.event, session)
break
}
return session
}

// TODO: This function has many duplicated code with `adaptMessage`, should refactor them
export async function decodeMessage(bot: LarkBot, body: Lark.Message): Promise<Universal.Message> {
export async function decodeMessage(bot: LarkBot, body: Lark.Message, details = true): Promise<Universal.Message> {
const json = JSON.parse(body.body.content) as MessageContentType<MessageType>
const assetEndpoint = trimSlash(bot.config.selfUrl ?? bot.ctx.server.config.selfUrl) + bot.config.path + '/assets'
const content: h[] = []
Expand Down Expand Up @@ -128,9 +133,17 @@ export async function decodeMessage(bot: LarkBot, body: Lark.Message): Promise<U
createdAt: +body.create_time,
updatedAt: +body.update_time,
id: body.message_id,
messageId: body.message_id,
user: {
id: body.sender.id,
},
channel: {
id: body.chat_id,
type: Universal.Channel.Type.TEXT,
},
content: content.map((c) => c.toString()).join(' '),
elements: content,
quote: body.upper_message_id ? await bot.getMessage(body.chat_id, body.upper_message_id) : undefined,
quote: (body.upper_message_id && details) ? await bot.getMessage(body.chat_id, body.upper_message_id, false) : undefined,
}
}

Expand Down

0 comments on commit c26f7e8

Please sign in to comment.