added iOS source code
[wl-app.git] / iOS / Pods / Realm / Realm / ObjectStore / src / sync / sync_user.cpp
diff --git a/iOS/Pods/Realm/Realm/ObjectStore/src/sync/sync_user.cpp b/iOS/Pods/Realm/Realm/ObjectStore/src/sync/sync_user.cpp
new file mode 100644 (file)
index 0000000..1adf8b1
--- /dev/null
@@ -0,0 +1,265 @@
+////////////////////////////////////////////////////////////////////////////
+//
+// 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.
+//
+////////////////////////////////////////////////////////////////////////////
+
+#include "sync/sync_user.hpp"
+
+#include "sync/impl/sync_metadata.hpp"
+#include "sync/sync_manager.hpp"
+#include "sync/sync_session.hpp"
+
+namespace realm {
+
+SyncUserContextFactory SyncUser::s_binding_context_factory;
+std::mutex SyncUser::s_binding_context_factory_mutex;
+
+SyncUser::SyncUser(std::string refresh_token,
+                   std::string identity,
+                   util::Optional<std::string> server_url,
+                   util::Optional<std::string> local_identity,
+                   TokenType token_type)
+: m_state(State::Active)
+, m_server_url(server_url.value_or(""))
+, m_token_type(token_type)
+, m_refresh_token(std::move(refresh_token))
+, m_identity(std::move(identity))
+{
+    {
+        std::lock_guard<std::mutex> lock(s_binding_context_factory_mutex);
+        if (s_binding_context_factory) {
+            m_binding_context = s_binding_context_factory();
+        }
+    }
+    if (token_type == TokenType::Normal) {
+        REALM_ASSERT(m_server_url.length() > 0);
+        bool updated = SyncManager::shared().perform_metadata_update([=](const auto& manager) {
+            auto metadata = manager.get_or_make_user_metadata(m_identity, m_server_url);
+            metadata->set_user_token(m_refresh_token);
+            m_is_admin = metadata->is_admin();
+            m_local_identity = metadata->local_uuid();
+        });
+        if (!updated)
+            m_local_identity = m_identity;
+    } else {
+        // Admin token users. The local identity serves as the directory path.
+        REALM_ASSERT(local_identity);
+        m_local_identity = std::move(*local_identity);
+    }
+}
+
+std::vector<std::shared_ptr<SyncSession>> SyncUser::all_sessions()
+{
+    std::lock_guard<std::mutex> lock(m_mutex);
+    std::vector<std::shared_ptr<SyncSession>> sessions;
+    if (m_state == State::Error) {
+        return sessions;
+    }
+    for (auto it = m_sessions.begin(); it != m_sessions.end();) {
+        if (auto ptr_to_session = it->second.lock()) {
+            if (!ptr_to_session->is_in_error_state()) {
+                sessions.emplace_back(std::move(ptr_to_session));
+                it++;
+                continue;
+            }
+        }
+        // This session is bad, destroy it.
+        it = m_sessions.erase(it);
+    }
+    return sessions;
+}
+
+std::shared_ptr<SyncSession> SyncUser::session_for_on_disk_path(const std::string& path)
+{
+    std::lock_guard<std::mutex> lock(m_mutex);
+    if (m_state == State::Error) {
+        return nullptr;
+    }
+    auto it = m_sessions.find(path);
+    if (it == m_sessions.end()) {
+        return nullptr;
+    }
+    auto locked = it->second.lock();
+    if (!locked) {
+        // Remove the session from the map, because it has fatally errored out or the entry is invalid.
+        m_sessions.erase(it);
+    }
+    return locked;
+}
+
+void SyncUser::update_refresh_token(std::string token)
+{
+    std::vector<std::shared_ptr<SyncSession>> sessions_to_revive;
+    {
+        std::unique_lock<std::mutex> lock(m_mutex);
+        if (auto session = m_management_session.lock())
+            sessions_to_revive.emplace_back(std::move(session));
+
+        if (auto session = m_permission_session.lock())
+            sessions_to_revive.emplace_back(std::move(session));
+
+        switch (m_state) {
+            case State::Error:
+                return;
+            case State::Active:
+                m_refresh_token = token;
+                break;
+            case State::LoggedOut: {
+                sessions_to_revive.reserve(m_waiting_sessions.size());
+                m_refresh_token = token;
+                m_state = State::Active;
+                for (auto& pair : m_waiting_sessions) {
+                    if (auto ptr = pair.second.lock()) {
+                        m_sessions[pair.first] = ptr;
+                        sessions_to_revive.emplace_back(std::move(ptr));
+                    }
+                }
+                m_waiting_sessions.clear();
+                break;
+            }
+        }
+        // Update persistent user metadata.
+        if (m_token_type != TokenType::Admin) {
+            SyncManager::shared().perform_metadata_update([=](const auto& manager) {
+                auto metadata = manager.get_or_make_user_metadata(m_identity, m_server_url);
+                metadata->set_user_token(token);
+            });
+        }
+    }
+    // (Re)activate all pending sessions.
+    // Note that we do this after releasing the lock, since the session may
+    // need to access protected User state in the process of binding itself.
+    for (auto& session : sessions_to_revive) {
+        session->revive_if_needed();
+    }
+}
+
+void SyncUser::log_out()
+{
+    if (m_token_type == TokenType::Admin) {
+        // Admin-token users cannot be logged out.
+        return;
+    }
+    std::lock_guard<std::mutex> lock(m_mutex);
+    if (m_state == State::LoggedOut) {
+        return;
+    }
+    m_state = State::LoggedOut;
+    // Move all active sessions into the waiting sessions pool. If the user is
+    // logged back in, they will automatically be reactivated.
+    for (auto& pair : m_sessions) {
+        if (auto ptr = pair.second.lock()) {
+            ptr->log_out();
+            m_waiting_sessions[pair.first] = ptr;
+        }
+    }
+    m_sessions.clear();
+    // Deactivate the sessions for the management and admin Realms.
+    if (auto session = m_management_session.lock())
+        session->log_out();
+
+    if (auto session = m_permission_session.lock())
+        session->log_out();
+
+    // Mark the user as 'dead' in the persisted metadata Realm.
+    SyncManager::shared().perform_metadata_update([=](const auto& manager) {
+        auto metadata = manager.get_or_make_user_metadata(m_identity, m_server_url, false);
+        if (metadata)
+            metadata->mark_for_removal();
+    });
+}
+
+void SyncUser::set_is_admin(bool is_admin)
+{
+    if (m_token_type == TokenType::Admin) {
+        return;
+    }
+    m_is_admin = is_admin;
+    SyncManager::shared().perform_metadata_update([=](const auto& manager) {
+        auto metadata = manager.get_or_make_user_metadata(m_identity, m_server_url);
+        metadata->set_is_admin(is_admin);
+    });
+}
+
+void SyncUser::invalidate()
+{
+    std::lock_guard<std::mutex> lock(m_mutex);
+    m_state = State::Error;
+}
+
+std::string SyncUser::refresh_token() const
+{
+    std::lock_guard<std::mutex> lock(m_mutex);
+    return m_refresh_token;
+}
+
+SyncUser::State SyncUser::state() const
+{
+    std::lock_guard<std::mutex> lock(m_mutex);
+    return m_state;
+}
+
+void SyncUser::register_session(std::shared_ptr<SyncSession> session)
+{
+    const std::string& path = session->path();
+    std::unique_lock<std::mutex> lock(m_mutex);
+    switch (m_state) {
+        case State::Active:
+            // Immediately ask the session to come online.
+            m_sessions[path] = session;
+            lock.unlock();
+            session->revive_if_needed();
+            break;
+        case State::LoggedOut:
+            m_waiting_sessions[path] = session;
+            break;
+        case State::Error:
+            break;
+    }
+}
+
+void SyncUser::set_binding_context_factory(SyncUserContextFactory factory)
+{
+    std::lock_guard<std::mutex> lock(s_binding_context_factory_mutex);
+    s_binding_context_factory = std::move(factory);
+}
+
+void SyncUser::register_management_session(const std::string& path)
+{
+    std::lock_guard<std::mutex> lock(m_mutex);
+    if (m_management_session.lock() || m_state == State::Error)
+        return;
+
+    m_management_session = SyncManager::shared().get_existing_session(path);
+}
+
+void SyncUser::register_permission_session(const std::string& path)
+{
+    std::lock_guard<std::mutex> lock(m_mutex);
+    if (m_permission_session.lock() || m_state == State::Error)
+        return;
+
+    m_permission_session = SyncManager::shared().get_existing_session(path);
+}
+
+}
+
+namespace std {
+size_t hash<realm::SyncUserIdentifier>::operator()(const realm::SyncUserIdentifier& k) const
+{
+    return ((hash<string>()(k.user_id) ^ (hash<string>()(k.auth_server_url) << 1)) >> 1);
+}
+}