mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-25 07:00:48 +09:00
refactor: platform
This commit is contained in:
@@ -16,8 +16,6 @@
|
|||||||
"db:migrate": "pnpm --filter @memoh/db migrate",
|
"db:migrate": "pnpm --filter @memoh/db migrate",
|
||||||
"db:generate": "pnpm --filter @memoh/db generate",
|
"db:generate": "pnpm --filter @memoh/db generate",
|
||||||
"db:studio": "pnpm --filter @memoh/db studio",
|
"db:studio": "pnpm --filter @memoh/db studio",
|
||||||
"telegram:start": "pnpm --filter @memoh/platform-telegram start",
|
|
||||||
"telegram:dev": "pnpm --filter @memoh/platform-telegram dev",
|
|
||||||
"cli": "pnpm --filter @memoh/client start",
|
"cli": "pnpm --filter @memoh/client start",
|
||||||
"docs:dev": "pnpm --filter @memoh/docs dev",
|
"docs:dev": "pnpm --filter @memoh/docs dev",
|
||||||
"docs:build": "pnpm --filter @memoh/docs build",
|
"docs:build": "pnpm --filter @memoh/docs build",
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
"@memoh/db": "workspace:*",
|
"@memoh/db": "workspace:*",
|
||||||
"@memoh/memory": "workspace:*",
|
"@memoh/memory": "workspace:*",
|
||||||
"@memoh/shared": "workspace:*",
|
"@memoh/shared": "workspace:*",
|
||||||
|
"@memoh/platform": "workspace:*",
|
||||||
|
"@memoh/platform-telegram": "workspace:*",
|
||||||
"drizzle-orm": "^0.45.1",
|
"drizzle-orm": "^0.45.1",
|
||||||
"elysia": "latest",
|
"elysia": "latest",
|
||||||
"node-cron": "^4.2.1",
|
"node-cron": "^4.2.1",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
DeletePlatformModel,
|
DeletePlatformModel,
|
||||||
UpdatePlatformConfigModel,
|
UpdatePlatformConfigModel,
|
||||||
SetPlatformActiveModel,
|
SetPlatformActiveModel,
|
||||||
|
getPlatformConfigSchema,
|
||||||
} from './model'
|
} from './model'
|
||||||
import {
|
import {
|
||||||
getPlatforms,
|
getPlatforms,
|
||||||
@@ -34,7 +35,6 @@ export const platformModule = new Elysia({
|
|||||||
await activePlatform({
|
await activePlatform({
|
||||||
id: platform.id,
|
id: platform.id,
|
||||||
name: platform.name,
|
name: platform.name,
|
||||||
endpoint: platform.endpoint,
|
|
||||||
config: platform.config as Record<string, unknown>,
|
config: platform.config as Record<string, unknown>,
|
||||||
active: platform.active,
|
active: platform.active,
|
||||||
})
|
})
|
||||||
@@ -140,13 +140,21 @@ export const platformModule = new Elysia({
|
|||||||
try {
|
try {
|
||||||
const { id } = params
|
const { id } = params
|
||||||
const { config } = body as { config: Record<string, unknown> }
|
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 {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: 'Platform not found',
|
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 {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
data: updatedPlatform,
|
data: updatedPlatform,
|
||||||
|
|||||||
@@ -1,10 +1,59 @@
|
|||||||
import { z } from 'zod'
|
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({
|
const PlatformSchema = z.object({
|
||||||
name: z.string().min(1, 'Platform name is required'),
|
name: z.string().min(1, 'Platform name is required'),
|
||||||
endpoint: z.string().min(1, 'Endpoint is required'),
|
|
||||||
config: z.record(z.string(), z.unknown()),
|
config: z.record(z.string(), z.unknown()),
|
||||||
active: z.boolean().optional().default(true),
|
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>
|
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 = {
|
export const UpdatePlatformConfigModel = {
|
||||||
params: z.object({
|
params: z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
|
|||||||
@@ -3,15 +3,12 @@ import { platform } from '@memoh/db/schema'
|
|||||||
import { Platform } from '@memoh/shared'
|
import { Platform } from '@memoh/shared'
|
||||||
import { eq, sql, desc, asc } from 'drizzle-orm'
|
import { eq, sql, desc, asc } from 'drizzle-orm'
|
||||||
import { calculateOffset, createPaginatedResult, type PaginatedResult } from '../../utils/pagination'
|
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 = {
|
type PlatformListItem = {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
endpoint: string
|
|
||||||
config: Record<string, unknown>
|
config: Record<string, unknown>
|
||||||
active: boolean
|
active: boolean
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
@@ -72,7 +69,6 @@ export const createPlatform = async (data: Omit<Platform, 'id'>) => {
|
|||||||
.insert(platform)
|
.insert(platform)
|
||||||
.values({
|
.values({
|
||||||
name: data.name,
|
name: data.name,
|
||||||
endpoint: data.endpoint,
|
|
||||||
config: data.config,
|
config: data.config,
|
||||||
active: data.active ?? true,
|
active: data.active ?? true,
|
||||||
})
|
})
|
||||||
@@ -81,7 +77,6 @@ export const createPlatform = async (data: Omit<Platform, 'id'>) => {
|
|||||||
await activePlatform({
|
await activePlatform({
|
||||||
id: newPlatform.id,
|
id: newPlatform.id,
|
||||||
name: newPlatform.name,
|
name: newPlatform.name,
|
||||||
endpoint: newPlatform.endpoint,
|
|
||||||
config: newPlatform.config as Record<string, unknown>,
|
config: newPlatform.config as Record<string, unknown>,
|
||||||
active: newPlatform.active,
|
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'>>) => {
|
export const updatePlatform = async (id: string, data: Partial<Omit<Platform, 'id'>>) => {
|
||||||
const updateData: {
|
const updateData: {
|
||||||
name?: string
|
name?: string
|
||||||
endpoint?: string
|
|
||||||
config?: Record<string, unknown>
|
config?: Record<string, unknown>
|
||||||
active?: boolean
|
active?: boolean
|
||||||
updatedAt: Date
|
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.name !== undefined) updateData.name = data.name
|
||||||
if (data.endpoint !== undefined) updateData.endpoint = data.endpoint
|
|
||||||
if (data.config !== undefined) updateData.config = data.config
|
if (data.config !== undefined) updateData.config = data.config
|
||||||
if (data.active !== undefined) updateData.active = data.active
|
if (data.active !== undefined) updateData.active = data.active
|
||||||
|
|
||||||
@@ -135,23 +128,29 @@ export const updatePlatformConfig = async (id: string, config: Record<string, un
|
|||||||
|
|
||||||
// active
|
// active
|
||||||
|
|
||||||
|
export const platformConstructors: Record<string, typeof BasePlatform> = {
|
||||||
|
telegram: TelegramPlatform,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const platforms = new Map<string, BasePlatform>()
|
||||||
|
|
||||||
export const activePlatform = async (platform: Platform) => {
|
export const activePlatform = async (platform: Platform) => {
|
||||||
await fetch(path.join(platform.endpoint, '/start'), {
|
const Constructor = platformConstructors[platform.name]
|
||||||
method: 'POST',
|
if (!Constructor) {
|
||||||
body: JSON.stringify(platform.config),
|
throw new Error('Platform constructor not found')
|
||||||
headers: {
|
}
|
||||||
'Content-Type': 'application/json',
|
const platformInstance = new Constructor()
|
||||||
},
|
await platformInstance.start(platform.config)
|
||||||
})
|
platforms.set(platform.name, platformInstance)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const inactivePlatform = async (platform: Platform) => {
|
export const inactivePlatform = async (platform: Platform) => {
|
||||||
await fetch(path.join(platform.endpoint, '/stop'), {
|
const platformInstance = platforms.get(platform.name)
|
||||||
method: 'POST',
|
if (!platformInstance) {
|
||||||
headers: {
|
throw new Error('Platform not found')
|
||||||
'Content-Type': 'application/json',
|
}
|
||||||
},
|
await platformInstance.stop()
|
||||||
})
|
platforms.delete(platform.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const setActivePlatform = async (id: string, active: boolean) => {
|
export const setActivePlatform = async (id: string, active: boolean) => {
|
||||||
@@ -162,7 +161,6 @@ export const setActivePlatform = async (id: string, active: boolean) => {
|
|||||||
const platformData: Platform = {
|
const platformData: Platform = {
|
||||||
id: currentPlatform.id,
|
id: currentPlatform.id,
|
||||||
name: currentPlatform.name,
|
name: currentPlatform.name,
|
||||||
endpoint: currentPlatform.endpoint,
|
|
||||||
config: currentPlatform.config as Record<string, unknown>,
|
config: currentPlatform.config as Record<string, unknown>,
|
||||||
active: active,
|
active: active,
|
||||||
}
|
}
|
||||||
@@ -187,11 +185,9 @@ export const sendMessageToPlatform = async (name: string, options: {
|
|||||||
if (!currentPlatform) {
|
if (!currentPlatform) {
|
||||||
throw new Error('Platform not found')
|
throw new Error('Platform not found')
|
||||||
}
|
}
|
||||||
await fetch(path.join(currentPlatform.endpoint, '/send'), {
|
const platformInstance = platforms.get(currentPlatform.name)
|
||||||
method: 'POST',
|
if (!platformInstance) {
|
||||||
body: JSON.stringify(options),
|
throw new Error('Platform not found')
|
||||||
headers: {
|
}
|
||||||
'Content-Type': 'application/json',
|
await platformInstance.send(options)
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { table } from 'table'
|
|||||||
import * as platformCore from '../../core/platform'
|
import * as platformCore from '../../core/platform'
|
||||||
import { formatError } from '../../utils'
|
import { formatError } from '../../utils'
|
||||||
import { getApiUrl } from '../../core/client'
|
import { getApiUrl } from '../../core/client'
|
||||||
|
import { PLATFORM_DEFINITIONS, type PlatformDefinition } from '../../types'
|
||||||
|
|
||||||
export function platformCommands(program: Command) {
|
export function platformCommands(program: Command) {
|
||||||
program
|
program
|
||||||
@@ -23,11 +24,10 @@ export function platformCommands(program: Command) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const tableData = [
|
const tableData = [
|
||||||
['ID', 'Name', 'Endpoint', 'Active', 'Created'],
|
['ID', 'Name', 'Active', 'Created'],
|
||||||
...platforms.map((item) => [
|
...platforms.map((item) => [
|
||||||
item.id.substring(0, 8) + '...',
|
item.id.substring(0, 8) + '...',
|
||||||
item.name,
|
item.name,
|
||||||
item.endpoint,
|
|
||||||
item.active ? chalk.green('✓ Active') : chalk.dim('✗ Inactive'),
|
item.active ? chalk.green('✓ Active') : chalk.dim('✗ Inactive'),
|
||||||
new Date(item.createdAt).toLocaleDateString(),
|
new Date(item.createdAt).toLocaleDateString(),
|
||||||
]),
|
]),
|
||||||
@@ -55,83 +55,73 @@ export function platformCommands(program: Command) {
|
|||||||
program
|
program
|
||||||
.command('create')
|
.command('create')
|
||||||
.description('Create platform configuration')
|
.description('Create platform configuration')
|
||||||
.option('-n, --name <name>', 'Platform name')
|
.action(async () => {
|
||||||
.option('-e, --endpoint <endpoint>', 'Platform endpoint URL')
|
|
||||||
.option('-c, --config <config>', 'Platform config (JSON string)')
|
|
||||||
.option('-a, --active', 'Set platform as active', true)
|
|
||||||
.action(async (options) => {
|
|
||||||
try {
|
try {
|
||||||
let { name, endpoint, config, active } = options
|
// Step 1: Select platform type
|
||||||
|
const { platformType } = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
type: 'list',
|
||||||
|
name: 'platformType',
|
||||||
|
message: 'Select platform type:',
|
||||||
|
choices: PLATFORM_DEFINITIONS.map((def) => ({
|
||||||
|
name: `${def.displayName} - ${def.description}`,
|
||||||
|
value: def.name,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
if (!name || !endpoint) {
|
const platformDef = PLATFORM_DEFINITIONS.find((def) => def.name === platformType)
|
||||||
const answers = await inquirer.prompt([
|
if (!platformDef) {
|
||||||
|
console.error(chalk.red('Invalid platform type'))
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Collect platform-specific config
|
||||||
|
console.log(chalk.cyan(`\nConfiguring ${platformDef.displayName}...\n`))
|
||||||
|
|
||||||
|
const configAnswers: Record<string, unknown> = {}
|
||||||
|
for (const field of platformDef.configFields) {
|
||||||
|
const answer = await inquirer.prompt([
|
||||||
{
|
{
|
||||||
type: 'input',
|
type: field.type || 'input',
|
||||||
name: 'name',
|
name: field.name,
|
||||||
message: 'Platform name:',
|
message: field.message,
|
||||||
when: !name,
|
default: field.default,
|
||||||
validate: (value: string) => {
|
validate: field.validate || ((value: string) => {
|
||||||
if (value.trim()) return true
|
if (field.required && !value?.toString().trim()) {
|
||||||
return 'Platform name is required'
|
return `${field.name} is required`
|
||||||
},
|
}
|
||||||
},
|
return true
|
||||||
{
|
}),
|
||||||
type: 'input',
|
|
||||||
name: 'endpoint',
|
|
||||||
message: 'Platform endpoint URL:',
|
|
||||||
when: !endpoint,
|
|
||||||
validate: (value: string) => {
|
|
||||||
if (value.trim()) return true
|
|
||||||
return 'Endpoint is required'
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'input',
|
|
||||||
name: 'config',
|
|
||||||
message: 'Platform config (JSON string):',
|
|
||||||
default: '{}',
|
|
||||||
when: !config,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'confirm',
|
|
||||||
name: 'active',
|
|
||||||
message: 'Set as active?',
|
|
||||||
default: true,
|
|
||||||
when: active === undefined,
|
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
configAnswers[field.name] = answer[field.name]
|
||||||
name = name || answers.name
|
|
||||||
endpoint = endpoint || answers.endpoint
|
|
||||||
config = config || answers.config
|
|
||||||
active = active ?? answers.active
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse config JSON
|
// Step 3: Confirm active status
|
||||||
let configObj: Record<string, unknown> = {}
|
const { active } = await inquirer.prompt([
|
||||||
if (config) {
|
{
|
||||||
try {
|
type: 'confirm',
|
||||||
configObj = JSON.parse(config)
|
name: 'active',
|
||||||
} catch {
|
message: 'Set as active?',
|
||||||
console.error(chalk.red('Invalid JSON config'))
|
default: true,
|
||||||
process.exit(1)
|
},
|
||||||
}
|
])
|
||||||
}
|
|
||||||
|
|
||||||
const spinner = ora('Creating platform configuration...').start()
|
const spinner = ora('Creating platform configuration...').start()
|
||||||
|
|
||||||
const platform = await platformCore.createPlatform({
|
const platform = await platformCore.createPlatform({
|
||||||
name,
|
name: platformType,
|
||||||
endpoint,
|
config: configAnswers,
|
||||||
config: configObj,
|
|
||||||
active,
|
active,
|
||||||
})
|
})
|
||||||
|
|
||||||
spinner.succeed(chalk.green('Platform configuration created successfully'))
|
spinner.succeed(chalk.green('Platform configuration created successfully'))
|
||||||
console.log(chalk.blue(`Name: ${platform.name}`))
|
console.log(chalk.blue(`\nPlatform: ${platformDef.displayName}`))
|
||||||
console.log(chalk.blue(`Endpoint: ${platform.endpoint}`))
|
console.log(chalk.blue(`Type: ${platform.name}`))
|
||||||
console.log(chalk.blue(`Active: ${platform.active ? 'Yes' : 'No'}`))
|
console.log(chalk.blue(`Active: ${platform.active ? 'Yes' : 'No'}`))
|
||||||
console.log(chalk.blue(`ID: ${platform.id}`))
|
console.log(chalk.blue(`ID: ${platform.id}`))
|
||||||
|
console.log(chalk.dim(`\nConfig: ${JSON.stringify(platform.config, null, 2)}`))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(chalk.red(formatError(error)))
|
console.error(chalk.red(formatError(error)))
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
@@ -145,10 +135,11 @@ export function platformCommands(program: Command) {
|
|||||||
const spinner = ora('Fetching platform configuration...').start()
|
const spinner = ora('Fetching platform configuration...').start()
|
||||||
try {
|
try {
|
||||||
const platform = await platformCore.getPlatform(id)
|
const platform = await platformCore.getPlatform(id)
|
||||||
|
const platformDef = PLATFORM_DEFINITIONS.find((def) => def.name === platform.name)
|
||||||
spinner.succeed(chalk.green('Platform Configuration'))
|
spinner.succeed(chalk.green('Platform Configuration'))
|
||||||
console.log(chalk.blue(`ID: ${platform.id}`))
|
console.log(chalk.blue(`ID: ${platform.id}`))
|
||||||
console.log(chalk.blue(`Name: ${platform.name}`))
|
console.log(chalk.blue(`Platform: ${platformDef?.displayName || platform.name}`))
|
||||||
console.log(chalk.blue(`Endpoint: ${platform.endpoint}`))
|
console.log(chalk.blue(`Type: ${platform.name}`))
|
||||||
console.log(chalk.blue(`Active: ${platform.active ? 'Yes' : 'No'}`))
|
console.log(chalk.blue(`Active: ${platform.active ? 'Yes' : 'No'}`))
|
||||||
console.log(chalk.blue(`Config: ${JSON.stringify(platform.config, null, 2)}`))
|
console.log(chalk.blue(`Config: ${JSON.stringify(platform.config, null, 2)}`))
|
||||||
console.log(chalk.blue(`Created At: ${new Date(platform.createdAt).toLocaleString('en-US')}`))
|
console.log(chalk.blue(`Created At: ${new Date(platform.createdAt).toLocaleString('en-US')}`))
|
||||||
@@ -163,8 +154,7 @@ export function platformCommands(program: Command) {
|
|||||||
program
|
program
|
||||||
.command('update <id>')
|
.command('update <id>')
|
||||||
.description('Update platform configuration')
|
.description('Update platform configuration')
|
||||||
.option('-n, --name <name>', 'Platform name')
|
.option('-n, --name <name>', 'Platform type (e.g., telegram)')
|
||||||
.option('-e, --endpoint <endpoint>', 'Platform endpoint URL')
|
|
||||||
.option('-c, --config <config>', 'Platform config (JSON string)')
|
.option('-c, --config <config>', 'Platform config (JSON string)')
|
||||||
.option('-a, --active <active>', 'Set active status (true/false)')
|
.option('-a, --active <active>', 'Set active status (true/false)')
|
||||||
.action(async (id, options) => {
|
.action(async (id, options) => {
|
||||||
@@ -172,7 +162,6 @@ export function platformCommands(program: Command) {
|
|||||||
const updates: Record<string, unknown> = {}
|
const updates: Record<string, unknown> = {}
|
||||||
|
|
||||||
if (options.name) updates.name = options.name
|
if (options.name) updates.name = options.name
|
||||||
if (options.endpoint) updates.endpoint = options.endpoint
|
|
||||||
if (options.config) {
|
if (options.config) {
|
||||||
try {
|
try {
|
||||||
updates.config = JSON.parse(options.config)
|
updates.config = JSON.parse(options.config)
|
||||||
@@ -193,8 +182,9 @@ export function platformCommands(program: Command) {
|
|||||||
const spinner = ora('Updating platform configuration...').start()
|
const spinner = ora('Updating platform configuration...').start()
|
||||||
const platform = await platformCore.updatePlatform(id, updates as any)
|
const platform = await platformCore.updatePlatform(id, updates as any)
|
||||||
spinner.succeed(chalk.green('Platform configuration updated successfully'))
|
spinner.succeed(chalk.green('Platform configuration updated successfully'))
|
||||||
console.log(chalk.blue(`Name: ${platform.name}`))
|
const platformDef = PLATFORM_DEFINITIONS.find((def) => def.name === platform.name)
|
||||||
console.log(chalk.blue(`Endpoint: ${platform.endpoint}`))
|
console.log(chalk.blue(`Platform: ${platformDef?.displayName || platform.name}`))
|
||||||
|
console.log(chalk.blue(`Type: ${platform.name}`))
|
||||||
console.log(chalk.blue(`Active: ${platform.active ? 'Yes' : 'No'}`))
|
console.log(chalk.blue(`Active: ${platform.active ? 'Yes' : 'No'}`))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(chalk.red(formatError(error)))
|
console.error(chalk.red(formatError(error)))
|
||||||
@@ -204,23 +194,62 @@ export function platformCommands(program: Command) {
|
|||||||
|
|
||||||
program
|
program
|
||||||
.command('update-config <id>')
|
.command('update-config <id>')
|
||||||
.description('Update platform config only')
|
.description('Update platform config interactively or via JSON')
|
||||||
.requiredOption('-c, --config <config>', 'Platform config (JSON string)')
|
.option('-c, --config <config>', 'Platform config (JSON string)')
|
||||||
.action(async (id, options) => {
|
.action(async (id, options) => {
|
||||||
try {
|
try {
|
||||||
let configObj: Record<string, unknown>
|
let configObj: Record<string, unknown>
|
||||||
try {
|
|
||||||
configObj = JSON.parse(options.config)
|
if (options.config) {
|
||||||
} catch {
|
// Use provided JSON config
|
||||||
console.error(chalk.red('Invalid JSON config'))
|
try {
|
||||||
process.exit(1)
|
configObj = JSON.parse(options.config)
|
||||||
|
} catch {
|
||||||
|
console.error(chalk.red('Invalid JSON config'))
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Interactive mode - get current platform first
|
||||||
|
const spinner = ora('Fetching platform...').start()
|
||||||
|
const platform = await platformCore.getPlatform(id)
|
||||||
|
spinner.stop()
|
||||||
|
|
||||||
|
const platformDef = PLATFORM_DEFINITIONS.find((def) => def.name === platform.name)
|
||||||
|
if (!platformDef) {
|
||||||
|
console.error(chalk.red(`Unknown platform type: ${platform.name}`))
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(chalk.cyan(`\nUpdating config for ${platformDef.displayName}...\n`))
|
||||||
|
|
||||||
|
configObj = {}
|
||||||
|
for (const field of platformDef.configFields) {
|
||||||
|
const currentValue = (platform.config as Record<string, unknown>)[field.name]
|
||||||
|
const answer = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
type: field.type || 'input',
|
||||||
|
name: field.name,
|
||||||
|
message: field.message,
|
||||||
|
default: currentValue || field.default,
|
||||||
|
validate: field.validate || ((value: string) => {
|
||||||
|
if (field.required && !value?.toString().trim()) {
|
||||||
|
return `${field.name} is required`
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
])
|
||||||
|
configObj[field.name] = answer[field.name]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const spinner = ora('Updating platform config...').start()
|
const spinner = ora('Updating platform config...').start()
|
||||||
const platform = await platformCore.updatePlatformConfig(id, configObj)
|
const platform = await platformCore.updatePlatformConfig(id, configObj)
|
||||||
spinner.succeed(chalk.green('Platform config updated successfully'))
|
spinner.succeed(chalk.green('Platform config updated successfully'))
|
||||||
console.log(chalk.blue(`Name: ${platform.name}`))
|
const platformDef = PLATFORM_DEFINITIONS.find((def) => def.name === platform.name)
|
||||||
console.log(chalk.blue(`Config: ${JSON.stringify(platform.config, null, 2)}`))
|
console.log(chalk.blue(`\nPlatform: ${platformDef?.displayName || platform.name}`))
|
||||||
|
console.log(chalk.blue(`Type: ${platform.name}`))
|
||||||
|
console.log(chalk.dim(`Config: ${JSON.stringify(platform.config, null, 2)}`))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(chalk.red(formatError(error)))
|
console.error(chalk.red(formatError(error)))
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
@@ -263,8 +292,9 @@ export function platformCommands(program: Command) {
|
|||||||
try {
|
try {
|
||||||
const platform = await platformCore.activatePlatform(id)
|
const platform = await platformCore.activatePlatform(id)
|
||||||
spinner.succeed(chalk.green('Platform activated successfully'))
|
spinner.succeed(chalk.green('Platform activated successfully'))
|
||||||
console.log(chalk.blue(`Name: ${platform.name}`))
|
const platformDef = PLATFORM_DEFINITIONS.find((def) => def.name === platform.name)
|
||||||
console.log(chalk.blue(`Endpoint: ${platform.endpoint}`))
|
console.log(chalk.blue(`Platform: ${platformDef?.displayName || platform.name}`))
|
||||||
|
console.log(chalk.blue(`Type: ${platform.name}`))
|
||||||
console.log(chalk.blue(`Active: ${platform.active ? chalk.green('Yes') : 'No'}`))
|
console.log(chalk.blue(`Active: ${platform.active ? chalk.green('Yes') : 'No'}`))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
spinner.fail(chalk.red('Operation failed'))
|
spinner.fail(chalk.red('Operation failed'))
|
||||||
@@ -281,8 +311,9 @@ export function platformCommands(program: Command) {
|
|||||||
try {
|
try {
|
||||||
const platform = await platformCore.inactivatePlatform(id)
|
const platform = await platformCore.inactivatePlatform(id)
|
||||||
spinner.succeed(chalk.green('Platform deactivated successfully'))
|
spinner.succeed(chalk.green('Platform deactivated successfully'))
|
||||||
console.log(chalk.blue(`Name: ${platform.name}`))
|
const platformDef = PLATFORM_DEFINITIONS.find((def) => def.name === platform.name)
|
||||||
console.log(chalk.blue(`Endpoint: ${platform.endpoint}`))
|
console.log(chalk.blue(`Platform: ${platformDef?.displayName || platform.name}`))
|
||||||
|
console.log(chalk.blue(`Type: ${platform.name}`))
|
||||||
console.log(chalk.blue(`Active: ${platform.active ? 'Yes' : chalk.dim('No')}`))
|
console.log(chalk.blue(`Active: ${platform.active ? 'Yes' : chalk.dim('No')}`))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
spinner.fail(chalk.red('Operation failed'))
|
spinner.fail(chalk.red('Operation failed'))
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import type { Platform, ApiResponse } from '../types'
|
|||||||
|
|
||||||
export interface CreatePlatformParams {
|
export interface CreatePlatformParams {
|
||||||
name: string
|
name: string
|
||||||
endpoint: string
|
|
||||||
config: Record<string, unknown>
|
config: Record<string, unknown>
|
||||||
active?: boolean
|
active?: boolean
|
||||||
}
|
}
|
||||||
@@ -11,7 +10,6 @@ export interface CreatePlatformParams {
|
|||||||
export interface PlatformListItem {
|
export interface PlatformListItem {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
endpoint: string
|
|
||||||
config: Record<string, unknown>
|
config: Record<string, unknown>
|
||||||
active: boolean
|
active: boolean
|
||||||
createdAt: string
|
createdAt: string
|
||||||
@@ -48,7 +46,6 @@ export async function createPlatform(params: CreatePlatformParams): Promise<Plat
|
|||||||
|
|
||||||
const payload: Record<string, unknown> = {
|
const payload: Record<string, unknown> = {
|
||||||
name: params.name,
|
name: params.name,
|
||||||
endpoint: params.endpoint,
|
|
||||||
config: params.config,
|
config: params.config,
|
||||||
active: params.active ?? true,
|
active: params.active ?? true,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,13 +72,70 @@ export interface Schedule {
|
|||||||
export interface Platform {
|
export interface Platform {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
endpoint: string
|
|
||||||
config: Record<string, unknown>
|
config: Record<string, unknown>
|
||||||
active: boolean
|
active: boolean
|
||||||
createdAt: string
|
createdAt: string
|
||||||
updatedAt: string
|
updatedAt: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Platform configuration definitions
|
||||||
|
export interface PlatformConfigField {
|
||||||
|
name: string
|
||||||
|
message: string
|
||||||
|
type?: 'input' | 'password' | 'number'
|
||||||
|
required?: boolean
|
||||||
|
default?: string | number
|
||||||
|
validate?: (value: string) => boolean | string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PlatformDefinition {
|
||||||
|
name: string
|
||||||
|
displayName: string
|
||||||
|
description: string
|
||||||
|
configFields: PlatformConfigField[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Platform configurations
|
||||||
|
export const PLATFORM_DEFINITIONS: PlatformDefinition[] = [
|
||||||
|
{
|
||||||
|
name: 'telegram',
|
||||||
|
displayName: 'Telegram',
|
||||||
|
description: 'Telegram Bot Platform',
|
||||||
|
configFields: [
|
||||||
|
{
|
||||||
|
name: 'botToken',
|
||||||
|
message: 'Bot Token:',
|
||||||
|
type: 'password',
|
||||||
|
required: true,
|
||||||
|
validate: (value: string) => {
|
||||||
|
if (!value.trim()) return 'Bot token is required'
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
// Future platforms can be added here
|
||||||
|
// {
|
||||||
|
// name: 'discord',
|
||||||
|
// displayName: 'Discord',
|
||||||
|
// description: 'Discord Bot Platform',
|
||||||
|
// configFields: [
|
||||||
|
// {
|
||||||
|
// name: 'botToken',
|
||||||
|
// message: 'Bot Token:',
|
||||||
|
// type: 'password',
|
||||||
|
// required: true,
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'clientId',
|
||||||
|
// message: 'Client ID:',
|
||||||
|
// type: 'input',
|
||||||
|
// required: true,
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
]
|
||||||
|
|
||||||
export interface MCPConnection {
|
export interface MCPConnection {
|
||||||
id: string
|
id: string
|
||||||
type: string
|
type: string
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { boolean, jsonb, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-c
|
|||||||
export const platform = pgTable('platform', {
|
export const platform = pgTable('platform', {
|
||||||
id: uuid('id').primaryKey().defaultRandom(),
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
name: text('name').notNull(),
|
name: text('name').notNull(),
|
||||||
endpoint: text('endpoint').notNull(),
|
// endpoint: text('endpoint').notNull(),
|
||||||
config: jsonb('config').notNull(),
|
config: jsonb('config').notNull(),
|
||||||
active: boolean('active').notNull().default(true),
|
active: boolean('active').notNull().default(true),
|
||||||
createdAt: timestamp('created_at').notNull().defaultNow(),
|
createdAt: timestamp('created_at').notNull().defaultNow(),
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
"memoh-tg-bot": "./src/bot.ts"
|
"memoh-tg-bot": "./src/bot.ts"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "bun run src/bot.ts",
|
|
||||||
"dev": "bun run --watch src/bot.ts"
|
"dev": "bun run --watch src/bot.ts"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
@@ -20,6 +19,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@memoh/client": "workspace:*",
|
"@memoh/client": "workspace:*",
|
||||||
"@memoh/platform": "workspace:*",
|
"@memoh/platform": "workspace:*",
|
||||||
|
"@memoh/shared": "workspace:*",
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
"ioredis": "^5.9.1",
|
"ioredis": "^5.9.1",
|
||||||
"telegraf": "^4.16.3",
|
"telegraf": "^4.16.3",
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
#!/usr/bin/env bun
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Telegram Bot Standalone Entry Point
|
|
||||||
*
|
|
||||||
* This file allows running the Telegram bot as a standalone process
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { TelegramPlatform } from './index'
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
const botToken = process.env.BOT_TOKEN
|
|
||||||
const redisUrl = process.env.REDIS_URL
|
|
||||||
const apiUrl = process.env.API_BASE_URL
|
|
||||||
|
|
||||||
if (!botToken) {
|
|
||||||
console.error('❌ BOT_TOKEN environment variable is required')
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('🚀 Starting Telegram bot...')
|
|
||||||
console.log(`📡 API URL: ${apiUrl || 'http://localhost:7002'}`)
|
|
||||||
console.log(`💾 Redis URL: ${redisUrl || 'redis://localhost:6379'}`)
|
|
||||||
|
|
||||||
const platform = new TelegramPlatform()
|
|
||||||
|
|
||||||
try {
|
|
||||||
platform.serve()
|
|
||||||
|
|
||||||
console.log('✅ Bot is running...')
|
|
||||||
console.log('Press Ctrl+C to stop')
|
|
||||||
|
|
||||||
// Graceful shutdown
|
|
||||||
process.once('SIGINT', async () => {
|
|
||||||
console.log('\n🛑 Stopping bot...')
|
|
||||||
await platform.stop()
|
|
||||||
process.exit(0)
|
|
||||||
})
|
|
||||||
|
|
||||||
process.once('SIGTERM', async () => {
|
|
||||||
console.log('\n🛑 Stopping bot...')
|
|
||||||
await platform.stop()
|
|
||||||
process.exit(0)
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error('❌ Failed to start bot:', error)
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
main()
|
|
||||||
|
|
||||||
@@ -1,65 +1,38 @@
|
|||||||
import { Telegraf, type Context } from 'telegraf'
|
import { Telegraf, type Context } from 'telegraf'
|
||||||
import { BasePlatform, SendSchema } from '@memoh/platform'
|
import { BasePlatform, PlatformMessage } from '@memoh/platform'
|
||||||
import { handleLogin, handleLogout, handleWhoami, requireAuth } from './auth'
|
import { handleLogin, handleLogout, handleWhoami, requireAuth } from './auth'
|
||||||
import { chatStreamAsync, type StreamEvent } from '@memoh/client'
|
import { chatStreamAsync, type StreamEvent } from '@memoh/client'
|
||||||
import { getTokenStorage } from './storage'
|
import { getTokenStorage } from './storage'
|
||||||
import z from 'zod'
|
|
||||||
import Redis from 'ioredis'
|
import Redis from 'ioredis'
|
||||||
|
import { Platform } from '@memoh/shared'
|
||||||
|
|
||||||
export interface TelegramPlatformConfig {
|
export interface TelegramPlatformConfig {
|
||||||
botToken: string
|
botToken: string
|
||||||
redisUrl?: string
|
|
||||||
apiUrl?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class TelegramPlatform extends BasePlatform {
|
export class TelegramPlatform extends BasePlatform {
|
||||||
name = 'telegram'
|
name = 'telegram'
|
||||||
description = 'Telegram Bot platform for Memoh'
|
description = 'Telegram Bot platform'
|
||||||
config = z.object({
|
|
||||||
botToken: z.string(),
|
|
||||||
})
|
|
||||||
port = 7101
|
|
||||||
|
|
||||||
private bot?: Telegraf
|
private bot?: Telegraf
|
||||||
redis = new Redis(process.env.REDIS_URL || 'redis://localhost:6379')
|
redis = new Redis(process.env.REDIS_URL || 'redis://localhost:6379')
|
||||||
// private storage?: TelegramRedisStorage
|
|
||||||
|
|
||||||
override async start(config: z.infer<typeof this.config>): Promise<void> {
|
async start({ botToken }: TelegramPlatformConfig): Promise<void> {
|
||||||
const botToken = config.botToken as string
|
|
||||||
if (!botToken) {
|
|
||||||
throw new Error('Bot token is required')
|
|
||||||
}
|
|
||||||
|
|
||||||
// // Initialize storage
|
|
||||||
// this.storage = new TelegramRedisStorage({
|
|
||||||
// redisUrl: config.redisUrl as string,
|
|
||||||
// apiUrl: config.apiUrl as string,
|
|
||||||
// })
|
|
||||||
|
|
||||||
// Initialize bot
|
|
||||||
this.bot = new Telegraf(botToken)
|
this.bot = new Telegraf(botToken)
|
||||||
|
|
||||||
// Register commands
|
|
||||||
this.registerCommands()
|
this.registerCommands()
|
||||||
|
|
||||||
// Start bot
|
|
||||||
this.bot.launch()
|
this.bot.launch()
|
||||||
console.log('✅ Telegram bot started successfully')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async stop(): Promise<void> {
|
async stop(): Promise<void> {
|
||||||
if (this.bot) {
|
if (this.bot) {
|
||||||
this.bot.stop('SIGTERM')
|
this.bot.stop('SIGTERM')
|
||||||
console.log('🛑 Telegram bot stopped')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (this.storage) {
|
|
||||||
// await this.storage.close()
|
|
||||||
// console.log('🛑 Redis connection closed')
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async send({ userId, message }: z.infer<typeof SendSchema>): Promise<void> {
|
async send({ message, userId }: PlatformMessage): Promise<void> {
|
||||||
const pattern = 'memoh:telegram:*:userId'
|
const pattern = 'memoh:telegram:*:userId'
|
||||||
let cursor = '0'
|
let cursor = '0'
|
||||||
let telegramUserId: string | null = null
|
let telegramUserId: string | null = null
|
||||||
@@ -74,11 +47,9 @@ export class TelegramPlatform extends BasePlatform {
|
|||||||
)
|
)
|
||||||
cursor = nextCursor
|
cursor = nextCursor
|
||||||
|
|
||||||
// 检查每个 key 的值是否匹配目标 userId
|
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
const storedUserId = await this.redis.get(key)
|
const storedUserId = await this.redis.get(key)
|
||||||
if (storedUserId === userId) {
|
if (storedUserId === userId) {
|
||||||
// 从 key 中提取 telegramUserId: memoh:telegram:{telegramUserId}:userId
|
|
||||||
const match = key.match(/^memoh:telegram:(.+):userId$/)
|
const match = key.match(/^memoh:telegram:(.+):userId$/)
|
||||||
if (match) {
|
if (match) {
|
||||||
telegramUserId = match[1]
|
telegramUserId = match[1]
|
||||||
|
|||||||
@@ -1,70 +1,18 @@
|
|||||||
import { Elysia } from 'elysia'
|
export interface PlatformMessage {
|
||||||
import { cors } from '@elysiajs/cors'
|
message: string
|
||||||
import { z } from 'zod'
|
userId: string
|
||||||
|
}
|
||||||
export const SendSchema = z.object({
|
|
||||||
message: z.string(),
|
|
||||||
userId: z.string(),
|
|
||||||
})
|
|
||||||
|
|
||||||
export class BasePlatform {
|
export class BasePlatform {
|
||||||
name: string = 'base'
|
name: string = 'base'
|
||||||
description: string = 'Base platform'
|
description: string = 'Base platform'
|
||||||
started: boolean = false
|
started: boolean = false
|
||||||
port: number = 7003
|
|
||||||
|
|
||||||
config = z.record(z.string(), z.unknown())
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
async start(config: z.infer<typeof this.config>): Promise<void> {}
|
async start(config: unknown): Promise<void> {}
|
||||||
|
|
||||||
async stop(): Promise<void> {}
|
async stop(): Promise<void> {}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
async send(data: z.infer<typeof SendSchema>): Promise<void> {}
|
async send(data: PlatformMessage): Promise<void> {}
|
||||||
|
|
||||||
serve<T extends z.infer<typeof this.config>>(config?: T): void {
|
|
||||||
new Elysia()
|
|
||||||
.use(cors({
|
|
||||||
origin: '*',
|
|
||||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
|
||||||
allowedHeaders: ['Content-Type', 'Authorization'],
|
|
||||||
credentials: true,
|
|
||||||
}))
|
|
||||||
.onStart(() => {
|
|
||||||
if (config) {
|
|
||||||
this.started = true
|
|
||||||
this.start(config)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.post('/start', async ({ body }) => {
|
|
||||||
if (!this.started) {
|
|
||||||
this.start(body)
|
|
||||||
this.started = true
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
body: this.config,
|
|
||||||
})
|
|
||||||
.post('/stop', async () => {
|
|
||||||
if (this.started) {
|
|
||||||
this.stop()
|
|
||||||
this.started = false
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.post('/send', async ({ body }) => {
|
|
||||||
await this.send(body)
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
body: SendSchema,
|
|
||||||
})
|
|
||||||
.listen(this.port)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
export interface Platform {
|
export interface Platform {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
endpoint: string
|
// endpoint: string
|
||||||
config: Record<string, unknown>
|
config: Record<string, unknown>
|
||||||
active: boolean
|
active: boolean
|
||||||
}
|
}
|
||||||
Generated
+9
@@ -132,6 +132,12 @@ importers:
|
|||||||
'@memoh/memory':
|
'@memoh/memory':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../memory
|
version: link:../memory
|
||||||
|
'@memoh/platform':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../platform
|
||||||
|
'@memoh/platform-telegram':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../platform-telegram
|
||||||
'@memoh/shared':
|
'@memoh/shared':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../shared
|
version: link:../shared
|
||||||
@@ -270,6 +276,9 @@ importers:
|
|||||||
'@memoh/platform':
|
'@memoh/platform':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../platform
|
version: link:../platform
|
||||||
|
'@memoh/shared':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../shared
|
||||||
dotenv:
|
dotenv:
|
||||||
specifier: ^16.4.7
|
specifier: ^16.4.7
|
||||||
version: 16.6.1
|
version: 16.6.1
|
||||||
|
|||||||
Reference in New Issue
Block a user