added iOS source code
[wl-app.git] / iOS / Pods / Realm / Realm / ObjectStore / src / sync / sync_user.cpp
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
19 #include "sync/sync_user.hpp"
20
21 #include "sync/impl/sync_metadata.hpp"
22 #include "sync/sync_manager.hpp"
23 #include "sync/sync_session.hpp"
24
25 namespace realm {
26
27 SyncUserContextFactory SyncUser::s_binding_context_factory;
28 std::mutex SyncUser::s_binding_context_factory_mutex;
29
30 SyncUser::SyncUser(std::string refresh_token,
31                    std::string identity,
32                    util::Optional<std::string> server_url,
33                    util::Optional<std::string> local_identity,
34                    TokenType token_type)
35 : m_state(State::Active)
36 , m_server_url(server_url.value_or(""))
37 , m_token_type(token_type)
38 , m_refresh_token(std::move(refresh_token))
39 , m_identity(std::move(identity))
40 {
41     {
42         std::lock_guard<std::mutex> lock(s_binding_context_factory_mutex);
43         if (s_binding_context_factory) {
44             m_binding_context = s_binding_context_factory();
45         }
46     }
47     if (token_type == TokenType::Normal) {
48         REALM_ASSERT(m_server_url.length() > 0);
49         bool updated = SyncManager::shared().perform_metadata_update([=](const auto& manager) {
50             auto metadata = manager.get_or_make_user_metadata(m_identity, m_server_url);
51             metadata->set_user_token(m_refresh_token);
52             m_is_admin = metadata->is_admin();
53             m_local_identity = metadata->local_uuid();
54         });
55         if (!updated)
56             m_local_identity = m_identity;
57     } else {
58         // Admin token users. The local identity serves as the directory path.
59         REALM_ASSERT(local_identity);
60         m_local_identity = std::move(*local_identity);
61     }
62 }
63
64 std::vector<std::shared_ptr<SyncSession>> SyncUser::all_sessions()
65 {
66     std::lock_guard<std::mutex> lock(m_mutex);
67     std::vector<std::shared_ptr<SyncSession>> sessions;
68     if (m_state == State::Error) {
69         return sessions;
70     }
71     for (auto it = m_sessions.begin(); it != m_sessions.end();) {
72         if (auto ptr_to_session = it->second.lock()) {
73             if (!ptr_to_session->is_in_error_state()) {
74                 sessions.emplace_back(std::move(ptr_to_session));
75                 it++;
76                 continue;
77             }
78         }
79         // This session is bad, destroy it.
80         it = m_sessions.erase(it);
81     }
82     return sessions;
83 }
84
85 std::shared_ptr<SyncSession> SyncUser::session_for_on_disk_path(const std::string& path)
86 {
87     std::lock_guard<std::mutex> lock(m_mutex);
88     if (m_state == State::Error) {
89         return nullptr;
90     }
91     auto it = m_sessions.find(path);
92     if (it == m_sessions.end()) {
93         return nullptr;
94     }
95     auto locked = it->second.lock();
96     if (!locked) {
97         // Remove the session from the map, because it has fatally errored out or the entry is invalid.
98         m_sessions.erase(it);
99     }
100     return locked;
101 }
102
103 void SyncUser::update_refresh_token(std::string token)
104 {
105     std::vector<std::shared_ptr<SyncSession>> sessions_to_revive;
106     {
107         std::unique_lock<std::mutex> lock(m_mutex);
108         if (auto session = m_management_session.lock())
109             sessions_to_revive.emplace_back(std::move(session));
110
111         if (auto session = m_permission_session.lock())
112             sessions_to_revive.emplace_back(std::move(session));
113
114         switch (m_state) {
115             case State::Error:
116                 return;
117             case State::Active:
118                 m_refresh_token = token;
119                 break;
120             case State::LoggedOut: {
121                 sessions_to_revive.reserve(m_waiting_sessions.size());
122                 m_refresh_token = token;
123                 m_state = State::Active;
124                 for (auto& pair : m_waiting_sessions) {
125                     if (auto ptr = pair.second.lock()) {
126                         m_sessions[pair.first] = ptr;
127                         sessions_to_revive.emplace_back(std::move(ptr));
128                     }
129                 }
130                 m_waiting_sessions.clear();
131                 break;
132             }
133         }
134         // Update persistent user metadata.
135         if (m_token_type != TokenType::Admin) {
136             SyncManager::shared().perform_metadata_update([=](const auto& manager) {
137                 auto metadata = manager.get_or_make_user_metadata(m_identity, m_server_url);
138                 metadata->set_user_token(token);
139             });
140         }
141     }
142     // (Re)activate all pending sessions.
143     // Note that we do this after releasing the lock, since the session may
144     // need to access protected User state in the process of binding itself.
145     for (auto& session : sessions_to_revive) {
146         session->revive_if_needed();
147     }
148 }
149
150 void SyncUser::log_out()
151 {
152     if (m_token_type == TokenType::Admin) {
153         // Admin-token users cannot be logged out.
154         return;
155     }
156     std::lock_guard<std::mutex> lock(m_mutex);
157     if (m_state == State::LoggedOut) {
158         return;
159     }
160     m_state = State::LoggedOut;
161     // Move all active sessions into the waiting sessions pool. If the user is
162     // logged back in, they will automatically be reactivated.
163     for (auto& pair : m_sessions) {
164         if (auto ptr = pair.second.lock()) {
165             ptr->log_out();
166             m_waiting_sessions[pair.first] = ptr;
167         }
168     }
169     m_sessions.clear();
170     // Deactivate the sessions for the management and admin Realms.
171     if (auto session = m_management_session.lock())
172         session->log_out();
173
174     if (auto session = m_permission_session.lock())
175         session->log_out();
176
177     // Mark the user as 'dead' in the persisted metadata Realm.
178     SyncManager::shared().perform_metadata_update([=](const auto& manager) {
179         auto metadata = manager.get_or_make_user_metadata(m_identity, m_server_url, false);
180         if (metadata)
181             metadata->mark_for_removal();
182     });
183 }
184
185 void SyncUser::set_is_admin(bool is_admin)
186 {
187     if (m_token_type == TokenType::Admin) {
188         return;
189     }
190     m_is_admin = is_admin;
191     SyncManager::shared().perform_metadata_update([=](const auto& manager) {
192         auto metadata = manager.get_or_make_user_metadata(m_identity, m_server_url);
193         metadata->set_is_admin(is_admin);
194     });
195 }
196
197 void SyncUser::invalidate()
198 {
199     std::lock_guard<std::mutex> lock(m_mutex);
200     m_state = State::Error;
201 }
202
203 std::string SyncUser::refresh_token() const
204 {
205     std::lock_guard<std::mutex> lock(m_mutex);
206     return m_refresh_token;
207 }
208
209 SyncUser::State SyncUser::state() const
210 {
211     std::lock_guard<std::mutex> lock(m_mutex);
212     return m_state;
213 }
214
215 void SyncUser::register_session(std::shared_ptr<SyncSession> session)
216 {
217     const std::string& path = session->path();
218     std::unique_lock<std::mutex> lock(m_mutex);
219     switch (m_state) {
220         case State::Active:
221             // Immediately ask the session to come online.
222             m_sessions[path] = session;
223             lock.unlock();
224             session->revive_if_needed();
225             break;
226         case State::LoggedOut:
227             m_waiting_sessions[path] = session;
228             break;
229         case State::Error:
230             break;
231     }
232 }
233
234 void SyncUser::set_binding_context_factory(SyncUserContextFactory factory)
235 {
236     std::lock_guard<std::mutex> lock(s_binding_context_factory_mutex);
237     s_binding_context_factory = std::move(factory);
238 }
239
240 void SyncUser::register_management_session(const std::string& path)
241 {
242     std::lock_guard<std::mutex> lock(m_mutex);
243     if (m_management_session.lock() || m_state == State::Error)
244         return;
245
246     m_management_session = SyncManager::shared().get_existing_session(path);
247 }
248
249 void SyncUser::register_permission_session(const std::string& path)
250 {
251     std::lock_guard<std::mutex> lock(m_mutex);
252     if (m_permission_session.lock() || m_state == State::Error)
253         return;
254
255     m_permission_session = SyncManager::shared().get_existing_session(path);
256 }
257
258 }
259
260 namespace std {
261 size_t hash<realm::SyncUserIdentifier>::operator()(const realm::SyncUserIdentifier& k) const
262 {
263     return ((hash<string>()(k.user_id) ^ (hash<string>()(k.auth_server_url) << 1)) >> 1);
264 }
265 }