ioserver

Damn simple way to setup your Socket.io server using coffeescript or vanilla JS class.

Usage no npm install needed!

<script type="module">
  import ioserver from 'https://cdn.skypack.dev/ioserver';
</script>

README

IOServer

NPM

Downloads per month npm version Build Status Known Vulnerabilities

Damn simple way to setup your Socket.io server using coffeescript or vanilla JS.

This will launch a server on hots:port specified (default: localhost:8080) and will register all method of the class set as service, except ones starting by '_' (underscore). The web server is based on Fastify so you can even add REST routes and interact with your socket.io rooms and namespaces.

The socket.io's registrated methods will then be accessible as standard client-side socket.io event:

  socket.emit 'method_name', data

Install

Install with npm:

  npm install ioserver

Basic Usage

Require the module:

  IOServer = require 'ioserver'

  app = new IOServer
        verbose: true

Add manager using:

  app.addManager
    name:      'manager_name'
    manager:   ManagerClass

Add services using:

  app.addService
    name:      'service_name'
    service:   ServiceClass

Add watchers using:

  app.addWatcher
    name:      'watcher_name'
    watcher:   WatcherClass

Add controller using:

  app.addController
    name:      'controller_name'
    controller:   ControllerClass

Start the server...

  app.start()

Extended usage

You can add services with Middlewares:

  app.addService
    name:      'service_name'
    service:   ServiceClass
    middlewares: [
      AccessMiddleware
    ]

Middlewares are invoked at the socket connection to namespaces, they are usually used for restricting access, validate connection method and parameters.

You can send event from external process

  app.sendTo
    event:   'event name'
    data:     data

to specific namespace ...

  app.sendTo
    namespace: '/namespace'
    event:     'event name'
    data:      data

... or specific room

  app.sendTo
    namespace: '/namespace'
    room:      'room_name'
    event:     'event name'
    data:      data

and even specific socket.id

  app.sendTo
    namespace: '/namespace'
    sid:       socket.id
    event:     'event name'
    data:      data

You can add controller with Middlewares and routes prefix:

  app.addController
    name:      'controller_name'
    prefix: '/my_prefix/'
    controller:   ControllerClass
    middlewares: [
      RESTMiddleware
    ]

You cann add watchers class that will be launched at start using watch() method

  app.addWatcher
    name:      'watcher_name'
    watcher:   WatcherClass

In order to meet the fastify requirements, some pre-requised are needed to setup REST endpoints.

  1. First your JS class will define your accessible controller's methods
module.exports = class HelloController
  constructor: (@app) ->

  _isAuthentified: (req, reply, next) ->
    if not req.headers['x-authentication']?
      return reply.forbidden()
    
    next()
  
  world: (req, reply) ->
    return { message: "Hello world" }
  
  display: (req, reply) ->
    return { message: "Hello #{req.params.message}" }
  
  restricted: (req, reply) ->
    return { message: "Welcome on Private Area" }
  1. Then setup a routes description file (by default it will be looked-up into a routes/${controller_name}.json directory at root level of your project). You can use different location by specifying routes options on IOServer instanciation (see unit-tests for examples).
[
  {
    "method": "GET",
    "url": "/",
    "handler": "world"
  },
  {
    "method": "GET",
    "url": "/:message",
    "handler": "display"
  },
  {
    "method": "GET",
    "url": "/private/",
    "handler": "restricted",
    "preValidation": "_isAuthentified"
  }
]

All routes options from fastify are supported

Common options are:

  app = require 'ioserver'
    port:     8443                         # change listening port
    host:     '192.168.1.10'               # change listening host
    mode:     ['websocket']                # Set socket.io client
                                           # transport modes
                                           # default is:
                                           #  ['websocket','polling']
                                           # available methods are:
                                           #  ['websocket','htmlfile','polling','jsonp-polling']
    verbose:  'DEBUG'                      # set verbosity level
    cookies: false                         # Enable cookie usage for
                                           # Socket.io v3

    cors: {                                # Set up CORS as requested
      origin: 'http://mydomain.com'        # in Socket.io v3
      methods: ['GET','POST']
    }

Example

  1. Write a simple class (singleChat.coffee)
  module.exports = class SingleChat
    
    constructor: (@app) ->
    
    replay: (socket, text) ->
      console.log "Someone say: #{text}."
      socket.broadcast.emit 'message', text

    # Synchronous event are supported
    sync_replay: (socket, text, callback) ->
      console.log "Someone say: #{text}."
      callback text

    # All methods starting with '_' are meant private
    # and will not be published
    _notAccessible: (socket) ->
      console.error "You should not be here !!"
  1. Start server-side ioserver process (server.coffee)
  IOServer      = require 'ioserver'
  ChatService = require './singleChat'

  app = new IOServer()

  app.addService
    name:  'chat'
    service:   ChatService

  app.start()
  1. Compile and run server
  coffee -c *.coffee
  node server.js
  1. Write simple client wich interact with server class method as socket.io events
  $           = require 'jquery'
  io          = require 'socket.io-client'
  NODE_SERVER = 'Your-server-ip'
  NODE_PORT   = 'Your-server-port' # Default 8080

  socket = io.connect "http://#{NODE_SERVER}:#{NODE_PORT}/chat"
  
  # When server emit action
  socket.on 'message', msg, ->
    $('.message_list').append "<div class='message'>#{msg}</div>"

  # Jquery client action
  $('button.send').on 'click', ->
    msg = $('input[name="message"]').val()
    socket.emit 'replay', msg
  
  # You can also use callback for synchronous actions
  $('button.send').on 'click', ->
    msg = $('input[name="message"]').val()
    socket.emit 'sync_replay', msg, (data) ->
      $('.message_list').append "<div class='message'>#{data}</div>"

For further case study you can also check de demo Chat application...
(link provided in few days weeks ;) )

Developers

If you want to contribute to this project you are more than welcome !

Run tests

npm test

Please use Coffeescript for development language

Compilation

Use coffeescript to compile your tests

coffee --no-header -wc ./test

Use coffeescript to compile your changes in IOServer

npm run build

Publish

The NPM publishing is automated, just commit (or better merge) into master with comment 'Release v1.0.x' in order to publish corresponding package in NPM.

Bump version

npm --no-git-tag-version version [<newversion> | major | minor | patch]

TODO

  • write better doc
  • publish chat demo example
  • improve unit tests for complete coverage (restricted method)
  • Add REST API support