1/* 2 * 3 * Copyright 2015 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19#import <UIKit/UIKit.h> 20#if COCOAPODS 21#import <RouteGuide/RouteGuide.pbrpc.h> 22#else 23#import "examples/protos/RouteGuide.pbrpc.h" 24#endif 25 26#import <GRPCClient/GRPCTransport.h> 27 28static NSString *const kHostAddress = @"localhost:50051"; 29 30/** Category to override RTGPoint's description. */ 31@interface RTGPoint (Description) 32- (NSString *)description; 33@end 34 35@implementation RTGPoint (Description) 36- (NSString *)description { 37 NSString *verticalDirection = self.latitude >= 0 ? @"N" : @"S"; 38 NSString *horizontalDirection = self.longitude >= 0 ? @"E" : @"W"; 39 return 40 [NSString stringWithFormat:@"%.02f%@ %.02f%@", abs(self.latitude) / 1E7f, verticalDirection, 41 abs(self.longitude) / 1E7f, horizontalDirection]; 42} 43@end 44 45/** Category to give RTGRouteNote a convenience constructor. */ 46@interface RTGRouteNote (Constructors) 47+ (instancetype)noteWithMessage:(NSString *)message 48 latitude:(float)latitude 49 longitude:(float)longitude; 50@end 51 52@implementation RTGRouteNote (Constructors) 53+ (instancetype)noteWithMessage:(NSString *)message 54 latitude:(float)latitude 55 longitude:(float)longitude { 56 RTGRouteNote *note = [self message]; 57 note.message = message; 58 note.location.latitude = (int32_t)latitude * 1E7; 59 note.location.longitude = (int32_t)longitude * 1E7; 60 return note; 61} 62@end 63 64#pragma mark Demo: Get Feature 65 66/** 67 * Run the getFeature demo. Calls getFeature with a point known to have a feature and a point known 68 * not to have a feature. 69 */ 70@interface GetFeatureViewController : UIViewController 71 72@property(weak, nonatomic) IBOutlet UILabel *outputLabel; 73 74@end 75 76@implementation GetFeatureViewController { 77 RTGRouteGuide *_service; 78} 79 80- (void)execRequest { 81 void (^handler)(RTGFeature *response, NSError *error) = ^(RTGFeature *response, NSError *error) { 82 // TODO(makdharma): Remove boilerplate by consolidating into one log function. 83 if (response.name.length) { 84 NSString *str = 85 [NSString stringWithFormat:@"%@\nFound feature called %@ at %@.", self.outputLabel.text, 86 response.location, response.name]; 87 self.outputLabel.text = str; 88 NSLog(@"Found feature called %@ at %@.", response.name, response.location); 89 } else if (response) { 90 NSString *str = [NSString stringWithFormat:@"%@\nFound no features at %@", 91 self.outputLabel.text, response.location]; 92 self.outputLabel.text = str; 93 NSLog(@"Found no features at %@", response.location); 94 } else { 95 NSString *str = 96 [NSString stringWithFormat:@"%@\nRPC error: %@", self.outputLabel.text, error]; 97 self.outputLabel.text = str; 98 NSLog(@"RPC error: %@", error); 99 } 100 }; 101 102 RTGPoint *point = [RTGPoint message]; 103 point.latitude = 409146138; 104 point.longitude = -746188906; 105 106 GRPCUnaryProtoCall *call = [_service 107 getFeatureWithMessage:point 108 responseHandler:[[GRPCUnaryResponseHandler alloc] initWithResponseHandler:handler 109 responseDispatchQueue:nil] 110 callOptions:nil]; 111 [call start]; 112 call = [_service 113 getFeatureWithMessage:[RTGPoint message] 114 responseHandler:[[GRPCUnaryResponseHandler alloc] initWithResponseHandler:handler 115 responseDispatchQueue:nil] 116 callOptions:nil]; 117 [call start]; 118} 119 120- (void)viewDidLoad { 121 [super viewDidLoad]; 122 123 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; 124 options.transport = GRPCDefaultTransportImplList.core_insecure; 125 126 _service = [[RTGRouteGuide alloc] initWithHost:kHostAddress callOptions:options]; 127} 128 129- (void)viewDidAppear:(BOOL)animated { 130 self.outputLabel.text = @"RPC log:"; 131 self.outputLabel.numberOfLines = 0; 132 self.outputLabel.font = [UIFont fontWithName:@"Helvetica Neue" size:8.0]; 133 [self execRequest]; 134} 135 136@end 137 138#pragma mark Demo: List Features 139 140/** 141 * Run the listFeatures demo. Calls listFeatures with a rectangle containing all of the features in 142 * the pre-generated database. Prints each response as it comes in. 143 */ 144@interface ListFeaturesViewController : UIViewController <GRPCProtoResponseHandler> 145 146@property(weak, nonatomic) IBOutlet UILabel *outputLabel; 147 148@end 149 150@implementation ListFeaturesViewController { 151 RTGRouteGuide *_service; 152} 153 154- (dispatch_queue_t)dispatchQueue { 155 return dispatch_get_main_queue(); 156} 157 158- (void)execRequest { 159 RTGRectangle *rectangle = [RTGRectangle message]; 160 rectangle.lo.latitude = 405E6; 161 rectangle.lo.longitude = -750E6; 162 rectangle.hi.latitude = 410E6; 163 rectangle.hi.longitude = -745E6; 164 165 NSLog(@"Looking for features between %@ and %@", rectangle.lo, rectangle.hi); 166 GRPCUnaryProtoCall *call = [_service listFeaturesWithMessage:rectangle 167 responseHandler:self 168 callOptions:nil]; 169 [call start]; 170} 171 172- (void)didReceiveProtoMessage:(GPBMessage *)message { 173 RTGFeature *response = (RTGFeature *)message; 174 if (response) { 175 NSString *str = 176 [NSString stringWithFormat:@"%@\nFound feature at %@ called %@.", self.outputLabel.text, 177 response.location, response.name]; 178 self.outputLabel.text = str; 179 NSLog(@"Found feature at %@ called %@.", response.location, response.name); 180 } 181} 182 183- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { 184 if (error) { 185 NSString *str = [NSString stringWithFormat:@"%@\nRPC error: %@", self.outputLabel.text, error]; 186 self.outputLabel.text = str; 187 NSLog(@"RPC error: %@", error); 188 } 189} 190 191- (void)viewDidLoad { 192 [super viewDidLoad]; 193 194 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; 195 options.transport = GRPCDefaultTransportImplList.core_insecure; 196 197 _service = [[RTGRouteGuide alloc] initWithHost:kHostAddress callOptions:options]; 198} 199 200- (void)viewDidAppear:(BOOL)animated { 201 self.outputLabel.text = @"RPC log:"; 202 self.outputLabel.numberOfLines = 0; 203 self.outputLabel.font = [UIFont fontWithName:@"Helvetica Neue" size:8.0]; 204 [self execRequest]; 205} 206 207@end 208 209#pragma mark Demo: Record Route 210 211/** 212 * Run the recordRoute demo. Sends several randomly chosen points from the pre-generated feature 213 * database with a variable delay in between. Prints the statistics when they are sent from the 214 * server. 215 */ 216@interface RecordRouteViewController : UIViewController 217 218@property(weak, nonatomic) IBOutlet UILabel *outputLabel; 219 220@end 221 222@implementation RecordRouteViewController { 223 RTGRouteGuide *_service; 224} 225 226- (void)execRequest { 227 NSString *dataBasePath = [NSBundle.mainBundle pathForResource:@"route_guide_db" ofType:@"json"]; 228 NSData *dataBaseContent = [NSData dataWithContentsOfFile:dataBasePath]; 229 NSError *error; 230 NSArray *features = [NSJSONSerialization JSONObjectWithData:dataBaseContent 231 options:0 232 error:&error]; 233 234 if (error) { 235 NSLog(@"Error reading database."); 236 NSString *str = @"Error reading database."; 237 self.outputLabel.text = str; 238 return; 239 } 240 241 void (^handler)(RTGRouteSummary *response, NSError *error) = 242 ^(RTGRouteSummary *response, NSError *error) { 243 if (response) { 244 NSString *str = [NSString 245 stringWithFormat:@"%@\nFinished trip with %i points\nPassed %i features\n" 246 "Travelled %i meters\nIt took %i seconds", 247 self.outputLabel.text, response.pointCount, response.featureCount, 248 response.distance, response.elapsedTime]; 249 self.outputLabel.text = str; 250 NSLog(@"Finished trip with %i points", response.pointCount); 251 NSLog(@"Passed %i features", response.featureCount); 252 NSLog(@"Travelled %i meters", response.distance); 253 NSLog(@"It took %i seconds", response.elapsedTime); 254 } else { 255 NSString *str = 256 [NSString stringWithFormat:@"%@\nRPC error: %@", self.outputLabel.text, error]; 257 self.outputLabel.text = str; 258 NSLog(@"RPC error: %@", error); 259 } 260 }; 261 262 // We can use unary response handler here because, despite the requests being a stream, the 263 // response of the RPC is unary. 264 GRPCStreamingProtoCall *call = 265 [_service recordRouteWithResponseHandler:[[GRPCUnaryResponseHandler alloc] 266 initWithResponseHandler:handler 267 responseDispatchQueue:nil] 268 callOptions:nil]; 269 [call start]; 270 for (id feature in features) { 271 RTGPoint *location = [RTGPoint message]; 272 location.longitude = [((NSNumber *)feature[@"location"][@"longitude"]) intValue]; 273 location.latitude = [((NSNumber *)feature[@"location"][@"latitude"]) intValue]; 274 NSString *str = 275 [NSString stringWithFormat:@"%@\nVisiting point %@", self.outputLabel.text, location]; 276 self.outputLabel.text = str; 277 NSLog(@"Visiting point %@", location); 278 [call writeMessage:location]; 279 } 280 [call finish]; 281} 282 283- (void)viewDidLoad { 284 [super viewDidLoad]; 285 286 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; 287 options.transport = GRPCDefaultTransportImplList.core_insecure; 288 289 _service = [[RTGRouteGuide alloc] initWithHost:kHostAddress callOptions:options]; 290} 291 292- (void)viewDidAppear:(BOOL)animated { 293 self.outputLabel.text = @"RPC log:"; 294 self.outputLabel.numberOfLines = 0; 295 self.outputLabel.font = [UIFont fontWithName:@"Helvetica Neue" size:8.0]; 296 [self execRequest]; 297} 298 299@end 300 301#pragma mark Demo: Route Chat 302 303/** 304 * Run the routeChat demo. Send some chat messages, and print any chat messages that are sent from 305 * the server. 306 */ 307@interface RouteChatViewController : UIViewController <GRPCProtoResponseHandler> 308 309@property(weak, nonatomic) IBOutlet UILabel *outputLabel; 310 311@end 312 313@implementation RouteChatViewController { 314 RTGRouteGuide *_service; 315} 316 317- (dispatch_queue_t)dispatchQueue { 318 return dispatch_get_main_queue(); 319} 320 321- (void)execRequest { 322 NSArray *notes = @[ 323 [RTGRouteNote noteWithMessage:@"First message" latitude:0 longitude:0], 324 [RTGRouteNote noteWithMessage:@"Second message" latitude:0 longitude:1], 325 [RTGRouteNote noteWithMessage:@"Third message" latitude:1 longitude:0], 326 [RTGRouteNote noteWithMessage:@"Fourth message" latitude:0 longitude:0] 327 ]; 328 329 GRPCStreamingProtoCall *call = [_service routeChatWithResponseHandler:self callOptions:nil]; 330 [call start]; 331 for (RTGRouteNote *note in notes) { 332 [call writeMessage:note]; 333 } 334 [call finish]; 335} 336 337- (void)didReceiveProtoMessage:(GPBMessage *)message { 338 RTGRouteNote *note = (RTGRouteNote *)message; 339 if (note) { 340 NSString *str = [NSString stringWithFormat:@"%@\nGot message %@ at %@", self.outputLabel.text, 341 note.message, note.location]; 342 self.outputLabel.text = str; 343 NSLog(@"Got message %@ at %@", note.message, note.location); 344 } 345} 346 347- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { 348 if (!error) { 349 NSLog(@"Chat ended."); 350 } else { 351 NSString *str = [NSString stringWithFormat:@"%@\nRPC error: %@", self.outputLabel.text, error]; 352 self.outputLabel.text = str; 353 NSLog(@"RPC error: %@", error); 354 } 355} 356 357- (void)viewDidLoad { 358 [super viewDidLoad]; 359 360 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; 361 options.transport = GRPCDefaultTransportImplList.core_insecure; 362 363 _service = [[RTGRouteGuide alloc] initWithHost:kHostAddress callOptions:options]; 364} 365 366- (void)viewDidAppear:(BOOL)animated { 367 // TODO(makarandd): Set these properties through UI builder 368 self.outputLabel.text = @"RPC log:"; 369 self.outputLabel.numberOfLines = 0; 370 self.outputLabel.font = [UIFont fontWithName:@"Helvetica Neue" size:8.0]; 371 [self execRequest]; 372} 373 374@end 375