Initial commit with CC BY-NC-ND 4.0 license

This commit is contained in:
2026-02-13 09:59:19 +08:00
commit 2c31e1cbc8
140 changed files with 44625 additions and 0 deletions

99
SL/bus/Amily2Bus.js Normal file
View File

@@ -0,0 +1,99 @@
import Logger from './log/Logger.js';
import FilePipe from './file/FilePipe.js';
// 【逃生通道】创建一个纯净的 Console 对象,绕过任何潜在的劫持
const getSafeConsole = () => {
try {
if (window._amilySafeConsole) return window._amilySafeConsole;
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
document.body.appendChild(iframe);
const safe = iframe.contentWindow.console;
// document.body.removeChild(iframe); // 保持 iframe 以维持 console 引用有效
window._amilySafeConsole = safe;
return safe;
} catch (e) {
return window.console; // Fallback
}
};
class Amily2Bus {
constructor() {
this.safeConsole = getSafeConsole();
/** @type {Logger|null} */
this.Logger = new Logger();
/** @type {FilePipe|null} */
this.FilePipe = new FilePipe();
// 已注册插件列表,防止重复注册
this.registry = new Set();
this.safeConsole.log('[Amily2Bus] Core container initialized with secure registry.');
}
/**
* 直接记录系统级日志 (Global Scope)
* 支持手动指定来源,方便终端调试或非插件环境调用
* @param {string} type 日志级别 (debug, info, warn, error)
* @param {string} message 消息内容
* @param {string} [origin='Bus'] 来源模块,默认为 'Bus'
* @param {string} [plugin='Global'] 来源插件/命名空间,调试时可指定如 'Console'
*/
log(type, message, origin = 'Bus', plugin = 'Global') {
this.safeConsole.error('[Amily2Bus DEBUG] log called (via SafeConsole):', { type, loggerExists: !!this.Logger });
if (this.Logger) {
this.Logger.process(plugin, origin, type, message);
}
}
/**
* 注册插件并获取专属上下文
* @param {string} pluginName 插件名称
* @returns {Object} 包含该插件专属 API 的上下文对象
*/
register(pluginName) {
if (!pluginName || typeof pluginName !== 'string') {
throw new Error('[Amily2Bus] Invalid plugin name.');
}
if (this.registry.has(pluginName)) {
console.warn(`[Amily2Bus] Plugin '${pluginName}' is already registered.`);
} else {
this.registry.add(pluginName);
console.log(`[Amily2Bus] Plugin registered: ${pluginName}`);
}
// 返回该插件专属的 API 上下文 (Capability Token)
return {
// 绑定了身份的日志接口
log: (origin, type, message) => {
if (this.Logger) {
// 自动填充 plugin 参数
this.Logger.log(pluginName, origin, type, message);
}
},
// 绑定了身份的文件接口
file: {
read: (path) => {
return this.FilePipe ? this.FilePipe.read(pluginName, path) : null;
},
write: (path, data) => {
return this.FilePipe ? this.FilePipe.write(pluginName, path, data) : false;
}
}
};
}
}
// 挂载全局单例 (自动初始化)
if (!window.Amily2Bus || !(window.Amily2Bus instanceof Amily2Bus)) {
window.Amily2Bus = new Amily2Bus();
}
export function initializeAmilyBus() {
if (!window.Amily2Bus || !(window.Amily2Bus instanceof Amily2Bus)) {
window.Amily2Bus = new Amily2Bus();
console.log('[Amily2] Amily2Bus 已成功初始化并附加到 window 对象');
}
}

3
SL/bus/README.md Normal file
View File

@@ -0,0 +1,3 @@
# Amily2Bus
Amily2总线类提供基础的文件操作方法和标准日志操作方法便于开发者使用和规范化日志处理。同时提供了插件注册和事件监听机制。

56
SL/bus/chain/Chain.js Normal file
View File

@@ -0,0 +1,56 @@
/**
* 通用责任链/中间件管理器
* 用于规范操作顺序,支持异步流程控制
*/
export class Chain {
constructor() {
this.middlewares = [];
}
/**
* 注册中间件
* @param {Function} fn (context, next) => Promise<void> | void
*/
use(fn) {
if (typeof fn !== 'function') {
throw new Error('[Chain] Middleware must be a function');
}
this.middlewares.push(fn);
return this;
}
/**
* 执行责任链
* @param {Object} context 传递给中间件的上下文对象
*/
async execute(context = {}) {
let index = -1;
const dispatch = async (i) => {
if (i <= index) {
throw new Error('[Chain] next() called multiple times in one middleware');
}
index = i;
const fn = this.middlewares[i];
if (!fn) return; // 链结束
try {
// 执行中间件,传入 context 和 next 函数
await fn(context, () => dispatch(i + 1));
} catch (err) {
console.error('[Chain] Middleware execution error:', err);
throw err;
}
};
await dispatch(0);
}
/**
* 清空链
*/
clear() {
this.middlewares = [];
}
}

