繁体   English   中英

如何在nodejs中订阅rout中的特定主题

[英]how to subscribe to specific topic inside rout in nodejs

我有这个用于物联网设备的过程。

  1. 从移动应用程序接收 HTTP 请求到我的服务器的消息 - 应用程序的用户通过 api 向服务器发送消息以在 iot 设备中打开中继应用程序发送 iot 设备的设备 ID。

  2. 服务器通过 MQTT 将上述步骤中的消息发布到特定主题并等待 5 秒以通过 MQTT 从设备接收到特定主题的动作响应。 如果在 5 秒内收到响应,则服务器向应用程序发送成功响应,然后用户知道操作是否成功,否则发送错误响应到步骤 1 中的原始 HTTP 请求

我没有找到 sulustion 如何做到这一点以及如何订阅特定主题设备将在 nodejs 中的路由内回复

我使用aws-iot核心的mqtt

var awsIot = require("aws-iot-device-sdk");
var http = require("http");
const port = "8082";
var url = require("url");
const express = require("express");
const { json } = require("body-parser");

const app = express();
var cors = require("cors");
const { Console } = require("console");
//const { rejects } = require("assert");
//const { resolve } = require("path/posix");
app.use(cors());
var device = awsIot.device({
  keyPath:
    "AWS/d337405f03a230065b9ngngefafa6b908ca03bed63e34f0d01fbf651ca8c58b75-private.pem.key",
  certPath:
    "AWS/d337405f03a230065b97f9efhhhgsfafa6b908ca03bed63e34f0d01fbf651ca8c58b75-certificate.pem.crt",
  caPath: "AWS/roorCA.pem",
  clientId: "testawsconection1", //esp32-erocam-122021
  host: "a2nl9gsbgfihjibb-ats.iot.eu-west-1.amazonaws.com",
});

async function getReq(topicLisiner) {
  const timeOutPromise = new Promise((reslove, rejects) =>
    setTimeout(() => {
      rejects("error time out");
    }, 10000)
  );

  const promisDevice = new Promise((reslove, rejects) => {
    ///
    device.on("connect", function () {
    
      device.subscribe("esp32/pub");

    });
    ///
    device.on(
      "message",
      function (topic, payload) {
        //device.subscribe(topicLisiner);
        console.log("topic1", topic, payload.toString());
        if (topic) {
          if (topic == topicLisiner) {
            device.unsubscribe(topicLisiner);
            device.on("close", function () {
        
              device.unsubscribe(topicLisiner);
    
            });
            reslove(payload.toString());
          }
        } else {
          rejects("error1");
        }
      },
      (error, result) => {
        if (error) rejects(error);
        else {
          reslove(result);
        }
      }
    );
  });
  return Promise.race([promisDevice, timeOutPromise]);
}

app.get("/test", async (req, res) => {


  device.publish("esp32/eran", JSON.stringify({ "open door": "5" }));

  console.log("----------------");

  try {
    const result = await getReq("esp32/pub");
    console.log(result);
    return res.send(result);
  } catch (error) {}

  return res.send("error time out-");


});

///

简短的回答是您不这样做,除非您非常确定自己在做什么,否则将诸如 HTTP 之类的同步请求/响应协议与异步发布/订阅协议混合通常是一个坏主意。 将 MQTT 发布移动到移动应用程序比尝试在中间添加HTTP会好得多。

更长的答案,这是可能的,但它不能扩展。 您只能拥有一个 HTTP 服务器来完成这项工作,因为它需要跟踪所有正在进行的请求。 它还要求发布的消息包含一个唯一的 ID,并将请求发布到设备,并且设备需要使用此 ID 进行响应。

您订阅了一个匹配所有设备的主题并一次处理它们。 以下是基于 mqtt.js 客户端库的示例,但应该是使用 AWS 库的方法的指南。

var waitingRequests = {}

device.on('message', function(topic, message){
  var msg = JSON.parse(message)
  var waiting = waitingRequests[msg.id]
  if (waiting) ({
    waiting.res.send(msg)
    delete waitingRequests[msg.id]
  }
})

//checks every second for timed out requests
setInterval(function(){
  var now = Date.now()
  var keys = Object.keys(waitingRequests)
  for (var key in keys) {
    var waiting = waitingRequests[keys[key]]
    var diff = now - waiting.timestamp;
    if (diff > 5000) {
      //timed out
      waiting.res.send("error timed out")
      delete waitingRequests[keys[key]]
    }
  }
}, 1000)

app.get("/test", async (req, res) => {
  device.publish("esp32/eran", JSON.stringify({ "open door": "5", "id": "someId" }));
  waitingRequests["someId"] = { res: res, timestamp: Date.now()}

});

在我的真实应用中将有无限的用户和无限的设备

从您的回答中,我不明白nodejs服务器如何同时控制来自diffrunt用户的许多相同的http req并发布和订阅diffrunt设备,因为当他重新运行消息时,ech设备适用于其他http req

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM