Skip to content

Commit

Permalink
Merge pull request #12 from devicehive/development
Browse files Browse the repository at this point in the history
Support of DeviceType in subscription
DeviceType API integration tests
Documentation improvements
  • Loading branch information
itrambovetskyi authored Jan 23, 2018
2 parents ffb4d99 + 6a0af9a commit 2275955
Show file tree
Hide file tree
Showing 31 changed files with 1,175 additions and 1,058 deletions.
19 changes: 8 additions & 11 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
FROM node:8.7.0-alpine
FROM node:9.4.0-alpine
ENV WORK_DIR=/usr/src/app/
RUN mkdir -p ${WORK_DIR} \
&& cd ${WORK_DIR}

WORKDIR ${WORK_DIR}

RUN apk add --no-cache --virtual .gyp \
python \
make \
g++

COPY . ${WORK_DIR}

RUN npm install \
&& apk del .gyp

RUN npm install pm2 -g
RUN apk add --no-cache --virtual .gyp \
python make g++ \
&& npm install \
&& apk del .gyp \
&& npm install pm2 -g \
&& npm cache clean --force

EXPOSE 1883
CMD ["pm2-docker", "src/broker.js"]
CMD ["pm2-docker", "src/broker.js"]
34 changes: 34 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
properties([
buildDiscarder(logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '7', numToKeepStr: '7'))
])

def publish_branches = ["development", "master"]

stage('Build and publish Docker image in CI repository') {
node('docker') {
checkout scm
echo 'Building image ...'
def mqtt = docker.build('devicehiveci/devicehive-mqtt:${BRANCH_NAME}', '--pull -f Dockerfile .')

echo 'Pushing image to CI repository ...'
docker.withRegistry('https://registry.hub.docker.com', 'devicehiveci_dockerhub'){
mqtt.push()
}
}
}

if (publish_branches.contains(env.BRANCH_NAME)) {
stage('Publish image in main repository') {
node('docker') {
// Builds from 'master' branch will have 'latest' tag
def IMAGE_TAG = (env.BRANCH_NAME == 'master') ? 'latest' : env.BRANCH_NAME

docker.withRegistry('https://registry.hub.docker.com', 'devicehiveci_dockerhub'){
sh """
docker tag devicehiveci/devicehive-mqtt:${BRANCH_NAME} registry.hub.docker.com/devicehive/devicehive-mqtt:${IMAGE_TAG}
docker push registry.hub.docker.com/devicehive/devicehive-mqtt:${IMAGE_TAG}
"""
}
}
}
}
66 changes: 43 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,39 @@ Start Up
===
The **devicehive-mqtt** broker can be launched directly via node, docker container or docker-compose.
With last choice is pretty easy to scale the broker horizontally.
Also you might to specify a set of environmental variables that are described in the next paragraph.
Also you might to specify a set of configurations/environmental variables that are described in the next paragraph.

