Add toUpdate function for sync V4
parent
c5d07f0a94
commit
632158f309
|
@ -967,6 +967,7 @@ toUnsigned : UnsignedData -> Event.UnsignedData
|
||||||
toUnsigned u =
|
toUnsigned u =
|
||||||
Event.UnsignedData
|
Event.UnsignedData
|
||||||
{ age = u.age
|
{ age = u.age
|
||||||
|
, membership = Nothing
|
||||||
, prevContent = Nothing
|
, prevContent = Nothing
|
||||||
, redactedBecause = Nothing
|
, redactedBecause = Nothing
|
||||||
, transactionId = u.transactionId
|
, transactionId = u.transactionId
|
||||||
|
|
|
@ -740,6 +740,7 @@ toUnsigned ev unsigned =
|
||||||
|
|
||||||
( Just e, Nothing ) ->
|
( Just e, Nothing ) ->
|
||||||
{ age = Nothing
|
{ age = Nothing
|
||||||
|
, membership = Nothing
|
||||||
, prevContent = Nothing
|
, prevContent = Nothing
|
||||||
, redactedBecause = Just e
|
, redactedBecause = Just e
|
||||||
, transactionId = Nothing
|
, transactionId = Nothing
|
||||||
|
@ -749,6 +750,7 @@ toUnsigned ev unsigned =
|
||||||
|
|
||||||
( _, Just (UnsignedData u) ) ->
|
( _, Just (UnsignedData u) ) ->
|
||||||
{ age = u.age
|
{ age = u.age
|
||||||
|
, membership = Nothing
|
||||||
, prevContent = u.prevContent
|
, prevContent = u.prevContent
|
||||||
, redactedBecause = ev
|
, redactedBecause = ev
|
||||||
, transactionId = u.transactionId
|
, transactionId = u.transactionId
|
||||||
|
|
|
@ -11,9 +11,19 @@ This API module represents the /sync endpoint on Matrix spec version v1.11.
|
||||||
|
|
||||||
-}
|
-}
|
||||||
|
|
||||||
import FastDict exposing (Dict)
|
import FastDict as Dict exposing (Dict)
|
||||||
import Internal.Api.Sync.V3 as PV
|
import Internal.Api.Sync.V3 as PV
|
||||||
|
import Internal.Config.Log exposing (Log, log)
|
||||||
|
import Internal.Config.Text as Text
|
||||||
|
import Internal.Filter.Timeline exposing (Filter)
|
||||||
import Internal.Tools.Json as Json
|
import Internal.Tools.Json as Json
|
||||||
|
import Internal.Tools.Timestamp as Timestamp exposing (Timestamp)
|
||||||
|
import Internal.Values.Envelope as E
|
||||||
|
import Internal.Values.Event as Event
|
||||||
|
import Internal.Values.Room as R
|
||||||
|
import Internal.Values.User as User exposing (User)
|
||||||
|
import Internal.Values.Vault as V
|
||||||
|
import Recursion
|
||||||
|
|
||||||
|
|
||||||
type alias SyncResponse =
|
type alias SyncResponse =
|
||||||
|
@ -60,7 +70,7 @@ type alias InviteState =
|
||||||
|
|
||||||
type alias StrippedStateEvent =
|
type alias StrippedStateEvent =
|
||||||
{ content : Json.Value
|
{ content : Json.Value
|
||||||
, sender : String
|
, sender : User
|
||||||
, stateKey : String
|
, stateKey : String
|
||||||
, eventType : String
|
, eventType : String
|
||||||
}
|
}
|
||||||
|
@ -88,8 +98,8 @@ type alias State =
|
||||||
type alias ClientEventWithoutRoomID =
|
type alias ClientEventWithoutRoomID =
|
||||||
{ content : Json.Value
|
{ content : Json.Value
|
||||||
, eventId : String
|
, eventId : String
|
||||||
, originServerTs : Int
|
, originServerTs : Timestamp
|
||||||
, sender : String
|
, sender : User
|
||||||
, stateKey : Maybe String
|
, stateKey : Maybe String
|
||||||
, eventType : String
|
, eventType : String
|
||||||
, unsigned : Maybe UnsignedData
|
, unsigned : Maybe UnsignedData
|
||||||
|
@ -159,7 +169,7 @@ type alias ToDevice =
|
||||||
|
|
||||||
type alias ToDeviceEvent =
|
type alias ToDeviceEvent =
|
||||||
{ content : Maybe Json.Value
|
{ content : Maybe Json.Value
|
||||||
, sender : Maybe String
|
, sender : Maybe User
|
||||||
, eventType : Maybe String
|
, eventType : Maybe String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,7 +381,7 @@ coderStrippedStateEvent =
|
||||||
{ fieldName = "sender"
|
{ fieldName = "sender"
|
||||||
, toField = .sender
|
, toField = .sender
|
||||||
, description = [ "The sender for the event." ]
|
, description = [ "The sender for the event." ]
|
||||||
, coder = Json.string
|
, coder = User.coder
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
(Json.field.required
|
(Json.field.required
|
||||||
|
@ -505,14 +515,14 @@ coderClientEventWithoutRoomID =
|
||||||
{ fieldName = "origin_server_ts"
|
{ fieldName = "origin_server_ts"
|
||||||
, toField = .originServerTs
|
, toField = .originServerTs
|
||||||
, description = [ "Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent." ]
|
, description = [ "Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent." ]
|
||||||
, coder = Json.int
|
, coder = Timestamp.coder
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
(Json.field.required
|
(Json.field.required
|
||||||
{ fieldName = "sender"
|
{ fieldName = "sender"
|
||||||
, toField = .sender
|
, toField = .sender
|
||||||
, description = [ "Contains the fully-qualified ID of the user who sent this event." ]
|
, description = [ "Contains the fully-qualified ID of the user who sent this event." ]
|
||||||
, coder = Json.string
|
, coder = User.coder
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
(Json.field.optional.value
|
(Json.field.optional.value
|
||||||
|
@ -815,7 +825,7 @@ coderToDeviceEvent =
|
||||||
{ fieldName = "sender"
|
{ fieldName = "sender"
|
||||||
, toField = .sender
|
, toField = .sender
|
||||||
, description = [ "The Matrix user ID of the user who sent this event." ]
|
, description = [ "The Matrix user ID of the user who sent this event." ]
|
||||||
, coder = Json.string
|
, coder = User.coder
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
(Json.field.optional.value
|
(Json.field.optional.value
|
||||||
|
@ -825,3 +835,194 @@ coderToDeviceEvent =
|
||||||
, coder = Json.string
|
, coder = Json.string
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
updateSyncResponse : { filter : Filter, since : Maybe String } -> SyncResponse -> ( E.EnvelopeUpdate V.VaultUpdate, List Log )
|
||||||
|
updateSyncResponse { filter, since } response =
|
||||||
|
-- Account data
|
||||||
|
[ response.accountData
|
||||||
|
|> Maybe.andThen .events
|
||||||
|
|> Maybe.map (List.map (\e -> V.SetAccountData e.eventType e.content))
|
||||||
|
|> Maybe.map
|
||||||
|
(\x ->
|
||||||
|
( E.ContentUpdate <| V.More x
|
||||||
|
, if List.length x > 0 then
|
||||||
|
List.length x
|
||||||
|
|> Text.logs.syncAccountDataFound
|
||||||
|
|> log.debug
|
||||||
|
|> List.singleton
|
||||||
|
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
-- TODO: Add device lists
|
||||||
|
-- Next batch
|
||||||
|
, Just ( E.SetNextBatch response.nextBatch, [] )
|
||||||
|
|
||||||
|
-- TODO: Add presence
|
||||||
|
-- Rooms
|
||||||
|
, Maybe.map
|
||||||
|
(updateRooms { filter = filter, nextBatch = response.nextBatch, since = since }
|
||||||
|
>> Tuple.mapFirst E.ContentUpdate
|
||||||
|
)
|
||||||
|
response.rooms
|
||||||
|
|
||||||
|
-- TODO: Add to_device
|
||||||
|
]
|
||||||
|
|> List.filterMap identity
|
||||||
|
|> List.unzip
|
||||||
|
|> Tuple.mapFirst E.More
|
||||||
|
|> Tuple.mapSecond List.concat
|
||||||
|
|
||||||
|
|
||||||
|
updateRooms : { filter : Filter, nextBatch : String, since : Maybe String } -> Rooms -> ( V.VaultUpdate, List Log )
|
||||||
|
updateRooms { filter, nextBatch, since } rooms =
|
||||||
|
let
|
||||||
|
( roomUpdate, roomLogs ) =
|
||||||
|
rooms.join
|
||||||
|
|> Maybe.withDefault Dict.empty
|
||||||
|
|> Dict.toList
|
||||||
|
|> List.map
|
||||||
|
(\( roomId, room ) ->
|
||||||
|
let
|
||||||
|
( u, l ) =
|
||||||
|
updateJoinedRoom
|
||||||
|
{ filter = filter
|
||||||
|
, nextBatch = nextBatch
|
||||||
|
, roomId = roomId
|
||||||
|
, since = since
|
||||||
|
}
|
||||||
|
room
|
||||||
|
in
|
||||||
|
( V.MapRoom roomId u, l )
|
||||||
|
)
|
||||||
|
|> List.unzip
|
||||||
|
|> Tuple.mapBoth V.More List.concat
|
||||||
|
in
|
||||||
|
( V.More
|
||||||
|
-- Add rooms
|
||||||
|
[ rooms.join
|
||||||
|
|> Maybe.withDefault Dict.empty
|
||||||
|
|> Dict.keys
|
||||||
|
|> List.map V.CreateRoomIfNotExists
|
||||||
|
|> V.More
|
||||||
|
|
||||||
|
-- Update rooms
|
||||||
|
, roomUpdate
|
||||||
|
|
||||||
|
-- TODO: Add invited rooms
|
||||||
|
-- TODO: Add knocked rooms
|
||||||
|
-- TODO: Add left rooms
|
||||||
|
]
|
||||||
|
, roomLogs
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
updateJoinedRoom : { filter : Filter, nextBatch : String, roomId : String, since : Maybe String } -> JoinedRoom -> ( R.RoomUpdate, List Log )
|
||||||
|
updateJoinedRoom data room =
|
||||||
|
( R.More
|
||||||
|
[ room.accountData
|
||||||
|
|> Maybe.andThen .events
|
||||||
|
|> Maybe.map
|
||||||
|
(\events ->
|
||||||
|
events
|
||||||
|
|> List.map (\e -> R.SetAccountData e.eventType e.content)
|
||||||
|
|> R.More
|
||||||
|
)
|
||||||
|
|> R.Optional
|
||||||
|
, room.ephemeral
|
||||||
|
|> Maybe.andThen .events
|
||||||
|
|> Maybe.map R.SetEphemeral
|
||||||
|
|> R.Optional
|
||||||
|
|
||||||
|
-- TODO: Add state
|
||||||
|
-- TODO: Add RoomSummary
|
||||||
|
, room.timeline
|
||||||
|
|> Maybe.map (updateTimeline data)
|
||||||
|
|> R.Optional
|
||||||
|
|
||||||
|
-- TODO: Add unread notifications
|
||||||
|
-- TODO: Add unread thread notifications
|
||||||
|
]
|
||||||
|
, []
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
updateTimeline : { filter : Filter, nextBatch : String, roomId : String, since : Maybe String } -> Timeline -> R.RoomUpdate
|
||||||
|
updateTimeline { filter, nextBatch, roomId, since } timeline =
|
||||||
|
R.AddSync
|
||||||
|
{ events = List.map (toEvent roomId) timeline.events
|
||||||
|
, filter = filter
|
||||||
|
, start =
|
||||||
|
case timeline.prevBatch of
|
||||||
|
Just _ ->
|
||||||
|
timeline.prevBatch
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
since
|
||||||
|
, end = nextBatch
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
toEvent : String -> ClientEventWithoutRoomID -> Event.Event
|
||||||
|
toEvent roomId event =
|
||||||
|
Recursion.runRecursion
|
||||||
|
(\ev ->
|
||||||
|
case Maybe.andThen (\(UnsignedData u) -> u.redactedBecause) ev.unsigned of
|
||||||
|
Just e ->
|
||||||
|
Recursion.recurseThen e
|
||||||
|
(\eo ->
|
||||||
|
Recursion.base
|
||||||
|
{ content = ev.content
|
||||||
|
, eventId = ev.eventId
|
||||||
|
, originServerTs = ev.originServerTs
|
||||||
|
, roomId = roomId
|
||||||
|
, sender = ev.sender
|
||||||
|
, stateKey = ev.stateKey
|
||||||
|
, eventType = ev.eventType
|
||||||
|
, unsigned = toUnsigned (Just eo) ev.unsigned
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
Recursion.base
|
||||||
|
{ content = ev.content
|
||||||
|
, eventId = ev.eventId
|
||||||
|
, originServerTs = ev.originServerTs
|
||||||
|
, roomId = roomId
|
||||||
|
, sender = ev.sender
|
||||||
|
, stateKey = ev.stateKey
|
||||||
|
, eventType = ev.eventType
|
||||||
|
, unsigned = toUnsigned Nothing ev.unsigned
|
||||||
|
}
|
||||||
|
)
|
||||||
|
event
|
||||||
|
|
||||||
|
|
||||||
|
toUnsigned : Maybe Event.Event -> Maybe UnsignedData -> Maybe Event.UnsignedData
|
||||||
|
toUnsigned ev unsigned =
|
||||||
|
case ( ev, unsigned ) of
|
||||||
|
( Nothing, Nothing ) ->
|
||||||
|
Nothing
|
||||||
|
|
||||||
|
( Just e, Nothing ) ->
|
||||||
|
{ age = Nothing
|
||||||
|
, membership = Nothing
|
||||||
|
, prevContent = Nothing
|
||||||
|
, redactedBecause = Just e
|
||||||
|
, transactionId = Nothing
|
||||||
|
}
|
||||||
|
|> Event.UnsignedData
|
||||||
|
|> Just
|
||||||
|
|
||||||
|
( _, Just (UnsignedData u) ) ->
|
||||||
|
{ age = u.age
|
||||||
|
, membership = Nothing
|
||||||
|
, prevContent = u.prevContent
|
||||||
|
, redactedBecause = ev
|
||||||
|
, transactionId = u.transactionId
|
||||||
|
}
|
||||||
|
|> Event.UnsignedData
|
||||||
|
|> Just
|
||||||
|
|
|
@ -348,6 +348,7 @@ fields :
|
||||||
}
|
}
|
||||||
, unsigned :
|
, unsigned :
|
||||||
{ age : Desc
|
{ age : Desc
|
||||||
|
, membership : Desc
|
||||||
, prevContent : Desc
|
, prevContent : Desc
|
||||||
, redactedBecause : Desc
|
, redactedBecause : Desc
|
||||||
, transactionId : Desc
|
, transactionId : Desc
|
||||||
|
@ -563,6 +564,9 @@ fields =
|
||||||
{ age =
|
{ age =
|
||||||
[ "The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is."
|
[ "The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is."
|
||||||
]
|
]
|
||||||
|
, membership =
|
||||||
|
[ "The room membership of the user making the request, at the time of the event."
|
||||||
|
]
|
||||||
, prevContent =
|
, prevContent =
|
||||||
[ "The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content."
|
[ "The previous content for this event. This field is generated by the local homeserver, and is only returned if the event is a state event, and the client has permission to see the previous content."
|
||||||
]
|
]
|
||||||
|
|
|
@ -59,6 +59,7 @@ helper functions.
|
||||||
type UnsignedData
|
type UnsignedData
|
||||||
= UnsignedData
|
= UnsignedData
|
||||||
{ age : Maybe Int
|
{ age : Maybe Int
|
||||||
|
, membership : Maybe String
|
||||||
, prevContent : Maybe Json.Value
|
, prevContent : Maybe Json.Value
|
||||||
, redactedBecause : Maybe Event
|
, redactedBecause : Maybe Event
|
||||||
, transactionId : Maybe String
|
, transactionId : Maybe String
|
||||||
|
@ -242,10 +243,10 @@ transactionId event =
|
||||||
|
|
||||||
unsignedCoder : Json.Coder UnsignedData
|
unsignedCoder : Json.Coder UnsignedData
|
||||||
unsignedCoder =
|
unsignedCoder =
|
||||||
Json.object4
|
Json.object5
|
||||||
{ name = Text.docs.unsigned.name
|
{ name = Text.docs.unsigned.name
|
||||||
, description = Text.docs.unsigned.description
|
, description = Text.docs.unsigned.description
|
||||||
, init = \a b c d -> UnsignedData { age = a, prevContent = b, redactedBecause = c, transactionId = d }
|
, init = \a b c d e -> UnsignedData { age = a, membership = b, prevContent = c, redactedBecause = d, transactionId = e }
|
||||||
}
|
}
|
||||||
(Json.field.optional.value
|
(Json.field.optional.value
|
||||||
{ fieldName = "age"
|
{ fieldName = "age"
|
||||||
|
@ -254,6 +255,13 @@ unsignedCoder =
|
||||||
, coder = Json.int
|
, coder = Json.int
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
(Json.field.optional.value
|
||||||
|
{ fieldName = "membership"
|
||||||
|
, toField = \(UnsignedData data) -> data.membership
|
||||||
|
, description = Text.fields.unsigned.membership
|
||||||
|
, coder = Json.string
|
||||||
|
}
|
||||||
|
)
|
||||||
(Json.field.optional.value
|
(Json.field.optional.value
|
||||||
{ fieldName = "prevContent"
|
{ fieldName = "prevContent"
|
||||||
, toField = \(UnsignedData data) -> data.prevContent
|
, toField = \(UnsignedData data) -> data.prevContent
|
||||||
|
|
Loading…
Reference in New Issue