blob: 5c5a8f6a48876dc41a6a9aafdd8b8e1e1a57b104 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
#import "remoting/ios/facade/remoting_service.h"
#import <Foundation/Foundation.h>
#import <Security/Security.h>
#import "base/mac/bind_objc_block.h"
#import "remoting/ios/domain/host_info.h"
#import "remoting/ios/domain/user_info.h"
#import "remoting/ios/facade/host_info.h"
#import "remoting/ios/facade/host_list_fetcher.h"
#import "remoting/ios/facade/ios_client_runtime_delegate.h"
#import "remoting/ios/facade/remoting_authentication.h"
#import "remoting/ios/keychain_wrapper.h"
#include "base/i18n/time_formatting.h"
#include "base/logging.h"
#include "base/strings/sys_string_conversions.h"
#include "net/url_request/url_request_context_getter.h"
#include "remoting/base/oauth_token_getter.h"
#include "remoting/base/oauth_token_getter_impl.h"
static NSString* const kCRDAuthenticatedUserEmailKey =
@"kCRDAuthenticatedUserEmailKey";
NSString* const kHostsDidUpdate = @"kHostsDidUpdate";
NSString* const kUserDidUpdate = @"kUserDidUpdate";
NSString* const kUserInfo = @"kUserInfo";
@interface RemotingService ()<RemotingAuthenticationDelegate> {
id<RemotingAuthentication> _authentication;
remoting::HostListFetcher* _hostListFetcher;
remoting::IosClientRuntimeDelegate* _clientRuntimeDelegate;
BOOL _isHostListFetching;
}
@end
@implementation RemotingService
@synthesize hosts = _hosts;
// RemotingService is a singleton.
+ (RemotingService*)instance {
static RemotingService* sharedInstance = nil;
static dispatch_once_t guard;
dispatch_once(&guard, ^{
sharedInstance = [[RemotingService alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
_hosts = nil;
_hostListFetcher = nil;
// TODO(yuweih): Maybe better to just cancel the previous request.
_isHostListFetching = NO;
// TODO(nicholss): This might need a pointer back to the service.
_clientRuntimeDelegate =
new remoting::IosClientRuntimeDelegate();
[self runtime]->SetDelegate(_clientRuntimeDelegate);
}
return self;
}
#pragma mark - RemotingService Implementation
- (void)startHostListFetchWith:(NSString*)accessToken {
if (_isHostListFetching) {
return;
}
_isHostListFetching = YES;
if (!_hostListFetcher) {
_hostListFetcher = new remoting::HostListFetcher(
remoting::ChromotingClientRuntime::GetInstance()->url_requester());
}
_hostListFetcher->RetrieveHostlist(
base::SysNSStringToUTF8(accessToken),
base::BindBlockArc(^(const std::vector<remoting::HostInfo>& hostlist) {
NSMutableArray<HostInfo*>* hosts =
[NSMutableArray arrayWithCapacity:hostlist.size()];
std::string status;
for (const remoting::HostInfo& host_info : hostlist) {
remoting::HostStatus host_status = host_info.status;
switch (host_status) {
case remoting::kHostStatusOnline:
status = "ONLINE";
break;
case remoting::kHostStatusOffline:
status = "OFFLINE";
break;
default:
NOTREACHED();
}
// TODO(nicholss): Not yet integrated: createdTime, kind,
// offlineReason. Add them as the app will need this info.
HostInfo* host = [[HostInfo alloc] init];
host.hostId = base::SysUTF8ToNSString(host_info.host_id);
host.hostName = base::SysUTF8ToNSString(host_info.host_name);
host.hostOs = base::SysUTF8ToNSString(host_info.host_os);
host.hostOsVersion =
base::SysUTF8ToNSString(host_info.host_os_version);
host.hostVersion = base::SysUTF8ToNSString(host_info.host_version);
host.jabberId = base::SysUTF8ToNSString(host_info.host_jid);
host.publicKey = base::SysUTF8ToNSString(host_info.public_key);
host.status = base::SysUTF8ToNSString(status);
host.updatedTime = base::SysUTF16ToNSString(
base::TimeFormatShortDateAndTime(host_info.updated_time));
[hosts addObject:host];
}
_hosts = hosts;
[self hostListUpdated];
_isHostListFetching = NO;
}));
}
#pragma mark - Notifications
- (void)hostListUpdated {
[[NSNotificationCenter defaultCenter] postNotificationName:kHostsDidUpdate
object:self
userInfo:nil];
}
#pragma mark - RemotingAuthenticationDelegate
- (void)userDidUpdate:(UserInfo*)user {
NSDictionary* userInfo = nil;
if (user) {
userInfo = [NSDictionary dictionaryWithObject:user forKey:kUserInfo];
[self requestHostListFetch];
} else {
_hosts = nil;
[self hostListUpdated];
}
[[NSNotificationCenter defaultCenter] postNotificationName:kUserDidUpdate
object:self
userInfo:userInfo];
}
#pragma mark - Properties
- (NSArray<HostInfo*>*)hosts {
if ([_authentication.user isAuthenticated]) {
return _hosts;
}
return nil;
}
- (remoting::ChromotingClientRuntime*)runtime {
return remoting::ChromotingClientRuntime::GetInstance();
}
#pragma mark - Implementation
- (void)requestHostListFetch {
[_authentication
callbackWithAccessToken:^(RemotingAuthenticationStatus status,
NSString* userEmail, NSString* accessToken) {
[self startHostListFetchWith:accessToken];
}];
}
- (void)setAuthentication:(id<RemotingAuthentication>)authentication {
DCHECK(_authentication == nil);
authentication.delegate = self;
_authentication = authentication;
}
- (id<RemotingAuthentication>)authentication {
DCHECK(_authentication != nil);
return _authentication;
}
@end