Created
January 2, 2026 12:19
-
-
Save fdcastel/cddf7ac8a4a614fc0a1e3b6d86e4f3da to your computer and use it in GitHub Desktop.
Monitors Syncthing connections in real-time with transfer rate calculations
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <# | |
| .SYNOPSIS | |
| Monitors Syncthing connections in real-time with transfer rate calculations. | |
| .DESCRIPTION | |
| Runs every 5 seconds to display Syncthing connection status. The first iteration | |
| shows current values without rate information. Subsequent iterations include | |
| inTotalMbps showing the data transfer rate. | |
| .PARAMETER IntervalSeconds | |
| The interval between checks in seconds. Default is 5. | |
| .EXAMPLE | |
| .\Monitor-SyncthingConnections.ps1 | |
| .EXAMPLE | |
| .\Monitor-SyncthingConnections.ps1 -IntervalSeconds 10 | |
| #> | |
| [CmdletBinding()] | |
| param( | |
| [Parameter()] | |
| [int]$IntervalSeconds = 5 | |
| ) | |
| function Resolve-HostName { | |
| <# | |
| .SYNOPSIS | |
| Resolves an IP address or hostname to its DNS name. | |
| .DESCRIPTION | |
| Cross-platform function to resolve hostnames. Uses Resolve-DnsName on Windows | |
| and host/dig commands on Linux. | |
| .PARAMETER Address | |
| The IP address or hostname to resolve | |
| #> | |
| [CmdletBinding()] | |
| param( | |
| [Parameter(Mandatory = $true)] | |
| [string]$Address | |
| ) | |
| try { | |
| if ($IsLinux -or $IsMacOS) { | |
| # Try using 'host' command on Linux/Mac | |
| $hostOutput = host $Address 2>$null | |
| if ($LASTEXITCODE -eq 0 -and $hostOutput) { | |
| # Parse output like "1.2.3.4.in-addr.arpa domain name pointer hostname.example.com." | |
| if ($hostOutput -match 'domain name pointer\s+(.+)\.$') { | |
| return $matches[1] | |
| } elseif ($hostOutput -match 'has address') { | |
| # Forward lookup, return original | |
| return $Address | |
| } | |
| } | |
| # Fallback: try 'dig' if available | |
| $digOutput = dig +short -x $Address 2>$null | |
| if ($LASTEXITCODE -eq 0 -and $digOutput) { | |
| $hostname = ($digOutput | Select-Object -First 1).TrimEnd('.') | |
| if ($hostname) { | |
| return $hostname | |
| } | |
| } | |
| # If all fails, return the address | |
| return $Address | |
| } else { | |
| # Windows: use Resolve-DnsName | |
| $dnsResult = Resolve-DnsName -Name $Address -ErrorAction SilentlyContinue | |
| if ($dnsResult) { | |
| return $dnsResult | Select-Object -ExpandProperty 'NameHost' -First 1 | |
| } else { | |
| return $Address | |
| } | |
| } | |
| } catch { | |
| return $Address | |
| } | |
| } | |
| function Add-ConnectionRate { | |
| <# | |
| .SYNOPSIS | |
| Calculates the data transfer rate between two Syncthing connection snapshots. | |
| .DESCRIPTION | |
| Takes two connection snapshots (Prior and Current) and calculates the inTotalMbps | |
| (MB per second) for each connection based on the difference in transferred data | |
| and time elapsed. | |
| .PARAMETER Prior | |
| The previous connection snapshot | |
| .PARAMETER Current | |
| The current connection snapshot | |
| .EXAMPLE | |
| $rate = Add-ConnectionRate -Prior $previousData -Current $currentData | |
| #> | |
| [CmdletBinding()] | |
| param( | |
| [Parameter(Mandatory = $true)] | |
| [PSCustomObject[]]$Prior, | |
| [Parameter(Mandatory = $true)] | |
| [PSCustomObject[]]$Current | |
| ) | |
| $result = @() | |
| for ($i = 0; $i -lt $Current.Count; $i++) { | |
| $currentItem = $Current[$i] | |
| # Try to find matching prior item by index (since host might be empty) | |
| # In a more robust solution, you'd match by device ID or address | |
| if ($i -lt $Prior.Count) { | |
| $priorItem = $Prior[$i] | |
| # Calculate time difference in seconds | |
| $currentTime = [DateTime]::Parse($currentItem.at) | |
| $priorTime = [DateTime]::Parse($priorItem.at) | |
| $timeDiffSeconds = ($currentTime - $priorTime).TotalSeconds | |
| # Calculate MB difference | |
| $mbDiff = $currentItem.inTotalMb - $priorItem.inTotalMb | |
| # Calculate rate (MB per second) | |
| if ($timeDiffSeconds -gt 0) { | |
| $mbps = [math]::Round($mbDiff / $timeDiffSeconds, 3) | |
| } else { | |
| $mbps = 0 | |
| } | |
| # Add the rate and diff properties to current item | |
| $currentItem | Add-Member -NotePropertyName 'inTotalMbDiff' -NotePropertyValue $mbDiff -Force | |
| $currentItem | Add-Member -NotePropertyName 'inTotalMbps' -NotePropertyValue $mbps -Force | |
| } | |
| $result += $currentItem | |
| } | |
| return $result | |
| } | |
| # Main monitoring loop | |
| $priorData = $null | |
| while ($true) { | |
| Clear-Host | |
| # Get current connection data | |
| $connections = syncthing cli show connections | | |
| ConvertFrom-Json | | |
| Select-Object -ExpandProperty 'Connections' | |
| $currentData = $connections.psobject.Properties.Value | | |
| Select-Object @{Name='host'; Expression={Resolve-HostName -Address $_.address.split(":")[0]}}, | |
| 'connected', | |
| 'paused', | |
| 'startedAt', | |
| 'at', | |
| @{Name='inTotalMb'; Expression={[int]($_.inBytesTotal / 1MB)}} | | |
| Sort-Object 'host' | |
| if ($priorData -eq $null) { | |
| # First iteration - display without rate | |
| $currentData | Format-Table -AutoSize | |
| } else { | |
| # Subsequent iterations - calculate and display rate | |
| $dataWithRate = Add-ConnectionRate -Prior $priorData -Current $currentData | |
| $dataWithRate | Format-Table -AutoSize | |
| } | |
| # Store current data for next iteration | |
| $priorData = $currentData | |
| # Wait for the specified interval | |
| Start-Sleep -Seconds $IntervalSeconds | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment