MQTT/Websocket/etc proxy for MessagingV2 API with message storage
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
mosquitto
.gitignore
.travis.yml
Dockerfile
Gopkg.lock
Gopkg.toml
README.md
docker-compose.tls.yml
docker-compose.yml
graphql.go
graphql_test.go
helpers_test.go
interfaces.go
main.go
main_test.go
messages.go
messages_test.go
models.go
models_test.go
mqtt.go
mqtt_test.go
routes.go
routes_test.go
schema.graphql
validate-auth-data.go
validate-auth-data_test.go
websocket.go
websocket_test.go

README.md

message-proxy-mqtt

Proxy application for Messaging v2 API which with HTTP (REST and GraphQL), WebSocket, MQTT transports and message storage.

Build Status

Quick install on VPS

docker and docker-compose should be preinstalled on your VPS. Don't use VPS based on OpenVZ (to avoid troubles with docker).

Configure receiving of SSL certificates (via Lets Encrypt)

  • Install curl, openssl and socat

  • Install acme.sh by

curl https://get.acme.sh | sh
  • Log out an log in again

  • Receive SSL certificate files for your domain

acme.sh --standalone --issue -d YOUR_DOMAIN

Runing the app

  • Create a directory for the app settings (for example /var/message-proxy-mqtt) and open it in the terminal

  • Install SSL certificates to this folder (make links to existing files)

mkdir ./cert && acme.sh --install-cert -d YOUR_DOMAIN --cert-file ./cert/cert.pem --key-file ./cert/privkey.pem  --fullchain-file ./cert/chain.pem --reloadcmd  "cd /var/message-proxy-mqtt && docker-compose restart"

After that acme.sh will renew certificates and restart the application itself

  • Download Mosquitto (MQTT broker) config file
mkdir -p ./mosquitto/config.tls
curl https://raw.githubusercontent.com/BandwidthExamples/message-proxy-mqtt/master/mosquitto/config.tls/mosquitto.conf -o ./mosquitto/config.tls/mosquitto.conf
  • Download docker-compose.yml
curl https://raw.githubusercontent.com/BandwidthExamples/message-proxy-mqtt/master/docker-compose.tls.yml -o docker-compose.yml
  • Run the app
docker-compose up -d
  • Open in firewall ports 443 (https and wss), 8883 (mqtt over tls) and 8983 (mqtt over wss)

Install

Extract sources

git clone https://github.com/BandwidthExamples/message-proxy-mqtt.git
cd message-proxy-mqtt

Using Docker

Run docker-compose up -d. After that the app will be available on port 8080. MQTT brocker will be available on port 1883. Connections to both ports will not be encrypted.

If you need to use SSL certificates make subdirectory cert and copy your certificate files there (cert.pem, privkey.pem, chain.pem). Use docker-compose.tls.yml to start the app.

Manual

Build the application

# Install dep (tool to manage dependencies)
go get -u github.com/golang/dep/cmd/dep

# Install dependencies
dep ensure

# Build the app
go build

Start Postgresql instance

Install postgresql and create empty database there. Set environment variable DATABASE_URL to postgres://PG_USER_NAME:PG_PASSWORD@PG_HOST/CREATED_DATABASE

Start Mosquitto instance

Install mosquitto MQTT broker. Install mosquitto-auth-plug (only http transport is required) with mosquitto. You can use ready docker image with auth plugin andbel/mosquitto-with-http-auth for that. Copy sample mosquitto config file from ./mosquitto/config/mosquitto.conf to you mosquitto instance. Change their params auth_opt_http_hostname, auth_opt_http_port, auth_opt_http_with_tls to right values. Start mosquitto instance. Set environment variable MQTT_BROKER to tcp://MQTT_HOST:MQTT_PORT.

Start the app

PORT=8080 GIN_MODE=release message-proxy-mqtt

# if you would like to see more detailed log output run as
PORT=8080 message-proxy-mqtt -logtostderr -v 2

Using the application

Configure you Dashboard (to receive notifications about messages)

Folow next steps and create new application on your Dashboard. Use https://YOUR_DOMAIN/bandwidth/callback/USER_ID (where USER_ID is you user id for voice and messaging api) as callback url for messages

REST calls

All REST requests require basic auth authorization with your voice and messaging api apiToken and apiSecret

Get your messages

GET https://YOUR_DOMAIN/users/USER_ID/messages

Optional query parameters:

