Skip to content

Commit

Permalink
feat(satori): support referrer
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Jan 3, 2025
1 parent ac0e32b commit 5a987b3
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 47 deletions.
15 changes: 4 additions & 11 deletions adapters/satori/src/bot.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
import { Bot, camelCase, Context, h, HTTP, JsonForm, snakeCase, Universal } from '@satorijs/core'

export function transformKey(source: any, callback: (key: string) => string) {
if (!source || typeof source !== 'object') return source
if (Array.isArray(source)) return source.map(value => transformKey(value, callback))
return Object.fromEntries(Object.entries(source).map(([key, value]) => {
if (key.startsWith('_')) return [key, value]
return [callback(key), transformKey(value, callback)]
}))
}

function createInternal(bot: SatoriBot, prefix = '') {
return new Proxy(() => {}, {
apply(target, thisArg, args) {
Expand Down Expand Up @@ -76,13 +67,15 @@ for (const [key, method] of Object.entries(Universal.Methods)) {
session.elements = await session.transform(h.normalize(args[index]))
if (await session.app.serial(session, 'before-send', session, args[3] ?? {})) return
payload[field.name] = session.elements.join('')
} else if (field.name === 'referrer') {
payload[field.name] = args[index]
} else {
payload[field.name] = transformKey(args[index], snakeCase)
payload[field.name] = Universal.transformKey(args[index], snakeCase)
}
}
}
this.logger.debug('[request]', key, payload)
const result = await this.http.post('/v1/' + key, payload)
return transformKey(result, camelCase)
return Universal.transformKey(result, camelCase)
}
}
4 changes: 2 additions & 2 deletions adapters/satori/src/ws.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Adapter, camelize, Context, HTTP, Logger, Schema, Time, Universal } from '@satorijs/core'
import { SatoriBot, transformKey } from './bot'
import { SatoriBot } from './bot'

