0
\$\begingroup\$

I've built this NodeJS server architecture 5 years ago. The project was in production all this time, I've been maintaining it actively, adding a lot of new features, and had no troubles with this architecture. So, now I have a budget to refactor it fundamentally. I'm considering if I should keep this architecture or move to the common REST architecture.

The project consists of a mobile app, web app, admin panel (also a web app), and a NodeJS server.

All 3 client-side parts are using Redux under the hood with socket.io sending actions with SOCKET/ prefix right to the server. The server accepts those actions and responds to them as many times as needed at any time.

I know where to improve the code, so, pls don't waste your time reviewing the code quality.

What I'm looking for is a review of this architecture. What are the downsides? Why I should use stateless REST instead of a stateful socket connection? Maybe it

I guess I'll omit the explanation of what are the pro-s of using this architecture for me, as it's not helpful in this context.

Probably, relevant info about this project:

  • This is enterprise software that will never exceed 2-3 thousand active users.
  • Vast majority of actions do not require real-time capabilities and would work just fine with question-answer model.
  • At the moment we have ~600 active users and still using $24/month GCP instance.

Here is the essence:

import http from 'http'
import express from 'express'
import socketIo from 'socket.io'
import EventEmitter from './EventEmitter'
import actions from './actions'

const socket = async (server) => {
  const io = socketIo(server)
  const connectedUsers = new Map()
  io.use(/*authorization middleware*/)
  io.on('connection', async socket => {
    const eventEmitter = new EventEmitter({ socket })
    console.info(`=== v.${config.version} New connection ===`)

    const sessionData = new Map()
    sessionData.set('role', 'notLogedInUser')
    sessionData.set('clientVersion', socket.authorizationData.clientVersion)

    socket.emit('connected')
    const emitAction = (actionType, actionPayload) => socket.emit('action', {
      type: actionType,
      payload: actionPayload
    })

    if (socket.authorizationData.authorized) {
      const user = await db.users.findById(socket.authorizationData.userId)
      sessionData.set('_id', user._id.toString())
      // ...assigne other important user's props to sessionData
      socket.on('action', async (action = {}) => {
        const { type, payload } = action
        if (!actions[type]) {
          return emitAction('SNACK', 'Invalid action type')
        }
        actions[type]({
          payload,
          emitAction,
          sessionData
        })
      })
    } else {
      emitAction('SNACK', 'Unauthorized')
    }

    socket.on('disconnect', () => {
      console.info(`=== ${socket.id} has disconnected ===`)
      connectedUsers.delete(socket.id)
    })
  })
}

let app = express()

app.server = https.createServer(app)

app.server.listen(config.port, '::', () => {
  socket(app.server, config.port, config.hostname)
})

export default app

Thanks 🙏

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.