Giter Club home page Giter Club logo

incus's Introduction

Incus Build Status Coverage Status

incus

Middleware for distributing messages via websockets, long polling, and push notifications

Features

  • Websocket authentication and management
  • Long Poll fall back
  • iOS push notifications support through APNS
  • Android push notifications support through GCM
  • Routing messages to specific phone, authenticated user, or webpage url
  • Configurable option for allowing users to send messages to other users
  • Redis pub/sub and Redis List support for sending messages from an application
  • SSL support
  • Stats logging

Usage

diagram

Front-end bindings

JavaScript: incus.js

The incus.js front-end npm browserified module is provided for consuming WebSocket events in the Browser or server-side. Self-contained, minified downloads are also available.

Application to a web browser

UID is a unique identifier for the user. It can be anywhere from an auto incremented ID to something more private such as a session id or OAuth token. If messages to users should be private from other users, then you should consider the UID a shared secret between the user and the server.

To send events to Incus from your webapp you need to publish a json formated string to a Redis pub/sub channel that Incus is listening on. This channel key can be configured but defaults to Incus. The json format is as follows:

{
    "command" : {
        "command" : string (message|setpage),
        "user"    : (optional) string -- Unique User ID,
        "page"    : (optional) string -- page identifier
    },
    "message" : {
        "event" : string,
        "data"  : object,
        "time"  : int
    }
}

the command is used to route the message to the correct user.

  • if user and page are both unset the message object will be sent to all users
  • if both user and page are set the message object will be sent to that user on that page
  • if just user is set, the message object will be sent to all sockets owned by the user identified by UID
  • if just page is set, the message object will be sent to all sockets whose page matches the page identifier

Push notifications

To send push notifications from your app, you need to push a json formated string to a Redis list. The list key is configurable but defaults to Incus_Queue

Android and iOS have slightly different schemas for sending push notifications.

iOS:

{
    "command" : {
        "command"      : "push",
        "push_type"    : "ios",
        "device_token" : string -- device token registered with APNS,
        "build"        : string -- build environment (store|beta|enterprise|development)
    },
    "message" : {
        "event" : string,
        "data"  : {
            "badge_count": optional int,
            "message_text": string,
            ...,
        },
        "time"  : int
    }
}

Notes:

  • At this time, dictionary APNS alerts are not supported.

Android:

Multiple registration ids can be listed in the same command

{
    "command" : {
        "command"          : "push",
        "push_type"        : "android",
        "registration_ids" : string -- one or more registration ids separated by commas
    },
    "message" : {
        "event" : string,
        "data"  : object,
        "time"  : int
    }
}

Presence-based message routing

{
    "command" : {
        "command": "pushormessage",
        "user": string -- Unique User ID,
        "device_token": string -- device token registered with APNS,
        "build": string -- build environment (store|beta|enterprise|development)
        "registration_ids": string -- one or more registration ids separated by commas
    },
    "message" : {
        "push": {
            "ios": {
                "badge_count": optional int,
                "message_text": string,
                ...
            },
            "android": {
                ...
            }
        },
        "websocket": {
            ...
        }
        "time": int
    }
}

APNS and GCM errors

Incus does not interact with the APNS Feedback Service. You should follow the APNS' guidelines on failed push attempts. They require querying their feedback service daily to find bad device tokens.

The GCM service does not offer a feedback service. When a push fails, Incus will add all relevant information to an error list in Redis (defaults to Incus_Android_Error_Queue). This should be used to remove bad registration ids from your app.

Installation

Method 1: Docker

  • Install Docker

  • Create a folder to share with Docker container:

mkdir -p ~/incus
  • Download configuration file and edit it at will:
wget https://raw.githubusercontent.com/Imgur/incus/master/config.yml -O ~/incus/config.yml
  • Start an instance of Redis (optional), skip it if you run your own Redis instance:
docker run -d --name incusredis redis

Start Incus:

docker run -i --name incus -p 4000:4000 --net="host" -v ~/incus:/etc/incus imgur/incus 

To stop Incus run:

docker stop incus

To run it again simply:

docker run incus

Method 2: Source

Install GO: https://golang.org/doc/install

Clone the repo:

