diff --git a/sm-monitor.ps1 b/sm-monitor.ps1 index dc840b6..9bda09b 100644 --- a/sm-monitor.ps1 +++ b/sm-monitor.ps1 @@ -1,7 +1,7 @@ #Requires -Version 7.0 <# ----------------------------------------------------------------------------------------------- <#PSScriptInfo -.VERSION 4.01 +.VERSION 4.03 .GUID 98d4b6b6-00e1-4632-a836-33767fe196cd .AUTHOR .PROJECTURI https://github.com/xeliuqa/SM-Monitor @@ -15,39 +15,48 @@ With Thanks To: == S A K K I == Stizerg == PlainLazy == Shanyaa == Miguell Get grpcurl here: https://github.com/fullstorydev/grpcurl/releases -------------------------------------------------------------------------------------------- #> -$version = "4.01" +$version = "4.03" $host.ui.RawUI.WindowTitle = $MyInvocation.MyCommand.Name - -# Import Configs -. ".\sm-configs.ps1" - -# Import NodeList -$nodeListFile = ".\sm-nodeList.txt" -if (Test-Path $nodeListFile) { - $nodeListContent = Get-Content $nodeListFile - $nodeList = @() - foreach ($line in $nodeListContent) { - if ($line.Trim() -ne "" -and $line[0] -ne "#") { - $nodeInfo = $line -split "," - $node = @{ - name = $nodeInfo[0].Trim() - host = if ($nodeInfo.Count -ge 2) { $nodeInfo[1].Trim() } else { "localhost" } - port = if ($nodeInfo.Count -ge 3 -and [int32]::TryParse($nodeInfo[2].Trim(), [ref]$null)) { [int]$nodeInfo[2].Trim() } else { 9092 } - port2 = if ($nodeInfo.Count -ge 4 -and [int32]::TryParse($nodeInfo[3].Trim(), [ref]$null)) { [int]$nodeInfo[3].Trim() } else { 9093 } - port3 = if ($nodeInfo.Count -ge 5 -and [int32]::TryParse($nodeInfo[4].Trim(), [ref]$null)) { [int]$nodeInfo[4].Trim() } else { 9094 } - su = if ($nodeInfo.Count -ge 6 -and [int32]::TryParse($nodeInfo[5].Trim(), [ref]$null)) { [int]$nodeInfo[5].Trim() } else { 0 } - } - $nodeList += $node + +function main { + # Import Configs + $settingsFile = ".\sm-configs.ps1" + if (Test-Path $settingsFile) { + . $settingsFile + } + else { + Write-Host "Error: sm-configs.ps1 not found." -ForegroundColor Red + Write-Host "Press any key to continue ..." + $null = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") + exit + } + # Import NodeList + $nodeListFile = ".\sm-nodeList.txt" + if (Test-Path $nodeListFile) { + $nodeListContent = Get-Content $nodeListFile + $nodeList = @() + foreach ($line in $nodeListContent) { + if ($line.Trim() -ne "" -and $line[0] -ne "#") { + $nodeInfo = $line -split "," + $node = @{ + name = $nodeInfo[0].Trim() + host = if ($nodeInfo.Count -ge 2) { $nodeInfo[1].Trim() } else { "localhost" } + port = if ($nodeInfo.Count -ge 3 -and [int32]::TryParse($nodeInfo[2].Trim(), [ref]$null)) { [int]$nodeInfo[2].Trim() } else { 9092 } + port2 = if ($nodeInfo.Count -ge 4 -and [int32]::TryParse($nodeInfo[3].Trim(), [ref]$null)) { [int]$nodeInfo[3].Trim() } else { 9093 } + port3 = if ($nodeInfo.Count -ge 5 -and [int32]::TryParse($nodeInfo[4].Trim(), [ref]$null)) { [int]$nodeInfo[4].Trim() } else { 9094 } + su = if ($nodeInfo.Count -ge 6 -and [int32]::TryParse($nodeInfo[5].Trim(), [ref]$null)) { [int]$nodeInfo[5].Trim() } else { 0 } + } + $nodeList += $node + } } } -} -else { - Write-Host "Error: sm-nodeList.txt not found." -ForegroundColor Red - Write-Host "Press any key to continue ..." - $null = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") -} - -function main { + else { + Write-Host "Error: sm-nodeList.txt not found." -ForegroundColor Red + Write-Host "Press any key to continue ..." + $null = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") + exit + } + $syncNodes = [System.Collections.Hashtable]::Synchronized(@{}) [System.Console]::CursorVisible = $false [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding @@ -56,34 +65,35 @@ function main { $OneHourTimer = [System.Diagnostics.Stopwatch]::StartNew() $tableRefreshTimer = [System.Diagnostics.Stopwatch]::StartNew() $stage = 2 # 0 to ignore stages or 2 for initial stages - + printSMMonitorLogo - + $gitVersion = Get-gitNewVersion $gitNewMonitorVersion = Get-gitNewMonitorVersion - + $malfeasanceStream = $null + if (Test-Path ".\RewardsTrackApp.tmp") { Clear-Content ".\RewardsTrackApp.tmp" } - + $nodeList | ForEach-Object { $syncNodes[$_.name] = $_ } - - while ($true) { + while ($true) { + $object = @() $epoch = $null $totalLayers = $null $rewardsTrackApp = @() - + $syncNodes.Values | ForEach-Object -ThrottleLimit 16 -Parallel { $node = $_ $grpcurl = $using:grpcurl $syncNodesCopy = $using:syncNodes - + if (($using:stage -ne 1) -and ($using:stage -ne 4) -and ($node.port -ne 0) -and ($node.port2 -ne 0)) { $status = $null $status = ((Invoke-Expression ("$($grpcurl) --plaintext -max-time 10 $($node.host):$($node.port) spacemesh.v1.NodeService.Status")) | ConvertFrom-Json).status 2>$null - + if ($status) { $node.online = "True" $node.status = "Online" @@ -91,16 +101,6 @@ function main { $node.syncedLayer = $status.syncedLayer.number $node.topLayer = $status.topLayer.number $node.verifiedLayer = $status.verifiedLayer.number - $publicKeys = ((Invoke-Expression ("$($grpcurl) --plaintext -max-time 5 $($node.host):$($node.port2) spacemesh.v1.SmesherService.SmesherIDs")) | ConvertFrom-Json) 2>$null - if ($publicKeys.publicKeys.Count -eq 1) { - $publicKey = $publicKeys.publicKeys[0] - } - if (!$publicKeys) { #to be removed in 2 weeks - $publicKey = ((Invoke-Expression ("$($grpcurl) --plaintext -max-time 5 $($node.host):$($node.port2) spacemesh.v1.SmesherService.SmesherID")) | ConvertFrom-Json).publicKey 2>$null - } - if ($publicKey) { - $node.publicKey = $publicKey - } if ($status.isSynced) { $node.synced = "True" $node.emailsent = "" @@ -122,18 +122,18 @@ function main { $node.ban = $null } } - + if ($node.online -and ($using:stage -ne 2) -and ($using:stage -ne 4) -and ($node.port -ne 0) -and ($node.port2 -ne 0)) { - + $node.epoch = ((Invoke-Expression ("$($grpcurl) --plaintext -max-time 5 $($node.host):$($node.port) spacemesh.v1.MeshService.CurrentEpoch")) | ConvertFrom-Json).epochnum 2>$null - + $version = $null $version = ((Invoke-Expression ("$($grpcurl) --plaintext -max-time 5 $($node.host):$($node.port) spacemesh.v1.NodeService.Version")) | ConvertFrom-Json).versionString.value 2>$null - + if ($null -ne $version) { $node.version = $version } - + $eventstream = (Invoke-Expression ("$($grpcurl) --plaintext -max-time 5 $($node.host):$($node.port2) spacemesh.v1.AdminService.EventsStream")) 2>$null if ($eventstream) { $eventstream = $eventstream -split "`n" | Where-Object { $_ } @@ -153,10 +153,10 @@ function main { $eligibilities += $json.eligibilities } if ($json.atxPublished) { - $atxPublished = $json.atxPublished + $atxPublished += $json.atxPublished } if ($json.poetWaitProof) { - $poetWaitProof = $json.poetWaitProof + $poetWaitProof += $json.poetWaitProof } } Catch { @@ -166,32 +166,34 @@ function main { } } } - + $layers = @{} foreach ($eligibility in $eligibilities) { if ($eligibility.epoch -eq $node.epoch.number) { $smesher = $eligibility.smesher $layers[$smesher] = $eligibility.eligibilities - } - if ($layers) { $node.layers = $layers } } - $atxTarget = $atxPublished.target - $poetWait = $poetWaitProof.target - if ($atxTarget) { - $node.atx = $atxTarget - } - elseif ($poetWait ) { - #-and ($null -eq $layers) - $node.atx = $poetWait + $activations = @{} + foreach ($aPublished in $atxPublished) { + if ($aPublished.current -eq $node.epoch.number) { + $smesher = $aPublished.smesher + $activations[$smesher] = $aPublished.target + $node.activations = $activations + } } - else { - $node.atx = " -" + $waitProof = @{} + foreach ($pWaitProof in $poetWaitProof) { + $smesher = $pWaitProof.smesher + $waitProof[$smesher] = $pWaitProof.target + $node.waitProof = $waitProof } - + } + + if ($node.online -and ($using:stage -ne 1) -and ($using:stage -ne 4) -and ($node.port -ne 0) -and ($node.port2 -ne 0)) { $smeshing = ((Invoke-Expression ("$($grpcurl) --plaintext -max-time 5 $($node.host):$($node.port2) spacemesh.v1.SmesherService.IsSmeshing")) | ConvertFrom-Json) 2>$null - if ($null -ne $smeshing.isSmeshing) { + if ($null -ne $smeshing.isSmeshing) { if ($smeshing.isSmeshing -eq "true") { $node.status = "Smeshing" } @@ -199,39 +201,23 @@ function main { $node.status = $smeshing.isSmeshing } } - - } - - if ($node.online -and ($using:stage -ne 1) -and ($using:stage -ne 4) -and ($node.port -ne 0) -and ($node.port2 -ne 0)) { + + $publicKeys = ((Invoke-Expression ("$($grpcurl) --plaintext -max-time 5 $($node.host):$($node.port2) spacemesh.v1.SmesherService.SmesherIDs")) | ConvertFrom-Json) 2>$null + if (($publicKeys.publicKeys.Count -eq 1) -and ($smeshing.isSmeshing -eq "true")) { + $node.publicKey = $publicKeys.publicKeys[0] + } + $state = ((Invoke-Expression ("$($grpcurl) --plaintext -max-time 5 $($node.host):$($node.port2) spacemesh.v1.SmesherService.PostSetupStatus")) | ConvertFrom-Json).status 2>$null - if ($state) { $node.numUnits = $state.opts.numUnits - + if ($state.state -eq "STATE_IN_PROGRESS") { - $percent = [math]::round(($state.numLabelsWritten / 1024 / 1024 / 1024 * 16) / ($state.opts.numUnits * 64) * 100, 0) + $percent = [math]::round(($state.numLabelsWritten / 1024 / 1024 / 1024 * 16) / ($state.opts.numUnits * 64) * 100, 2) $node.status = "$($percent)%" } } } - - if (($using:checkIfBanned -eq "True") -and ($using:stage -ne 2) -and ($using:stage -ne 4) -and ($node.port -ne 0) -and ($node.port2 -ne 0)) { - if ($node.publicKey) { - $publicKeylow = [System.BitConverter]::ToString([System.Convert]::FromBase64String($node.publicKey)).Replace("-", "").ToLower() - $response = (Invoke-Expression ("$($grpcurl) --plaintext -max-time 5 $($node.host):$($node.port) spacemesh.v1.MeshService.MalfeasanceStream")) 2>$null - if ($response -match "MALFEASANCE_HARE") { - if ($response -match $publicKeylow) { - if ($using:utf8 -eq "False") { $node.ban = " X" } else { $node.ban = "`u{1F480}" } #"yes" - } - else { - if ($using:utf8 -eq "False") { $node.ban = " OK" } else { $node.ban = "`u{1f197}" } #"no" - } - } - else { $node.ban = "" } - } - else { $node.ban = " -" } - } - + if (($node.port -ne 0) -and ($node.port2 -ne 0) -and ($node.port3 -ne 0)) { $node.post = @{} $states = ((Invoke-Expression ("$($grpcurl) --plaintext -max-time 5 $($node.host):$($node.port3) spacemesh.v1.PostInfoService.PostStates")) | ConvertFrom-Json).states 2>$null @@ -246,10 +232,10 @@ function main { } } } - - if (($using:stage -ne 2) -and ($node.port -eq 0) -and ($node.port2 -eq 0) -and ($node.port3 -ne 0)) { - $postStatus = Invoke-Expression ("curl http://$($node.host):$($node.port3)/status") 2>$null - if ($postStatus) { + + if (($using:stage -ne 2) -and ($node.port -eq 0) -and ($node.port2 -eq 0) -and ($node.port3 -ne 0)) { + $postStatus = Invoke-Expression ("curl http://$($node.host):$($node.port3)/status") 2>$null + if ($postStatus) { if ($postStatus -match '^{.*}$') { $postStatus = $postStatus | ConvertFrom-Json if ($postStatus.PSObject.Properties.Name -contains "Proving") { @@ -261,17 +247,19 @@ function main { else { $node.status = $postStatus.Replace("`"", "") } - } - else { - $node.status = "Offline" - } - } - + } + else { + $node.status = "Offline" + } + } + $syncNodesCopy[$_.name] = $node } - + $postServices = @{} $layers = @{} + $activations = @{} + $waitProofs = @{} foreach ($node in $syncNodes.Values) { if (($node.port -ne 0) -and ($node.port2 -ne 0)) { foreach ($name in $node.post.Keys) { @@ -283,41 +271,79 @@ function main { $layers += $node.layers $node.layers = $null } + if ($node.activations) { + $activations += $node.activations + $node.activations = $null + } + if ($node.waitProof) { + $waitProofs += $node.waitProof + $node.waitProof = $null + } } } - - $nodeList | ForEach-Object { - $node = $syncNodes[$_.name] - + + foreach ($node in $syncNodes.Values) { + $node.atx = $null + $node.ban = $null + $node.rewards = $null + $node.layers = $null + if ($epoch -lt $node.epoch.number) { $epoch = $node.epoch.number } - + foreach ($name in $postServices.Keys) { $post = $postServices[$name] if ($name -eq $node.name) { $node.publicKey = $post.id + } } - + foreach ($key in $layers.Keys) { - $layer = $layers[$name].layers if ($key -eq $node.publicKey) { $node.rewards = $layers[$key].count $node.layers = $layers[$key] } } - + + foreach ($key in $activations.Keys) { + if ($key -eq $node.publicKey) { + $node.atx = [string]$activations[$key] + } + } + + foreach ($key in $waitProofs.Keys) { + if ($key -eq $node.publicKey) { + if ($node.atx) { + $node.atx = $node.atx + ', ' + $waitProofs[$key] + } + else { + $node.atx = $waitProofs[$key] + } + } + } + if (($node.su) -and (!$node.numUnits) -and ($node.port -eq 0)) { $node.numUnits = $node.su } - + if ($node.publicKey -and !$node.shortKey) { $node.fullkey = (B64_to_Hex -id2convert $node.publicKey) # Extract last 5 digits from SmesherID $node.shortKey = $node.fullkey.substring($node.fullkey.length - 5, 5) } - + + if (($checkIfBanned -eq "True") -and ($malfeasanceStream -match "MALFEASANCE_HARE") -and $node.fullkey) { + if ($malfeasanceStream -match $node.fullkey) { + if ($utf8 -eq "False") { $node.ban = " X" } else { $node.ban = "`u{1F480}" } #"yes" + } + else { + if ($utf8 -eq "False") { $node.ban = " OK" } else { $node.ban = "`u{1f197}" } #"no" + } + } + else { $node.ban = "" } + $totalLayers = $totalLayers + $node.rewards if ($node.layers) { if ($fileFormat -eq 1) { @@ -343,11 +369,32 @@ function main { $rewardsTrackApp += $nodeData } } - + if ($node.topLayer -gt $topLayer) { $topLayer = $node.topLayer } + } + + foreach ($node in $syncNodes.Values) { + if (($stage -ne 2) -and ($node.port -eq 0) -and ($node.port2 -eq 0) -and ($node.port3 -ne 0)) { + if ($node.status -eq "Idle") { + $found = $false + foreach ($name in $postServices.Keys) { + $post = $postServices[$name] + if ($name -eq $node.name) { + $found = $true + } + } + if (!$found) { + $node.status = "Idle!" + } + } + } + } + $nodeList | ForEach-Object { + $node = $syncNodes[$_.name] + $o = [PSCustomObject]@{ Name = $node.name NodeID = $node.shortKey @@ -368,10 +415,10 @@ function main { ELG = $node.atx BAN = $node.ban } - + $object += $o } - + if ($rewardsTrackApp -and ($fileFormat -ne 0)) { $files = Get-ChildItem -Path .\ -Filter "RewardsTrackApp_*.json" foreach ($file in $files) { @@ -391,52 +438,55 @@ function main { } } - if (($showWalletBalance -eq "True") -and ($stage -lt 2)) { + if (($stage -ne 4) -and ($stage -ne 1)) { # Find all private nodes, then select the first in the list. Once we have this, we know that we have a good Online Local Private Node $filterObjects = $object | Where-Object { $_.Synced -match "True" } # -and $_.Host -match "localhost" -and $_.status -match "True" if ($filterObjects) { $privateOnlineNodes = $filterObjects[0] + if (($checkIfBanned -eq "True") -and !$malfeasanceStream) { + $malfeasanceStream = (Invoke-Expression ("$($grpcurl) --plaintext -max-time 5 $($privateOnlineNodes.Host):$($privateOnlineNodes.Port) spacemesh.v1.MeshService.MalfeasanceStream")) 2>$null + } } else { $privateOnlineNodes = $null } - - # If private nodes are found, determine the PS version and execute corresponding grpcurl if statement. Else skip. - if ($privateOnlineNodes.name.count -gt 0) { - $coinbase = (Invoke-Expression "$grpcurl --plaintext -max-time 10 $($privateOnlineNodes.Host):$($privateOnlineNodes.Port2) spacemesh.v1.SmesherService.Coinbase" | ConvertFrom-Json).accountId.address - $jsonPayload = "{ `"filter`": { `"account_id`": { `"address`": `"$coinbase`" }, `"account_data_flags`": 4 } }" - $balance = (Invoke-Expression "$grpcurl -plaintext -d '$jsonPayload' $($privateOnlineNodes.Host):$($privateOnlineNodes.Port) spacemesh.v1.GlobalStateService.AccountDataQuery" | ConvertFrom-Json).accountItem.accountWrapper.stateCurrent.balance.value - $balanceSMH = [string]([math]::Round($balance / 1000000000, 3)) + " SMH" - $coinbase = "($coinbase)" - if ($fakeCoins -ne 0) { [string]$balanceSMH = "$($fakeCoins) SMH" } - if ($coinbaseAddressVisibility -eq "partial") { - $coinbase = '(' + $($coinbase).Substring($($coinbase).IndexOf(")") - 4, 4) + ')' - } - elseif ($coinbaseAddressVisibility -eq "hidden") { - $coinbase = "(----)" - } + } + + # If private nodes are found, determine the PS version and execute corresponding grpcurl if statement. Else skip. + if (($showWalletBalance -eq "True") -and $privateOnlineNodes.name.count -gt 0) { + $coinbase = (Invoke-Expression "$grpcurl --plaintext -max-time 10 $($privateOnlineNodes.Host):$($privateOnlineNodes.Port2) spacemesh.v1.SmesherService.Coinbase" | ConvertFrom-Json).accountId.address + $jsonPayload = "{ `"filter`": { `"account_id`": { `"address`": `"$coinbase`" }, `"account_data_flags`": 4 } }" + $balance = (Invoke-Expression "$grpcurl -plaintext -d '$jsonPayload' $($privateOnlineNodes.Host):$($privateOnlineNodes.Port) spacemesh.v1.GlobalStateService.AccountDataQuery" | ConvertFrom-Json).accountItem.accountWrapper.stateCurrent.balance.value + $balanceSMH = [string]([math]::Round($balance / 1000000000, 3)) + " SMH" + $coinbase = "($coinbase)" + if ($fakeCoins -ne 0) { [string]$balanceSMH = "$($fakeCoins) SMH" } + if ($coinbaseAddressVisibility -eq "partial") { + $coinbase = '(' + $($coinbase).Substring($($coinbase).IndexOf(")") - 4, 4) + ')' } - else { - $coinbase = "" - $balanceSMH = "Unable to retrieve the balance at the moment" + elseif ($coinbaseAddressVisibility -eq "hidden") { + $coinbase = "(----)" } } + else { + $coinbase = "" + $balanceSMH = "Unable to retrieve the balance at the moment" + } $columnRules = applyColumnRules - + Clear-Host $object | ForEach-Object { $props = 'Name', 'Host' if ($ShowPorts -eq "True") { $props += 'Port', 'Port2', 'Port3' } $props += 'Peers', 'Synced', 'Layer', 'Verified', 'Version', 'Status', 'NodeID', 'SU', 'SizeTiB', 'RWD' - #if ($showELG -eq "True") { $props += 'ELG' } - #if ($checkIfBanned -eq "True") { $props += 'BAN' } + if ($showELG -eq "True") { $props += 'ELG' } + if ($checkIfBanned -eq "True") { $props += 'BAN' } $_ | Select-Object $props } | ColorizeMyObject -ColumnRules $columnRules #$object | Select-Object Name, NodeID, Host, Port, Peers, SU, SizeTiB, Synced, Top, Verified, Version, status, RWD, ELG, BAN | ColorizeMyObject -ColumnRules $columnRules - + $tableRefreshTimer.Restart() - + if (($queryHighestAtx -eq "True") -and ($null -eq $highestAtxJob) -and ($null -eq $highestAtx)) { $syncedNode = $syncNodes.Values | Where-Object { $_.synced -eq "True" } | Select-Object -First 1 if ($syncedNode) { @@ -453,9 +503,9 @@ function main { $highestAtx = ($jobResult | ConvertFrom-Json).atx $highestAtxJob = $null } - + Write-Host `n - + Write-Host "-------------------------------------- Info: -----------------------------------" -ForegroundColor Yellow if ($epoch) { Write-Host "Current Epoch: " -ForegroundColor Cyan -nonewline; Write-Host $epoch -ForegroundColor Green @@ -478,37 +528,44 @@ function main { } } Write-Host "--------------------------------------------------------------------------------" -ForegroundColor Yellow - Write-Host "ELG - The number of Epoch when the node will be eligible for rewards. " -ForegroundColor DarkGray + #Write-Host "ELG - The number of Epoch when the node will be eligible for rewards. " -ForegroundColor DarkGray Write-Host `n - + #SM-Monitor Version Check if (($gitNewMonitorVersion) -and ($stage -ne 2)) { $taglist = ($gitNewMonitorVersion -split "-")[0] -replace "[^.0-9]" if ([version]$version -lt [version]$taglist) { - Write-Host "Info:" -ForegroundColor White -nonewline; Write-Host " --> New SM-Monitor update avaiable! $($taglist)" -ForegroundColor DarkYellow + Write-Host "Info:" -ForegroundColor White -nonewline; Write-Host " --> New sm-monitor update avaiable! $($taglist)" -ForegroundColor DarkYellow + Write-Host `n } } - + #Version Check if (($gitVersion) -and ($stage -ne 2)) { $currentVersion = ($gitVersion -split "-")[0] -replace "[^.0-9]" foreach ($node in ($object | Where-Object { (($_.status -notmatch "Offline") -and ($_.status)) })) { $node.version = ($node.version -split "-")[0] -replace "[^.0-9]" if ([version]$node.version -lt [version]$currentVersion) { - Write-Host "Info:" -ForegroundColor White -nonewline; Write-Host " --> New go-spacemesh update avaiable! $($gitVersion)" -ForegroundColor DarkYellow + Write-Host "Github Go-Spacemesh version: $($gitVersion)" -ForegroundColor Green + Write-Host "Info:" -ForegroundColor White -nonewline; Write-Host " --> Some of your nodes are Outdated!" -ForegroundColor DarkYellow + Write-Host `n break } } } - + $newline = "`r`n" - foreach ($node in $object | Where-Object { (($_.status -match "Offline") -and ($_.port -ne 0)) }) { + $nodesOffline = $null + foreach ($node in $object | Where-Object { (($_.status -match "Offline") -and ($_.port -ne 0) -and ($stage -ne 2)) }) { $nodesOffline = $true + break } - if (($nodesOffline) -and ($stage -ne 2)) { + if ($nodesOffline) { Write-Host "Info:" -ForegroundColor White -nonewline; Write-Host " --> Some of your nodes are Offline!" -ForegroundColor DarkYellow + Write-Host `n if ($emailEnable -eq "True" -And (isValidEmail($myEmail))) { $Body = "Warning, some nodes are offline!" + foreach ($node in $syncNodes.Values) { if (!$node.online) { $Body = $body + $newLine + $node.name + " " + $node.Host + " " + $node.status @@ -518,18 +575,18 @@ function main { } } } - + if ($OKtoSend) { $From = "001smmonitor@gmail.com" $To = $myEmail $Subject = "Your Spacemesh node is offline" - + # Define the SMTP server details $SMTPServer = "smtp.gmail.com" $SMTPPort = 587 $SMTPUsername = "001smmonitor@gmail.com" $SMTPPassword = "uehd zqix qrbh gejb" - + # Create a new email object $Email = New-Object System.Net.Mail.MailMessage $Email.From = $From @@ -538,12 +595,12 @@ function main { $Email.Body = $Body # Uncomment below to send HTML formatted email #$Email.IsBodyHTML = $true - + # Create an SMTP client object and send the email $SMTPClient = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort) $SMTPClient.EnableSsl = $true $SMTPClient.Credentials = New-Object System.Net.NetworkCredential($SMTPUsername, $SMTPPassword) - + Try { $SMTPClient.Send($Email) } @@ -553,23 +610,25 @@ function main { } Finally { Write-Host "Email sent..." -ForegroundColor DarkYellow + Write-Host `n $OKtoSend = "" } } } } - - $currentDate = Get-Date -Format HH:mm:ss - # Refresh - Write-Host `n - Write-Host "Press SPACE to refresh" -ForegroundColor DarkGray - Write-Host "Last refresh: " -ForegroundColor Yellow -nonewline; Write-Host "$currentDate" -ForegroundColor Green - + + if ($stage -ne 2) { + $currentDate = Get-Date -Format HH:mm:ss + # Refresh + Write-Host "Press SPACE to refresh" -ForegroundColor DarkGray + Write-Host "Last refresh: " -ForegroundColor Yellow -nonewline; Write-Host "$currentDate" -ForegroundColor Green + } + # Get original position of cursor $originalPosition = $host.UI.RawUI.CursorPosition $relativeCursorPosition = New-Object System.Management.Automation.Host.Coordinates - - $clearmsg = " " * ([System.Console]::WindowWidth - 1) + + $clearmsg = " " * ([System.Console]::WindowWidth - 18) if ($utf8 -eq "False") { $frames = @("|", "/", "-", "\") } @@ -590,7 +649,8 @@ function main { if ($stage -gt 0) { $stage = $stage - 1 } - + + Write-Host "Next refresh in: " -nonewline -ForegroundColor Yellow; :waitloop while ($stage -eq 0) { for ($i = 0; $i -lt $frames.Count; $i++) { @@ -605,26 +665,30 @@ function main { if ([System.Console]::KeyAvailable) { $key = [System.Console]::ReadKey($true) if ($key.Key -eq "Spacebar") { break waitloop } + if ($key.Key -eq "R") { + main + return + } } $secondsLeft = ($tableRefreshTime - $tableRefreshTimeElapsed) -as [int] $frame = $frames[$i % $frameCount] $bufferHeight = $host.UI.RawUI.BufferSize.Height $relativeCursorPosition.Y = $originalPosition.Y - $host.UI.RawUI.WindowPosition.Y if ($bufferHeight -gt $relativeCursorPosition.Y) { - [Console]::SetCursorPosition(0, $relativeCursorPosition.Y) + [Console]::SetCursorPosition(17, $relativeCursorPosition.Y) [Console]::Write($clearmsg) - [Console]::SetCursorPosition(0, $relativeCursorPosition.Y) - Write-Host "Next refresh in: " -nonewline -ForegroundColor Yellow; Write-Host "$($secondsLeft.ToString().PadLeft(3, ' ')) $frame" -nonewline + [Console]::SetCursorPosition(17, $relativeCursorPosition.Y) + Write-Host "$($secondsLeft.ToString().PadLeft(3, ' ')) $frame" -nonewline } - Start-Sleep -Milliseconds 100 + Start-Sleep -Milliseconds 120 } } $relativeCursorPosition.Y = $originalPosition.Y - $host.UI.RawUI.WindowPosition.Y [Console]::SetCursorPosition(0, $relativeCursorPosition.Y) [Console]::Write($clearmsg) [Console]::SetCursorPosition(0, $relativeCursorPosition.Y) - Write-Host "Updating..." -NoNewline - + Write-Host "Updating..." -NoNewline -ForegroundColor Yellow + # Reset some variables every hour $OneHoursElapsed = $OneHourTimer.Elapsed.TotalHours if ($OneHoursElapsed -ge 1) { @@ -634,15 +698,16 @@ function main { } $gitNewMonitorVersion = Get-gitNewMonitorVersion $highestAtx = $null + $malfeasanceStream = $null $OneHourTimer.Restart() } } } - + function IsValidEmail { param([string]$Email) $Regex = '^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$' - + try { $obj = [mailaddress]$Email if ($obj.Address -match $Regex) { @@ -654,7 +719,7 @@ function IsValidEmail { return $False } } - + function B64_to_Hex { param ( [Parameter(Position = 0, Mandatory = $true)] @@ -662,7 +727,7 @@ function B64_to_Hex { ) [System.BitConverter]::ToString([System.Convert]::FromBase64String($id2convert)).Replace("-", "") } - + function Hex_to_B64 { param ( [Parameter(Position = 0, Mandatory = $true)] @@ -671,54 +736,54 @@ function Hex_to_B64 { $NODE_ID_BYTES = for ($i = 0; $i -lt $id2convert.Length; $i += 2) { [Convert]::ToByte($id2convert.Substring($i, 2), 16) } [System.Convert]::ToBase64String($NODE_ID_BYTES) } - + function ColorizeMyObject { param ( [Parameter(ValueFromPipeline = $true)] $InputObject, - + [Parameter(Mandatory = $true)] [System.Collections.ArrayList]$ColumnRules ) - + begin { $dataBuffer = @() } - + process { $dataBuffer += $InputObject } - + end { $headers = $dataBuffer[0].PSObject.Properties.Name - + $maxWidths = @{} foreach ($header in $headers) { $headerLength = "$header".Length $dataMaxLength = ($dataBuffer | ForEach-Object { "$($_.$header)".Length } | Measure-Object -Maximum).Maximum $maxWidths[$header] = [Math]::Max($headerLength, $dataMaxLength) } - + $headers | ForEach-Object { $paddedHeader = $_.PadRight($maxWidths[$_]) Write-Host $paddedHeader -NoNewline; Write-Host " " -NoNewline } Write-Host "" - + $headers | ForEach-Object { $dashes = '-' * $maxWidths[$_] Write-Host $dashes -NoNewline Write-Host " " -NoNewline } Write-Host "" - + foreach ($row in $dataBuffer) { foreach ($header in $headers) { $propertyValue = "$($row.$header)" $foregroundColor = $null $backgroundColor = $null - + foreach ($rule in $ColumnRules) { if ($header -eq $rule.Column) { if ($propertyValue -like $rule.Value) { @@ -730,9 +795,9 @@ function ColorizeMyObject { } } } - + $paddedValue = $propertyValue.PadRight($maxWidths[$header]) - + if ($foregroundColor -or $backgroundColor) { if ($backgroundColor) { Write-Host $paddedValue -NoNewline -ForegroundColor $foregroundColor -BackgroundColor $backgroundColor @@ -744,14 +809,14 @@ function ColorizeMyObject { else { Write-Host $paddedValue -NoNewline } - + Write-Host " " -NoNewline } Write-Host "" } } } - + function Get-gitNewVersion { .{ $gitNewVersion = Invoke-RestMethod -Method 'GET' -uri "https://api.github.com/repos/spacemeshos/go-spacemesh/releases/latest" 2>$null @@ -761,7 +826,7 @@ function Get-gitNewVersion { } | Out-Null return $gitNewVersion } - + function Get-gitNewMonitorVersion { .{ $tagList = Invoke-RestMethod -Method 'GET' -uri "https://api.github.com/repos/xeliuqa/SM-Monitor/releases/latest" 2>$null @@ -771,7 +836,7 @@ function Get-gitNewMonitorVersion { } | Out-Null return $tagList } - + function printSMMonitorLogo { Clear-Host $foregroundColor = "Green" @@ -780,26 +845,26 @@ function printSMMonitorLogo { $colDelay = 0 # milliseconds $logoWidth = 86 # Any time you change the logo, all rows have to be the exact width. Then assign to this var. $logoHeight = 9 # Any time you change the logo, recount the rows and assign to this var. - + $screenWidth = $host.UI.RawUI.WindowSize.Width $screenHeight = $host.UI.RawUI.WindowSize.Height $horizontalOffset = [Math]::Max(0, [Math]::Ceiling(($screenWidth - $logoWidth) / 2)) $verticalOffset = [Math]::Max(0, [Math]::Ceiling(($screenHeight - $logoHeight) / 2)) - + $asciiArt = @" - _________ _____ _____ __ __ - /\ / _____/ / \ / \ ____ ____ |__|/ |_ ___________ /\ - \/ \_____ \ / \ / \ ______ / \ / \ / _ \ / \| \ __\/ _ \_ __ \ \/ - /\ / \/ Y \ /_____/ / Y ( <_> ) | \ || | ( <_> ) | \/ /\ - \/ /_______ /\____|__ / \____|__ /\____/|___| /__||__| \____/|__| \/ - \/ \/ \/ \/ - _____________________________________________________________________ - /_____/_____/_____/_____/_____/ https://github.com/xeliuqa/SM-Monitor - https://www.spacemesh.io + _________ _____ _____ __ __ + /\ / _____/ / \ / \ ____ ____ |__|/ |_ ___________ /\ + \/ \_____ \ / \ / \ ______ / \ / \ / _ \ / \| \ __\/ _ \_ __ \ \/ + /\ / \/ Y \ /_____/ / Y ( <_> ) | \ || | ( <_> ) | \/ /\ + \/ /_______ /\____|__ / \____|__ /\____/|___| /__||__| \____/|__| \/ + \/ \/ \/ \/ + _____________________________________________________________________ + /_____/_____/_____/_____/_____/ https://github.com/xeliuqa/SM-Monitor + https://www.spacemesh.io "@ - + $lines = $asciiArt -split "`n" - + for ($col = 1; $col -le $lines[0].Length; $col++) { for ($row = 1; $row -le $lines.Length; $row++) { $char = if ($col - 1 -lt $lines[$row - 1].Length) { $lines[$row - 1][$col - 1] } else { ' ' } @@ -826,13 +891,13 @@ function printSMMonitorLogo { } Start-Sleep -Milliseconds $colDelay } - + $CursorPosition = [System.Management.Automation.Host.Coordinates]::new(0, $lines.Length + $verticalOffset + 1) $host.UI.RawUI.CursorPosition = $CursorPosition # Start-Sleep $logoDelay # Clear-Host } - + function applyColumnRules { # Colors: Black, Blue, Cyan, DarkBlue, DarkCyan, DarkGray, DarkGreen, DarkMagenta, DarkRed, DarkYellow, Gray, Green, Magenta, Red, White, Yellow return @( @@ -854,6 +919,7 @@ function applyColumnRules { @{ Column = "Status"; Value = "*"; ForegroundColor = "Yellow"; BackgroundColor = $DefaultBackgroundColor }, @{ Column = "Status"; Value = "Online"; ForegroundColor = "Green"; BackgroundColor = $DefaultBackgroundColor }, @{ Column = "Status"; Value = "Idle"; ForegroundColor = "Green"; BackgroundColor = $DefaultBackgroundColor }, + @{ Column = "Status"; Value = "Idle!"; ForegroundColor = "Red"; BackgroundColor = $DefaultBackgroundColor }, @{ Column = "Status"; Value = "Proving"; ForegroundColor = "Yellow"; BackgroundColor = $DefaultBackgroundColor }, @{ Column = "Status"; Value = "Smeshing"; ForegroundColor = "Green"; BackgroundColor = $DefaultBackgroundColor }, @{ Column = "Status"; Value = "False"; ForegroundColor = "DarkRed"; BackgroundColor = $DefaultBackgroundColor }, @@ -864,5 +930,5 @@ function applyColumnRules { @{ Column = "ELG"; Value = $poetWait; ForegroundColor = "Yellow"; BackgroundColor = $DefaultBackgroundColor } ) } - -main + +main \ No newline at end of file