Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support LRO methods #27

Merged
merged 12 commits into from
Oct 1, 2019
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@
"@types/command-line-args": "^5.0.0",
"@types/get-stdin": "^5.0.1",
"@types/mocha": "^5.2.5",
"@types/node": "^11.12.0",
"@types/node": "^11.13.20",
"@types/nunjucks": "^3.1.0",
"@types/rimraf": "^2.0.2",
"assert-rejects": "^1.0.0",
"c8": "^5.0.1",
"c8": "^5.0.4",
"codecov": "^3.0.4",
"espower-typescript": "^9.0.0",
"google-gax": "^1.6.0",
Expand Down
4 changes: 2 additions & 2 deletions templates/typescript_gapic/package.json.njk
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
"scripts": {
"lint": "gts check",
"clean": "gts clean",
"compile": "tsc -p .",
"compile-protos": "pbjs -p protos -t static-module -o pbjs-genfiles/protos.js {{ api.filesToGenerate.join(' ') }} && pbts pbjs-genfiles/protos.js -o pbjs-genfiles/protos.d.ts",
"compile": "tsc -p . && cp -r protos build/",
"compile-protos": "compileProtos src",
"fix": "gts fix",
"prepare": "npm run compile-protos && npm run compile",
"pretest": "npm run compile-protos && npm run compile"
Expand Down
183 changes: 125 additions & 58 deletions templates/typescript_gapic/src/$version/$service_client.ts.njk
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
{% import "./license.njk" as license %}{{license.license()}}
import * as gax from 'google-gax';
import * as path from 'path';
import * as protobuf from 'protobufjs';

import * as packageJson from '../../package.json';
import * as protos from '../../pbjs-genfiles/protos';
import * as protosTypes from '../../protos/protos';
import * as gapicConfig from './echo_client_config.json';

const version = packageJson.version;
Expand All @@ -14,7 +13,9 @@ export interface ClientOptions extends gax.GrpcClientOptions,
gax.ClientStubOptions {
libName?: string;
libVersion?: string;
clientConfig?: gax.ClientConfig;
clientConfig: gax.ClientConfig;
fallback?: boolean;
apiEndpoint?: string;
}

interface Descriptors {
Expand Down Expand Up @@ -49,42 +50,56 @@ export class {{ service.name }}Client {

constructor(opts: ClientOptions) {
// Ensure that options include the service address and port.
opts = opts || {};
const isBrowser = (typeof window !== 'undefined');
if (isBrowser){
opts.fallback = true;
}
// If we are in browser, we are already using fallback because of the
// "browser" field in package.json.
// But if we were explicitly requested to use fallback, let's do it now.
const gaxModule = !isBrowser && opts.fallback ? gax.fallback : gax;
const servicePath =
opts.servicePath ||
opts.apiEndpoint ||
(this.constructor as typeof {{service.name}}Client).servicePath;

opts = Object.assign(
{
clientConfig: {},
port: (this.constructor as typeof {{ service.name }}Client).port,
servicePath: (this.constructor as typeof {{ service.name }}Client).servicePath,
servicePath: servicePath,
},
opts);

// Create a `gaxGrpc` object, with any grpc-specific options
// sent to the client.
opts.scopes = (this.constructor as typeof {{ service.name }}Client).scopes;
const gaxGrpc = new gax.GrpcClient(opts);
const gaxGrpc = new gaxModule.GrpcClient(opts);

// Save the auth object to the client, for use by other methods.
this.auth = gaxGrpc.auth;
this.auth = (gaxGrpc.auth as gax.GoogleAuth);

// Determine the client header string.
const clientHeader = [
`gl-node/${process.version}`,
`grpc/${gaxGrpc.grpcVersion}`,
`gax/${gax.version}`,
`gax/${gaxModule.version}`,
`gapic/${version}`,
`gl-web/${gaxModule.version}`
];
if (opts.libName && opts.libVersion) {
clientHeader.push(`${opts.libName}/${opts.libVersion}`);
}
// Load the applicable protos.
// For Node.js, pass the path to JSON proto file.
// For browsers, pass the JSON content.

const gaxProtos = Object.assign(
{},
{%- set protosJoiner = joiner() %}
{%- for filename in api.filesToGenerate %}
{{- protosJoiner() }}
gaxGrpc.loadProto(
path.join(__dirname, '..', '..', 'protos'),
'{{ filename }}')
{%- endfor -%}
const nodejsProtoPath = path.join(__dirname, '..', '..', 'protos', 'protos.json');
const protos = gaxGrpc.loadProto(
opts.fallback ?
require("../../protos/protos.json") :
nodejsProtoPath
);
{%- if (service.paging.length > 0) %}

Expand All @@ -96,7 +111,7 @@ export class {{ service.name }}Client {
{%- for method in service.paging %}
{{- pagingJoiner() }}
{{ method.name.toCamelCase() }}:
new gax.PageDescriptor('pageToken', 'nextPageToken', '{{ method.pagingFieldName }}')
new gaxModule.PageDescriptor('pageToken', 'nextPageToken', '{{ method.pagingFieldName }}')
{%- endfor %}
};
{%- endif %}
Expand All @@ -109,41 +124,41 @@ export class {{ service.name }}Client {
{%- set streamingJoiner = joiner() %}
{%- for method in service.streaming %}
{{- streamingJoiner() }}
{{ method.name.toCamelCase() }}: new gax.StreamDescriptor(gax.StreamType.{{ method.streaming }})
{{ method.name.toCamelCase() }}: new gaxModule.StreamDescriptor(gax.StreamType.{{ method.streaming }})
{%- endfor %}
};
{%- endif %}

{%- if (service.longrunning.length > 0) %}
{%- if (service.longRunning.length > 0) %}
// This API contains "long-running operations", which return a
// an Operation object that allows for tracking of the operation,
// rather than holding a request open.
let protoFilesRoot = new gax.GoogleProtoFilesRoot();
{%- for filename in api.filesToGenerate %}
protoFilesRoot = protobuf.loadSync(
path.join(__dirname, '..', '..', 'protos', '{{ filename }}'),
protoFilesRoot);
{%- endfor %}
const protoFilesRoot = opts.fallback?
gaxModule.protobuf.Root.fromJSON(require("../../protos/protos.json")) :
gaxModule.protobuf.loadSync(nodejsProtoPath);

const operationsClient = new gax.lro({
auth: gaxGrpc.auth,
const operationsClient = gaxModule.lro({
auth: this.auth,
// @ts-ignore
grpc: gaxGrpc.grpc,
}).operationsClient(opts);

{%- for method in service.longrunning %}
{%- for method in service.longRunning %}
const {{ method.name.toCamelCase() }}Response = protoFilesRoot.lookup(
'{{ method.longrunning.responseType }}');
'{{ method.longRunning.responseType }}');
const {{ method.name.toCamelCase() }}Metadata = protoFilesRoot.lookup(
'{{ method.longrunning.metadataType }}');
'{{ method.longRunning.metadataType }}');
{%- endfor %}

this._descriptors.longrunning = {
{%- set longrunningJoiner = joiner() %}
{%- for method in service.longrunning %}
{{- longrunningJoiner() }}
{{ method.name.toCamelCase() }}: new gax.LongrunningDescriptor(
{%- set longRunningJoiner = joiner() %}
{%- for method in service.longRunning %}
{{- longRunningJoiner() }}
{{ method.name.toCamelCase() }}: new gaxModule.LongrunningDescriptor(
operationsClient,
// @ts-ignore
{{ method.name.toCamelCase() }}Response.decode.bind({{ method.name.toCamelCase() }}Response),
// @ts-ignore
{{ method.name.toCamelCase() }}Metadata.decode.bind({{ method.name.toCamelCase() }}Metadata))
{%- endfor %}
};
Expand All @@ -161,9 +176,14 @@ export class {{ service.name }}Client {

// Put together the "service stub" for
// google.showcase.v1alpha2.Echo.
const {{ service.name.toCamelCase() }}Stub =
const {{ service.name.toCamelCase() }}Stub = gaxGrpc.createStub(
// @ts-ignore We cannot check types that are loaded in runtime.
gaxGrpc.createStub(gaxProtos.{{ api.naming.protoPackage }}.{{ service.name }}, opts);
opts.fallback ?
// @ts-ignore
protos.lookupService('{{api.naming.protoPackage}}.{{ service.name }}') :
// @ts-ignore
protos.{{api.naming.protoPackage}}.{{ service.name }},
opts);

const {{ service.name.toCamelCase() }}StubMethods =
[
Expand All @@ -175,7 +195,9 @@ export class {{ service.name }}Client {
];

for (const methodName of {{ service.name.toCamelCase() }}StubMethods) {
// @ts-ignore
const innerCallPromise = {{ service.name.toCamelCase() }}Stub.then(
// @ts-ignore
stub => (...args: Array<{}>) => {
return stub[methodName].apply(stub, args);
},
Expand All @@ -198,6 +220,13 @@ export class {{ service.name }}Client {
static get servicePath() {
return '{{ service.hostname }}';
}
/**
* The DNS address for this API service - same as servicePath(),
* exists for compatibility reasons.
*/
static get apiEndpoint() {
return 'localhost';
}

/**
* The port for this API service.
Expand Down Expand Up @@ -246,31 +275,31 @@ export class {{ service.name }}Client {

{%- for method in service.simpleMethods %}
{{ method.name.toCamelCase() }}(
request: protos{{ method.inputInterface }},
request: protosTypes{{ method.inputInterface }},
options?: gax.CallOptions):
Promise<[
protos{{ method.outputInterface }},
protos{{ method.inputInterface }}|undefined, {}|undefined
protosTypes{{ method.outputInterface }},
protosTypes{{ method.inputInterface }}|undefined, {}|undefined
]>;
{{ method.name.toCamelCase() }}(
request: protos{{ method.inputInterface }},
request: protosTypes{{ method.inputInterface }},
options: gax.CallOptions,
callback: Callback<
protos{{ method.outputInterface }},
protos{{ method.inputInterface }}|undefined,
protosTypes{{ method.outputInterface }},
protosTypes{{ method.inputInterface }}|undefined,
{}|undefined>): void;
{{ method.name.toCamelCase() }}(
request: protos{{ method.inputInterface }},
request: protosTypes{{ method.inputInterface }},
optionsOrCallback?: gax.CallOptions|Callback<
protos{{ method.outputInterface }},
protos{{ method.inputInterface }}|undefined, {}|undefined>,
protosTypes{{ method.outputInterface }},
protosTypes{{ method.inputInterface }}|undefined, {}|undefined>,
callback?: Callback<
protos{{ method.outputInterface }},
protos{{ method.inputInterface }}|undefined,
protosTypes{{ method.outputInterface }},
protosTypes{{ method.inputInterface }}|undefined,
{}|undefined>):
Promise<[
protos{{ method.outputInterface }},
protos{{ method.inputInterface }}|undefined, {}|undefined
protosTypes{{ method.outputInterface }},
protosTypes{{ method.inputInterface }}|undefined, {}|undefined
]>|void {
request = request || {};
let options = optionsOrCallback;
Expand All @@ -292,7 +321,7 @@ export class {{ service.name }}Client {
}
{%- elif method.serverStreaming %}
{{ method.name.toCamelCase() }}(
request?: protos{{ method.inputInterface }},
request?: protosTypes{{ method.inputInterface }},
options?: gax.CallOptions):
gax.ServerStreamingCall{
request = request || {};
Expand All @@ -303,21 +332,21 @@ export class {{ service.name }}Client {
{{ method.name.toCamelCase() }}(
options: gax.CallOptions,
callback: Callback<
protos{{ method.outputInterface }},
protos{{ method.inputInterface }}|undefined, {}|undefined>):
protosTypes{{ method.outputInterface }},
protosTypes{{ method.inputInterface }}|undefined, {}|undefined>):
gax.ClientStreamingCall;
{{ method.name.toCamelCase() }}(
callback: Callback<
protos{{ method.outputInterface }},
protos{{ method.inputInterface }}|undefined, {}|undefined>):
protosTypes{{ method.outputInterface }},
protosTypes{{ method.inputInterface }}|undefined, {}|undefined>):
gax.ClientStreamingCall;
{{ method.name.toCamelCase() }}(
optionsOrCallback: gax.CallOptions|Callback<
protos{{ method.outputInterface }},
protos{{ method.inputInterface }}|undefined, {}|undefined>,
protosTypes{{ method.outputInterface }},
protosTypes{{ method.inputInterface }}|undefined, {}|undefined>,
callback?: Callback<
protos{{ method.outputInterface }},
protos{{ method.inputInterface }}|undefined, {}|undefined>):
protosTypes{{ method.outputInterface }},
protosTypes{{ method.inputInterface }}|undefined, {}|undefined>):
gax.ClientStreamingCall {
if (optionsOrCallback instanceof Function && callback === undefined) {
callback = optionsOrCallback;
Expand All @@ -328,4 +357,42 @@ export class {{ service.name }}Client {
}
{%- endif %}
{% endfor %}
{%- for method in service.longRunning %}
{{ method.name.toCamelCase() }}(
request: protosTypes{{ method.inputInterface }},
options?: gax.CallOptions):
Promise<[
protosTypes{{ method.outputInterface }},
protosTypes{{ method.inputInterface }}|undefined, {}|undefined
]>;
{{ method.name.toCamelCase() }}(
request: protosTypes{{ method.inputInterface }},
options: gax.CallOptions,
callback: Callback<
protosTypes{{ method.outputInterface }},
protosTypes{{ method.inputInterface }}|undefined,
{}|undefined>): void;
{{ method.name.toCamelCase() }}(
request: protosTypes{{ method.inputInterface }},
optionsOrCallback?: gax.CallOptions|Callback<
protosTypes{{ method.outputInterface }},
protosTypes{{ method.inputInterface }}|undefined, {}|undefined>,
callback?: Callback<
protosTypes{{ method.outputInterface }},
protosTypes{{ method.inputInterface }}|undefined,
{}|undefined>):
Promise<[
protosTypes{{ method.outputInterface }},
protosTypes{{ method.inputInterface }}|undefined, {}|undefined
]>|void {
request = request || {};
let options = optionsOrCallback;
if (typeof options === 'function' && callback === undefined) {
callback = options;
options = {};
}
options = options || {};
return this._innerApiCalls.{{ method.name.toCamelCase() }}(request, options, callback);
}
{%- endfor %}
}
3 changes: 2 additions & 1 deletion templates/typescript_gapic/tsconfig.json.njk
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"compilerOptions": {
"rootDir": ".",
"outDir": "build",
"resolveJsonModule": true
"resolveJsonModule": true,
"lib": ["es2016", "dom"]
},
"include": [
"src/*.ts",
Expand Down
Loading