mkdir $GOPATH/src/github.com/Imgur/
cd $GOPATH/src/github.com/Imgur/
git clone [email protected]:Imgur/incus.git

To Install:

cd $GOPATH/src/github.com/Imgur/incus
go get -v ./...
go install -v ./incus
cp $GOPATH/bin/incus /usr/sbin/incus
cp scripts/initd.sh /etc/init.d/incus
mkdir /etc/incus
cp config.yml /etc/incus/config.yml
touch /var/log/incus.log

Starting, Stopping, Restarting incus:

sudo /etc/init.d/incus start
sudo /etc/init.d/incus stop
sudo /etc/init.d/incus restart

Configuration

Incus needs to be restarted after any configuration change.

CLIENT_BROADCASTS

true

Clients may send messages to other clients

false

Clients may not send messages to other clients.

Default: true


LISTENING_PORT

This value controls the port that Incus binds to (TCP).

Default: 4000


CONNECTION_TIMEOUT (unstable)

This value controls how long TCP connections are held open for.

0

Connections are held open forever.

anything else

Connections are held open for this many seconds.

Default: 0


LOG_LEVEL

debug

All messages, including errors and debug are printed to standard output.

error

Only errors are printed to standard output.

Default: debug


REDIS_PORT_6379_TCP_ADDR

This value controls the TCP address (or hostname) to connect to Redis.

Note: The variable name is always REDIS_PORT_6379_TCP_ADDR even if the port is not 6379.

Default: 127.0.0.1


REDIS_PORT_6379_TCP_PORT

This value controls the TCP port to connect to Redis.

Note: The variable name is always REDIS_PORT_6379_TCP_PORT even if the port is not 6379.

Default: 6379


REDIS_MESSAGE_CHANNEL

This value controls the Redis PubSub channel to use.

Default: Incus


TLS_ENABLED

This value controls whether the server will also listen on a TLS-enabled port.

false

TLS is disabled, so the server will only listen over its insecure port.

true

TLS is enabled, so the socket will listen over both its insecure port and its TLS-enabled secure port.

Default: false


TLS_PORT

This value controls what TCP port is exposed when using TLS

Default: 443


CERT_FILE

This value controls what X.509 certificate is offered to clients connecting on the TLS port. The certificate is expected in PEM format. The value is a path name resolved relative to the working directory of Incus.

Default: cert.pem


KEY_FILE

This value controls what X.509 private key is used for decrypting the TLS traffic. The key is expected in PEM format.

Default: key.pem


APNS_ENABLED

This value controls whether the server will listen for and send iOS push notifications

false

APSN is disabled, the server will not listen for iOS push notifications

true

APNS is enabled, the server will listen for and send iOS push notifications

Default: false


APNS_[BUILD]_CERT

Where [BUILD] is one of: DEVELOPMENT, STORE, ENTERPRISE, or BETA

This value controls what APNS granted cert the server will use when calling the APNS API. Each build environment has its own instance of this configuration variable.

Default: myapnsappcert.pem


APNS_[BUILD]_PRIVATE_KEY

Where [BUILD] is one of: DEVELOPMENT, STORE, ENTERPRISE, or BETA

This value controls what APNS granted private key the server will use when calling the APNS API. Each build environment has its own instance of this configuration variable.

Default: myapnsappprivatekey.pem


APNS_[BUILD]_URL

Where [BUILD] is one of: DEVELOPMENT, STORE, ENTERPRISE, or BETA

This value controls what APNS url is used when calling the APNS API. Each build environment has its own instance of this configuration variable.

Default: gateway.push.apple.com:2195

APNS_DEVELOPMENT_URL defaults to gateway.sandbox.push.apple.com:2195


IOS_PUSH_SOUND

This value controls what sound plays on push notification receive.

Default: bingbong.aiff


GCM_ENABLED

This value controls whether the server will listen for and send Android push notifications

false

GCM is disabled, the server will not listen for Android push notifications

true

GCM is enabled, the server will listen for and send Android push notifications

Default: false


GCM_API_KEY

This is the GCM granted api key used for calling the GCM API.

Default: foobar


ANDROID_ERROR_QUEUE

This value controls where Android push errors are stored for later retrieval.

Default: Incus_Android_Error_Queue

incus's People

Contributors

