1

I'm learning socket.io and typescript. I'm currently building an app where I want to emit event on databases changes to the client.For the backend, I'm using Express, typescript and nodeJS

I've looked on a lot of posts but I don't understand how I can access my io instance to be able to emit my event from my controller functions. Also most examples are on javascript which is more confusing.

Currently in my app.ts I have the following configuration. How can I move my addOnlineHandler, logOutHandler and sendNotificationHandler in my controller functions to be able to emit event on database change directly from createOrder function of the controller ?

I've tried importing all orderHandler function in the controller but it's not working. I'm unable to access the io instance to emit events.

app.ts

import  express  from "express";
import dotenv from "dotenv";
import userRoute from './routes/user'
import mongoose from "mongoose";
import { createServer } from "http";
import { Server,Socket } from "socket.io";
import {addOnlineShopHandler,logOutHandler, sendNotificationHandler} from "./socket/orderHandler";


dotenv.config();
const app = express();

const httpServer = createServer(app);

const io = new Server(httpServer, {
    cors:{
        origin:"*"
    }
});

const onConnection = (socket:Socket) => {
    addOnlineShopHandler(socket)
    logOutHandler(socket)
    sendNotificationHandler(socket)
    
  }

io.on("connection",onConnection)


httpServer.listen(process.env.PORT, () => {
    console.log('Backend server is running')
});

const connectToDatabase = async (dbConnectionString:string) => {
    await mongoose.connect(dbConnectionString)
    console.log('Connection to DB sucess')
}

connectToDatabase(`${process.env.MONGO_URI}`).catch(err => console.log(err))

app.use('/api/users',userRoute)

My controller file where I need to be able to emit event when order is created.

orderController.ts

import { RequestHandler } from "express";


export const createOrder:RequestHandler = async (req, res) => {
    // I want to use socket.io in this function 
    // emit event when order created 


}

My orderHandler file.

orderHandler.ts

import { Server,Socket } from "socket.io";

interface IOnlineShop {
    shopId:string, 
    socketId:string
}

let onlineShop:IOnlineShop[] = []

export const addOnlineShopHandler = (socket:Socket) => {
    console.log('someone is in')
    
    const addNewShop = (shopId:string, socketId:string) => {
        !onlineShop.some((currentShop) => currentShop.shopId === shopId) && onlineShop.push({shopId,socketId})
    }
    const newShopConnected = (shopId:string) => {
        addNewShop(shopId,socket.id)
    }

    socket.on('newShopConnected',newShopConnected)

}

export const logOutHandler = (socket:Socket) => {

    const removeShop = (socketId:string) => {
        onlineShop = onlineShop.filter((currentShop)=>{currentShop.socketId !== socketId})
        console.log('someone is out')
    }
    socket.on('disconnect',removeShop)
    
}


export const sendNotificationHandler = (socket:Socket) =>{
    const getUser = (shopId:string) =>{
        return onlineShop.find((currentShop) => currentShop.shopId === shopId)}
    const sendNotification = (data:any) =>{
        const receiver = getUser('randomshopId')
        console.log(receiver)
    }

    socket.on("sendNotif",sendNotification)
}


I've looked theses posts and still can't get around the solution, maybe using typescript is what is confusing me. Any help or explanation of the workflow would be appreciated. how to use socket.io in controller file Use socket.io in controllers Socket.IO + Express framework | Emit/Fire From Express Controller & Router

Thank you,

Abbab
  • 45
  • 6

1 Answers1

2

You can attach io to the app object:

app.set('io', io);

You can then access it from within controllers with req.app.get('io')

ben-natan
  • 141
  • 1
  • 4
  • Thank you for the answer it seems to be working for emitting! But I can't take event from the client inside the controller. Do you happen to now why io.sockets.on is not getting data from client ? – Abbab Jan 24 '22 at 04:30
  • To set a listener inside a controller (which I do not know if it is good practice or not) you need to attach the `socket` object to the app inside your `onConnection` function. Then you can access this socket object inside the controller and set a listener on it. – ben-natan Jan 24 '22 at 23:06
  • However I think you should never do this as it adds a listener every time the controller gets called. Maybe socketio rooms can help you. – ben-natan Jan 24 '22 at 23:25