33using System . Linq ;
44using System . Net . Http ;
55using System . Threading . Tasks ;
6+ using LiveKit . Internal . Threading ;
67using Newtonsoft . Json ;
78
89namespace LiveKit
@@ -21,7 +22,7 @@ public interface ITokenSource
2122 /// </summary>
2223 public interface ITokenSourceFixed : ITokenSource
2324 {
24- public Task < ConnectionDetails > FetchConnectionDetails ( ) ;
25+ public TaskYieldInstruction < ConnectionDetails > FetchConnectionDetails ( ) ;
2526 }
2627
2728 /// <summary>
@@ -30,7 +31,7 @@ public interface ITokenSourceFixed : ITokenSource
3031 /// </summary>
3132 public interface ITokenSourceConfigurable : ITokenSource
3233 {
33- public Task < ConnectionDetails > FetchConnectionDetails ( TokenSourceFetchOptions options ) ;
34+ public TaskYieldInstruction < ConnectionDetails > FetchConnectionDetails ( TokenSourceFetchOptions options ) ;
3435 }
3536
3637 /// <summary>
@@ -48,10 +49,10 @@ public TokenSourceLiteral(string serverUrl, string participantToken)
4849 _participantToken = participantToken ;
4950 }
5051
51- public Task < ConnectionDetails > FetchConnectionDetails ( )
52+ public TaskYieldInstruction < ConnectionDetails > FetchConnectionDetails ( )
5253 {
5354 var result = new ConnectionDetails { ServerUrl = _serverUrl , ParticipantToken = _participantToken } ;
54- return Task . FromResult ( result ) ;
55+ return new TaskYieldInstruction < ConnectionDetails > ( Task . FromResult ( result ) ) ;
5556 }
5657 }
5758
@@ -70,9 +71,22 @@ public TokenSourceCustom(CustomTokenFunction customTokenFunction)
7071 _customTokenFunction = customTokenFunction ;
7172 }
7273
73- public Task < ConnectionDetails > FetchConnectionDetails ( )
74+ public TaskYieldInstruction < ConnectionDetails > FetchConnectionDetails ( )
7475 {
75- return _customTokenFunction ( ) ;
76+ // Route a synchronous throw (or a null return) from the user's function through the
77+ // instruction's IsError/Exception, so callers never have to guard the call itself.
78+ Task < ConnectionDetails > task ;
79+ try
80+ {
81+ task = _customTokenFunction ( )
82+ ?? Task . FromException < ConnectionDetails > (
83+ new InvalidOperationException ( "Custom token function returned a null task" ) ) ;
84+ }
85+ catch ( Exception e )
86+ {
87+ task = Task . FromException < ConnectionDetails > ( e ) ;
88+ }
89+ return new TaskYieldInstruction < ConnectionDetails > ( task ) ;
7690 }
7791 }
7892
@@ -94,7 +108,14 @@ public TokenSourceEndpoint(string endpointUrl, IEnumerable<StringPair> headers)
94108 _headers = headers ;
95109 }
96110
97- public async Task < ConnectionDetails > FetchConnectionDetails ( TokenSourceFetchOptions options )
111+ public TaskYieldInstruction < ConnectionDetails > FetchConnectionDetails ( TokenSourceFetchOptions options )
112+ {
113+ // Async methods can't return the (non-awaitable) instruction directly, so the actual
114+ // request lives in the helper below; the returned task carries any synchronous throw.
115+ return new TaskYieldInstruction < ConnectionDetails > ( FetchConnectionDetailsAsync ( options ) ) ;
116+ }
117+
118+ private async Task < ConnectionDetails > FetchConnectionDetailsAsync ( TokenSourceFetchOptions options )
98119 {
99120 var requestBody = BuildRequest ( options ) ;
100121 var jsonBody = JsonConvert . SerializeObject ( requestBody ) ;
0 commit comments