// // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "OWSDevicesService.h" #import "NSNotificationCenter+OWS.h" #import "OWSDevice.h" #import "OWSError.h" #import "OWSRequestFactory.h" #import "TSNetworkManager.h" #import <Mantle/MTLJSONAdapter.h> #import <SessionProtocolKit/SessionProtocolKit.h> NS_ASSUME_NONNULL_BEGIN NSString *const NSNotificationName_DeviceListUpdateSucceeded = @"NSNotificationName_DeviceListUpdateSucceeded"; NSString *const NSNotificationName_DeviceListUpdateFailed = @"NSNotificationName_DeviceListUpdateFailed"; NSString *const NSNotificationName_DeviceListUpdateModifiedDeviceList = @"NSNotificationName_DeviceListUpdateModifiedDeviceList"; @implementation OWSDevicesService + (void)refreshDevices { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self getDevicesWithSuccess:^(NSArray<OWSDevice *> *devices) { // If we have more than one device; we may have a linked device. if (devices.count > 1) { // Setting this flag here shouldn't be necessary, but we do so // because the "cost" is low and it will improve robustness. [OWSDeviceManager.sharedManager setMayHaveLinkedDevices]; } BOOL didAddOrRemove = [OWSDevice replaceAll:devices]; [NSNotificationCenter.defaultCenter postNotificationNameAsync:NSNotificationName_DeviceListUpdateSucceeded object:nil]; if (didAddOrRemove) { [NSNotificationCenter.defaultCenter postNotificationNameAsync:NSNotificationName_DeviceListUpdateModifiedDeviceList object:nil]; } } failure:^(NSError *error) { OWSLogError(@"Request device list failed with error: %@", error); [NSNotificationCenter.defaultCenter postNotificationNameAsync:NSNotificationName_DeviceListUpdateFailed object:error]; }]; }); } + (void)getDevicesWithSuccess:(void (^)(NSArray<OWSDevice *> *))successCallback failure:(void (^)(NSError *))failureCallback { TSRequest *request = [OWSRequestFactory getDevicesRequest]; [[TSNetworkManager sharedManager] makeRequest:request success:^(NSURLSessionDataTask *task, id responseObject) { OWSLogVerbose(@"Get devices request succeeded"); NSArray<OWSDevice *> *devices = [self parseResponse:responseObject]; if (devices) { successCallback(devices); } else { OWSLogError(@"unable to parse devices response:%@", responseObject); NSError *error = OWSErrorMakeUnableToProcessServerResponseError(); failureCallback(error); } } failure:^(NSURLSessionDataTask *task, NSError *error) { OWSLogVerbose(@"Get devices request failed with error: %@", error); failureCallback(error); }]; } + (void)unlinkDevice:(OWSDevice *)device success:(void (^)(void))successCallback failure:(void (^)(NSError *))failureCallback { TSRequest *request = [OWSRequestFactory deleteDeviceRequestWithDevice:device]; [[TSNetworkManager sharedManager] makeRequest:request success:^(NSURLSessionDataTask *task, id responseObject) { OWSLogVerbose(@"Delete device request succeeded"); successCallback(); } failure:^(NSURLSessionDataTask *task, NSError *error) { OWSLogVerbose(@"Get devices request failed with error: %@", error); failureCallback(error); }]; } + (NSArray<OWSDevice *> *)parseResponse:(id)responseObject { if (![responseObject isKindOfClass:[NSDictionary class]]) { OWSLogError(@"Device response was not a dictionary."); return nil; } NSDictionary *response = (NSDictionary *)responseObject; NSArray<NSDictionary *> *devicesAttributes = response[@"devices"]; if (!devicesAttributes) { OWSLogError(@"Device response had no devices."); return nil; } NSMutableArray<OWSDevice *> *devices = [NSMutableArray new]; for (NSDictionary *deviceAttributes in devicesAttributes) { NSError *error; OWSDevice *_Nullable device = [OWSDevice deviceFromJSONDictionary:deviceAttributes error:&error]; if (error || !device) { OWSLogError(@"Failed to build device from dictionary with error: %@", error); } else { [devices addObject:device]; } } return [devices copy]; } @end NS_ASSUME_NONNULL_END