mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-16 13:27:08 +00:00
triggers
This commit is contained in:
parent
c3b7127333
commit
a3c74f82db
7 changed files with 615 additions and 5 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -2,3 +2,4 @@ node_modules/
|
||||||
data/
|
data/
|
||||||
utils/processors
|
utils/processors
|
||||||
utils/tools
|
utils/tools
|
||||||
|
utils/triggers
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,8 @@ class ChatGPTConfig {
|
||||||
dataDir: 'data',
|
dataDir: 'data',
|
||||||
// 处理器目录,相对于插件下
|
// 处理器目录,相对于插件下
|
||||||
processorsDirPath: 'utils/processors',
|
processorsDirPath: 'utils/processors',
|
||||||
|
// 触发器目录,相对于插件目录下
|
||||||
|
triggersDir: 'utils/triggers',
|
||||||
// 工具目录,相对于插件目录下
|
// 工具目录,相对于插件目录下
|
||||||
toolsDirPath: 'utils/tools',
|
toolsDirPath: 'utils/tools',
|
||||||
// 云端API url
|
// 云端API url
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@ import {
|
||||||
ProcessorsManager,
|
ProcessorsManager,
|
||||||
RAGManager,
|
RAGManager,
|
||||||
ToolManager,
|
ToolManager,
|
||||||
ToolsGroupManager
|
ToolsGroupManager,
|
||||||
|
TriggerManager
|
||||||
} from 'chaite'
|
} from 'chaite'
|
||||||
import ChatGPTConfig from '../../config/config.js'
|
import ChatGPTConfig from '../../config/config.js'
|
||||||
import { LowDBChannelStorage } from './storage/lowdb/channel_storage.js'
|
import { LowDBChannelStorage } from './storage/lowdb/channel_storage.js'
|
||||||
|
|
@ -31,6 +32,8 @@ import { SQLiteUserStateStorage } from './storage/sqlite/user_state_storage.js'
|
||||||
import { SQLiteToolsGroupStorage } from './storage/sqlite/tool_groups_storage.js'
|
import { SQLiteToolsGroupStorage } from './storage/sqlite/tool_groups_storage.js'
|
||||||
import { checkMigrate } from './storage/sqlite/migrate.js'
|
import { checkMigrate } from './storage/sqlite/migrate.js'
|
||||||
import { SQLiteHistoryManager } from './storage/sqlite/history_manager.js'
|
import { SQLiteHistoryManager } from './storage/sqlite/history_manager.js'
|
||||||
|
import SQLiteTriggerStorage from './storage/sqlite/trigger_storage.js'
|
||||||
|
import LowDBTriggerStorage from './storage/lowdb/trigger_storage,.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 认证,以便共享上传
|
* 认证,以便共享上传
|
||||||
|
|
@ -129,7 +132,7 @@ export async function initRagManager (model, dimensions) {
|
||||||
|
|
||||||
export async function initChaite () {
|
export async function initChaite () {
|
||||||
const storage = ChatGPTConfig.chaite.storage
|
const storage = ChatGPTConfig.chaite.storage
|
||||||
let channelsStorage, chatPresetsStorage, toolsStorage, processorsStorage, userStateStorage, historyStorage, toolsGroupStorage
|
let channelsStorage, chatPresetsStorage, toolsStorage, processorsStorage, userStateStorage, historyStorage, toolsGroupStorage, triggerStorage
|
||||||
switch (storage) {
|
switch (storage) {
|
||||||
case 'sqlite': {
|
case 'sqlite': {
|
||||||
const dbPath = path.join(dataDir, 'data.db')
|
const dbPath = path.join(dataDir, 'data.db')
|
||||||
|
|
@ -145,6 +148,8 @@ export async function initChaite () {
|
||||||
await userStateStorage.initialize()
|
await userStateStorage.initialize()
|
||||||
toolsGroupStorage = new SQLiteToolsGroupStorage(dbPath)
|
toolsGroupStorage = new SQLiteToolsGroupStorage(dbPath)
|
||||||
await toolsGroupStorage.initialize()
|
await toolsGroupStorage.initialize()
|
||||||
|
triggerStorage = new SQLiteTriggerStorage(dbPath)
|
||||||
|
await triggerStorage.initialize()
|
||||||
historyStorage = new SQLiteHistoryManager(dbPath, path.join(dataDir, 'images'))
|
historyStorage = new SQLiteHistoryManager(dbPath, path.join(dataDir, 'images'))
|
||||||
await checkMigrate()
|
await checkMigrate()
|
||||||
break
|
break
|
||||||
|
|
@ -157,6 +162,7 @@ export async function initChaite () {
|
||||||
toolsStorage = new LowDBToolsStorage(ChatGPTStorage)
|
toolsStorage = new LowDBToolsStorage(ChatGPTStorage)
|
||||||
processorsStorage = new LowDBProcessorsStorage(ChatGPTStorage)
|
processorsStorage = new LowDBProcessorsStorage(ChatGPTStorage)
|
||||||
userStateStorage = new LowDBUserStateStorage(ChatGPTStorage)
|
userStateStorage = new LowDBUserStateStorage(ChatGPTStorage)
|
||||||
|
triggerStorage = new LowDBTriggerStorage(ChatGPTStorage)
|
||||||
const ChatGPTHistoryStorage = (await import('storage/lowdb/storage.js')).ChatGPTHistoryStorage
|
const ChatGPTHistoryStorage = (await import('storage/lowdb/storage.js')).ChatGPTHistoryStorage
|
||||||
await ChatGPTHistoryStorage.init()
|
await ChatGPTHistoryStorage.init()
|
||||||
historyStorage = new LowDBHistoryManager(ChatGPTHistoryStorage)
|
historyStorage = new LowDBHistoryManager(ChatGPTHistoryStorage)
|
||||||
|
|
@ -176,8 +182,14 @@ export async function initChaite () {
|
||||||
const processorsManager = await ProcessorsManager.init(processorsDir, processorsStorage)
|
const processorsManager = await ProcessorsManager.init(processorsDir, processorsStorage)
|
||||||
const chatPresetManager = await ChatPresetManager.init(chatPresetsStorage)
|
const chatPresetManager = await ChatPresetManager.init(chatPresetsStorage)
|
||||||
const toolsGroupManager = await ToolsGroupManager.init(toolsGroupStorage)
|
const toolsGroupManager = await ToolsGroupManager.init(toolsGroupStorage)
|
||||||
|
const triggersDir = path.resolve('./plugins/chatgpt-plugin', ChatGPTConfig.chaite.triggersDir)
|
||||||
|
if (!fs.existsSync(triggersDir)) {
|
||||||
|
fs.mkdirSync(triggersDir, { recursive: true })
|
||||||
|
}
|
||||||
|
const triggerManager = new TriggerManager(triggersDir, triggerStorage)
|
||||||
|
await triggerManager.initialize()
|
||||||
const userModeSelector = new ChatGPTUserModeSelector()
|
const userModeSelector = new ChatGPTUserModeSelector()
|
||||||
let chaite = Chaite.init(channelsManager, toolsManager, processorsManager, chatPresetManager, toolsGroupManager,
|
let chaite = Chaite.init(channelsManager, toolsManager, processorsManager, chatPresetManager, toolsGroupManager, triggerManager,
|
||||||
userModeSelector, userStateStorage, historyStorage, logger)
|
userModeSelector, userStateStorage, historyStorage, logger)
|
||||||
logger.info('Chaite 初始化完成')
|
logger.info('Chaite 初始化完成')
|
||||||
chaite.setCloudService(ChatGPTConfig.chaite.cloudBaseUrl)
|
chaite.setCloudService(ChatGPTConfig.chaite.cloudBaseUrl)
|
||||||
|
|
|
||||||
122
models/chaite/storage/lowdb/trigger_storage,.js
Normal file
122
models/chaite/storage/lowdb/trigger_storage,.js
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
import { ChaiteStorage, TriggerDTO } from 'chaite'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends {ChaiteStorage<import('chaite').TriggerDTO>}
|
||||||
|
*/
|
||||||
|
export class LowDBTriggerStorage extends ChaiteStorage {
|
||||||
|
getName () {
|
||||||
|
return 'LowDBTriggerStorage'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {LowDBStorage} storage
|
||||||
|
*/
|
||||||
|
constructor (storage) {
|
||||||
|
super()
|
||||||
|
this.storage = storage
|
||||||
|
/**
|
||||||
|
* 集合
|
||||||
|
* @type {LowDBCollection}
|
||||||
|
*/
|
||||||
|
this.collection = this.storage.collection('triggers')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取单个触发器
|
||||||
|
* @param {string} key
|
||||||
|
* @returns {Promise<import('chaite').TriggerDTO>}
|
||||||
|
*/
|
||||||
|
async getItem (key) {
|
||||||
|
const obj = await this.collection.findOne({ id: key })
|
||||||
|
if (!obj) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return new TriggerDTO(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存触发器
|
||||||
|
* @param {string} id
|
||||||
|
* @param {import('chaite').TriggerDTO} trigger
|
||||||
|
* @returns {Promise<string>}
|
||||||
|
*/
|
||||||
|
async setItem (id, trigger) {
|
||||||
|
// 设置或更新时间戳
|
||||||
|
if (!trigger.createdAt) {
|
||||||
|
trigger.createdAt = new Date().toISOString()
|
||||||
|
}
|
||||||
|
trigger.updatedAt = new Date().toISOString()
|
||||||
|
|
||||||
|
if (id && await this.getItem(id)) {
|
||||||
|
await this.collection.updateById(id, trigger)
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
const result = await this.collection.insert(trigger)
|
||||||
|
return result.id
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除触发器
|
||||||
|
* @param {string} key
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async removeItem (key) {
|
||||||
|
await this.collection.deleteById(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有触发器
|
||||||
|
* @returns {Promise<import('chaite').TriggerDTO[]>}
|
||||||
|
*/
|
||||||
|
async listItems () {
|
||||||
|
const list = await this.collection.findAll()
|
||||||
|
return list.map(item => new TriggerDTO({}).fromString(JSON.stringify(item)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据条件筛选触发器
|
||||||
|
* @param {Record<string, unknown>} filter
|
||||||
|
* @returns {Promise<import('chaite').TriggerDTO[]>}
|
||||||
|
*/
|
||||||
|
async listItemsByEqFilter (filter) {
|
||||||
|
const allList = await this.listItems()
|
||||||
|
return allList.filter(item => {
|
||||||
|
for (const key in filter) {
|
||||||
|
if (item[key] !== filter[key]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据IN条件筛选触发器
|
||||||
|
* @param {Array<{
|
||||||
|
* field: string;
|
||||||
|
* values: unknown[];
|
||||||
|
* }>} query
|
||||||
|
* @returns {Promise<import('chaite').TriggerDTO[]>}
|
||||||
|
*/
|
||||||
|
async listItemsByInQuery (query) {
|
||||||
|
const allList = await this.listItems()
|
||||||
|
return allList.filter(item => {
|
||||||
|
for (const { field, values } of query) {
|
||||||
|
if (!values.includes(item[field])) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空所有触发器
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async clear () {
|
||||||
|
await this.collection.deleteAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LowDBTriggerStorage
|
||||||
474
models/chaite/storage/sqlite/trigger_storage.js
Normal file
474
models/chaite/storage/sqlite/trigger_storage.js
Normal file
|
|
@ -0,0 +1,474 @@
|
||||||
|
import { ChaiteStorage, TriggerDTO } from 'chaite'
|
||||||
|
import sqlite3 from 'sqlite3'
|
||||||
|
import path from 'path'
|
||||||
|
import fs from 'fs'
|
||||||
|
import { generateId } from '../../../../utils/common.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends {ChaiteStorage<import('chaite').TriggerDTO>}
|
||||||
|
*/
|
||||||
|
export class SQLiteTriggerStorage extends ChaiteStorage {
|
||||||
|
getName () {
|
||||||
|
return 'SQLiteTriggerStorage'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} dbPath 数据库文件路径
|
||||||
|
*/
|
||||||
|
constructor (dbPath) {
|
||||||
|
super()
|
||||||
|
this.dbPath = dbPath
|
||||||
|
this.db = null
|
||||||
|
this.initialized = false
|
||||||
|
this.tableName = 'triggers'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化数据库连接和表结构
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async initialize () {
|
||||||
|
if (this.initialized) return
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// 确保目录存在
|
||||||
|
const dir = path.dirname(this.dbPath)
|
||||||
|
if (!fs.existsSync(dir)) {
|
||||||
|
fs.mkdirSync(dir, { recursive: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
this.db = new sqlite3.Database(this.dbPath, async (err) => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建触发器表,将主要属性分列存储
|
||||||
|
this.db.run(`CREATE TABLE IF NOT EXISTS ${this.tableName} (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
modelType TEXT,
|
||||||
|
code TEXT,
|
||||||
|
cloudId INTEGER,
|
||||||
|
embedded INTEGER,
|
||||||
|
uploader TEXT,
|
||||||
|
createdAt TEXT,
|
||||||
|
updatedAt TEXT,
|
||||||
|
md5 TEXT,
|
||||||
|
status TEXT,
|
||||||
|
permission TEXT,
|
||||||
|
isOneTime INTEGER,
|
||||||
|
extraData TEXT -- 存储其他额外数据的JSON
|
||||||
|
)`, (err) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
} else {
|
||||||
|
// 创建索引以提高查询性能
|
||||||
|
this.db.run(`CREATE INDEX IF NOT EXISTS idx_triggers_name ON ${this.tableName} (name)`, (err) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
} else {
|
||||||
|
this.db.run(`CREATE INDEX IF NOT EXISTS idx_triggers_status ON ${this.tableName} (status)`, (err) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
} else {
|
||||||
|
this.initialized = true
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确保数据库已初始化
|
||||||
|
*/
|
||||||
|
async ensureInitialized () {
|
||||||
|
if (!this.initialized) {
|
||||||
|
await this.initialize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 TriggerDTO 对象转换为数据库记录
|
||||||
|
* @param {import('chaite').TriggerDTO} trigger
|
||||||
|
* @returns {Object} 数据库记录
|
||||||
|
*/
|
||||||
|
_triggerToRecord (trigger) {
|
||||||
|
// 提取主要字段,剩余的放入extraData
|
||||||
|
const {
|
||||||
|
id, name, description, modelType, code, cloudId,
|
||||||
|
embedded, uploader, createdAt, updatedAt, md5,
|
||||||
|
status, permission, isOneTime, ...rest
|
||||||
|
} = trigger
|
||||||
|
|
||||||
|
// 序列化上传者对象
|
||||||
|
const uploaderStr = uploader ? JSON.stringify(uploader) : null
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: id || '',
|
||||||
|
name: name || '',
|
||||||
|
description: description || '',
|
||||||
|
modelType: modelType || 'executable',
|
||||||
|
code: code || null,
|
||||||
|
cloudId: cloudId || null,
|
||||||
|
embedded: embedded ? 1 : 0,
|
||||||
|
uploader: uploaderStr,
|
||||||
|
createdAt: createdAt || '',
|
||||||
|
updatedAt: updatedAt || '',
|
||||||
|
md5: md5 || '',
|
||||||
|
status: status || 'enabled',
|
||||||
|
permission: permission || 'public',
|
||||||
|
isOneTime: isOneTime ? 1 : 0,
|
||||||
|
extraData: Object.keys(rest).length > 0 ? JSON.stringify(rest) : null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将数据库记录转换为 TriggerDTO 对象
|
||||||
|
* @param {Object} record 数据库记录
|
||||||
|
* @returns {import('chaite').TriggerDTO} TriggerDTO对象
|
||||||
|
*/
|
||||||
|
_recordToTrigger (record) {
|
||||||
|
// 若记录不存在则返回null
|
||||||
|
if (!record) return null
|
||||||
|
|
||||||
|
// 解析上传者
|
||||||
|
let uploader = null
|
||||||
|
try {
|
||||||
|
if (record.uploader) {
|
||||||
|
uploader = JSON.parse(record.uploader)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 解析错误,使用null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析额外数据
|
||||||
|
let extraData = {}
|
||||||
|
try {
|
||||||
|
if (record.extraData) {
|
||||||
|
extraData = JSON.parse(record.extraData)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 解析错误,使用空对象
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构造基本对象
|
||||||
|
const triggerData = {
|
||||||
|
id: record.id,
|
||||||
|
name: record.name,
|
||||||
|
description: record.description,
|
||||||
|
modelType: record.modelType,
|
||||||
|
code: record.code,
|
||||||
|
cloudId: record.cloudId,
|
||||||
|
embedded: Boolean(record.embedded),
|
||||||
|
uploader,
|
||||||
|
createdAt: record.createdAt,
|
||||||
|
updatedAt: record.updatedAt,
|
||||||
|
md5: record.md5,
|
||||||
|
status: record.status,
|
||||||
|
permission: record.permission,
|
||||||
|
isOneTime: Boolean(record.isOneTime),
|
||||||
|
...extraData
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TriggerDTO(triggerData)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取单个触发器
|
||||||
|
* @param {string} key 触发器ID
|
||||||
|
* @returns {Promise<import('chaite').TriggerDTO>}
|
||||||
|
*/
|
||||||
|
async getItem (key) {
|
||||||
|
await this.ensureInitialized()
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.db.get(`SELECT * FROM ${this.tableName} WHERE id = ?`, [key], (err, row) => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const trigger = this._recordToTrigger(row)
|
||||||
|
resolve(trigger)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存触发器
|
||||||
|
* @param {string} id 触发器ID
|
||||||
|
* @param {import('chaite').TriggerDTO} trigger 触发器对象
|
||||||
|
* @returns {Promise<string>}
|
||||||
|
*/
|
||||||
|
async setItem (id, trigger) {
|
||||||
|
await this.ensureInitialized()
|
||||||
|
|
||||||
|
if (!id) {
|
||||||
|
id = generateId()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加上时间戳
|
||||||
|
if (!trigger.createdAt) {
|
||||||
|
trigger.createdAt = new Date().toISOString()
|
||||||
|
}
|
||||||
|
|
||||||
|
trigger.updatedAt = new Date().toISOString()
|
||||||
|
|
||||||
|
// 转换为数据库记录
|
||||||
|
const record = this._triggerToRecord(trigger)
|
||||||
|
record.id = id // 确保ID是指定的ID
|
||||||
|
|
||||||
|
// 构建插入或更新SQL
|
||||||
|
const fields = Object.keys(record)
|
||||||
|
const placeholders = fields.map(() => '?').join(', ')
|
||||||
|
const updates = fields.map(field => `${field} = ?`).join(', ')
|
||||||
|
const values = fields.map(field => record[field])
|
||||||
|
const duplicateValues = [...values] // 用于ON CONFLICT时的更新
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.db.run(
|
||||||
|
`INSERT INTO ${this.tableName} (${fields.join(', ')})
|
||||||
|
VALUES (${placeholders})
|
||||||
|
ON CONFLICT(id) DO UPDATE SET ${updates}`,
|
||||||
|
[...values, ...duplicateValues],
|
||||||
|
function (err) {
|
||||||
|
if (err) {
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
resolve(id)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除触发器
|
||||||
|
* @param {string} key 触发器ID
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async removeItem (key) {
|
||||||
|
await this.ensureInitialized()
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.db.run(`DELETE FROM ${this.tableName} WHERE id = ?`, [key], (err) => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有触发器
|
||||||
|
* @returns {Promise<import('chaite').TriggerDTO[]>}
|
||||||
|
*/
|
||||||
|
async listItems () {
|
||||||
|
await this.ensureInitialized()
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.db.all(`SELECT * FROM ${this.tableName}`, (err, rows) => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const triggers = rows.map(row => this._recordToTrigger(row)).filter(Boolean)
|
||||||
|
resolve(triggers)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据条件筛选触发器
|
||||||
|
* @param {Record<string, unknown>} filter 筛选条件
|
||||||
|
* @returns {Promise<import('chaite').TriggerDTO[]>}
|
||||||
|
*/
|
||||||
|
async listItemsByEqFilter (filter) {
|
||||||
|
await this.ensureInitialized()
|
||||||
|
|
||||||
|
// 如果没有筛选条件,返回所有
|
||||||
|
if (!filter || Object.keys(filter).length === 0) {
|
||||||
|
return this.listItems()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试使用SQL字段直接过滤
|
||||||
|
const directFields = ['id', 'name', 'description', 'modelType', 'cloudId', 'status', 'permission']
|
||||||
|
const sqlFilters = []
|
||||||
|
const sqlParams = []
|
||||||
|
const extraFilters = {}
|
||||||
|
let hasExtraFilters = false
|
||||||
|
|
||||||
|
// 区分数据库字段和额外字段
|
||||||
|
for (const key in filter) {
|
||||||
|
const value = filter[key]
|
||||||
|
|
||||||
|
// 如果是直接支持的字段,构建SQL条件
|
||||||
|
if (directFields.includes(key)) {
|
||||||
|
sqlFilters.push(`${key} = ?`)
|
||||||
|
sqlParams.push(value)
|
||||||
|
} else if (key === 'embedded') {
|
||||||
|
// embedded 字段需要特殊处理为 0/1
|
||||||
|
sqlFilters.push('embedded = ?')
|
||||||
|
sqlParams.push(value ? 1 : 0)
|
||||||
|
} else if (key === 'isOneTime') {
|
||||||
|
// isOneTime 字段需要特殊处理为 0/1
|
||||||
|
sqlFilters.push('isOneTime = ?')
|
||||||
|
sqlParams.push(value ? 1 : 0)
|
||||||
|
} else {
|
||||||
|
// 其他字段需要在结果中进一步过滤
|
||||||
|
extraFilters[key] = value
|
||||||
|
hasExtraFilters = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建SQL查询
|
||||||
|
let sql = `SELECT * FROM ${this.tableName}`
|
||||||
|
if (sqlFilters.length > 0) {
|
||||||
|
sql += ` WHERE ${sqlFilters.join(' AND ')}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.db.all(sql, sqlParams, (err, rows) => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
let triggers = rows.map(row => this._recordToTrigger(row)).filter(Boolean)
|
||||||
|
|
||||||
|
// 如果有需要在内存中过滤的额外字段
|
||||||
|
if (hasExtraFilters) {
|
||||||
|
triggers = triggers.filter(trigger => {
|
||||||
|
for (const key in extraFilters) {
|
||||||
|
if (trigger[key] !== extraFilters[key]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(triggers)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据IN条件筛选触发器
|
||||||
|
* @param {Array<{ field: string; values: unknown[]; }>} query
|
||||||
|
* @returns {Promise<import('chaite').TriggerDTO[]>}
|
||||||
|
*/
|
||||||
|
async listItemsByInQuery (query) {
|
||||||
|
await this.ensureInitialized()
|
||||||
|
|
||||||
|
// 如果没有查询条<E8AFA2><E69DA1><EFBFBD>,返回所有
|
||||||
|
if (!query || query.length === 0) {
|
||||||
|
return this.listItems()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试使用SQL IN子句来优化查询
|
||||||
|
const directFields = ['id', 'name', 'description', 'modelType', 'cloudId', 'status', 'permission']
|
||||||
|
const sqlFilters = []
|
||||||
|
const sqlParams = []
|
||||||
|
const extraQueries = []
|
||||||
|
|
||||||
|
// 处理每个查询条件
|
||||||
|
for (const { field, values } of query) {
|
||||||
|
if (values.length === 0) continue
|
||||||
|
|
||||||
|
// 如果是直接支持的字段,使用SQL IN子句
|
||||||
|
if (directFields.includes(field)) {
|
||||||
|
const placeholders = values.map(() => '?').join(', ')
|
||||||
|
sqlFilters.push(`${field} IN (${placeholders})`)
|
||||||
|
sqlParams.push(...values)
|
||||||
|
} else if (field === 'embedded') {
|
||||||
|
const boolValues = values.map(v => v ? 1 : 0)
|
||||||
|
const placeholders = boolValues.map(() => '?').join(', ')
|
||||||
|
sqlFilters.push(`embedded IN (${placeholders})`)
|
||||||
|
sqlParams.push(...boolValues)
|
||||||
|
} else if (field === 'isOneTime') {
|
||||||
|
const boolValues = values.map(v => v ? 1 : 0)
|
||||||
|
const placeholders = boolValues.map(() => '?').join(', ')
|
||||||
|
sqlFilters.push(`isOneTime IN (${placeholders})`)
|
||||||
|
sqlParams.push(...boolValues)
|
||||||
|
} else {
|
||||||
|
// 其他字段在内存中过滤
|
||||||
|
extraQueries.push({ field, values })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建SQL查询
|
||||||
|
let sql = `SELECT * FROM ${this.tableName}`
|
||||||
|
if (sqlFilters.length > 0) {
|
||||||
|
sql += ` WHERE ${sqlFilters.join(' AND ')}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.db.all(sql, sqlParams, (err, rows) => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
let triggers = rows.map(row => this._recordToTrigger(row)).filter(Boolean)
|
||||||
|
|
||||||
|
// 如果有需要在内存中过滤的条件
|
||||||
|
if (extraQueries.length > 0) {
|
||||||
|
triggers = triggers.filter(trigger => {
|
||||||
|
for (const { field, values } of extraQueries) {
|
||||||
|
if (!values.includes(trigger[field])) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(triggers)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空表中所有数据
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async clear () {
|
||||||
|
await this.ensureInitialized()
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.db.run(`DELETE FROM ${this.tableName}`, (err) => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭数据库连接
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async close () {
|
||||||
|
if (!this.db) return Promise.resolve()
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.db.close(err => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
} else {
|
||||||
|
this.initialized = false
|
||||||
|
this.db = null
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SQLiteTriggerStorage
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"author": "ikechan8370",
|
"author": "ikechan8370",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chaite": "^1.3.11",
|
"chaite": "^1.4.0",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"keyv": "^5.3.1",
|
"keyv": "^5.3.1",
|
||||||
"keyv-file": "^5.1.2",
|
"keyv-file": "^5.1.2",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { Chaite } from 'chaite'
|
import { Chaite } from 'chaite'
|
||||||
import common from '../../../lib/common/common.js'
|
import common from '../../../lib/common/common.js'
|
||||||
import fetch from 'node-fetch'
|
import fetch from 'node-fetch'
|
||||||
import res from 'express/lib/response.js'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将e中的消息转换为chaite的UserMessage
|
* 将e中的消息转换为chaite的UserMessage
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue