Error while Configuring Socket.io on Microsoft Azure: 400 Bad Request

Baibhav M 0 Reputation points
2023-10-07T07:35:13.43+00:00

I'm working on a Node.js application that uses Socket.io for real-time communication and deploying it on Microsoft Azure. However, I'm encountering an error that I can't seem to resolve. Here's my detailed code

Client-side code:

import { io } from "socket.io-client";
const SERVER_URL =
  process.argv[2] || "https://moneyballstore.webpubsub.azure.com";
const SOCKET_PATH = "/clients/socketio/hubs/fast_hub";

const socket = io(SERVER_URL, {
      path: SOCKET_PATH,
      auth: {
        crazygames_auth: token,
      },
    });

app.js:

import express from "express";
import bodyParser from "body-parser";
import "dotenv/config";
import cors from "cors";
import cookieParser from "cookie-parser";
import { createServer } from "http";
import cron from "node-cron";
import { useAzureSocketIO } from "@azure/web-pubsub-socket.io";
import process from "process";
import path from "path";

// Import middleware
import jwtSocketMiddleware from "./middlewares/jwtSocketMiddleware.js";
import { connectDB } from "./db/connect.js";

// Import all routes
import authRoutes from "./routes/authRoutes.js";
import userRoutes from "./routes/userRoutes.js";
import gameRoutes from "./routes/gameRoutes.js";
import adminRoutes from "./routes/adminRoutes.js";
import paymentRoutes from "./routes/paymentRoutes.js";
import {
  handleEventBeforeInitialize,
  handleEventAfterInitialize,
} from "./modules/cornModule.js";

// Import game controllers
import {
  spareParity,
  fastParity,
  easyParity,
} from "./controllers/gameController.js";
import { incrementCountById } from "./modules/dbModule.js";

const app = express();
const server = createServer(app);
const PORT = process.env.PORT || 8000;
const databaseUrl = process.env.DATABASE_URL;
const __dirname = path.dirname(new URL(import.meta.url).pathname);

app.use(
  cors({
    origin: "http://localhost:5173",
    methods: ["GET", "POST"],
    allowedHeaders: [
      "Origin",
      "X-Requested-With",
      "Content-Type",
      "Accept",
      "Authorization",
    ],
    credentials: true,
    optionSuccessStatus: 200,
  })
);

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());

app.use("/api/v1/auth", authRoutes);
app.use("/api/v1/user", userRoutes);
app.use("/api/v1/payment", paymentRoutes);
app.use("/api/v1/admin", adminRoutes);

let ioSpareParty = gameRoutes.setIoSpare(server);
let ioFastParty = gameRoutes.setIoFast(server);
let ioEasyParty = gameRoutes.setIoEasy(server);

// Create an async function to perform the initialization
const initializeSocketIO = async () => {
  try {
    // Initialize ioSpareParty
    await useAzureSocketIO(ioSpareParty, {
      hub: "spare_hub",
      connectionString:
        process.argv[2] || process.env.WebPubSubConnectionString,
    });

    console.log("ioSpareParty initialized successfully.");

    // Initialize ioFastParty
    await useAzureSocketIO(ioFastParty, {
      hub: "fast_hub",
      connectionString:
        process.argv[2] || process.env.WebPubSubConnectionString,
    });

    console.log("ioFastParty initialized successfully.");

    // Initialize ioEasyParty
    await useAzureSocketIO(ioEasyParty, {
      hub: "easy_hub",
      connectionString:
        process.argv[2] || process.env.WebPubSubConnectionString,
    });

    console.log("ioEasyParty initialized successfully.");
  } catch (error) {
    console.error("Initialization error:", error);
  }
};

// Call the initialization function
initializeSocketIO();

ioSpareParty.use(jwtSocketMiddleware);
ioFastParty.use(jwtSocketMiddleware);
ioEasyParty.use(jwtSocketMiddleware);

ioSpareParty.on("connection", spareParity);
ioFastParty.on("connection", fastParity);
ioEasyParty.on("connection", easyParity);

// cron schedule events
// Handle Spare Parity schedule
cron.schedule("*/3 * * * *", async () => {
  try {
    const periodId = "6502c66ff3c8210a9981a723";
    // Execute the event before initializeArraysToZero
    const gameResult = await handleEventBeforeInitialize("spareParity");

    // After the promise is resolved
    handleEventAfterInitialize("spareParity", gameResult, periodId);
    incrementCountById(periodId);
  } catch (error) {
    console.error("Error in cron job:", error);
  }
});

// Handle Fast Parity
cron.schedule("*/30 * * * * *", async () => {
  try {
    const periodId = "6502c686f3c8210a9981a728";
    // Execute the event before initializeArraysToZero
    const gameResult = await handleEventBeforeInitialize("fastParity");

    // After the promise is resolved
    handleEventAfterInitialize("fastParity", gameResult, periodId);
    incrementCountById(periodId);
  } catch (error) {
    console.error("Error:", error);
  }
});

// Handle Easy Parity
cron.schedule("*/30 * * * * *", async () => {
  try {
    const periodId = "6502c6a4f3c8210a9981a72a";
    // Execute the event before initializeArraysToZero
    const gameResult = await handleEventBeforeInitialize("easyParity");
    // After the promise is resolved
    handleEventAfterInitialize("easyParity", gameResult, periodId);
    incrementCountById(periodId);
  } catch (error) {}
});

app.use(express.static("./client/dist"));
app.get("*", (req, res) => {
  res.sendFile(path.resolve(__dirname, "client", "dist", "index.html"));
});

