From 1f720232beb84239f2b348482e259f380a5bc39a Mon Sep 17 00:00:00 2001 From: Krishna Date: Thu, 9 Feb 2023 15:11:43 +0530 Subject: [PATCH 01/14] pod spec update --- README.md | 4 ++-- example/ios/Podfile.lock | 4 ++-- package.json | 12 ++++++------ react-native-grpc.podspec | 2 +- scripts/bootstrap.js | 2 +- src/client.ts | 12 +++++++++++- tsconfig.json | 2 +- 7 files changed, 24 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index dea66b5..68af55a 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,13 @@ gRPC for react-native ## Installation ```sh -npm install @mitch528/react-native-grpc +npm install @krishnafkh/react-native-grpc ``` ## Usage ```ts -import { GrpcClient, GrpcMetadata } from '@mitch528/react-native-grpc'; +import { GrpcClient, GrpcMetadata } from '@krishnafkh/react-native-grpc'; GrpcClient.setHost('example.com'); diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 6db48da..4645840 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -259,7 +259,7 @@ PODS: - React-jsinspector (0.70.6) - React-logger (0.70.6): - glog - - react-native-grpc (1.0.0-1): + - react-native-grpc (1.0.2): - gRPC-Swift - React-Core - React-perflogger (0.70.6) @@ -637,7 +637,7 @@ SPEC CHECKSUMS: React-jsiexecutor: b4a65947391c658450151275aa406f2b8263178f React-jsinspector: 60769e5a0a6d4b32294a2456077f59d0266f9a8b React-logger: 1623c216abaa88974afce404dc8f479406bbc3a0 - react-native-grpc: 328ef8ca6228c1a408dc0ebe3d0d5eab949fd13a + react-native-grpc: 9cfbb1f3064b90afaad667ee7a517cd37e7e9e66 React-perflogger: 8c79399b0500a30ee8152d0f9f11beae7fc36595 React-RCTActionSheet: 7316773acabb374642b926c19aef1c115df5c466 React-RCTAnimation: 5341e288375451297057391227f691d9b2326c3d diff --git a/package.json b/package.json index 75095fc..be147b1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "@mitch528/react-native-grpc", - "version": "1.0.0-6", + "name": "@krishnafkh/react-native-grpc", + "version": "1.0.2", "description": "gRPC for react-native", "main": "lib/commonjs/index", "module": "lib/module/index", @@ -38,13 +38,13 @@ "android", "grpc" ], - "repository": "https://github.com/Mitch528/react-native-grpc", - "author": "Mitch528 (https://github.com/Mitch528)", + "repository": "https://github.com/krishnafkh/react-native-grpc", + "author": "Krishna (https://github.com/krishnafkh/)", "license": "MIT", "bugs": { - "url": "https://github.com/Mitch528/react-native-grpc/issues" + "url": "https://github.com/krishnafkh/react-native-grpc/issues" }, - "homepage": "https://github.com/Mitch528/react-native-grpc#readme", + "homepage": "https://github.com/krishnafkh/react-native-grpc#readme", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" diff --git a/react-native-grpc.podspec b/react-native-grpc.podspec index 1c59af1..c3bc4f5 100644 --- a/react-native-grpc.podspec +++ b/react-native-grpc.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.authors = package["author"] s.platforms = { :ios => "10.0" } - s.source = { :git => "https://github.com/Mitch528/react-native-grpc.git", :tag => "#{s.version}" } + s.source = { :git => "https://github.com/krishnafkh/react-native-grpc.git", :tag => "#{s.version}" } s.source_files = "ios/**/*.{h,m,mm,swift}" diff --git a/scripts/bootstrap.js b/scripts/bootstrap.js index cdba731..25e043e 100644 --- a/scripts/bootstrap.js +++ b/scripts/bootstrap.js @@ -24,7 +24,7 @@ if (process.cwd() !== root || args.length) { const scriptsDest = path.join( root, - 'example/node_modules/@mitch528/react-native-grpc/scripts' + 'example/node_modules/@krishnafkh/react-native-grpc/scripts' ); if (!fs.existsSync(path.dirname(scriptsDest))) { diff --git a/src/client.ts b/src/client.ts index 8eb5d22..09db882 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,6 +1,6 @@ import { AbortController, AbortSignal } from 'abort-controller'; import { fromByteArray, toByteArray } from 'base64-js'; -import { NativeEventEmitter, NativeModules } from 'react-native'; +import { NativeEventEmitter, NativeModules, Platform } from 'react-native'; import { GrpcError } from './errors'; import { GrpcServerStreamingCall, @@ -175,11 +175,21 @@ export class GrpcClient { setInsecure(insecure: boolean): void { Grpc.setInsecure(insecure); } + + /** + * setCompression - only for Android. + * @param enable + * @param compressorName + * @param limit + */ setCompression( enable: boolean, compressorName: string, limit?: number ): void { + if (Platform.OS !== 'android') { + return; + } Grpc.setCompression(enable, compressorName, limit?.toString()); } setKeepalive(enabled: boolean, time: number, timeout: number): void { diff --git a/tsconfig.json b/tsconfig.json index 7cccb8f..990e9d4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "baseUrl": ".", "paths": { - "@mitch528/react-native-grpc": [ + "@krishnafkh/react-native-grpc": [ "./src/index" ] }, From ec3c4c778faf4c35a817de68ba37eeef6b9fe9db Mon Sep 17 00:00:00 2001 From: Shivam-fkh <109650911+Shivam-fkh@users.noreply.github.com> Date: Wed, 12 Apr 2023 15:28:41 +0530 Subject: [PATCH 02/14] Reverted swift dependency for ios pods (#1) * Shivam | reverted grpc swift pod dependency * Shivam | added pod target * Shivam | removed swift dependency --------- Co-authored-by: Shivam-NL --- ios/ByteBuffer+GRPCPayload.swift | 18 -- ios/Grpc.h | 9 +- ios/Grpc.m | 347 +++++++++++++++++--- ios/Grpc.xcodeproj/project.pbxproj | 18 +- ios/GrpcError.swift | 15 - ios/RNGrpc.swift | 411 ------------------------ ios/react-native-grpc-Bridging-Header.h | 3 - react-native-grpc.podspec | 10 +- 8 files changed, 326 insertions(+), 505 deletions(-) delete mode 100644 ios/ByteBuffer+GRPCPayload.swift delete mode 100644 ios/GrpcError.swift delete mode 100644 ios/RNGrpc.swift delete mode 100644 ios/react-native-grpc-Bridging-Header.h diff --git a/ios/ByteBuffer+GRPCPayload.swift b/ios/ByteBuffer+GRPCPayload.swift deleted file mode 100644 index 1415e91..0000000 --- a/ios/ByteBuffer+GRPCPayload.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// Created by Mitchell Kutchuk on 11/14/22. -// - -import Foundation -import NIO -import GRPC - -extension ByteBuffer: GRPCPayload { - public init(serializedByteBuffer: inout ByteBuffer) { - self = serializedByteBuffer - } - - public func serialize(into buffer: inout ByteBuffer) { - var copy = self - buffer.writeBuffer(©) - } -} \ No newline at end of file diff --git a/ios/Grpc.h b/ios/Grpc.h index e06b7b1..b91e0c9 100644 --- a/ios/Grpc.h +++ b/ios/Grpc.h @@ -1,5 +1,10 @@ #import +#import -@interface Grpc : NSObject +@interface Grpc : RCTEventEmitter -@end +@property (nonatomic, copy) NSString* grpcHost; +@property (nonatomic, copy) NSNumber* grpcResponseSizeLimit; +@property (nonatomic, assign) BOOL grpcInsecure; + +@end \ No newline at end of file diff --git a/ios/Grpc.m b/ios/Grpc.m index 4fc94f6..209dbb2 100644 --- a/ios/Grpc.m +++ b/ios/Grpc.m @@ -1,52 +1,325 @@ -#import "React/RCTBridgeModule.h" -#import "RCTEventEmitter.h" +#import "Grpc.h" +#import +#import -@interface RCT_EXTERN_MODULE(Grpc, RCTEventEmitter) +@interface GrpcResponseHandler : NSObject -RCT_EXTERN_METHOD(setInsecure: - (nonnull NSNumber *)insecure) +- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback + messageCallback:(void (^)(id))messageCallback + closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback + writeDataCallback:(void (^)(void))writeDataCallback; -RCT_EXTERN_METHOD(setResponseSizeLimit: - (nonnull NSNumber *)limit) +- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback + messageCallback:(void (^)(id))messageCallback + closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback; -RCT_EXTERN_METHOD(setHost: - (NSString *) host) +@end -RCT_EXTERN_METHOD(setCompression: - (nonnull NSNumber *) enabled - compressorName: (NSString *) compressorName - limit: (NSString *) limit) +@implementation GrpcResponseHandler { + void (^_initialMetadataCallback)(NSDictionary *); -RCT_EXTERN_METHOD(setKeepalive: -(nonnull NSNumber *) enabled - time: (nonnull NSNumber *) time - timeout: (nonnull NSNumber *) timeout -) + void (^_messageCallback)(id); -RCT_EXTERN_METHOD(getIsInsecure: - (RCTPromiseResolveBlock) resolve reject: - (RCTPromiseRejectBlock) reject) + void (^_closeCallback)(NSDictionary *, NSError *); -RCT_EXTERN_METHOD(getResponseSizeLimit: - (RCTPromiseResolveBlock) resolve reject: - (RCTPromiseRejectBlock) reject) + void (^_writeDataCallback)(void); -RCT_EXTERN_METHOD(getHost: - (RCTPromiseResolveBlock) resolve reject: - (RCTPromiseRejectBlock) reject) + dispatch_queue_t _dispatchQueue; +} -RCT_EXTERN_METHOD(unaryCall: - (nonnull NSNumber *) callId path: (NSString*) path obj: (NSDictionary*) obj headers:(NSDictionary*) headers resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback + messageCallback:(void (^)(id))messageCallback + closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback + writeDataCallback:(void (^)(void))writeDataCallback { + if ((self = [super init])) { + _initialMetadataCallback = initialMetadataCallback; + _messageCallback = messageCallback; + _closeCallback = closeCallback; + _writeDataCallback = writeDataCallback; + _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); + } + return self; +} -RCT_EXTERN_METHOD(serverStreamingCall: - (nonnull NSNumber *) callId path: (NSString*) path obj: (NSDictionary*) obj headers:(NSDictionary*) headers resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback + messageCallback:(void (^)(id))messageCallback + closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback { + return [self initWithInitialMetadataCallback:initialMetadataCallback + messageCallback:messageCallback + closeCallback:closeCallback + writeDataCallback:nil]; +} -RCT_EXTERN_METHOD(clientStreamingCall: - (nonnull NSNumber *) callId path: (NSString*) path obj: (NSDictionary*) obj headers:(NSDictionary*) headers resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +- (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata { + if (self->_initialMetadataCallback) { + self->_initialMetadataCallback(initialMetadata); + } +} -RCT_EXTERN_METHOD(finishClientStreaming: - (nonnull NSNumber *) callId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +- (void)didReceiveRawMessage:(id)message { + if (self->_messageCallback) { + self->_messageCallback(message); + } +} + +- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { + if (self->_closeCallback) { + self->_closeCallback(trailingMetadata, error); + } +} + +- (void)didWriteData { + if (self->_writeDataCallback) { + self->_writeDataCallback(); + } +} + +- (dispatch_queue_t)dispatchQueue { + return _dispatchQueue; +} + +@end + +@implementation Grpc { + bool hasListeners; + NSMutableDictionary *calls; +} + +- (instancetype)init { + if (self = [super init]) { + calls = [[NSMutableDictionary alloc] init]; + } + + return self; +} + +// Will be called when this module's first listener is added. +- (void)startObserving { + hasListeners = YES; + // Set up any upstream listeners or background tasks as necessary +} + +// Will be called when this module's last listener is removed, or on dealloc. +- (void)stopObserving { + hasListeners = NO; + // Remove upstream listeners, stop unnecessary background tasks +} + +- (NSArray *)supportedEvents { + return @[@"grpc-call"]; +} + +- (GRPCCallOptions *)getCallOptionsWithHeaders:(NSDictionary *)headers { + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.initialMetadata = headers; + options.transport = self.grpcInsecure ? GRPCDefaultTransportImplList.core_insecure : GRPCDefaultTransportImplList.core_secure; + + if (self.grpcResponseSizeLimit != nil) { + options.responseSizeLimit = self.grpcResponseSizeLimit.unsignedLongValue; + } + + return options; +} + +RCT_EXPORT_METHOD(getHost: + (RCTPromiseResolveBlock) resolve) { + resolve(self.grpcHost); +} + +RCT_EXPORT_METHOD(getIsInsecure: + (RCTPromiseResolveBlock) resolve) { + resolve([NSNumber numberWithBool:self.grpcInsecure]); +} + +RCT_EXPORT_METHOD(setHost: + (NSString *) host) { + self.grpcHost = host; +} + + +RCT_EXPORT_METHOD(setInsecure: + (nonnull NSNumber*) insecure) { + self.grpcInsecure = [insecure boolValue]; +} + +RCT_EXPORT_METHOD(setResponseSizeLimit: + (nonnull NSNumber*) limit) { + self.grpcResponseSizeLimit = limit; +} + +RCT_EXPORT_METHOD(unaryCall: + (nonnull NSNumber*)callId + path:(NSString*)path + obj:(NSDictionary*)obj + headers:(NSDictionary*)headers + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + NSData *requestData = [[NSData alloc] initWithBase64EncodedString:[obj valueForKey:@"data"] options:NSDataBase64DecodingIgnoreUnknownCharacters]; + + GRPCCall2 *call = [self startGrpcCallWithId:callId path:path headers:headers]; + + [call writeData:requestData]; + [call finish]; + + [calls setObject:call forKey:callId]; + + resolve([NSNull null]); +} + +RCT_EXPORT_METHOD(serverStreamingCall: + (nonnull NSNumber*)callId + path:(NSString*)path + obj:(NSDictionary*)obj + headers:(NSDictionary*)headers + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + NSData *requestData = [[NSData alloc] initWithBase64EncodedString:[obj valueForKey:@"data"] options:NSDataBase64DecodingIgnoreUnknownCharacters]; + + GRPCCall2 *call = [self startGrpcCallWithId:callId path:path headers:headers]; + + [call writeData:requestData]; + [call finish]; + + [calls setObject:call forKey:callId]; + + resolve([NSNull null]); +} + +RCT_EXPORT_METHOD(cancelGrpcCall: + (nonnull NSNumber*)callId + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + GRPCCall2 *call = [calls objectForKey:callId]; + + if (call != nil) { + [call cancel]; + + resolve([NSNumber numberWithBool:true]); + } else { + resolve([NSNumber numberWithBool:false]); + } +} + +RCT_EXPORT_METHOD(clientStreamingCall: + (nonnull NSNumber*)callId + path:(NSString*)path + obj:(NSDictionary*)obj + headers:(NSDictionary*)headers + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + NSData *requestData = [[NSData alloc] initWithBase64EncodedString:[obj valueForKey:@"data"] options:NSDataBase64DecodingIgnoreUnknownCharacters]; + + GRPCCall2 *call = [calls objectForKey:callId]; + + if (call == nil) { + call = [self startGrpcCallWithId:callId path:path headers:headers]; + + [calls setObject:call forKey:callId]; + } + + [call writeData:requestData]; + + resolve([NSNull null]); +} + +RCT_EXPORT_METHOD(finishClientStreaming: + (nonnull NSNumber*)callId + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + GRPCCall2 *call = [calls objectForKey:callId]; + + if (call != nil) { + [call finish]; + + resolve([NSNumber numberWithBool:true]); + } else { + resolve([NSNumber numberWithBool:false]); + } +} + +- (GRPCCall2 *)startGrpcCallWithId:(NSNumber *)callId path:(NSString *)path headers:(NSDictionary *)headers { + GRPCRequestOptions *requestOptions = [[GRPCRequestOptions alloc] initWithHost:self.grpcHost + path:path + safety:GRPCCallSafetyDefault]; + + GRPCCallOptions *callOptions = [self getCallOptionsWithHeaders:headers]; + + GrpcResponseHandler *handler = [[GrpcResponseHandler alloc] initWithInitialMetadataCallback:^(NSDictionary *initialMetadata) { + if (self->hasListeners) { + NSDictionary *responseHeaders = [[NSMutableDictionary alloc] initWithDictionary:initialMetadata]; + + [responseHeaders enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL *exit) { + if ([object isKindOfClass:[NSData class]]) { + [responseHeaders setValue:[object base64EncodedStringWithOptions:0] forKey:key]; + } + }]; + + NSDictionary *event = @{ + @"id": callId, + @"type": @"headers", + @"payload": responseHeaders, + }; + + [self sendEventWithName:@"grpc-call" body:event]; + } + } + messageCallback:^(id message) { + NSData *data = (NSData *) message; + + if (self->hasListeners) { + NSDictionary *event = @{ + @"id": callId, + @"type": @"response", + @"payload": [data base64EncodedStringWithOptions:nil], + }; + + [self sendEventWithName:@"grpc-call" body:event]; + } + } + closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { + [calls removeObjectForKey:callId]; + + NSDictionary *responseTrailers = [[NSMutableDictionary alloc] initWithDictionary:trailingMetadata]; + + [responseTrailers enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL *exit) { + if ([object isKindOfClass:[NSData class]]) { + [responseTrailers setValue:[object base64EncodedStringWithOptions:0] forKey:key]; + } + }]; + + if (self->hasListeners) { + if (error != nil) { + NSDictionary *event = @{ + @"id": callId, + @"type": @"error", + @"error": error.localizedDescription, + @"code": [NSNumber numberWithLong:error.code], + @"trailers": responseTrailers, + }; + + [self sendEventWithName:@"grpc-call" body:event]; + } else { + NSDictionary *event = @{ + @"id": callId, + @"type": @"trailers", + @"payload": responseTrailers, + }; + + [self sendEventWithName:@"grpc-call" body:event]; + } + } + } + ]; + + GRPCCall2 *call = [[GRPCCall2 alloc] initWithRequestOptions:requestOptions + responseHandler:handler + callOptions:callOptions]; + + [call start]; + + return call; +} + +RCT_EXPORT_MODULE() -RCT_EXTERN_METHOD(cancelGrpcCall: - (nonnull NSNumber *) callId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) @end \ No newline at end of file diff --git a/ios/Grpc.xcodeproj/project.pbxproj b/ios/Grpc.xcodeproj/project.pbxproj index 6bfe22e..1e62edd 100644 --- a/ios/Grpc.xcodeproj/project.pbxproj +++ b/ios/Grpc.xcodeproj/project.pbxproj @@ -21,11 +21,6 @@ /* Begin PBXFileReference section */ 134814201AA4EA6300B7C361 /* libGrpc.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libGrpc.a; sourceTree = BUILT_PRODUCTS_DIR; }; B3E7B5891CC2AC0600A0062D /* Grpc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Grpc.m; sourceTree = ""; }; - EB245ED12945270800E49A04 /* Grpc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Grpc.h; sourceTree = ""; }; - EB88E79329295B440030506F /* RNGrpc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNGrpc.swift; sourceTree = ""; }; - EB88E79529295B440030506F /* ByteBuffer+GRPCPayload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ByteBuffer+GRPCPayload.swift"; sourceTree = ""; }; - EB88E79929295B450030506F /* GrpcError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GrpcError.swift; sourceTree = ""; }; - EB88E79F29295C6E0030506F /* react-native-grpc-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "react-native-grpc-Bridging-Header.h"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -50,11 +45,6 @@ 58B511D21A9E6C8500147676 = { isa = PBXGroup; children = ( - EB245ED12945270800E49A04 /* Grpc.h */, - EB88E79F29295C6E0030506F /* react-native-grpc-Bridging-Header.h */, - EB88E79529295B440030506F /* ByteBuffer+GRPCPayload.swift */, - EB88E79929295B450030506F /* GrpcError.swift */, - EB88E79329295B440030506F /* RNGrpc.swift */, B3E7B5891CC2AC0600A0062D /* Grpc.m */, 134814211AA4EA7D00B7C361 /* Products */, ); @@ -224,14 +214,12 @@ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../../../React/**", "$(SRCROOT)/../../react-native/React/**", - "$(SRCROOT)/../node_modules/react-native/React/**", - "$(SRCROOT)/../../../../../ios/Pods/Headers/**", ); LIBRARY_SEARCH_PATHS = "$(inherited)"; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = Grpc; SKIP_INSTALL = YES; - SWIFT_OBJC_BRIDGING_HEADER = "react-native-grpc-Bridging-Header.h"; + SWIFT_OBJC_BRIDGING_HEADER = "Grpc-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; @@ -245,14 +233,12 @@ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../../../React/**", "$(SRCROOT)/../../react-native/React/**", - "$(SRCROOT)/../node_modules/react-native/React/**", - "$(SRCROOT)/../../../../../ios/Pods/Headers/**", ); LIBRARY_SEARCH_PATHS = "$(inherited)"; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = Grpc; SKIP_INSTALL = YES; - SWIFT_OBJC_BRIDGING_HEADER = "react-native-grpc-Bridging-Header.h"; + SWIFT_OBJC_BRIDGING_HEADER = "Grpc-Bridging-Header.h"; SWIFT_VERSION = 5.0; }; name = Release; diff --git a/ios/GrpcError.swift b/ios/GrpcError.swift deleted file mode 100644 index cd68b48..0000000 --- a/ios/GrpcError.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// Created by Mitchell Kutchuk on 11/14/22. -// - -import Foundation - -enum GrpcError: String, Error { - case invalidHost = "Host is invalid" - case invalidHeader = "Header value is invalid" - case invalidData = "Data is invalid" - case invalidCallId = "Call id is invalid" - case callIdTypeMismatch = "Call with id did not match call type" - case connectionFailure = "Connection failure" - case notImplemented = "Not implemented" -} \ No newline at end of file diff --git a/ios/RNGrpc.swift b/ios/RNGrpc.swift deleted file mode 100644 index 505c255..0000000 --- a/ios/RNGrpc.swift +++ /dev/null @@ -1,411 +0,0 @@ -// -// Grpc.swift -// react-native-grpc -// -// Created by Mitchell Kutchuk on 11/12/22. -// - -import Foundation -import GRPC -import NIO -import NIOHPACK - -typealias GrpcCall = any ClientCall - -@objc(Grpc) -class RNGrpc: RCTEventEmitter { - private let group = PlatformSupport.makeEventLoopGroup(loopCount: System.coreCount) - - var grpcInsecure = false - var grpcHost: String? - var grpcResponseSizeLimit: Int? - var grpcCompression: Bool? - var grpcCompressorName: String? - var grpcCompressionLimit: Int? - var grpcKeepaliveEnabled: Bool? - var grpcKeepaliveTime: Int64? - var grpcKeepaliveTimeout: Int64? - var calls = [Int: GrpcCall]() - var connection: GRPCChannel? - - deinit { - try! group.syncShutdownGracefully() - } - - @objc - public func setInsecure(_ insecure: NSNumber) { - self.grpcInsecure = insecure.boolValue - self.handleOptionsChange() - } - - @objc - public func setHost(_ host: String) { - self.grpcHost = host - self.handleOptionsChange() - } - - @objc - public func setCompression(_ enabled: NSNumber, compressorName: String, - limit: String?) { - self.grpcCompression = enabled.boolValue - self.grpcCompressorName = compressorName - self.grpcCompressionLimit = Int(limit ?? "") - self.handleOptionsChange() - } - - @objc - public func setKeepalive(_ enabled: NSNumber, time: NSNumber, timeout: NSNumber) { - self.grpcKeepaliveEnabled = enabled.boolValue - self.grpcKeepaliveTime = time.int64Value - self.grpcKeepaliveTimeout = timeout.int64Value - self.handleOptionsChange() - } - - @objc - public func setResponseSizeLimit(_ responseSizeLimit: NSNumber) { - self.grpcResponseSizeLimit = responseSizeLimit.intValue - self.handleOptionsChange() - } - - @objc - public func getResponseSizeLimit(_ resolve: @escaping RCTPromiseResolveBlock, - reject: @escaping RCTPromiseRejectBlock) { - resolve(self.grpcResponseSizeLimit) - } - - @objc - public func getIsInsecure(_ resolve: @escaping RCTPromiseResolveBlock, - reject: @escaping RCTPromiseRejectBlock) { - resolve(self.grpcInsecure) - } - - @objc - public func getHost(_ resolve: @escaping RCTPromiseResolveBlock, - reject: @escaping RCTPromiseRejectBlock) { - resolve(self.grpcHost) - } - - @objc - override func constantsToExport() -> [AnyHashable: Any]! { - [:] - } - - @objc - override static func requiresMainQueueSetup() -> Bool { - false - } - - @objc - public func unaryCall(_ callId: NSNumber, - path: String, - obj: NSDictionary, - headers: NSDictionary, - resolve: @escaping RCTPromiseResolveBlock, - reject: @escaping RCTPromiseRejectBlock) { - do { - try self.startGrpcCallWithId(callId: callId.intValue, obj: obj, type: .unary, path: path, headers: headers) - - resolve(nil) - } catch { - reject("grpc", error.localizedDescription, error) - } - } - - @objc - public func serverStreamingCall(_ callId: NSNumber, - path: String, - obj: NSDictionary, - headers: NSDictionary, - resolve: @escaping RCTPromiseResolveBlock, - reject: @escaping RCTPromiseRejectBlock) { - do { - try self.startGrpcCallWithId(callId: callId.intValue, obj: obj, type: .serverStreaming, path: path, headers: headers) - - resolve(nil) - } catch { - reject("grpc", error.localizedDescription, error) - } - } - - @objc - public func clientStreamingCall(_ callId: NSNumber, - path: String, - obj: NSDictionary, - headers: NSDictionary, - resolve: @escaping RCTPromiseResolveBlock, - reject: @escaping RCTPromiseRejectBlock) { - do { - var call: GrpcCall? = self.calls[callId.intValue] - - if call == nil { - call = try self.startGrpcCallWithId(callId: callId.intValue, obj: obj, type: .clientStreaming, path: path, headers: headers) - } - - guard let clientCall = call as? ClientStreamingCall else { - throw GrpcError.callIdTypeMismatch - } - - guard let base64 = obj["data"] as? String, let data = Data(base64Encoded: base64) else { - throw GrpcError.invalidData - } - - let payload = ByteBuffer(data: data) - - clientCall.sendMessage(payload) - - resolve(true) - } catch { - reject("grpc", error.localizedDescription, error) - } - } - - @objc - public func finishClientStreaming(_ callId: NSNumber, - resolve: @escaping RCTPromiseResolveBlock, - reject: @escaping RCTPromiseRejectBlock) { - do { - guard let call = self.calls[callId.intValue] else { - throw GrpcError.invalidCallId - } - - guard let clientCall = call as? ClientStreamingCall else { - throw GrpcError.callIdTypeMismatch - } - - clientCall.sendEnd() - .whenComplete({ result in - resolve(nil) - }) - } catch { - reject("grpc", error.localizedDescription, error) - } - } - - @objc - public func cancelGrpcCall(_ callId: NSNumber, - resolve: @escaping RCTPromiseResolveBlock, - reject: @escaping RCTPromiseRejectBlock) { - guard let call = self.calls[callId.intValue] else { - resolve(false) - - return - } - - call.cancel(promise: nil) - - resolve(true) - } - - - private func startGrpcCallWithId(callId: Int, - obj: NSDictionary, - type: GRPCCallType, - path: String, - headers: NSDictionary) throws -> GrpcCall { - guard let conn = self.connection else { - throw GrpcError.connectionFailure - } - - guard let base64 = obj["data"] as? String, let data = Data(base64Encoded: base64) else { - throw GrpcError.invalidData - } - - let payload = ByteBuffer(data: data) - - let headerDict = headers.allKeys.map { - (String(describing: $0), String(describing: headers[$0]!)) - } - - let options = self.getCallOptionsWithHeaders(headers: HPACKHeaders(headerDict)) - - var call: GrpcCall - - var headers = [String: String]() - var trailers = [String: String]() - - func dispatchEvent(event: NSDictionary) { - self.sendEvent(withName: "grpc-call", body: event) - } - - func handleResponseResult(result: Result) { - switch result { - case .success(let response): - let data = Data(buffer: response) - let event: NSDictionary = [ - "id": callId, - "type": "response", - "payload": data.base64EncodedString() - ] - - dispatchEvent(event: event) - case .failure(let error): - let status = error as? GRPCStatus - - let event: NSDictionary = [ - "id": callId, - "type": "error", - "code": status?.code.rawValue ?? -1, - "error": status?.message ?? status?.description ?? "", - "trailers": NSDictionary(dictionary: trailers) - ] - - dispatchEvent(event: event) - } - } - - func removeCall() { - DispatchQueue.main.async { - self.calls.removeValue(forKey: callId) - } - } - - switch type { - case .unary: - let unaryCall: UnaryCall = conn.makeUnaryCall(path: path, request: payload, callOptions: options) - call = unaryCall - - unaryCall.response.whenComplete { result in - handleResponseResult(result: result) - removeCall() - } - case .clientStreaming: - let clientStreaming: ClientStreamingCall = conn.makeClientStreamingCall(path: path, callOptions: options) - - call = clientStreaming - - clientStreaming.response.whenComplete({ result in - handleResponseResult(result: result) - removeCall() - }) - case .serverStreaming: - let serverStreaming: ServerStreamingCall = conn.makeServerStreamingCall(path: path, request: payload, callOptions: options, interceptors: [ClientInterceptor](), handler: { response in - let data = Data(buffer: response) - let event: NSDictionary = [ - "id": callId, - "type": "response", - "payload": data.base64EncodedString() - ] - - dispatchEvent(event: event) - }) - - call = serverStreaming - default: - throw GrpcError.notImplemented - } - - call.initialMetadata.whenSuccess { result in - for data in result { - headers[data.name] = data.value - } - - let event: NSDictionary = [ - "id": callId, - "type": "headers", - "payload": NSDictionary(dictionary: headers) - ] - - dispatchEvent(event: event) - } - - call.trailingMetadata.whenSuccess { result in - for data in result { - trailers[data.name] = data.value - } - - let event: NSDictionary = [ - "id": callId, - "type": "trailers", - "payload": NSDictionary(dictionary: trailers) - ] - - dispatchEvent(event: event) - } - - calls[callId] = call - - return call - } - - private func getCallOptionsWithHeaders(headers: HPACKHeaders) -> CallOptions { - var encoding: ClientMessageEncoding = .disabled - - if let enabled = self.grpcCompression, enabled { - let compressionAlgorithm: [CompressionAlgorithm] - let limit = self.grpcCompressionLimit ?? .max - - switch self.grpcCompressorName { - case "gzip": - compressionAlgorithm = [.gzip] - case "deflate": - compressionAlgorithm = [.deflate] - case "identity": - compressionAlgorithm = [.identity] - default: - compressionAlgorithm = CompressionAlgorithm.all - } - - encoding = ClientMessageEncoding.enabled( - .init(forRequests: compressionAlgorithm.first, - acceptableForResponses: compressionAlgorithm, - decompressionLimit: .absolute(limit) - ) - ) - } - - return CallOptions(customMetadata: headers, messageEncoding: encoding) - } - - private func handleOptionsChange() { - if let conn = self.connection { - let loop = self.group.next() - conn.closeGracefully(deadline: .distantFuture, promise: loop.makePromise()) - } - - self.connection = try? self.createConnection() - } - - private func createConnection() throws -> GRPCChannel? { - guard let host = self.grpcHost else { - throw GrpcError.invalidHost - } - - guard let url = URLComponents(string: "https://\(host)"), let host = url.host else { - throw GrpcError.invalidHost - } - - let port = url.port ?? (self.grpcInsecure ? 80 : 443) - - var config = GRPCChannelPool.Configuration.with( - target: .hostAndPort(host, port), - transportSecurity: self.grpcInsecure ? .plaintext : .tls(.makeClientDefault(compatibleWith: self.group)), - eventLoopGroup: self.group - ) - - if let maxReceiveSize = self.grpcResponseSizeLimit { - config.maximumReceiveMessageLength = maxReceiveSize - } - - if let enabled = grpcKeepaliveEnabled, enabled { - let interval = self.grpcKeepaliveTime != nil ? TimeAmount.seconds(self.grpcKeepaliveTime!) : TimeAmount.nanoseconds(.max) - - let timeout = TimeAmount.seconds(grpcKeepaliveTimeout ?? 20) - - let keepalive = ClientConnectionKeepalive( - interval: interval, - timeout: timeout, - permitWithoutCalls: true - ) - - config.keepalive = keepalive - } - - return try? GRPCChannelPool.with(configuration: config) - } - - - @objc - override func supportedEvents() -> [String] { - ["grpc-call"] - } -} diff --git a/ios/react-native-grpc-Bridging-Header.h b/ios/react-native-grpc-Bridging-Header.h deleted file mode 100644 index 8992b22..0000000 --- a/ios/react-native-grpc-Bridging-Header.h +++ /dev/null @@ -1,3 +0,0 @@ -#import -#import -#import diff --git a/react-native-grpc.podspec b/react-native-grpc.podspec index c3bc4f5..5651bc7 100644 --- a/react-native-grpc.podspec +++ b/react-native-grpc.podspec @@ -15,12 +15,16 @@ Pod::Spec.new do |s| s.source_files = "ios/**/*.{h,m,mm,swift}" - s.static_framework = true s.dependency "React-Core" - s.dependency "gRPC-Swift" + s.dependency "gRPC" # Pods directory corresponding to this app's Podfile, relative to the location of this podspec. pods_root = 'Pods' -end + + s.pod_target_xcconfig = { + # This is needed by all pods that depend on gRPC-RxLibrary: + 'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES', + } +end \ No newline at end of file From f9a3276d7d828c3c5ca0253a9f286d3f392d7819 Mon Sep 17 00:00:00 2001 From: Pradyumna Sahoo Date: Mon, 4 Sep 2023 19:12:40 +0530 Subject: [PATCH 03/14] grpc_reset_connection (#2) * grpc_reset_connection * package-name-fix * package-name-fix * type-script-added * comments-added * comments-added * removed unwanted --------- Co-authored-by: Krishna --- .../java/com/reactnativegrpc/GrpcModule.java | 63 ++++++++++++++++++- src/client.ts | 57 ++++++++++++++++- 2 files changed, 117 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/com/reactnativegrpc/GrpcModule.java b/android/src/main/java/com/reactnativegrpc/GrpcModule.java index c0e50ea..9c87682 100644 --- a/android/src/main/java/com/reactnativegrpc/GrpcModule.java +++ b/android/src/main/java/com/reactnativegrpc/GrpcModule.java @@ -1,8 +1,12 @@ package com.reactnativegrpc; - +import android.util.Log; +import android.widget.Toast; import android.util.Base64; +import android.util.Log; +import android.widget.Toast; import androidx.annotation.NonNull; +import androidx.annotation.UiThread; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Promise; @@ -19,6 +23,7 @@ import io.grpc.CallOptions; import io.grpc.ClientCall; +import io.grpc.ConnectivityState; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; import io.grpc.Metadata; @@ -40,6 +45,8 @@ public class GrpcModule extends ReactContextBaseJavaModule { private ManagedChannel managedChannel = null; + private boolean isUiLogEnabled = false; + public GrpcModule(ReactApplicationContext context) { this.context = context; } @@ -332,9 +339,9 @@ private static String normalizePath(String path) { private void handleOptionsChanged() { if (this.managedChannel != null) { + this.managedChannel.resetConnectBackoff(); this.managedChannel.shutdown(); } - this.managedChannel = createManagedChannel(); } @@ -359,4 +366,56 @@ private ManagedChannel createManagedChannel() { managedChannel = channelBuilder.build(); return managedChannel; } + + @ReactMethod + public void resetConnection(final String message){ + handleOptionsChanged(); + + showToast("resetConnection "+message); + } + + @ReactMethod + public void onConnectionStateChange(){ + if(null == managedChannel) return; + + final ConnectivityState connectivityState = managedChannel.getState(true); + if(ConnectivityState.CONNECTING == connectivityState){ + showToast("onConnectionState CONNECTING"); + } else if(ConnectivityState.IDLE == connectivityState){ + showToast("onConnectionState IDLE"); + } else if(ConnectivityState.READY == connectivityState){ + showToast("onConnectionState READY"); + } else if(ConnectivityState.TRANSIENT_FAILURE == connectivityState){ + showToast("onConnectionState TRANSIENT_FAILURE"); + } else if(ConnectivityState.SHUTDOWN == connectivityState){ + showToast("onConnectionState SHUTDOWN"); + } else { + showToast("onConnectionState UNDEFINED"); + } + if(ConnectivityState.TRANSIENT_FAILURE == connectivityState && managedChannel.isTerminated() || managedChannel.isShutdown()){ + resetConnection("onConnectionStateChange"); + } + } + + @ReactMethod + public void enterIdle(){ + if(null == managedChannel) return; + + managedChannel.enterIdle(); + + showToast("enterIdle"); + } + + @ReactMethod + public void setUiLogEnabled(boolean isUiLogEnabled){ + this.isUiLogEnabled = isUiLogEnabled; + } + + @UiThread + private void showToast(final String message){ + if(!isUiLogEnabled || null == context) return; + + Toast.makeText(context,message,Toast.LENGTH_SHORT).show(); + Log.d("GRPC_MODULE",message); + } } diff --git a/src/client.ts b/src/client.ts index 09db882..e8a4f94 100644 --- a/src/client.ts +++ b/src/client.ts @@ -21,6 +21,11 @@ type GrpcType = { setCompression(enable: boolean, compressorName: string, limit?: string): void; setKeepalive(enabled: boolean, time: number, timeout: number): void; setResponseSizeLimit(limitInBytes: number): void; + resetConnection(message: string):void; + setKeepAliveTime(keepAliveTime: number):void; + onConnectionStateChange():void; + setUiLogEnabled(enable:boolean):void; + enterIdle():void; unaryCall( id: number, path: string, @@ -187,7 +192,7 @@ export class GrpcClient { compressorName: string, limit?: number ): void { - if (Platform.OS !== 'android') { + if (!this.isAndroid()) { return; } Grpc.setCompression(enable, compressorName, limit?.toString()); @@ -198,6 +203,49 @@ export class GrpcClient { setResponseSizeLimit(limitInBytes: number): void { Grpc.setResponseSizeLimit(limitInBytes); } + + /** + * resetConnection - only for Android + * @param message - to debug where we are calling 'resetConnection' + * */ + resetConnection(message: string): void { + if (!this.isAndroid()) { + return; + } + Grpc.resetConnection(message); + } + /** + * setUiLogEnabled - only for Android + * @param enable - to debug where we are calling current grpc connection status + * in ui + * */ + setUiLogEnabled(enable: boolean): void { + if (!this.isAndroid()) { + return; + } + Grpc.setUiLogEnabled(enable); + } + /** + * onConnectionStateChange - only for Android + * grpc connection different state + * * */ + onConnectionStateChange(): void { + if (!this.isAndroid()) { + return; + } + Grpc.onConnectionStateChange(); + } + /** + * enterIdle - only for Android + * set grpc connection state to idle + * * */ + enterIdle(): void { + if (!this.isAndroid()) { + return; + } + Grpc.enterIdle(); + } + unaryCall( method: string, data: Uint8Array, @@ -291,6 +339,13 @@ export class GrpcClient { return call; } + + + + private isAndroid(): Boolean { + return Platform.OS == 'android'; + } + } export { Grpc }; From 6ee56d77c66e96b600d69edfa4c5ca028d889547 Mon Sep 17 00:00:00 2001 From: Krishna Date: Mon, 4 Sep 2023 19:41:25 +0530 Subject: [PATCH 04/14] lint fix --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1c4f79..61d495d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [Unreleased] - 2023-09-04 + +### Added + +Add option to configure keepalive + ## [1.0.0-6] - 2023-01-13 ### Added diff --git a/package.json b/package.json index be147b1..73a6485 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@krishnafkh/react-native-grpc", - "version": "1.0.2", + "version": "1.0.4", "description": "gRPC for react-native", "main": "lib/commonjs/index", "module": "lib/module/index", From c6811a1998c69d97ecdb6e5ac3884ef150030b80 Mon Sep 17 00:00:00 2001 From: Krishna Date: Mon, 4 Sep 2023 19:41:55 +0530 Subject: [PATCH 05/14] lint fix --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 73a6485..11718c2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@krishnafkh/react-native-grpc", - "version": "1.0.4", + "version": "1.0.3", "description": "gRPC for react-native", "main": "lib/commonjs/index", "module": "lib/module/index", From e7e2460eddfa8187d662a4b4bf30ed4803383f3e Mon Sep 17 00:00:00 2001 From: Krishna Date: Mon, 4 Sep 2023 19:43:20 +0530 Subject: [PATCH 06/14] lint fix --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61d495d..a866174 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ Add option to configure keepalive +## [1.0.3] - 2023-04-12 + +### Added + +Reverted swift dependency for ios pods + ## [1.0.0-6] - 2023-01-13 ### Added From c31c7f48c841d457c233095467413ad871e3256e Mon Sep 17 00:00:00 2001 From: Krishna Date: Mon, 4 Sep 2023 19:47:08 +0530 Subject: [PATCH 07/14] lint fix --- src/client.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/client.ts b/src/client.ts index e8a4f94..75e3a7a 100644 --- a/src/client.ts +++ b/src/client.ts @@ -21,11 +21,11 @@ type GrpcType = { setCompression(enable: boolean, compressorName: string, limit?: string): void; setKeepalive(enabled: boolean, time: number, timeout: number): void; setResponseSizeLimit(limitInBytes: number): void; - resetConnection(message: string):void; - setKeepAliveTime(keepAliveTime: number):void; - onConnectionStateChange():void; - setUiLogEnabled(enable:boolean):void; - enterIdle():void; + resetConnection(message: string): void; + setKeepAliveTime(keepAliveTime: number): void; + onConnectionStateChange(): void; + setUiLogEnabled(enable: boolean): void; + enterIdle(): void; unaryCall( id: number, path: string, @@ -340,12 +340,9 @@ export class GrpcClient { return call; } - - private isAndroid(): Boolean { - return Platform.OS == 'android'; + return Platform.OS === 'android'; } - } export { Grpc }; From 83dbd9c0f0fd5a57fa7131a7da977bf59deb1c0c Mon Sep 17 00:00:00 2001 From: Krishna Date: Mon, 4 Sep 2023 19:49:28 +0530 Subject: [PATCH 08/14] lint fix --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 11718c2..73a6485 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@krishnafkh/react-native-grpc", - "version": "1.0.3", + "version": "1.0.4", "description": "gRPC for react-native", "main": "lib/commonjs/index", "module": "lib/module/index", From 69e6027052c11cfda30e41ba78c1e669435e4ff8 Mon Sep 17 00:00:00 2001 From: Krishna S <98591247+krishnafkh@users.noreply.github.com> Date: Mon, 4 Sep 2023 21:36:32 +0530 Subject: [PATCH 09/14] lint fix (#4) --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a866174..7f60fcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,15 @@ ### Added +LINT FIX + +## [1.0.4] - 2023-04-12 + +### Added + Add option to configure keepalive + ## [1.0.3] - 2023-04-12 ### Added From b24b3115195f8ab40091c257e7650836c03d3faf Mon Sep 17 00:00:00 2001 From: Krishna S <98591247+krishnafkh@users.noreply.github.com> Date: Mon, 4 Sep 2023 21:42:43 +0530 Subject: [PATCH 10/14] Main v 1.0.5 (#5) * lint fix * lint fix --- example/src/App.tsx | 2 +- example/src/transport.ts | 12 ++++++------ package.json | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/example/src/App.tsx b/example/src/App.tsx index f8a1250..c29c5ec 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,5 +1,5 @@ import 'text-encoding'; -import { GrpcClient } from '@mitch528/react-native-grpc'; +import { GrpcClient } from '@krishnafkh/react-native-grpc'; import React, { useEffect, useState } from 'react'; import { StyleSheet, Text, View } from 'react-native'; import { RNGrpcTransport } from './transport'; diff --git a/example/src/transport.ts b/example/src/transport.ts index b08c1a7..7af8db6 100644 --- a/example/src/transport.ts +++ b/example/src/transport.ts @@ -1,6 +1,6 @@ /* eslint-disable eslint-comments/no-unlimited-disable */ import { ClientStreamingCall, DuplexStreamingCall, mergeRpcOptions, MethodInfo, RpcOptions, RpcOutputStreamController, RpcStatus, RpcTransport, ServerStreamingCall, UnaryCall } from '@protobuf-ts/runtime-rpc'; -import { GrpcClient, GrpcMetadata } from '@mitch528/react-native-grpc'; +import { GrpcClient, GrpcMetadata } from '@krishnafkh/react-native-grpc'; import { AbortSignal } from 'abort-controller'; /* eslint-disable */ @@ -32,11 +32,11 @@ export class RNGrpcTransport implements RpcTransport { }); } - const response = call.response.then(resp => method.O.fromBinary(resp)); + const response = call.response.then((resp: any) => method.O.fromBinary(resp)); const status = call.trailers.then(() => ({ code: 0, detail: '', - } as any), ({ error, code }) => ({ + } as any), ({ error, code }: any) => ({ code: code, detail: error })); @@ -52,14 +52,14 @@ export class RNGrpcTransport implements RpcTransport { const status = call.trailers.then(() => ({ code: 0, detail: '', - } as any), ({ error, code }) => ({ + } as any), ({ error, code }: any) => ({ code: code, detail: error })); const outStream = new RpcOutputStreamController(); - call.responses.on('data', (data) => { + call.responses.on('data', (data: any) => { outStream.notifyMessage(method.O.fromBinary(data)); }); @@ -69,7 +69,7 @@ export class RNGrpcTransport implements RpcTransport { } }); - call.responses.on('error', (reason) => { + call.responses.on('error', (reason: any) => { outStream.notifyError(reason); }); diff --git a/package.json b/package.json index 73a6485..1ac52e6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@krishnafkh/react-native-grpc", - "version": "1.0.4", + "version": "1.0.5", "description": "gRPC for react-native", "main": "lib/commonjs/index", "module": "lib/module/index", From 635d2111946d842c918d3a4be34af1ed302ca070 Mon Sep 17 00:00:00 2001 From: Pradyumna Sahoo Date: Mon, 4 Sep 2023 22:08:11 +0530 Subject: [PATCH 11/14] synced-code (#6) --- .../java/com/reactnativegrpc/GrpcModule.java | 28 ++--- src/client.ts | 117 +++++++----------- 2 files changed, 58 insertions(+), 87 deletions(-) diff --git a/android/src/main/java/com/reactnativegrpc/GrpcModule.java b/android/src/main/java/com/reactnativegrpc/GrpcModule.java index 9c87682..8b0c8d7 100644 --- a/android/src/main/java/com/reactnativegrpc/GrpcModule.java +++ b/android/src/main/java/com/reactnativegrpc/GrpcModule.java @@ -1,6 +1,5 @@ package com.reactnativegrpc; -import android.util.Log; -import android.widget.Toast; + import android.util.Base64; import android.util.Log; import android.widget.Toast; @@ -42,11 +41,10 @@ public class GrpcModule extends ReactContextBaseJavaModule { private boolean keepAliveEnabled = false; private Integer keepAliveTime; private Integer keepAliveTimeout; + private boolean isUiLogEnabled = false; private ManagedChannel managedChannel = null; - private boolean isUiLogEnabled = false; - public GrpcModule(ReactApplicationContext context) { this.context = context; } @@ -70,34 +68,29 @@ public void getIsInsecure(final Promise promise) { @ReactMethod public void setHost(String host) { this.host = host; - this.handleOptionsChanged(); } @ReactMethod public void setInsecure(boolean insecure) { this.isInsecure = insecure; - this.handleOptionsChanged(); } @ReactMethod - public void setCompression(Boolean enable, String compressorName, String limit) { + public void setCompression(Boolean enable, String compressorName) { this.withCompression = enable; this.compressorName = compressorName; - this.handleOptionsChanged(); } @ReactMethod public void setResponseSizeLimit(int limit) { this.responseSizeLimit = limit; - this.handleOptionsChanged(); } @ReactMethod - public void setKeepalive(boolean enabled, int time, int timeout) { + public void setKeepAlive(boolean enabled, int time, int timeout) { this.keepAliveEnabled = enabled; this.keepAliveTime = time; this.keepAliveTimeout = timeout; - this.handleOptionsChanged(); } @ReactMethod @@ -333,13 +326,12 @@ private static String normalizePath(String path) { if (path.startsWith("/")) { path = path.substring(1); } - return path; } - private void handleOptionsChanged() { + @ReactMethod + public void initGrpcChannel() { if (this.managedChannel != null) { - this.managedChannel.resetConnectBackoff(); this.managedChannel.shutdown(); } this.managedChannel = createManagedChannel(); @@ -360,7 +352,7 @@ private ManagedChannel createManagedChannel() { channelBuilder = channelBuilder .keepAliveWithoutCalls(true) .keepAliveTime(keepAliveTime, TimeUnit.SECONDS) - .keepAliveTimeout(keepAliveTime, TimeUnit.SECONDS); + .keepAliveTimeout(keepAliveTimeout, TimeUnit.SECONDS); } managedChannel = channelBuilder.build(); @@ -369,7 +361,11 @@ private ManagedChannel createManagedChannel() { @ReactMethod public void resetConnection(final String message){ - handleOptionsChanged(); + if(null == managedChannel) return; + + this.managedChannel.resetConnectBackoff(); + + this.initGrpcChannel(); showToast("resetConnection "+message); } diff --git a/src/client.ts b/src/client.ts index 75e3a7a..c4ed0be 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,6 +1,6 @@ import { AbortController, AbortSignal } from 'abort-controller'; import { fromByteArray, toByteArray } from 'base64-js'; -import { NativeEventEmitter, NativeModules, Platform } from 'react-native'; +import {NativeEventEmitter, NativeModules, Platform} from 'react-native'; import { GrpcError } from './errors'; import { GrpcServerStreamingCall, @@ -14,18 +14,14 @@ type GrpcRequestObject = { }; type GrpcType = { + getHost: () => Promise; getIsInsecure: () => Promise; setHost(host: string): void; setInsecure(insecure: boolean): void; - setCompression(enable: boolean, compressorName: string, limit?: string): void; - setKeepalive(enabled: boolean, time: number, timeout: number): void; + setCompression(enable: boolean, compressorName: string): void; setResponseSizeLimit(limitInBytes: number): void; - resetConnection(message: string): void; - setKeepAliveTime(keepAliveTime: number): void; - onConnectionStateChange(): void; - setUiLogEnabled(enable: boolean): void; - enterIdle(): void; + initGrpcChannel(): void; unaryCall( id: number, path: string, @@ -46,6 +42,11 @@ type GrpcType = { requestHeaders?: GrpcMetadata ): Promise; finishClientStreaming(id: number): Promise; + resetConnection(message: string):void; + setKeepAlive(enable : boolean,keepAliveTime: number,keepAliveTimeOut: number):void; + onConnectionStateChange():void; + setUiLogEnabled(enable:boolean):void; + enterIdle():void; }; type GrpcEventType = 'response' | 'error' | 'headers' | 'trailers'; @@ -56,20 +57,20 @@ type GrpcEventPayload = type: 'response'; payload: string; } | { - type: 'error'; - error: string; - code?: number; - trailers?: GrpcMetadata; - } | { - type: 'headers'; - payload: GrpcMetadata; - } | { - type: 'trailers'; - payload: GrpcMetadata; - } | { - type: 'status'; - payload: number; - }; + type: 'error'; + error: string; + code?: number; + trailers?: GrpcMetadata; +} | { + type: 'headers'; + payload: GrpcMetadata; +} | { + type: 'trailers'; + payload: GrpcMetadata; +} | { + type: 'status'; + payload: number; +}; type GrpcEvent = { id: number; @@ -145,13 +146,18 @@ function handleGrpcEvent(event: GrpcEvent) { case 'trailers': deferred.trailers?.resolve(event.payload); deferred.data?.notifyComplete(); + + delete deferredMap[event.id]; break; case 'error': const error = new GrpcError(event.error, event.code, event.trailers); + deferred.headers?.reject(error); + deferred.trailers?.reject(error); deferred.response?.reject(error); deferred.data?.noitfyError(error); + delete deferredMap[event.id]; break; } } @@ -180,72 +186,41 @@ export class GrpcClient { setInsecure(insecure: boolean): void { Grpc.setInsecure(insecure); } - - /** - * setCompression - only for Android. - * @param enable - * @param compressorName - * @param limit - */ - setCompression( - enable: boolean, - compressorName: string, - limit?: number - ): void { - if (!this.isAndroid()) { - return; - } - Grpc.setCompression(enable, compressorName, limit?.toString()); - } - setKeepalive(enabled: boolean, time: number, timeout: number): void { - Grpc.setKeepalive(enabled, time, timeout); + setCompression(enable: boolean, compressorName: string): void { + Grpc.setCompression(enable, compressorName); } setResponseSizeLimit(limitInBytes: number): void { Grpc.setResponseSizeLimit(limitInBytes); } - /** - * resetConnection - only for Android - * @param message - to debug where we are calling 'resetConnection' - * */ + initGrpcChannel(){ + Grpc.initGrpcChannel(); + }; + + setKeepAlive(enable : boolean,keepAliveTime: number,keepAliveTimeOut: number): void { + Grpc.setKeepAlive(enable,keepAliveTime,keepAliveTimeOut); + } + resetConnection(message: string): void { - if (!this.isAndroid()) { - return; - } + if(!this.isAndroid()) return; Grpc.resetConnection(message); } - /** - * setUiLogEnabled - only for Android - * @param enable - to debug where we are calling current grpc connection status - * in ui - * */ setUiLogEnabled(enable: boolean): void { - if (!this.isAndroid()) { - return; - } + if(!this.isAndroid()) return; Grpc.setUiLogEnabled(enable); } - /** - * onConnectionStateChange - only for Android - * grpc connection different state - * * */ + onConnectionStateChange(): void { - if (!this.isAndroid()) { - return; - } + if(!this.isAndroid()) return; Grpc.onConnectionStateChange(); } - /** - * enterIdle - only for Android - * set grpc connection state to idle - * * */ + enterIdle(): void { - if (!this.isAndroid()) { - return; - } + if(!this.isAndroid()) return; Grpc.enterIdle(); } + unaryCall( method: string, data: Uint8Array, @@ -340,7 +315,7 @@ export class GrpcClient { return call; } - private isAndroid(): Boolean { + private isAndroid() : Boolean { return Platform.OS === 'android'; } } From a946280d818abe3007abeeafb18eff042a83614f Mon Sep 17 00:00:00 2001 From: Pradyumna Sahoo Date: Mon, 4 Sep 2023 22:27:22 +0530 Subject: [PATCH 12/14] Grpc connection (#7) * synced-code * Lint-fix * Lint-fix --- CHANGELOG.md | 10 ++++++++-- package.json | 1 + src/client.ts | 40 +++++++++++++++++++++++----------------- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f60fcc..9f224ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,13 @@ -# Changelog - ## [Unreleased] - 2023-09-04 +### Added +1. Channel Creation happening from JS layer +2. Reset Connection +3. Reset Connection State based on current state +4. UI log to debug release build + +## [1.0.5] - 2023-04-12 + ### Added LINT FIX diff --git a/package.json b/package.json index 1ac52e6..ae8b0c8 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "test": "jest", "typescript": "tsc --noEmit", "lint": "eslint \"**/*.{js,ts,tsx}\"", + "lint:fix": "eslint '**/*.{js,ts,tsx}' --fix", "prepare": "bob build", "release": "release-it", "example": "yarn --cwd example", diff --git a/src/client.ts b/src/client.ts index c4ed0be..de20df9 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,6 +1,6 @@ import { AbortController, AbortSignal } from 'abort-controller'; import { fromByteArray, toByteArray } from 'base64-js'; -import {NativeEventEmitter, NativeModules, Platform} from 'react-native'; +import { NativeEventEmitter, NativeModules, Platform } from 'react-native'; import { GrpcError } from './errors'; import { GrpcServerStreamingCall, @@ -14,7 +14,6 @@ type GrpcRequestObject = { }; type GrpcType = { - getHost: () => Promise; getIsInsecure: () => Promise; setHost(host: string): void; @@ -42,11 +41,15 @@ type GrpcType = { requestHeaders?: GrpcMetadata ): Promise; finishClientStreaming(id: number): Promise; - resetConnection(message: string):void; - setKeepAlive(enable : boolean,keepAliveTime: number,keepAliveTimeOut: number):void; - onConnectionStateChange():void; - setUiLogEnabled(enable:boolean):void; - enterIdle():void; + resetConnection(message: string): void; + setKeepAlive( + enable: boolean, + keepAliveTime: number, + keepAliveTimeOut: number + ): void; + onConnectionStateChange(): void; + setUiLogEnabled(enable: boolean): void; + enterIdle(): void; }; type GrpcEventType = 'response' | 'error' | 'headers' | 'trailers'; @@ -193,34 +196,37 @@ export class GrpcClient { Grpc.setResponseSizeLimit(limitInBytes); } - initGrpcChannel(){ + initGrpcChannel() { Grpc.initGrpcChannel(); - }; + } - setKeepAlive(enable : boolean,keepAliveTime: number,keepAliveTimeOut: number): void { - Grpc.setKeepAlive(enable,keepAliveTime,keepAliveTimeOut); + setKeepAlive( + enable: boolean, + keepAliveTime: number, + keepAliveTimeOut: number + ): void { + Grpc.setKeepAlive(enable, keepAliveTime, keepAliveTimeOut); } resetConnection(message: string): void { - if(!this.isAndroid()) return; + if (!this.isAndroid()) return; Grpc.resetConnection(message); } setUiLogEnabled(enable: boolean): void { - if(!this.isAndroid()) return; + if (!this.isAndroid()) return; Grpc.setUiLogEnabled(enable); } onConnectionStateChange(): void { - if(!this.isAndroid()) return; + if (!this.isAndroid()) return; Grpc.onConnectionStateChange(); } enterIdle(): void { - if(!this.isAndroid()) return; + if (!this.isAndroid()) return; Grpc.enterIdle(); } - unaryCall( method: string, data: Uint8Array, @@ -315,7 +321,7 @@ export class GrpcClient { return call; } - private isAndroid() : Boolean { + private isAndroid(): Boolean { return Platform.OS === 'android'; } } From 36481ab77e76a5b400cb8a401bc5ae7eadba50d4 Mon Sep 17 00:00:00 2001 From: androidappteam Date: Wed, 5 Jun 2024 12:45:08 +0530 Subject: [PATCH 13/14] build.gradle, package.json updated --- android/build.gradle | 3 ++- package.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 4f2b430..a763ad3 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -26,10 +26,11 @@ def getExtOrIntegerDefault(name) { } android { + namespace 'com.reactnativegrpc' compileSdkVersion getExtOrIntegerDefault('compileSdkVersion') buildToolsVersion getExtOrDefault('buildToolsVersion') defaultConfig { - minSdkVersion 16 + minSdkVersion 24 targetSdkVersion getExtOrIntegerDefault('targetSdkVersion') versionCode 1 versionName "1.0" diff --git a/package.json b/package.json index ae8b0c8..6d3609b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@krishnafkh/react-native-grpc", - "version": "1.0.5", + "version": "1.0.6", "description": "gRPC for react-native", "main": "lib/commonjs/index", "module": "lib/module/index", From 576988007f3f2baf5358cc7942162f1446e90ec8 Mon Sep 17 00:00:00 2001 From: androidappteam Date: Wed, 5 Jun 2024 12:56:59 +0530 Subject: [PATCH 14/14] Bumped package version to 1.0.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6d3609b..d60496b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@krishnafkh/react-native-grpc", - "version": "1.0.6", + "version": "1.0.7", "description": "gRPC for react-native", "main": "lib/commonjs/index", "module": "lib/module/index",