Skip to content

Commit 13aeeff

Browse files
Merge pull request #5 from dowjones/feature/doc_exceeded_check
unify functionality for setting creds for both auth flows
2 parents 3c31658 + a0cdab5 commit 13aeeff

18 files changed

+541
-403
lines changed

Listener.js

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
11
const PubSub = require('@google-cloud/pubsub');
2-
const ConfigUtil = require('./config/ConfigUtil');
3-
const fetchCredentials = require('./services/fetchCredentials');
4-
const path = require('path');
5-
const os = require('os');
2+
const Config = require('./config/Config');
3+
const ExtractionApiService = require('./services/ExtractionApiService');
64

75
/** Class that allows you to listen to a number of Dow Jones PubSub subscriptions. This is a singleton. */
86
class Listener {
97

108
constructor(accountCredentials, pubsubClient) {
11-
this.configUtil = new ConfigUtil(accountCredentials);
9+
this.config = new Config(accountCredentials);
10+
this.extractionApiService = new ExtractionApiService(
11+
this.config.getExtractionApiHost(),
12+
this.config.getAccountCredentials(),
13+
this.config.getOauthUrl()
14+
);
1215
this.pubsubClient = pubsubClient;
1316
}
1417

15-
initialize(credentials, pubSub) {
18+
initialize(credentials) {
1619
this.projectId = credentials.project_id;
1720
this.pubsubClient = this.pubsubClient || new PubSub({
1821
projectId: this.projectId,
1922
credentials
2023
});
2124

22-
this.defaultSubscriptionId = this.configUtil.getSubscriptionId();
25+
this.defaultSubscriptionId = this.config.getSubscriptionId();
2326
}
2427

2528
/**
@@ -39,24 +42,20 @@ class Listener {
3942
* want to use the default.
4043
*/
4144
listen(onMessageCallback, subscription) {
42-
return this.getCredentials().then((credentials) => {
45+
return this.extractionApiService.getStreamingCredentials().then((credentials) => {
4346
this.initialize(credentials);
4447
this.readyListener(onMessageCallback, subscription);
4548
return true;
4649
}).catch((err) => {
4750
if (err.message) {
48-
console.log(err.message);
51+
console.error(err.message);
4952
} else {
50-
console.log(JSON.stringify(err));
53+
console.error(JSON.stringify(err));
5154
}
5255
return false;
5356
});
5457
}
5558

56-
getCredentials() {
57-
return fetchCredentials(this.configUtil);
58-
}
59-
6059
readyListener(onMessageCallback, subscriptionId) {
6160
const sub = subscriptionId || this.defaultSubscriptionId;
6261

@@ -75,20 +74,42 @@ class Listener {
7574

7675
const pubsubSubscription = this.pubsubClient.subscription(subscriptionFullName);
7776

77+
this.extractionApiService.getAccountInfo().then(accountInfo =>
78+
this.checkDocCountExceeded(sub, accountInfo.max_allowed_document_extracts));
79+
7880
pubsubSubscription.get().then((data) => {
7981
const pubsubSub = data[0];
8082
pubsubSub.on('message', onMessage);
8183
pubsubSub.on('error', (subErr) => {
82-
console.log(`On Subscription Error: ${subErr}`);
84+
console.error(`On Subscription Error: ${subErr}`);
8385
pubsubSub.removeListener('message', onMessage);
8486
pubsubSub.on('message', onMessage);
8587
});
8688
}).catch((err) => {
87-
console.log(`Error retrieving subscription from Google PubSub: ${err}`);
89+
console.error(`Error retrieving subscription from Google PubSub: ${err}`);
8890
});
8991

9092
console.log('Listeners for subscriptions have been configured, set and await message arrival.');
9193
}
94+
95+
checkDocCountExceeded(subscriptionId, maxDocumentsReceived) {
96+
const streamDisabledMsg =
97+
`\nOOPS! Looks like you've exceeded the maximum number of documents received for your account (${maxDocumentsReceived}).\n` +
98+
'As such, no new documents will be added to your stream\'s queue.\n' +
99+
'However, you won\'t lose access to any documents that have already been added to the queue.\n' +
100+
'These will continue to be streamed to you.\n' +
101+
'Contact your account administrator with any questions or to upgrade your account limits.';
102+
const interval = 300000;
103+
this.extractionApiService.isStreamDisabled(subscriptionId).then((isDisabled) => {
104+
if (isDisabled) {
105+
console.error(streamDisabledMsg);
106+
}
107+
setTimeout(this.checkDocCountExceeded.bind(this), interval, subscriptionId, maxDocumentsReceived);
108+
}).catch((err) => {
109+
console.error(err);
110+
setTimeout(this.checkDocCountExceeded.bind(this), interval, subscriptionId, maxDocumentsReceived);
111+
});
112+
}
92113
}
93114

94115
module.exports = Listener;

README.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Alternatively you can simply check out this project from Git.
1616
#### Authentication Options
1717
There are two credential types that can be used.
1818

19-
Option 1. Service Account Id (service_account_id)
19+
Option 1. User Key
2020

2121
Option 2. Client Credentials (user_id, client_id, password)
2222

@@ -27,10 +27,10 @@ They will not override values passed directly to the `Listener` constructor (Opt
2727

2828
Option 1. Set environment variables.
2929

30-
###### Service Account ID
30+
###### User Key
3131

32-
**SERVICE_ACCOUNT_ID**
33-
Dow Jones provided Service Account ID.
32+
**USER_KEY**
33+
Dow Jones provided user key.
3434

3535
**SUBSCRIPTION_ID**
3636
This environment variable holds the subscription ID.
@@ -53,11 +53,11 @@ Option 1. Set environment variables.
5353

5454
Option 2. Modify the 'customerConfig.json' file. In this project's root you will find the 'customerConfig.json' file. Add your credentials and subscription ID. Ensure your additions follow the JSON data format conventions.
5555

56-
###### Service Account Id
56+
###### User Key
5757

5858
```
5959
{
60-
"service_account_id": "<Dow Jones provided Service Account Id>",
60+
"user_key": "<Dow Jones provided user key>",
6161
"subscription_id": "<Subscription ID returned upon stream creation>"
6262
}
6363
```
@@ -86,15 +86,15 @@ Option 3: Passing values as function arguments. Specifically you can pass either
8686
8787
const listener = new Listener({
8888
/**
89-
Service Account ID
89+
User Key
9090
*/
91-
service_account_id: "<YOUR SERVICE ACCOUNT ID HERE>",
91+
user_key: "<YOUR USER KEY HERE>",
9292
/**
9393
Client Credentials
9494
*/
9595
user_id: "<YOUR USER ID HERE>",
9696
client_id: "<YOUR CLIENT ID HERE>",
97-
password: "<YOUR PASSWORD HERE>"
97+
password: "<YOUR PASSWORD HERE>",
9898
});
9999
listener.listen(onMessageCallback);
100100
~~~~
@@ -137,11 +137,11 @@ Step 1: Build the docker image. Execute the following command line:
137137

138138
Step 2: Run the docker image
139139

140-
###### Service Account ID
140+
###### User Key
141141

142142
~~~
143143
docker run -it \
144-
-e SERVICE_ACCOUNT_ID="<your service account ID"> \
144+
-e USER_KEY="<your user key"> \
145145
-e SUBSCRIPTION_ID="<your subscription ID>" \
146146
dj-dna-streaming-javascript
147147
~~~

config/Config.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
const ConfigFileUtil = require('./ConfigFileUtil');
2+
const path = require('path');
3+
4+
class Config {
5+
6+
constructor(credentials) {
7+
this.credentials = credentials;
8+
9+
this.Constants = {
10+
OAUTH_URL_ENV: 'OAUTH_URL',
11+
OAUTH_URL_DEFAULT: 'https://accounts.dowjones.com/oauth2/v1/token',
12+
USER_ID_ENV: 'USER_ID',
13+
CLIENT_ID_ENV: 'CLIENT_ID',
14+
PASSWORD_ENV: 'PASSWORD',
15+
USER_KEY_ENV: 'USER_KEY',
16+
SUBSCRIPTION_ID_ENV: 'SUBSCRIPTION_ID',
17+
EXTRACTION_API_HOST_ENV: 'EXTRACTION_API_HOST',
18+
EXTRACTION_API_HOST_DEFAULT: 'https://api.dowjones.com',
19+
CONFIG_FILE_PATH_DEFAULT: path.join(__dirname, '../customerConfig.json')
20+
};
21+
22+
this._configFileUtil = new ConfigFileUtil(this.Constants.CONFIG_FILE_PATH_DEFAULT);
23+
}
24+
25+
// needed to use a separate config file for testing
26+
setConfigFilePath(configFilePath) {
27+
this._configFileUtil = new ConfigFileUtil(configFilePath);
28+
}
29+
30+
getExtractionApiHost() {
31+
const extractionApiHost = process.env[this.Constants.EXTRACTION_API_HOST_ENV];
32+
return extractionApiHost || this.Constants.EXTRACTION_API_HOST_DEFAULT;
33+
}
34+
35+
getOauthUrl() {
36+
const oauthUrl = process.env[this.Constants.OAUTH_URL_ENV];
37+
return oauthUrl || this.Constants.OAUTH_URL_DEFAULT;
38+
}
39+
40+
getSubscriptionId() {
41+
const subscriptionId = process.env[this.Constants.SUBSCRIPTION_ID_ENV];
42+
return subscriptionId || this._configFileUtil.getSubscriptionId();
43+
}
44+
45+
getAccountCredentials() {
46+
// first get credentials from parameters if they're defined there
47+
let accountCreds = this.credentials;
48+
49+
// if creds not passed in as params check env vars for credentials
50+
if (!this._areCredsSet(accountCreds)) {
51+
accountCreds = this._initCredsFromEnv();
52+
53+
// finally check config file for credentials
54+
if (!this._areCredsSet(accountCreds)) {
55+
accountCreds = this._configFileUtil.getAccountCredentials();
56+
}
57+
}
58+
59+
return this._areCredsSet(accountCreds) ? accountCreds : new Error(
60+
'Error: No account credentials specified\n' +
61+
'Must specify user_id, client_id, and password as args to Listener constructor, env vars, or via customerConfig.json file\n' +
62+
'See dj-dna-streaming-javascript README.md'
63+
);
64+
}
65+
66+
_initCredsFromEnv() {
67+
return {
68+
user_id: process.env[this.Constants.USER_ID_ENV],
69+
client_id: process.env[this.Constants.CLIENT_ID_ENV],
70+
password: process.env[this.Constants.PASSWORD_ENV],
71+
user_key: process.env[this.Constants.USER_KEY_ENV]
72+
};
73+
}
74+
75+
_areCredsSet(accountCreds) {
76+
return accountCreds && (accountCreds.user_key || (accountCreds.user_id && accountCreds.client_id && accountCreds.password));
77+
}
78+
}
79+
80+
module.exports = Config;

config/ConfigFileUtil.js

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
const path = require('path');
21
const fs = require('fs');
32
const _ = require('lodash');
43

54
class ConfigFileUtil {
65

7-
constructor() {
8-
this.configFilePath = path.join(__dirname, '../customerConfig.json');
6+
constructor(configFilePath) {
7+
this.configFilePath = configFilePath;
98
this.initialized = false;
109
}
1110

@@ -41,30 +40,17 @@ class ConfigFileUtil {
4140
return this.config.subscription_id;
4241
}
4342

44-
getServiceAccountId() {
45-
if (!this.initialized) {
46-
this.initialize();
47-
}
48-
49-
return _.trim(this.config.service_account_id);
50-
}
51-
5243
getAccountCredentials() {
5344
if (!this.initialized) {
5445
this.initialize();
5546
}
5647

57-
let accountCreds;
58-
59-
if (this.config.user_id && this.config.client_id && this.config.password) {
60-
accountCreds = {
61-
userId: _.trim(this.config.user_id),
62-
clientId: _.trim(this.config.client_id),
63-
password: _.trim(this.config.password)
64-
}
65-
}
66-
67-
return accountCreds;
48+
return {
49+
user_key: _.trim(this.config.user_key),
50+
user_id: _.trim(this.config.user_id),
51+
client_id: _.trim(this.config.client_id),
52+
password: _.trim(this.config.password)
53+
};
6854
}
6955
}
7056

0 commit comments

Comments
 (0)