This app provides monitoring and information features for the common freifunk user and the technical stuff of a freifunk community.
Code base is taken from a TUM Practical Course project and added here to see if Freifunk Altdorf can use it.
https://www.freifunk-altdorf.de
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
378 lines
9.7 KiB
378 lines
9.7 KiB
/** |
|
* Copyright (c) 2015-present, Facebook, Inc. |
|
* |
|
* This source code is licensed under the MIT license found in the |
|
* LICENSE file in the root directory of this source tree. |
|
*/ |
|
|
|
#import "RCTBridge.h" |
|
#import "RCTBridge+Private.h" |
|
|
|
#import <objc/runtime.h> |
|
|
|
#import "RCTConvert.h" |
|
#import "RCTEventDispatcher.h" |
|
#if RCT_ENABLE_INSPECTOR |
|
#import "RCTInspectorDevServerHelper.h" |
|
#endif |
|
#import "RCTLog.h" |
|
#import "RCTModuleData.h" |
|
#import "RCTPerformanceLogger.h" |
|
#import "RCTProfile.h" |
|
#import "RCTReloadCommand.h" |
|
#import "RCTUtils.h" |
|
|
|
NSString *const RCTJavaScriptWillStartLoadingNotification = @"RCTJavaScriptWillStartLoadingNotification"; |
|
NSString *const RCTJavaScriptWillStartExecutingNotification = @"RCTJavaScriptWillStartExecutingNotification"; |
|
NSString *const RCTJavaScriptDidLoadNotification = @"RCTJavaScriptDidLoadNotification"; |
|
NSString *const RCTJavaScriptDidFailToLoadNotification = @"RCTJavaScriptDidFailToLoadNotification"; |
|
NSString *const RCTDidInitializeModuleNotification = @"RCTDidInitializeModuleNotification"; |
|
NSString *const RCTBridgeWillReloadNotification = @"RCTBridgeWillReloadNotification"; |
|
NSString *const RCTBridgeWillDownloadScriptNotification = @"RCTBridgeWillDownloadScriptNotification"; |
|
NSString *const RCTBridgeDidDownloadScriptNotification = @"RCTBridgeDidDownloadScriptNotification"; |
|
NSString *const RCTBridgeDidDownloadScriptNotificationSourceKey = @"source"; |
|
|
|
static NSMutableArray<Class> *RCTModuleClasses; |
|
NSArray<Class> *RCTGetModuleClasses(void) |
|
{ |
|
return RCTModuleClasses; |
|
} |
|
|
|
void RCTFBQuickPerformanceLoggerConfigureHooks(__unused JSGlobalContextRef ctx) { } |
|
|
|
/** |
|
* Register the given class as a bridge module. All modules must be registered |
|
* prior to the first bridge initialization. |
|
*/ |
|
void RCTRegisterModule(Class); |
|
void RCTRegisterModule(Class moduleClass) |
|
{ |
|
static dispatch_once_t onceToken; |
|
dispatch_once(&onceToken, ^{ |
|
RCTModuleClasses = [NSMutableArray new]; |
|
}); |
|
|
|
RCTAssert([moduleClass conformsToProtocol:@protocol(RCTBridgeModule)], |
|
@"%@ does not conform to the RCTBridgeModule protocol", |
|
moduleClass); |
|
|
|
// Register module |
|
[RCTModuleClasses addObject:moduleClass]; |
|
} |
|
|
|
/** |
|
* This function returns the module name for a given class. |
|
*/ |
|
NSString *RCTBridgeModuleNameForClass(Class cls) |
|
{ |
|
#if RCT_DEBUG |
|
RCTAssert([cls conformsToProtocol:@protocol(RCTBridgeModule)], |
|
@"Bridge module `%@` does not conform to RCTBridgeModule", cls); |
|
#endif |
|
|
|
NSString *name = [cls moduleName]; |
|
if (name.length == 0) { |
|
name = NSStringFromClass(cls); |
|
} |
|
|
|
if ([name hasPrefix:@"RK"]) { |
|
name = [name substringFromIndex:2]; |
|
} else if ([name hasPrefix:@"RCT"]) { |
|
name = [name substringFromIndex:3]; |
|
} |
|
|
|
return name; |
|
} |
|
|
|
#if RCT_DEBUG |
|
void RCTVerifyAllModulesExported(NSArray *extraModules) |
|
{ |
|
// Check for unexported modules |
|
unsigned int classCount; |
|
Class *classes = objc_copyClassList(&classCount); |
|
|
|
NSMutableSet *moduleClasses = [NSMutableSet new]; |
|
[moduleClasses addObjectsFromArray:RCTGetModuleClasses()]; |
|
[moduleClasses addObjectsFromArray:[extraModules valueForKeyPath:@"class"]]; |
|
|
|
for (unsigned int i = 0; i < classCount; i++) { |
|
Class cls = classes[i]; |
|
Class superclass = cls; |
|
while (superclass) { |
|
if (class_conformsToProtocol(superclass, @protocol(RCTBridgeModule))) { |
|
if ([moduleClasses containsObject:cls]) { |
|
break; |
|
} |
|
|
|
// Verify it's not a super-class of one of our moduleClasses |
|
BOOL isModuleSuperClass = NO; |
|
for (Class moduleClass in moduleClasses) { |
|
if ([moduleClass isSubclassOfClass:cls]) { |
|
isModuleSuperClass = YES; |
|
break; |
|
} |
|
} |
|
if (isModuleSuperClass) { |
|
break; |
|
} |
|
|
|
RCTLogWarn(@"Class %@ was not exported. Did you forget to use RCT_EXPORT_MODULE()?", cls); |
|
break; |
|
} |
|
superclass = class_getSuperclass(superclass); |
|
} |
|
} |
|
|
|
free(classes); |
|
} |
|
#endif |
|
|
|
@interface RCTBridge () <RCTReloadListener> |
|
@end |
|
|
|
@implementation RCTBridge |
|
{ |
|
NSURL *_delegateBundleURL; |
|
} |
|
|
|
dispatch_queue_t RCTJSThread; |
|
|
|
+ (void)initialize |
|
{ |
|
static dispatch_once_t onceToken; |
|
dispatch_once(&onceToken, ^{ |
|
|
|
// Set up JS thread |
|
RCTJSThread = (id)kCFNull; |
|
}); |
|
} |
|
|
|
static RCTBridge *RCTCurrentBridgeInstance = nil; |
|
|
|
/** |
|
* The last current active bridge instance. This is set automatically whenever |
|
* the bridge is accessed. It can be useful for static functions or singletons |
|
* that need to access the bridge for purposes such as logging, but should not |
|
* be relied upon to return any particular instance, due to race conditions. |
|
*/ |
|
+ (instancetype)currentBridge |
|
{ |
|
return RCTCurrentBridgeInstance; |
|
} |
|
|
|
+ (void)setCurrentBridge:(RCTBridge *)currentBridge |
|
{ |
|
RCTCurrentBridgeInstance = currentBridge; |
|
} |
|
|
|
- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)delegate |
|
launchOptions:(NSDictionary *)launchOptions |
|
{ |
|
return [self initWithDelegate:delegate |
|
bundleURL:nil |
|
moduleProvider:nil |
|
launchOptions:launchOptions]; |
|
} |
|
|
|
- (instancetype)initWithBundleURL:(NSURL *)bundleURL |
|
moduleProvider:(RCTBridgeModuleListProvider)block |
|
launchOptions:(NSDictionary *)launchOptions |
|
{ |
|
return [self initWithDelegate:nil |
|
bundleURL:bundleURL |
|
moduleProvider:block |
|
launchOptions:launchOptions]; |
|
} |
|
|
|
- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)delegate |
|
bundleURL:(NSURL *)bundleURL |
|
moduleProvider:(RCTBridgeModuleListProvider)block |
|
launchOptions:(NSDictionary *)launchOptions |
|
{ |
|
if (self = [super init]) { |
|
_delegate = delegate; |
|
_bundleURL = bundleURL; |
|
_moduleProvider = block; |
|
_launchOptions = [launchOptions copy]; |
|
|
|
[self setUp]; |
|
} |
|
return self; |
|
} |
|
|
|
RCT_NOT_IMPLEMENTED(- (instancetype)init) |
|
|
|
- (void)dealloc |
|
{ |
|
/** |
|
* This runs only on the main thread, but crashes the subclass |
|
* RCTAssertMainQueue(); |
|
*/ |
|
[self invalidate]; |
|
} |
|
|
|
- (void)didReceiveReloadCommand |
|
{ |
|
[self reload]; |
|
} |
|
|
|
- (NSArray<Class> *)moduleClasses |
|
{ |
|
return self.batchedBridge.moduleClasses; |
|
} |
|
|
|
- (id)moduleForName:(NSString *)moduleName |
|
{ |
|
return [self.batchedBridge moduleForName:moduleName]; |
|
} |
|
|
|
- (id)moduleForClass:(Class)moduleClass |
|
{ |
|
return [self moduleForName:RCTBridgeModuleNameForClass(moduleClass)]; |
|
} |
|
|
|
- (NSArray *)modulesConformingToProtocol:(Protocol *)protocol |
|
{ |
|
NSMutableArray *modules = [NSMutableArray new]; |
|
for (Class moduleClass in self.moduleClasses) { |
|
if ([moduleClass conformsToProtocol:protocol]) { |
|
id module = [self moduleForClass:moduleClass]; |
|
if (module) { |
|
[modules addObject:module]; |
|
} |
|
} |
|
} |
|
return [modules copy]; |
|
} |
|
|
|
- (BOOL)moduleIsInitialized:(Class)moduleClass |
|
{ |
|
return [self.batchedBridge moduleIsInitialized:moduleClass]; |
|
} |
|
|
|
- (id)jsBoundExtraModuleForClass:(Class)moduleClass |
|
{ |
|
return [self.batchedBridge jsBoundExtraModuleForClass:moduleClass]; |
|
} |
|
|
|
- (void)reload |
|
{ |
|
#if RCT_ENABLE_INSPECTOR |
|
// Disable debugger to resume the JsVM & avoid thread locks while reloading |
|
[RCTInspectorDevServerHelper disableDebugger]; |
|
#endif |
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:RCTBridgeWillReloadNotification object:self]; |
|
|
|
/** |
|
* Any thread |
|
*/ |
|
dispatch_async(dispatch_get_main_queue(), ^{ |
|
[self invalidate]; |
|
[self setUp]; |
|
}); |
|
} |
|
|
|
- (void)requestReload |
|
{ |
|
[self reload]; |
|
} |
|
|
|
- (Class)bridgeClass |
|
{ |
|
return [RCTCxxBridge class]; |
|
} |
|
|
|
- (void)setUp |
|
{ |
|
RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTBridge setUp]", nil); |
|
|
|
_performanceLogger = [RCTPerformanceLogger new]; |
|
[_performanceLogger markStartForTag:RCTPLBridgeStartup]; |
|
[_performanceLogger markStartForTag:RCTPLTTI]; |
|
|
|
Class bridgeClass = self.bridgeClass; |
|
|
|
#if RCT_DEV |
|
RCTExecuteOnMainQueue(^{ |
|
RCTRegisterReloadCommandListener(self); |
|
}); |
|
#endif |
|
|
|
// Only update bundleURL from delegate if delegate bundleURL has changed |
|
NSURL *previousDelegateURL = _delegateBundleURL; |
|
_delegateBundleURL = [self.delegate sourceURLForBridge:self]; |
|
if (_delegateBundleURL && ![_delegateBundleURL isEqual:previousDelegateURL]) { |
|
_bundleURL = _delegateBundleURL; |
|
} |
|
|
|
// Sanitize the bundle URL |
|
_bundleURL = [RCTConvert NSURL:_bundleURL.absoluteString]; |
|
|
|
self.batchedBridge = [[bridgeClass alloc] initWithParentBridge:self]; |
|
[self.batchedBridge start]; |
|
|
|
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @""); |
|
} |
|
|
|
- (BOOL)isLoading |
|
{ |
|
return self.batchedBridge.loading; |
|
} |
|
|
|
- (BOOL)isValid |
|
{ |
|
return self.batchedBridge.valid; |
|
} |
|
|
|
- (BOOL)isBatchActive |
|
{ |
|
return [_batchedBridge isBatchActive]; |
|
} |
|
|
|
- (void)invalidate |
|
{ |
|
RCTBridge *batchedBridge = self.batchedBridge; |
|
self.batchedBridge = nil; |
|
|
|
if (batchedBridge) { |
|
RCTExecuteOnMainQueue(^{ |
|
[batchedBridge invalidate]; |
|
}); |
|
} |
|
} |
|
|
|
- (void)registerAdditionalModuleClasses:(NSArray<Class> *)modules |
|
{ |
|
[self.batchedBridge registerAdditionalModuleClasses:modules]; |
|
} |
|
|
|
- (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args |
|
{ |
|
NSArray<NSString *> *ids = [moduleDotMethod componentsSeparatedByString:@"."]; |
|
NSString *module = ids[0]; |
|
NSString *method = ids[1]; |
|
[self enqueueJSCall:module method:method args:args completion:NULL]; |
|
} |
|
|
|
- (void)enqueueJSCall:(NSString *)module method:(NSString *)method args:(NSArray *)args completion:(dispatch_block_t)completion |
|
{ |
|
[self.batchedBridge enqueueJSCall:module method:method args:args completion:completion]; |
|
} |
|
|
|
- (void)enqueueCallback:(NSNumber *)cbID args:(NSArray *)args |
|
{ |
|
[self.batchedBridge enqueueCallback:cbID args:args]; |
|
} |
|
|
|
- (void)registerSegmentWithId:(NSUInteger)segmentId path:(NSString *)path |
|
{ |
|
[self.batchedBridge registerSegmentWithId:segmentId path:path]; |
|
} |
|
|
|
- (JSGlobalContextRef)jsContextRef |
|
{ |
|
return [self.batchedBridge jsContextRef]; |
|
} |
|
|
|
@end
|
|
|