stream-dev-tools
v1.2.11
Published
npm package for developing VectorWatch stream
Downloads
18
Readme
Getting started
Install the latest version available on NPM:
npm install stream-dev-tools --save
Then:
var VectorWatch = require('stream-dev-tools');
Streams
How it works
Streams are text based content that is displayed on the Vector Watch. From a technical point of view, the system works as follows. The watch exchanges data with the phone application (available on iOS, Android and Windows Phone), the app exchanges data with our cloud and our cloud exchanges data with a stream node. .
The communication between Vector Cloud and a Stream Node is handled using HTTP protocol. The Stream Node listens on a HTTP endpoint to receive Vector events and it calls HTTP endpoints on the Vector Cloud in order to push realtime data to the Vector Watch.
How to use it
In order to host a stream, you need the API token generated for your developer account and a streamUID which you can create here.
var vectorStream = VectorWatch.createStreamNode({
token: '***',
streamUID: '***'
});
Listen to requestConfig
events, triggered when someone drops the stream onto an empty stream slot, creating a stream instance:
vectorStream.requestConfig = function(resolve, reject) {
resolve({
renderOptions: {
MySetting: {
type: 'GRID_LAYOUT',
dataType: 'STATIC'
}
},
settings: {
MySetting: [
{ name: 'Option #1', value: 1 },
{ name: 'Option #2', value: 2 }
]
},
defaults: {
MySetting: { value: 1 }
}
});
};
Listen to registerSettings
events, triggered when someone configures a stream instance:
vectorStream.registerSettings = function(resolve, reject, settings) {
if (settings.MySetting1 == 1) {
resolve('Selected Option #1');
} else if (settings.MySetting1 == 2) {
resolve('Selected Option #2');
} else {
reject(new Error('Invalid option selected.'));
}
};
Apps
How it works
How to use it
API Reference
Summary
VectorWatch
Static Methods
StreamNode
Methods
- push
- pushNow
- authTokensForStateExpired
- retrieveSettings
- retrieveState
- getAuthTokensForState
- dbCleanUp
- getMiddleware
- startStreamServer
- changeAuthTokensForState
Events
AppNode
Methods
Events
VectorWatch : Object
Methods
VectorWatch.createStreamNode
(Configoptions
) → StreamNode
StreamNode : Object
Properties
stateStorage
authStorage
Methods
.push
(Statestate
, Stringdata
, Numberdelay
) → StreamNode
This method will put the 'data' String for the given channel(state) in the cache object and send it
to the cloud after the delay has passed.
After that all the users that listen to that channel will see the new information.
Example:
stream.push({channelLabel:"....", settings1:{name:"...", value:""}}, "Info to be shown", 1);
.pushNow
() → StreamNode
This method will flush the cache and send all the information to the cloud.
.authTokensForStateExpired
(Statestate
) → StreamNode
This method will inform the mobile app that the user's authentification has expired
Example:
stream.authTokensForStateExpired({channelLabel:"....", __auth:{....},settings1:{name:"...", value:""}});
Get all the settings stored in the DB. On success the resolve(settingsArray) method is called,
otherwise the reject(error) method.
The developer can access the returned array in the resolve(settingsArray) callback, as a parameter.
Example:
stream.retrieveSettings(function (allSettingsObject) {
//Do something on success
}, function(){
//Do something on failure
});
.retrieveState
alias of.retrieveSettings
.getAuthTokensForState
(Statestate
, Function<Error, AuthTokens>callback
) →undefined
Get the authentification information for the given 'state'
Delete al settings from the DB.
Returns the configurated expressJS app
.startStreamServer
(Numberport
, Functioncallback
) →undefined
.changeAuthTokensForState
(Statestate
, AuthTokensauthTokens
) →undefined
Inserts/Updates the authentification information in the db/memory
Events (overridable methods)
.requestConfig
(Functionresolve
, Functionreject
, AuthTokensauthTokens
)
/** This method is called in order to retrieve all the settings(name, order, display option) when
an user adds the stream to a watch-face.
* Call the resolve() method with a Config Object as a parameter for success or the reject() method
with an error message.
*/
stream.requestConfig = function (resolve, reject, authTokens) {
resolve({
"renderOptions": {
"DataTypeSettings": {
"type": "GRID_LAYOUT",
"dataType": "STATIC",
"order": 0
},
"DisplaySettings0": {
"type": "INPUT_LIST",
"dataType": "DYNAMIC",
"order": 1,
"asYouType": true,
"minChars": 3
}
},
"settings": {
"DataTypeSettings": [
{
"name": "Counter",
"value": 1
},
{
"name": "Last Update",
"value": 2
}
]
},
"defaults": {
"DataTypeSettings": {
"name": "Counter",
"value": 1
}
}
});
};
.requestOptions
(Functionresolve
, Functionreject
, StringsettingName
, StringsearchTerm
, Statesettings
, AuthTokensauthTokens
)
/** This method is called in order to retrieve all the options for a particular setting(given by the settingName parameter).
* Call the resolve() method with an array of SettingValue objects for success or the reject() method with an error message.
* The state parameter holds all the previous settings
*/
stream.requestOptions = function (resolve, reject, settingName, searchTerm, state, authTokens) {
resolve([{name:"Option0"},{name:"Options1"}]);
};
.registerSettings
(Functionresolve
, Functionreject
, Statesettings
, AuthTokensauthTokens
)
/** This method is called every time a user selects the desired settings.
* The DB(if not in dev mode) is automatically updated.
* When implementing this method the developer must call the 'resolve' function parameter
after he retrieves/generates the data.
* */
stream.registerSettings = function (resolve, reject, settings) {
resolve("Welcome!");
};
.unregisterSettings
(Functionresolve
, Functionreject
, Statesettings
, AuthTokensauthTokens
)
/** This method is called every time a user removes the stream from a watch-face.
* */
stream.unregisterSettings = function (resolve, reject, settings) {
resolve();
};
AppNode : Object
TODO
State : Object
Properties
__auth
Object (for internal use only)channelLabel
String (optional){setting name}
SettingValue (there is a property for each setting)
Example:
{
"__auth": {
"code": "...",
"state": "..."
},
"MySetting1": { "value": "2" },
"MySetting2": { "value": "1" },
"channelLabel": "..."
}
Config : Object
This object tells the phone application what are the stream settings and how to display them
renderOptions
Object<String, RenderOption>settings
Object<String, SettingValue>defaults
Object<String, SettingValue>
Example
{
"renderOptions": {
"MySetting1": {
"type": "GRID_LAYOUT",
"hint": "Select an option for MySetting1",
"order": 0,
"dataType": "STATIC"
},
"MySetting2": {
"type": "INPUT_LIST_STRICT",
"hint": "Type an option for MySetting2",
"order": 1,
"dataType": "STATIC"
}
},
"settings": {
"MySetting1": [
{ "name": "Option #1", "value": "1" },
{ "name": "Option #2", "value": "2" }
],
"MySetting2": [
{ "name": "Option #1", "value": "1" },
{ "name": "Option #2", "value": "2" }
]
},
"defaults": {
"MySetting1": { "value": "1" },
"MySetting2": { "value": "1" }
}
}
RenderOption : Object
Properties
name
String (can be omitted if this in the value of a property with the same name)type
String (one of the following:GRID_LAYOUT
,INPUT_LIST
orINPUT_LIST_STRICT
)hint
String (optional)order
Number (required if more than a RenderOption is specified)dataType
String (one of the following:STATIC
orDYNAMIC
)asYouType
Boolean (required ifdataType
isDYNAMIC
)minChars
Number (required ifasYouType
istrue
)
Example
{
"type": "GRID_LAYOUT",
"dataType": "STATIC"
}
SettingValue : Object
Properties
name
String (can be omitted if this is the value of a property with the same name)value
Object (can be anything, but most of the times this will be String)
Example
{
"name": "Option #1",
"value": "1"
}
AuthTokens : Object
This class holds the tokens required for authorization.
This class is abstract, see OAuth1Tokens and OAuth2Tokens for concrete implementations.
OAuth1Tokens : AuthTokens
Properties
Example
{
"oauth_access_token": "...",
"oauth_access_token_secret": "..."
}
OAuth2Tokens : AuthTokens
Properties
Example
{
"access_token": "..."
}
#Sample This is a simple stream that shows the current number of stream instances or the last update(month.year).
var streamDevTools = require('./index.js');
var configJSON = {
streamUUID: "***",
streamType: "public",
hasSettings: true,
token: "***",
portNumber: "2999"
};
var sample_stream = streamDevTools.createStreamNode(configJSON);
var DisplaySettings0 = [{name: 'simple', value: 1}, {name: 'detailed', value: 2}],
DisplaySettings1 = [{name: 'with icons', value: 1}, {name: 'without icons', value: 2}];
var counter = 0, lastUpdated;
setLastUpdated();
/** Update the stream value for all users
* @returns {null}
*/
function updateAll() {
sample_stream.retrieveSettings(function (allSettingsObject) {
//Here we retrieve all the settings from the db.
/*
* allSettingsObject = {"...chanelLabel...":{...State Object...},
* "...chanelLabel...":{...State Object...},
* ....
* }
* */
var pushArray = [];
for (channelLabel in allSettingsObject) {
//Here we iterate through all the settings and 'push' the corresponding information.
if (allSettingsObject.hasOwnProperty(channelLabel)) {
sample_stream.push(allSettingsObject[channelLabel], getData(allSettingsObject[channelLabel]));
}
}
//Flush the buffer and send all the information to the cloud.
sample_stream.pushNow();
});
}
/** Returns the corresponding String that will be shown on th watch for a set of settings
* @returns {null}
*/
function getData(settings) {
var data = '', counterText = " stream instances:", dateText = " last update:";
if (settings.DataTypeSettings.name.indexOf("Counter") > -1) {
data = counter;
if(settings.DisplaySettings0.name.indexOf("detailed") > -1) {
data += counterText;
}
} else {
data = lastUpdated;
if(settings.DisplaySettings0.name.indexOf("detailed") > -1) {
data += dateText;
}
}
if(settings.DisplaySettings0.name.indexOf("without") == -1) {
return " " + data;
} else {
return data;
}
}
/** Returns the corresponding String that will be shown on th watch for a set of settings
* @returns {null}
*/
function setLastUpdated(){
lastUpdated = new Date().getDate() +"." + new Date().getMonth();
}
/** Over-ridden method. Calls the success callback with the desired configuration.
* @returns {null}
*/
sample_stream.requestConfig = function (resolve, reject) {
resolve({
"renderOptions": {
"DataTypeSettings": {
"type": "GRID_LAYOUT",
"dataType": "STATIC",
"order": 0
},
"DisplaySettings0": {
"type": "INPUT_LIST",
"dataType": "DYNAMIC",
"order": 1,
"asYouType": true,
"minChars": 3
},
"DisplaySettings1": {
"type": "INPUT_LIST",
"dataType": "DYNAMIC",
"order": 2,
"asYouType": true,
"minChars": 3
}
},
"settings": {
"DataTypeSettings": [
{
"name": "Counter",
"value": 1
},
{
"name": "Last Update",
"value": 2
}
],
"DisplaySettings0": [],
"DisplaySettings1": []
},
"defaults": {
"DataTypeSettings": {
"name": "Counter",
"value": 1
}
}
});
};
/** Over-ridden method. Calls the success callback with the found options for the current dynamic setting
* @returns {null}
*/
sample_stream.requestOptions = function (resolve, reject, settingName, searchTerm, state) {
var settingItem, results = [];
switch (settingName) {
case 'DisplaySettings0':
settingItem = DisplaySettings0;
break;
case 'DisplaySettings1':
settingItem = DisplaySettings1;
break;
}
settingItem.forEach(function (option) {
if (option.name.indexOf(searchTerm) > -1) {
results.push(option);
}
});
resolve(results);
};
/** Over-ridden method. The counter and the lastUpdated variables are updated and the corresponding information is generated and send
* @returns {null}
*/
sample_stream.registerSettings = function (resolve, reject, settings) {
counter++;
resolve(getData(settings));
setLastUpdated();
};
/** Over-ridden method. The counter and the lastUpdated variables are updated and the corresponding information is generated and send
* @returns {null}
*/
sample_stream.unregisterSettings = function (resolve, reject, settings) {
// success
counter--;
setLastUpdated();
resolve();
};
sample_stream.startStreamServer(configJSON.portNumber, function () {
console.log('Listening on ' + configJSON.portNumber);
updateAll();
});
setInterval(updateAll, 60 * 60 * 60);