void close(std::unique_lock<std::mutex>& lock, SyncSession& session) const override { switch (session.m_config.stop_policy) { case SyncSessionStopPolicy::Immediately: session.advance_state(lock, inactive); break; case SyncSessionStopPolicy::LiveIndefinitely: // Don't do anything; session lives forever. break; case SyncSessionStopPolicy::AfterChangesUploaded: // Wait for all pending changes to upload. session.advance_state(lock, dying); break; } }
bool revive_if_needed(std::unique_lock<std::mutex>& lock, SyncSession& session) const override { // Revive. session.create_sync_session(); session.advance_state(lock, waiting_for_access_token); return true; }
void refresh_access_token(std::unique_lock<std::mutex>& lock, SyncSession& session, std::string access_token, const util::Optional<std::string>& server_url) const override { // Since the sync session was previously unbound, it's safe to do this from the // calling thread. if (!session.m_server_url) { session.m_server_url = server_url; } if (session.m_session_has_been_bound) { session.m_session->refresh(std::move(access_token)); } else { session.m_session->bind(*session.m_server_url, std::move(access_token)); session.m_session_has_been_bound = true; } if (session.m_deferred_commit_notification) { session.m_session->nonsync_transact_notify(*session.m_deferred_commit_notification); session.m_deferred_commit_notification = util::none; } session.advance_state(lock, active); if (session.m_deferred_close) { session.m_deferred_close = false; session.m_state->close(lock, session); } }
void bind_with_admin_token(std::unique_lock<std::mutex>& lock, SyncSession& session, const std::string& admin_token, const std::string& server_url) const override { session.create_sync_session(); session.advance_state(lock, waiting_for_access_token); session.m_state->refresh_access_token(lock, session, admin_token, server_url); }
bool access_token_expired(std::unique_lock<std::mutex>& lock, SyncSession& session) const override { session.advance_state(lock, waiting_for_access_token); std::shared_ptr<SyncSession> session_ptr = session.shared_from_this(); lock.unlock(); session.m_config.bind_session_handler(session_ptr->m_realm_path, session_ptr->m_config, session_ptr); return false; }
void enter_state(std::unique_lock<std::mutex>&, SyncSession& session) const override { size_t current_death_count = ++session.m_death_count; session.m_session->async_wait_for_upload_completion([session=&session, current_death_count](std::error_code) { std::unique_lock<std::mutex> lock(session->m_state_mutex); if (session->m_state == &State::dying && session->m_death_count == current_death_count) { session->advance_state(lock, inactive); } }); }
void enter_state(std::unique_lock<std::mutex>& lock, SyncSession& session) const override { // If we have no session, we cannot possibly upload anything. if (!session.m_session) { session.advance_state(lock, inactive); return; } size_t current_death_count = ++session.m_death_count; std::weak_ptr<SyncSession> weak_session = session.shared_from_this(); session.m_session->async_wait_for_upload_completion([weak_session, current_death_count](std::error_code) { if (auto session = weak_session.lock()) { std::unique_lock<std::mutex> lock(session->m_state_mutex); if (session->m_state == &State::dying && session->m_death_count == current_death_count) { session->advance_state(lock, inactive); } } }); }
bool handle_error(std::unique_lock<std::mutex>& lock, SyncSession& session, const SyncError& error) const override { if (error.is_fatal) { session.advance_state(lock, inactive); } // If the error isn't fatal, don't change state, but don't // allow it to be reported either. // FIXME: What if the token expires while a session is dying? // Should we allow the token to be refreshed so that changes // can finish being uploaded? return true; }
void close(std::unique_lock<std::mutex>& lock, SyncSession& session) const override { switch (session.m_config.stop_policy) { case SyncSessionStopPolicy::Immediately: // Immediately kill the session. session.advance_state(lock, inactive); break; case SyncSessionStopPolicy::LiveIndefinitely: case SyncSessionStopPolicy::AfterChangesUploaded: // Defer handling closing the session until after the login response succeeds. session.m_deferred_close = true; break; } }
void enter_state(std::unique_lock<std::mutex>&, SyncSession& session) const override { ++session.m_pending_upload_threads; std::thread([session=&session] { std::unique_lock<std::mutex> lock(session->m_state_mutex); if (session->m_pending_upload_threads != 1) { --session->m_pending_upload_threads; return; } if (session->m_state != &State::dying) { // The session was revived. Don't kill it. --session->m_pending_upload_threads; return; } session->m_session->wait_for_upload_complete_or_client_stopped(); --session->m_pending_upload_threads; session->advance_state(lock, inactive); }).detach(); }
void refresh_access_token(std::unique_lock<std::mutex>& lock, SyncSession& session, std::string access_token, const util::Optional<std::string>& server_url) const override { session.create_sync_session(); // Since the sync session was previously unbound, it's safe to do this from the // calling thread. if (!session.m_server_url) { session.m_server_url = server_url; } if (session.m_session_has_been_bound) { session.m_session->refresh(std::move(access_token)); session.m_session->cancel_reconnect_delay(); } else { session.m_session->bind(*session.m_server_url, std::move(access_token)); session.m_session_has_been_bound = true; } if (session.m_server_override) session.m_session->override_server(session.m_server_override->address, session.m_server_override->port); // Register all the pending wait-for-completion blocks. for (auto& package : session.m_completion_wait_packages) { (*session.m_session.*package.waiter)(std::move(package.callback)); } session.m_completion_wait_packages.clear(); // Handle any deferred commit notification. if (session.m_deferred_commit_notification) { session.m_session->nonsync_transact_notify(*session.m_deferred_commit_notification); session.m_deferred_commit_notification = util::none; } session.advance_state(lock, active); if (session.m_deferred_close) { session.m_state->close(lock, session); } }
void log_out(std::unique_lock<std::mutex>& lock, SyncSession& session) const override { session.advance_state(lock, inactive); }
bool revive_if_needed(std::unique_lock<std::mutex>& lock, SyncSession& session) const override { // Revive. session.advance_state(lock, active); return false; }
void close_if_connecting(std::unique_lock<std::mutex>& lock, SyncSession& session) const override { // Ignore the sync configuration's stop policy as we're not yet connected. session.advance_state(lock, inactive); }
void access_token_expired(std::unique_lock<std::mutex>& lock, SyncSession& session) const override { session.advance_state(lock, waiting_for_access_token); }