/
gcloud.js
149 lines (120 loc) · 5.5 KB
/
gcloud.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Google Cloud-specific definitions for sigfox-gcloud
/* eslint-disable max-len,new-cap */
const isProduction = (process.env.NODE_ENV === 'production'); // True on production server.
const functionName = process.env.FUNCTION_NAME || 'unknown_function';
const logName = process.env.LOGNAME || 'sigfox-gcloud';
const projectId = process.env.GCLOUD_PROJECT; // Google Cloud project ID.
// This is needed because Node.js doesn't cache DNS lookups and will cause DNS quota to be exceeded in Google Cloud.
require('dnscache')({ enable: true });
// If the file .env exists in the current folder, use it to populate
// the environment variables e.g. GCLOUD_PROJECT=myproject
require('dotenv').load();
const path = require('path');
// Assume that the Google Service Account credentials are present in this file.
// This is needed for calling Google Cloud PubSub, Logging, Trace, Debug APIs
// on Linux / MacOS / Ubuntu on Windows. Assume it's in the main folder for the app.
const keyFilename = path.join(process.cwd(), 'google-credentials.json');
const credentials = isProduction ? null : { projectId, keyFilename };
// //////////////////////////////////////////////////////////////////////////////////// endregion
// region Utility Functions
// //////////////////////////////////////////////////////////////////////////////////// endregion
// region Instrumentation Functions: Trace the execution of this Sigfox Callback across multiple Cloud Functions via Google Cloud Tracing
const tracing = process.env.DISABLE_TRACE ? null : require('gcloud-trace')();
const tracingtrace = process.env.DISABLE_TRACE ? null : require('gcloud-trace/src/trace');
function createRootTrace(req, rootTraceId) {
// Return the root trace for instrumentation.
// eslint-disable-next-line new-cap
if (!tracingtrace) return null;
return new tracingtrace(tracing, rootTraceId);
}
function startTrace(/* req */) {
// Start the trace.
if (!tracing) return null;
return tracing.startTrace();
}
// //////////////////////////////////////////////////////////////////////////////////// endregion
// region Logging Functions: Log to Google Cloud Logging, Error Reporting and PubSub
let loggingLog = null;
const errorReport = require('@google-cloud/error-reporting')({ reportUnhandledRejections: true });
function getLogger() {
// Return the logger object for writing logs. Create it if necessary.
if (!loggingLog) { // eslint-disable-next-line global-require
loggingLog = require('@google-cloud/logging')(credentials)
.log(logName, { removeCircular: true }); // Mark circular refs by [Circular]
console.log('created_logger');
}
return loggingLog;
}
function reportError(req, err /* action, para */) {
// Report the error to the Stackdriver Error Reporting API
errorReport.report(err);
}
function shutdown(/* req */) {
// Clean up any logging connections. Google Cloud Logger must be disposed
// or it will throw errors later.
loggingLog = null;
console.log('disposed_logger');
return Promise.resolve('OK');
}
// //////////////////////////////////////////////////////////////////////////////////// endregion
// region Messaging Functions: Dispatch messages between Cloud Functions via Google Cloud PubSub
const pubsub = require('@google-cloud/pubsub');
const queueCache = {};
function getQueue(req, projectId0, topicName) {
// Return the PubSub queue for the topic.
const key = [projectId0, topicName].join('|');
if (queueCache[key]) return queueCache[key];
const pubsubCredentials = Object.assign({}, credentials,
{ projectId: projectId0 || projectId }); // eslint-disable-next-line no-use-before-define
const topic = pubsub(pubsubCredentials).topic(topicName);
queueCache[key] = topic;
return topic;
}
// //////////////////////////////////////////////////////////////////////////////////// endregion
// region Device State Functions: Memorise the device state with Google Cloud IoT
// TODO
// //////////////////////////////////////////////////////////////////////////////////// endregion
// region Startup
function init(para1, para2) {
// Run the function in the wrapper, passed as "this".
// Call the callback upon success or failure.
// Returns a promise. The number of parameters depend on
// whether this function is called in HTTP Mode (para=req,res)
// or PubSub Queue Mode (para=event).
// Check the mode of trigger: HTTP or PubSub.
if (process.env.FUNCTION_TRIGGER_TYPE === 'HTTP_TRIGGER') {
// HTTP Function: (para1,para2) = (req,res)
const req = Object.assign({}, para1); // Shallow clone the request.
const res = para2;
req.res = res; // Save the response object in the request for easy reference.
return { req, res };
}
// Else it will be PubSub Queue Mode: para1=event.
// Decode the body.
// TODO: const event = para1;
return {};
}
// //////////////////////////////////////////////////////////////////////////////////// endregion
// region Module Exports
module.exports = {
projectId,
functionName,
logName,
sourceName: process.env.GAE_SERVICE || process.env.FUNCTION_NAME || logName,
credentials,
// Logging
getLogger,
reportError,
// Instrumentation
startTrace,
createRootTrace,
// Messaging
getQueue,
// Device State: Not implemented yet for Google Cloud. Will probably be based on Google Cloud IoT.
createDevice: (/* req, device */) => Promise.resolve({}),
getDeviceState: (/* req, device */) => Promise.resolve({}),
updateDeviceState: (req, device, state) => Promise.resolve(state),
// Startup
init,
shutdown,
};