alanimgur avatar briankassouf avatar ecto avatar jacobgreenleaf avatar jasdev avatar mburst avatar readmecritic avatar samuelebistoletti avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

incus's Issues

Update docker

Is there a recommended way of updating the docker image (on my end) I have not used it very much so no idea how I can follow the latest release from Incus

Allow AlertDictionary for ios

I would like to add support for AlertDictionary and more keys from the Payload that is used now. Any thoughts on how to handle this? Use one of them based on keys used or a key we add to the command (probably the best way) or ...
I can do a PR right away

Websockets not working

I am using incusjs to connect to incus on the client side (where you should really do either poll or websocket and not abort the poll when websocket comes through, this leaves Incus thinking there are 2 connections while this is not true if you are open I will do a PR for this)

I am using this command

{
    "command": {
        "command": "pushormessage",
        "user": "user1"
    },
    "message": {
        "time": 0,
        "websocket": {
            "event": "test",
            "data": {...},
            "time": 0
        }
    }
}

And I am doing both (normally only lpush needed right?)

redis.publish('Incus', JSON.stringify(command));
redis.lpush('Incus_Queue', JSON.stringify(command));

but none seem to trigger Incus to use the websocket

When long polling we need to buffer commands

When commands are received for a client that is longpolling, then we need to buffer commands that arrive between when the message is sent to the longpoller, and when they reconnect. For example,

t=0, A connects via longpoll
t=100, message is received by A's long poller, and A's long poller disconnects
t=101, message is received by Incus for A, but is dropped because there is no client for A
t=102, A connects via longpoll

Instead, we need a threshold (preferably in time-units rather than absolute number of messages) buffer:

t=0, A connects via longpoll. 
t=100, message is received by A's long poller, and A's long poller disconnects
t=101, message is received by Incus for A, and is placed into a buffer
t=102, A connects via longpoll, and a pending message is dispatched, and A's long poller disconnects.
t=104, A connects via longpoll.

Incus crashes on websocket disconnect

I am trying to get this working with websockets but sometimes during testing when reloading my webpage this happens

2015/08/31 10:17:18 Error: websocket: close 1001 
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x68 pc=0x45e034]

goroutine 21 [running]:
github.com/Imgur/incus.(*RedisStore).MarkInactive(0x0, 0xc20800ada0, 0x5, 0xc20800b0a8, 0x1, 0x0, 0x0)
    /go/src/github.com/Imgur/incus/redis_store.go:211 +0x144
github.com/Imgur/incus.(*Socket).Close(0xc208010310, 0x0, 0x0)
    /go/src/github.com/Imgur/incus/sockets.go:85 +0x111
created by github.com/Imgur/incus.(*Socket).listenForMessages
    /go/src/github.com/Imgur/incus/sockets.go:147 +0x1df

goroutine 1 [IO wait, 2 minutes]:
net.(*pollDesc).Wait(0xc208010610, 0x72, 0x0, 0x0)
    /usr/src/go/src/net/fd_poll_runtime.go:84 +0x47
net.(*pollDesc).WaitRead(0xc208010610, 0x0, 0x0)
    /usr/src/go/src/net/fd_poll_runtime.go:89 +0x43
net.(*netFD).accept(0xc2080105b0, 0x0, 0x7f18e9c1abb0, 0xc20800ab30)
    /usr/src/go/src/net/fd_unix.go:419 +0x40b
net.(*TCPListener).AcceptTCP(0xc208038040, 0x482bce, 0x0, 0x0)
    /usr/src/go/src/net/tcpsock_posix.go:234 +0x4e
net/http.tcpKeepAliveListener.Accept(0xc208038040, 0x0, 0x0, 0x0, 0x0)
    /usr/src/go/src/net/http/server.go:1976 +0x4c
net/http.(*Server).Serve(0xc20805c360, 0x7f18e9c1c160, 0xc208038040, 0x0, 0x0)
    /usr/src/go/src/net/http/server.go:1728 +0x92
net/http.(*Server).ListenAndServe(0xc20805c360, 0x0, 0x0)
    /usr/src/go/src/net/http/server.go:1718 +0x154
net/http.ListenAndServe(0xc20800ae60, 0x5, 0x0, 0x0, 0x0, 0x0)
    /usr/src/go/src/net/http/server.go:1808 +0xba
