mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-27 07:16:19 +09:00
refactor: platform
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
DeletePlatformModel,
|
||||
UpdatePlatformConfigModel,
|
||||
SetPlatformActiveModel,
|
||||
getPlatformConfigSchema,
|
||||
} from './model'
|
||||
import {
|
||||
getPlatforms,
|
||||
@@ -34,7 +35,6 @@ export const platformModule = new Elysia({
|
||||
await activePlatform({
|
||||
id: platform.id,
|
||||
name: platform.name,
|
||||
endpoint: platform.endpoint,
|
||||
config: platform.config as Record<string, unknown>,
|
||||
active: platform.active,
|
||||
})
|
||||
@@ -140,13 +140,21 @@ export const platformModule = new Elysia({
|
||||
try {
|
||||
const { id } = params
|
||||
const { config } = body as { config: Record<string, unknown> }
|
||||
const updatedPlatform = await updatePlatformConfig(id, config)
|
||||
if (!updatedPlatform) {
|
||||
|
||||
// Get the platform to validate config against its schema
|
||||
const platform = await getPlatformById(id)
|
||||
if (!platform) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Platform not found',
|
||||
}
|
||||
}
|
||||
|
||||
// Validate config against platform-specific schema
|
||||
const configSchema = getPlatformConfigSchema(platform.name)
|
||||
const validatedConfig = configSchema.parse(config) as Record<string, unknown>
|
||||
|
||||
const updatedPlatform = await updatePlatformConfig(id, validatedConfig)
|
||||
return {
|
||||
success: true,
|
||||
data: updatedPlatform,
|
||||
|
||||
@@ -1,10 +1,59 @@
|
||||
import { z } from 'zod'
|
||||
|
||||
// Platform-specific config schemas
|
||||
export const TelegramConfigSchema = z.object({
|
||||
botToken: z.string().min(1, 'Bot token is required'),
|
||||
})
|
||||
|
||||
// Registry of platform config schemas
|
||||
// When adding a new platform, add its config schema here
|
||||
export const platformConfigSchemas: Record<string, z.ZodSchema> = {
|
||||
telegram: TelegramConfigSchema,
|
||||
// Add more platforms here as they are implemented
|
||||
// discord: DiscordConfigSchema,
|
||||
// slack: SlackConfigSchema,
|
||||
}
|
||||
|
||||
// Helper function to get config schema for a platform
|
||||
export const getPlatformConfigSchema = (platformName: string): z.ZodSchema => {
|
||||
const schema = platformConfigSchemas[platformName]
|
||||
if (!schema) {
|
||||
throw new Error(`Unknown platform: ${platformName}. Supported platforms: ${Object.keys(platformConfigSchemas).join(', ')}`)
|
||||
}
|
||||
return schema
|
||||
}
|
||||
|
||||
// Base platform schema with dynamic config validation
|
||||
const PlatformSchema = z.object({
|
||||
name: z.string().min(1, 'Platform name is required'),
|
||||
endpoint: z.string().min(1, 'Endpoint is required'),
|
||||
config: z.record(z.string(), z.unknown()),
|
||||
active: z.boolean().optional().default(true),
|
||||
}).superRefine((data, ctx) => {
|
||||
// Validate that the platform name is supported
|
||||
if (!platformConfigSchemas[data.name]) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: `Unknown platform: ${data.name}. Supported platforms: ${Object.keys(platformConfigSchemas).join(', ')}`,
|
||||
path: ['name'],
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Validate the config against the platform-specific schema
|
||||
try {
|
||||
const configSchema = getPlatformConfigSchema(data.name)
|
||||
configSchema.parse(data.config)
|
||||
} catch (error) {
|
||||
if (error instanceof z.ZodError) {
|
||||
error.issues.forEach((issue: z.ZodIssue) => {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: issue.message,
|
||||
path: ['config', ...issue.path],
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export type PlatformInput = z.infer<typeof PlatformSchema>
|
||||
@@ -32,6 +81,8 @@ export const DeletePlatformModel = {
|
||||
}),
|
||||
}
|
||||
|
||||
// For updating config, we need to know the platform name to validate
|
||||
// This will be used with additional validation in the route handler
|
||||
export const UpdatePlatformConfigModel = {
|
||||
params: z.object({
|
||||
id: z.string(),
|
||||
|
||||
@@ -3,15 +3,12 @@ import { platform } from '@memoh/db/schema'
|
||||
import { Platform } from '@memoh/shared'
|
||||
import { eq, sql, desc, asc } from 'drizzle-orm'
|
||||
import { calculateOffset, createPaginatedResult, type PaginatedResult } from '../../utils/pagination'
|
||||
import path from 'node:path'
|
||||
import { BasePlatform } from '@memoh/platform'
|
||||
import { TelegramPlatform } from '@memoh/platform-telegram'
|
||||
|
||||
/**
|
||||
* 平台列表返回类型
|
||||
*/
|
||||
type PlatformListItem = {
|
||||
id: string
|
||||
name: string
|
||||
endpoint: string
|
||||
config: Record<string, unknown>
|
||||
active: boolean
|
||||
createdAt: Date
|
||||
@@ -72,7 +69,6 @@ export const createPlatform = async (data: Omit<Platform, 'id'>) => {
|
||||
.insert(platform)
|
||||
.values({
|
||||
name: data.name,
|
||||
endpoint: data.endpoint,
|
||||
config: data.config,
|
||||
active: data.active ?? true,
|
||||
})
|
||||
@@ -81,7 +77,6 @@ export const createPlatform = async (data: Omit<Platform, 'id'>) => {
|
||||
await activePlatform({
|
||||
id: newPlatform.id,
|
||||
name: newPlatform.name,
|
||||
endpoint: newPlatform.endpoint,
|
||||
config: newPlatform.config as Record<string, unknown>,
|
||||
active: newPlatform.active,
|
||||
})
|
||||
@@ -92,7 +87,6 @@ export const createPlatform = async (data: Omit<Platform, 'id'>) => {
|
||||
export const updatePlatform = async (id: string, data: Partial<Omit<Platform, 'id'>>) => {
|
||||
const updateData: {
|
||||
name?: string
|
||||
endpoint?: string
|
||||
config?: Record<string, unknown>
|
||||
active?: boolean
|
||||
updatedAt: Date
|
||||
@@ -101,7 +95,6 @@ export const updatePlatform = async (id: string, data: Partial<Omit<Platform, 'i
|
||||
}
|
||||
|
||||
if (data.name !== undefined) updateData.name = data.name
|
||||
if (data.endpoint !== undefined) updateData.endpoint = data.endpoint
|
||||
if (data.config !== undefined) updateData.config = data.config
|
||||
if (data.active !== undefined) updateData.active = data.active
|
||||
|
||||
@@ -135,23 +128,29 @@ export const updatePlatformConfig = async (id: string, config: Record<string, un
|
||||
|
||||
// active
|
||||
|
||||
export const platformConstructors: Record<string, typeof BasePlatform> = {
|
||||
telegram: TelegramPlatform,
|
||||
}
|
||||
|
||||
export const platforms = new Map<string, BasePlatform>()
|
||||
|
||||
export const activePlatform = async (platform: Platform) => {
|
||||
await fetch(path.join(platform.endpoint, '/start'), {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(platform.config),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
const Constructor = platformConstructors[platform.name]
|
||||
if (!Constructor) {
|
||||
throw new Error('Platform constructor not found')
|
||||
}
|
||||
const platformInstance = new Constructor()
|
||||
await platformInstance.start(platform.config)
|
||||
platforms.set(platform.name, platformInstance)
|
||||
}
|
||||
|
||||
export const inactivePlatform = async (platform: Platform) => {
|
||||
await fetch(path.join(platform.endpoint, '/stop'), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
const platformInstance = platforms.get(platform.name)
|
||||
if (!platformInstance) {
|
||||
throw new Error('Platform not found')
|
||||
}
|
||||
await platformInstance.stop()
|
||||
platforms.delete(platform.name)
|
||||
}
|
||||
|
||||
export const setActivePlatform = async (id: string, active: boolean) => {
|
||||
@@ -162,7 +161,6 @@ export const setActivePlatform = async (id: string, active: boolean) => {
|
||||
const platformData: Platform = {
|
||||
id: currentPlatform.id,
|
||||
name: currentPlatform.name,
|
||||
endpoint: currentPlatform.endpoint,
|
||||
config: currentPlatform.config as Record<string, unknown>,
|
||||
active: active,
|
||||
}
|
||||
@@ -187,11 +185,9 @@ export const sendMessageToPlatform = async (name: string, options: {
|
||||
if (!currentPlatform) {
|
||||
throw new Error('Platform not found')
|
||||
}
|
||||
await fetch(path.join(currentPlatform.endpoint, '/send'), {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(options),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
const platformInstance = platforms.get(currentPlatform.name)
|
||||
if (!platformInstance) {
|
||||
throw new Error('Platform not found')
|
||||
}
|
||||
await platformInstance.send(options)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user