Skip to content

Commit

Permalink
feat: support LRO methods (#27)
Browse files Browse the repository at this point in the history
* init lro setup

* upgrade google-gax

* add dom to tsconfig for browser check

* copy protos to build/

* Revert "copy protos to build/"

This reverts commit 028eb20.

* copy protos/ to build/

* load protos from json file

* LRO methods & update baseline test

* gts fix

* update gts version and fix back the format

* change path name & update baseline
  • Loading branch information
xiaozhenliu-gg5 authored Oct 1, 2019
1 parent ce6276a commit 65994f9
Show file tree
Hide file tree
Showing 5 changed files with 266 additions and 103 deletions.
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

0 comments on commit 65994f9

Please sign in to comment.