<repo_name>andrewn/radiotag-node-tester<file_sep>/main.js
module.exports = {
  radiotag: require('./lib/radiotag'),
  cpa: require('./lib/cpa')
};<file_sep>/bin/flow
#!/usr/bin/env node

var Promise  = require('es6-promise').Promise,
    radiotag = require('radiotag.js'),
    cpa      = require('cpa.js'),
    config;

try {
  config = require('../config.json').radiotag;
} catch (e) {
  config = {};
}

var serverName = process.env['SERVER'],
    server = config[serverName];

if (!server) {
  console.error('No server', serverName, 'found in config.json');
  process.exit();
}

var uri       = server.uri,
    stationId = server.stationId;

authProvider(stationId, uri)
  .then(register, errorHandlerForStep('init'))
  .then(requestUserCode, errorHandlerForStep('register'))
  .then(askUserToVerifyCode, errorHandlerForStep('requestUserCode'))
  .then(pollForAccessToken, errorHandlerForStep('askUserToVerifyCode'))
  .then(tagWithAccessToken, errorHandlerForStep('pollForAccessToken'))
  .then(displayTag, errorHandlerForStep('tagWithAccessToken'))
  .then(null, errorHandlerForStep('catch all'));

/*
  Return an error handler function with msg
*/
function errorHandlerForStep(msg) {
  return function (error) {
    console.error('Error: ', msg, error);
  };
}

/*
  Get auth provider
*/
function authProvider(stationId, uri) {
  return new Promise(function (resolve, reject) {
    console.log('Entire flow');
    console.log('Station id:', stationId);
    console.log('Base URI:', uri, '\n');

    console.log('\nGet auth provider...');
    radiotag.getAuthProvider(uri, function (error, authProviderBaseUrl, modes) {
      if (error) {
        reject(error);
      } else {
        console.log('  authProviderBaseUrl: ', authProviderBaseUrl);
        console.log('  modes: ', modes);
        resolve({
          stationId: stationId,
          uri: uri,
          authProviderBaseUrl: authProviderBaseUrl,
          modes: modes
        });
      }
    });
  });
}

/*
  Register for a clientId and clientSecret
*/
function register(params) {

  console.log('\nCPA register');
  console.log('  authProviderBaseUrl', params.authProviderBaseUrl);

  var domain = radiotag.utils.getDomain(params.uri);
  params.domain = domain;
  console.log('  domain', params.domain);

  return new Promise(function (resolve, reject) {
    cpa.device.registerClient(
      params.authProviderBaseUrl,
      'My Device Name',
      'radiotag-node-test',
      '0.0.1',
      function (error, clientId, clientSecret) {
        if (error) {
          reject(error);
        } else {
          console.log('\nRegistered:');
          console.log('  clientId %s, clientSecret %s', clientId, clientSecret);
          params.clientId = clientId;
          params.clientSecret = clientSecret;
          resolve(params);
        }
      }
    );
  });
}

/*
  CPA:
    Get a user code to show to user
*/
function requestUserCode(params) {
  return new Promise(function (resolve, reject) {
    console.log('\nCPA request user code with ');
    console.log('  authProvider', params.authProviderBaseUrl);
    console.log('  clientId', params.clientId);
    console.log('  clientSecret', params.clientSecret);
    console.log('  domain', params.domain);

    cpa.device.requestUserCode(
      params.authProviderBaseUrl,
      params.clientId,
      params.clientSecret,
      params.domain,
      function (error, data) {
        if (error) {
          reject(error);
        } else {
          console.log('Got user code');
          params.user = data;
          resolve(params);
        }
      }
    );
  });
}

function askUserToVerifyCode(params) {
  console.log('\n\n****\n');
  console.log('Please visit ' + params.user.verification_uri + ' and enter code: ' + params.user.user_code);
  console.log('\n****');

  return Promise.resolve(params);
}

