{"id":13447584,"url":"https://github.com/primus/primus","last_synced_at":"2025-05-13T19:15:11.334Z","repository":{"id":9141193,"uuid":"10932532","full_name":"primus/primus","owner":"primus","description":":zap: Primus, the creator god of the transformers \u0026 an abstraction layer for real-time to prevent module lock-in.","archived":false,"fork":false,"pushed_at":"2023-11-06T18:13:11.000Z","size":2998,"stargazers_count":4476,"open_issues_count":50,"forks_count":272,"subscribers_count":110,"default_branch":"master","last_synced_at":"2025-04-27T20:00:03.607Z","etag":null,"topics":["browserchannel","framework","http","javascript","node","nodejs","polling","real-time","sockjs","websocket"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"drowaudio/drowaudio","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/primus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2013-06-25T08:17:42.000Z","updated_at":"2025-04-21T08:23:40.000Z","dependencies_parsed_at":"2022-08-09T09:15:19.407Z","dependency_job_id":"9783841f-d1d4-4978-9969-0247a58caa5f","html_url":"https://github.com/primus/primus","commit_stats":{"total_commits":1519,"total_committers":72,"mean_commits":21.09722222222222,"dds":0.5681369321922317,"last_synced_commit":"16f251362332c6c32dc38a7b77efce2b1ec1399c"},"previous_names":[],"tags_count":107,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/primus%2Fprimus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/primus%2Fprimus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/primus%2Fprimus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/primus%2Fprimus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/primus","download_url":"https://codeload.github.com/primus/primus/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254010822,"owners_count":21998999,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["browserchannel","framework","http","javascript","node","nodejs","polling","real-time","sockjs","websocket"],"created_at":"2024-07-31T05:01:21.703Z","updated_at":"2025-05-13T19:15:11.314Z","avatar_url":"https://github.com/primus.png","language":"JavaScript","readme":"# Primus\n\n[![Version npm](https://img.shields.io/npm/v/primus.svg?style=flat-square)](https://www.npmjs.com/package/primus)[![CI](https://img.shields.io/github/actions/workflow/status/primus/primus/ci.yml?branch=master\u0026label=CI\u0026style=flat-square)](https://github.com/primus/primus/actions?query=workflow%3ACI+branch%3Amaster)[![Coverage Status](https://img.shields.io/coveralls/primus/primus/master.svg?style=flat-square)](https://coveralls.io/r/primus/primus?branch=master)\n\nPrimus, the creator god of transformers but now also known as universal wrapper\nfor real-time frameworks. There are a lot of real-time frameworks available for\nNode.js and they all have different opinions on how real-time should be done.\nPrimus provides a common low level interface to communicate in real-time using\nvarious real-time frameworks.\n\n### Advantages\n\n1. Effortless switching between real-time frameworks by changing one single line\n   of code. No more API rewrites needed when your project requirements change,\n   the framework gets abandoned or simply breaks down.\n2. Built-in reconnect, it just works. The reconnect is controlled by a\n   randomised exponential back-off algorithm to reduce server stress.\n3. Offline detection, Primus is smart enough to detect when users drop their\n   internet connection (switching WIFI points/cell towers for example) and\n   reconnects when they are back online.\n4. Automatically encodes and decodes messages using custom parsers. Can be\n   easily switched for binary encoding for example.\n5. A clean, stream-compatible interface for the client and server. You can\n   just `stream#pipe` data around. In addition to that, the client works on\n   Node.js as well, write once, run it everywhere.\n6. Fixes various of bugs in the supported frameworks and additional stability\n   patches to improve real-time communication.\n8. Comes with an amazing plugin interface to keep the core library as fast and\n   lean as possible while still allowing the server and the client to be\n   extended.\n9. Last but not least, Primus is built with love, passion and dedication to the\n   real-time web.\n\n### Installation\n\nPrimus is released on `npm` and can be installed using:\n\n```\nnpm install primus --save\n```\n\n### Before Starting\n\nIf you deploy your application behind a reverse proxy (Nginx, HAProxy, etc.) you\nmight need to add WebSocket specific settings to its configuration files. If\nyou intend to use WebSockets, please ensure that these settings have been added.\nThere are some example configuration files available in the\n[observing/balancerbattle](https://github.com/observing/balancerbattle)\nrepository.\n\n### Table of Contents\n\n- [Introduction](#primus)\n  - [Advantages](#advantages)\n- [Installation](#installation)\n- [Getting started](#getting-started)\n  - [Client library](#client-library)\n- [Connecting from the browser](#connecting-from-the-browser)\n- [Connecting from the server](#connecting-from-the-server)\n- [Authorization](#authorization)\n- [Broadcasting](#broadcasting)\n- [Destruction](#destruction)\n- [Events](#events)\n- [Heartbeats and latency](#heartbeats-and-latency)\n- [Supported real-time frameworks](#supported-real-time-frameworks)\n  - [BrowserChannel](#browserchannel)\n  - [Engine.IO](#engineio)\n  - [Faye](#faye)\n  - [SockJS](#sockjs)\n  - [uws](#uws)\n  - [WebSockets](#websockets)\n- [Transformer inconsistencies](#transformer-inconsistencies)\n- [Parsers](#parsers)\n- [Middleware](#middleware)\n- [Plugins](#plugins)\n  - [Extending the Spark / Socket](#extending-the-spark--socket)\n  - [Transforming and intercepting messages](#transforming-and-intercepting-messages)\n  - [Primus project plugins](#primus-project-plugins)\n  - [Community plugins](#community-plugins)\n- [Community](#community)\n- [FAQ](#FAQ)\n  - [Scaling](#what-is-the-best-way-to-scale-primus)\n  - [Cluster](#can-i-use-cluster)\n  - [Express](#how-do-i-use-primus-with-express)\n  - [RequireJS](#is-requirejs-supported)\n  - [Custom headers](#can-i-send-custom-headers-to-the-server)\n- [Versioning](#versioning)\n  - [History](#history)\n  - [Convention](#convention)\n  - [Release cycle](#release-cycle)\n- [Other languages](#other-languages)\n  - [Protocol](#protocol)\n- [License](#license)\n\n### Getting started\n\nPrimus doesn't ship with real-time frameworks as dependencies, it assumes that\nyou as user add them yourself as a dependency. This is done to keep the module\nas lightweight as possible. This works because `require` in will walk through\nyour directories searching for `node_module` folders that have these matching\ndependencies.\n\nPrimus needs to be \"attached\" to a HTTP compatible server. These includes the\nbuilt-in `http` and `https` servers but also the `spdy` module as it has the\nsame API as node servers. Creating a new Primus instance is relatively\nstraightforward:\n\n```js\n'use strict';\n\nvar Primus = require('primus')\n  , http = require('http');\n\nvar server = http.createServer(/* request handler */)\n  , primus = new Primus(server, {/* options */});\n```\nThe following options can be provided:\n\nName                | Description                               | Default\n--------------------|-------------------------------------------|---------------\nauthorization       | Authorization handler                     | `null`\npathname            | The URL namespace that Primus can own     | `/primus`\nparser              | Message encoder for all communication     | `JSON`\ntransformer         | The transformer we should use internally  | `websockets`\nplugin              | The plugins that should be applied        | `{}`\npingInterval        | Interval at which heartbeats are sent     | `30000`\nglobal              | Set a custom client class / global name   | `Primus`\ncompression         | Use permessage-deflate / HTTP compression | `false`\nmaxLength           | Maximum allowed packet size, in bytes     | `10485760`\ntransport           | Transformer specific configuration        | `{}`\nidGenerator         | Custom spark id generator function        | `undefined`\norigins             | **cors** List of origins                  | `*`\nmethods             | **cors** List of accepted HTTP methods    | `GET,HEAD,PUT,POST,DELETE,OPTIONS`\ncredentials         | **cors** Allow sending of credentials     | `true`\nmaxAge              | **cors** Cache duration of CORS preflight | `30 days`\nheaders             | **cors** Allowed headers                  | `false`\nexposed             | **cors** Headers exposed to the client    | `false`\n\nThe options that are prefixed with **cors** are supplied to our\n[access-control](https://github.com/primus/access-control) module which handles\nHTTP Access Control (CORS), so for a more detailed explanation of these options\ncheck it out.\n\nThe `transport` option allows you to use any configuration option supported by\nthe underlying real-time framework. Its use is discouraged as these options\nare framework specific and no longer work if you change transformer. Our advise\nis to use it only if you know what you are doing and if you need fine-grained\ncontrol over the real-time framework. Please also keep in mind that some of\nthese options are overriden by Primus.\n\nThe `pingInterval` option specifies the interval at which heartbeats are\ntransmitted. It is possible to completely disable the heartbeats by setting the\nvalue of the `pingInterval` option to `false`.\n\nThe `idGenerator` option can be used to define a function which will be called\nto set each [`spark.id`](#sparkid). The generator function should return\na unique string each time it is invoked. If `idGenerator` is not defined, Primus\nwill try to use ids provided by the transformer. If the transformer does not\nprovide ids, Primus will use [nanoid](https://github.com/ai/nanoid) to generate\n`Spark` ids.\n\nIf you don't have a pre-existing server where you want or can attach your Primus\nserver to you can also use the `Primus.createServer` convenience method. The\n`createServer` method will automatically:\n\n- Setup a HTTP, HTTPS or SPDY server for you on the given port number.\n- Setup your Primus server with the given configuration.\n- Listen on the HTTP, HTTPS, SPDY server.\n- Attach a `primus.on('connection')` listener.\n- Return the created Primus instance.\n\n```js\nPrimus.createServer(function connection(spark) {\n\n}, { port: 8080, transformer: 'websockets' });\n```\n\nIn the above example we automatically create a HTTP server which will listen\non port 8080, a primus instance with the `websockets` transformer and start\nlistening for incoming connections. The supplied function in the\n`Primus.createServer` method is optional. You can just listen for incoming\nconnections your self using the returned Primus instance. If you want to listen to\na HTTPS or SPDY server, which is recommended, you can directly pass the SPDY and\nHTTPS certs/keys/pfx files in the options object:\n\n```js\nvar primus = Primus.createServer({\n  port: 443,\n  root: '/folder/with/https/cert/files',\n  cert: 'myfilename.cert',\n  key: 'myfilename.cert',\n  ca: 'myfilename.ca',\n  pfx: 'filename.pfx',\n  passphrase: 'my super sweet password'\n});\n\nprimus.on('connection', function (spark) {\n  spark.write('hello connnection');\n});\n```\n\n`Primus.createServer` returns a warning when it starts a HTTP server. The\nwarning advises you to use a HTTPS server and can be disabled setting the\noption `iknowhttpsisbetter` to `true`.\n\n#### Client library\n\nAs most libraries come with their own client-side framework for making the\nconnection we've also created a small wrapper for this. The library can be\nretrieved using:\n\n```js\nprimus.library();\n```\n\nWhich returns the client-side library as a string (which can then be minified or\neven have more code added to it). It does not come pre-minified as that is out\nof the scope of this project. You can store this on a CDN or on your static server.\nDo whatever you want with it, but remember to regenerate it every time you change\nPrimus server options. This is important because some properties of the client\nare set using the server configuration. For example if you change the\n`pathname`, the client should be regenerated to reflect that change and work\ncorrectly. We advise you to regenerate the library every time you redeploy so\nyou always have a client compatible with your back-end. To save the file you\ncan use:\n\n```js\nprimus.save(__dirname +'/primus.js');\n```\n\nThis will store the compiled library in your current directory. If you want to\nsave it asynchronously, you can supply the method with a callback method:\n\n```js\nprimus.save(__dirname +'/primus.js', function save(err) {\n\n});\n```\n\nBut to make it easier for you during development we've automatically added an\nextra route to the supplied HTTP server, this will serve the library for you so\nyou don't have to save it. Please note, that this route isn't optimised for\nserving static assets and should only be used during development. In your HTML\npage add:\n\n```html\n\u003cscript src=\"/primus/primus.js\"\u003e\u003c/script\u003e\n```\n\nAs you can see, it will use the `/primus` pathname by default. Primus needs to\nown the whole path/namespace in order to function properly as it will forward\nall other requests directly in to the transformers so they can work their magic.\nIf you already have a static folder with the name `primus` you can change the\npathname to something different and still make this work. But you would of\ncourse need to update the `src` attribute of the script tag to set the correct\nlocation. It's always available at:\n\n```\n\u003cprotocol\u003e://\u003cserver location\u003e/\u003cpathname\u003e/primus.js\n```\n\nHere `\u003cpathname\u003e` is the `pathname` set in server options above. The client\nis cross domain compatible so you don't have to serve it from the\nsame domain you're running Primus on. But please note, that the real-time\nframework you're using might be tied to same domain restrictions.\n\nOnce you're all set up you can start listening for connections. These\nconnections are announced through the `connection` event.\n\n```js\nprimus.on('connection', function (spark) {\n  // spark is the new connection.\n});\n```\n\nDisconnects are announced using a `disconnection` event:\n\n```js\nprimus.on('disconnection', function (spark) {\n  // the spark that disconnected\n});\n```\n\nThe `spark` argument is the actual real-time socket/connection. Sparks have a\nreally low level interface and only expose a couple properties that are cross\nengine supported. The interface is modeled towards a Node.js stream compatible\ninterface. So this will include all methods that are available on the [stream\ninterface](https://nodejs.org/api/stream.html) including `Spark#pipe`.\n\n#### spark.headers\n\nThe `spark.headers` property contains the headers of either the request\nthat started a handshake with the server or the headers of the actual real-time\nconnection. This depends on the module you are using.\n\n*Please note that sending custom headers from the client to the server is\nimpossible as not all transports that these transformers support can add custom\nheaders to a request (JSONP for example). If you need to send custom data, use a\nquery string when connecting*\n\n#### spark.address\n\nThe `spark.address` property contains the `ip` and `port` of the\nconnection. If you're running your server behind a reverse proxy it will\nautomatically use the `x-forwarded-for` header. This way you will always have\nthe address of the connecting client and not the IP address of your proxy.\n\n*Please note that the `port` is probably out of date by the time you're going\nto read it as it's retrieved from an old request, not the request that is\nactive at the time you access this property.*\n\n#### spark.query\n\nThe `spark.query` contains the query string you used to connect to the server. It's\nparsed as an object. Please note that this may not be available for all supported\ntransformers.\n\n#### spark.socket\n\nThe `spark.socket` is set to the underlying socket of the transformer. This is not\nnecessarily a raw `Socket` and will differ from transformer to transformer.\n\n#### spark.id\n\nThis is a unique id that we use to identify this single connection with. Normally\nthe frameworks refer to this as a `sessionid`, which is confusing as it's only\nused for the duration of one single connection. You should not see this as a\n\"session id\", and rather expect it to change between disconnects and reconnects.\n\n#### spark.request\n\nThe `spark.request` gives you access to the HTTP request that was used to\ninitiate the real-time connection with the server. Please note that this request\nis already answered and closed (in most cases) so do not attempt to write or\nanswer it anyway. But it might be useful to access methods that get added by\nmiddleware layers, etc.\n\n#### spark.write(data)\n\nYou can use the `spark.write` method to send data over the socket. The data is\nautomatically encoded for you using the `parser` that you've set while creating\nthe Primus server instance. This method always returns `true` on success and\n`false` on failure so back pressure isn't handled.\n\n```js\nspark.write({ foo: 'bar' });\n```\n\n#### spark.end(data, options)\n\nYou can use `spark.end` to close the connection. This method takes two optional\narguments. The first, if provided, is the `data` to send to the client before\nclosing the connection. The second is an options object used to customize the\nbehavior of the method. By default the `spark.end` method closes the connection\nin a such way that the client knows it was intentional and it doesn't attempt a\nreconnection.\n\n```js\nspark.end(); // the client doesn't reconnect automatically\n```\n\nYou can change this behavior and trigger a client-side reconnection using the\n`reconnect` option.\n\n```js\nspark.end(undefined, { reconnect: true }); // trigger a client-side reconnection\n```\n\n#### spark.emits(event, parser)\n\nThis method is mostly used internally. It works similarly to the native `bind`\nfunction, returning a function that emits the assigned `event` every time it's\ncalled. If the last argument is a function, it will be used to parse the\narguments of the returned function. The `parser` is optional and always async,\nits **first** argument is a callback that follows the usual error first pattern,\nall successive arguments are the ones to parse. Using the `parser` you can\nreduce the arguments down to a single value, remove them completely or prevent\nthe event from being emitted. See [emits](https://github.com/primus/emits) for\ndetailed usage instructions.\n\n```js\nspark.emits('event', function parser(next, structure) {\n  next(undefined, structure.data);\n});\n```\n\nPlease note that the data that is received here isn't decoded yet.\n\n#### spark.on('data')\n\nThe `data` event is emitted when a message is received from the client. It's\nautomatically decoded by the specified decoder.\n\n```js\nspark.on('data', function message(data) {\n  // the message we've received.\n});\n```\n\n#### spark.on('end')\n\nThe `end` event is emitted when the client has disconnected.\n\n```js\nprimus.on('connection', function (spark) {\n  console.log('connection has the following headers', spark.headers);\n  console.log('connection was made from', spark.address);\n  console.log('connection id', spark.id);\n\n  spark.on('data', function (data) {\n    console.log('received data from the client', data);\n\n    //\n    // Always close the connection if we didn't receive our secret imaginary\n    // handshake.\n    //\n    if ('foo' !== data.secrethandshake) spark.end();\n    spark.write({ foo: 'bar' });\n    spark.write('banana');\n  });\n\n  spark.write('Hello world');\n})\n```\n\n### Connecting from the Browser\n\nPrimus comes with its client framework which can be compiled using\n`primus.library()` as mentioned above. To create a connection you can simply\ncreate a new Primus instance:\n\n```js\nvar primus = new Primus(url, { options });\n\n//\n// But it can be easier, with some syntax sugar.\n//\nvar primus = Primus.connect(url, { options });\n```\n\nThe URL should confirm the following conditions:\n\n- It should include the protocol it needs to connect with. This can either be\n  `http` or `https`. We recommend that you're using HTTPS for all your\n  connections as this prevents connection blocking by firewalls and anti-virus\n  programs.\n- The URL should not include a pathname. The pathname is configured by the\n  server (See: [getting-started](#getting-started)) and needs to be configured\n  there as it will be compiled in to the `primus.js` client file.\n\nIf no `url` argument is passed, it will default to the current URL.\n\nThe following options can be provided:\n\nName                | Description                             | Default\n--------------------|-----------------------------------------|---------------\n[reconnect]         | Configures the exponential back off     | `{}`\ntimeout             | Connect time out                        | `10000` ms\npingTimeout         | Max time to wait for a server ping      | `45000` ms\n[strategy]          | Our reconnect strategies                | `\"disconnect,online,timeout\"`\nmanual              | Manually open the connection            | `false`\nwebsockets          | Should we use WebSockets                | Boolean, is detected\nnetwork             | Use native `online`/`offline` detection | Boolean, is feature detected\ntransport           | Transport specific configuration        | `{}`\nqueueSize           | Number of messages that can be queued   | `Infinity`\n\nThere are 2 important options that we're going to look a bit closer at.\n\n##### Reconnect\n\nWhen the connection goes down unexpectedly an automatic reconnect process is\nstarted. It uses a randomised exponential back-off algorithm to prevent clients\nfrom DDoSing your server when you reboot as they will all be re-connecting at\ndifferent times. The reconnection can be configured using the `options` argument\nin `Primus` and you should add these options to the `reconnect` property:\n\nName                | Description                              | Default\n--------------------|------------------------------------------|---------------\nmax                 | Maximum delay for a reconnection attempt | `Infinity`\nmin                 | Minimum delay for a reconnection attempt | `500` ms\nretries             | Maximum amount of attempts               | `10`\nreconnect timeout   | Maximum time for an attempt to complete  | `30000` ms\nfactor              | Exponential back off factor              | `2`\n\n```js\nprimus = Primus.connect(url, {\n  reconnect: {\n      max: Infinity // Number: The max delay before we try to reconnect.\n    , min: 500 // Number: The minimum delay before we try reconnect.\n    , retries: 10 // Number: How many times we should try to reconnect.\n  }\n});\n```\n\nWhen you're going to customize `min` please note that it will grow\nexponentially e.g. `500 -\u003e 1000 -\u003e 2000 -\u003e 4000 -\u003e 8000` and is randomized\nso expect to have slightly higher or lower values.\n\nPlease note that when we reconnect, we will receive a new `connection` event on\nthe server and a new `open` event on the client, as the previous connection was\ncompletely dead and should therefore be considered a new connection.\n\nIf you are interested in learning more about the backoff algorithm you might\nwant to read http://dthain.blogspot.nl/2009/02/exponential-backoff-in-distributed.html\n\n##### Strategy\n\nThe strategy allows you to configure when you want a `reconnect` operation to\nkick in. We're providing some **sane** defaults for this but we still want to\nprovide users with highest level of customization:\n\n\u003cdl\u003e\n  \u003cdt\u003edisconnect\u003c/dt\u003e\n  \u003cdd\u003e\n    Reconnect when we detect an unintentional disconnect in the connection.\n  \u003c/dd\u003e\n  \u003cdt\u003eonline\u003c/dt\u003e\n  \u003cdd\u003e\n    Reconnect when the browser went from an offline event to an online event.\n  \u003c/dd\u003e\n  \u003cdt\u003etimeout\u003c/dt\u003e\n  \u003cdd\u003e\n    Reconnect when we failed to establish our initial connection. This can\n    happen because we took too long to connect or because there was an error\n    while we tried to connect (which happens when you connect to a dead server)\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\nYou can supply these options as a comma-separated `String`:\n\n```js\nvar primus = new Primus(url, { strategy: 'online, timeout, disconnect' })\n```\n\nOr as an `Array`:\n\n```js\nvar primus = new Primus(url, { strategy: [ 'online', 'timeout', 'disconnect' ]});\n```\n\nWe'll try to normalize everything as much as possible, we `toLowerCase` everything\nand join it back to a readable string so if you wrote `dIsconNect` it will get\nnormalized to `disconnect`.\n\n**If you are using authentication you should disable the `timeout` strategy as\nthere is no way of detecting the difference between a failed authorization and a\nfailed connect. If you leave this enabled with authorization every unauthorized\naccess will try to reconnect again**.\n\nWe automatically disable this for you when you've set the authorization before\nyou save the library.\n\nBut there are always use cases where reconnection is not advised for your\napplication. In these cases we've provided a way to completely disable the\nreconnection, this is done by setting the `strategy` to `false`:\n\n```js\nvar primus = new Primus(url, { strategy: false });\n```\nIf you want to manually control the reconnection you can call `primus.end()`\nto close the connection and `primus.open()` to establish a new one. **Be sure\nto use `primus.open()` correctly, see below for details.**\n\n[reconnect]: #reconnect\n[strategy]: #strategy\n\n##### transport\n\nThe transport object allows you to add a transport specific configuration.\nWe only recommend using this if you understand and accept the following\nconsequences:\n\n- Primus will try to override configuration properties that are needed to\n  ensure a correct functioning.\n- We might start using options without any announcement or major version bump.\n- Expect your client and its connection to malfunction once you switch between\n  different transports, as these configurations are specific to the bundled\n  transformer library/client.\n- Bugs and bug reports caused by using this functionality are closed\n  immediately.\n\nHaving that said, this gives you total freedom while still getting the benefits\nof Primus.\n\n#### primus.open()\n\nThis method opens a connection with the server. By default it is called\nautomatically when the Primus instance is created, but there are cases where\nit's desirable to open the connection manually. To do this set the `manual`\noption to `true` and when you have the Primus instance call the method:\n\n```js\nprimus.open();\n```\n\n**When you call `primus.open()` you should make sure that the connection is\ntotally dead (e.g. after an `end` event) and primus isn't already trying or\nplanning to reconnect**.\n\n#### primus.write(message)\n\nOnce you've created your Primus instance you're ready to go. When you want to\nwrite data to your server you can just call the `.write` method:\n\n```js\nprimus.write('message');\n```\n\nIt automatically encodes your messages using the parser that you've specified on\nthe server. So sending objects back and forth between the server is nothing\ndifferent then just writing:\n\n```js\nprimus.write({ foo: 'bar' });\n```\n\nWhen you are sending messages to the server, you don't have to wait for the\n`open` event to happen, the client will automatically buffer all the data you've\nsend and automatically write it to the server once it's connected. The client\nsupports a couple of different events.\n\n#### primus.on('data')\n\nThe `data` event is the most important event of the whole library. It's emitted\nwhen we receive data from the server. The data that is received is already\ndecoded by the specified parser.\n\n```js\nprimus.on('data', function message(data) {\n  console.log('Received a new message from the server', data);\n});\n```\n\n#### primus.on('open')\n\nThe `open` event is emitted when we've successfully created a connection with\nthe server. It will also be emitted when we've successfully reconnected after the\nconnection goes down unintentionally.\n\n```js\nprimus.on('open', function open() {\n  console.log('Connection is alive and kicking');\n});\n```\n\n#### primus.on('error')\n\nThe `error` event is emitted when something breaks that is out of our control.\nUnlike Node.js, we do not throw an error if no `error` event listener is\nspecified. In general, when there is an active connection, it is not directly\nclosed when an `error` event is emitted. The cause of an error, in fact, could\nbe that the parser failed to encode or decode a message. In this case we only\nemit the error, discard the message and keep the connection alive. An `error`\nevent can also be emitted when a connection fails to establish. When this\nhappens the client automatically tries to reconnect, unless the connection gets\nclosed for some other reason. The only exception is when there is an\nauthorization hook. If we get an error when connecting to a server where\nauthorization is required, we simply close the connection, as we can't\ndeterminate if the error is the result of an unauthorized access or not.\n\n```js\nprimus.on('error', function error(err) {\n  console.error('Something horrible has happened', err.stack);\n});\n```\n\n#### primus.on('reconnect')\n\nThe `reconnect` event is emitted when we're attempting to reconnect to the\nserver. This all happens transparently and it's just a way for you to know when\nthese reconnects are actually happening.\n\n```js\nprimus.on('reconnect', function (opts) {\n  console.log('Reconnection attempt started');\n});\n```\n\n#### primus.on('reconnect scheduled')\n\nLooks a lot like the `reconnect` event mentioned above, but it's emitted when\nwe've detected that connection went/is down and we're going to start a reconnect\noperation. This event would be ideal to update your application's UI when the\nconnection is down and you are trying to reconnect in x seconds.\n\n```js\nprimus.on('reconnect scheduled', function (opts) {\n  console.log('Reconnecting in %d ms', opts.scheduled);\n  console.log('This is attempt %d out of %d', opts.attempt, opts.retries);\n});\n```\n\n#### primus.on('reconnected')\n\nThe client successfully reconnected with the server.\n\n```js\nprimus.on('reconnected', function (opts) {\n  console.log('It took %d ms to reconnect', opts.duration);\n});\n```\n\n#### primus.on('reconnect timeout')\n\nThe `reconnect timeout` event is emitted when a reconnection attempt takes too\nmuch time. This can happen for example when the server does not answer a request\nin a timely manner.\n\n```js\nprimus.on('reconnect timeout', function (err, opts) {\n  console.log('Timeout expired: %s', err.message);\n});\n```\n\nAfter this event a whole new reconnection procedure is automatically started, so\nyou don't have to worry about it.\n\n#### primus.on('reconnect failed')\n\nThis event is emitted when the reconnection failed, for example when all\nattempts to reconnect have been unsuccessful.\n\n```js\nprimus.on('reconnect failed', function (err, opts) {\n  console.log('The reconnection failed: %s', err.message);\n});\n```\n\n#### primus.on('end')\n\nThe `end` event is emitted when we've closed the connection. When this event is\nemitted you should consider your connection to be fully dead with no way of\nreconnecting. But it's also emitted when the server closes the connection.\n\n```js\nprimus.on('end', function () {\n  console.log('Connection closed');\n});\n```\n\n#### primus.end()\n\nWhen you want to close the connection you can call the `primus.end()` method.\nAfter this the connection should be considered dead and a new connection needs\nto be made using `Primus.connect(url)` or `primus = new Primus(url)` if you want\nto talk with the server again.\n\n```js\nprimus.end();\n```\n\n#### primus.destroy()\n\nThis method literally destroys the `primus` instance. Internally it calls the\n`primus.end()` method but it also frees some potentially heavy objects like\nthe underlying socket, the timers, the message transformers, etc. It also\nremoves all the event listeners but before doing that it emits a final `destroy`\nevent. Keep in mind that once this method is executed, you can no longer use\n`primus.open()` on the same `primus` instance.\n\n```js\nprimus.on('destroy', function () {\n  console.log('Feel the power of my lasers!');\n});\n\nprimus.destroy();\n```\n\n#### primus.emits(event, parser)\n\nThis method is analogous to the [`spark.emits`](#sparkemitsevent-parser) method.\nIt returns a function that emits the given event every time it's called. See\n[emits](https://github.com/primus/emits) for detailed usage instructions.\n\n```js\nprimus.emits('event', function parser(next, structure) {\n  next(undefined, structure.data);\n});\n```\n\n#### primus.id(callback)\n\nThere are cases where it is necessary to retrieve the [`spark.id`](#sparkid)\nfrom the client. To make this easier, we added a `primus.id()` method that\ntakes a callback function to which the id will be passed.\n\n```js\nprimus.id(function (id) {\n  console.log(id);\n});\n```\n\n### Connecting from the server\n\nThere are two ways of creating a server side client.\n\n1. When you've created your `primus` instance you can access the `Socket`\n   property on it. This `Socket` is automatically configured to connect to the\n   correct pathname, using the same `transformer` and `parser` that you've\n   specified when you created your `primus` instance.\n\n   ```js\n   var primus = new Primus(server, { transformer: transformer, parser: parser })\n     , Socket = primus.Socket;\n\n   var client = new Socket('http://localhost:8080');\n   //\n   // It has the same interface as the client, so you can just socket.write or\n   // listen for the `open` events etc.\n   //\n   ```\n2. You might need to connect from a different node process where you don't have\n   access to your `primus` instance and the compatible `Socket` instance. For\n   these cases there a special `createSocket` method where you can specify the\n   `transformer`, `parser`, `plugin` that you are using on your server to create\n   another compatible socket.\n\n   ```js\n   var Primus = require('primus') // Primus library from npm install primus\n     , Socket = Primus.createSocket({ transformer: transformer, parser: parser })\n     , client = new Socket('http://localhost:8080');\n   ```\n\nWhen you are using plugins with Primus make sure you add them **before** you\nreference the `primus.Socket` or it will compile a client without your plugins.\nIf you're using the `Primus.createSocket` api you can directly supply the\nplugins as part of the options as it supports `plugin` object:\n\n```js\nvar Socket = Primus.createSocket({\n  transformer: transformer,\n  parser: parser,\n  plugin: {\n    'my-emitter': require('my-emitter'),\n    'substream': require('substream')\n  }\n});\n```\n\nThe constructor returned by `primus.Socket` or `Primus.createSocket` has the\nsame signature of the constructor used to connect from the browser. This\nmeans that you can use all the options mentioned in the previous\n[section](#connecting-from-the-browser):\n\n```js\nvar Socket = Primus.createSocket()\n  , client = new Socket('http://localhost:8080', { options });\n```\n\nIf you do not know which transformer and parser are used on the server, we\nexpose a small JSON \"spec\" file that exposes this information. The specification\ncan be reached on the `/\u003cpathname\u003e/spec` and will output the following JSON\ndocument:\n\n  ```json\n  {\n    \"version\":\"2.4.0\",\n    \"pathname\":\"/primus\",\n    \"parser\":\"json\",\n    \"transformer\":\"websockets\"\n  }\n  ```\n\n### Authorization\n\n#### Server\n\nPrimus has a built-in auth hook that allows you to leverage the basic auth\nheader to validate the connection. To setup the optional auth hook, use the\n`Primus#authorize` method:\n\n```js\nvar authParser = require('basic-auth-parser');\n\n//\n// Add hook on server\n//\nprimus.authorize(function (req, done) {\n  var auth;\n\n  try { auth = authParser(req.headers['authorization']) }\n  catch (ex) { return done(ex) }\n\n  //\n  // Do some async auth check\n  //\n  authCheck(auth, done);\n});\n\nprimus.on('connection', function (spark) {\n  //\n  // You only get here if you make it through the auth hook!\n  //\n});\n```\n\nIn this particular case, if an error is passed to `done` by `authCheck` or\nthe exception handler then the connection attempt will never make it to the\n`primus.on('connection')` handler.\n\nThe error you pass can either be a string or an object. If an object, it can\nhave the following properties which affect the response sent to the client:\n\n- `statusCode`: The HTTP status code returned to the client. Defaults to 401.\n- `authenticate`: If set and `statusCode` is 401 then a `WWW-Authenticate`\n  header is added to the response, with a value equal to the `authenticate`\n  property's value.\n- `message`: The error message returned to the client. The response body will be\n  `{error: message}`, JSON-encoded.\n\nIf the error you pass is a string then a 401 response is sent to the client\nwith no `WWW-Authenticate` header and the string as the error message.\n\nFor example to send 500 when an exception is caught, 403 for forbidden users\nand details of the basic auth scheme being used when authentication fails:\n\n```js\nprimus.authorize(function (req, done) {\n  var auth;\n\n  if (req.headers.authorization) {\n    try { auth = authParser(req.headers.authorization) }\n    catch (ex) {\n      ex.statusCode = 500;\n      return done(ex);\n    }\n\n    if ((auth.scheme === 'myscheme') \u0026\u0026\n        checkCredentials(auth.username, auth.password)) {\n      if (userAllowed(auth.username)) {\n        return done();\n      } else {\n        return done({ statusCode: 403, message: 'Go away!' });\n      }\n    }\n  }\n\n  done({\n    message: 'Authentication required',\n    authenticate: 'Basic realm=\"myscheme\"'\n  });\n});\n```\n\nPlease note that the auth hook is run each and every time a request is made to\nthe server.\n\n#### Client\n\nUnfortunately, the amount of detail you get in your client when authorization\nfails depends on the transformer in use. Most real-time frameworks supported\nby Primus don't expose the status code, headers or response body.\n\nThe WebSocket transformer's underlying transport socket will fire an\n`unexpected-response` event with the HTTP request and response:\n\n```js\nprimus.on('outgoing::open', function () {\n  primus.socket.on('unexpected-response', function (req, res) {\n    console.error(res.statusCode);\n    console.error(res.headers['www-authenticate']);\n\n    //\n    // It's up to us to close the request (although it will time out).\n    //\n    req.abort();\n\n    //\n    // It's also up to us to emit an error so primus can clean up.\n    //\n    primus.socket.emit('error', 'authorization failed: ' + res.statusCode);\n  });\n});\n```\n\nIf you want to read the response body then you can do something like this:\n\n```js\nprimus.on('outgoing::open', function () {\n  primus.socket.on('unexpected-response', function (req, res) {\n    console.error(res.statusCode);\n    console.error(res.headers['www-authenticate']);\n\n    var data = '';\n\n    res.on('data', function (v) {\n      data += v;\n    });\n\n    res.on('end', function () {\n      //\n      // Remember error message is in the 'error' property.\n      //\n      primus.socket.emit('error', new Error(JSON.parse(data).error));\n    });\n  });\n});\n```\n\nIf `unexpected-response` isn't caught (because the WebSocket transformer isn't\nbeing used or you don't listen for it) then you'll get an `error` event:\n\n```js\nprimus.on('error', function error(err) {\n  console.error('Something horrible has happened', err.stack);\n});\n```\n\nAs noted above, `err` won't contain any details about the authorization failure\nso you won't be able to distinguish it from other errors.\n\n### Broadcasting\n\nBroadcasting allows you to write a message to every connected `Spark` on your server.\nThere are 2 different ways of doing broadcasting in Primus. The easiest way is to\nuse the `Primus#write` method which will write a message to every connected user:\n\n```js\nprimus.write('message');\n```\n\nThere are cases where you only want to broadcast a message to a smaller group of\nusers. To make it easier to do this, we've added a `Primus#forEach` method which\nallows you to iterate over all active connections.\n\n```js\nprimus.forEach(function (spark, id, connections) {\n  if (spark.query.foo !== 'bar') return;\n\n  spark.write('message');\n});\n```\n\nThe method can be also used asynchronously. To enable the asynchronous iteration\nyou have to call `Primus#forEach` with two arguments. The first is the iterator\nfunction that is called on every step. The iterator is called with a connection\nfrom the list and a callback for when it has finished. The second argument is\nthe main callback and is called when the iteration has finished.\n\n```js\nprimus.forEach(function (spark, next) {\n  //\n  // Do something and call next when done\n  //\n  next();\n}, function (err) {\n  console.log('We are done');\n});\n```\n\nThere are also cases where you want to select a single `Spark`. To do this you\ncan use the `Primus#spark` method.\n\n```js\n// Get a spark by its id\nvar spark = primus.spark(id);\n\nspark.write('message');\n```\n\nThis method returns a `Spark` or `undefined` if the given id doesn't match any\nof the active `Spark` ids on the server.\n\n### Destruction\n\nIn rare cases you might need to destroy the Primus instance you've created. You\ncan use the `primus.destroy()` or `primus.end()` method for this. This method\naccepts an Object which allows you to configure the destruction process:\n\n- `close` Close the HTTP server that Primus received. Defaults to `true`.\n- `reconnect` Automatically reconnect the clients. Defaults to `false`.\n- `timeout` Close all active connections and clean up the Primus instance after\n  the specified amount of timeout. Defaults to `0`.\n\nThe timeout is especially useful if you want gracefully shutdown your server but\nreally don't want to wait an infinite amount of time.\n\n```js\nprimus.destroy({ timeout: 10000 });\n```\n\n### Events\n\nPrimus is built upon the Stream and EventEmitter interfaces. This is a summary\nof the events emitted by Primus.\n\nEvent                 | Usage       | Location      | Description\n----------------------|-------------|---------------|----------------------------------------\n`outgoing::reconnect` | private     | client        | Transformer should reconnect.\n`reconnect scheduled` | **public**  | client        | We're scheduling a reconnect.\n`reconnect`           | **public**  | client        | Reconnect attempt is about to be made.\n`reconnected`         | **public**  | client        | Successfully reconnected.\n`reconnect timeout`   | **public**  | client        | Reconnect attempt took too much time.\n`reconnect failed`    | **public**  | client        | Failed to reconnect.\n`timeout`             | **public**  | client        | Failed to connect to server.\n`outgoing::open`      | private     | client/spark  | Transformer should connect.\n`incoming::open`      | private     | client/spark  | Transformer has connected.\n`open`                | **public**  | client        | Connection is open.\n`destroy`             | **public**  | client        | The instance has been destroyed.\n`incoming::error`     | private     | client        | Transformer received an error.\n`error`               | **public**  | client/spark  | An error happened.\n`incoming::data`      | private     | client/server | Transformer received data.\n`outgoing::data`      | private     | client/spark  | Transformer should write data.\n`data`                | **public**  | client/spark  | We received data.\n`incoming::end`       | private     | client/spark  | Transformer closed the connection.\n`outgoing::end`       | private     | client/spark  | Transformer should close connection.\n`end`                 | **public**  | client/spark  | The connection has ended.\n`close`               | **public**  | client/server | The connection has closed, we might reconnect. / The server has been destroyed.\n`connection`          | **public**  | server        | We received a new connection.\n`disconnection`       | **public**  | server        | We received a disconnection.\n`initialised`         | **public**  | server        | The server is initialised.\n`plugin`              | **public**  | server        | A new plugin has been added.\n`plugout`             | **public**  | server        | A plugin has been removed.\n`incoming::ping`      | private     | client        | We received a ping message.\n`outgoing::ping`      | private     | spark         | We're sending a ping message.\n`incoming::pong`      | private     | spark         | We received a pong message.\n`outgoing::pong`      | private     | client        | We're sending a pong message.\n`heartbeat`           | **public**  | spark         | We've received a response to a heartbeat.\n`online`              | **public**  | client        | We've regained a network connection.\n`offline`             | **public**  | client        | We've lost our internet connection.\n`log`                 | **public**  | server        | Log messages.\n`readyStateChange`    | **public**  | client/spark  | The readyState has changed.\n`outgoing::url`       | private     | client        | The options used to construct the URL.\n\nAs a rule of thumb assume that every event that is prefixed with `incoming::` or\n`outgoing::` is reserved for internal use only and that emitting such events your\nself will most likely result in chaos and destruction.\n\nTo make it easier for developers to emit events on Primus itself, we've added a\nsmall helper function that checks if the event you want to emit is reserved for\nPrimus only. This would be all `incoming::` and `outgoing::` prefixed events and\nthe events listed above. This method is called `\u003cclass\u003e.reserved()` and it's\nimplemented on the `Spark`:\n\n```js\nprimus.on('connection', function connection(spark) {\n  spark.on('data', function (data) {\n    //\n    // Just imagine that we receive an array of arguments from the client which\n    // first argument is the name of the event that we need to emit and the\n    // second argument are the arguments for function.\n    //\n    if (spark.reserved(data.args[0])) return;\n\n    spark.emit.apply(spark, data.args[0]);\n  });\n});\n```\n\nBut also the client:\n\n```js\nvar primus = new Primus('http://example.bar');\n\nprimus.on('data', function (data) {\n  if (primus.reserved(data.args[0])) return;\n\n  primus.emit.apply(primus, data.args);\n});\n```\n\nAnd of course the `Primus` instance as well.\n\n### Heartbeats and latency\n\nHeartbeats are used in Primus to figure out if we still have an active, working\nand reliable connection with the server. These heartbeats are sent from the\n**server** to the client as shown in the following diagram.\n\n```\n     client will disconnect\n       if not recv within\n          `pingTimeout`\n\n     primus:pong:{timestamp}\n    +----------------------+\n    |                      |\n+---v----+            +---------+\n| server |            |  client |\n+--------+            +----^----+\n    |                      |\n    +----------------------+\n     primus:ping:{timestamp}\n\n      sent at `pingInterval`\n      server will disconnect\n      if no response since\n           last ping\n```\n\nThe heartbeat message that we send over the connection is\n`primus::ping::\u003ctimestamp\u003e`. Upon receipt of this message, the client will send\nback a `primus::pong::\u003ctimestamp\u003e` message with the same `\u003ctimestamp\u003e` it\nreceived from the server.\nThis allows to calculate the latency between messages by simply getting\nthe `\u003ctimestamp\u003e` and comparing it with the local time.\n\n### Supported Real-time Frameworks\n\nThe following transformers/transports are supported in Primus:\n\n#### BrowserChannel\n\nBrowserChannel was the original technology that GMail used for their real-time\ncommunication. It's designed for same domain communication and does not use\nWebSockets. To use BrowserChannel you need to install the `browserchannel`\nmodule:\n\n```\nnpm install browserchannel --save\n```\n\nAnd tell `Primus` that you want to use `browserchannel` as transformer:\n\n```js\nvar primus = new Primus(server, { transformer: 'browserchannel' });\n```\n\nThe `browserchannel` transformer comes with built-in node client support and can be\naccessed using:\n\n```js\nvar Socket = primus.Socket\n  , socket = new Socket('url');\n```\n\nPlease note that you should use at least version `1.0.6` which contains support\nfor query strings.\n\n#### Engine.IO\n\nEngine.IO is the low level transport functionality of Socket.IO 1.0. It supports\nmultiple transports for creating a real-time connection. It uses transport\nupgrading instead of downgrading which makes it more resilient to blocking\nproxies and firewalls. To enable `engine.io` you need to install the `engine.io`\nmodule:\n\n```\nnpm install engine.io --save\n```\n\nAnd tell `Primus` that you want to use `engine.io` as transformer:\n\n```js\nvar primus = new Primus(server, { transformer: 'engine.io' });\n```\n\nIf you want to use the client interface inside of Node.js you also need to\ninstall the `engine.io-client`:\n\n```\nnpm install engine.io-client --save\n```\n\nAnd then you can access it from your server instance:\n\n```js\nvar Socket = primus.Socket\n  , socket = new Socket('url');\n```\n\n#### Faye\n\nFaye is a WebSocket only transformer. It uses the `faye-websocket` module which\nis part of the [Faye](http://faye.jcoglan.com/) project and supports all\nprotocol specifications. To use this you need to install the `faye-websocket`\nmodule:\n\n```\nnpm install faye-websocket --save\n```\n\nAnd tell `Primus` that you want to use `faye` as transformer:\n\n```js\nvar primus = new Primus(server, { transformer: 'faye' });\n```\n\nThe `faye` transformer comes with built-in node client support and can be\naccessed using:\n\n```js\nvar Socket = primus.Socket\n  , socket = new Socket('url');\n```\n\n#### SockJS\n\nSockJS is a real-time server that focuses on cross-domain connections and does\nthis by using multiple transports. To use SockJS you need to install the\n`sockjs` module:\n\n```\nnpm install sockjs --save\n```\n\nAnd tell `Primus` that you want to use `sockjs` as transformer:\n\n```js\nvar primus = new Primus(server, { transformer: 'sockjs' });\n```\n\nIf you want to use the client interface inside of Node.js you also need to\ninstall the `sockjs-client` module:\n\n```\nnpm install sockjs-client --save\n```\n\nAnd then you can access it from your server instance:\n\n```js\nvar Socket = primus.Socket\n  , socket = new Socket('url');\n```\n\n#### uws\n\nuws is a WebSocket only transformer. It uses the `uws` module which is probably\nthe fastest WebSocket server available in Node.js. To use uws you have to\ninstall the `uws` module:\n\n```\nnpm install uws --save\n```\n\nAnd tell `Primus` that you want to use `uws` as transformer:\n\n```js\nvar primus = new Primus(server, { transformer: 'uws' });\n```\n\nIf you want to use the client interface inside of Node.js you also need to\ninstall the `ws` module:\n\n```\nnpm install ws --save\n```\n\nAnd then you can access it from your server instance:\n\n```js\nvar Socket = primus.Socket\n  , socket = new Socket('url');\n```\n\n#### WebSockets\n\nIf you are targeting a high end audience or maybe just need something for\ninternal uses you can use a pure WebSocket server. This transformer uses the\npopular `ws` module which is battle tested and supports all protocol\nspecifications. To use WebSockets you need to install the `ws` module:\n\n```\nnpm install ws --save\n```\n\nAnd tell `Primus` that you want to use `WebSockets` as transformer:\n\n```js\nvar primus = new Primus(server, { transformer: 'websockets' });\n```\n\nThe `WebSockets` transformer comes with built-in node client support and can be\naccessed using:\n\n```js\nvar Socket = primus.Socket\n  , socket = new Socket('url');\n```\n\nAs you can see from the examples above, it doesn't matter how you write the name\nof the transformer, we just `toLowerCase()` everything.\n\n### Transformer inconsistencies\n\n- BrowserChannel does not give you access to the `remotePort` of the incoming\n  connection. So when you access `spark.address` the `port` property will be set\n  to `1337` by default.\n- BrowserChannel is the only transformer that does not support cross domain\n  connections.\n- BrowserChannel and SockJS are written in CoffeeScript and this can make\n  debugging harder when their internals fail.\n- Engine.IO and SockJS do not ship their client-side library with their server\n  side component. We're bundling a snapshot of these libraries inside of Primus.\n  We will always be targeting the latest version of these transformers when we\n  bundle the library.\n\n### Parsers\n\nIn addition to support different frameworks we've also made it possible to use\ncustom encoding and decoding libraries. We're using `JSON` by default but you\ncould also use `binary` or `EJSON` for example (but these parsers need to be\nsupported by Primus, so check out the parser folder for examples). To specify\nthe parser to use you can supply a `parser` configuration option:\n\n```js\nvar primus = new Primus(server, { parser: 'JSON' });\n```\n\nAll parsers have an `async` interface for error handling.\n\n### Middleware\n\nPrimus has two ways of extending the functionality. We have [plugins](#plugins)\nbut also support middleware. And there is an important difference between these.\nThe middleware layers allows you to modify the incoming requests **before** they\nare passed in to the transformers. Plugins allow you to modify and interact with\nthe sparks. The middleware layer is only run for the requests that are handled\nby Primus.\n\nWe support 2 kind of middleware, **async** and **sync** middleware. The main\ndifference between these kinds is that sync middleware doesn't require a\ncallback, it is completely optional. In Primus, we eat our own dog food. Various\nof components in Primus are implemented through middleware layers:\n\n- `cors`: Adds the Access Control headers.\n- `primus.js`: It serves our `primus.js` client file.\n- `spec`: It outputs the server specification (version, transformer, path).\n- `authorization`: Our authorization handler, which is implemented as a middleware.\n- `no-cache`: Add no-cache headers to every HTTP request.\n- `x-xss`: Add `X-XSS-Protection` headers to every HTTP request.\n\n#### Primus.use(name, fn, options, index)\n\nThe `primus.use` method is how you add middleware layers to your system. All\nmiddleware layers need to be named. This allows you to also enable, disable and\nremove middleware layers. The supplied function can either be a pre-configured\nfunction that is ready to answer request/response or an unconfigured\nmiddleware. An unconfigured middleware is a function with less then 2 arguments.\nWe execute this function automatically with `Primus` as context of the function\nand optionally, the options that got provided:\n\n```js\nprimus.use('name', function () {\n  var primus = this;\n\n  return function (req, res) {\n    res.end('foo');\n  }\n}, { foo: 'bar' });\n```\n\nAs you can see in the example above, we assume that you return the actual\nmiddleware layer. If you don't need any pre-configuration you can just supply\nthe function directly:\n\n```js\n// sync middleware\nprimus.use('name', function (req, res) {\n\n});\n\n// async middleware\nprimus.use('name', function (req, res, next) {\n  doStuff();\n});\n```\n\nYou need to be aware that these middleware layers are running for HTTP requests\nbut also for upgrade requests. Certain middleware layers should only run for\nHTTP or Upgrade requests. To make it possible you can add a `http` or `upgrade`\nproperty to the middleware function and set it to `false` if you don't want it\nto be triggered.\n\n```js\nprimus.use('name', function () {\n  function middleware(req, res, next) {\n\n  }\n\n  middleware.upgrade = false; // Don't run this middleware for upgrades\n\n  return middleware;\n});\n```\n\nBy default a new middleware layer is added after the previous one, but there\nare cases where you need to add a middleware at a specified index in\nthe stack. To accomplish this you can use the optional 0 based `index`\nargument.\n\n```js\n// add a middleware after the first two in the stack\nprimus.use('name', function (req, res) {\n\n}, 2);\n```\n\n#### Primus.remove(name)\n\nThis method allows you to remove configured middleware. This works\nfor the middleware layers that you added but also the middleware layers that we\nadd by default. If you want to use a different way to serve the `primus.js`\nfile you can simply:\n\n```js\nprimus.remove('primus.js');\n```\n\nAnd add your own middleware instead.\n\n#### Primus.disable(name)\n\nIn addition to removing middleware layers, it's also possible to disable them so\nthey are skipped when we iterate over the middleware layers. It might be useful\nto just disable certain middleware layers in production.\n\n```js\nprimus.disable('name');\n```\n\n#### Primus.enable(name)\n\nOf course, when you can disable middleware there also needs to be way to enable\nthem again. This is exactly what this method does. Re-enable a disabled\nmiddleware layer.\n\n```js\nprimus.enable('name');\n```\n\n### Plugins\n\nPrimus was built as a low level interface where you can build your applications\nupon. At it's core, it's nothing more than something that passes messages back\nand forth between the client and server. To make it easier for developers to\nswitch to Primus we've developed a simple but effective plugin system that\nallows you to extend Primus's functionality.\n\nPlugins are added on the server side in the form of an `Object`:\n\n```js\n//\n// Require a plugin directly.\n//\nprimus.plugin('name', require('metroplex'));\n\n//\n// Or supply it manually with the required object structure\n//\nprimus.plugin('name', {\n  server: function (primus, options) {},\n  client: function (primus, options) {},\n  library: 'client side library'\n});\n```\n\nOr you can pass the plugin `Object` directly into the constructor:\n\n```js\nvar primus = new Primus(server, { plugin: {\n  name: {\n    server: function (primus, options) {},\n    client: function (primus, options) {},\n    library: 'client side library'\n  }\n}})\n```\n\nAnd last but not least, you can also supply the constructor with a comma or\nspace separated list of plugin names which will be required automatically:\n\n```js\nvar primus = new Primus(server, { plugin: 'metroplex, primus-emit' })\n```\n\nTo remove added plugins you can use the `plugout` method:\n\n```js\nprimus.plugin('name', require('metroplex'));\nprimus.plugout('name'); // returns true/false indicating successful removal.\n```\n\nThe server function is only executed on the server side and receives 2\narguments:\n\n1. A reference to the initialised Primus server.\n2. The options that were passed in the `new Primus(server, { options })`\n   constructor. So the plugin can be configured through the same interface.\n\nThe client receives the same arguments:\n\n1. A reference to the initialised Primus client.\n2. The options that were passed in the `new Primus(url, { options })`\n   constructor. So the plugin can be configured through the same interface.\n\nThe only thing you need to remember is that the client is stored in the library\nusing `toString()` so it cannot have any references outside the client's\nclosure. But luckily, there's a `library` property that will also be included on\nthe client side when it's specified. The `library` property should be an\nabsolute path to the library file.\n\n#### Intercepting the `connection` events\n\nThe `connection` event is emitted using a `async` emitter. It checks if your\nsupplied event emitter function has extra callback function. When it detects\nthis it will wait with the execution of the other assigned listeners until the\ncallback has been called. Please note that the order of assigning event\nlisteners is still respected so if you've assigned a `connection` listener\nbefore an async connection listener it will still be executed first.\n\n```js\nprimus.on('connection', function (spark) {\n  console.log('first call, i have no spark.newproperty', spark.newproperty);\n});\n\nprimus.on('connection', function (spark, next) {\n  longrunningasynmethod(spark.query, function (err, data) {\n    spark.newproperty = data;\n\n    console.log('second call, i added the new property');\n    next(err);\n  });\n});\n\nprimus.on('connection', function (spark) {\n  console.log('third call, i can read the ', spark.newproperty);\n});\n```\n\nWhen an error argument is supplied it will automatically end the connection and\nemit an `error` event on the spark. If you are coming from Socket.IO 1.0 \u003e=,\nthis will basically work the same way as their middleware system.\n\n#### Extending the Spark / Socket\n\nThe server has a `.Spark` property that can be extended. This allows you to\neasily add new functionality to the socket. For example adding join room\nfunction would be as easy as:\n\n```js\nprimus.plugin('rooms', {\n  server: function (primus) {\n    var Spark = primus.Spark;\n\n    Spark.prototype.join = function () {\n      // implement room functionality.\n    };\n  }\n});\n```\n\n#### Transforming and intercepting messages\n\nIntercepting and transforming messages is something that a lot of plugins\nrequire. When you're building an `EventEmitter` plugin or something else you\nprobably don't want the default `data` event to be emitted but your custom\nevent. There are 2 different types of messages that can be transformed:\n\n1. `incoming` These messages are being received by the server.\n2. `outgoing` These messages are being sent to the client.\n\nThe transformer is available on both the client and the server and share, like\nyou would have expected the same identical API. Adding a new transformer is\nrelatively straightforward:\n\n```js\nprimus.transform('incoming', function (packet) {\n  //\n  // The packet.data contains the actual message that either received or\n  // transformed.\n  //\n\n  // This would transform all incoming messages to foo;\n  packet.data = 'foo';\n\n  // If you are handling the message and want to prevent the `data` event from\n  // happening, simply `return false` at the end of your function. No new\n  // transformers will be called, and the event won't be emitted.\n});\n```\n\nThese transformations can easily be done in the plugins:\n\n```js\nprimus.plugin('name', {\n  server: function (primus) {\n    primus.transform('outgoing', function (packet) {\n      packet.data = 'foo';\n    });\n\n    primus.transform('incoming', function (packet) {\n      if (packet.data === 'foo') packet.data = 'bar';\n    });\n  },\n\n  client: function (primus) {\n    primus.transform('outgoing', function (packet) {\n      packet.data = 'foo';\n    });\n\n    primus.transform('incoming', function (packet) {\n      if (packet.data === 'foo') packet.data = 'bar';\n    });\n  }\n});\n```\n\nWe also expose asynchronous interfaces for these transformers. If your function\naccepts 2 arguments we automatically assume it's async and that the last\nargument is the callback variable:\n\n```js\nprimus.transform('outgoing', function (packet, next) {\n  asyncprocess(packet.data, function (err, data) {\n    //\n    // If you return an error here, it will be emitted as `error` on the\n    // spark/client and no `data` event will be emitted.\n    //\n    if (err) return next(err);\n\n    //\n    // If you just wanted to ignore this message instead of emitting an error\n    // you can do:\n    //\n    if (err) return next(undefined, false);\n\n    //\n    // To update the data, just re-assign the `data` property on the packet you\n    // received and call the next callback.\n    //\n    packet.data = data;\n    next();\n  });\n});\n```\n\n#### Primus project plugins\n\nThe following plugins are part of the Primus project.\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/primus/fortress-maximus\"\u003efortess-maximus\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003e\n    Fortress Maximus validates every incoming message on your Primus server as all\n    user input should be seen as a potential security risk.\n  \u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/fortress-maximus\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/fortress-maximus.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\u003ca href=\"https://github.com/primus/fortress-maximus/actions?query=workflow%3ACI+branch%3Amaster\"\u003e\u003cimg\n      src=\"https://img.shields.io/github/actions/workflow/status/primus/fortress-maximus/ci.yml?branch=master\u0026label=CI\u0026style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/primus/metroplex\"\u003emetroplex\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003e\n    Metroplex is a Redis based spark/connection registry for Primus. It stores\n    the sparks and their server address. So you can cluster multiple primus's\n    together with Metroplex and Omega Supreme\n  \u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/metroplex\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/metroplex.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\u003ca href=\"https://github.com/primus/metroplex/actions?query=workflow%3ACI+branch%3Amaster\"\u003e\u003cimg\n      src=\"https://img.shields.io/github/actions/workflow/status/primus/metroplex/ci.yml?branch=master\u0026label=CI\u0026style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/primus/mirage\"\u003emirage\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003e\n    Mirage generates and validates persistent session IDs.\n  \u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/mirage\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/mirage.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\u003ca href=\"https://github.com/primus/mirage/actions?query=workflow%3ACI+branch%3Amaster\"\u003e\u003cimg\n      src=\"https://img.shields.io/github/actions/workflow/status/primus/mirage/ci.yml?branch=master\u0026label=CI\u0026style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/primus/omega-supreme\"\u003eomega-supreme\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003e\n    Omega Supreme allows you to broadcast messages to Primus using a regular\n    HTTP request. These messages can be broacasted to every spark, single spark\n    or a collection of sparks.\n  \u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/omega-supreme\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/omega-supreme.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\u003ca href=\"https://github.com/primus/omega-supreme/actions?query=workflow%3ACI+branch%3Amaster\"\u003e\u003cimg\n      src=\"https://img.shields.io/github/actions/workflow/status/primus/omega-supreme/ci.yml?branch=master\u0026label=CI\u0026style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/primus/primus-analytics\"\u003eprimus-analytics\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003e\n    Integrates Primus with Google Analytics.\n  \u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/primus-analytics\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/primus-analytics.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\u003ca href=\"https://github.com/primus/primus-analytics/actions?query=workflow%3ACI+branch%3Amaster\"\u003e\u003cimg\n      src=\"https://img.shields.io/github/actions/workflow/status/primus/primus-analytics/ci.yml?branch=master\u0026label=CI\u0026style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/primus/primus-emit\"\u003eprimus-emit\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003e\n    The emit module adds client -\u003e server and server -\u003e client event emitting to Primus.\n  \u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/primus-emit\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/primus-emit.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\u003ca href=\"https://github.com/primus/primus-emit/actions?query=workflow%3ACI+branch%3Amaster\"\u003e\u003cimg\n      src=\"https://img.shields.io/github/actions/workflow/status/primus/primus-emit/ci.yml?branch=master\u0026label=CI\u0026style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/primus/substream\"\u003esubstream\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003e\n    Substream is an opinionated but stream compatible connection multiplexer on\n    top of the Primus connections. These streams can be created without\n    pre-defining them on the server or client.\n  \u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/substream\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/substream.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\u003ca href=\"https://github.com/primus/substream/actions?query=workflow%3ACI+branch%3Amaster\"\u003e\u003cimg\n      src=\"https://img.shields.io/github/actions/workflow/status/primus/substream/ci.yml?branch=master\u0026label=CI\u0026style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n#### Community plugins\n\nThese are also plugins created by our amazing community. If you want your module\nto be listed here, please open a pull request.\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/Shopetti/backbone.primus\"\u003ebackbone.primus\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003eBind primus.io events to backbone models and collections.\u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://travis-ci.org/Shopetti/backbone.primus\"\u003e\u003cimg\n      src=\"https://img.shields.io/travis/Shopetti/backbone.primus/master.svg?style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003cdl\u003e\n  \u003cdt\u003e\n    \u003ca href=\"https://github.com/latentflip/hapi_primus_sessions\"\u003e\n      hapi_primus_sessions\n    \u003c/a\u003e\n  \u003c/dt\u003e\n  \u003cdd\u003e\n    A hapi and primus plugin which extends primus' spark with a `getSession(cb)`\n    method which returns the current hapi session object.\n  \u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/hapi_primus_sessions\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/hapi_primus_sessions.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/lemonde/primus-cluster\"\u003eprimus-cluster\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003eScale Primus across multiple servers or with node cluster.\u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/primus-cluster\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/primus-cluster.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\u003ca href=\"https://github.com/lemonde/primus-cluster/actions?query=workflow%3ACI+branch%3Amain\"\u003e\u003cimg\n      src=\"https://img.shields.io/github/actions/workflow/status/lemonde/primus-cluster/ci.yml?branch=main\u0026label=CI\u0026style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/cayasso/primus-emitter\"\u003eprimus-emitter\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003eA module that adds emitter capabilities to Primus.\u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/primus-emitter\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/primus-emitter.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\u003ca href=\"https://travis-ci.org/cayasso/primus-emitter\"\u003e\u003cimg\n      src=\"https://img.shields.io/travis/cayasso/primus-emitter/master.svg?style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/zemirco/primus-express-session\"\u003eprimus-express-session\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003eShare a user session between Express and Primus.\u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/primus-express-session\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/primus-express-session.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\u003ca href=\"https://travis-ci.org/zemirco/primus-express-session\"\u003e\u003cimg\n      src=\"https://img.shields.io/travis/zemirco/primus-express-session/master.svg?style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/cayasso/primus-multiplex\"\u003eprimus-multiplex\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003eA module that adds multiplexing capabilities to Primus.\u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/primus-multiplex\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/primus-multiplex.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\u003ca href=\"https://travis-ci.org/cayasso/primus-multiplex\"\u003e\u003cimg\n      src=\"https://img.shields.io/travis/cayasso/primus-multiplex/master.svg?style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/mmalecki/primus-redis\"\u003eprimus-redis\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003e\n    primus-redis is a Redis store for Primus. It takes care of distributing\n    messages to other instances using Redis Pub/Sub.\n  \u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/primus-redis\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/primus-redis.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\u003ca href=\"https://travis-ci.org/mmalecki/primus-redis\"\u003e\u003cimg\n      src=\"https://img.shields.io/travis/mmalecki/primus-redis/master.svg?style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/mmalecki/primus-redis-rooms\"\u003eprimus-redis-rooms\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003e\n    primus-redis-rooms is a Redis store for Primus and primus-rooms.\n  \u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/primus-redis-rooms\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/primus-redis-rooms.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\u003ca href=\"https://travis-ci.org/mmalecki/primus-redis-rooms\"\u003e\u003cimg\n      src=\"https://img.shields.io/travis/mmalecki/primus-redis-rooms/master.svg?style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/cayasso/primus-resource\"\u003eprimus-resource\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003e\n    Define resources with auto-bound methods that can be called remotely on top of Primus.\n  \u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/primus-resource\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/primus-resource.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\u003ca href=\"https://travis-ci.org/cayasso/primus-resource\"\u003e\u003cimg\n      src=\"https://img.shields.io/travis/cayasso/primus-resource/master.svg?style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/swissmanu/primus-responder\"\u003eprimus-responder\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003eClient and server plugin that adds a request/response cycle to Primus.\u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/primus-responder\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/primus-responder.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\u003ca href=\"https://travis-ci.org/swissmanu/primus-responder\"\u003e\u003cimg\n      src=\"https://img.shields.io/travis/swissmanu/primus-responder/master.svg?style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/cayasso/primus-rooms\"\u003eprimus-rooms\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003e\n    A module that adds rooms capabilities to Primus. It's based on the rooms\n    implementation of Socket.IO.\n  \u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/primus-rooms\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/primus-rooms.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\u003ca href=\"https://travis-ci.org/cayasso/primus-rooms\"\u003e\u003cimg\n      src=\"https://img.shields.io/travis/cayasso/primus-rooms/master.svg?style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/fadeenk/primus-rooms-redis-adapter\"\u003eprimus-rooms-redis-adapter\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003e\n    A redis adapter for primus-rooms module. Supports integration with metroplex and omega-supreme.\n  \u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/primus-rooms-redis-adapter\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/primus-rooms-redis-adapter.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\u003ca href=\"https://travis-ci.org/fadeenk/primus-rooms-redis-adapter\"\u003e\u003cimg\n      src=\"https://img.shields.io/travis/fadeenk/primus-rooms-redis-adapter/master.svg?style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/Fishrock123/primus-spark-latency\"\u003eprimus-spark-latency\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003eAdds a latency property to primus sparks server-side.\u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://www.npmjs.com/package/primus-spark-latency\"\u003e\u003cimg\n      src=\"https://img.shields.io/npm/v/primus-spark-latency.svg?style=flat-square\"\n      alt=\"NPM version\" /\u003e\u003c/a\u003e\u003ca href=\"https://travis-ci.org/Fishrock123/primus-spark-latency\"\u003e\u003cimg\n      src=\"https://img.shields.io/travis/Fishrock123/primus-spark-latency/master.svg?style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n### Community\n\nDeployed Primus to production or built an awesome demo using the technology?\nWe've set up a special [wiki] page for it where you can show your awesome\ncreations or learn from demo and example applications how to use Primus.\nCheckout the wiki page at:\n\nhttps://github.com/primus/primus/wiki/Production\n\n[wiki]: https://github.com/primus/primus/wiki\n\n### FAQ\n\n#### What is the best way to scale Primus\n\nScaling Primus is as simple as sticking it behind a load balancer that supports\n[sticky sessions](https://github.com/primus/primus/issues/147) and run multiple\nversions of your application. This is a vital feature that your load balancer\nneeds to support. This ensures that the incoming requests always go back to the\nsame server. If your load balancer does not support sticky sessions, get another\none. I highly recommend [HAProxy](http://www.haproxy.org/). According to my own\ntesting it is the fastest and best proxy available that supports WebSockets. See\nhttps://github.com/observing/balancerbattle for more detailed information.\n\nThe reason for which sticky-sessions are so important is that a lot of frameworks\nthat use polling transports require to save a state in the node process in order\nto work correctly. This state contains times, sessions ids, handshake data etc.\nIf a request from the same client does not enter the same node process it will\nbe treated as an `unknown` request and your real-time connection will be closed.\n\nIf you want more advanced scaling and messaging please take a look at the various\nplugins we've written for this scope. Plugins like metroplex, omega-supreme and\nprimacron can be time savers.\n\n#### Can I use cluster?\n\n\u003e Note: The following only applies to websocket emulation transformers like\n\u003e sockjs or engine.io. If you are using `ws`, `uws` or `faye-websocket`, there\n\u003e is no need for sticky sessions, and thus no issue.\n\nThe `cluster` module that ships with Node.js does not implement sticky sessions.\n\nThere are projects like `stick-session` which attempt to implement\nsticky-sessions in cluster, but the problem with this specific approach is that\nit uses the `remoteAddress` of the connection. For some people this isn't a\nproblem but when you add this behind a load balancer the remote address will be\nset to the address of the load balancer that forwards the requests. So all in all\nit only causes more scalability problems instead of solving them. This is why\nwe've opted to warn people about the risks of `cluster` when we detect that the\nPrimus library is run in a worker environment. **USE IT AT YOUR OWN RISK**.\n\nTo turn off the cluster warning in your Primus instance you can set the option\n`iknowclusterwillbreakconnections` to `true`.\n\n#### How do I use Primus with Express\n\nExpress' `express()` instance isn't a valid HTTP server. In order to make it\nwork with `Primus` and other real-time transformers you need to feed the instance\nto a real `http` server and supply this server. See example below:\n\n```js\n'use strict';\n\nvar express = require('express')\n  , Primus = require('primus')\n  , app = express();\n\n//\n// Do your express magic.\n//\n\nvar server = require('http').createServer(app)\n  , primus = new Primus(server, { options });\n\nserver.listen(port);\n```\n\n#### Is require.js supported\n\nRequire.js is supported to a certain degree. The `primus.js` core file should be\ncompatible with require.js but it could be that the transformer of your choosing\nisn't compatible with require.js. For example `engine.io` uses `component` which\nintroduces it's own `require` function that causes issues. In addition to that,\nthere are plugins which might use these modules that break require.js. The\ngeneral advice for this is to drop require.js in favour of plain script loading\nor use of browserify where possible. If you feel strong about require.js we accept\npull requests that improve this behaviour or helps us save guard against these\nissues.\n\n#### Can I send custom headers to the server\n\nIt is not possible to send custom headers from the client to the server. This is\nbecause these headers need to be set by the actual transports that the\ntransformers are using. The only transport that would support this would be AJAX\npolling. To send custom data to the server use a query string in your connection\nURL, as this is something that all transports support.\n\n```js\nvar primus = new Primus('http://localhost:8080/?token=1\u0026name=foo');\n```\n\n### Versioning\n\n#### History\n\nYou can discover the version history and change logs on the\n[Releases](https://github.com/primus/primus/releases) page\n\n#### Convention\n\nAll `0.x.x` releases should be considered unstable and not ready for production.\nThe version number is laid out as: `major.minor.patch` and tries to follow\nsemver as closely as possible but this is how we use our version numbering:\n\n\u003cdl\u003e\n  \u003cdt\u003emajor\u003c/dt\u003e\n  \u003cdd\u003e\n    \u003cp\u003e\n      A major and possible breaking change has been made in the primus core.\n      These changes are not backwards compatible with older versions.\n    \u003c/p\u003e\n  \u003c/dd\u003e\n  \u003cdt\u003eminor\u003c/dt\u003e\n  \u003cdd\u003e\n    \u003cp\u003e\n      New features are added or a big change has happened with one of the\n      real-time libraries that we're supporting.\n    \u003c/p\u003e\n  \u003c/dd\u003e\n  \u003cdt\u003epatch\u003c/dt\u003e\n  \u003cdd\u003e\n    \u003cp\u003e\n      A bug has been fixed, without any major internal and breaking changes.\n    \u003c/p\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n#### Release cycle\n\nThere isn't a steady or monthly release cycle. We usually release a new version\nwhen:\n\n1. A critical bug is discovered.\n2. There have been a lot of minor changes.\n3. A framework did an incompatible update.\n4. A new framework is added.\n5. People ask for it.\n\n### Other languages\n\nThese projects are maintained by our valuable community and allow you to use\nPrimus in a different language than JavaScript:\n\n\u003cdl\u003e\n  \u003cdt\u003e\u003ca href=\"https://github.com/seegno/primus-objc\"\u003eprimus-objc\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003e\n    A client written in Objective-C for the Primus real-time framework with\n    initial support for web sockets (via SocketRocket) and socket.io (via\n    socket.IO-objc). Easily switch between different real-time Objective-C\n    frameworks without any code changes.\n  \u003c/dd\u003e\n  \u003cdd\u003e\n    \u003ca href=\"https://travis-ci.org/seegno/primus-objc\"\u003e\u003cimg\n      src=\"https://img.shields.io/travis/seegno/primus-objc/master.svg?style=flat-square\"\n      alt=\"Build Status\" /\u003e\u003c/a\u003e\n  \u003c/dd\u003e\n\n  \u003cdt\u003e\u003ca href=\"https://github.com/cine-io/primus-android\"\u003eprimus-android\u003c/a\u003e\u003c/dt\u003e\n  \u003cdd\u003e\n    A Primus client written in Java for Android with\n    initial support for web sockets via \u003ca href=\"https://github.com/koush/AndroidAsync\"\u003eAndroidAsync\u003c/a\u003e.\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\nWant to have your project listed here? Add it using a pull-request!\n\n#### Protocol\n\nPrimus uses some internal protocol messages in order to keep the connection open\nand stable between a client and a server. If you are planning on implementing\nPrimus in another language you must handle the following `primus::*` prefixed\nmessages:\n\n- `primus::ping::\u003cping\u003e` **server -\u003e client**, The ping type contains the time\n  in EPOCH. Ping messages are needed to keep the connection open as certain load\n  balancers, proxies and browsers will close connections automatically when\n  there is inactivity.\n- `primus::pong::\u003cping\u003e` **client -\u003e server**, The pong is the response to the\n  `ping` packet. It echoes back the exact value that it received.\n- `primus::server::close` **server -\u003e client**, Indication that the server\n  intentionally closed the connection and that no reconnection/connection should\n  be made.\n- `primus::id::` **client -\u003e server**, Request of the internal `spark.id`\n  that's assigned to the connection.\n- `primus::id::\u003cspark.id\u003e` **server -\u003e client**, The internal `id` that we used\n  on the server to identify the connection as we do not sync this information by\n  default and requires a `primus.id()` call on the client.\n\nAny other message that is prefixed with `primus::` should be ignored and not\nemitted to the user.\n\n### License\n\n[MIT](LICENSE)\n","funding_links":[],"categories":["Packages","JavaScript","Repository","包","目录","Real-time","websocket","framework"],"sub_categories":["Real-time","实时","即时通信"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprimus%2Fprimus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprimus%2Fprimus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprimus%2Fprimus/lists"}