diff --git a/bot.ps1 b/bot.ps1
index 66906b1..db540cf 100644
--- a/bot.ps1
+++ b/bot.ps1
@@ -1,70 +1,224 @@
-param (
- [Parameter(Mandatory=$true)]
- [string]
- $HomeServer,
-
- [Parameter(Mandatory=$true)]
- [string]
- $User,
-
- [Parameter(Mandatory=$true)]
- [securestring]
- $AccessToken
-)
-
-function Send-MatrixEvent {
- param (
- [Parameter(Mandatory=$true)]
- [string]
- $RoomId,
-
- [Parameter(Mandatory=$true)]
- [string]
- $Event,
-
- [Parameter(Mandatory=$true)]
- [string]
- $EventType
- )
-
- #txn_id should be unique per client, so we use timestamp+random
- $txn_id = '{0}{1}' -f (Get-Date -UFormat '%s'),(Get-Random)
-
- $uri = '{0}/_matrix/client/r0/rooms/{1}/send/{2}/{3}' -f $HomeServer,$RoomId,$EventType,$txn_id
-
- $header_splat = @{
- Authentication = 'Bearer'
- Token = $AccessToken
- ContentType = 'application/json'
- }
- $http_splat = @{
- Uri = $uri
- Method = 'Put'
- Body = $Event
- }
-
- $response = Invoke-RestMethod @header_splat @http_splat
- if($response.event_id) {
- Write-Output ('Event {0} sent to room {1}' -f $response.event_id,$RoomId)
- }
-}
-function Send-MatrixNotice {
- param (
- [Parameter(Mandatory=$true)]
- [string]
- $RoomId,
-
- [Parameter(Mandatory=$true)]
- [string]
- $Message
- )
-
- $event = @{
- msgtype = 'm.notice'
- body = $Message
- } | ConvertTo-Json -Compress
-
- Send-MatrixEvent -RoomId $RoomId -Event $event -EventType 'm.room.message'
-}
-
-Send-MatrixNotice -RoomId '!amKUIaaKdERatZsJgB:matrix.org' -Message ('asef :) {0}' -f (Get-Date))
\ No newline at end of file
+param (
+ [Parameter(Mandatory=$true)]
+ [string]
+ $HomeServer,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $User,
+
+ [Parameter(Mandatory=$true)]
+ [securestring]
+ $AccessToken
+)
+
+function Send-MatrixEvent {
+ param (
+ [Parameter(Mandatory=$true)]
+ [string]
+ $RoomId,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $Event,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $EventType
+ )
+
+ #txn_id should be unique per client, so we use timestamp+random
+ $txn_id = '{0}{1}' -f (Get-Date -UFormat '%s'),(Get-Random)
+
+ $uri = '{0}/_matrix/client/r0/rooms/{1}/send/{2}/{3}' -f $HomeServer,$RoomId,$EventType,$txn_id
+
+ $header_splat = @{
+ Authentication = 'Bearer'
+ Token = $AccessToken
+ ContentType = 'application/json'
+ }
+ $http_splat = @{
+ Uri = $uri
+ Method = 'Put'
+ Body = $Event
+ }
+
+ $response = Invoke-RestMethod @header_splat @http_splat
+ if($response.event_id) {
+ Write-Host ('Event {0} sent to room {1}' -f $response.event_id,$RoomId)
+ }
+}
+function Send-MatrixNotice {
+ param (
+ [Parameter(Mandatory=$true)]
+ [string]
+ $RoomId,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $Body,
+
+ [Parameter(Mandatory=$false)]
+ [string]
+ $FormattedBody
+ )
+
+ $event = @{
+ msgtype = 'm.notice'
+ body = $Body
+ }
+
+ if($FormattedBody) {
+ $event += @{
+ format = 'org.matrix.custom.html'
+ formatted_body = $FormattedBody
+ }
+ }
+
+ $event_json = $event | ConvertTo-Json -Compress
+
+ Send-MatrixEvent -RoomId $RoomId -Event $event_json -EventType 'm.room.message'
+}
+function Compare-Timestamps {
+ param (
+ [Parameter(Mandatory=$true)]
+ [Int64]
+ $OriginServerTs
+ )
+
+ $current_time = (Get-Date).ToUniversalTime()
+
+ #$OriginServerTs is milliseconds since 1970-01-01 (epoch time in milliseconds)
+ $original_time = Get-Date -Date ((Get-Date -Date '1970-01-01') + [timespan]::FromMilliseconds($OriginServerTs))
+
+ #return the difference
+ Write-Output ($current_time - $original_time)
+}
+function ConvertTo-HumanReadableTimespan {
+ param (
+ [parameter(Mandatory=$true)]
+ [timespan]
+ $TimeSpan
+ )
+
+ switch($TimeSpan) {
+ Default {
+ $output = '{0} days' -f [System.Math]::Round($TimeSpan.TotalDays, 2)
+ }
+ {$PSItem.TotalHours -lt 24} {
+ $output = '{0} h' -f [System.Math]::Round($TimeSpan.TotalHours, 2)
+ }
+ {$PSItem.TotalMinutes -lt 120} {
+ $output = '{0} min' -f [System.Math]::Round($TimeSpan.TotalMinutes, 2)
+ }
+ {$PSItem.TotalSeconds -lt 120} {
+ $output = '{0} s' -f [System.Math]::Round($TimeSpan.TotalSeconds, 2)
+ }
+ {$PSItem.TotalMilliseconds -lt 10000} {
+ $output = '{0} ms' -f [System.Math]::Round($TimeSpan.TotalMilliseconds, 0)
+ }
+ }
+
+ Write-Output $output
+}
+function Join-Pong {
+ param (
+ [Parameter(Mandatory=$true)]
+ [string]
+ $RoomId,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $PingEventId,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $SenderMxId,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $ReadableTimespan,
+
+ [Parameter(Mandatory=$false)]
+ [string]
+ $Ball
+ )
+
+ if($Ball) {
+ $padded_ball = $Ball+' '
+ }
+
+ $body = '{0}: Pong! (ping {1}took {2} to arrive)' -f $SenderMxId,$padded_ball,$ReadableTimespan
+ $formatted_body = '{0}: Pong! ' -f $SenderMxId
+ $formatted_body += '(ping {2}took {3} to arrive)' -f $RoomId,$PingEventId,$padded_ball,$ReadableTimespan
+
+ return @{
+ Body = $body
+ FormattedBody = $formatted_body
+ }
+}
+function Open-MatrixEvent {
+ param (
+ [Parameter(Mandatory=$true)]
+ $Event,
+
+ [Parameter(Mandatory=$true)]
+ $RoomId
+ )
+
+ #the "ball" is a string returned by the bot
+ if($Event.content.msgtype -eq 'm.text' -and $Event.content.body -match '!ping( (?.*))?') {
+ $difference = Compare-Timestamps -OriginServerTs $Event.origin_server_ts
+ $readable_timespan = ConvertTo-HumanReadableTimespan -TimeSpan $difference
+
+ #$bodies contains a hashtable with keys Body and FormattedBody
+ $bodies = Join-Pong -RoomId $RoomId -PingEventId $Event.event_id -SenderMxId $Event.sender -ReadableTimespan $readable_timespan -Ball $Matches.ball
+
+ Send-MatrixNotice -RoomId $RoomId @bodies
+ }
+}
+function Start-MatrixSync {
+ param (
+ [string]
+ $Token,
+
+ [int]
+ $Timeout = 30000
+ )
+
+ $uri = '{0}/_matrix/client/r0/sync?timeout={1}' -f $HomeServer,$Timeout
+ if($Token) {
+ $uri += '&since={0}' -f $Token
+ }
+
+ $header_splat = @{
+ Authentication = 'Bearer'
+ Token = $AccessToken
+ ContentType = 'application/json'
+ }
+ $http_splat = @{
+ Uri = $uri
+ }
+
+ $response = Invoke-RestMethod @header_splat @http_splat
+
+ #.PSObject.Properties because the rooms under .join are [NoteProperty]
+ $room_ids = $response.rooms.join.PSObject.Properties.Name
+ foreach($room_id in $room_ids) {
+ $events = $response.rooms.join.$room_id.timeline.events
+ foreach($event in $events) {
+ Open-MatrixEvent -Event $event -RoomId $room_id
+ }
+ }
+
+ Write-Output $response.next_batch
+}
+
+#Send-MatrixNotice -RoomId '!amKUIaaKdERatZsJgB:matrix.org' -Message ('asef :) {0}' -f (Get-Date))
+
+#start sync loop
+while($true) {
+ #use the token of the last sync
+ #initial token is $null
+ $token = Start-MatrixSync -Token $token
+}
\ No newline at end of file