Parameter Description
from The phone number to filter the messages that came from (must be in E.164 format, like +19195551212).
to The phone number to filter the messages that was sent to (must be in E.164 format, like +19195551212).
fromDateTime The starting date time to filter the messages (must be in yyyy-MM-dd hh:mm:ss format, like 2014-05-25 12:00:00.
toDateTime The ending date time to filter the messages (must be in yyyy-MM-dd hh:mm:ss format, like 2014-05-25 12:00:00.)
direction Filter by direction of message: in, out
applicationId the application id which was used to send the messages
status the message status: sent, received, delivered, failed
size Used for pagination to indicate the size of each page requested for querying a list of messages. If no value is specified the default value is 30
page Used for pagination to indicate the page number. If no value is specified the default value is 1.
Example
curl --request GET \
  --url http://my-domain/users/u-xxxxxx/messages \
  --user apiToken:apiSecret

Response

{
    "page": 1,
    "size": 30,
    "pageCount": 1,
    "messages": [
    {
        "id": "yMGeuDtRzQMDQiYCOhgHOvgSeycJPJHYNufNjJhhjUVRuSqfgqVMkPYVkURUpiFv",
        "time": "2018-03-17T06:38:06.54208Z",
        "from": "111",
        "to": [
            "222"
        ],
        "text": "test",
        "media": [
            "url1",
            "url2"
        ],
        "applicationId": "appId",
        "tag": "",
        "direction": "out",
        "error": "test",
        "errorCode": 1000,
        "status": "failed",
        "segmentCount": 1
    }]
}

Get only a message

GET https://YOUR_DOMAIN/users/USER_ID/messages/MESSAGE_ID

Example
curl --request GET \
  --url http://my-domain/users/u-xxxxxx/messages/yMGeuDtRzQMDQiYCOhgHOvgSeycJPJHYNufNjJhhjUVRuSqfgqVMkPYVkURUpiFv \
  --user apiToken:apiSecret

Response

{
    "id": "yMGeuDtRzQMDQiYCOhgHOvgSeycJPJHYNufNjJhhjUVRuSqfgqVMkPYVkURUpiFv",
    "time": "2018-03-17T06:38:06.54208Z",
    "from": "111",
    "to": [
        "222"
    ],
    "text": "test",
    "media": [
        "url1",
        "url2"
    ],
    "applicationId": "appId",
    "tag": "",
    "direction": "out",
    "error": "test",
    "errorCode": 1000,
    "status": "failed",
    "segmentCount": 1
}

Send a message (or some messages)

POST https://YOUR_DOMAIN/users/USER_ID/messages with json payload

Look at here for supported parameters

Example
curl --request POST \
  --url http://mydomain/users/u-xxxxx/messages \
  --header 'content-type: application/json' \
  --data '{
    "from": "111",
    "to": "222",
    "text": "test",
    "applicationId": "appId"
}' \
  --user apiToken:apiSecret

Response

{
    "id": "yMGeuDtRzQMDQiYCOhgHOvgSeycJPJHYNufNjJhhjUVRuSqfgqVMkPYVkURUpiFd",
    "time": "2018-03-29T09:38:06.5420801+03:00",
    "from": "111",
    "to": [
        "222"
    ],
    "text": "test",
    "media": [],
    "applicationId": "appId",
    "tag": "",
    "direction": "out",
    "error": "test",
    "errorCode": 1000,
    "status": "failed",
    "segmentCount": 1
}

Websocket calls

Receiving notifications about changed messages

Use next url wss://DOMAIN_NAME/messages/ws?userId=USER_ID&apiToken=API_TOKEN&apiSecret=API_SECRET with transport message-ws to start to receive notifications about changed messages.

const socket = new WebSocket('wss://mydomain/messages/ws?userId=myUserId&apiToken=myApiToken&apiSecret=myApiSecret', 'message-ws');
socket.onmessage = ev => {
    const message = JSON.parse(ev.data);
    if (message.status === 'received') {
        //TODO handle incoming message
    }
}

GraphQL calls

Entry point for GraphQL query and mutations requests is POST https://YOUR_DOMAIN/users/USER_ID/graphql with basic authorization apiToken:apiSecret.

Get your messages

Use query messages for that.

{
    messages {
        id
        from
        to
        text
    }
}
{
    messages(applicationId: "appId") {
        id
        from
        to
        text
    }
}

Optional query arguments:

Parameter Description
from The phone number to filter the messages that came from (must be in E.164 format, like +19195551212).
to The phone number to filter the messages that was sent to (must be in E.164 format, like +19195551212).
fromDateTime The starting date time to filter the messages (must be in yyyy-MM-dd hh:mm:ss format, like 2014-05-25 12:00:00.
toDateTime The ending date time to filter the messages (must be in yyyy-MM-dd hh:mm:ss format, like 2014-05-25 12:00:00.)
direction Filter by direction of message: in, out
applicationId the application id which was used to send the messages
status the message status: sent, received, delivered, failed
first, offset Used for pagination to indicate how many records to return and with which offset

Get a message

Use query messages for that.

{
    message(id: "xyzxyzxyz") {
        id
        from
        to
        text
    }
}

Send a message (or some messages)

Use mutation sendMessage for that.

mutation {
    sendMessage(from: "from", to: ["to"], text: "hello", applicationId: "appId) {
        id
    }
}

Supported arguments: from, to, text, applicationId, media, tag.

Receving notifications about changed messages

For GraphQL subscriptions use websocket entry point wss://YOU_DOMAIN/graphql/subscriptions with authToken value userId:apiToken:apiSecret.

Use subscription onMessageChanged to receive notifications about any message changes (incoming messages too).

subscription {
    onMessageChanged {
        id
        from
        to
        text
        status
        applicationId
    }
}

Access to Graphiql (UI for exploring GraphQL)

Open in browser https://YOUR_DOMAIN/users/USER_ID/graphql. User your apiToken and apiSecret to authentificate.

MQTT calls

All MQTT calls requires authorization. Use you userId ans user name and apiToken:apiSecret as password.

Sending a messages (or some messages)

Send to topic users/USER_ID/messages with json payload like {"to": ["to"], from: "from", "text": "text", "applicationId": "appID"}. Look at here for supported parameters.

Receving notifications about changed messages

Subscribe to users/USER_ID/messages/# to receive notifications about all your changed messages. Subscribe to users/USER_ID/messages/in/+ to receive notifications about only incoming messages. Subscribe to users/USER_ID/messages/out/MESSAGE_ID to receive notifications about changes of given sent message.

You will receive json encoded string with messages data.