Skip to content

Commit

Permalink
feat(satori): support blobs in internal apis
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Nov 25, 2024
1 parent ea5156f commit c9fa47c
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 6 deletions.
2 changes: 1 addition & 1 deletion adapters/satori/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@satorijs/adapter-satori",
"description": "Satori Adapter for Satorijs",
"version": "1.3.1",
"version": "1.4.0",
"type": "module",
"exports": {
".": {
Expand Down
32 changes: 30 additions & 2 deletions adapters/satori/src/bot.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Bot, camelCase, Context, h, HTTP, snakeCase, Universal } from '@satorijs/core'
import { Bot, camelCase, Context, Dict, h, HTTP, snakeCase, Universal, valueMap } from '@satorijs/core'

export function transformKey(source: any, callback: (key: string) => string) {
if (!source || typeof source !== 'object') return source
Expand All @@ -9,12 +9,40 @@ export function transformKey(source: any, callback: (key: string) => string) {
}))
}

function serialize(data: any, path: string, blobs: Dict<Blob>) {
if (!data || typeof data !== 'object') return data
if (data instanceof Blob) {
blobs[path] = data
return null
}
if (Array.isArray(data)) {
return data.map((value, index) => serialize(value, `${path}.${index}`, blobs))
}
return valueMap(data, (value, key) => {
return serialize(value, `${path}.${key}`, blobs)
})
}

function createInternal(bot: SatoriBot, prefix = '') {
return new Proxy(() => {}, {
apply(target, thisArg, args) {
const key = snakeCase(prefix.slice(1))
bot.logger.debug('[request.internal]', key, args)
return bot.http.post('/v1/internal/' + key, args)
const blobs: Dict<Blob> = Object.create(null)
const data = serialize(args, '$', blobs)
if (!Object.keys(blobs).length) {
return bot.http.post('/v1/internal/' + key, args)
}
const form = new FormData()
form.append('$', new Blob([JSON.stringify(data)], { type: 'application/json' }))
for (const [key, value] of Object.entries(blobs)) {
if (value instanceof File) {
form.append(key, value, value.name)
} else {
form.append(key, value)
}
}
return bot.http.post('/v1/internal/' + key, form)
},
get(target, key, receiver) {
if (typeof key === 'symbol' || key in target) {
Expand Down
2 changes: 1 addition & 1 deletion packages/server/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@satorijs/plugin-server",
"description": "Basic API server for Satori protocol",
"version": "2.7.3",
"version": "2.8.0",
"type": "module",
"exports": {
".": {
Expand Down
32 changes: 30 additions & 2 deletions packages/server/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Binary, camelCase, Context, makeArray, sanitize, Schema, Service, Session, snakeCase, Time, Universal } from '@satorijs/core'
import { Binary, camelCase, Context, Dict, makeArray, sanitize, Schema, Service, Session, snakeCase, Time, Universal, valueMap } from '@satorijs/core'
import {} from '@cordisjs/plugin-server'
import WebSocket from 'ws'
import { Readable } from 'node:stream'
Expand Down Expand Up @@ -33,6 +33,17 @@ function transformKey(source: any, callback: (key: string) => string) {
}))
}

function deserialize(data: any, path: string, blobs: Dict<Blob>) {
if (path in blobs) return blobs[path]
if (!data || typeof data !== 'object') return data
if (Array.isArray(data)) {
return data.map((value, index) => deserialize(value, `${path}.${index}`, blobs))
}
return valueMap(data, (value, key) => {
return deserialize(value, `${path}.${key}`, blobs)
})
}

class SatoriServer extends Service<SatoriServer.Config> {
static inject = ['server', 'http']

Expand Down Expand Up @@ -122,7 +133,21 @@ class SatoriServer extends Service<SatoriServer.Config> {
return
}
try {
const result = await bot.internal[name](...koa.request.body)
let args = koa.request.body
if (koa.request.files) {
const blobs: Dict<Blob> = Object.create(null)
const { $, ...files } = koa.request.files
const [json] = await Promise.all([
readFile(makeArray($)[0].filepath, 'utf8'),
Promise.all(Object.entries(files).map(async ([key, value]) => {
value = makeArray(value)[0]
const buffer = await readFile(value.filepath)
return [key, new File([buffer], value.originalFilename!, { type: value.mimetype! })]
})),
])
args = deserialize(JSON.parse(json), '$', blobs)
}
const result = await bot.internal[name](...args)
koa.body = result
koa.status = 200
} catch (error) {
Expand Down Expand Up @@ -171,6 +196,9 @@ class SatoriServer extends Service<SatoriServer.Config> {
if (!ctx.http.isError(error) || !error.response) throw error
koa.status = error.response.status
koa.body = error.response.data
for (const [key, value] of error.response.headers) {
koa.set(key, value)
}
}
}
})
Expand Down

0 comments on commit c9fa47c

Please sign in to comment.