| 156 | } |
| 157 | |
| 158 | std::string CloudProviderBase::GetAccessToken() { |
| 159 | std::unique_lock<std::mutex> lock(m_mtx); |
| 160 | |
| 161 | if (TokenValid()) return m_tok.access; |
| 162 | if (m_tok.refresh.empty()) { |
| 163 | LOG("%s GetAccessToken: no refresh token", LogTag()); |
| 164 | if (m_authFailureCb) m_authFailureCb(AuthFailureName()); |
| 165 | return {}; |
| 166 | } |
| 167 | |
| 168 | if (m_refreshing) { |
| 169 | if (!m_refreshCv.wait_for(lock, std::chrono::seconds(30), |
| 170 | [this] { return !m_refreshing; })) { |
| 171 | LOG("%s GetAccessToken: timed out waiting for in-flight refresh", LogTag()); |
| 172 | return {}; |
| 173 | } |
| 174 | if (TokenValid()) return m_tok.access; |
| 175 | LOG("%s GetAccessToken: other thread refresh failed", LogTag()); |
| 176 | return {}; |
| 177 | } |
| 178 | |
| 179 | if (m_lastRefreshFailTime > 0 && |
| 180 | (int64_t)time(nullptr) - m_lastRefreshFailTime < REFRESH_BACKOFF_SECS) { |
| 181 | LOG("%s GetAccessToken: in backoff period", LogTag()); |
| 182 | return {}; |
| 183 | } |
| 184 | |
| 185 | m_refreshing = true; |
| 186 | lock.unlock(); |
| 187 | |
| 188 | bool ok = RefreshAccessToken(); |
| 189 | |
| 190 | lock.lock(); |
| 191 | m_refreshing = false; |
| 192 | m_refreshCv.notify_all(); |
| 193 | |
| 194 | if (!ok) return {}; |
| 195 | return m_tok.access; |
| 196 | } |
| 197 | |
| 198 | // ── Transport delegation ─────────────────────────────────────────────────── |
| 199 |
nothing calls this directly
no outgoing calls
no test coverage detected