| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
There was a problem hiding this comment.
might need help to understand the TokenSource a bit more
Sorry, something went wrong.
Manual ad-hoc helper for exercising token sources locally; the sandbox ID must be supplied via LIVEKIT_SANDBOX_ID rather than hard-coded in source. Co-authored-by: Cursor <cursoragent@cursor.com>
|
I am using the tokensource sandbox and it is working fine for me 👍 |
Sorry, something went wrong.
…/token_source_api
There was a problem hiding this comment.
lgtm with some comments, please address them.
Great work!!!
Sorry, something went wrong.
| @@ -0,0 +1,109 @@ | |||
| # Token lifecycle | |||
|
|
|||
| Succinct reference for how join credentials and in-session refresh interact in | |||
There was a problem hiding this comment.
@1egoman , could you please help review this token-lifecycle.md ?
Sorry, something went wrong.
There was a problem hiding this comment.
I actually generated this for him while I had some active LLM context around this topic, I removed it as I don't want this SDK to be an authoritative documentation source compared to docs.livekit.io.
I do think we should have some better docs around token source and lifetimes, while going through this process it felt a little disjointed and agents/frontend-focused and not just a general document for token source terms, functions, lifecycles, etc for client SDKs.
Sorry, something went wrong.
| #include "livekit/room_event_types.h" | ||
| #include "livekit/stats.h" | ||
| #include "livekit/subscription_thread_dispatcher.h" | ||
| #include "livekit/token_source.h" |
There was a problem hiding this comment.
nit, would you consider forward declare those types, and move the #include "livekit/token_source.h" to the cpp ?
One benefit for it is that it could speed up the build.
Sorry, something went wrong.
There was a problem hiding this comment.
Added
Sorry, something went wrong.
| /// @brief Base interface for token sources that provide full credentials directly. | ||
| class LIVEKIT_API TokenSourceFixed { | ||
| public: | ||
| virtual ~TokenSourceFixed(); |
There was a problem hiding this comment.
nit, just do "virtual ~TokenSourceFixed() = default" here and remove the cpp line
The same for virtual ~TokenSourceConfigurable() = default;
Sorry, something went wrong.
There was a problem hiding this comment.
Added
Sorry, something went wrong.
| return connect(details.value().server_url, details.value().participant_token, options); | ||
| } | ||
|
|
||
| bool Room::connect(TokenSourceConfigurable& token_source, const TokenRequestOptions& request_options, |
There was a problem hiding this comment.
consider a helper function like
namespace {
template <typename FetchFn>
bool connectWithTokenSource(Room& room, const RoomOptions& options, FetchFn&& fetch) {
Result<TokenSourceResponse, TokenSourceError> details =
Result<TokenSourceResponse, TokenSourceError>::failure(TokenSourceError{"token source not invoked"});
try {
details = fetch().get();
} catch (const std::exception& e) {
LK_LOG_ERROR("Room::connect failed: token source threw: {}", e.what());
return false;
} catch (...) {
LK_LOG_ERROR("Room::connect failed: token source threw unknown exception");
return false;
}
if (!details) {
LK_LOG_ERROR("Room::connect failed: token source error: {}", details.error().message);
return false;
}
const auto& value = details.value();
return room.connect(value.server_url, value.participant_token, options);
}
} // namespace
Then these two function can become:
bool Room::connect(TokenSourceFixed& token_source, const RoomOptions& options) {
return connectWithTokenSource(*this, options, [&] {
return token_source.fetch();
});
}
bool Room::connect(TokenSourceConfigurable& token_source,
const TokenRequestOptions& request_options,
const RoomOptions& options) {
return connectWithTokenSource(*this, options, [&] {
return token_source.fetch(request_options, false);
});
}
Sorry, something went wrong.
There was a problem hiding this comment.
FWIW, we opted not to do this in other sdks, and determined this was the session api's job. Relevant pull request: livekit/client-sdk-js#1677
Sorry, something went wrong.
There was a problem hiding this comment.
Added!
Sorry, something went wrong.
| : provider_(std::move(provider)) {} | ||
|
|
||
| std::future<Result<TokenSourceResponse, TokenSourceError>> CustomTokenSource::fetch(const TokenRequestOptions& options, | ||
| bool /*force_refresh*/) { |
There was a problem hiding this comment.
any idea why CustomTokenSource will skip the force_refresh ?
Sorry, something went wrong.
There was a problem hiding this comment.
This comment actually led to an API design change, see here: e39e55e
Having such an argument for a custom source would require passing that argument along to the custom implementation, which felt weird as the custom token source was just a user function that could decide anything it needed to. I have instead dropped force_refresh entirely, and opted for caching_token_source.invalidate() which matches how Swift/Android do it.
In short, this original design around forcing refresh was modeled after JS with the force_refresh. But JS actually goes for an inheritance-based approach to cacheing token sources, vs. here which is using a decorator (Swift/Android do it this way), so forcing refresh was consistent across all sub-classes and didn't have an awkward drop like this did.
It was basically a divergence in both approaches (force + decorator vs. force + inheritance), now it's more aligned to Swift/Android.
Sorry, something went wrong.
| return TokenSourceResult::success(*cached_details_); | ||
| } | ||
|
|
||
| auto result = inner_->fetch(*options_snapshot, force_refresh).get(); |
There was a problem hiding this comment.
any reason why we want to run the inner_->fetch() under the lock ?
Will it be safer to do ?
{
std::scoped_lock lock(mutex_);
if (!force_refresh && cached_details_ && cached_options_ &&
tokenRequestOptionsEqual(*cached_options_, *options_snapshot) &&
isParticipantTokenValid(cached_details_->participant_token)) {
return TokenSourceResult::success(*cached_details_);
}
}
auto result = inner_->fetch(*options_snapshot, force_refresh).get();
Sorry, something went wrong.
There was a problem hiding this comment.
Holding the mutex over the fetch is how JS and Swift do it, I'm open to your change but it would be a divergence
Sorry, something went wrong.
| auto source = std::unique_ptr<SandboxTokenSource>(new SandboxTokenSource(sandbox_id, options, base_url)); | ||
| auto resolved = resolveSandboxEndpoint(sandbox_id, std::move(options), base_url); | ||
| source->endpoint_ = | ||
| EndpointTokenSourceTestAccess::create(std::move(resolved.url), std::move(resolved.options), std::move(transport)); |
There was a problem hiding this comment.
isn't the endpoint_ created in line 210 already ? any reason why it needs to be re-created ?
Sorry, something went wrong.
There was a problem hiding this comment.
Great catch, this slipped through. Now have a private constructor that accepts an already made endpoint so both the public and test access versions can avoid recreation
Sorry, something went wrong.
| } | ||
|
|
||
| const std::wstring host(components.lpszHostName, components.dwHostNameLength); | ||
| const std::wstring path(components.lpszUrlPath, components.dwUrlPathLength); |
There was a problem hiding this comment.
question, does path need to include lpszExtraInfo ? like when lpszExtraInfoLength > 0 ?
Sorry, something went wrong.
There was a problem hiding this comment.
Addressed
Sorry, something went wrong.
…/token_source_api
There was a problem hiding this comment.
Generally looks good to me, and I think matches the interfaces on other sdks pretty well!
Sorry, something went wrong.
…/token_source_api
…/token_source_api
…/token_source_api
| Back | FazBrowse Home | New Git URL |
Summary
Server Token Refresh
LiveKit server token refresh existed before this feature, but this branch now adds support for the FFI event onTokenRefreshed.
New Dependencies
Testing
Validated through a combination of unit, integration, and standalone binary tester program against a LiveKit Cloud agent with a live token server.
Token Server Action
Integration tests now test against a basic token server implementation run in GitHub actions live (skipped locally).
Sandbox Token
Verified locally by connecting to a LiveKit cloud instance:
auto sandbox_token = livekit::SandboxTokenSource::create("<omitted but valid>");And results printed below: