mirror of
https://github.com/MarSeventh/CloudFlare-ImgBed.git
synced 2026-01-31 09:03:19 +08:00
408 lines
11 KiB
JavaScript
408 lines
11 KiB
JavaScript
/**
|
||
* D1 数据库操作工具类
|
||
* 用于替代原有的KV存储操作
|
||
*/
|
||
|
||
class D1Database {
|
||
constructor(db) {
|
||
this.db = db;
|
||
}
|
||
}
|
||
|
||
// ==================== 文件操作 ====================
|
||
|
||
/**
|
||
* 保存文件记录 (替代 KV.put)
|
||
*/
|
||
D1Database.prototype.putFile = function(fileId, value, options) {
|
||
value = value || '';
|
||
options = options || {};
|
||
var metadata = options.metadata || {};
|
||
|
||
// 从metadata中提取字段用于索引
|
||
var extractedFields = this.extractMetadataFields(metadata);
|
||
|
||
var stmt = this.db.prepare(
|
||
'INSERT OR REPLACE INTO files (' +
|
||
'id, value, metadata, file_name, file_type, file_size, ' +
|
||
'upload_ip, upload_address, list_type, timestamp, ' +
|
||
'label, directory, channel, channel_name, ' +
|
||
'tg_file_id, tg_chat_id, tg_bot_token, is_chunked' +
|
||
') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
|
||
);
|
||
|
||
return stmt.bind(
|
||
fileId,
|
||
value,
|
||
JSON.stringify(metadata),
|
||
extractedFields.fileName,
|
||
extractedFields.fileType,
|
||
extractedFields.fileSize,
|
||
extractedFields.uploadIP,
|
||
extractedFields.uploadAddress,
|
||
extractedFields.listType,
|
||
extractedFields.timestamp,
|
||
extractedFields.label,
|
||
extractedFields.directory,
|
||
extractedFields.channel,
|
||
extractedFields.channelName,
|
||
extractedFields.tgFileId,
|
||
extractedFields.tgChatId,
|
||
extractedFields.tgBotToken,
|
||
extractedFields.isChunked
|
||
).run();
|
||
};
|
||
|
||
/**
|
||
* 获取文件记录 (替代 KV.get)
|
||
*/
|
||
D1Database.prototype.getFile = function(fileId) {
|
||
var self = this;
|
||
var stmt = this.db.prepare('SELECT * FROM files WHERE id = ?');
|
||
return stmt.bind(fileId).first().then(function(result) {
|
||
if (!result) return null;
|
||
|
||
return {
|
||
value: result.value,
|
||
metadata: JSON.parse(result.metadata || '{}')
|
||
};
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 获取文件记录包含元数据 (替代 KV.getWithMetadata)
|
||
*/
|
||
D1Database.prototype.getFileWithMetadata = function(fileId) {
|
||
return this.getFile(fileId);
|
||
};
|
||
|
||
/**
|
||
* 删除文件记录 (替代 KV.delete)
|
||
*/
|
||
D1Database.prototype.deleteFile = function(fileId) {
|
||
var stmt = this.db.prepare('DELETE FROM files WHERE id = ?');
|
||
return stmt.bind(fileId).run();
|
||
};
|
||
|
||
/**
|
||
* 列出文件 (替代 KV.list)
|
||
*/
|
||
D1Database.prototype.listFiles = function(options) {
|
||
options = options || {};
|
||
var prefix = options.prefix || '';
|
||
var limit = options.limit || 1000;
|
||
var cursor = options.cursor || null;
|
||
|
||
var query = 'SELECT id, metadata FROM files';
|
||
var params = [];
|
||
|
||
if (prefix) {
|
||
query += ' WHERE id LIKE ?';
|
||
params.push(prefix + '%');
|
||
}
|
||
|
||
if (cursor) {
|
||
query += prefix ? ' AND' : ' WHERE';
|
||
query += ' id > ?';
|
||
params.push(cursor);
|
||
}
|
||
|
||
query += ' ORDER BY id LIMIT ?';
|
||
params.push(limit + 1);
|
||
|
||
var stmt = this.db.prepare(query);
|
||
if (params.length > 0) {
|
||
stmt = stmt.bind.apply(stmt, params);
|
||
}
|
||
return stmt.all().then(function(response) {
|
||
var results = response.results || [];
|
||
var hasMore = results.length > limit;
|
||
if (hasMore) {
|
||
results.pop();
|
||
}
|
||
|
||
var keys = results.map(function(row) {
|
||
return {
|
||
name: row.id,
|
||
metadata: JSON.parse(row.metadata || '{}')
|
||
};
|
||
});
|
||
|
||
return {
|
||
keys: keys,
|
||
cursor: hasMore && keys.length > 0 ? keys[keys.length - 1].name : null,
|
||
list_complete: !hasMore
|
||
};
|
||
});
|
||
};
|
||
|
||
// ==================== 设置操作 ====================
|
||
|
||
/**
|
||
* 保存设置 (替代 KV.put)
|
||
*/
|
||
D1Database.prototype.putSetting = function(key, value, category) {
|
||
if (!category && key.startsWith('manage@sysConfig@')) {
|
||
category = key.split('@')[2];
|
||
}
|
||
|
||
var stmt = this.db.prepare(
|
||
'INSERT OR REPLACE INTO settings (key, value, category) VALUES (?, ?, ?)'
|
||
);
|
||
|
||
return stmt.bind(key, value, category).run();
|
||
};
|
||
|
||
/**
|
||
* 获取设置 (替代 KV.get)
|
||
*/
|
||
D1Database.prototype.getSetting = function(key) {
|
||
var stmt = this.db.prepare('SELECT value FROM settings WHERE key = ?');
|
||
return stmt.bind(key).first().then(function(result) {
|
||
return result ? result.value : null;
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 删除设置 (替代 KV.delete)
|
||
*/
|
||
D1Database.prototype.deleteSetting = function(key) {
|
||
var stmt = this.db.prepare('DELETE FROM settings WHERE key = ?');
|
||
return stmt.bind(key).run();
|
||
};
|
||
|
||
/**
|
||
* 列出设置 (替代 KV.list)
|
||
*/
|
||
D1Database.prototype.listSettings = function(options) {
|
||
options = options || {};
|
||
var prefix = options.prefix || '';
|
||
var limit = options.limit || 1000;
|
||
|
||
var query = 'SELECT key, value FROM settings';
|
||
var params = [];
|
||
|
||
if (prefix) {
|
||
query += ' WHERE key LIKE ?';
|
||
params.push(prefix + '%');
|
||
}
|
||
|
||
query += ' ORDER BY key LIMIT ?';
|
||
params.push(limit);
|
||
|
||
var stmt = this.db.prepare(query);
|
||
if (params.length > 0) {
|
||
stmt = stmt.bind.apply(stmt, params);
|
||
}
|
||
return stmt.all().then(function(response) {
|
||
var results = response.results || [];
|
||
var keys = results.map(function(row) {
|
||
return {
|
||
name: row.key,
|
||
value: row.value
|
||
};
|
||
});
|
||
|
||
return { keys: keys };
|
||
});
|
||
};
|
||
|
||
// ==================== 索引操作 ====================
|
||
|
||
/**
|
||
* 保存索引操作记录
|
||
*/
|
||
D1Database.prototype.putIndexOperation = function(operationId, operation) {
|
||
var stmt = this.db.prepare(
|
||
'INSERT OR REPLACE INTO index_operations (id, type, timestamp, data) VALUES (?, ?, ?, ?)'
|
||
);
|
||
|
||
return stmt.bind(
|
||
operationId,
|
||
operation.type,
|
||
operation.timestamp,
|
||
JSON.stringify(operation.data)
|
||
).run();
|
||
};
|
||
|
||
/**
|
||
* 获取索引操作记录
|
||
*/
|
||
D1Database.prototype.getIndexOperation = function(operationId) {
|
||
var stmt = this.db.prepare('SELECT * FROM index_operations WHERE id = ?');
|
||
return stmt.bind(operationId).first().then(function(result) {
|
||
if (!result) return null;
|
||
|
||
return {
|
||
type: result.type,
|
||
timestamp: result.timestamp,
|
||
data: JSON.parse(result.data)
|
||
};
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 删除索引操作记录
|
||
*/
|
||
D1Database.prototype.deleteIndexOperation = function(operationId) {
|
||
var stmt = this.db.prepare('DELETE FROM index_operations WHERE id = ?');
|
||
return stmt.bind(operationId).run();
|
||
};
|
||
|
||
/**
|
||
* 列出索引操作记录
|
||
*/
|
||
D1Database.prototype.listIndexOperations = function(options) {
|
||
options = options || {};
|
||
var limit = options.limit || 1000;
|
||
var processed = options.processed;
|
||
|
||
var query = 'SELECT * FROM index_operations';
|
||
var params = [];
|
||
|
||
if (processed !== null && processed !== undefined) {
|
||
query += ' WHERE processed = ?';
|
||
params.push(processed);
|
||
}
|
||
|
||
query += ' ORDER BY timestamp LIMIT ?';
|
||
params.push(limit);
|
||
|
||
var stmt = this.db.prepare(query);
|
||
if (params.length > 0) {
|
||
stmt = stmt.bind.apply(stmt, params);
|
||
}
|
||
return stmt.all().then(function(response) {
|
||
var results = response.results || [];
|
||
return results.map(function(row) {
|
||
return {
|
||
id: row.id,
|
||
type: row.type,
|
||
timestamp: row.timestamp,
|
||
data: JSON.parse(row.data),
|
||
processed: row.processed
|
||
};
|
||
});
|
||
});
|
||
};
|
||
|
||
// ==================== 工具方法 ====================
|
||
|
||
/**
|
||
* 从metadata中提取字段用于索引
|
||
*/
|
||
D1Database.prototype.extractMetadataFields = function(metadata) {
|
||
return {
|
||
fileName: metadata.FileName || null,
|
||
fileType: metadata.FileType || null,
|
||
fileSize: metadata.FileSize || null,
|
||
uploadIP: metadata.UploadIP || null,
|
||
uploadAddress: metadata.UploadAddress || null,
|
||
listType: metadata.ListType || null,
|
||
timestamp: metadata.TimeStamp || null,
|
||
label: metadata.Label || null,
|
||
directory: metadata.Directory || null,
|
||
channel: metadata.Channel || null,
|
||
channelName: metadata.ChannelName || null,
|
||
tgFileId: metadata.TgFileId || null,
|
||
tgChatId: metadata.TgChatId || null,
|
||
tgBotToken: metadata.TgBotToken || null,
|
||
isChunked: metadata.IsChunked || false
|
||
};
|
||
};
|
||
|
||
// ==================== 通用方法 ====================
|
||
|
||
/**
|
||
* 通用的put方法,根据key类型自动选择存储位置
|
||
*/
|
||
D1Database.prototype.put = function(key, value, options) {
|
||
options = options || {};
|
||
|
||
if (key.startsWith('manage@sysConfig@') || key.startsWith('manage@')) {
|
||
return this.putSetting(key, value);
|
||
} else if (key.startsWith('manage@index@operation_')) {
|
||
var operationId = key.replace('manage@index@operation_', '');
|
||
var operation = JSON.parse(value);
|
||
return this.putIndexOperation(operationId, operation);
|
||
} else {
|
||
return this.putFile(key, value, options);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 通用的get方法,根据key类型自动选择获取位置
|
||
*/
|
||
D1Database.prototype.get = function(key) {
|
||
var self = this;
|
||
|
||
if (key.startsWith('manage@sysConfig@') || key.startsWith('manage@')) {
|
||
return this.getSetting(key);
|
||
} else if (key.startsWith('manage@index@operation_')) {
|
||
var operationId = key.replace('manage@index@operation_', '');
|
||
return this.getIndexOperation(operationId).then(function(operation) {
|
||
return operation ? JSON.stringify(operation) : null;
|
||
});
|
||
} else {
|
||
return this.getFile(key).then(function(file) {
|
||
return file ? file.value : null;
|
||
});
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 通用的getWithMetadata方法
|
||
*/
|
||
D1Database.prototype.getWithMetadata = function(key) {
|
||
var self = this;
|
||
|
||
if (key.startsWith('manage@sysConfig@') || key.startsWith('manage@')) {
|
||
return this.getSetting(key).then(function(value) {
|
||
return value ? { value: value, metadata: {} } : null;
|
||
});
|
||
} else {
|
||
return this.getFileWithMetadata(key);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 通用的delete方法
|
||
*/
|
||
D1Database.prototype.delete = function(key) {
|
||
if (key.startsWith('manage@sysConfig@') || key.startsWith('manage@')) {
|
||
return this.deleteSetting(key);
|
||
} else if (key.startsWith('manage@index@operation_')) {
|
||
var operationId = key.replace('manage@index@operation_', '');
|
||
return this.deleteIndexOperation(operationId);
|
||
} else {
|
||
return this.deleteFile(key);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 通用的list方法
|
||
*/
|
||
D1Database.prototype.list = function(options) {
|
||
options = options || {};
|
||
var prefix = options.prefix || '';
|
||
var self = this;
|
||
|
||
if (prefix.startsWith('manage@sysConfig@') || prefix.startsWith('manage@')) {
|
||
return this.listSettings(options);
|
||
} else if (prefix.startsWith('manage@index@operation_')) {
|
||
return this.listIndexOperations(options).then(function(operations) {
|
||
var keys = operations.map(function(op) {
|
||
return {
|
||
name: 'manage@index@operation_' + op.id
|
||
};
|
||
});
|
||
return { keys: keys };
|
||
});
|
||
} else {
|
||
return this.listFiles(options);
|
||
}
|
||
};
|
||
|
||
// 导出构造函数
|
||
export { D1Database };
|