-
Notifications
You must be signed in to change notification settings - Fork 19
Open
Description
Hi @Mitch528,
What a great work, thanks for sharing it with us, really.
I'm really new to react native, and I'm trying to figure out why expo does not register "Grpc" as a "NativeModule".
I even tried to fork and very much simplify/debug, to no end.
If I directly call the native and copy the typescript wrapper (lol) it does the trick... somehow
I don't want to take too much of your time, but if you heard of anything, or has any suggestion for me to look up, I'm trying for some some days. If I can't figure out, maybe I will really keep the copied the typescript wrapper part, that is working for now
This never works (NativeModules.Grpc is not there, NativeModules is {} empty object, always)
import { GrpcClient } from '@mitch528/react-native-grpc';
import { NativeModules } from 'react-native';
import { AuthServiceClientImpl } from '../../proto/auth';
// The native function (IOS/Android) that actually make the gRPC calls.
// The library makes it available under the name `Grpc`.
const Grpc = NativeModules.Grpc;
if (!Grpc || typeof Grpc.setHost !== 'function') {
console.log('[Grpc] GrpcClient is not properly initialized. Use custom dev client via `expo run:android`.');
}
const client = new GrpcClient();
console.log('Grpc:', Grpc);
console.log('NativeModules:', NativeModules);
Grpc.setHost('host:6969');
export const authClient = new AuthServiceClientImpl({
request: async (service, method, data) => {
const path = `/${service}/${method}`;
const { responseData } = await client.unaryCall(path, data)
return responseData;
},
});This completelly works (NativeModules.Grpc is defined, always)
import { GrpcError, GrpcUnaryCall, type GrpcMetadata, type ServerOutputStream } from '@mitch528/react-native-grpc'; // only for types
import { fromByteArray, toByteArray } from 'base64-js';
import { NativeEventEmitter, NativeModules } from 'react-native';
import { AuthServiceClientImpl } from '../../proto/auth';
const GrpcClient = NativeModules.Grpc;
const GrpcEmitter = new NativeEventEmitter(GrpcClient);
GrpcEmitter.addListener('grpc-call', (event) => {
const deferred = deferredMap.get(event.id);
if (deferred) {
switch (event.type) {
case 'headers':
deferred.headers?.resolve(event.payload);
break;
case 'response':
const data = toByteArray(event.payload);
deferred.data?.notifyData(data);
deferred.response?.resolve(data);
break;
case 'trailers':
deferred.trailers?.resolve(event.payload);
deferred.data?.notifyComplete();
deferredMap.delete(event.id);
break;
case 'error':
const error = new GrpcError(event.error, event.code, event.trailers);
deferred.response?.reject(error);
deferred.data?.noitfyError(error);
break;
}
}
});
if (!GrpcClient || typeof GrpcClient.setHost !== 'function') {
throw new Error('[Grpc] GrpcClient is not properly initialized. Use custom dev client via `expo run:android`.');
}
GrpcClient.setHost('host:6969');
let idCtr = 1;
function getId(): number {
return idCtr++;
}
type GrpcRequestObject = {
data: string;
};
type Deferred<T> = {
completed: boolean;
promise: Promise<T>;
resolve: (value: T) => void;
reject: (reason: any) => void;
};
function createDeferred<T>(signal: AbortSignal) {
const deferred: Deferred<T> = { completed: false } as Deferred<T>;
deferred.promise = new Promise<T>((resolve, reject) => {
deferred.resolve = (value) => {
deferred.completed = true;
resolve(value);
};
deferred.reject = (reason) => {
deferred.completed = true;
reject(reason);
};
});
signal.addEventListener('abort', () => {
if (!deferred.completed) {
deferred.reject('aborted');
}
});
return deferred;
}
type DeferredCalls = {
headers?: Deferred<GrpcMetadata>;
response?: Deferred<Uint8Array>;
trailers?: Deferred<GrpcMetadata>;
data?: ServerOutputStream;
};
type DeferredCallMap = Map<number, DeferredCalls>;
const deferredMap: DeferredCallMap = new Map<number, DeferredCalls>();
export const authClient = new AuthServiceClientImpl({
request: async (service, method, data) => {
const path = `/${service}/${method}`;
// lib code
const requestData = fromByteArray(data);
const obj: GrpcRequestObject = {
data: requestData,
};
const id = getId();
const abort = new AbortController();
abort.signal.addEventListener('abort', () => {
GrpcClient.cancelGrpcCall(id);
});
const response = createDeferred<Uint8Array>(abort.signal);
const headers = createDeferred<GrpcMetadata>(abort.signal);
const trailers = createDeferred<GrpcMetadata>(abort.signal);
deferredMap.set(id, {
response,
headers,
trailers,
});
//
// console.log('req data', data, typeof data);
// console.log('req path', path);
// console.log('req headers', headers);
// console.log('GrpcClient.unaryCall', GrpcClient.unaryCall)
GrpcClient.unaryCall(id, path, obj, {});
const call = new GrpcUnaryCall(
method,
data,
{},
headers.promise,
response.promise,
trailers.promise,
abort as any,
);
// console.log('result', call);
// console.log('result end');
const res = await call.response;
console.log('res', res);
const head = await call.headers;
console.log('head', head);
const trai = await call.trailers;
console.log('trai', trai);
return res!;
},
});Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels