WebSocket推送改进
All checks were successful
ci/woodpecker/push/check_format Pipeline was successful

This commit is contained in:
zhbaor 2025-03-16 20:21:44 +08:00
parent d7a82eb4fb
commit 27a6ea8dd2
4 changed files with 33 additions and 22 deletions

View file

@ -110,6 +110,8 @@ class Handler(logging.StreamHandler):
msg = f"{record.asctime} {record.levelname} {record.message}" msg = f"{record.asctime} {record.levelname} {record.message}"
if record.exc_info: if record.exc_info:
msg += "\n" + format_exception(record.exc_info) msg += "\n" + format_exception(record.exc_info)
config.log_lines.append(msg)
config.log_lines = config.log_lines[-100:]
config.ws_queue.put({"type": "log", "data": msg}) config.ws_queue.put({"type": "log", "data": msg})
@ -159,13 +161,15 @@ def save_screenshot(img: tp.Image) -> None:
def ws_push(item): def ws_push(item):
if item["type"] == "log": # 先筛选出需要推送的客户端
config.log_lines.append(item["data"]) push_list = []
config.log_lines = config.log_lines[-100:] for ws in config.ws_connections:
elif item["type"] == "screenshot": if ws.push_config.get(item["type"], False):
config.screenshot_notification = item push_list.append(ws)
if not config.ws_connections: if not push_list:
return return
# 对数据进行处理
if item["type"] == "sc": if item["type"] == "sc":
import cv2 import cv2
@ -177,8 +181,10 @@ def ws_push(item):
img = base64.b64encode(img).decode("utf-8") img = base64.b64encode(img).decode("utf-8")
img = f"data:image/jpeg;base64,{img}" img = f"data:image/jpeg;base64,{img}"
item["data"] = img item["data"] = img
# 序列化并推送
data = json.dumps(item) data = json.dumps(item)
for ws in config.ws_connections: for ws in push_list:
ws.send(data) ws.send(data)

View file

@ -88,15 +88,23 @@ profile_name = "mower-ng webui"
@app.route("/ws", websocket=True) @app.route("/ws", websocket=True)
def log(): def log():
ws = Server.accept(request.environ, ping_interval=5) ws = Server.accept(request.environ, ping_interval=5)
ws.push_config = {"log": True}
config.ws_connections.append(ws) config.ws_connections.append(ws)
logger.debug(f"WebSocket客户端建立连接,共{len(config.ws_connections)}条连接") logger.debug(f"WebSocket客户端建立连接,共{len(config.ws_connections)}条连接")
# 即使WebSocket客户端设置log=False和screenshot=False,依然会收到最初的日志和性能排名
# 两种解决方案:
# 1. 以前的数据通过HTTP API获取(比较麻烦)
# 2. 等待客户端发送配置后再发送数据
# 为了兼容helper,暂不进行修改
ws.send(json.dumps({"type": "log", "data": "\n".join(config.log_lines)})) ws.send(json.dumps({"type": "log", "data": "\n".join(config.log_lines)}))
if config.screenshot_notification: if config.screenshot_notification:
ws.send(json.dumps(config.screenshot_notification)) ws.send(json.dumps(config.screenshot_notification))
try: try:
while True: while True:
ws.receive() ws.push_config.update(json.loads(ws.receive()))
except ConnectionClosed: except ConnectionClosed:
config.ws_connections.remove(ws) config.ws_connections.remove(ws)
logger.debug(f"WebSocket客户端断开连接,共{len(config.ws_connections)}条连接") logger.debug(f"WebSocket客户端断开连接,共{len(config.ws_connections)}条连接")

View file

