Private/WebSocketHelper.ps1
|
function New-OpWebSocket { [OutputType([System.Net.WebSockets.ClientWebSocket])] param( [Parameter(Mandatory)] [string]$Uri, [hashtable]$Headers, [int]$TimeoutSeconds = 15 ) $ws = [System.Net.WebSockets.ClientWebSocket]::new() $ws.Options.SetRequestHeader('User-Agent', "onepam-powershell/$script:ModuleVersion") if ($Headers) { foreach ($key in $Headers.Keys) { $ws.Options.SetRequestHeader($key, $Headers[$key]) } } $cts = [System.Threading.CancellationTokenSource]::new([TimeSpan]::FromSeconds($TimeoutSeconds)) try { $ws.ConnectAsync([Uri]$Uri, $cts.Token).GetAwaiter().GetResult() } catch { $ws.Dispose() throw "WebSocket connection failed: $_" } finally { $cts.Dispose() } $ws } function Send-OpWsMessage { param( [Parameter(Mandatory)] [System.Net.WebSockets.ClientWebSocket]$WebSocket, [Parameter(Mandatory)] [string]$Message, [System.Net.WebSockets.WebSocketMessageType]$MessageType = [System.Net.WebSockets.WebSocketMessageType]::Text, [int]$TimeoutSeconds = 30 ) $bytes = [System.Text.Encoding]::UTF8.GetBytes($Message) $segment = [ArraySegment[byte]]::new($bytes) $cts = [System.Threading.CancellationTokenSource]::new([TimeSpan]::FromSeconds($TimeoutSeconds)) try { $WebSocket.SendAsync($segment, $MessageType, $true, $cts.Token).GetAwaiter().GetResult() } finally { $cts.Dispose() } } function Send-OpWsBinaryMessage { param( [Parameter(Mandatory)] [System.Net.WebSockets.ClientWebSocket]$WebSocket, [Parameter(Mandatory)] [byte[]]$Data, [int]$TimeoutSeconds = 30 ) $segment = [ArraySegment[byte]]::new($Data) $cts = [System.Threading.CancellationTokenSource]::new([TimeSpan]::FromSeconds($TimeoutSeconds)) try { $WebSocket.SendAsync($segment, [System.Net.WebSockets.WebSocketMessageType]::Binary, $true, $cts.Token).GetAwaiter().GetResult() } finally { $cts.Dispose() } } $script:MaxWsMessageSize = 100 * 1024 * 1024 # 100 MB function Receive-OpWsMessage { [OutputType([PSCustomObject])] param( [Parameter(Mandatory)] [System.Net.WebSockets.ClientWebSocket]$WebSocket, [int]$BufferSize = 65536, [int]$TimeoutSeconds = 30 ) $buffer = [byte[]]::new($BufferSize) $segment = [ArraySegment[byte]]::new($buffer) $cts = [System.Threading.CancellationTokenSource]::new([TimeSpan]::FromSeconds($TimeoutSeconds)) $ms = [System.IO.MemoryStream]::new() try { do { $result = $WebSocket.ReceiveAsync($segment, $cts.Token).GetAwaiter().GetResult() if ($result.MessageType -eq [System.Net.WebSockets.WebSocketMessageType]::Close) { return [PSCustomObject]@{ MessageType = 'Close' Data = $null Text = $null } } $ms.Write($buffer, 0, $result.Count) if ($ms.Length -gt $script:MaxWsMessageSize) { throw "WebSocket message exceeds maximum size of $($script:MaxWsMessageSize / 1MB) MB." } } while (-not $result.EndOfMessage) $allBytes = $ms.ToArray() [PSCustomObject]@{ MessageType = $result.MessageType.ToString() Data = $allBytes Text = if ($result.MessageType -eq [System.Net.WebSockets.WebSocketMessageType]::Text) { [System.Text.Encoding]::UTF8.GetString($allBytes) } else { $null } } } finally { $ms.Dispose() $cts.Dispose() } } function Close-OpWebSocket { param( [Parameter(Mandatory)] [System.Net.WebSockets.ClientWebSocket]$WebSocket ) if ($WebSocket.State -eq [System.Net.WebSockets.WebSocketState]::Open) { $cts = [System.Threading.CancellationTokenSource]::new([TimeSpan]::FromSeconds(5)) try { $WebSocket.CloseAsync( [System.Net.WebSockets.WebSocketCloseStatus]::NormalClosure, 'Closing', $cts.Token ).GetAwaiter().GetResult() } catch { } finally { $cts.Dispose() } } $WebSocket.Dispose() } |