UNPKG

4.72 kBJavaScriptView Raw
1"use strict";
2// Copyright 2016 Google LLC
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15Object.defineProperty(exports, "__esModule", { value: true });
16exports.Operation = void 0;
17/*!
18 * @module common/operation
19 */
20const service_object_1 = require("./service-object");
21const util_1 = require("util");
22// eslint-disable-next-line @typescript-eslint/no-explicit-any
23class Operation extends service_object_1.ServiceObject {
24 /**
25 * An Operation object allows you to interact with APIs that take longer to
26 * process things.
27 *
28 * @constructor
29 * @alias module:common/operation
30 *
31 * @param {object} config - Configuration object.
32 * @param {module:common/service|module:common/serviceObject|module:common/grpcService|module:common/grpcServiceObject} config.parent - The parent object.
33 */
34 constructor(config) {
35 const methods = {
36 /**
37 * Checks to see if an operation exists.
38 */
39 exists: true,
40 /**
41 * Retrieves the operation.
42 */
43 get: true,
44 /**
45 * Retrieves metadata for the operation.
46 */
47 getMetadata: {
48 reqOpts: {
49 name: config.id,
50 },
51 },
52 };
53 config = Object.assign({
54 baseUrl: '',
55 }, config);
56 // eslint-disable-next-line @typescript-eslint/no-explicit-any
57 config.methods = (config.methods || methods);
58 super(config);
59 this.completeListeners = 0;
60 this.hasActiveListeners = false;
61 this.listenForEvents_();
62 }
63 /**
64 * Wraps the `complete` and `error` events in a Promise.
65 *
66 * @return {Promise}
67 */
68 promise() {
69 return new Promise((resolve, reject) => {
70 this.on('error', reject).on('complete', (metadata) => {
71 resolve([metadata]);
72 });
73 });
74 }
75 /**
76 * Begin listening for events on the operation. This method keeps track of how
77 * many "complete" listeners are registered and removed, making sure polling
78 * is handled automatically.
79 *
80 * As long as there is one active "complete" listener, the connection is open.
81 * When there are no more listeners, the polling stops.
82 *
83 * @private
84 */
85 listenForEvents_() {
86 this.on('newListener', (event) => {
87 if (event === 'complete') {
88 this.completeListeners++;
89 if (!this.hasActiveListeners) {
90 this.hasActiveListeners = true;
91 this.startPolling_();
92 }
93 }
94 });
95 this.on('removeListener', (event) => {
96 if (event === 'complete' && --this.completeListeners === 0) {
97 this.hasActiveListeners = false;
98 }
99 });
100 }
101 /**
102 * Poll for a status update. Returns null for an incomplete
103 * status, and metadata for a complete status.
104 *
105 * @private
106 */
107 poll_(callback) {
108 this.getMetadata((err, body) => {
109 if (err || body.error) {
110 callback(err || body.error);
111 return;
112 }
113 if (!body.done) {
114 callback(null);
115 return;
116 }
117 callback(null, body);
118 });
119 }
120 /**
121 * Poll `getMetadata` to check the operation's status. This runs a loop to
122 * ping the API on an interval.
123 *
124 * Note: This method is automatically called once a "complete" event handler
125 * is registered on the operation.
126 *
127 * @private
128 */
129 async startPolling_() {
130 if (!this.hasActiveListeners) {
131 return;
132 }
133 try {
134 const metadata = await (0, util_1.promisify)(this.poll_.bind(this))();
135 if (!metadata) {
136 setTimeout(this.startPolling_.bind(this), this.pollIntervalMs || 500);
137 return;
138 }
139 this.emit('complete', metadata);
140 }
141 catch (err) {
142 this.emit('error', err);
143 }
144 }
145}
146exports.Operation = Operation;
147//# sourceMappingURL=operation.js.map
\No newline at end of file