mm_os
Version:
MM_OS服务端架构,用于快速构建应用程序,支持网站建设、小程序后台、AI应用、物联网(IOT/AIOT)、游戏服务端等多种场景。
274 lines (248 loc) • 7.93 kB
JavaScript
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;