Classes/GChatConnection.ps1
class GChatConnection : Connection { [string]$ConfigName [String]$SheetId [string]$SheetName [int]$PollingFrequency [bool]$Connected [object]$ReceiveJob = $null GChatConnection([string]$ConfigName,[string]$SheetId,[string]$SheetName,[int]$PollingFrequency) { if ((Show-PSGSuiteConfig).ConfigName -ne $ConfigName) { Switch-PSGSuiteConfig -ConfigName $ConfigName } $this.ConfigName = $ConfigName $this.SheetId = $SheetId $this.SheetName = $SheetName $this.PollingFrequency = $PollingFrequency } # Connect to GChat and start receiving messages [void]Connect() { if ($null -eq $this.ReceiveJob -or $this.ReceiveJob.State -ne 'Running') { $this.LogDebug('Connecting to Google Sheet MQ') #$this.TestConnect() $this.StartReceiveJob() } else { $this.LogDebug([LogSeverity]::Warning, 'Receive job is already running') } } # Log in to GChat with the bot token and get a URL to connect to via websockets [void]TestConnect() { try { if (Import-GSSheet -SpreadsheetId $this.SheetId -SheetName $this.SheetName -Range "A1" -ErrorAction Stop) { $this.LogVerbose("Connection to Sheet validated!") } else { $this.LogInfo([LogSeverity]::Error, 'Failed to connect to Sheet!') } } catch { $this.LogInfo([LogSeverity]::Error, 'Failed to connect to Sheet!') throw $_ } } # Setup the websocket receive job [void]StartReceiveJob() { $recv = { [CmdLetBinding()] Param ( [parameter(Mandatory = $true,Position = 0)] $ConfigName, [parameter(Mandatory = $true,Position = 1)] $SheetId, [parameter(Mandatory = $true,Position = 2)] $SheetName, [parameter(Mandatory = $true,Position = 3)] $PollingFrequency ) if (!(Get-Module PSGSuite)) { Import-Module PSGSuite -MinimumVersion "2.13.0" -Verbose:$false -Force } if ((Show-PSGSuiteConfig).ConfigName -ne $ConfigName) { Switch-PSGSuiteConfig -ConfigName $ConfigName } # Connect to Google Sheet MQ Write-Warning "[GChatBackend:ReceiveJob] Connecting to Google Sheet MQ at [$($SheetId)::$($SheetName)]" # Receive messages and put on output stream so the backend can read them while ($true) { $completeCount = 0 Write-Verbose "[GChatBackend:ReceiveJob] Polling Sheet MQ for new messages" try { if ($fullSheet = Import-GSSheet -SpreadsheetId $SheetId -SheetName $SheetName -ErrorAction Stop) { $fullSheetCount = if ($fullSheet.Id[0] -eq 'Event') { 0 } elseif (!$fullSheet.Count) { 1 } else { $fullSheet.Count } Write-Verbose "[GChatBackend:ReceiveJob] Received [$fullSheetCount] new messages" for ($i = 0; $i -lt $fullSheetCount; $i++) { if ($fullSheet[$i].Acked -eq "No") { $message = $fullSheet[$i] $msg = ConvertFrom-Json -InputObject $message.Event Write-Verbose "Message ID [$($message.Id)] received from [$($msg.user.email)] with text [$($msg.message.argumentText)]. Sending serialized event JSON to Output stream" ConvertTo-Json -InputObject $message -Depth 20 $rowId = $i + 2 - $completeCount Export-GSSheet -SpreadsheetId $SheetId -Value "Yes" -SheetName $SheetName -Range "C$($rowId)" -ErrorAction Stop | Out-Null $completeCount++ } } } } catch { Write-Warning $_ } finally { $sleepParams = @{} if ($PollingFrequency -ge 1000) { $sleepParams['Milliseconds'] = $PollingFrequency } else { $sleepParams['Seconds'] = $PollingFrequency } Start-Sleep @sleepParams } } } try { $this.LogVerbose("Starting Google Sheet MQ receive job [ConfigName:$($this.ConfigName) | SheetId:$($this.SheetId) | SheetName:$($this.SheetName) | PollingFrequency:$($this.PollingFrequency)]") $this.ReceiveJob = Start-Job -Name ReceiveSheetMessages -ScriptBlock $recv -ArgumentList $this.ConfigName,$this.SheetId,$this.SheetName,$this.PollingFrequency -ErrorAction Stop -Verbose $this.Connected = $true $this.Status = [ConnectionStatus]::Connected $this.LogInfo("Started Google Sheet MQ receive job [$($this.ReceiveJob.Id)]") } catch { $this.LogInfo([LogSeverity]::Error, "$($_.Exception.Message)", [ExceptionFormatter]::Summarize($_)) } } # Read all available data from the job [string]ReadReceiveJob() { # Read stream info from the job so we can log them $infoStream = $this.ReceiveJob.ChildJobs[0].Information.ReadAll() $warningStream = $this.ReceiveJob.ChildJobs[0].Warning.ReadAll() $errStream = $this.ReceiveJob.ChildJobs[0].Error.ReadAll() $verboseStream = $this.ReceiveJob.ChildJobs[0].Verbose.ReadAll() $debugStream = $this.ReceiveJob.ChildJobs[0].Debug.ReadAll() foreach ($item in $infoStream) { $this.LogInfo($item.ToString()) } foreach ($item in $warningStream) { $this.LogInfo([LogSeverity]::Warning, $item.ToString()) } foreach ($item in $errStream) { $this.LogInfo([LogSeverity]::Error, $item.ToString()) } foreach ($item in $verboseStream) { $this.LogVerbose($item.ToString()) } foreach ($item in $debugStream) { $this.LogVerbose($item.ToString()) } # The receive job stopped for some reason. Reestablish the connection if the job isn't running if ($this.ReceiveJob.State -ne 'Running') { $this.LogInfo([LogSeverity]::Warning, "Receive job state is [$($this.ReceiveJob.State)]. Attempting to reconnect...") Start-Sleep -Seconds 5 $this.Connect() } if ($this.ReceiveJob.HasMoreData) { return $this.ReceiveJob.ChildJobs[0].Output.ReadAll() } else { return $null } } # Stop the receive job [void]Disconnect() { $this.LogInfo('Closing connection') if ($this.ReceiveJob) { $this.LogInfo("Stopping receive job [$($this.ReceiveJob.Id)]") $this.ReceiveJob | Stop-Job -Confirm:$false -PassThru | Remove-Job -Force -ErrorAction SilentlyContinue } $this.Connected = $false $this.Status = [ConnectionStatus]::Disconnected } } |