Skip to content

Pubsub API

Josh Feinsilber edited this page Nov 5, 2019 · 7 revisions

Blueboat allows you to use a variety of PubSub options to transfer messages between processes or machines. For Gimkit, we found that none of Blueboat's PubSub options that require an internet connection worked well with anything more than 2,000 concurrent players. Because of this, we use the EventEmitterPubsub and route clients to the correct server by using the first two digits of the game codes in Gimkit.

EventEmitterPubSub

This PubSub option can only be used on a single machine, on a single NodeJS process. This is what you will want to use to quickly get started with Blueboat. This is the method to use if you are only running your game server on a single computer & process.

Example

import { Server, EventEmitterPubSub } from 'blueboat'

const server = new Server({
  ...otherOptions
  pubsub: EventEmitterPubSub(),
})

EventEmitterClusterPubsub

This PubSub option is useful if you have a game server running only on one machine, but want to utilize all cores by forking multiple copies of the same process. This is the only PubSub option that does require an additional step to use though since it requires a forking of your NodeJS process. The additional step is to create a function that is called to start your app. This is where you would set up your Express server and such. Using this PubSub also requires that you use an adapter.

Example

import * as express from "express"
import { Server, EventEmitterClusterPubsub } from 'blueboat'


const start = () => {
  const app = express()
  const server = {
    ...otherOptions,
    adapters: [EventEmitterClusterPubsub.ClusterAdapter()],
    pubsub: EventEmitterClusterPubsub.PubSub(),
  }
  server.listen(3000)
}

EventEmitterClusterPubsub.ProcessStarter(start, 3) // second argument is the number of workers

RedisPubSub

This PubSub option is the quickest way to get Blueboat working across multiple machines

Example

import { Server, RedisPubSub } from 'blueboat'

const redisOptions {
  host: 'localhost',
  port: 6379,
}

const server = new Server({
  ...otherOptions,
  pubsub: RedisPubSub(redisOptions),
})

RabbitMQPubSub

This PubSub option is another way to get Blueboat working across multiple machines

Example

import { Server, RabbitMQPubSub } from 'blueboat'


const server = new Server({
  ...otherOptions
  pubsub: RabbitMQPubSub('RabbitMQ Connect Address Here'),
})

Make Your Own PubSub!

If none of these options work for you, you can also create your own PubSub mechanism. Just make sure it follows the PubSub API.

On Function: This is called when a new listener is added

type OnFunction = (key: string, callback: (data: any) => any) => {
    unsubscribe: () => any;
};

Publish Function: This is called when a new message is published

type Publish = (key: string, data: any) => any;

Here's a quick and dirty example creating a PubSub mechanism using just NodeJS Memory

import { PubSub } from "blueboat"

const listeners = {} as {
  [key: string]: Array<{ id: string; callback: (data?: any) => any }>
}

const unsubscribe = (key: string, id: string) => {
  if (listeners[key]) {
    listeners[key] = listeners.key.filter(listener => {
      return !(listener.id === id)
    })
  }
  if (listeners[key].length === 0) {
    listeners[key] = null
  }
}

const on = (key: string, callback: (data: any) => any) => {
  const uniqueId = Math.random().toString()
  const alreadyListening = listeners[key] ? true : false

  if (alreadyListening) {
    listeners[key].push({ id: uniqueId, callback })
  } else {
    listeners[key] = [{ id: uniqueId, callback }]
  }
  return { unsubscribe: () => unsubscribe(key, uniqueId) }
}

const publish = (key: string, data: any) => {
  if (listeners[key]) {
    listeners[key].forEach(listener => {
      listener.callback(data)
    })
  }
}

const MemoryPubSub = new PubSub(on, publish)