const start = async () => {
  try {
    await connectDB(databaseUrl);
    server.listen(PORT, console.log("Server running at " + PORT));
  } catch (error) {
    console.log(error);
  }
};

start();

jwt middleware code:

import jwt from "jsonwebtoken";

const jwtSocketMiddleware = (socket, next) => {
  const token = socket.handshake.auth.crazygames_auth;

  if (!token) {
    return next(new Error("Access denied. No token provided."));
  }

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);

    socket.decoded = decoded; // Attach user info to the socket object
    next(); // Continue to the next middleware or connection
  } catch (error) {
    return next(new Error("Invalid token."));
  }
};

export default jwtSocketMiddleware;

game routes code:

import { Server } from "socket.io";

let _ioSpareParty;
let _ioFastParty;
let _ioEasyParty;

const origin = "https://moneyballstore.azurewebsites.net/";

const setIoSpare = (server) => {
  _ioSpareParty = new Server(server, {
    path: "/clients/socketio/hubs/spare_hub",
    cors: {
      origin: origin, // Update this to match your client's URL
      methods: ["GET", "POST"],
      allowedHeaders: [
        "Origin",
        "X-Requested-With",
        "Content-Type",
        "Accept",
        "Authorization",
      ],
      credentials: true,
      optionSuccessStatus: 200,
    },
  });

  return _ioSpareParty;
};

const setIoFast = (server) => {
  _ioFastParty = new Server(server, {
    path: "/clients/socketio/hubs/fast_hub",
    cors: {
      origin: origin, // Update this to match your client's URL
      methods: ["GET", "POST"],
      allowedHeaders: [
        "Origin",
        "X-Requested-With",
        "Content-Type",
        "Accept",
        "Authorization",
      ],
      credentials: true,
      optionSuccessStatus: 200,
    },
  });

  return _ioFastParty;
};

const setIoEasy = (server) => {
  _ioEasyParty = new Server(server, {
    path: "/clients/socketio/hubs/easy_hub",
    cors: {
      origin: origin, // Update this to match your client's URL
      methods: ["GET", "POST"],
      allowedHeaders: [
        "Origin",
        "X-Requested-With",
        "Content-Type",
        "Accept",
        "Authorization",
      ],
      credentials: true,
      optionSuccessStatus: 200,
    },
  });

  return _ioEasyParty;
};

const getIOSpare = () => {
  return _ioSpareParty;
};

const getIOFast = () => {
  return _ioFastParty;
};

const getIOEasy = () => {
  try {
    return _ioEasyParty;
  } catch (error) {
    console.log(error);
  }
};

export default {
  setIoSpare,
  setIoFast,
  setIoEasy,
  getIOSpare,
  getIOFast,
  getIOEasy,
};

Azure Web PubSub
Azure Web PubSub
An Azure service that provides real-time messaging for web applications using WebSockets and the publish-subscribe pattern.
60 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Siyuan Xing 0 Reputation points Microsoft Employee
    2023-10-10T08:11:59.22+00:00

    Hi Baibhav, I tried to reproduce your issue. For your code is not a minimal and runnable repro, I modified it to make it complete for execution. Then I found it works well without any issues. Here is what I did:

    1. Remove incomplete or unnecessary code in app.js. Result:
    import express from "express";
    import bodyParser from "body-parser";
    import "dotenv/config";
    import cors from "cors";
    import cookieParser from "cookie-parser";
    import { createServer } from "http";
    import { useAzureSocketIO } from "@azure/web-pubsub-socket.io";
    import process from "process";
    
    // Import middleware
    import jwtSocketMiddleware from "./middlewares/jwtSocketMiddleware.js";
    
    import gameRoutes from "./routes/gameRoutes.js";
    
    
    const app = express();
    const server = createServer(app);
    
    const PORT = process.env.PORT || 8000;
    
    app.use(
      cors({
        origin: "http://localhost:5173",
        methods: ["GET", "POST"],
        allowedHeaders: [
          "Origin",
          "X-Requested-With",
          "Content-Type",
          "Accept",
          "Authorization",
        ],
        credentials: true,
        optionSuccessStatus: 200,
      })
    );
    
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: true }));
    app.use(cookieParser());
    
    let ioFastParty = gameRoutes.setIoFast(server);
    
    // Create an async function to perform the initialization
    const initializeSocketIO = async () => {
      try {
        // Initialize ioFastParty
        await useAzureSocketIO(ioFastParty, {
          hub: "fast_hub",
          connectionString:
            process.argv[2] || process.env.WebPubSubConnectionString,
        });
    
        console.log("ioFastParty initialized successfully.");
    
      } catch (error) {
        console.error("Initialization error:", error);
      }
    };
    
    initializeSocketIO();
    
    ioFastParty.use(jwtSocketMiddleware);
    
    ioFastParty.on("connection", (socket) => {
        console.log("connected!");
    });
    
    const start = async () => {
      try {
        // await connectDB(databaseUrl);
        server.listen(PORT, console.log("Server running at " + PORT));
      } catch (error) {
        console.log(error);
      }
    };
    
    start();
    
    1. Assign token with some value in client.js
    const token='123'
    

    3.Remove JWT verification logic for quick test. Remove 2 lines below in jwtSocketMiddleware.js

    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    socket.decoded = decoded; // Attach user info to the socket object
    

    4.Open two terminal, in the first one, run node app.js. In the second one, run node client.js. And I found everything goes well.

    You could reproduce with steps above. If it works well, the root cause is in removed/hidden codes. You could gradually added them back and locate the accurate root cause.

    And you could also give us a reproduction code which is minimal, complete and runnable. We'd like to help you find out the root cause using this minimal reproduction code.

    0 comments No comments