commit 676ed9753833bc86e51feb204c87c1841ef82ee7 Author: “Naeel” Date: Wed Jul 22 08:26:03 2026 +0400 feat: Node.js consumer amqplib diff --git a/package.json b/package.json new file mode 100644 index 0000000..7366070 --- /dev/null +++ b/package.json @@ -0,0 +1,7 @@ +{ + "name": "iot-consumer", + "version": "1.0.0", + "main": "server.js", + "scripts": { "start": "node server.js" }, + "dependencies": { "amqplib": "^0.10.0", "express": "^4.21.0", "redis": "^4.7.0", "mongodb": "^6.0.0" } +} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..9cc1ecd --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +Flask>=3.0 +gunicorn>=21.2 +redis>=5.0 +pymongo>=4.0 diff --git a/server.js b/server.js new file mode 100644 index 0000000..866c506 --- /dev/null +++ b/server.js @@ -0,0 +1,84 @@ +const amqp = require("amqplib"); +const express = require("express"); +const { createClient } = require("redis"); +const { MongoClient } = require("mongodb"); + +const RMQ_HOST = process.env.RMQ_HOST || "localhost"; +const RMQ_PORT = parseInt(process.env.RMQ_PORT || "5672"); +const RMQ_USER = process.env.RMQ_USER || "guest"; +const RMQ_PASS = process.env.RMQ_PASS || "guest"; +const RMQ_QUEUE = process.env.RMQ_QUEUE || "iot-events"; + +const REDIS_HOST = process.env.REDIS_HOST || "localhost"; +const REDIS_PORT = parseInt(process.env.REDIS_PORT || "6379"); +const REDIS_PASS = process.env.REDIS_PASS || undefined; + +const MONGO_URI = process.env.MONGO_URI || "mongodb://localhost:27017/iot"; +const MONGO_DB = process.env.MONGO_DB || "iot"; + +let consumed = 0, errors = 0; +let redis, mongo, mongoColl; + +async function getRedis() { + if (!redis) { + redis = createClient({ socket: { host: REDIS_HOST, port: REDIS_PORT }, password: REDIS_PASS }); + redis.on("error", () => {}); + await redis.connect(); + console.log("Redis connected"); + } + return redis; +} + +async function getMongo() { + if (!mongo) { + mongo = new MongoClient(MONGO_URI); + await mongo.connect(); + mongoColl = mongo.db(MONGO_DB).collection("iot_events"); + await mongoColl.createIndex({ timestamp: 1 }, { expireAfterSeconds: 604800 }); + console.log("MongoDB connected"); + } + return mongoColl; +} + +async function store(event) { + const r = await getRedis(); + await r.hSet("iot:latest", event.sensor_id, JSON.stringify({ + value: event.value, unit: event.unit, location: event.location, timestamp: event.timestamp, + })); + await r.hIncrBy("iot:counters", event.device_type, 1); + await r.zAdd("iot:recent", [{ score: 0, value: JSON.stringify(event) }]); + await r.zRemRangeByRank("iot:recent", 0, -1001); + const coll = await getMongo(); + await coll.insertOne({ + event_id: event.event_id, sensor_id: event.sensor_id, + device_type: event.device_type, location: event.location, + value: event.value, unit: event.unit, timestamp: new Date(event.timestamp), + }); +} + +async function start() { + const conn = await amqp.connect(`amqp://${RMQ_USER}:${RMQ_PASS}@${RMQ_HOST}:${RMQ_PORT}`); + const ch = await conn.createChannel(); + await ch.assertQueue(RMQ_QUEUE, { durable: true }); + ch.prefetch(10); + await ch.consume(RMQ_QUEUE, async (msg) => { + try { + if (msg) { + const event = JSON.parse(msg.content.toString()); + await store(event); + consumed++; + ch.ack(msg); + if (consumed % 10 === 0) console.log(`Consumed ${consumed} events`); + } + } catch (e) { + errors++; + console.error("Error:", e.message); + } + }); + console.log(`Consumer listening on queue: ${RMQ_QUEUE}`); +} + +const app = express(); +app.get("/", (req, res) => res.json({ service: "iot-consumer", status: "running", queue: RMQ_QUEUE, consumed, errors })); +app.get("/health", (req, res) => res.json({ status: "ok" })); +app.listen(process.env.PORT || 3000, () => { console.log("Consumer started"); start(); });