532 lines
25 KiB
Objective-C
532 lines
25 KiB
Objective-C
/// === hs.wifi.watcher ===
|
|
///
|
|
/// Watch for changes to the associated wifi network
|
|
|
|
@import Cocoa ;
|
|
@import LuaSkin ;
|
|
@import CoreWLAN ;
|
|
|
|
@class HSWifiWatcher ;
|
|
@class HSWifiWatcherManager ;
|
|
|
|
static const char *USERDATA_TAG = "hs.wifi.watcher" ;
|
|
static LSRefTable refTable = LUA_NOREF ;
|
|
static NSDictionary *watchableTypes ;
|
|
static HSWifiWatcherManager *manager ;
|
|
|
|
#define get_objectFromUserdata(objType, L, idx, tag) (objType*)*((void**)luaL_checkudata(L, idx, tag))
|
|
// #define get_structFromUserdata(objType, L, idx, tag) ((objType *)luaL_checkudata(L, idx, tag))
|
|
// #define get_cfobjectFromUserdata(objType, L, idx, tag) *((objType *)luaL_checkudata(L, idx, tag))
|
|
|
|
#pragma mark - Support Functions and Classes
|
|
|
|
@interface HSWifiWatcherManager : NSObject <CWEventDelegate>
|
|
// Having problems with 10.10 and 10.11 even though Docs say it should work, so for now, we'll go the old route...
|
|
// @property CWWiFiClient *client ;
|
|
@property CWInterface *interface;
|
|
@property NSMutableSet *watchers ;
|
|
@end
|
|
|
|
@interface HSWifiWatcher : NSObject
|
|
@property int callbackRef ;
|
|
@property int selfRef ;
|
|
@property NSSet *watchingFor ;
|
|
@end
|
|
|
|
@implementation HSWifiWatcherManager
|
|
- (instancetype)init {
|
|
self = [super init] ;
|
|
if (self) {
|
|
_watchers = [[NSMutableSet alloc] init] ;
|
|
|
|
// Having problems with 10.10 and 10.11 even though Docs say it should work, so for now, we'll go the old route...
|
|
// _client = [[CWWiFiClient alloc] init] ;
|
|
// _client.delegate = self ;
|
|
// Using the notification center for the notifications requires us to retain a reference to the interface
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
_interface = [CWInterface interface] ;
|
|
#pragma clang diagnostic pop
|
|
|
|
|
|
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter] ;
|
|
[watchableTypes enumerateKeysAndObjectsUsingBlock:^(__unused NSString *key, NSString *value, __unused BOOL *stop) {
|
|
// Having problems with 10.10 and 10.11 even though Docs say it should work, so for now, we'll go the old route...
|
|
// if ([value isKindOfClass:[NSNumber class]]) {
|
|
// NSError *error ;
|
|
// [self->_client startMonitoringEventWithType:[value integerValue] error:&error] ;
|
|
// if (error) {
|
|
// [LuaSkin logWarn:[NSString stringWithFormat:@"%s:initManager unable to register for event type %@: %@", USERDATA_TAG, key, [error localizedDescription]]] ;
|
|
// }
|
|
// }
|
|
[nc addObserver:self selector:@selector(identifyNotification:) name:value object:nil];
|
|
}] ;
|
|
}
|
|
return self ;
|
|
}
|
|
|
|
// If we ever go back to the "non-deprecated" approach, this is no longer required
|
|
- (void)dealloc {
|
|
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter] ;
|
|
[watchableTypes enumerateKeysAndObjectsUsingBlock:^(__unused NSString *key, NSString *value, __unused BOOL *stop) {
|
|
[nc removeObserver:self name:value object:nil];
|
|
}] ;
|
|
}
|
|
|
|
- (void)identifyNotification:(NSNotification *)notification {
|
|
NSString *type = notification.name ;
|
|
NSString *interface = _interface.interfaceName ;
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
if ([type isEqualToString:CWPowerDidChangeNotification]) {
|
|
[self invokeCallbacksFor:@"powerChange" withDetails:@[ interface ]] ;
|
|
} else if ([type isEqualToString:CWSSIDDidChangeNotification]) {
|
|
[self invokeCallbacksFor:@"SSIDChange" withDetails:@[ interface ]] ;
|
|
} else if ([type isEqualToString:CWBSSIDDidChangeNotification]) {
|
|
[self invokeCallbacksFor:@"BSSIDChange" withDetails:@[ interface ]] ;
|
|
} else if ([type isEqualToString:CWCountryCodeDidChangeNotification]) {
|
|
[self invokeCallbacksFor:@"countryCodeChange" withDetails:@[ interface ]] ;
|
|
} else if ([type isEqualToString:CWLinkDidChangeNotification]) {
|
|
[self invokeCallbacksFor:@"linkChange" withDetails:@[ interface ]] ;
|
|
} else if ([type isEqualToString:CWLinkQualityDidChangeNotification]) {
|
|
NSNumber *rssi = notification.userInfo[CWLinkQualityNotificationRSSIKey] ;
|
|
NSNumber *transmitRate = notification.userInfo[CWLinkQualityNotificationTransmitRateKey] ;
|
|
[self invokeCallbacksFor:@"linkQualityChange" withDetails:@[ interface, rssi, transmitRate ]] ;
|
|
} else if ([type isEqualToString:CWModeDidChangeNotification]) {
|
|
[self invokeCallbacksFor:@"modeChange" withDetails:@[ interface ]] ;
|
|
} else if ([type isEqualToString:CWScanCacheDidUpdateNotification]) {
|
|
[self invokeCallbacksFor:@"scanCacheUpdated" withDetails:@[ interface ]] ;
|
|
} else {
|
|
[LuaSkin logWarn:[NSString stringWithFormat:@"%s:identifyNotification - unrecognized notification received: %@", USERDATA_TAG, type]] ;
|
|
}
|
|
#pragma clang diagnostic pop
|
|
}
|
|
|
|
// Having problems with 10.10 and 10.11 even though Docs say it should work, so for now, we'll go the old route...
|
|
// // // Need to determine if these are useful or if they indicate problems we can't handle at present
|
|
// // // anyways... will wait until I know more or someone asks about them.
|
|
// //
|
|
// // - (void)clientConnectionInterrupted {
|
|
// // [self invokeCallbacksFor:@"connectionInterrupted" withDetails:nil] ;
|
|
// // }
|
|
// //
|
|
// // - (void)clientConnectionInvalidated {
|
|
// // [self invokeCallbacksFor:@"connectionInvalidated" withDetails:nil] ;
|
|
// // }
|
|
//
|
|
// - (void)powerStateDidChangeForWiFiInterfaceWithName:(NSString *)interfaceName {
|
|
// [self invokeCallbacksFor:@"powerChange" withDetails:@[ interfaceName ]] ;
|
|
// }
|
|
//
|
|
// - (void)ssidDidChangeForWiFiInterfaceWithName:(NSString *)interfaceName {
|
|
// [self invokeCallbacksFor:@"SSIDChange" withDetails:@[ interfaceName ]] ;
|
|
// }
|
|
//
|
|
// - (void)bssidDidChangeForWiFiInterfaceWithName:(NSString *)interfaceName {
|
|
// [self invokeCallbacksFor:@"BSSIDChange" withDetails:@[ interfaceName ]] ;
|
|
// }
|
|
//
|
|
// - (void)countryCodeDidChangeForWiFiInterfaceWithName:(NSString *)interfaceName {
|
|
// [self invokeCallbacksFor:@"countryCodeChange" withDetails:@[ interfaceName ]] ;
|
|
// }
|
|
//
|
|
// // // apparently Travis doesn't know about this yet... and since I don't know how to test it
|
|
// // // anyways, I'll wait until I know more or someone asks for it
|
|
// //
|
|
// // - (void)virtualInterfaceStateChangedForWiFiInterfaceWithName:(NSString *)interfaceName {
|
|
// // [self invokeCallbacksFor:@"virtualInterfaceStateChanged" withDetails:@[ interfaceName ]] ;
|
|
// // }
|
|
//
|
|
// // // I think this applies to beacon support which I can't really test with my current hardware
|
|
// // // and can't find well documented for macOS at present... I'm holding off on this until I
|
|
// // // know more or someone asks about it.
|
|
// //
|
|
// // - (void)rangingReportEventForWiFiInterfaceWithName:(NSString *)interfaceName data:(NSArray *)rangingData error:(NSError *)error {
|
|
// // NSMutableDictionary *details = [[NSMutableArray alloc] init] ;
|
|
// // [details addObject:interfaceName] ;
|
|
// // if (rangingData) [details addObject:rangingData] ;
|
|
// // if (error) [details addObject:[error localizedDescription]] ;
|
|
// // [self invokeCallbacksFor:@"rangingReport" withDetails:details] ;
|
|
// // }
|
|
//
|
|
// - (void)linkDidChangeForWiFiInterfaceWithName:(NSString *)interfaceName {
|
|
// [self invokeCallbacksFor:@"linkChange" withDetails:@[ interfaceName ]] ;
|
|
// }
|
|
//
|
|
// - (void)linkQualityDidChangeForWiFiInterfaceWithName:(NSString *)interfaceName rssi:(NSInteger)rssi transmitRate:(double)transmitRate {
|
|
// [self invokeCallbacksFor:@"linkQualityChange" withDetails:@[ interfaceName, @(rssi), @(transmitRate) ]] ;
|
|
// }
|
|
//
|
|
// - (void)modeDidChangeForWiFiInterfaceWithName:(NSString *)interfaceName {
|
|
// [self invokeCallbacksFor:@"modeChange" withDetails:@[ interfaceName ]] ;
|
|
// }
|
|
//
|
|
// - (void)scanCacheUpdatedForWiFiInterfaceWithName:(NSString *)interfaceName {
|
|
// [self invokeCallbacksFor:@"scanCacheUpdated" withDetails:@[ interfaceName ]] ;
|
|
// }
|
|
|
|
- (void)invokeCallbacksFor:(NSString *)message withDetails:(NSArray *)details {
|
|
if (!watchableTypes[message]) {
|
|
[LuaSkin logError:[NSString stringWithFormat:@"%s:invokeCallbacksFor called with unrecognized lable:%@", USERDATA_TAG, message]] ;
|
|
return ;
|
|
}
|
|
[_watchers enumerateObjectsUsingBlock:^(HSWifiWatcher *aWatcher, __unused BOOL *stop) {
|
|
if ([aWatcher.watchingFor containsObject:message]) {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
if (aWatcher.callbackRef != LUA_NOREF) {
|
|
LuaSkin *skin = [LuaSkin sharedWithState:NULL] ;
|
|
_lua_stackguard_entry(skin.L);
|
|
[skin pushLuaRef:refTable ref:aWatcher.callbackRef] ;
|
|
[skin pushNSObject:aWatcher] ;
|
|
[skin pushNSObject:message] ;
|
|
NSUInteger count = (details) ? [details count] : 0 ;
|
|
if (count > 0) [skin growStack:(int)count withMessage:"hs.wifi.watcher:invokeCallbacksFor"];
|
|
if (details) {
|
|
for (id argument in details) {
|
|
[skin pushNSObject:argument withOptions:LS_NSDescribeUnknownTypes] ;
|
|
}
|
|
}
|
|
[skin protectedCallAndError:[NSString stringWithFormat:@"hs.wifi.watcher callback for %@", message] nargs:(2 + (int)count) nresults:0];
|
|
_lua_stackguard_exit(skin.L);
|
|
}
|
|
}) ;
|
|
}
|
|
}] ;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation HSWifiWatcher
|
|
|
|
- (instancetype)init {
|
|
self = [super init] ;
|
|
if (self) {
|
|
_callbackRef = LUA_NOREF ;
|
|
_selfRef = 0 ;
|
|
_watchingFor = [NSSet setWithObject:@"SSIDChange"] ;
|
|
}
|
|
return self ;
|
|
}
|
|
|
|
@end
|
|
|
|
#pragma mark - Module Functions
|
|
|
|
/// hs.wifi.watcher.new(fn) -> watcher
|
|
/// Constructor
|
|
/// Creates a new watcher for WiFi network events
|
|
///
|
|
/// Parameters:
|
|
/// * fn - A function that will be called when a WiFi event that is being monitored occurs. The function should expect 2 or 4 arguments as described in the notes below.
|
|
///
|
|
/// Returns:
|
|
/// * A `hs.wifi.watcher` object
|
|
///
|
|
/// Notes:
|
|
/// * For backwards compatibility, only "SSIDChange" is watched for by default, so existing code can continue to ignore the callback function arguments unless you add or change events with the [hs.wifi.watcher:watchingFor](#watchingFor).
|
|
/// * The callback function should expect between 3 and 5 arguments, depending upon the events being watched. The possible arguments are as follows:
|
|
/// * `watcher`, "SSIDChange", `interface` - occurs when the associated network for the Wi-Fi interface changes
|
|
/// * `watcher` - the watcher object itself
|
|
/// * `message` - the message specifying the event, in this case "SSIDChange"
|
|
/// * `interface` - the name of the interface for which the event occured
|
|
/// * Use `hs.wifi.currentNetwork([interface])` to identify the new network, which may be nil when you leave a network.
|
|
/// * `watcher`, "BSSIDChange", `interface` - occurs when the base station the Wi-Fi interface is connected to changes
|
|
/// * `watcher` - the watcher object itself
|
|
/// * `message` - the message specifying the event, in this case "BSSIDChange"
|
|
/// * `interface` - the name of the interface for which the event occured
|
|
/// * `watcher`, "countryCodeChange", `interface` - occurs when the adopted country code of the Wi-Fi interface changes
|
|
/// * `watcher` - the watcher object itself
|
|
/// * `message` - the message specifying the event, in this case "countryCodeChange"
|
|
/// * `interface` - the name of the interface for which the event occured
|
|
/// * `watcher`, "linkChange", `interface` - occurs when the link state for the Wi-Fi interface changes
|
|
/// * `watcher` - the watcher object itself
|
|
/// * `message` - the message specifying the event, in this case "linkChange"
|
|
/// * `interface` - the name of the interface for which the event occured
|
|
/// * `watcher`, "linkQualityChange", `interface` - occurs when the RSSI or transmit rate for the Wi-Fi interface changes
|
|
/// * `watcher` - the watcher object itself
|
|
/// * `message` - the message specifying the event, in this case "linkQualityChange"
|
|
/// * `interface` - the name of the interface for which the event occured
|
|
/// * `rssi` - the RSSI value for the currently associated network on the Wi-Fi interface
|
|
/// * `rate` - the transmit rate for the currently associated network on the Wi-Fi interface
|
|
/// * `watcher`, "modeChange", `interface` - occurs when the operating mode of the Wi-Fi interface changes
|
|
/// * `watcher` - the watcher object itself
|
|
/// * `message` - the message specifying the event, in this case "modeChange"
|
|
/// * `interface` - the name of the interface for which the event occured
|
|
/// * `watcher`, "powerChange", `interface` - occurs when the power state of the Wi-Fi interface changes
|
|
/// * `watcher` - the watcher object itself
|
|
/// * `message` - the message specifying the event, in this case "powerChange"
|
|
/// * `interface` - the name of the interface for which the event occured
|
|
/// * `watcher`, "scanCacheUpdated", `interface` - occurs when the scan cache of the Wi-Fi interface is updated with new information
|
|
/// * `watcher` - the watcher object itself
|
|
/// * `message` - the message specifying the event, in this case "scanCacheUpdated"
|
|
/// * `interface` - the name of the interface for which the event occured
|
|
// ///
|
|
// /// * `watcher`, "virtualInterfaceStateChanged", `interface` - occurs when the state of a Wi-Fi virtual interface changes
|
|
// /// * `watcher` - the watcher object itself
|
|
// /// * `message` - the message specifying the event, in this case "virtualInterfaceStateChanged"
|
|
// /// * `interface` - the name of the interface for which the event occured
|
|
static int wifi_watcher_new(lua_State *L) {
|
|
LuaSkin *skin = [LuaSkin sharedWithState:L] ;
|
|
[skin checkArgs:LS_TFUNCTION, LS_TBREAK] ;
|
|
HSWifiWatcher *newWatcher = [[HSWifiWatcher alloc] init] ;
|
|
if (newWatcher) {
|
|
lua_pushvalue(L, 1) ;
|
|
newWatcher.callbackRef = [skin luaRef:refTable] ;
|
|
}
|
|
[skin pushNSObject:newWatcher] ;
|
|
return 1 ;
|
|
}
|
|
|
|
#pragma mark - Module Methods
|
|
|
|
/// hs.wifi.watcher:start() -> watcher
|
|
/// Method
|
|
/// Starts the SSID watcher
|
|
///
|
|
/// Parameters:
|
|
/// * None
|
|
///
|
|
/// Returns:
|
|
/// * The `hs.wifi.watcher` object
|
|
static int wifi_watcher_start(lua_State *L) {
|
|
LuaSkin *skin = [LuaSkin sharedWithState:L] ;
|
|
[skin checkArgs:LS_TUSERDATA, USERDATA_TAG, LS_TBREAK] ;
|
|
HSWifiWatcher *watcher = [skin toNSObjectAtIndex:1] ;
|
|
[manager.watchers addObject:watcher] ;
|
|
lua_pushvalue(L, 1) ;
|
|
return 1 ;
|
|
}
|
|
|
|
/// hs.wifi.watcher:stop() -> watcher
|
|
/// Method
|
|
/// Stops the SSID watcher
|
|
///
|
|
/// Parameters:
|
|
/// * None
|
|
///
|
|
/// Returns:
|
|
/// * The `hs.wifi.watcher` object
|
|
static int wifi_watcher_stop(lua_State *L) {
|
|
LuaSkin *skin = [LuaSkin sharedWithState:L] ;
|
|
[skin checkArgs:LS_TUSERDATA, USERDATA_TAG, LS_TBREAK] ;
|
|
HSWifiWatcher *watcher = [skin toNSObjectAtIndex:1] ;
|
|
[manager.watchers removeObject:watcher] ;
|
|
lua_pushvalue(L, 1) ;
|
|
return 1 ;
|
|
}
|
|
|
|
/// hs.wifi.watcher:watchingFor([messages]) -> watcher | current-value
|
|
/// Method
|
|
/// Get or set the specific types of wifi events to generate a callback for with this watcher.
|
|
///
|
|
/// Parameters:
|
|
/// * `messages` - an optional table of or list of strings specifying the types of events this watcher should invoke a callback for. You can specify multiple types of events to watch for. Defaults to `{ "SSIDChange" }`.
|
|
///
|
|
/// Returns:
|
|
/// * if a value is provided, returns the watcher object; otherwise returns the current values as a table of strings.
|
|
///
|
|
/// Notes:
|
|
/// * the possible values for this method are described in [hs.wifi.watcher.eventTypes](#eventTypes).
|
|
/// * the special string "all" specifies that all event types should be watched for.
|
|
static int wifi_watcher_watchingFor(lua_State *L) {
|
|
LuaSkin *skin = [LuaSkin sharedWithState:L] ;
|
|
[skin checkArgs:LS_TUSERDATA, USERDATA_TAG, LS_TTABLE | LS_TOPTIONAL, LS_TBREAK] ;
|
|
HSWifiWatcher *watcher = [skin toNSObjectAtIndex:1] ;
|
|
if (lua_gettop(L) == 1) {
|
|
[skin pushNSObject:watcher.watchingFor] ;
|
|
} else {
|
|
NSArray *messages = [skin toNSObjectAtIndex:2] ;
|
|
if ([messages isKindOfClass:[NSArray class]]) {
|
|
__block NSString *messageError ;
|
|
[messages enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL *stop) {
|
|
if ([obj isKindOfClass:[NSString class]]) {
|
|
if (![[watchableTypes allKeys] containsObject:obj]) {
|
|
*stop = YES ;
|
|
messageError = [NSString stringWithFormat:@"unrecognized message at index %lu; expected one of %@", idx + 1, [[watchableTypes allKeys] componentsJoinedByString:@", "]] ;
|
|
}
|
|
} else {
|
|
*stop = YES ;
|
|
messageError = [NSString stringWithFormat:@"expected string at index %lu", idx + 1] ;
|
|
}
|
|
}] ;
|
|
if (messageError) return luaL_argerror(L, 2, [messageError UTF8String]) ;
|
|
watcher.watchingFor = [NSSet setWithArray:messages] ;
|
|
lua_pushvalue(L, 1) ;
|
|
} else {
|
|
return luaL_argerror(L, 2, "expected an array of messages") ;
|
|
}
|
|
}
|
|
return 1 ;
|
|
}
|
|
|
|
#pragma mark - Module Constants
|
|
|
|
/// hs.wifi.watcher.eventTypes[]
|
|
/// Constant
|
|
/// A table containing the possible event types that this watcher can monitor for.
|
|
///
|
|
/// Notes:
|
|
/// * The following events are available for monitoring:
|
|
/// * "SSIDChange" - monitor when the associated network for the Wi-Fi interface changes
|
|
/// * "BSSIDChange" - monitor when the base station the Wi-Fi interface is connected to changes
|
|
/// * "countryCodeChange" - monitor when the adopted country code of the Wi-Fi interface changes
|
|
/// * "linkChange" - monitor when the link state for the Wi-Fi interface changes
|
|
/// * "linkQualityChange" - monitor when the RSSI or transmit rate for the Wi-Fi interface changes
|
|
/// * "modeChange" - monitor when the operating mode of the Wi-Fi interface changes
|
|
/// * "powerChange" - monitor when the power state of the Wi-Fi interface changes
|
|
/// * "scanCacheUpdated" - monitor when the scan cache of the Wi-Fi interface is updated with new information
|
|
// /// * "virtualInterfaceStateChanged" - monitor when the state of a Wi-Fi virtual interface changes
|
|
static int pushEventTypes(lua_State *L) {
|
|
[[LuaSkin sharedWithState:L] pushNSObject:[watchableTypes allKeys]] ;
|
|
return 1 ;
|
|
}
|
|
|
|
#pragma mark - Lua<->NSObject Conversion Functions
|
|
// These must not throw a lua error to ensure LuaSkin can safely be used from Objective-C
|
|
// delegates and blocks.
|
|
|
|
static int pushHSWifiWatcher(lua_State *L, id obj) {
|
|
HSWifiWatcher *value = obj;
|
|
value.selfRef++ ;
|
|
void** valuePtr = lua_newuserdata(L, sizeof(HSWifiWatcher *));
|
|
*valuePtr = (__bridge_retained void *)value;
|
|
luaL_getmetatable(L, USERDATA_TAG);
|
|
lua_setmetatable(L, -2);
|
|
return 1;
|
|
}
|
|
|
|
static id toHSWifiWatcherFromLua(lua_State *L, int idx) {
|
|
LuaSkin *skin = [LuaSkin sharedWithState:L] ;
|
|
HSWifiWatcher *value ;
|
|
if (luaL_testudata(L, idx, USERDATA_TAG)) {
|
|
value = get_objectFromUserdata(__bridge HSWifiWatcher, L, idx, USERDATA_TAG) ;
|
|
} else {
|
|
[skin logError:[NSString stringWithFormat:@"expected %s object, found %s", USERDATA_TAG,
|
|
lua_typename(L, lua_type(L, idx))]] ;
|
|
}
|
|
return value ;
|
|
}
|
|
|
|
#pragma mark - Hammerspoon/Lua Infrastructure
|
|
|
|
static int userdata_tostring(lua_State* L) {
|
|
LuaSkin *skin = [LuaSkin sharedWithState:L] ;
|
|
// HSWifiWatcher *obj = [skin luaObjectAtIndex:1 toClass:"HSWifiWatcher"] ;
|
|
[skin pushNSObject:[NSString stringWithFormat:@"%s: (%p)", USERDATA_TAG, lua_topointer(L, 1)]] ;
|
|
return 1 ;
|
|
}
|
|
|
|
static int userdata_eq(lua_State* L) {
|
|
// can't get here if at least one of us isn't a userdata type, and we only care if both types are ours,
|
|
// so use luaL_testudata before the macro causes a lua error
|
|
if (luaL_testudata(L, 1, USERDATA_TAG) && luaL_testudata(L, 2, USERDATA_TAG)) {
|
|
LuaSkin *skin = [LuaSkin sharedWithState:L] ;
|
|
HSWifiWatcher *obj1 = [skin luaObjectAtIndex:1 toClass:"HSWifiWatcher"] ;
|
|
HSWifiWatcher *obj2 = [skin luaObjectAtIndex:2 toClass:"HSWifiWatcher"] ;
|
|
lua_pushboolean(L, [obj1 isEqualTo:obj2]) ;
|
|
} else {
|
|
lua_pushboolean(L, NO) ;
|
|
}
|
|
return 1 ;
|
|
}
|
|
|
|
static int userdata_gc(lua_State* L) {
|
|
HSWifiWatcher *obj = get_objectFromUserdata(__bridge_transfer HSWifiWatcher, L, 1, USERDATA_TAG) ;
|
|
if (obj) {
|
|
obj.selfRef-- ;
|
|
if (obj.selfRef == 0) {
|
|
obj.callbackRef = [[LuaSkin sharedWithState:L] luaUnref:refTable ref:obj.callbackRef] ;
|
|
[manager.watchers removeObject:obj] ;
|
|
obj = nil ;
|
|
}
|
|
}
|
|
// Remove the Metatable so future use of the variable in Lua won't think its valid
|
|
lua_pushnil(L) ;
|
|
lua_setmetatable(L, 1) ;
|
|
return 0 ;
|
|
}
|
|
|
|
static int meta_gc(lua_State* __unused L) {
|
|
[manager.watchers removeAllObjects] ;
|
|
NSError *error ;
|
|
// Having problems with 10.10 and 10.11 even though Docs say it should work, so for now, we'll go the old route...
|
|
// [manager.client stopMonitoringAllEventsAndReturnError:&error] ;
|
|
if (error) {
|
|
[LuaSkin logWarn:[NSString stringWithFormat:@"%s:meta_gc unable to unregister events: %@", USERDATA_TAG, [error localizedDescription]]] ;
|
|
}
|
|
// Having problems with 10.10 and 10.11 even though Docs say it should work, so for now, we'll go the old route...
|
|
// manager.client = nil ;
|
|
manager = nil ;
|
|
return 0 ;
|
|
}
|
|
|
|
// Metatable for userdata objects
|
|
static const luaL_Reg userdata_metaLib[] = {
|
|
{"start", wifi_watcher_start},
|
|
{"stop", wifi_watcher_stop},
|
|
{"watchingFor", wifi_watcher_watchingFor},
|
|
|
|
{"__tostring", userdata_tostring},
|
|
{"__eq", userdata_eq},
|
|
{"__gc", userdata_gc},
|
|
{NULL, NULL}
|
|
};
|
|
|
|
// Functions for returned object when module loads
|
|
static luaL_Reg moduleLib[] = {
|
|
{"new", wifi_watcher_new},
|
|
{NULL, NULL}
|
|
};
|
|
|
|
// Metatable for module, if needed
|
|
static const luaL_Reg module_metaLib[] = {
|
|
{"__gc", meta_gc},
|
|
{NULL, NULL}
|
|
};
|
|
|
|
int luaopen_hs_libwifiwatcher(lua_State* L) {
|
|
LuaSkin *skin = [LuaSkin sharedWithState:L] ;
|
|
refTable = [skin registerLibraryWithObject:USERDATA_TAG
|
|
functions:moduleLib
|
|
metaFunctions:module_metaLib
|
|
objectFunctions:userdata_metaLib];
|
|
|
|
watchableTypes = @{
|
|
// Having problems with 10.10 and 10.11 even though Docs say it should work, so for now, we'll go the old route...
|
|
// @"powerChange" : @(CWEventTypePowerDidChange),
|
|
// @"SSIDChange" : @(CWEventTypeSSIDDidChange),
|
|
// @"BSSIDChange" : @(CWEventTypeBSSIDDidChange),
|
|
// @"countryCodeChange" : @(CWEventTypeCountryCodeDidChange),
|
|
// @"linkChange" : @(CWEventTypeLinkDidChange),
|
|
// @"linkQualityChange" : @(CWEventTypeLinkQualityDidChange),
|
|
// @"modeChange" : @(CWEventTypeModeDidChange),
|
|
// @"scanCacheUpdated" : @(CWEventTypeScanCacheUpdated),
|
|
// // see delegate for comments regarding these
|
|
// // @"virtualInterfaceStateChanged" : @(CWEventTypeVirtualInterfaceStateChanged),
|
|
// // @"rangingReport" : @(CWEventTypeRangingReportEvent),
|
|
// // @"connectionInterrupted" : @"clientConnectionInterrupted",
|
|
// // @"connectionInvalidated" : @"clientConnectionInvalidated",
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
@"powerChange" : CWPowerDidChangeNotification,
|
|
@"SSIDChange" : CWSSIDDidChangeNotification,
|
|
@"BSSIDChange" : CWBSSIDDidChangeNotification,
|
|
@"countryCodeChange" : CWCountryCodeDidChangeNotification,
|
|
@"linkChange" : CWLinkDidChangeNotification,
|
|
@"linkQualityChange" : CWLinkQualityDidChangeNotification,
|
|
@"modeChange" : CWModeDidChangeNotification,
|
|
@"scanCacheUpdated" : CWScanCacheDidUpdateNotification,
|
|
#pragma clang diagnostic pop
|
|
} ;
|
|
|
|
manager = [[HSWifiWatcherManager alloc] init] ;
|
|
|
|
[skin registerPushNSHelper:pushHSWifiWatcher forClass:"HSWifiWatcher"];
|
|
[skin registerLuaObjectHelper:toHSWifiWatcherFromLua forClass:"HSWifiWatcher"
|
|
withUserdataMapping:USERDATA_TAG];
|
|
|
|
pushEventTypes(L) ; lua_setfield(L, -2, "eventTypes") ;
|
|
|
|
return 1;
|
|
}
|