123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- ////////////////////////////////////////////////////////////////////////////
- //
- // Copyright 2016 Realm Inc.
- //
- // 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 "RLMUser_Private.hpp"
- #import "RLMAPIKeyAuth.h"
- #import "RLMApp_Private.hpp"
- #import "RLMBSON_Private.hpp"
- #import "RLMCredentials_Private.hpp"
- #import "RLMMongoClient_Private.hpp"
- #import "RLMRealmConfiguration+Sync.h"
- #import "RLMSyncConfiguration_Private.hpp"
- #import "RLMSyncSession_Private.hpp"
- #import <realm/object-store/sync/sync_manager.hpp>
- #import <realm/object-store/sync/sync_session.hpp>
- #import <realm/object-store/sync/sync_user.hpp>
- #import <realm/object-store/util/bson/bson.hpp>
- using namespace realm;
- @interface RLMUser () {
- std::shared_ptr<SyncUser> _user;
- }
- @end
- @implementation RLMUserSubscriptionToken {
- @public
- std::unique_ptr<realm::Subscribable<SyncUser>::Token> _token;
- }
- - (instancetype)initWithToken:(realm::Subscribable<SyncUser>::Token&&)token {
- if (self = [super init]) {
- _token = std::make_unique<realm::Subscribable<SyncUser>::Token>(std::move(token));
- return self;
- }
- return nil;
- }
- - (NSUInteger)value {
- return _token->value();
- }
- @end
- @implementation RLMUser
- #pragma mark - API
- - (instancetype)initWithUser:(std::shared_ptr<SyncUser>)user
- app:(RLMApp *)app {
- if (self = [super init]) {
- _user = user;
- _app = app;
- return self;
- }
- return nil;
- }
- - (BOOL)isEqual:(id)object {
- if (![object isKindOfClass:[RLMUser class]]) {
- return NO;
- }
- return _user == ((RLMUser *)object)->_user;
- }
- - (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id<RLMBSON>)partitionValue {
- auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self
- partitionValue:partitionValue
- customFileURL:nil
- stopPolicy:RLMSyncStopPolicyAfterChangesUploaded];
- RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
- config.syncConfiguration = syncConfig;
- return config;
- }
- - (void)logOut {
- if (!_user) {
- return;
- }
- _user->log_out();
- }
- - (BOOL)isLoggedIn {
- return _user->is_logged_in();
- }
- - (void)invalidate {
- if (!_user) {
- return;
- }
- _user = nullptr;
- }
- - (std::string)pathForPartitionValue:(std::string const&)partitionValue {
- if (!_user) {
- return "";
- }
- auto path = _user->sync_manager()->path_for_realm(*_user, partitionValue);
- if ([NSFileManager.defaultManager fileExistsAtPath:@(path.c_str())]) {
- return path;
- }
- // Previous versions converted the partition value to a path *twice*,
- // so if the file resulting from that exists open it instead
- NSString *encodedPartitionValue = [@(partitionValue.data())
- stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLPathAllowedCharacterSet]];
- NSString *overEncodedRealmName = [[NSString alloc] initWithFormat:@"%@/%@", self.identifier, encodedPartitionValue];
- auto legacyPath = _user->sync_manager()->path_for_realm(*_user, overEncodedRealmName.UTF8String);
- if ([NSFileManager.defaultManager fileExistsAtPath:@(legacyPath.c_str())]) {
- return legacyPath;
- }
- return path;
- }
- - (nullable RLMSyncSession *)sessionForPartitionValue:(id<RLMBSON>)partitionValue {
- if (!_user) {
- return nil;
- }
- std::stringstream s;
- s << RLMConvertRLMBSONToBson(partitionValue);
- auto path = [self pathForPartitionValue:s.str()];
- if (auto session = _user->session_for_on_disk_path(path)) {
- return [[RLMSyncSession alloc] initWithSyncSession:session];
- }
- return nil;
- }
- - (NSArray<RLMSyncSession *> *)allSessions {
- if (!_user) {
- return @[];
- }
- NSMutableArray<RLMSyncSession *> *buffer = [NSMutableArray array];
- auto sessions = _user->all_sessions();
- for (auto session : sessions) {
- [buffer addObject:[[RLMSyncSession alloc] initWithSyncSession:std::move(session)]];
- }
- return [buffer copy];
- }
- - (NSString *)identifier {
- if (!_user) {
- return @"";
- }
- return @(_user->identity().c_str());
- }
- - (NSArray<RLMUserIdentity *> *)identities {
- if (!_user) {
- return @[];
- }
- NSMutableArray<RLMUserIdentity *> *buffer = [NSMutableArray array];
- auto identities = _user->identities();
- for (auto& identity : identities) {
- [buffer addObject: [[RLMUserIdentity alloc] initUserIdentityWithProviderType:@(identity.provider_type.c_str())
- identifier:@(identity.id.c_str())]];
- }
- return [buffer copy];
- }
- - (RLMUserState)state {
- if (!_user) {
- return RLMUserStateRemoved;
- }
- switch (_user->state()) {
- case SyncUser::State::LoggedIn:
- return RLMUserStateLoggedIn;
- case SyncUser::State::LoggedOut:
- return RLMUserStateLoggedOut;
- case SyncUser::State::Removed:
- return RLMUserStateRemoved;
- }
- }
- - (void)refreshCustomDataWithCompletion:(RLMUserCustomDataBlock)completion {
- _user->refresh_custom_data([completion, self](util::Optional<app::AppError> error) {
- if (!error) {
- return completion([self customData], nil);
- }
- completion(nil, RLMAppErrorToNSError(*error));
- });
- }
- - (void)linkUserWithCredentials:(RLMCredentials *)credentials
- completion:(RLMOptionalUserBlock)completion {
- _app._realmApp->link_user(_user, credentials.appCredentials,
- ^(std::shared_ptr<SyncUser> user, util::Optional<app::AppError> error) {
- if (error && error->error_code) {
- return completion(nil, RLMAppErrorToNSError(*error));
- }
- completion([[RLMUser alloc] initWithUser:user app:_app], nil);
- });
- }
- - (void)removeWithCompletion:(RLMOptionalErrorBlock)completion {
- _app._realmApp->remove_user(_user, ^(realm::util::Optional<app::AppError> error) {
- [self handleResponse:error completion:completion];
- });
- }
- - (void)logOutWithCompletion:(RLMOptionalErrorBlock)completion {
- _app._realmApp->log_out(_user, ^(realm::util::Optional<app::AppError> error) {
- [self handleResponse:error completion:completion];
- });
- }
- - (RLMAPIKeyAuth *)apiKeysAuth {
- return [[RLMAPIKeyAuth alloc] initWithApp: _app];
- }
- - (RLMMongoClient *)mongoClientWithServiceName:(NSString *)serviceName {
- return [[RLMMongoClient alloc] initWithUser:self serviceName:serviceName];
- }
- - (void)callFunctionNamed:(NSString *)name
- arguments:(NSArray<id<RLMBSON>> *)arguments
- completionBlock:(RLMCallFunctionCompletionBlock)completionBlock {
- bson::BsonArray args;
- for (id<RLMBSON> argument in arguments) {
- args.push_back(RLMConvertRLMBSONToBson(argument));
- }
- _app._realmApp->call_function(_user,
- std::string(name.UTF8String),
- args, [completionBlock](util::Optional<app::AppError> error,
- util::Optional<bson::Bson> response) {
- if (error) {
- return completionBlock(nil, RLMAppErrorToNSError(*error));
- }
- completionBlock(RLMConvertBsonToRLMBSON(*response), nil);
- });
- }
- - (void)handleResponse:(realm::util::Optional<realm::app::AppError>)error
- completion:(RLMOptionalErrorBlock)completion {
- if (error && error->error_code) {
- return completion(RLMAppErrorToNSError(*error));
- }
- completion(nil);
- }
- #pragma mark - Private API
- + (void)_setUpBindingContextFactory {
- SyncUser::set_binding_context_factory([] {
- return std::make_shared<CocoaSyncUserContext>();
- });
- }
- - (NSString *)refreshToken {
- if (!_user || _user->refresh_token().empty()) {
- return nil;
- }
- return @(_user->refresh_token().c_str());
- }
- - (NSString *)accessToken {
- if (!_user || _user->access_token().empty()) {
- return nil;
- }
- return @(_user->access_token().c_str());
- }
- - (NSDictionary *)customData {
- if (!_user || !_user->custom_data()) {
- return @{};
- }
- return (NSDictionary *)RLMConvertBsonToRLMBSON(*_user->custom_data());
- }
- - (std::shared_ptr<SyncUser>)_syncUser {
- return _user;
- }
- - (RLMUserSubscriptionToken *)subscribe:(RLMUserNotificationBlock) block {
- return [[RLMUserSubscriptionToken alloc] initWithToken:_user->subscribe([block, self] (auto&) {
- block(self);
- })];
- }
- - (void)unsubscribe:(RLMUserSubscriptionToken *)token {
- _user->unsubscribe(*token->_token);
- }
- @end
- #pragma mark - RLMUserIdentity
- @implementation RLMUserIdentity
- - (instancetype)initUserIdentityWithProviderType:(NSString *)providerType
- identifier:(NSString *)identifier {
- if (self = [super init]) {
- _providerType = providerType;
- _identifier = identifier;
- }
- return self;
- }
- @end
|