Invoke-MetasysGetStream.ps1

# https://www.reddit.com/r/PowerShell/comments/g8p8ya/powershell_and_rest_serversent_events_api_sse_not/

function Invoke-MetasysGetStream {
    <#
        .SYNOPSIS
            Connects to the /stream resource on a Metasys site to listen for events

        .DESCRIPTION
            Some of the operations on a Metasys site can send events to a client. For example, one can sign up for Change of Value updates for an attribute value. Then whenever that attribute changes value, the client is notified.

            To do this requires a few steps.

            - Open two powershell terminals
            - In each establish a connection using Connect-MetasysAccount
            - In the first terminal, run Invoke-MetasysGetStream. In a short time you'll receive a hello event. The data in that event will be your stream id that you use to sign up for events.
            - In the second terminal, invoke an operation that supports subscriptions. For example, read the present value of an analog object and include the METASYS-SUBSCRIBE header with the value of your stream id. In the first terminal you should receive an object.values.update event with the current value of the object.
            - In the UI or in the second terminal, change the value of the attribute you read in the previous step. Within a short period of time you should see another object.values.update event with the new value.
    #>

    param (
        # By default the event stream is just a stream of text. Use this switch to stream a collection of objects instead
        [switch]$ReturnObjects
    )

    $token = [MetasysEnvVars]::getTokenAsPlainText()

    if ($null -eq $token ) {
        Write-Error "No connection to a Metasys site exists. Please connect using Connect-MetasysAccount"
        exit
    }

    $metasysHost = [MetasysEnvVars]::getSiteHost()
    $version = [MetasysEnvVars]::getVersion()
    $Url = "https://$metasysHost/api/v$version/stream"

    $request = [System.Net.WebRequest]::CreateHttp($Url)
    $request.Headers.Add("Authorization", "Bearer $token")
    $request.AllowReadStreamBuffering = $false
    $response = $request.GetResponse()
    $stream = $response.GetResponseStream()

    $encoding = [System.Text.Encoding]::UTF8

    if ($ReturnObjects) {
        $parser = New-EventParser
    }
    while ($true) {

        [byte[]]$buffer = New-Object byte[] 2048

        $length = $Stream.Read($buffer, 0, 2048)


        $text = $encoding.GetString($buffer, 0, $length)
        # We want to remove any trailing new line since the outputing of
        # $test is going to cause another new line to be sent anyway and
        # we want to avoid duplicated newlines

        if ($text.EndsWith("`r`n")) {
            $text = $text.Substring(0, $text.Length - 2)
        }
        elseif ($text.EndsWith("`n")) {
            $text = $text.Substring(0, $text.Length - 1)
        }

        if ($ReturnObjects) {
            # Split the text into lines and feed each to our event
            # parser
            $text -split '\r?\n' | ForEach-Object { &$parser -line $_ }
        } else {
            $text
        }

    }

}


Set-Alias -Name ims -Value Invoke-MetasysGetStream
Export-ModuleMember -Alias "ims"
Export-ModuleMember -Function "Invoke-MetasysGetStream"