61
SL/bus/file/FilePipe.js Normal file
View File

@@ -0,0 +1,61 @@
class FilePipe {
constructor() {
this.name = "FilePipe";
// 模拟的根存储路径,实际环境可能对应 IndexedDB 的 Store Name 或 Node 的 baseDir
this.basePath = "/virtual_fs/";
}
/**
* 安全路径解析与校验
* @param {string} plugin 插件名称(命名空间)
* @param {string} relativePath 相对路径
* @returns {string|null} 合法的绝对路径,如果违规则返回 null
*/
_resolvePath(plugin, relativePath) {
if (!plugin || typeof plugin !== 'string') {
console.error(`[FilePipe] Security Error: Invalid plugin identity.`);
return null;
}
// 简单防越权:禁止包含 ".."
if (relativePath.includes('..')) {
console.error(`[FilePipe] Security Error: Directory traversal attempt blocked for plugin '${plugin}'. Path: ${relativePath}`);
return null;
}
// 强制限定在插件目录下
// 格式: /virtual_fs/PluginName/filename
return `${this.basePath}${plugin}/${relativePath}`;
}
/**
* 读取文件
* @param {string} plugin 调用方插件名
* @param {string} path 文件相对路径
*/
async read(plugin, path) {
const safePath = this._resolvePath(plugin, path);
if (!safePath) return null;
console.log(`[FilePipe] Reading from: ${safePath}`);
// TODO: Implement actual file reading logic
return null;
}
/**
* 写入文件
* @param {string} plugin 调用方插件名
* @param {string} path 文件相对路径
* @param {any} data 数据
*/
async write(plugin, path, data) {
const safePath = this._resolvePath(plugin, path);
if (!safePath) return false;
console.log(`[FilePipe] Writing to: ${safePath}`);
// TODO: Implement actual file writing logic
return true;
}
}
export default FilePipe;

216
SL/bus/log/Logger.js Normal file
View File