function pollForAccessToken(params) {
  var pollIntervalInSecs = params.user.interval * 1000;

  return new Promise(function (resolve, reject) {
    /* Does a single request for access token
       and resolve, rejects or schedules another request
    */
    function accessToken() {
      process.stdout.write('.');

      cpa.device.requestUserAccessToken(
        params.authProviderBaseUrl,
        params.clientId,
        params.clientSecret,
        params.user.device_code,
        params.domain,
        function tokenDone(error, data) {
          if (error) {
            reject(error);
          } else if (data) {
            console.log('  access token data: ', data);
            params.token = data;
            resolve(params);
          } else {
            setTimeout(accessToken, pollIntervalInSecs);
          }
        }
      );
    }

    accessToken();
  });
}

function tagWithAccessToken(params) {
  return new Promise(function (resolve, reject) {
    radiotag.tag(
      params.stationId,
      params.uri,
      params.token.access_token,
      function (error, tag) {
        if (error) {
          reject(error);
        } else {
          resolve(tag);
        }
      }
    );
  });
}

function displayTag(tag) {
  console.log('\n\n****');
  console.log('Tagged! 🎉');
  console.log(tag);
  console.log('****');

  return Promise.resolve(tag);
}


<file_sep>/README.md
A small utility for testing cpa.js and radiotag.js in node.js

Install
--

    npm install

To use local radiotag.js:

    npm link radiotag.js

To use local cpa.js:

    npm link cpa.js

Configure and use
--

    cp config.json.example config.json

### Entire flow:

To test the entire CPA -> radiotag flow then the minimum config you'll need is:

    {
      "radiotag" : {
        "EBU": {
          "stationId": "0.c222.ce15.ce1.dab",
          "uri": "http://bbc1-cpa.ebu.io/"
        }
      }
    }

Then run:

    SERVER=EBU bin/flow

The entire CPA flow will run, prompting you with a URL and user code on the command line when necessary. When an access code is acuired then a tag will be made.

### Radiotag only

You can test any part of the radiotag.js API by adding a valid server URI, station ID and access token in the `radiotag` section of the config.

Then run:

    SERVER=<name> bin/radiotag <action>

e.g.

    SERVER=BBC bin/radiotag auth

    stationId 0.c222.ce15.ce1.dab
    accessToken ...
    uri ...
    null 'https://radiotag.api.bbci.co.uk/ap/' { client: false, user: true, anonymous: false }

### CPA only

You can test any part of the cpa.js API by adding valid keys in the `cpa` section of the config.

Then run:

    SERVER=<name> bin/cpa <action>

e.g.

    SERVER=BBC bin/cpa register

    authProvider https://auth-cpa.ebu.io/
    clientName My CPA device
    clientId 100054
    clientSecret f8960c7c324588145e5ba627d3abd1ed
    domain bbc1-cpa.ebu.io
    softwareId cpa-radiotag-node-test
    softwareVersion 0.0.0
    Register success: client_id: 1039455   client_secret: d6560b27efe15df67af0a14c2a90b9cc

<file_sep>/lib/radiotag.js
var radiotag = require('radiotag.js'),
    config;

try {
  config = require('../config.json').radiotag;
} catch (e) {
  config = {};
}

var serverName = process.env['SERVER'],
    server = config[serverName];

if (!server) {
  console.error('No server', serverName, 'found in config.json');
  process.exit();
}

var stationId   = server.stationId,
    accessToken = server.accessToken,
    uri         = server.uri;

console.log('stationId', stationId);
console.log('accessToken', accessToken);
console.log('uri', uri);

module.exports = {
  tag: function () {
    radiotag.tag(stationId, uri, accessToken, tagDone);
  },
  list: function () {
    radiotag.listTags(uri, accessToken, listDone);
  },
  auth: function () {
    radiotag.getAuthProvider(uri, authDone);
  }
}

function listDone(error, tags) {
  console.log('List', error, tags);
}

function tagDone(error, tag) {
  if (error) {
    console.error('Tag error', error);
  } else {
    console.log('Tag', tag);
  }
}

function authDone(err, authProviderBaseUrl, modes) {
   console.log(err, authProviderBaseUrl, modes);
 }