# Pixie


## Pixie is a [Faye]( compatible Bayeux implementation

Pixie is inspired by [Faye]( and was originally
planned as a port, but has diverged significantly as I've learned the Erlang
way of modelling these sorts of problems.

# Heroku Add-on

If you're planning on running Faye on Heroku you're probably going to have a
bad time.  Take a look at [MessageRocket]( as an
alternative, and help support the author to maintain more great open source

## License

Pixie is Copyright (c) 2015 James Harton and licensed under the terms of
the MIT Public License (see the LICENSE file included with this distribution
for more details).

## Installation

Add `pixie` to your dependencies in the `mix.exs` file:

def deps do
  # ...
  {:pixie, "~> 0.1.3"}
  # ...

Also to the `application` section of your `mix.exs` file:

def application do
    applications: [
      # ...
      # ...

Then use `mix deps.get` to download Pixie from [hex](

## Status

Pixie is still pre 1.0, however it works and is compatible with the
popular [Faye]( JavaScript and Ruby clients.

Pixie is used in production at [MessageRocket]( to
handle relatively large message loads.  Development is mostly guided by the
needs of MessageRocket, however pull requests and issues are gratefully

## Features

  - Compatible with Faye JavaScript and Ruby clients.
  - Supports both in-memory (ETS) and clustered (Redis) backends.
  - Handles all Bayeux message types.
  - Handles all Bayeux features except service channels.
  - Handles the following connection types:
      - long-polling
      - cross-origin-long-polling
      - callback-polling
      - websocket

## Usage

Once you have pixie installed in your project you can run a stand alone-server
with `mix pixie.server`.

### Configuration

The configuration options and their defaults are shown here:

# This is the default backend configuration, you don't need to set it.
config :pixie, :backend,
  name: :ETS

# If you want to use Redis for clustering. The Redis backend defaults to
# localhost, unless you specify it here.
config :pixie, :backend,
  name: :Redis,
  redis_url: "redis://localhost:6379"

# When clients subscribe to channels we don't have to respond immediately, and
# can instead wait until there is a message to be sent on that channel or a
# heartbeat timeout expires, whichever happens first.
# Setting this option to true means that subscriptions are responded to
# which *may* increase time to first message for those not using websockets.
config :pixie, :subscribe_immediately, false

# Add extensions to be loaded at startup:
config :pixie, :extensions, [My.Extension.Module.Name]

# Add monitors to be loaded at startup:
config :pixie, :monitors, [
  # ... or ...
  {My.Monitor.Module.Name, [some_arg]}

# Explicitly configure transports available to clients:
config :pixie, :enabled_transports, ~w| long-polling cross-origin-long-polling callback-polling websocket |

### Using with Phoenix

You can add Pixie as a custom dispatcher rule for Phoenix with Cowboy by adding
the following to your application configuration:

config :myapp, MyApp.Endpoint,
  http: [
    dispatch: [
      {:_, [
        {"/pixie", Pixie.Adapter.Cowboy.HttpHandler, {Pixie.Adapter.Plug, []}},
        {:_,       Plug.Adapters.Cowboy.Handler,     {MyApp.Endpoint, []}}

Obviously, you can change `"/pixie"` to any path you wish.

### Sending messages from the server

You can publish messages from within the server using `Pixie.publish`.

Pixie.publish "/my/channel", %{message: "Pixie is awesome!"}

### Receiving messages from the server

You can subscribe to a channel and receive messages on that channel using

{:ok, pid} = Pixie.subscribe "/my/channel", fn (message, _pid)->
  IO.puts "Received message: #{inspect message}"

A separate worker process is created for each subscription, and it's pid is
both returned from the `subscribe` call, but also passed as the second argument
into the callback function, which means that you can do things like receive a
single message, then unsubscribe:

Pixie.subscribe "/only_one_message", fn(message, pid)->
  IO.puts "Received message: #{inspect message}"
  Pixie.unsubscribe pid

Either way, you can use `Pixie.unsubscribe pid` to unsubscribe and terminate
the subscription process.

### Writing extensions

Pixie supports extensions which allow you to modify messages as they come into
the server.  You can write your own module and use the `Pixie.Extension`
behaviour.  Your extension needs only implement two functions:

  - `incoming %Pixie.Event{}` which returns a (possibly) modified event.
  - `outgoing %Pixie.Message.Publish{}` which returns a (possibly) modified

The `Pixie.Event` struct contains the following fields:

  - `client_id`: The ID of the Client.  You can use this to find `Pixie.Client`
                 and `Pixie.Transport` processes should you need to.
  - `message`:   The incoming message from the client. Messages are represented
    - `%Pixie.Message.Handshake{}`:   A client handshake request.
    - `%Pixie.Message.Connect{}`:     A client connection request.
    - `%Pixie.Message.Subscribe{}`:   A subscription request.
    - `%Pixie.Message.Publish{}`:     A message to be published by the user.
    - `%Pixie.Message.Unsubscribe{}`: An unsubscription request.
    - `%Pixie.Message.Disconnect{}`:  A client disconnection request.
  - `response`:  The response to be sent back to the client.  You can use the
                 functions in `Pixie.Protocol.Error` (automatically imported
                 for you) or you can modify the response directly.

The details of all these structs should be available on

You can configure Pixie to load your extensions at start-up (as per the
configuration section above) or you can add and remove them at runtime.

Pixie.ExtensionRegistry.register MyExtension

# ... and ...

Pixie.ExtensionRegistry.unregister MyExtension

### Writing Monitors

Pixie provides monitoring functionality which allows you to subscribe to events
which are happennings in the system.

Provided events are:

  - Client created.
  - Client destroyed.
  - Channel created.
  - Channel destroyed.
  - Client subscribed to channel.
  - Client unsubscribed from channel.
  - Message received for publication.
  - Message delivered to receiving client.

All events also receive a [Timex]( timestamp
recording the time at which they were generated - as there are potentially
a lot of them and they may sit in a process mailbox for some time.

You can use the `Pixie.Monitor` behaviour to define your event handler:

defmodule MyMonitor do
  use Pixie.Monitor

  def created_channel channel_name, at do "Channel \#\{channel_name} created at \#\{format at}"

  def destroyed_channel channel_name, at do "Channel \#\{channel_name} destroyed at \#\{format at}"

  defp format timestamp do
      |> Date.from(:timestamp)
      |> DateFormat.format!("{UNIX}")

Or you can use your own `GenEvent` handler, if the monitor API doesn't work
for you.

You can find more information in the [documentation](

## Running the tests

Run `mix espec`.

## Contributing

1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Added some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request