Environmental variables
---
`NODE_ENV` - "prod" for production, "dev" for development
`BROKER_PORT` - port on wich broker will start (default: 1883)
`WS_SERVER_URL` - path to Web Socket server (default: ws://playground.devicehive.com/api/websocket)
`REDIS_SERVER_HOST` - Redis storage host (default: localhost)
`REDIS_SERVER_PORT` - Redis storage port (default: 6379)
`DEBUG` - [debug] modules logger (modules: subscriptionmanager, websocketfactory, websocketmanager)
`APP_LOG_LEVEL` - application logger level (levels: debug, info, warn, error)
`ENABLE_PM` - enable process monitoring with [PM2] module

# Configuration
## Broker
[path-to-broker-project]/src/config.json

- **_BROKER_PORT_** - port on wich broker will start (default: 1883)
- **_WS_SERVER_URL_** - path to Web Socket server (default: ws://localhost:8080/dh/websocket)
- **_REDIS_SERVER_HOST_** - Redis storage host (default: localhost)
- **_REDIS_SERVER_PORT_** - Redis storage port (default: 6379)
- **_APP_LOG_LEVEL_** - application logger level (levels: debug, info, warn, error)
- **_ENABLE_PM_** - enable process monitoring with [PM2] module

Each configuration field can be overridden with corresponding environmental variable with "BROKER" prefix, for example:

BROKER.BROKER_PORT=6000

Prefix separator can be overridden by **_ENVSEPARATOR_** environmental variable. Example:

ENVSEPARATOR=_
BROKER_BROKER_PORT=6000

## Broker modules logging
Through the "DEBUG" ([debug]) environment variable you are able to specify next modules loggers:

- **_subscriptionmanager_** - SubscriptionManager module logging;
- **_websocketfactory_** - WebSocketFactory module logging;
- **_websocketmanager_** - WebSocketManager module logging;

Example:

DEBUG=subscriptionmanager,websocketfactory,websocketmanager

Run with Node
---
In the folder of cloned **devicehive-mqtt** repo run next commands:
Expand All @@ -59,11 +79,7 @@ Install all dependencies:

Start broker:

<environmental-variables-list> node ./src/broker.js

Where:

_environmental-variables-list_ - list of environmental variables, e.g. _NODE_ENV=prod,BROKER_PORT=1883,..._
node ./src/broker.js

Also, it's pretty useful to enable process monitoring with [PM2] module (ENABLE_PM environmental variables) and
start the broker via PM2.
Expand Down Expand Up @@ -125,6 +141,7 @@ DeviceHive messaging structure projection on MQTT topic structure
===
[DeviceHive] has next structure entities:
- network
- device type
- device
- message type
* notification
Expand All @@ -146,14 +163,17 @@ To receive responses of request the MQTT client should subscribe to the response
Where _requestAction_ ia a request action (**user/get**, **device/delete**, **token/refresh etc.**)
Response topic should be always private (e.g. with client ID mentioned)

The MQTT client is able to subscribe to the notification/command topic to receive notification/command push messages
The MQTT client is able to subscribe to the notification/command/command_update topic to receive notification/command/command_update push messages

dh/notification/<networkID>/<deviceID>/<notificationName>[@<clientID>]
dh/notification/<networkID>/<deviceTypeID>/<deviceID>/<notificationName>[@<clientID>]
dh/command/<networkID>/<deviceID>/<commandName>[@<clientID>]
dh/command/<networkID>/<deviceTypeID>/<deviceID>/<commandName>[@<clientID>]

dh/command_update/<networkID>/<deviceTypeID>/<deviceID>/<commandName>[@<clientID>]

Where:
- networkID - id of the network
- deviceTypeID - id of the device type
- deviceID - id of the device
- notificationName - notification name
- commandName - command name
Expand Down Expand Up @@ -234,15 +254,15 @@ _**Connection with username and password, subscription for notification and comm
client.on('connect', () => {
/* Subscribe for notification push messages with name = notificationName
of device with id = deviceId on network with id = networkId */
client.subscribe('dh/notification/<networkId>/<deviceId>/<notificationName>');
client.subscribe('dh/notification/<networkId>/<deviceTypeId>/<deviceId>/<notificationName>');

/* Subscribe for notification push messages with name = notificationName
of any device on network with id = networkId */
client.subscribe('dh/notification/<networkId>/+/<notificationName>');
client.subscribe('dh/notification/<networkId>/<deviceTypeId>/+/<notificationName>');

/* Subscribe for command push messages with name = commandName
of device with id = deviceId on network with id = networkId */
client.subscribe('dh/command/<networkId>/<deviceId>/<commandName>');
client.subscribe('dh/command/<networkId>/<deviceTypeId>/<deviceId>/<commandName>');

/* Subscribe for command push messages on network with id = networkId
for any device with any command name */
Expand Down
7 changes: 7 additions & 0 deletions config/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const path = require(`path`);
const configurator = require(`json-evn-configurator`);


module.exports = {
broker: configurator(path.join(__dirname, `../src/config.json`), `BROKER`)
};
8 changes: 4 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ services:
- cote
- redis
environment:
- WS_SERVER_URL=ws://playground.dev.devicehive.com/api/websocket
- WS_SERVER_URL=ws://playground-dev.devicehive.com/api/websocket
- REDIS_SERVER_HOST=redis
- REDIS_SERVER_PORT=6379
- ENABLE_PM=false
Expand All @@ -30,7 +30,7 @@ services:
- cote
- redis
environment:
- WS_SERVER_URL=ws://playground.dev.devicehive.com/api/websocket
- WS_SERVER_URL=ws://playground-dev.devicehive.com/api/websocket
- REDIS_SERVER_HOST=redis
- REDIS_SERVER_PORT=6379
- ENABLE_PM=false
Expand All @@ -41,7 +41,7 @@ services:
- cote
- redis
environment:
- WS_SERVER_URL=ws://playground.dev.devicehive.com/api/websocket
- WS_SERVER_URL=ws://playground-dev.devicehive.com/api/websocket
- REDIS_SERVER_HOST=redis
- REDIS_SERVER_PORT=6379
- ENABLE_PM=false
Expand All @@ -52,7 +52,7 @@ services:
- cote
- redis
environment:
- WS_SERVER_URL=ws://playground.dev.devicehive.com/api/websocket
- WS_SERVER_URL=ws://playground-dev.devicehive.com/api/websocket
- REDIS_SERVER_HOST=redis
- REDIS_SERVER_PORT=6379
- ENABLE_PM=false
Expand Down
32 changes: 23 additions & 9 deletions lib/TopicStructure.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class TopicStructure {
me.domain = ``;
me.action = ``;
me.network = ``;
me.deviceType = ``;
me.device = ``;
me.name = ``;
me.owner = ``;
Expand All @@ -40,14 +41,16 @@ class TopicStructure {

const shift = me.response || me.request ? 1 : 0;
const network = partedTopicBody[2 + shift];
const device = partedTopicBody[3 + shift];
let name = partedTopicBody[4 + shift];
const deviceType = partedTopicBody[3 + shift];
const device = partedTopicBody[4 + shift];
let name = partedTopicBody[5 + shift];

name = (me.hasOwner() && name) ? name.split(CONST.CLIENT_ID_TOPIC_SPLITTER)[0] : name;

me.domain = partedTopicBody[0];
me.action = partedTopicBody[1 + shift];
me.network = (!network || CONST.MQTT.WILDCARDS.includes(network)) ? `` : network;
me.deviceType = (!deviceType || CONST.MQTT.WILDCARDS.includes(deviceType)) ? `` : deviceType;
me.device = (!device || CONST.MQTT.WILDCARDS.includes(device)) ? `` : device;
me.name = (!name || CONST.MQTT.WILDCARDS.includes(name)) ? `` : name;

Expand Down Expand Up @@ -129,10 +132,20 @@ class TopicStructure {
* Get topic network
* @returns {*}
*/
getNetwork () {
getNetworkIds () {
const me = this;

return me.network;
return !me.device && me.network ? [ me.network ] : undefined;
}

/**
* Get topic device type
* @returns {*}
*/
getDeviceTypeIds () {
const me = this;

return !me.device && me.deviceType ? [ me.deviceType ] : undefined;
}

/**
Expand All @@ -142,17 +155,17 @@ class TopicStructure {
getDevice () {
const me = this;

return me.device;
return me.device || undefined;
}

/**
* Get topic Name
* @returns {*}
*/
getName () {
getNames () {
const me = this;

return me.name;
return me.name ? [ me.name ] : undefined;
}

/**
Expand Down Expand Up @@ -215,15 +228,16 @@ class TopicStructure {
CONST.TOPICS.PARTS.NOTIFICATION :
CONST.TOPICS.PARTS.COMMAND;
const network = dataObject[propertyKey].networkId;
const deviceType = dataObject[propertyKey].deviceTypeId;
const device = dataObject[propertyKey].deviceId;
const name = dataObject[propertyKey][propertyKey];

topicParts = [CONST.TOPICS.PARTS.DH, action, network, device, name];
topicParts = [CONST.TOPICS.PARTS.DH, action, network, deviceType, device, name];
} else {
topicParts = [CONST.TOPICS.PARTS.DH, CONST.TOPICS.PARTS.RESPONSE, dataObject.action];
}

return !!owner ? topicParts.join("/") + CONST.CLIENT_ID_TOPIC_SPLITTER + owner : topicParts.join("/");
return owner ? `${topicParts.join("/")}${CONST.CLIENT_ID_TOPIC_SPLITTER}${owner}` : topicParts.join("/");
}
}

Expand Down
Loading

0 comments on commit 2275955

Please sign in to comment.