UNPKG

mm_os

Version:

MM_OS服务端架构,用于快速构建应用程序,支持网站建设、小程序后台、AI应用、物联网(IOT/AIOT)、游戏服务端等多种场景。

274 lines (248 loc) 7.93 kB
const { Aedes } = require('aedes'); const net = require('net'); const { Adapter } = require('./adapter'); const { Persist } = require('./custom_persistence.js'); /** * MQTT适配器 */ class Mqtt extends Adapter { static config = { host: '127.0.0.1', port: 1883, cache: true, prefix: 'mqtt_', ttl: 3600000, push_topic: 'client/iot/${client_id}', receive_topic: 'client/iot/${client_id}', auth_enabled: false, auth_users: [], // 用户名密码列表,格式: {username: 'user', password: 'pass'} }; /** * 构造函数 * @param {object} config 配置参数 * @param {object} parent 父对象 */ constructor(config, parent) { super({ ...Mqtt.config, ...config }, parent); } } /** * 初始化适配器 * @param {object} cache 缓存管理器 * @returns {object} 适配器实例 * @private */ Mqtt.prototype._init = function (cache) { // 创建自定义持久化实例 let persist = null; if (this.server && cache) { persist = new Persist(this.config, cache); this.log('info', 'MQTT使用自定义持久化'); } // 创建aedes实例,传入自定义持久化 this.broker = new Aedes({ persist: persist }); // 创建TCP服务器 this.web = net.createServer(this.broker.handle); // 配置身份验证 this._setupAuth(); // 监听客户端连接 this.broker.on('client', (client) => { // 存储客户端连接 this.clients.set(client.id, client); // 记录连接日志 this.log('info', `MQTT客户端连接成功: ${client.id}`); }); return this; }; /** * 检查用户是否存在 * @param {string} client_id 客户端ID * @param {string} username 用户名 * @param {string} password 密码 * @returns {Promise<boolean>} 是否存在 */ Mqtt.prototype.checkUser = async function (client_id, username, password) { this.log('debug', '检查用户', { client_id }); let pass = password ? password.toString() : ''; // 查找匹配的用户 // 在实际应用中,这里可以改为异步数据库查询 // 例如: return await db.query('SELECT * FROM users WHERE username = ? AND password = ?', [username, password_str]); return this.config.auth_users.find(u => u.username === username && u.password === pass); }; /** * 验证客户端身份 * @param {object} client 客户端对象 * @param {string} username 用户名 * @param {object} password 密码 * @returns {Promise<boolean>} 是否验证通过 */ Mqtt.prototype.auth = async function (client, username, password) { // 查找匹配的用户 return await this.checkUser(client.id, username, password); }; /** * 配置身份验证 * @private */ Mqtt.prototype._setupAuth = function () { // 如果启用了身份验证 if (this.config.auth_enabled) { // 监听认证事件 this.broker.auth = async (client, username, password, callback) => { try { // 转换密码格式为字符串 let password_str = password ? password.toString() : ''; // 记录认证尝试 this.log('debug', `MQTT认证尝试: clientId=${client.id}, username=${username}, password=${password_str ? '[存在]' : '[不存在]'}`); // 如果提供了自定义验证函数,则使用自定义验证 let user = await this.auth(client, username, password_str); if (user) { this.log('info', `MQTT认证成功: clientId=${client.id}, username=${username}`); return callback(null, true); } else { this.log('warn', `MQTT认证失败: clientId=${client.id}, username=${username}, 用户名或密码错误`); return callback(new Error('用户名或密码错误')); } } catch (error) { this.log('error', `MQTT认证错误: clientId=${client.id}`, error); return callback(new Error('认证服务内部错误')); } }; this.log('info', 'MQTT身份验证已启用'); } }; /** * 启动MQTT服务器 */ Mqtt.prototype.start = function () { let { host, port } = this.config; this.web.listen(port, host, () => { this.log('info', `MQTT启动成功!访问地址:mqtt://${host}:${port}`); if (this.config.auth_enabled) { this.log('info', 'MQTT身份验证已启用'); } }); // 监听服务器错误 this.web.on('error', (error) => { this.log('error', 'MQTT服务器启动失败:', error); }); }; /** * 发送消息 * @private * @param {string} client_id 客户端ID * @param {string} message 消息内容 * @param {object} [options] 发送选项 * @param {number} [options.qos=0] QoS级别(0, 1, 2) * @param {boolean} [options.retain=false] 是否为retain消息 * @returns {boolean} 发送是否成功 */ Mqtt.prototype._send = function (client_id, message, options) { let client = this.clients.get(client_id); if (client) { try { // 默认选项 const OPTS = { qos: 0, retain: false, push_topic: null, ...options || {}}; // MQTT通常需要发布到特定主题,这里简单处理 // 实际应用中可能需要根据协议规范处理 let topic = OPTS.push_topic || this.config.push_topic.replace('${client_id}', client_id); this.broker.publish({ topic: topic, payload: message, qos: OPTS.qos, retain: OPTS.retain }); this.log('debug', `MQTT服务器向 ${client_id} 发送消息: ${message}, qos: ${OPTS.qos}, retain: ${OPTS.retain}`); return true; } catch (error) { this.log('error', 'MQTT发送消息失败:', error); return false; } } else { this.log('warn', `MQTT客户端 ${client_id} 不存在或已关闭`); return false; } }; /** * 发布消息到指定主题 * @param {string} topic 主题 * @param {string} message 消息内容 * @param {object} [options] 发布选项 * @param {number} [options.qos=0] QoS级别(0, 1, 2) * @param {boolean} [options.retain=false] 是否为retain消息 * @returns {boolean} 发布是否成功 */ Mqtt.prototype.publish = function (topic, message, options) { try { // 默认选项 const OPTS = {qos: 0, retain: false, push_topic: null, ...options || {}}; this.broker.publish({ topic: topic, payload: message, qos: OPTS.qos, retain: OPTS.retain }); this.log('debug', `MQTT服务器发布消息到主题 ${topic}: ${message}, qos: ${OPTS.qos}, retain: ${OPTS.retain}`); return true; } catch (error) { this.log('error', 'MQTT发布消息失败:', error); return false; } }; /** * 订阅主题 * @param {string} topic 主题 * @param {Function} callback 回调函数 */ Mqtt.prototype.subscribe = function (topic, callback) { this.broker.subscribe(topic, callback); }; /** * 取消订阅主题 * @param {string} topic 主题 * @param {Function} callback 回调函数 */ Mqtt.prototype.unsubscribe = function (topic, callback) { this.broker.unsubscribe(topic, callback); }; /** * 停止服务器 */ Mqtt.prototype.stop = function () { // 调用父类的_stop方法 this._stop(); // 关闭服务器 this.web.close(() => { // 清空客户端集合 this.clients.clear(); this.log('info', 'MQTT服务器已停止'); }); }; /** * 停止Adapter服务器 * @private */ Mqtt.prototype._stop = function () { // 关闭所有客户端连接 for (let [client_id, client] of this.clients) { try { // 使用MQTT客户端的断开连接方法 if (client && client.close) { client.close(); } } catch (error) { this.log('error', `关闭MQTT客户端 ${client_id} 失败:`, error); } } }; exports.Mqtt = Mqtt;