diff options
author | Paul Beusterien <paulbeusterien@google.com> | 2017-05-15 12:27:07 -0700 |
---|---|---|
committer | Paul Beusterien <paulbeusterien@google.com> | 2017-05-15 12:27:07 -0700 |
commit | 98ba64449a632518bd2b86fe8d927f4a960d3ddc (patch) | |
tree | 131d9c4272fa6179fcda6c5a33fcb3b1bd57ad2e /Firebase/Database/Utilities | |
parent | 32461366c9e204a527ca05e6e9b9404a2454ac51 (diff) |
Initial
Diffstat (limited to 'Firebase/Database/Utilities')
45 files changed, 2251 insertions, 0 deletions
diff --git a/Firebase/Database/Utilities/FAtomicNumber.h b/Firebase/Database/Utilities/FAtomicNumber.h new file mode 100644 index 0000000..589dc25 --- /dev/null +++ b/Firebase/Database/Utilities/FAtomicNumber.h @@ -0,0 +1,23 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> + +@interface FAtomicNumber : NSObject + +- (NSNumber *) getAndIncrement; + +@end diff --git a/Firebase/Database/Utilities/FAtomicNumber.m b/Firebase/Database/Utilities/FAtomicNumber.m new file mode 100644 index 0000000..be0e537 --- /dev/null +++ b/Firebase/Database/Utilities/FAtomicNumber.m @@ -0,0 +1,54 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FAtomicNumber.h" + +@interface FAtomicNumber() { + unsigned long number; +} + +@property (nonatomic, strong) NSLock* lock; + +@end + +@implementation FAtomicNumber + +@synthesize lock; + +- (id)init +{ + self = [super init]; + if (self) { + number = 1; + self.lock = [[NSLock alloc] init]; + } + return self; +} + +- (NSNumber *) getAndIncrement { + NSNumber* result; + + // See: http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html#//apple_ref/doc/uid/10000057i-CH8-SW14 to improve, etc. + + [self.lock lock]; + result = [NSNumber numberWithUnsignedLong:number]; + number = number + 1; + [self.lock unlock]; + + return result; +} + +@end diff --git a/Firebase/Database/Utilities/FEventEmitter.h b/Firebase/Database/Utilities/FEventEmitter.h new file mode 100644 index 0000000..069e10f --- /dev/null +++ b/Firebase/Database/Utilities/FEventEmitter.h @@ -0,0 +1,33 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRDatabaseQuery.h" +#import "FIRDatabaseConfig.h" +#import "FTypedefs_Private.h" + +@interface FEventEmitter : NSObject + +- (id) initWithAllowedEvents:(NSArray *)theAllowedEvents queue:(dispatch_queue_t)queue; + +- (id) getInitialEventForType:(NSString *)eventType; +- (void) triggerEventType:(NSString *)eventType data:(id)data; + +- (FIRDatabaseHandle)observeEventType:(NSString *)eventType withBlock:(fbt_void_id)block; +- (void) removeObserverForEventType:(NSString *)eventType withHandle:(FIRDatabaseHandle)handle; + +- (void) validateEventType:(NSString *)eventType; + +@end diff --git a/Firebase/Database/Utilities/FEventEmitter.m b/Firebase/Database/Utilities/FEventEmitter.m new file mode 100644 index 0000000..f7c569b --- /dev/null +++ b/Firebase/Database/Utilities/FEventEmitter.m @@ -0,0 +1,145 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#import "FEventEmitter.h" +#import "FUtilities.h" +#import "FRepoManager.h" +#import "FIRDatabaseQuery_Private.h" + +@interface FEventListener : NSObject + +@property (nonatomic, copy) fbt_void_id userCallback; +@property (nonatomic) FIRDatabaseHandle handle; + +@end + +@implementation FEventListener + +@synthesize userCallback; +@synthesize handle; + +@end + + +@interface FEventEmitter () + +@property (nonatomic, strong) NSArray *allowedEvents; +@property (nonatomic, strong) NSMutableDictionary *listeners; +@property (nonatomic, strong) dispatch_queue_t queue; + +@end + + +@implementation FEventEmitter + +@synthesize allowedEvents; +@synthesize listeners; + +- (id) initWithAllowedEvents:(NSArray *)theAllowedEvents queue:(dispatch_queue_t)queue { + if (theAllowedEvents == nil || [theAllowedEvents count] == 0) { + @throw [NSException exceptionWithName:@"AllowedEventsValidation" reason:@"FEventEmitters must be initialized with at least one valid event." userInfo:nil]; + } + + self = [super init]; + + if (self) { + self.allowedEvents = [theAllowedEvents copy]; + self.listeners = [[NSMutableDictionary alloc] init]; + self.queue = queue; + } + + return self; +} + +- (id) getInitialEventForType:(NSString *)eventType { + @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"You must override getInitialEvent: when subclassing FEventEmitter" userInfo:nil]; +} + +- (void) triggerEventType:(NSString *)eventType data:(id)data { + [self validateEventType:eventType]; + NSMutableDictionary *eventTypeListeners = [self.listeners objectForKey:eventType]; + for (FEventListener *listener in eventTypeListeners) { + [self triggerListener:listener withData:data]; + } +} + +- (void) triggerListener:(FEventListener *)listener withData:(id)data { + // TODO, should probably get this from FRepo or something although it ends up being the same. (Except maybe for testing) + if (listener.userCallback) { + dispatch_async(self.queue, ^{ + listener.userCallback(data); + }); + } +} + +- (FIRDatabaseHandle)observeEventType:(NSString *)eventType withBlock:(fbt_void_id)block { + [self validateEventType:eventType]; + + // Create listener + FEventListener *listener = [[FEventListener alloc] init]; + listener.handle = [[FUtilities LUIDGenerator] integerValue]; + listener.userCallback = block; // copies block automatically + + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self addEventListener:listener forEventType:eventType]; + }); + + return listener.handle; +} + +- (void) addEventListener:(FEventListener *)listener forEventType:(NSString *)eventType { + // Get or initializer listeners map [FIRDatabaseHandle -> callback block] for eventType + NSMutableArray *eventTypeListeners = [self.listeners objectForKey:eventType]; + if (eventTypeListeners == nil) { + eventTypeListeners = [[NSMutableArray alloc] init]; + [self.listeners setObject:eventTypeListeners forKey:eventType]; + } + + // Add listener and fire the current event for this listener + [eventTypeListeners addObject:listener]; + id initialData = [self getInitialEventForType:eventType]; + [self triggerListener:listener withData:initialData]; +} + +- (void) removeObserverForEventType:(NSString *)eventType withHandle:(FIRDatabaseHandle)handle { + [self validateEventType:eventType]; + + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self removeEventListenerWithHandle:handle forEventType:eventType]; + }); +} + +- (void)removeEventListenerWithHandle:(FIRDatabaseHandle)handle forEventType:(NSString *)eventType { + NSMutableArray *eventTypeListeners = [self.listeners objectForKey:eventType]; + for (FEventListener *listener in [eventTypeListeners copy]) { + if (handle == NSNotFound || handle == listener.handle) { + [eventTypeListeners removeObject:listener]; + } + } +} + + +- (void) validateEventType:(NSString *)eventType { + if ([self.allowedEvents indexOfObject:eventType] == NSNotFound) { + @throw [NSException exceptionWithName:@"InvalidEventType" + reason:[NSString stringWithFormat:@"%@ is not a valid event type. %@ is the list of valid events.", + eventType, self.allowedEvents] + userInfo:nil]; + } +} + +@end diff --git a/Firebase/Database/Utilities/FNextPushId.h b/Firebase/Database/Utilities/FNextPushId.h new file mode 100644 index 0000000..2da54f0 --- /dev/null +++ b/Firebase/Database/Utilities/FNextPushId.h @@ -0,0 +1,23 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> + +@interface FNextPushId : NSObject + ++ (NSString *) get:(NSTimeInterval)now; + +@end diff --git a/Firebase/Database/Utilities/FNextPushId.m b/Firebase/Database/Utilities/FNextPushId.m new file mode 100644 index 0000000..af54e3d --- /dev/null +++ b/Firebase/Database/Utilities/FNextPushId.m @@ -0,0 +1,63 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FNextPushId.h" +#import "FUtilities.h" + +static NSString *const PUSH_CHARS = @"-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; + +@implementation FNextPushId + ++ (NSString *) get:(NSTimeInterval)currentTime { + static long long lastPushTime = 0; + static int lastRandChars[12]; + + long long now = (long long)(currentTime * 1000); + + BOOL duplicateTime = now == lastPushTime; + lastPushTime = now; + + unichar timeStampChars[8]; + for(int i = 7; i >= 0; i--) { + timeStampChars[i] = [PUSH_CHARS characterAtIndex:(now % 64)]; + now = (long long)floor(now / 64); + } + + NSMutableString* id = [[NSMutableString alloc] init]; + [id appendString:[NSString stringWithCharacters:timeStampChars length:8]]; + + + if(!duplicateTime) { + for(int i = 0; i < 12; i++) { + lastRandChars[i] = (int)floor(arc4random() % 64); + } + } + else { + int i = 0; + for(i = 11; i >= 0 && lastRandChars[i] == 63; i--) { + lastRandChars[i] = 0; + } + lastRandChars[i]++; + } + + for(int i = 0; i < 12; i++) { + [id appendFormat:@"%C", [PUSH_CHARS characterAtIndex:lastRandChars[i]]]; + } + + return [NSString stringWithString:id]; +} + +@end diff --git a/Firebase/Database/Utilities/FParsedUrl.h b/Firebase/Database/Utilities/FParsedUrl.h new file mode 100644 index 0000000..7145f86 --- /dev/null +++ b/Firebase/Database/Utilities/FParsedUrl.h @@ -0,0 +1,25 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FRepoInfo.h" +#import "FPath.h" + +@interface FParsedUrl : NSObject + +@property (nonatomic, strong) FRepoInfo* repoInfo; +@property (nonatomic, strong) FPath* path; + +@end diff --git a/Firebase/Database/Utilities/FParsedUrl.m b/Firebase/Database/Utilities/FParsedUrl.m new file mode 100644 index 0000000..eb83330 --- /dev/null +++ b/Firebase/Database/Utilities/FParsedUrl.m @@ -0,0 +1,24 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FParsedUrl.h" + +@implementation FParsedUrl + +@synthesize repoInfo; +@synthesize path; + +@end diff --git a/Firebase/Database/Utilities/FStringUtilities.h b/Firebase/Database/Utilities/FStringUtilities.h new file mode 100644 index 0000000..34ac9af --- /dev/null +++ b/Firebase/Database/Utilities/FStringUtilities.h @@ -0,0 +1,26 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> + +@interface FStringUtilities : NSObject + ++ (NSString *) base64EncodedSha1:(NSString *)str; ++ (NSString *) urlDecoded:(NSString *)url; ++ (NSString *) urlEncoded:(NSString *)url; ++ (NSString *) sanitizedForUserAgent:(NSString *)str; + +@end diff --git a/Firebase/Database/Utilities/FStringUtilities.m b/Firebase/Database/Utilities/FStringUtilities.m new file mode 100644 index 0000000..dff58e0 --- /dev/null +++ b/Firebase/Database/Utilities/FStringUtilities.m @@ -0,0 +1,61 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <CommonCrypto/CommonDigest.h> +#import "FStringUtilities.h" +#import "NSData+SRB64Additions.h" + +@implementation FStringUtilities + +// http://stackoverflow.com/questions/3468268/objective-c-sha1 +// http://stackoverflow.com/questions/7310457/ios-objective-c-sha-1-and-base64-problem ++ (NSString *) base64EncodedSha1:(NSString *)str { + const char *cstr = [str cStringUsingEncoding:NSUTF8StringEncoding]; + // NSString reports length in characters, but we want it in bytes, which strlen will give us. + unsigned long dataLen = strlen(cstr); + NSData *data = [NSData dataWithBytes:cstr length:dataLen]; + uint8_t digest[CC_SHA1_DIGEST_LENGTH]; + CC_SHA1(data.bytes, (unsigned int)data.length, digest); + NSData* output = [[NSData alloc] initWithBytes:digest length:CC_SHA1_DIGEST_LENGTH]; + return [FSRUtilities base64EncodedStringFromData:output]; +} + ++ (NSString *) urlDecoded:(NSString *)url { + NSString* replaced = [url stringByReplacingOccurrencesOfString:@"+" withString:@" "]; + NSString* decoded = [replaced stringByRemovingPercentEncoding]; + // This is kind of a hack, but is generally how the js client works. We could run into trouble if + // some piece is a correctly escaped %-sequence, and another isn't. But, that's bad input anyways... + if (decoded) { + return decoded; + } else { + return replaced; + } +} + ++ (NSString *) urlEncoded:(NSString *)url { + // Didn't seem like there was an Apple NSCharacterSet that had our version of the encoding + // So I made my own, following RFC 2396 https://www.ietf.org/rfc/rfc2396.txt + // allowedCharacters = alphanum | "-" | "_" | "~" + NSCharacterSet *allowedCharacters = [NSCharacterSet characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_~"]; + return [url stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters]; +} + ++ (NSString *) sanitizedForUserAgent:(NSString *)str { + return [str stringByReplacingOccurrencesOfString:@"/|_" withString:@"|" options:NSRegularExpressionSearch range:NSMakeRange(0, [str length])]; +} + + +@end diff --git a/Firebase/Database/Utilities/FTypedefs.h b/Firebase/Database/Utilities/FTypedefs.h new file mode 100644 index 0000000..4a24ca5 --- /dev/null +++ b/Firebase/Database/Utilities/FTypedefs.h @@ -0,0 +1,45 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> + +#ifndef Firebase_FTypedefs_h +#define Firebase_FTypedefs_h + +/** + * Stub... + */ +@class FIRDataSnapshot; +@class FIRDatabaseReference; +@class FAuthData; +@protocol FNode; + +// fbt = Firebase Block Typedef + +typedef void (^fbt_void_void)(void); +typedef void (^fbt_void_datasnapshot_nsstring) (FIRDataSnapshot *snapshot, NSString *prevName); +typedef void (^fbt_void_datasnapshot) (FIRDataSnapshot *snapshot); +typedef void (^fbt_void_user)(FAuthData *user); +typedef void (^fbt_void_nsstring_id)(NSString* status, id data); +typedef void (^fbt_void_nserror_id)(NSError* error, id data); +typedef void (^fbt_void_nserror)(NSError *error); +typedef void (^fbt_void_nserror_ref)(NSError* error, FIRDatabaseReference * ref); +typedef void (^fbt_void_nserror_user)(NSError* error, FAuthData * user); +typedef void (^fbt_void_nserror_json)(NSError* error, NSDictionary* json); +typedef void (^fbt_void_nsdictionary)(NSDictionary *data); +typedef id (^fbt_id_node_nsstring)(id<FNode> node, NSString* childName); + +#endif diff --git a/Firebase/Database/Utilities/FUtilities.h b/Firebase/Database/Utilities/FUtilities.h new file mode 100644 index 0000000..f5e312f --- /dev/null +++ b/Firebase/Database/Utilities/FUtilities.h @@ -0,0 +1,76 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> +#import "FIRLogger.h" +#import "FParsedUrl.h" + +@interface FUtilities : NSObject + ++ (NSArray *) splitString:(NSString *)str intoMaxSize:(const unsigned int)size; ++ (NSNumber *) LUIDGenerator; ++ (FParsedUrl *) parseUrl:(NSString *)url; ++ (NSString *) getJavascriptType:(id)obj; ++ (NSError *) errorForStatus:(NSString *)status andReason:(NSString *)reason; ++ (NSNumber *) intForString:(NSString *)string; ++ (NSString *) ieee754StringForNumber:(NSNumber *)val; ++ (void) setLoggingEnabled:(BOOL)enabled; ++ (BOOL) getLoggingEnabled; + ++ (NSString*) minName; ++ (NSString*) maxName; ++ (NSComparisonResult) compareKey:(NSString *)a toKey:(NSString *)b; ++ (NSComparator) stringComparator; ++ (NSComparator) keyComparator; + ++ (double)randomDouble; + +@end + +typedef enum { + FLogLevelDebug = 1, + FLogLevelInfo = 2, + FLogLevelWarn = 3, + FLogLevelError = 4, + FLogLevelNone = 5 +} FLogLevel; + +// Log tags +FOUNDATION_EXPORT NSString *const kFPersistenceLogTag; + +#define FFLog(code, format, ...) FFDebug((code), (format), ##__VA_ARGS__) + +#define FFDebug(code, format, ...) do { \ + if (FFIsLoggingEnabled(FLogLevelDebug)) { \ + FIRLogDebug(kFIRLoggerDatabase, (code), (format), ##__VA_ARGS__); \ + } \ +} while(0) + +#define FFInfo(code, format, ...) do { \ + if (FFIsLoggingEnabled(FLogLevelInfo)) { \ + FIRLogError(kFIRLoggerDatabase, (code), (format), ##__VA_ARGS__); \ + } \ +} while(0) + +#define FFWarn(code, format, ...) do { \ + if (FFIsLoggingEnabled(FLogLevelWarn)) { \ + FIRLogWarning(kFIRLoggerDatabase, (code), (format), ##__VA_ARGS__); \ + } \ +} while(0) + +BOOL FFIsLoggingEnabled(FLogLevel logLevel); +void firebaseUncaughtExceptionHandler(NSException *exception); +void firebaseJobsTroll(void); diff --git a/Firebase/Database/Utilities/FUtilities.m b/Firebase/Database/Utilities/FUtilities.m new file mode 100644 index 0000000..7c25e3b --- /dev/null +++ b/Firebase/Database/Utilities/FUtilities.m @@ -0,0 +1,389 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FUtilities.h" +#import "FStringUtilities.h" +#import "FConstants.h" +#import "FAtomicNumber.h" + +#define ARC4RANDOM_MAX 0x100000000 +#define INTEGER_32_MIN (-2147483648) +#define INTEGER_32_MAX 2147483647 + +#pragma mark - +#pragma mark C functions + +static FLogLevel logLevel = FLogLevelInfo; // Default log level is info +static NSMutableDictionary* options = nil; + +BOOL FFIsLoggingEnabled(FLogLevel level) { + return level >= logLevel; +} + +void firebaseJobsTroll(void) { + FFLog(@"I-RDB095001", @"password super secret; JFK conspiracy; Hello there! Having fun digging through Firebase? We're always hiring! jobs@firebase.com"); +} + +#pragma mark - +#pragma mark Private property and singleton specification + +@interface FUtilities() { + +} + +@property (nonatomic, strong) FAtomicNumber* localUid; + ++ (FUtilities*)singleton; + +@end + +@implementation FUtilities + +@synthesize localUid; + +- (id)init +{ + self = [super init]; + if (self) { + self.localUid = [[FAtomicNumber alloc] init]; + } + return self; +} + +// TODO: We really want to be able to set the log level ++ (void) setLoggingEnabled:(BOOL)enabled { + logLevel = enabled ? FLogLevelDebug : FLogLevelInfo; +} + ++ (BOOL) getLoggingEnabled { + return logLevel == FLogLevelDebug; +} + ++ (FUtilities*) singleton +{ + static dispatch_once_t pred = 0; + __strong static id _sharedObject = nil; + dispatch_once(&pred, ^{ + _sharedObject = [[self alloc] init]; // or some other init method + }); + return _sharedObject; +} + +// Refactor as a category of NSString ++ (NSArray *) splitString:(NSString *) str intoMaxSize:(const unsigned int) size { + if(str.length <= size) { + return [NSArray arrayWithObject:str]; + } + + NSMutableArray* dataSegs = [[NSMutableArray alloc] init]; + for(int c = 0; c < str.length; c += size) { + if (c + size > str.length) { + int rangeStart = c; + unsigned long rangeLength = size - ((c + size) - str.length); + [dataSegs addObject:[str substringWithRange:NSMakeRange(rangeStart, rangeLength)]]; + } + else { + int rangeStart = c; + int rangeLength = size; + [dataSegs addObject:[str substringWithRange:NSMakeRange(rangeStart, rangeLength)]]; + } + } + return dataSegs; +} + ++ (NSNumber *) LUIDGenerator { + FUtilities* f = [FUtilities singleton]; + return [f.localUid getAndIncrement]; +} + ++ (NSString *) decodePath:(NSString *)pathString { + NSMutableArray* decodedPieces = [[NSMutableArray alloc] init]; + NSArray* pieces = [pathString componentsSeparatedByString:@"/"]; + for (NSString* piece in pieces) { + if (piece.length > 0) { + [decodedPieces addObject:[FStringUtilities urlDecoded:piece]]; + } + } + return [NSString stringWithFormat:@"/%@", [decodedPieces componentsJoinedByString:@"/"]]; +} + ++ (FParsedUrl *) parseUrl:(NSString *)url { + NSString* original = url; + //NSURL* n = [[NSURL alloc] initWithString:url] + + NSString* host; + NSString* namespace; + bool secure; + + NSString* scheme = nil; + FPath* path = nil; + NSRange colonIndex = [url rangeOfString:@"//"]; + if (colonIndex.location != NSNotFound) { + scheme = [url substringToIndex:colonIndex.location - 1]; + url = [url substringFromIndex:colonIndex.location + 2]; + } + NSInteger slashIndex = [url rangeOfString:@"/"].location; + if (slashIndex == NSNotFound) { + slashIndex = url.length; + } + + host = [[url substringToIndex:slashIndex] lowercaseString]; + if (slashIndex >= url.length) { + url = @""; + } else { + url = [url substringFromIndex:slashIndex + 1]; + } + + NSArray *parts = [host componentsSeparatedByString:@"."]; + if([parts count] == 3) { + NSInteger colonIndex = [[parts objectAtIndex:2] rangeOfString:@":"].location; + if (colonIndex != NSNotFound) { + // we have a port, use the provided scheme + secure = [scheme isEqualToString:@"https"]; + } else { + secure = YES; + } + + namespace = [[parts objectAtIndex:0] lowercaseString]; + NSString* pathString = [self decodePath:[NSString stringWithFormat:@"/%@", url]]; + path = [[FPath alloc] initWith:pathString]; + } + else { + [NSException raise:@"No Firebase database specified." format:@"No Firebase database found for input: %@", url]; + } + + FRepoInfo* repoInfo = [[FRepoInfo alloc] initWithHost:host isSecure:secure withNamespace:namespace]; + + FFLog(@"I-RDB095002", @"---> Parsed (%@) to: (%@,%@); ns=(%@); path=(%@)", original, [repoInfo description], [repoInfo connectionURL], repoInfo.namespace, [path description]); + + FParsedUrl* parsedUrl = [[FParsedUrl alloc] init]; + parsedUrl.repoInfo = repoInfo; + parsedUrl.path = path; + + return parsedUrl; +} + +/* + case str: JString => priString + "string:" + str.s; + case bool: JBool => priString + "boolean:" + bool.value; + case double: JDouble => priString + "number:" + double.num; + case int: JInt => priString + "number:" + int.num; + case _ => { + error("Leaf node has value '" + data.value + "' of invalid type '" + data.value.getClass.toString + "'"); + ""; + } + */ + ++ (NSString *) getJavascriptType:(id)obj { + if ([obj isKindOfClass:[NSDictionary class]]) { + return kJavaScriptObject; + } else if([obj isKindOfClass:[NSString class]]) { + return kJavaScriptString; + } + else if ([obj isKindOfClass:[NSNumber class]]) { + // We used to just compare to @encode(BOOL) as suggested at + // http://stackoverflow.com/questions/2518761/get-type-of-nsnumber, but on arm64, @encode(BOOL) returns "B" + // instead of "c" even though objCType still returns 'c' (signed char). So check both. + if(strcmp([obj objCType], @encode(BOOL)) == 0 || + strcmp([obj objCType], @encode(signed char)) == 0) { + return kJavaScriptBoolean; + } + else { + return kJavaScriptNumber; + } + } + else { + return kJavaScriptNull; + } +} + ++ (NSError *) errorForStatus:(NSString *)status andReason:(NSString *)reason { + static dispatch_once_t pred = 0; + __strong static NSDictionary* errorMap = nil; + __strong static NSDictionary* errorCodes = nil; + dispatch_once(&pred, ^{ + errorMap = @{ + @"permission_denied": @"Permission Denied", + @"unavailable": @"Service is unavailable", + kFErrorWriteCanceled: @"Write cancelled by user" + }; + errorCodes = @{ + @"permission_denied": @1, + @"unavailable": @2, + kFErrorWriteCanceled: @3 + }; + }); + + if ([status isEqualToString:kFWPResponseForActionStatusOk]) { + return nil; + } else { + NSInteger code; + NSString* desc = nil; + if (reason) { + desc = reason; + } else if ([errorMap objectForKey:status] != nil) { + desc = [errorMap objectForKey:status]; + } else { + desc = status; + } + + if ([errorCodes objectForKey:status] != nil) { + NSNumber* num = [errorCodes objectForKey:status]; + code = [num integerValue]; + } else { + // XXX what to do here? + code = 9999; + } + + return [[NSError alloc] initWithDomain:kFErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey: desc}]; + } +} + ++ (NSNumber *) intForString:(NSString *)string { + static NSCharacterSet *notDigits = nil; + if (!notDigits) { + notDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet]; + } + if ([string rangeOfCharacterFromSet:notDigits].length == 0) { + NSInteger num; + NSScanner* scanner = [NSScanner scannerWithString:string]; + if ([scanner scanInteger:&num]) { + return [NSNumber numberWithInteger:num]; + } + } + return nil; +} + ++ (NSString *) ieee754StringForNumber:(NSNumber *)val { + double d = [val doubleValue]; + NSData* data = [NSData dataWithBytes:&d length:sizeof(double)]; + NSMutableString* str = [[NSMutableString alloc] init]; + const unsigned char* buffer = (const unsigned char*)[data bytes]; + for (int i = 0; i < data.length; i++) { + unsigned char byte = buffer[7 - i]; + [str appendFormat:@"%02x", byte]; + } + return str; +} + +static inline BOOL tryParseStringToInt(__unsafe_unretained NSString* str, NSInteger* integer) { + // First do some cheap checks (NOTE: The below checks are significantly faster than an equivalent regex :-( ). + NSUInteger length = str.length; + if (length > 11 || length == 0) { + return NO; + } + long long value = 0; + BOOL negative = NO; + NSUInteger i = 0; + if ([str characterAtIndex:0] == '-') { + if (length == 1) { + return NO; + } + negative = YES; + i = 1; + } + for(; i < length; i++) { + unichar c = [str characterAtIndex:i]; + // Must be a digit, or '-' if it's the first char. + if (c < '0' || c > '9') { + return NO; + } else { + int charValue = c - '0'; + value = value*10 + charValue; + } + } + + value = (negative) ? -value : value; + + if (value < INTEGER_32_MIN || value > INTEGER_32_MAX) { + return NO; + } else { + *integer = (NSInteger)value; + return YES; + } +} + ++ (NSString *) maxName { + static dispatch_once_t once; + static NSString *maxName; + dispatch_once(&once, ^{ + maxName = [[NSString alloc] initWithFormat:@"[MAX_NAME]"]; + }); + return maxName; +} + ++ (NSString *) minName { + static dispatch_once_t once; + static NSString *minName; + dispatch_once(&once, ^{ + minName = [[NSString alloc] initWithFormat:@"[MIN_NAME]"]; + }); + return minName; +} + ++ (NSComparisonResult) compareKey:(NSString *)a toKey:(NSString *)b { + if (a == b) { + return NSOrderedSame; + } else if (a == [FUtilities minName] || b == [FUtilities maxName]) { + return NSOrderedAscending; + } else if (b == [FUtilities minName] || a == [FUtilities maxName]) { + return NSOrderedDescending; + } else { + NSInteger aAsInt, bAsInt; + if (tryParseStringToInt(a, &aAsInt)) { + if (tryParseStringToInt(b, &bAsInt)) { + if (aAsInt > bAsInt) { + return NSOrderedDescending; + } else if (aAsInt < bAsInt) { + return NSOrderedAscending; + } else if (a.length > b.length) { + return NSOrderedDescending; + } else if (a.length < b.length) { + return NSOrderedAscending; + } else { + return NSOrderedSame; + } + } else { + return (NSComparisonResult) NSOrderedAscending; + } + } else if (tryParseStringToInt(b, &bAsInt)) { + return (NSComparisonResult) NSOrderedDescending; + } else { + // Perform literal character by character search to prevent a > b && b > a issues. + // Note that calling -(NSString *)decomposedStringWithCanonicalMapping also works. + return [a compare:b options:NSLiteralSearch]; + } + } +} + ++ (NSComparator) keyComparator { + return ^NSComparisonResult(__unsafe_unretained NSString *a, __unsafe_unretained NSString *b) { + return [FUtilities compareKey:a toKey:b]; + }; +} + ++ (NSComparator) stringComparator { + return ^NSComparisonResult(__unsafe_unretained NSString *a, __unsafe_unretained NSString *b) { + return [a compare:b]; + }; +} + ++ (double) randomDouble { + return ((double) arc4random() / ARC4RANDOM_MAX); +} + +@end + diff --git a/Firebase/Database/Utilities/FValidation.h b/Firebase/Database/Utilities/FValidation.h new file mode 100644 index 0000000..faa8f76 --- /dev/null +++ b/Firebase/Database/Utilities/FValidation.h @@ -0,0 +1,45 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> +#import "FPath.h" +#import "FIRDataEventType.h" +#import "FParsedUrl.h" +#import "FTypedefs.h" + +@interface FValidation : NSObject + ++ (void) validateFrom:(NSString *)fn writablePath:(FPath *)path; ++ (void) validateFrom:(NSString *)fn knownEventType:(FIRDataEventType)event; ++ (void) validateFrom:(NSString *)fn validPathString:(NSString *)pathString; ++ (void) validateFrom:(NSString *)fn validRootPathString:(NSString *)pathString; ++ (void) validateFrom:(NSString *)fn validKey:(NSString *)key; ++ (void) validateFrom:(NSString *)fn validURL:(FParsedUrl *)parsedUrl; + ++ (void) validateToken:(NSString *)token; + +// Functions for handling passing errors back ++ (void) handleError:(NSError *)error withUserCallback:(fbt_void_nserror_id)userCallback; ++ (void) handleError:(NSError *)error withSuccessCallback:(fbt_void_nserror)userCallback; + +// Functions used for validating while creating snapshots in FSnapshotUtilities ++ (BOOL) validateFrom:(NSString*)fn isValidLeafValue:(id)value withPath:(NSArray*)path; ++ (void) validateFrom:(NSString*)fn validDictionaryKey:(id)keyId withPath:(NSArray*)path; ++ (void) validateFrom:(NSString*)fn validUpdateDictionaryKey:(id)keyId withValue:(id)value; ++ (void) validateFrom:(NSString*)fn isValidPriorityValue:(id)value withPath:(NSArray*)path; ++ (BOOL) validatePriorityValue:value; + +@end diff --git a/Firebase/Database/Utilities/FValidation.m b/Firebase/Database/Utilities/FValidation.m new file mode 100644 index 0000000..c4c6b2b --- /dev/null +++ b/Firebase/Database/Utilities/FValidation.m @@ -0,0 +1,312 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FValidation.h" +#import "FConstants.h" +#import "FParsedUrl.h" +#import "FTypedefs.h" + + +// Have to escape: * ? + [ ( ) { } ^ $ | \ . / +// See: https://developer.apple.com/library/mac/#documentation/Foundation/Reference/NSRegularExpression_Class/Reference/Reference.html + +NSString *const kInvalidPathCharacters = @"[].#$"; +NSString *const kInvalidKeyCharacters = @"[].#$/"; + +@implementation FValidation + ++ (void) validateFrom:(NSString *)fn writablePath:(FPath *)path { + if([[path getFront] isEqualToString:kDotInfoPrefix]) { + @throw [[NSException alloc] initWithName:@"WritablePathValidation" reason:[NSString stringWithFormat:@"(%@) failed to path %@: Can't modify data under %@", fn, [path description], kDotInfoPrefix] userInfo:nil]; + } +} + ++ (void) validateFrom:(NSString*)fn knownEventType:(FIRDataEventType)event { + switch (event) { + case FIRDataEventTypeValue: + case FIRDataEventTypeChildAdded: + case FIRDataEventTypeChildChanged: + case FIRDataEventTypeChildMoved: + case FIRDataEventTypeChildRemoved: + return; + break; + default: + @throw [[NSException alloc] initWithName:@"KnownEventTypeValidation" reason:[NSString stringWithFormat:@"(%@) Unknown event type: %d", fn, (int) event] userInfo:nil]; + break; + } +} + ++ (BOOL) isValidPathString:(NSString *)pathString { + static dispatch_once_t token; + static NSCharacterSet *badPathChars = nil; + dispatch_once(&token, ^{ + badPathChars = [NSCharacterSet characterSetWithCharactersInString:kInvalidPathCharacters]; + }); + return pathString != nil && [pathString length] != 0 && + [pathString rangeOfCharacterFromSet:badPathChars].location == NSNotFound; +} + ++ (void) validateFrom:(NSString *)fn validPathString:(NSString *)pathString { + if(! [self isValidPathString:pathString]) { + @throw [[NSException alloc] initWithName:@"InvalidPathValidation" reason:[NSString stringWithFormat:@"(%@) Must be a non-empty string and not contain '.' '#' '$' '[' or ']'", fn] userInfo:nil]; + } +} + ++ (void) validateFrom:(NSString *)fn validRootPathString:(NSString *)pathString { + static dispatch_once_t token; + static NSRegularExpression *dotInfoRegex = nil; + dispatch_once(&token, ^{ + dotInfoRegex = [NSRegularExpression regularExpressionWithPattern:@"^\\/*\\.info(\\/|$)" options:0 error:nil]; + }); + + NSString *tempPath = pathString; + // HACK: Obj-C regex are kinda' slow. Do a plain string search first before bothering with the regex. + if ([pathString rangeOfString:@".info"].location != NSNotFound) { + tempPath = [dotInfoRegex stringByReplacingMatchesInString:pathString options:0 range:NSMakeRange(0, pathString.length) withTemplate:@"/"]; + } + [self validateFrom:fn validPathString:tempPath]; +} + ++ (BOOL) isValidKey:(NSString *)key { + static dispatch_once_t token; + static NSCharacterSet *badKeyChars = nil; + dispatch_once(&token, ^{ + badKeyChars = [NSCharacterSet characterSetWithCharactersInString:kInvalidKeyCharacters]; + }); + return key != nil && key.length > 0 && [key rangeOfCharacterFromSet:badKeyChars].location == NSNotFound; +} + ++ (void) validateFrom:(NSString *)fn validKey:(NSString *)key { + if (![self isValidKey:key]) { + @throw [[NSException alloc] initWithName:@"InvalidKeyValidation" reason:[NSString stringWithFormat:@"(%@) Must be a non-empty string and not contain '/' '.' '#' '$' '[' or ']'", fn] userInfo:nil]; + } +} + ++ (void) validateFrom:(NSString *)fn validURL:(FParsedUrl *)parsedUrl { + NSString* pathString = [parsedUrl.path description]; + [self validateFrom:fn validRootPathString:pathString]; +} + +#pragma mark - +#pragma mark Authentication validation + ++ (BOOL) stringNonempty:(NSString *)str { + return str != nil && ![str isKindOfClass:[NSNull class]] && str.length > 0; +} + ++ (void) validateToken:(NSString *)token { + if (![FValidation stringNonempty:token]) { + [NSException raise:NSInvalidArgumentException format:@"Can't have empty string or nil for custom token"]; + } +} + +#pragma mark - +#pragma mark Handling authentication errors + +/** +* This function immediately calls the callback. +* It assumes that it is not on FirebaseWorker thread. +* It assumes it's on a user-controlled thread. +*/ ++ (void) handleError:(NSError *)error withUserCallback:(fbt_void_nserror_id)userCallback { + if (userCallback) { + userCallback(error, nil); + } +} + +/** +* This function immediately calls the callback. +* It assumes that it is not on FirebaseWorker thread. +* It assumes it's on a user-controlled thread. +*/ ++ (void) handleError:(NSError *)error withSuccessCallback:(fbt_void_nserror)userCallback { + if (userCallback) { + userCallback(error); + } +} + +#pragma mark - +#pragma mark Snapshot validation + ++ (BOOL) validateFrom:(NSString*)fn isValidLeafValue:(id)value withPath:(NSArray*)path { + if ([value isKindOfClass:[NSString class]]) { + // Try to avoid conversion to bytes if possible + NSString* theString = value; + if ([theString maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding] > kFirebaseMaxLeafSize && + [theString lengthOfBytesUsingEncoding:NSUTF8StringEncoding] > kFirebaseMaxLeafSize) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString* pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) String exceeds max size of %u utf8 bytes: %@", fn, (int)kFirebaseMaxLeafSize, pathString] userInfo:nil]; + } + return YES; + } + + else if ([value isKindOfClass:[NSNumber class]]) { + // Cannot store NaN, but otherwise can store NSNumbers. + if ([[NSDecimalNumber notANumber] isEqualToNumber:value]) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString* pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Cannot store NaN at path: %@.", fn, pathString] userInfo:nil]; + } + return YES; + } + + else if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary* dval = value; + if (dval[kServerValueSubKey] != nil) { + if ([dval count] > 1) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString* pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Cannot store other keys with server value keys.%@.", fn, pathString] userInfo:nil]; + } + return YES; + } + return NO; + } + + else if (value == [NSNull null] || value == nil) { + // Null is valid type to store at leaf + return YES; + } + + return NO; +} + ++ (NSString*) parseAndValidateKey:(id)keyId fromFunction:(NSString*)fn path:(NSArray*)path { + if (![keyId isKindOfClass:[NSString class]]) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString* pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Non-string keys are not allowed in object at path: %@", fn, pathString] userInfo:nil]; + } + return (NSString*)keyId; +} + ++ (void) validateFrom:(NSString*)fn validDictionaryKey:(id)keyId withPath:(NSArray*)path { + NSString *key = [self parseAndValidateKey:keyId fromFunction:fn path:path]; + if (![key isEqualToString:kPayloadPriority] && ![key isEqualToString:kPayloadValue] && ![key isEqualToString:kServerValueSubKey] && ![FValidation isValidKey:key]) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Invalid key in object at path: %@. Keys must be non-empty and cannot contain '/' '.' '#' '$' '[' or ']'", fn, pathString] userInfo:nil]; + } +} + ++ (void) validateFrom:(NSString*)fn validUpdateDictionaryKey:(id)keyId withValue:(id)value { + FPath *path = [FPath pathWithString:[self parseAndValidateKey:keyId fromFunction:fn path:@[]]]; + __block NSInteger keyNum = 0; + [path enumerateComponentsUsingBlock:^void (NSString *key, BOOL *stop) { + if ([key isEqualToString:kPayloadPriority] && keyNum == [path length] - 1) { + [self validateFrom:fn isValidPriorityValue:value withPath:@[]]; + } else { + keyNum++; + + if (![FValidation isValidKey:key]) { + @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Invalid key in object. Keys must be non-empty and cannot contain '.' '#' '$' '[' or ']'", fn] userInfo:nil]; + } + } + }]; +} + ++ (void) validateFrom:(NSString*)fn isValidPriorityValue:(id)value withPath:(NSArray*)path { + [self validateFrom:fn isValidPriorityValue:value withPath:path throwError:YES]; +} + +/** +* Returns YES if priority is valid. +*/ ++ (BOOL)validatePriorityValue:value { + return [self validateFrom:nil isValidPriorityValue:value withPath:nil throwError:NO]; +} + +/** +* Helper for validating priorities. If passed YES for throwError, it'll throw descriptive errors on validation +* problems. Else, it'll just return YES/NO. +*/ ++ (BOOL) validateFrom:(NSString*)fn isValidPriorityValue:(id)value withPath:(NSArray*)path throwError:(BOOL)throwError { + if ([value isKindOfClass:[NSNumber class]]) { + if ([[NSDecimalNumber notANumber] isEqualToNumber:value]) { + if (throwError) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Cannot store NaN as priority at path: %@.", fn, pathString] userInfo:nil]; + } else { + return NO; + } + } else if (value == (id) kCFBooleanFalse || value == (id) kCFBooleanTrue) { + if (throwError) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Cannot store true/false as priority at path: %@.", fn, pathString] userInfo:nil]; + } else { + return NO; + } + } + } + else if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dval = value; + if (dval[kServerValueSubKey] != nil) { + if ([dval count] > 1) { + if (throwError) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Cannot store other keys with server value keys as priority at path: %@.", fn, pathString] userInfo:nil]; + } else { + return NO; + } + } + } else { + if (throwError) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Cannot store an NSDictionary as priority at path: %@.", fn, pathString] userInfo:nil]; + } else { + return NO; + } + } + } + else if ([value isKindOfClass:[NSArray class]]) { + if (throwError) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Cannot store an NSArray as priority at path: %@.", fn, pathString] userInfo:nil]; + } else { + return NO; + } + } + + // It's valid! + return YES; +} +@end diff --git a/Firebase/Database/Utilities/NSString+FURLUtils.h b/Firebase/Database/Utilities/NSString+FURLUtils.h new file mode 100644 index 0000000..7bd39bc --- /dev/null +++ b/Firebase/Database/Utilities/NSString+FURLUtils.h @@ -0,0 +1,24 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> + +@interface NSString (FURLUtils) + +- (NSString *) urlEncoded; +- (NSString *) urlDecoded; + +@end diff --git a/Firebase/Database/Utilities/NSString+FURLUtils.m b/Firebase/Database/Utilities/NSString+FURLUtils.m new file mode 100644 index 0000000..2e018c8 --- /dev/null +++ b/Firebase/Database/Utilities/NSString+FURLUtils.m @@ -0,0 +1,38 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "NSString+FURLUtils.h" + +@implementation NSString (FURLUtils) + +- (NSString *) urlDecoded { + NSString* replaced = [self stringByReplacingOccurrencesOfString:@"+" withString:@" "]; + NSString* decoded = [replaced stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + // This is kind of a hack, but is generally how the js client works. We could run into trouble if + // some piece is a correctly escaped %-sequence, and another isn't. But, that's bad input anyways... + if (decoded) { + return decoded; + } else { + return replaced; + } +} + +- (NSString *) urlEncoded { + CFStringRef urlString = CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef)self, NULL, (CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ", kCFStringEncodingUTF8); + return (__bridge NSString *) urlString; +} + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleBoolBlock.h b/Firebase/Database/Utilities/Tuples/FTupleBoolBlock.h new file mode 100644 index 0000000..bceeed2 --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleBoolBlock.h @@ -0,0 +1,25 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> +#import "FTypedefs.h" + +@interface FTupleBoolBlock : NSObject + +@property (nonatomic, readwrite) BOOL boolean; +@property (nonatomic, copy) fbt_void_void block; + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleBoolBlock.m b/Firebase/Database/Utilities/Tuples/FTupleBoolBlock.m new file mode 100644 index 0000000..c4cd8bf --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleBoolBlock.m @@ -0,0 +1,24 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FTupleBoolBlock.h" + +@implementation FTupleBoolBlock + +@synthesize boolean; +@synthesize block; + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleCallbackStatus.h b/Firebase/Database/Utilities/Tuples/FTupleCallbackStatus.h new file mode 100644 index 0000000..6ec2375 --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleCallbackStatus.h @@ -0,0 +1,24 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> +#import "FTypedefs_Private.h" + +@interface FTupleCallbackStatus : NSObject +@property (nonatomic, copy) fbt_void_nsstring_nsstring block; +@property (nonatomic) NSString* status; +@property (nonatomic) NSString* errorReason; +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleCallbackStatus.m b/Firebase/Database/Utilities/Tuples/FTupleCallbackStatus.m new file mode 100644 index 0000000..05914bf --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleCallbackStatus.m @@ -0,0 +1,22 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FTupleCallbackStatus.h" + +@implementation FTupleCallbackStatus +@synthesize block; +@synthesize status; +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleFirebase.h b/Firebase/Database/Utilities/Tuples/FTupleFirebase.h new file mode 100644 index 0000000..ff84bbb --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleFirebase.h @@ -0,0 +1,26 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> +#import "FIRDatabaseReference.h" + +@interface FTupleFirebase : NSObject + +@property (nonatomic, strong) FIRDatabaseReference * one; +@property (nonatomic, strong) FIRDatabaseReference * two; +@property (nonatomic, strong) FIRDatabaseReference * three; + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleFirebase.m b/Firebase/Database/Utilities/Tuples/FTupleFirebase.m new file mode 100644 index 0000000..3956f8b --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleFirebase.m @@ -0,0 +1,25 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FTupleFirebase.h" + +@implementation FTupleFirebase + +@synthesize one; +@synthesize two; +@synthesize three; + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleNodePath.h b/Firebase/Database/Utilities/Tuples/FTupleNodePath.h new file mode 100644 index 0000000..fbf62c7 --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleNodePath.h @@ -0,0 +1,28 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> +#import "FPath.h" +#import "FNode.h" + +@interface FTupleNodePath : NSObject + +@property (nonatomic, strong) FPath* path; +@property (nonatomic, strong) id<FNode> node; + +- (id) initWithNode:(id<FNode>)aNode andPath:(FPath *)aPath; + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleNodePath.m b/Firebase/Database/Utilities/Tuples/FTupleNodePath.m new file mode 100644 index 0000000..eefc0c2 --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleNodePath.m @@ -0,0 +1,33 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FTupleNodePath.h" + +@implementation FTupleNodePath + +@synthesize path; +@synthesize node; + +- (id) initWithNode:(id<FNode>)aNode andPath:(FPath *)aPath { + self = [super init]; + if (self) { + self.path = aPath; + self.node = aNode; + } + return self; +} + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleObjectNode.h b/Firebase/Database/Utilities/Tuples/FTupleObjectNode.h new file mode 100644 index 0000000..6fcb746 --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleObjectNode.h @@ -0,0 +1,27 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> +#import "FNode.h" + +@interface FTupleObjectNode : NSObject + +- (id)initWithObject:(id)aObj andNode:(id<FNode>)aNode; + +@property (nonatomic, strong) id<FNode> node; +@property (nonatomic, strong) id obj; + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleObjectNode.m b/Firebase/Database/Utilities/Tuples/FTupleObjectNode.m new file mode 100644 index 0000000..4c533b0 --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleObjectNode.m @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#import "FTupleObjectNode.h" + +@implementation FTupleObjectNode + +@synthesize obj; +@synthesize node; + +- (id)initWithObject:(id)aObj andNode:(id<FNode>)aNode { + self = [super init]; + if (self) { + self.obj = aObj; + self.node = aNode; + } + return self; +} + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleObjects.h b/Firebase/Database/Utilities/Tuples/FTupleObjects.h new file mode 100644 index 0000000..4ff1fcf --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleObjects.h @@ -0,0 +1,24 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> + +@interface FTupleObjects : NSObject + +@property (nonatomic, strong) id objA; +@property (nonatomic, strong) id objB; + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleObjects.m b/Firebase/Database/Utilities/Tuples/FTupleObjects.m new file mode 100644 index 0000000..a9e4c88 --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleObjects.m @@ -0,0 +1,24 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FTupleObjects.h" + +@implementation FTupleObjects + +@synthesize objA; +@synthesize objB; + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleOnDisconnect.h b/Firebase/Database/Utilities/Tuples/FTupleOnDisconnect.h new file mode 100644 index 0000000..91ad5e4 --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleOnDisconnect.h @@ -0,0 +1,27 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> +#import "FTypedefs_Private.h" + +@interface FTupleOnDisconnect : NSObject + +@property (strong, nonatomic) NSString* pathString; +@property (strong, nonatomic) NSString* action; +@property (strong, nonatomic) id data; +@property (strong, nonatomic) fbt_void_nsstring_nsstring onComplete; + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleOnDisconnect.m b/Firebase/Database/Utilities/Tuples/FTupleOnDisconnect.m new file mode 100644 index 0000000..bd45822 --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleOnDisconnect.m @@ -0,0 +1,26 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FTupleOnDisconnect.h" + +@implementation FTupleOnDisconnect + +@synthesize pathString; +@synthesize action; +@synthesize data; +@synthesize onComplete; + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTuplePathValue.h b/Firebase/Database/Utilities/Tuples/FTuplePathValue.h new file mode 100644 index 0000000..f7ed423 --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTuplePathValue.h @@ -0,0 +1,25 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> + +@class FPath; + +@interface FTuplePathValue : NSObject +@property (nonatomic, strong, readonly) FPath *path; +@property (nonatomic, strong, readonly) id value; +- (id) initWithPath:(FPath *)aPath value:(id)aValue; +@end diff --git a/Firebase/Database/Utilities/Tuples/FTuplePathValue.m b/Firebase/Database/Utilities/Tuples/FTuplePathValue.m new file mode 100644 index 0000000..49240aa --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTuplePathValue.m @@ -0,0 +1,38 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FTuplePathValue.h" +#import "FPath.h" + +@interface FTuplePathValue () +@property (nonatomic, strong, readwrite) id value; +@property (nonatomic, strong, readwrite) FPath *path; +@end + +@implementation FTuplePathValue +@synthesize path; +@synthesize value; + +- (id) initWithPath:(FPath *)aPath value:(id)aValue { + self = [super init]; + if (self) { + self.value = aValue; + self.path = aPath; + } + return self; +} + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleRemovedQueriesEvents.h b/Firebase/Database/Utilities/Tuples/FTupleRemovedQueriesEvents.h new file mode 100644 index 0000000..f986916 --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleRemovedQueriesEvents.h @@ -0,0 +1,30 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> + +@interface FTupleRemovedQueriesEvents : NSObject +/** +* `FIRDatabaseQuery`s removed with [SyncPoint removeEventRegistration:] +*/ +@property (nonatomic, strong, readonly) NSArray *removedQueries; +/** +* cancel events as FEvent +*/ +@property (nonatomic, strong, readonly) NSArray *cancelEvents; + +- (id) initWithRemovedQueries:(NSArray *)removed cancelEvents:(NSArray *)events; +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleRemovedQueriesEvents.m b/Firebase/Database/Utilities/Tuples/FTupleRemovedQueriesEvents.m new file mode 100644 index 0000000..818d16b --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleRemovedQueriesEvents.m @@ -0,0 +1,37 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FTupleRemovedQueriesEvents.h" + +@interface FTupleRemovedQueriesEvents () +@property (nonatomic, strong, readwrite) NSArray *removedQueries; +@property (nonatomic, strong, readwrite) NSArray *cancelEvents; +@end + +@implementation FTupleRemovedQueriesEvents +@synthesize removedQueries; +@synthesize cancelEvents; + +- (id) initWithRemovedQueries:(NSArray *)removed cancelEvents:(NSArray *)events { + self = [super init]; + if (self) { + self.removedQueries = removed; + self.cancelEvents = events; + } + return self; +} + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleSetIdPath.h b/Firebase/Database/Utilities/Tuples/FTupleSetIdPath.h new file mode 100644 index 0000000..5133d6d --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleSetIdPath.h @@ -0,0 +1,27 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> +#import "FPath.h" + +@interface FTupleSetIdPath : NSObject + +- (id) initWithSetId:(NSNumber *)aSetId andPath:(FPath *)aPath; + +@property (strong, nonatomic) NSNumber* setId; +@property (strong, nonatomic) FPath* path; + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleSetIdPath.m b/Firebase/Database/Utilities/Tuples/FTupleSetIdPath.m new file mode 100644 index 0000000..5d3312b --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleSetIdPath.m @@ -0,0 +1,33 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FTupleSetIdPath.h" + +@implementation FTupleSetIdPath + +@synthesize path; +@synthesize setId; + +- (id) initWithSetId:(NSNumber *)aSetId andPath:(FPath *)aPath { + self = [super init]; + if (self) { + self.setId = aSetId; + self.path = aPath; + } + return self; +} + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleStringNode.h b/Firebase/Database/Utilities/Tuples/FTupleStringNode.h new file mode 100644 index 0000000..e3fec80 --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleStringNode.h @@ -0,0 +1,27 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> +#import "FNode.h" + +@interface FTupleStringNode : NSObject + +- (id)initWithString:(NSString *)aString andNode:(id<FNode>)aNode; + +@property (nonatomic, strong) id<FNode> node; +@property (nonatomic, strong) NSString* string; + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleStringNode.m b/Firebase/Database/Utilities/Tuples/FTupleStringNode.m new file mode 100644 index 0000000..f058a8e --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleStringNode.m @@ -0,0 +1,34 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FTupleStringNode.h" + +@implementation FTupleStringNode + +@synthesize string; +@synthesize node; + +- (id)initWithString:(NSString *)aString andNode:(id<FNode>)aNode { + self = [super init]; + if (self) { + self.string = aString; + self.node = aNode; + } + return self; +} + + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleTSN.h b/Firebase/Database/Utilities/Tuples/FTupleTSN.h new file mode 100644 index 0000000..bc62b2d --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleTSN.h @@ -0,0 +1,25 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> +#import "FTupleStringNode.h" + +@interface FTupleTSN : NSObject + +@property (nonatomic, strong) FTupleStringNode* from; +@property (nonatomic, strong) FTupleStringNode* to; + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleTSN.m b/Firebase/Database/Utilities/Tuples/FTupleTSN.m new file mode 100644 index 0000000..348c319 --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleTSN.m @@ -0,0 +1,24 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FTupleTSN.h" + +@implementation FTupleTSN + +@synthesize from; +@synthesize to; + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleTransaction.h b/Firebase/Database/Utilities/Tuples/FTupleTransaction.h new file mode 100644 index 0000000..c9dcf4b --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleTransaction.h @@ -0,0 +1,74 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> +#import "FPath.h" +#import "FTypedefs_Private.h" +#import "FTypedefs.h" + +@interface FTupleTransaction : NSObject + +@property (nonatomic, strong) FPath* path; +@property (nonatomic, copy) fbt_transactionresult_mutabledata update; +@property (nonatomic, copy) fbt_void_nserror_bool_datasnapshot onComplete; +@property (nonatomic) FTransactionStatus status; + +/** +* Used when combining transaction at different locations to figure out which one goes first. +*/ +@property (nonatomic, strong) NSNumber* order; +/** +* Whether to raise local events for this transaction +*/ +@property (nonatomic) BOOL applyLocally; + +/** +* Count how many times we've retried the transaction +*/ +@property (nonatomic) int retryCount; + +/** +* Function to call to clean up our listener +*/ +@property (nonatomic, copy) fbt_void_void unwatcher; + +/** +* Stores why a transaction was aborted +*/ +@property (nonatomic, strong, readonly) NSString* abortStatus; +@property (nonatomic, strong, readonly) NSString* abortReason; + +- (void)setAbortStatus:(NSString *)abortStatus reason:(NSString *)reason; +- (NSError *)abortError; + +@property (nonatomic, strong) NSNumber *currentWriteId; + +/** +* Stores the input snapshot, before the update +*/ +@property (nonatomic, strong) id<FNode> currentInputSnapshot; + +/** +* Stores the unresolved (for server values) output snapshot, after the update +*/ +@property (nonatomic, strong) id<FNode> currentOutputSnapshotRaw; + +/** + * Stores the resolved (for server values) output snapshot, after the update + */ +@property (nonatomic, strong) id<FNode> currentOutputSnapshotResolved; + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleTransaction.m b/Firebase/Database/Utilities/Tuples/FTupleTransaction.m new file mode 100644 index 0000000..bcff54e --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleTransaction.m @@ -0,0 +1,38 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FTupleTransaction.h" +#import "FUtilities.h" + +@interface FTupleTransaction () + +@property (nonatomic, strong) NSString *abortStatus; +@property (nonatomic, strong) NSString *abortReason; + +@end + +@implementation FTupleTransaction + +- (void)setAbortStatus:(NSString *)abortStatus reason:(NSString *)reason { + self.abortStatus = abortStatus; + self.abortReason = reason; +} + +- (NSError *)abortError { + return (self.abortStatus != nil) ? [FUtilities errorForStatus:self.abortStatus andReason:self.abortReason] : nil; +} + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleUserCallback.h b/Firebase/Database/Utilities/Tuples/FTupleUserCallback.h new file mode 100644 index 0000000..d598217 --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleUserCallback.h @@ -0,0 +1,31 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> +#import "FTypedefs.h" +#import "FQueryParams.h" + +@interface FTupleUserCallback : NSObject + +- (id) initWithHandle:(NSUInteger)handle; + +@property (nonatomic, copy) fbt_void_datasnapshot_nsstring datasnapshotPrevnameCallback; +@property (nonatomic, copy) fbt_void_datasnapshot datasnapshotCallback; +@property (nonatomic, copy) fbt_void_nserror cancelCallback; +@property (nonatomic, copy) FQueryParams* queryParams; +@property (nonatomic) NSUInteger handle; + +@end diff --git a/Firebase/Database/Utilities/Tuples/FTupleUserCallback.m b/Firebase/Database/Utilities/Tuples/FTupleUserCallback.m new file mode 100644 index 0000000..dc33bbd --- /dev/null +++ b/Firebase/Database/Utilities/Tuples/FTupleUserCallback.m @@ -0,0 +1,35 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FTupleUserCallback.h" + +@implementation FTupleUserCallback + +@synthesize datasnapshotCallback; +@synthesize datasnapshotPrevnameCallback; +@synthesize cancelCallback; +@synthesize queryParams; +@synthesize handle; + +- (id) initWithHandle:(NSUInteger)theHandle { + self = [super init]; + if (self) { + self.handle = theHandle; + } + return self; +} + +@end |