Private/Open-MyWebApiRealtimeConnection.ps1
|
function Open-MyWebApiRealtimeConnection { # Opens one explicit SignalR connection for the supplied REST session. Automatic # reconnect is intentionally disabled: the protocol's required signalr_token is # embedded in the handshake URL, so reconnecting with a stale query token would be # unsafe. Call Connect-MT*Realtime again after a disconnect to obtain a fresh token. [CmdletBinding()] param( [Parameter(Mandatory)][ValidateSet('mt4','mt5')][string] $Hub, [string] $TradePlatform, [object] $Connection ) if (-not ('MyWebApi.RealtimeSink' -as [type])) { throw 'Real-time support requires compatible SignalR client assemblies. Reinstall the packaged module or run scripts/restore-lib.sh with the supported PowerShell runtime.' } $ctx = Resolve-MyWebApiContext -Connection $Connection $baseUri = Assert-MyWebApiEndpoint -Value ([string](Get-MyWebApiContextProperty -Context $ctx -Name 'BaseUrl')) -Name 'BaseUrl' -Context $ctx $tpDefault = Get-MyWebApiContextProperty -Context $ctx -Name 'DefaultTradePlatform' $tp = if ($TradePlatform) { $TradePlatform } else { $tpDefault } if (-not $tp) { throw 'No trade platform: pass -TradePlatform or set -DefaultTradePlatform on Connect-MyWebApi.' } $token = Get-MyWebApiToken -Connection $ctx $url = "{0}/hubs/{1}/v2?tradePlatform={2}&signalr_token={3}" -f $baseUri.AbsoluteUri.TrimEnd('/'), $Hub, [uri]::EscapeDataString($tp), [uri]::EscapeDataString($token) $safeUrl = $url -replace '(?i)(signalr_token=)[^&]*', '$1<REDACTED>' try { $builder = [Microsoft.AspNetCore.SignalR.Client.HubConnectionBuilder]::new() # signalr_token is retained because the v2 server may require this protocol. # Automatic reconnect is not enabled; a fresh Connect call renews this URL/token. $null = [Microsoft.AspNetCore.SignalR.Client.HubConnectionBuilderHttpExtensions]::WithUrl($builder, $url) $connectionObject = $builder.Build() $sink = [MyWebApi.RealtimeSink]::new($connectionObject) $sink.On('OnConnectionStatus') if ($Hub -eq 'mt4') { $sink.On('OnTick') } $startTask = $sink.StartAsync() $timeout = Get-MyWebApiContextProperty -Context $ctx -Name 'RealtimeTimeoutSeconds' if ($null -eq $timeout -or [int]$timeout -lt 1) { $timeout = 30 } if (-not $startTask.Wait([Math]::Min([int]$timeout, 3600) * 1000)) { try { $sink.Dispose() } catch { Write-Verbose "Realtime cleanup failed after timeout: $($_.Exception.Message)" } throw "Timed out opening SignalR connection after $timeout second(s) ($safeUrl)." } [void]$startTask.GetAwaiter().GetResult() [pscustomobject]@{ PSTypeName = 'MyWebApi.RealtimeConnection' Hub = $Hub TradePlatform = $tp Session = $ctx Sink = $sink UrlForDiagnostics = $safeUrl } } catch { $message = $_.Exception.Message -replace '(?i)(signalr_token=)[^&\s]*', '$1<REDACTED>' throw "Failed to open SignalR connection at ${safeUrl}: $message" } } |