Files
mobile_comm/luatos/air780epm/module/Air780EPM/demo/websocket/websocket_sender.lua
T
wangfq 173dd6874f init: Air780EPM 官方 LuatOS 项目代码基线
- 来源: 合宙 LuatOS 官方仓库 air780epm 模块完整代码
- 路径: luatos/air780epm/module/Air780EPM/demo 含官方 demo(含 mqtt/mqtts/socket/uart 等)
- 后续: 基于 demo 开发 UART<->MQTT 数据上报功能
2026-08-31 08:53:49 +08:00

207 lines
8.5 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
--[[
@module websocket_sender
@summary WebSocket client数据发送应用功能模块
@version 1.0
@date 2025.08.25
@author 陈媛媛
@usage
本文件为WebSocket client 数据发送应用功能模块,核心业务逻辑为:
1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)订阅"SEND_DATA_REQ"消息,将其他应用模块需要发送的数据存储到队列send_queue中;
2、websocket sender task接收"CONNECT_OK"、"SEND_REQ"、"SEND_OK"三种类型的"WEBSOCKET_EVENT"消息,遍历队列send_queue,逐条发送数据到server
3、websocket sender task接收"DISCONNECTED"类型的"WEBSOCKET_EVENT"消息,丢弃掉队列send_queue中未发送的数据;
4、任何一条数据无论发送成功还是失败,只要这条数据有回调函数,都会通过回调函数通知数据发送方;
本文件的对外接口有1个:
1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func):订阅"SEND_DATA_REQ"消息;
其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的数据以及回调函数和回调参数一起publish出去;
本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
]]
local websocket_sender = {}
--[[
数据发送队列,数据结构为:
{
[1] = {data="data1", cb={func=callback_function1, para=callback_para1}},
[2] = {data="data2", cb={func=callback_function2, para=callback_para2}},
[3] = {data="data3", cb={func=callback_function3, para=callback_para3}},
}
data的内容为要发送的数据,string类型,必须存在;
cb.func的内容为数据发送结果的用户回调函数,可以不存在;
cb.para的内容为数据发送结果的用户回调函数的回调参数,可以不存在;
]]
local send_queue = {}
-- WebSocket client的任务名前缀
websocket_sender.TASK_NAME_PREFIX = "websocket_"
-- websocket_client_sender的任务名
websocket_sender.TASK_NAME = websocket_sender.TASK_NAME_PREFIX.."sender"
-- "SEND_DATA_REQ"消息的处理函数
local function send_data_req_proc_func(tag, data, cb)
-- 确保data是字符串类型
local data_str = tostring(data)
-- 检查是否是"echo"命令
if data_str == '"echo"' then
log.info("WebSocket发送处理", "收到echo命令,发送数据")
-- 创建JSON格式的echo响应
local response = json.encode({
action = "echo",
msg = os.date("%a %Y-%m-%d %H:%M:%S") -- %a表示星期几缩写
})
-- 将echo响应插入到发送队列send_queue中
table.insert(send_queue, {data=response, cb=cb})
log.info("准备发送数据到服务器,长度", #response)
log.info("原始数据:", response)
else
-- 根据tag类型输出日志
if tag == "timer" then
-- 对于timer数据,修改日志为"发送心跳"
log.info("发送心跳", "长度", #data_str)
log.info("原始数据:", data_str)
table.insert(send_queue, {data=data_str, cb=cb})
else
-- 其他数据(如uart
log.info("准备发送数据到服务器,长度", #data_str)
log.info("原始数据:", data_str)
log.info("UART发送到服务器的数据包类型", type(data_str))
log.info("转发普通数据")
table.insert(send_queue, {data=data_str, cb=cb})
end
end
-- 发送消息通知 websocket sender task,有新数据等待发送
sys.sendMsg(websocket_sender.TASK_NAME, "WEBSOCKET_EVENT", "SEND_REQ")
end
-- 按照顺序发送send_queue中的数据
-- 如果调用send接口成功,则返回当前正在发送的数据项
-- 如果调用send接口失败,通知回调函数发送失败后,继续发送下一条数据
local function send_item(ws_client)
local item
-- 如果发送队列中有数据等待发送
while #send_queue > 0 do
-- 取出来第一条数据赋值给item
-- 同时从队列send_queue中删除这一条数据
item = table.remove(send_queue, 1)
-- 检查WebSocket连接状态
if not ws_client or not ws_client:ready() then
log.warn("WebSocket发送处理", "WebSocket连接未就绪,无法发送")
-- 如果当前发送的数据有用户回调函数,则执行用户回调函数
if item.cb and item.cb.func then
item.cb.func(false, item.cb.para)
end
-- 触发重连
sys.sendMsg(websocket_sender.TASK_NAME, "WEBSOCKET_EVENT", "DISCONNECTED")
return nil
end
-- send数据
-- result表示调用send接口的同步结果,返回值有以下几种:
-- 如果失败,返回false
-- 如果成功,返回true
result = ws_client:send(item.data)
-- send接口调用成功
if result then
-- 根据数据内容修改日志输出
if item.data:match("^%d+$") then -- 如果数据是纯数字(来自timer)
log.info("wbs_sender", "发送心跳成功", "长度", #item.data)
else
log.info("wbs_sender", "发送成功", "长度", #item.data)
end
if item.cb and item.cb.func then
item.cb.func(true, item.cb.para)
end
-- 发送成功,通知网络环境检测看门狗功能模块进行喂狗
-- 使用来自定时器的数据作为心跳
if item.data:match("^%d+$") then -- 如果数据是纯数字(来自timer)
sys.publish("FEED_NETWORK_WATCHDOG")
end
return item
-- send接口调用失败
else
log.warn("WebSocket发送处理", "数据发送失败")
-- 如果当前发送的数据有用户回调函数,则执行用户回调函数
if item.cb and item.cb.func then
item.cb.func(false, item.cb.para)
end
-- 触发重连
sys.sendMsg(websocket_sender.TASK_NAME, "WEBSOCKET_EVENT", "DISCONNECTED")
return nil
end
end
return nil
end
-- websocket client sender的任务处理函数
local function websocket_client_sender_task_func()
local ws_client
local send_item_obj
local result, msg
while true do
-- 等待"WEBSOCKET_EVENT"消息
msg = sys.waitMsg(websocket_sender.TASK_NAME, "WEBSOCKET_EVENT")
log.info("WebSocket发送任务等待消息", msg[2], msg[3])
-- WebSocket连接成功
-- msg[3]表示WebSocket client对象
if msg[2] == "CONNECT_OK" then
ws_client = msg[3]
log.info("WebSocket发送任务", "WebSocket连接成功")
-- 发送send_queue中的所有数据
while #send_queue > 0 do
send_item_obj = send_item(ws_client)
if not send_item_obj then
break
end
end
-- WebSocket send数据请求
elseif msg[2] == "SEND_REQ" then
log.info("WebSocket发送任务", "收到发送请求")
-- 如果WebSocket client对象存在
if ws_client then
send_item_obj = send_item(ws_client)
end
-- WebSocket send数据成功
elseif msg[2] == "SEND_OK" then
log.info("WebSocket发送任务", "数据发送成功")
-- 继续发送send_queue中的数据
send_item_obj = send_item(ws_client)
-- WebSocket断开连接
elseif msg[2] == "DISCONNECTED" then
log.info("WebSocket发送任务", "WebSocket连接断开")
-- 清空WebSocket client对象
ws_client = nil
-- 如果发送队列中有数据等待发送
while #send_queue > 0 do
-- 取出来第一条数据赋值给send_item_obj
-- 同时从队列send_queue中删除这一条数据
send_item_obj = table.remove(send_queue, 1)
-- 如果当前发送的数据有用户回调函数,则执行用户回调函数
if send_item_obj.cb and send_item_obj.cb.func then
send_item_obj.cb.func(false, send_item_obj.cb.para)
end
end
-- 当前没有正在等待发送结果的发送项
send_item_obj = nil
end
end
end
-- 订阅"SEND_DATA_REQ"消息;
sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)
--创建并且启动一个task
sys.taskInitEx(websocket_client_sender_task_func, websocket_sender.TASK_NAME)
return websocket_sender