Skip to content

Commit

Permalink
Fix line endings. Add invoke-method util file
Browse files Browse the repository at this point in the history
  • Loading branch information
alexandros-megas committed Feb 23, 2024
1 parent 62e29ab commit 64ac6b9
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 25 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -347,4 +347,6 @@ $RECYCLE.BIN/
# Windows shortcuts
*.lnk

# End of https://www.toptal.com/developers/gitignore/api/node,visualstudiocode,macos,windows,linux,intellij
# End of https://www.toptal.com/developers/gitignore/api/node,visualstudiocode,macos,windows,linux,intellij

.vscode
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20.11.0
20.11.0
20 changes: 0 additions & 20 deletions .vscode/settings.json

This file was deleted.

7 changes: 4 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"typescript": "^5.3.3"
},
"dependencies": {
"@grpc/grpc-js": "^1.10.1",
"axios": "^1.6.7",
"clarifai-nodejs-grpc": "^10.0.9",
"google-protobuf": "^3.21.2",
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// export all the things
200 changes: 200 additions & 0 deletions src/utils/invoke-method.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
import { Metadata, ServiceError, CallOptions } from "@grpc/grpc-js";
import { UserAppIDSet } from "clarifai-nodejs-grpc/proto/clarifai/api/resources_pb";
import { V2Client } from "clarifai-nodejs-grpc/proto/clarifai/api/service_grpc_pb";
import { ListInputsRequest } from "clarifai-nodejs-grpc/proto/clarifai/api/service_pb";

type GrpcCb<Res> = (err: ServiceError | null, res: Res) => void;

type Method1<Req, Res> = (req: Req, callback: GrpcCb<Res>) => void;
type Method2<Req, Res> = (
req: Req,
metadata: Metadata,
callback: GrpcCb<Res>,
) => void;
type Method3<Req, Res> = (
req: Req,
metadata: Metadata,
options: Partial<CallOptions>,
callback: GrpcCb<Res>,
) => void;

type Method<Req, Res> =
| Method1<Req, Res>
| Method2<Req, Res>
| Method3<Req, Res>;

/**
* This is a helper function to create a callback that resolves or rejects a promise.
* The error type is always `ServiceError` since that's what the grpc package uses, rather
* than `any` which is the standard node.js callback error type.
*/
function makeCallback<Res>(
resolve: (value: Res) => void,
reject: (reason?: ServiceError) => void,
): GrpcCb<Res> {
return (err, res) => {
if (err) {
reject(err);
} else {
resolve(res);
}
};
}

/**
* Invoke a method that takes 1 argument: the request object.
* @param client the client.
* @param method the method.
* @param req the request object.
* @returns a promise that resolves to the response object.
*/
function invokeMethod1<Req, Res>(
client: V2Client,
method: Method1<Req, Res>,
req: Req,
): Promise<Res> {
return new Promise((resolve, reject) => {
method.call(client, req, makeCallback(resolve, reject));
});
}

/**
* Invoke a method that takes 2 arguments: the request object and request metadata such as authentication token.
* @param client the client.
* @param method the method.
* @param req the request object.
* @param metadata the metadata object.
* @returns a promise that resolves to the response object.
*/
function invokeMethod2<Req, Res>(
client: V2Client,
method: Method2<Req, Res>,
req: Req,
metadata: Metadata,
): Promise<Res> {
return new Promise((resolve, reject) => {
method.call(client, req, metadata, makeCallback(resolve, reject));
});
}

/**
* Invoke a method that takes 3 arguments: the request object, request metadata, and call options.
* @param client the client.
* @param method the method.
* @param req the request object.
* @param metadata the metadata object.
* @param options the call options.
* @returns a promise that resolves to the response object.
*/
function invokeMethod3<Req, Res>(
client: V2Client,
method: Method3<Req, Res>,
req: Req,
metadata: Metadata,
options: Partial<CallOptions>,
): Promise<Res> {
return new Promise((resolve, reject) => {
method.call(client, req, metadata, options, makeCallback(resolve, reject));
});
}

/*
* This is the main function that we will use to invoke any gRPC method.
*/
export function invokeMethod<Req, Res>(
client: V2Client,
method: Method1<Req, Res>,
req: Req,
): Promise<Res>;
export function invokeMethod<Req, Res>(
client: V2Client,
method: Method2<Req, Res>,
req: Req,
metadata: Metadata,
): Promise<Res>;
export function invokeMethod<Req, Res>(
client: V2Client,
method: Method3<Req, Res>,
req: Req,
metadata: Metadata,
options: Partial<CallOptions>,
): Promise<Res>;
export function invokeMethod<Req, Res>(
client: V2Client,
method: Method1<Req, Res> | Method2<Req, Res> | Method3<Req, Res>,
req: Req,
metadata?: Metadata,
options?: Partial<CallOptions>,
): Promise<Res> {
if (isMethod1(method)) {
return invokeMethod1(client, method, req);
}
if (isMethod2(method)) {
return invokeMethod2(client, method, req, metadata!);
}
return invokeMethod3(client, method, req, metadata!, options!);
}

function isMethod1<A, B>(m: Method<A, B>): m is Method1<A, B> {
return m.length === 2;
}
function isMethod2<A, B>(m: Method<A, B>): m is Method2<A, B> {
return m.length === 3;
}

/**************************EXAMPLES*************************/

async function __example__one__(client: V2Client) {
const userAppId = new UserAppIDSet();
userAppId.setAppId("main");
userAppId.setUserId("clarifai");

const req = new ListInputsRequest();
req.setUserAppId(userAppId);

// res1 is correctly inferred as MultiInputsResponse
const res1 = await invokeMethod(client, client.listInputs, req);
console.log(res1);
}

async function __example__two__(client: V2Client) {
const userAppId = new UserAppIDSet();
userAppId.setAppId("main");
userAppId.setUserId("clarifai");

const req = new ListInputsRequest();
req.setUserAppId(userAppId);

const metadata = new Metadata();
metadata.set("authorization", "my-api-key");

// res2 is still correctly inferred as MultiInputsResponse
const res2 = await invokeMethod(client, client.listInputs, req, metadata);
console.log(res2);
}

async function __example__three__(client: V2Client) {
const userAppId = new UserAppIDSet();
userAppId.setAppId("main");
userAppId.setUserId("clarifai");

const req = new ListInputsRequest();
req.setUserAppId(userAppId);

const metadata = new Metadata();
metadata.set("authorization", "my-api-key");

const options = {
deadline: Date.now() + 1000,
};

// res3 is still correctly inferred as MultiInputsResponse
const res3 = await invokeMethod(
client,
client.listInputs,
req,
metadata,
options,
);
console.log(res3);
}

0 comments on commit 64ac6b9

Please sign in to comment.