@ -21905,13 +21905,6 @@ const __unplugin_components_7 = /* @__PURE__ */ defineComponent({
})) : null); })) : null);
} }
}); });
function useNotification() {
const api = inject(notificationApiInjectionKey, null);
if (api === null) {
throwError("use-notification", "No outer `n-notification-provider` found.");
}
return api;
}
function self$1(vars) { function self$1(vars) {
const { const {
baseColor, baseColor,
@ -25982,7 +25975,7 @@ const useConfigStore = /* @__PURE__ */ defineStore("config", () => {
const { data } = await axios.get(`${""}/scene`); const { data } = await axios.get(`${""}/scene`);
scene_comment.value = data; scene_comment.value = data;
} }
const conf = ref({ webview: { scale: 1 } }); const conf = ref({});
const int2bool = ["leifeng_mode", "maa_rg_enable", "mail_enable"]; const int2bool = ["leifeng_mode", "maa_rg_enable", "mail_enable"];
const str2list = ["free_blacklist", "reload_room", "maa_mall_buy", "maa_mall_blacklist"]; const str2list = ["free_blacklist", "reload_room", "maa_mall_buy", "maa_mall_blacklist"];
function parse_config(data) { function parse_config(data) {
@ -26046,12 +26039,11 @@ const useConfigStore = /* @__PURE__ */ defineStore("config", () => {
const _sfc_main$1 = { const _sfc_main$1 = {
__name: "WebSocket", __name: "WebSocket",
setup(__props) { setup(__props) {
useNotification();
const mower_store = useMowerStore(); const mower_store = useMowerStore();
const { ws, log_lines, sc_uri, speed_msg, basement_task_list } = storeToRefs(mower_store); const { ws, log_lines, sc_uri, speed_msg, basement_task_list } = storeToRefs(mower_store);
const config_store = useConfigStore(); const config_store = useConfigStore();
const { conf, timestamp, post_conf } = storeToRefs(config_store); const { timestamp, post_conf } = storeToRefs(config_store);
const { parse_config } = config_store; const { load_config } = config_store;
function listen_ws() { function listen_ws() {
let backend_url; let backend_url;
{ {
@ -26059,7 +26051,10 @@ const _sfc_main$1 = {
} }
const ws_url = backend_url.replace(/^http/, "ws") + "/ws"; const ws_url = backend_url.replace(/^http/, "ws") + "/ws";
ws.value = new ReconnectingWebSocket(ws_url); ws.value = new ReconnectingWebSocket(ws_url);
ws.value.onmessage = ({ data }) => { ws.value.onopen = () => {
ws.value.send({ log: True, sc: True, conf: True, screenshot: True });
};
ws.value.onmessage = async ({ data }) => {
data = JSON.parse(data); data = JSON.parse(data);
if (data.type == "log") { if (data.type == "log") {
log_lines.value = log_lines.value.concat(data.data.split("\n")).slice(-100); log_lines.value = log_lines.value.concat(data.data.split("\n")).slice(-100);
@ -26067,13 +26062,12 @@ const _sfc_main$1 = {
if (timestamp.value < data.time) { if (timestamp.value < data.time) {
post_conf.value = false; post_conf.value = false;
timestamp.value = data.time; timestamp.value = data.time;
conf.value = parse_config(data.data); await load_config();
} }
} else if (data.type == "sc") { } else if (data.type == "sc") {
sc_uri.value = data.data; sc_uri.value = data.data;
} else if (data.type == "screenshot") { } else if (data.type == "screenshot") {
speed_msg.value = [data.msg, data.color]; speed_msg.value = [data.msg, data.color];
console.log(speed_msg.value);
} else if (data.type == "task_list") { } else if (data.type == "task_list") {
basement_task_list.value = data.data; basement_task_list.value = data.data;
} }

View file

@ -20,6 +20,9 @@ function listen_ws() {
} }
const ws_url = backend_url.replace(/^http/, 'ws') + '/ws' const ws_url = backend_url.replace(/^http/, 'ws') + '/ws'
ws.value = new ReconnectingWebSocket(ws_url) ws.value = new ReconnectingWebSocket(ws_url)
ws.value.onopen = () => {
ws.value.send({ log: True, sc: True, conf: True, screenshot: True })
}
ws.value.onmessage = async ({ data }) => { ws.value.onmessage = async ({ data }) => {
data = JSON.parse(data) data = JSON.parse(data)
if (data.type == 'log') { if (data.type == 'log') {