RLMUser.mm 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 Realm Inc.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. //
  17. ////////////////////////////////////////////////////////////////////////////
  18. #import "RLMUser_Private.hpp"
  19. #import "RLMAPIKeyAuth.h"
  20. #import "RLMApp_Private.hpp"
  21. #import "RLMBSON_Private.hpp"
  22. #import "RLMCredentials_Private.hpp"
  23. #import "RLMMongoClient_Private.hpp"
  24. #import "RLMRealmConfiguration+Sync.h"
  25. #import "RLMSyncConfiguration_Private.hpp"
  26. #import "RLMSyncSession_Private.hpp"
  27. #import <realm/object-store/sync/sync_manager.hpp>
  28. #import <realm/object-store/sync/sync_session.hpp>
  29. #import <realm/object-store/sync/sync_user.hpp>
  30. #import <realm/object-store/util/bson/bson.hpp>
  31. using namespace realm;
  32. @interface RLMUser () {
  33. std::shared_ptr<SyncUser> _user;
  34. }
  35. @end
  36. @implementation RLMUserSubscriptionToken {
  37. @public
  38. std::unique_ptr<realm::Subscribable<SyncUser>::Token> _token;
  39. }
  40. - (instancetype)initWithToken:(realm::Subscribable<SyncUser>::Token&&)token {
  41. if (self = [super init]) {
  42. _token = std::make_unique<realm::Subscribable<SyncUser>::Token>(std::move(token));
  43. return self;
  44. }
  45. return nil;
  46. }
  47. - (NSUInteger)value {
  48. return _token->value();
  49. }
  50. @end
  51. @implementation RLMUser
  52. #pragma mark - API
  53. - (instancetype)initWithUser:(std::shared_ptr<SyncUser>)user
  54. app:(RLMApp *)app {
  55. if (self = [super init]) {
  56. _user = user;
  57. _app = app;
  58. return self;
  59. }
  60. return nil;
  61. }
  62. - (BOOL)isEqual:(id)object {
  63. if (![object isKindOfClass:[RLMUser class]]) {
  64. return NO;
  65. }
  66. return _user == ((RLMUser *)object)->_user;
  67. }
  68. - (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id<RLMBSON>)partitionValue {
  69. auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self
  70. partitionValue:partitionValue
  71. customFileURL:nil
  72. stopPolicy:RLMSyncStopPolicyAfterChangesUploaded];
  73. RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
  74. config.syncConfiguration = syncConfig;
  75. return config;
  76. }
  77. - (void)logOut {
  78. if (!_user) {
  79. return;
  80. }
  81. _user->log_out();
  82. }
  83. - (BOOL)isLoggedIn {
  84. return _user->is_logged_in();
  85. }
  86. - (void)invalidate {
  87. if (!_user) {
  88. return;
  89. }
  90. _user = nullptr;
  91. }
  92. - (std::string)pathForPartitionValue:(std::string const&)partitionValue {
  93. if (!_user) {
  94. return "";
  95. }
  96. auto path = _user->sync_manager()->path_for_realm(*_user, partitionValue);
  97. if ([NSFileManager.defaultManager fileExistsAtPath:@(path.c_str())]) {
  98. return path;
  99. }
  100. // Previous versions converted the partition value to a path *twice*,
  101. // so if the file resulting from that exists open it instead
  102. NSString *encodedPartitionValue = [@(partitionValue.data())
  103. stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLPathAllowedCharacterSet]];
  104. NSString *overEncodedRealmName = [[NSString alloc] initWithFormat:@"%@/%@", self.identifier, encodedPartitionValue];
  105. auto legacyPath = _user->sync_manager()->path_for_realm(*_user, overEncodedRealmName.UTF8String);
  106. if ([NSFileManager.defaultManager fileExistsAtPath:@(legacyPath.c_str())]) {
  107. return legacyPath;
  108. }
  109. return path;
  110. }
  111. - (nullable RLMSyncSession *)sessionForPartitionValue:(id<RLMBSON>)partitionValue {
  112. if (!_user) {
  113. return nil;
  114. }
  115. std::stringstream s;
  116. s << RLMConvertRLMBSONToBson(partitionValue);
  117. auto path = [self pathForPartitionValue:s.str()];
  118. if (auto session = _user->session_for_on_disk_path(path)) {
  119. return [[RLMSyncSession alloc] initWithSyncSession:session];
  120. }
  121. return nil;
  122. }
  123. - (NSArray<RLMSyncSession *> *)allSessions {
  124. if (!_user) {
  125. return @[];
  126. }
  127. NSMutableArray<RLMSyncSession *> *buffer = [NSMutableArray array];
  128. auto sessions = _user->all_sessions();
  129. for (auto session : sessions) {
  130. [buffer addObject:[[RLMSyncSession alloc] initWithSyncSession:std::move(session)]];
  131. }
  132. return [buffer copy];
  133. }
  134. - (NSString *)identifier {
  135. if (!_user) {
  136. return @"";
  137. }
  138. return @(_user->identity().c_str());
  139. }
  140. - (NSArray<RLMUserIdentity *> *)identities {
  141. if (!_user) {
  142. return @[];
  143. }
  144. NSMutableArray<RLMUserIdentity *> *buffer = [NSMutableArray array];
  145. auto identities = _user->identities();
  146. for (auto& identity : identities) {
  147. [buffer addObject: [[RLMUserIdentity alloc] initUserIdentityWithProviderType:@(identity.provider_type.c_str())
  148. identifier:@(identity.id.c_str())]];
  149. }
  150. return [buffer copy];
  151. }
  152. - (RLMUserState)state {
  153. if (!_user) {
  154. return RLMUserStateRemoved;
  155. }
  156. switch (_user->state()) {
  157. case SyncUser::State::LoggedIn:
  158. return RLMUserStateLoggedIn;
  159. case SyncUser::State::LoggedOut:
  160. return RLMUserStateLoggedOut;
  161. case SyncUser::State::Removed:
  162. return RLMUserStateRemoved;
  163. }
  164. }
  165. - (void)refreshCustomDataWithCompletion:(RLMUserCustomDataBlock)completion {
  166. _user->refresh_custom_data([completion, self](util::Optional<app::AppError> error) {
  167. if (!error) {
  168. return completion([self customData], nil);
  169. }
  170. completion(nil, RLMAppErrorToNSError(*error));
  171. });
  172. }
  173. - (void)linkUserWithCredentials:(RLMCredentials *)credentials
  174. completion:(RLMOptionalUserBlock)completion {
  175. _app._realmApp->link_user(_user, credentials.appCredentials,
  176. ^(std::shared_ptr<SyncUser> user, util::Optional<app::AppError> error) {
  177. if (error && error->error_code) {
  178. return completion(nil, RLMAppErrorToNSError(*error));
  179. }
  180. completion([[RLMUser alloc] initWithUser:user app:_app], nil);
  181. });
  182. }
  183. - (void)removeWithCompletion:(RLMOptionalErrorBlock)completion {
  184. _app._realmApp->remove_user(_user, ^(realm::util::Optional<app::AppError> error) {
  185. [self handleResponse:error completion:completion];
  186. });
  187. }
  188. - (void)logOutWithCompletion:(RLMOptionalErrorBlock)completion {
  189. _app._realmApp->log_out(_user, ^(realm::util::Optional<app::AppError> error) {
  190. [self handleResponse:error completion:completion];
  191. });
  192. }
  193. - (RLMAPIKeyAuth *)apiKeysAuth {
  194. return [[RLMAPIKeyAuth alloc] initWithApp: _app];
  195. }
  196. - (RLMMongoClient *)mongoClientWithServiceName:(NSString *)serviceName {
  197. return [[RLMMongoClient alloc] initWithUser:self serviceName:serviceName];
  198. }
  199. - (void)callFunctionNamed:(NSString *)name
  200. arguments:(NSArray<id<RLMBSON>> *)arguments
  201. completionBlock:(RLMCallFunctionCompletionBlock)completionBlock {
  202. bson::BsonArray args;
  203. for (id<RLMBSON> argument in arguments) {
  204. args.push_back(RLMConvertRLMBSONToBson(argument));
  205. }
  206. _app._realmApp->call_function(_user,
  207. std::string(name.UTF8String),
  208. args, [completionBlock](util::Optional<app::AppError> error,
  209. util::Optional<bson::Bson> response) {
  210. if (error) {
  211. return completionBlock(nil, RLMAppErrorToNSError(*error));
  212. }
  213. completionBlock(RLMConvertBsonToRLMBSON(*response), nil);
  214. });
  215. }
  216. - (void)handleResponse:(realm::util::Optional<realm::app::AppError>)error
  217. completion:(RLMOptionalErrorBlock)completion {
  218. if (error && error->error_code) {
  219. return completion(RLMAppErrorToNSError(*error));
  220. }
  221. completion(nil);
  222. }
  223. #pragma mark - Private API
  224. + (void)_setUpBindingContextFactory {
  225. SyncUser::set_binding_context_factory([] {
  226. return std::make_shared<CocoaSyncUserContext>();
  227. });
  228. }
  229. - (NSString *)refreshToken {
  230. if (!_user || _user->refresh_token().empty()) {
  231. return nil;
  232. }
  233. return @(_user->refresh_token().c_str());
  234. }
  235. - (NSString *)accessToken {
  236. if (!_user || _user->access_token().empty()) {
  237. return nil;
  238. }
  239. return @(_user->access_token().c_str());
  240. }
  241. - (NSDictionary *)customData {
  242. if (!_user || !_user->custom_data()) {
  243. return @{};
  244. }
  245. return (NSDictionary *)RLMConvertBsonToRLMBSON(*_user->custom_data());
  246. }
  247. - (std::shared_ptr<SyncUser>)_syncUser {
  248. return _user;
  249. }
  250. - (RLMUserSubscriptionToken *)subscribe:(RLMUserNotificationBlock) block {
  251. return [[RLMUserSubscriptionToken alloc] initWithToken:_user->subscribe([block, self] (auto&) {
  252. block(self);
  253. })];
  254. }
  255. - (void)unsubscribe:(RLMUserSubscriptionToken *)token {
  256. _user->unsubscribe(*token->_token);
  257. }
  258. @end
  259. #pragma mark - RLMUserIdentity
  260. @implementation RLMUserIdentity
  261. - (instancetype)initUserIdentityWithProviderType:(NSString *)providerType
  262. identifier:(NSString *)identifier {
  263. if (self = [super init]) {
  264. _providerType = providerType;
  265. _identifier = identifier;
  266. }
  267. return self;
  268. }
  269. @end