export class SatoriAdapter<C extends Context = Context> extends Adapter.WsClientBase<C, SatoriBot<C>> {
static schema = true as any
Expand Down Expand Up @@ -91,7 +91,7 @@ export class SatoriAdapter<C extends Context = Context> extends Adapter.WsClient
let parsed: Universal.ServerPayload
data = data.toString()
try {
parsed = transformKey(JSON.parse(data), camelize)
parsed = Universal.transformKey(JSON.parse(data), camelize)
} catch (error) {
return this.logger.warn('cannot parse message', data)
}
Expand Down
10 changes: 5 additions & 5 deletions packages/core/src/bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface Bot extends Methods {

export abstract class Bot<C extends Context = Context, T = any> {
static reusable = true
static MessageEncoder?: new (bot: Bot, channelId: string, guildId?: string, options?: SendOptions) => MessageEncoder
static MessageEncoder?: new (bot: Bot, channelId: string, referrer?: any, options?: SendOptions) => MessageEncoder

public [Service.tracker] = {
associate: 'bot',
Expand Down Expand Up @@ -191,13 +191,13 @@ export abstract class Bot<C extends Context = Context, T = any> {
}
}

async createMessage(channelId: string, content: h.Fragment, guildId?: string, options?: SendOptions) {
async createMessage(channelId: string, content: h.Fragment, referrer?: any, options?: SendOptions) {
const { MessageEncoder } = this.constructor as typeof Bot
return new MessageEncoder(this, channelId, guildId, options).send(content)
return new MessageEncoder(this, channelId, referrer, options).send(content)
}

async sendMessage(channelId: string, content: h.Fragment, guildId?: string, options?: SendOptions) {
const messages = await this.createMessage(channelId, content, guildId, options)
async sendMessage(channelId: string, content: h.Fragment, referrer?: any, options?: SendOptions) {
const messages = await this.createMessage(channelId, content, referrer, options)
return messages.map(message => message.id)
}

Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Bot } from './bot'
import { ExtractParams, InternalRequest, InternalRouter, JsonForm } from './internal'
import { Session } from './session'
import { HTTP } from '@cordisjs/plugin-http'
import { Response, SendOptions } from '@satorijs/protocol'
import { Meta, Response, SendOptions } from '@satorijs/protocol'
import h from '@satorijs/element'

h.warn = new Logger('element').warn
Expand Down Expand Up @@ -277,7 +277,7 @@ export class Satori<C extends Context = Context> extends Service<unknown, C> {
return response
}

toJSON(meta = false) {
toJSON(meta = false): Meta {
return {
logins: meta ? undefined : this.bots.map(bot => bot.toJSON()),
proxyUrls: [...this.proxyUrls],
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export abstract class MessageEncoder<C extends Context = Context, B extends Bot<
public results: Message[] = []
public session: C[typeof Context.session]

constructor(public bot: B, public channelId: string, public guildId?: string, public options: SendOptions = {}) {}
constructor(public bot: B, public channelId: string, public referrer?: any, public options: SendOptions = {}) {}

async prepare() {}

Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface Session {
operatorId: string
roleId: string
quote: Message
referrer: any
}

export class Session<C extends Context = Context> {
Expand Down Expand Up @@ -187,3 +188,4 @@ defineAccessor(Session.prototype, 'messageId', ['event', 'message', 'id'])
defineAccessor(Session.prototype, 'operatorId', ['event', 'operator', 'id'])
defineAccessor(Session.prototype, 'roleId', ['event', 'role', 'id'])
defineAccessor(Session.prototype, 'quote', ['event', 'message', 'quote'])
defineAccessor(Session.prototype, 'referrer', ['event', 'referrer'])
30 changes: 21 additions & 9 deletions packages/protocol/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export const Methods: Dict<Method> = {
'channel.delete': Method('deleteChannel', ['channel_id']),
'channel.mute': Method('muteChannel', ['channel_id', 'guild_id', 'enable']),

'message.create': Method('createMessage', ['channel_id', 'content']),
'message.create': Method('createMessage', ['channel_id', 'content', 'referrer']),
'message.update': Method('editMessage', ['channel_id', 'message_id', 'content']),
'message.delete': Method('deleteMessage', ['channel_id', 'message_id']),
'message.get': Method('getMessage', ['channel_id', 'message_id']),
Expand Down Expand Up @@ -100,8 +100,8 @@ export type Order = 'asc' | 'desc'

export interface Methods {
// message
createMessage(channelId: string, content: Element.Fragment, guildId?: string, options?: SendOptions): Promise<Message[]>
sendMessage(channelId: string, content: Element.Fragment, guildId?: string, options?: SendOptions): Promise<string[]>
createMessage(channelId: string, content: Element.Fragment, referrer?: any, options?: SendOptions): Promise<Message[]>
sendMessage(channelId: string, content: Element.Fragment, referrer?: any, options?: SendOptions): Promise<string[]>
sendPrivateMessage(userId: string, content: Element.Fragment, guildId?: string, options?: SendOptions): Promise<string[]>
getMessage(channelId: string, messageId: string): Promise<Message>
getMessageList(channelId: string, next?: string, direction?: Direction, limit?: number, order?: Order): Promise<TwoWayList<Message>>
Expand Down Expand Up @@ -214,13 +214,13 @@ export interface User {
isBot?: boolean
}

export interface Resource<K> {
export interface Resource<K = any> {
attrs: (keyof K)[]
children: (keyof K)[]
content?: keyof K
}

export function Resource<K>(attrs: (keyof K)[], children: (keyof K)[] = [], content?: keyof K): Resource<K> {
export function Resource<K>(attrs: (keyof K)[] = [], children: (keyof K)[] = [], content?: keyof K): Resource<K> {
return { attrs, children, content }
}

Expand Down Expand Up @@ -270,6 +270,15 @@ export namespace Resource {
}
}

export function transformKey(source: any, callback: (key: string) => string) {
if (!source || typeof source !== 'object') return source
if (Array.isArray(source)) return source.map(value => transformKey(value, callback))
return Object.fromEntries(Object.entries(source).map(([key, value]) => {
if (key.startsWith('_') || key === 'referrer') return [key, value]
return [callback(key), transformKey(value, callback)]
}))
}

export interface GuildMember {
user?: User
name?: string
Expand Down Expand Up @@ -380,6 +389,7 @@ export interface Event {
role?: GuildRole
user?: User
button?: Button
referrer: any
_type?: string
_data?: any
/** @deprecated */
Expand All @@ -388,6 +398,11 @@ export interface Event {
subsubtype?: string
}

export interface Meta {
logins: Login[]
proxyUrls: string[]
}

export type MessageLike = Message | Event

export const enum Opcode {
Expand Down Expand Up @@ -420,10 +435,7 @@ export interface GatewayBody {
token?: string
sn?: number
}
[Opcode.READY]: {
logins: Login[]
proxyUrls: string[]
}
[Opcode.READY]: Meta
[Opcode.META]: {
proxyUrls: string[]
}
Expand Down
26 changes: 9 additions & 17 deletions packages/server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,6 @@ class Client {
authorized = false
}

function transformKey(source: any, callback: (key: string) => string) {
if (!source || typeof source !== 'object') return source
if (Array.isArray(source)) return source.map(value => transformKey(value, callback))
return Object.fromEntries(Object.entries(source).map(([key, value]) => {
if (key.startsWith('_')) return [key, value]
return [callback(key), transformKey(value, callback)]
}))
}

const FILTER_HEADERS = [
'host',
'authorization',
Expand Down Expand Up @@ -99,10 +90,11 @@ class SatoriServer extends Service<SatoriServer.Config> {

const json = koa.request.body
const args = method.fields.map(({ name }) => {
return transformKey(json[name], camelCase)
if (name === 'referrer') return json[name]
return Universal.transformKey(json[name], camelCase)
})
const result = await bot[method.name](...args)
koa.body = transformKey(result, snakeCase)
koa.body = Universal.transformKey(result, snakeCase)
koa.status = 200
})

Expand Down Expand Up @@ -171,13 +163,13 @@ class SatoriServer extends Service<SatoriServer.Config> {

ctx.server.post(path + '/v1/meta', async (koa) => {
if (checkAuth(koa)) return
koa.body = transformKey(ctx.satori.toJSON(), snakeCase)
koa.body = Universal.transformKey(ctx.satori.toJSON(), snakeCase)
koa.status = 200
})

ctx.server.post(path + '/v1/meta/webhook.create', async (koa) => {
if (checkAuth(koa)) return
const webhook: SatoriServer.Webhook = transformKey(koa.request.body, camelCase)
const webhook: SatoriServer.Webhook = Universal.transformKey(koa.request.body, camelCase)
const index = config.webhooks.findIndex(({ url }) => url === webhook.url)
if (index === -1) {
config.webhooks.push(webhook)
Expand Down Expand Up @@ -230,12 +222,12 @@ class SatoriServer extends Service<SatoriServer.Config> {
client.authorized = true
socket.send(JSON.stringify({
op: Universal.Opcode.READY,
body: transformKey(ctx.satori.toJSON(), snakeCase),
body: Universal.transformKey(ctx.satori.toJSON(), snakeCase),
}))
if (!payload.body?.sn) return
for (const session of buffer) {
if (session.id <= payload.body.sn) continue
dispatch(socket, transformKey(session.toJSON(), snakeCase))
dispatch(socket, Universal.transformKey(session.toJSON(), snakeCase))
}
} else if (payload.op === Universal.Opcode.PING) {
socket.send(JSON.stringify({
Expand Down Expand Up @@ -272,12 +264,12 @@ class SatoriServer extends Service<SatoriServer.Config> {
}

ctx.on('internal/session', (session) => {
const body = transformKey(session.toJSON(), snakeCase)
const body = Universal.transformKey(session.toJSON(), snakeCase)
sendEvent(Universal.Opcode.EVENT, body)
})

ctx.on('satori/meta', () => {
const body = transformKey(ctx.satori.toJSON(true), snakeCase)
const body = Universal.transformKey(ctx.satori.toJSON(true), snakeCase)
sendEvent(Universal.Opcode.META, body)
})
}
Expand Down

0 comments on commit 5a987b3

Please sign in to comment.