@@ -0,0 +1,216 @@
/**
* 日志总类,用于记录日志信息
* 支持基于位运算的自定义日志级别控制
*/
class Logger {
static LOG_HEADER_DEBUG = '[DEBUG]';
static LOG_HEADER_INFO = '[INFO]';
static LOG_HEADER_WARN = '[WARN]';
static LOG_HEADER_ERROR = '[ERROR]';
static LOG_LEVEL_CODE = {
none: 0x0, // 0
debug: 0x1, // 1
info: 0x2, // 2
warn: 0x4, // 4
error: 0x8, // 8
all: 0xF // 15
};
constructor() {
// 全局默认级别 (默认开启 info, warn, error)
this.globalLevel = Logger.LOG_LEVEL_CODE.info | Logger.LOG_LEVEL_CODE.warn | Logger.LOG_LEVEL_CODE.error;
// 针对特定插件或模块的配置
// 结构示例:
// {
// "PluginA": 3, // PluginA 下所有模块掩码为 3 (debug | info)
// "PluginB::ModuleX": 8 // 仅 PluginB 下的 ModuleX 掩码为 8 (error)
// }
this.levelConfig = {};
}
/**
* 将输入转换为对应的日志级别掩码
* @param {number|string|string[]} levelInput
* @returns {number} 掩码
*/
_parseLevelInput(levelInput) {
if (typeof levelInput === 'number') {
return levelInput;
}
if (typeof levelInput === 'string') {
if (Logger.LOG_LEVEL_CODE.hasOwnProperty(levelInput)) {
return Logger.LOG_LEVEL_CODE[levelInput];
}
// 支持 "debug|info" 这种写法
if (levelInput.includes('|')) {
return levelInput.split('|').reduce((mask, l) => mask | (Logger.LOG_LEVEL_CODE[l.trim()] || 0), 0);
}
console.warn(`[Logger] Unknown log level string: ${levelInput}`);
return 0;
}
if (Array.isArray(levelInput)) {
return levelInput.reduce((mask, l) => mask | (Logger.LOG_LEVEL_CODE[l] || 0), 0);
}
return 0;
}
/**
* 设置日志级别(覆盖模式)
* @param {string} target 目标范围,可以是 'Global'、'PluginName' 或 'PluginName::ModuleName'
* @param {number|string|string[]} level 输入的级别配置
*/
setLevel(target, level) {
const mask = this._parseLevelInput(level);
if (target === 'Global') {
this.globalLevel = mask;
console.log(`[Logger] Global log level mask set to: ${mask.toString(2)}`);
} else {
this.levelConfig[target] = mask;
console.log(`[Logger] Log level mask for '${target}' set to: ${mask.toString(2)}`);
}
}
/**
* 添加日志级别(增量模式)
* @param {string} target
* @param {number|string|string[]} level
*/
addLevel(target, level) {
const maskToAdd = this._parseLevelInput(level);
let currentMask;
if (target === 'Global') {
currentMask = this.globalLevel;
this.globalLevel = currentMask | maskToAdd;
console.log(`[Logger] Added level to Global. New mask: ${this.globalLevel.toString(2)}`);
} else {
currentMask = this.levelConfig[target] !== undefined ? this.levelConfig[target] : this.globalLevel;
this.levelConfig[target] = currentMask | maskToAdd;
console.log(`[Logger] Added level to '${target}'. New mask: ${this.levelConfig[target].toString(2)}`);
}
}
/**
* 移除日志级别(减量模式)
* @param {string} target
* @param {number|string|string[]} level
*/
removeLevel(target, level) {
const maskToRemove = this._parseLevelInput(level);
let currentMask;
if (target === 'Global') {
currentMask = this.globalLevel;
// 使用 & ~mask 实现移除
this.globalLevel = currentMask & ~maskToRemove;
console.log(`[Logger] Removed level from Global. New mask: ${this.globalLevel.toString(2)}`);
} else {
currentMask = this.levelConfig[target] !== undefined ? this.levelConfig[target] : this.globalLevel;
this.levelConfig[target] = currentMask & ~maskToRemove;
console.log(`[Logger] Removed level from '${target}'. New mask: ${this.levelConfig[target].toString(2)}`);
}
}
/**
* 获取指定上下文的生效日志级别掩码(级联查找)
* @param {string} plugin
* @param {string} origin (Module)
*/
_getEffectiveLevelMask(plugin, origin) {
// 1. 检查精确匹配 "Plugin::Module"
const specificKey = `${plugin}::${origin}`;
if (this.levelConfig.hasOwnProperty(specificKey)) {
return this.levelConfig[specificKey];
}
// 2. 检查插件级匹配 "Plugin"
if (this.levelConfig.hasOwnProperty(plugin)) {
return this.levelConfig[plugin];
}
// 3. 返回全局默认
return this.globalLevel;
}
/**
* 标准日志处理方法 (Core Processing)
* 统一处理过滤、格式化和输出,支持默认归属 Global
*/
process(plugin, origin, type, message, inFile = false) {
// [DEBUG] 强制输出以确认方法被调用 (使用 error 级别防止被过滤)
console.error('[Logger DEBUG] Process called:', { plugin, origin, type, message });
// 1. 默认归属处理
const safePlugin = plugin || 'Global';
const safeOrigin = origin || 'System';
// 2. 获取当前上下文生效的日志级别掩码
const effectiveMask = this._getEffectiveLevelMask(safePlugin, safeOrigin);
// 3. 获取当前日志类型的位码
const typeCode = Logger.LOG_LEVEL_CODE[type];
// 4. 级别筛选位与运算结果为0则表示该级别未开启
if (typeCode === undefined || (effectiveMask & typeCode) === 0) {
return;
}
const timestamp = new Date().toLocaleTimeString();
// 格式: [12:00:00] [PluginName::ClassName] [INFO]: message
const fullMessage = `[${timestamp}] [${safePlugin}::${safeOrigin}] [${type.toUpperCase()}]: ${message}`;
// 5. Console Output
switch (type) {
case 'debug':
console.debug(fullMessage);
break;
case 'info':
console.info(fullMessage);
break;
case 'warn':
console.warn(fullMessage);
break;
case 'error':
console.error(fullMessage);
break;
default:
console.log(fullMessage);
break;
}
// 6. File Output (via FilePipe)
if (inFile) {
// Logger 自身也需要作为系统组件注册,获取写入权限
if (!this.sysBus) {
if (window.Amily2Bus && window.Amily2Bus.register) {
this.sysBus = window.Amily2Bus.register('SystemLogger');
}
}
if (this.sysBus && this.sysBus.file) {
// 使用注册后的安全接口写入,无需再手动传 'SystemLogger'
this.sysBus.file.write('runtime.log', fullMessage + '\n');
} else {
// Fallback: 如果总线未就绪,仅在控制台警告一次,避免死循环
if (!this._warned) {
console.warn('[Logger] FilePipe system not linked. Log not saved to file.');
this._warned = true;
}
}
}
}
log(plugin, origin, type, message, inFile = false) {
this.process(plugin, origin, type, message, inFile);
}
}
export default Logger;