Skip to content

Commit

Permalink
feat(satori): matrix and onebot support v3
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Sep 28, 2023
1 parent 7d525aa commit 764c0d7
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 117 deletions.
2 changes: 1 addition & 1 deletion adapters/discord/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const decodeUser = (user: Discord.User): Universal.User => ({
id: user.id,
name: user.username,
userId: user.id,
avatar: `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.png`,
avatar: user.avatar && `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.png`,
username: user.username,
discriminator: user.discriminator,
isBot: user.bot || false,
Expand Down
32 changes: 10 additions & 22 deletions adapters/matrix/src/bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Bot, Context, omit, Quester, Schema, Universal } from '@satorijs/satori
import { HttpAdapter } from './http'
import { MatrixMessageEncoder } from './message'
import * as Matrix from './types'
import { adaptMessage, dispatchSession } from './utils'
import { adaptMessage, decodeUser, dispatchSession } from './utils'

export class MatrixBot extends Bot<MatrixBot.Config> {
static MessageEncoder = MatrixMessageEncoder
Expand All @@ -17,7 +17,8 @@ export class MatrixBot extends Bot<MatrixBot.Config> {
super(ctx, config)
this.id = config.id
this.platform = 'matrix'
this.userId = `@${this.id}:${this.config.host}`
this.user.id = `@${this.id}:${this.config.host}`
this.user.name = config.name || this.id
this.endpoint = (config.endpoint || `https://${config.host}`) + '/_matrix'
this.internal = new Matrix.Internal(this)
ctx.plugin(HttpAdapter, this)
Expand Down Expand Up @@ -73,21 +74,14 @@ export class MatrixBot extends Bot<MatrixBot.Config> {

async getUser(userId: string) {
const profile = await this.internal.getProfile(userId)
let avatar: string
if (profile.avatar_url) avatar = this.internal.getAssetUrl(profile.avatar_url)
return {
id: userId,
name: profile.displayname,
userId,
avatar,
username: userId,
nickname: profile.displayname,
}
const user = decodeUser(profile, userId)
user.avatar = user.avatar && this.internal.getAssetUrl(user.avatar)
return user
}

async getGuild(guildId: string) {
const { id, name } = await this.getChannel(guildId)
return { id, name, guildId, guildName: name }
return { id, name }
}

async getChannel(id: string) {
Expand All @@ -114,14 +108,7 @@ export class MatrixBot extends Bot<MatrixBot.Config> {
.map(event => {
const content = event.content as Matrix.M_ROOM_MEMBER
return {
user: {
id: event.state_key,
name: event.state_key,
},
userId: event.state_key,
username: event.state_key,
nickname: content.displayname,
avatar: this.internal.getAssetUrl(content.avatar_url),
user: decodeUser(content, event.state_key),
isBot: !!this.ctx.bots.find(bot => bot.userId === event.state_key),
roles: [levels.users[event.state_key].toString()],
}
Expand All @@ -130,7 +117,8 @@ export class MatrixBot extends Bot<MatrixBot.Config> {
}

async getGuildMember(guildId: string, userId: string) {
return (await this.getGuildMemberList(guildId)).data.find(user => user.userId === userId)
const { data } = await this.getGuildMemberList(guildId)
return data.find(member => member.user.id === userId)
}

async createReaction(channelId: string, messageId: string, emoji: string) {
Expand Down
6 changes: 3 additions & 3 deletions adapters/matrix/src/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export class MatrixMessageEncoder extends MessageEncoder<MatrixBot> {
const session = this.bot.session(this.session)
const { data, filename, mime } = await this.bot.ctx.http.file(url)
const id = await this.bot.internal.sendMediaMessage(
this.channelId, type, Buffer.from(data), this.reply?.messageId, mime, filename,
this.channelId, type, Buffer.from(data), this.reply?.id, mime, filename,
)
session.messageId = id
this.results.push(session)
Expand All @@ -25,10 +25,10 @@ export class MatrixMessageEncoder extends MessageEncoder<MatrixBot> {
try {
const session = this.bot.session(this.session)
if (this.reply) {
this.buffer = `> <${this.reply.userId}> ${this.reply.content}\n\n` + this.buffer
this.buffer = `> <${this.reply.user.id}> ${this.reply.content}\n\n` + this.buffer
}
const id = await this.bot.internal.sendTextMessage(
this.channelId, this.buffer, this.reply?.messageId,
this.channelId, this.buffer, this.reply?.id,
)
session.messageId = id
this.results.push(session)
Expand Down
58 changes: 34 additions & 24 deletions adapters/matrix/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,29 @@ import { MatrixBot } from './bot'
import * as Matrix from './types'
import { INode, ITag, parse, SyntaxKind } from 'html5parser'

export function adaptAuthor(bot: MatrixBot, event: Matrix.ClientEvent): Universal.Author {
return {
userId: event.sender,
username: event.sender,
isBot: !!bot.ctx.bots.find(bot => bot.userId === event.sender),
}
}
export const decodeUser = (data: Matrix.Profile, id: string): Universal.User => ({
id,
name: data.displayname,
avatar: data.avatar_url,
})

export async function adaptMessage(bot: MatrixBot, event: Matrix.ClientEvent, result: Universal.Message = {}): Promise<Universal.Message> {
result.messageId = event.event_id
result.channelId = event.room_id
result.guildId = event.room_id
result.userId = event.sender
result.timestamp = event.origin_server_ts
result.author = adaptAuthor(bot, event)
result.isDirect = false
const content = event.content as Matrix.M_ROOM_MESSAGE
export async function adaptMessage(
bot: MatrixBot,
data: Matrix.ClientEvent,
message: Universal.Message = {},
payload: Universal.Message | Universal.EventData = message,
): Promise<Universal.Message> {
message.id = message.messageId = data.event_id
const content = data.content as Matrix.M_ROOM_MESSAGE
const reply = content['m.relates_to']?.['m.in_reply_to']
if (reply) {
result.quote = await bot.getMessage(event.room_id, reply.event_id)
message.quote = await bot.getMessage(data.room_id, reply.event_id)
}
switch (content.msgtype) {
case 'm.text':
case 'm.emote':
case 'm.notice': {
result.content = parsseContent(bot, content)
message.content = parsseContent(bot, content)
break
}
case 'm.image':
Expand All @@ -37,15 +34,29 @@ export async function adaptMessage(bot: MatrixBot, event: Matrix.ClientEvent, re
case 'm.video': {
const url = bot.internal.getAssetUrl((content as any).url)
const type = content.msgtype.substring(2)
result.content = segment(type === 'audio' ? 'record' : type, { url }).toString()
message.content = segment(type === 'audio' ? 'record' : type, { url }).toString()
break
}
default:
return null
}
// result.content is not a setter if result is a Universal.Message
result.elements ??= segment.parse(result.content)
return result
message.elements ??= segment.parse(message.content)

if (!payload) return message
payload.timestamp = data.origin_server_ts
payload.channel = {
id: data.room_id,
type: Universal.Channel.Type.TEXT,
}
payload.guild = {
id: data.room_id,
}
payload.user = {
id: data.sender,
}
payload.member = {}
return message
}

export async function adaptSession(bot: MatrixBot, event: Matrix.ClientEvent): Promise<Session> {
Expand All @@ -60,15 +71,14 @@ export async function adaptSession(bot: MatrixBot, event: Matrix.ClientEvent): P
} else {
session.type = 'message'
}
if (!await adaptMessage(bot, event, session)) return null
if (!await adaptMessage(bot, event, session.data.message = {}, session.data)) return null
return session
}
session.userId = event.sender
session.guildId = event.room_id
session.channelId = event.room_id
session.messageId = event.event_id
session.timestamp = event.origin_server_ts
session.author = adaptAuthor(bot, event)
session.isDirect = false
switch (event.type) {
case 'm.room.redaction': {
Expand All @@ -88,7 +98,7 @@ export async function adaptSession(bot: MatrixBot, event: Matrix.ClientEvent): P
case 'm.room.member': {
bot.syncRooms()
const memberEvent = event.content as Matrix.M_ROOM_MEMBER
session.targetId = (memberEvent as any).state_key
session['targetId'] = (memberEvent as any).state_key
session.operatorId = event.sender
session.messageId = event.event_id
if (memberEvent.reason) {
Expand Down
6 changes: 3 additions & 3 deletions adapters/onebot/src/bot/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,18 @@ export class BaseBot<T extends BaseBot.Config = BaseBot.Config> extends Bot<T> {

async getLogin() {
const data = await this.internal.getLoginInfo()
this.user = OneBot.adaptUser(data)
this.user = OneBot.decodeUser(data)
return this.toJSON()
}

async getUser(userId: string) {
const data = await this.internal.getStrangerInfo(userId)
return OneBot.adaptUser(data)
return OneBot.decodeUser(data)
}

async getFriendList() {
const data = await this.internal.getFriendList()
return { data: data.map(OneBot.adaptUser) }
return { data: data.map(OneBot.decodeUser) }
}

async handleFriendRequest(messageId: string, approve: boolean, comment?: string) {
Expand Down
4 changes: 2 additions & 2 deletions adapters/onebot/src/bot/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,12 @@ export class OneBotBot<T extends OneBotBot.Config = OneBotBot.Config> extends Ba

async getGuildMember(guildId: string, userId: string) {
const data = await this.internal.getGroupMemberInfo(guildId, userId)
return OneBot.adaptGuildMember(data)
return OneBot.decodeGuildMember(data)
}

async getGuildMemberList(guildId: string) {
const data = await this.internal.getGroupMemberList(guildId)
return { data: data.map(OneBot.adaptGuildMember) }
return { data: data.map(OneBot.decodeGuildMember) }
}

async kickGuildMember(guildId: string, userId: string, permanent?: boolean) {
Expand Down
12 changes: 8 additions & 4 deletions adapters/onebot/src/bot/message.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { h, MessageEncoder, pick } from '@satorijs/satori'
import { h, MessageEncoder, pick, Universal } from '@satorijs/satori'
import { BaseBot } from './base'
import { CQCode } from './cqcode'
import { Author } from '../types'

export interface Author extends Universal.User {
time?: string | number
messageId?: string
}

class State {
author: Partial<Author> = {}
Expand Down Expand Up @@ -58,8 +62,8 @@ export class OneBotMessageEncoder extends MessageEncoder<BaseBot> {
this.stack[1].children.push({
type: 'node',
data: {
name: author.nickname || author.username || this.bot.username,
uin: author.userId || this.bot.userId,
name: author.nick || author.name || this.bot.user.name,
uin: author.id || this.bot.userId,
content: this.children as any,
time: `${Math.floor((+author.time || Date.now()) / 1000)}`,
},
Expand Down
20 changes: 9 additions & 11 deletions adapters/onebot/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,15 @@ export * from './ws'

export default OneBotBot

declare global {
namespace Satori {
interface Session {
onebot?: OneBot.Payload & OneBot.Internal
}
declare module '@satorijs/core' {
interface Session {
onebot?: OneBot.Payload & OneBot.Internal
}

interface Events {
'onebot/message-reactions-updated': {}
'onebot/channel-updated': {}
'onebot/channel-created': {}
'onebot/channel-destroyed': {}
}
interface Events {
'onebot/message-reactions-updated'(session: Session): void
'onebot/channel-updated'(session: Session): void
'onebot/channel-created'(session: Session): void
'onebot/channel-destroyed'(session: Session): void
}
}
7 changes: 1 addition & 6 deletions adapters/onebot/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { camelize, Dict, Logger, Universal } from '@satorijs/satori'
import { camelize, Dict, Logger } from '@satorijs/satori'
import { CQCode } from './bot'

export interface Response {
Expand Down Expand Up @@ -89,11 +89,6 @@ export interface UnidirectionalFriendInfo extends AccountInfo {
source: string
}

export interface Author extends Universal.Author {
time?: string | number
messageId?: string
}

export interface GroupBase {
group_id: number
group_name: string
Expand Down
Loading

0 comments on commit 764c0d7

Please sign in to comment.