main.listenAndServe(0xc20803ac60)
    /go/src/github.com/Imgur/incus/incus/main.go:71 +0x166
main.main()
    /go/src/github.com/Imgur/incus/incus/main.go:66 +0x51e

goroutine 5 [syscall, 8 minutes]:
os/signal.loop()
    /usr/src/go/src/os/signal/signal_unix.go:21 +0x1f
created by os/signal.init·1
    /usr/src/go/src/os/signal/signal_unix.go:27 +0x35

goroutine 6 [chan send, 2 minutes]:
github.com/Imgur/incus.func·015()
    /go/src/github.com/Imgur/incus/sockets.go:25 +0x13a
created by github.com/Imgur/incus.init·1
    /go/src/github.com/Imgur/incus/sockets.go:27 +0x5c

goroutine 7 [chan receive, 8 minutes]:
main.func·002()
    /go/src/github.com/Imgur/incus/incus/main.go:92 +0x198
created by main.InstallSignalHandlers
    /go/src/github.com/Imgur/incus/incus/main.go:103 +0x25

goroutine 8 [sleep]:
github.com/Imgur/incus.(*Server).RecordStats(0xc208040460, 0x3b9aca00)
    /go/src/github.com/Imgur/incus/server.go:301 +0x5f
created by main.main
    /go/src/github.com/Imgur/incus/incus/main.go:57 +0x430

goroutine 9 [sleep]:
github.com/Imgur/incus.(*Server).LogConnectedClientsPeriodically(0xc208040460, 0x4a817c800)
    /go/src/github.com/Imgur/incus/server.go:308 +0xff
created by main.main
    /go/src/github.com/Imgur/incus/incus/main.go:58 +0x459

goroutine 20 [select, 2 minutes]:
github.com/Imgur/incus.(*Socket).listenForWrites(0xc208010310)
    /go/src/github.com/Imgur/incus/sockets.go:163 +0x736
created by github.com/Imgur/incus.func·011
    /go/src/github.com/Imgur/incus/server.go:131 +0x9a4

goroutine 14 [sleep]:
github.com/Imgur/incus.(*Server).SendHeartbeatsPeriodically(0xc208040460, 0x4a817c800)
    /go/src/github.com/Imgur/incus/server.go:280 +0x36
created by main.main
    /go/src/github.com/Imgur/incus/incus/main.go:63 +0x4ea

goroutine 18 [select, 2 minutes]:
github.com/Imgur/incus.func·011(0x7f18e9c1c340, 0xc208044320, 0xc208032680)
    /go/src/github.com/Imgur/incus/server.go:133 +0xb4e
net/http.HandlerFunc.ServeHTTP(0xc20800af00, 0x7f18e9c1c340, 0xc208044320, 0xc208032680)
    /usr/src/go/src/net/http/server.go:1265 +0x41
net/http.(*ServeMux).ServeHTTP(0xc20803a6c0, 0x7f18e9c1c340, 0xc208044320, 0xc208032680)
    /usr/src/go/src/net/http/server.go:1541 +0x17d
net/http.serverHandler.ServeHTTP(0xc20805c360, 0x7f18e9c1c340, 0xc208044320, 0xc208032680)
    /usr/src/go/src/net/http/server.go:1703 +0x19a
net/http.(*conn).serve(0xc208044000)
    /usr/src/go/src/net/http/server.go:1204 +0xb57
created by net/http.(*Server).Serve
    /usr/src/go/src/net/http/server.go:1751 +0x35e

Allow for unicode chars in ios notifications

Currently I am getting these errors:

2015/11/26 16:41:26 Alert (iOS): {"aps":{"alert":"Test: 💬test","badge":-1,"sound":"bingbong.aiff"},"payload":{"event":"notification","data":{"message_text":"Test: 💬 test","notification":{"body":"💬 test","id":121,"image":"urlToImage","tag":121,"title":"Test"}},"time":1448556086}}
2015/11/26 16:41:26 Error (iOS): encoding/hex: invalid byte: U+0074 't'

I add them in javascript like this: '\uD83D\uDCAC'
EDIT: adding like 💬 in js does not help

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.