Add toUpdate function for sync V1 - V3
							parent
							
								
									b239eecc6b
								
							
						
					
					
						commit
						c5d07f0a94
					
				| 
						 | 
				
			
			@ -12,12 +12,16 @@ This API module represents the /sync endpoint on Matrix spec version v1.1.
 | 
			
		|||
-}
 | 
			
		||||
 | 
			
		||||
import FastDict as Dict exposing (Dict)
 | 
			
		||||
import Internal.Config.Log exposing (Log)
 | 
			
		||||
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.StrippedEvent as StrippedEvent exposing (StrippedEvent)
 | 
			
		||||
import Internal.Tools.StrippedEvent as StrippedEvent
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -64,7 +68,7 @@ type alias InviteState =
 | 
			
		|||
 | 
			
		||||
type alias StrippedState =
 | 
			
		||||
    { content : Json.Value
 | 
			
		||||
    , sender : String
 | 
			
		||||
    , sender : User
 | 
			
		||||
    , stateKey : String
 | 
			
		||||
    , eventType : String
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -93,7 +97,7 @@ type alias SyncStateEvent =
 | 
			
		|||
    , eventId : String
 | 
			
		||||
    , originServerTs : Timestamp
 | 
			
		||||
    , prevContent : Maybe Json.Value
 | 
			
		||||
    , sender : String
 | 
			
		||||
    , sender : User
 | 
			
		||||
    , stateKey : String
 | 
			
		||||
    , eventType : String
 | 
			
		||||
    , unsigned : Maybe UnsignedData
 | 
			
		||||
| 
						 | 
				
			
			@ -125,7 +129,7 @@ type alias SyncRoomEvent =
 | 
			
		|||
    { content : Json.Value
 | 
			
		||||
    , eventId : String
 | 
			
		||||
    , originServerTs : Timestamp
 | 
			
		||||
    , sender : String
 | 
			
		||||
    , sender : User
 | 
			
		||||
    , eventType : String
 | 
			
		||||
    , unsigned : Maybe UnsignedData
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -164,7 +168,7 @@ type alias ToDevice =
 | 
			
		|||
 | 
			
		||||
type alias ToDeviceEvent =
 | 
			
		||||
    { content : Maybe Json.Value
 | 
			
		||||
    , sender : Maybe String
 | 
			
		||||
    , sender : Maybe User
 | 
			
		||||
    , eventType : Maybe String
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -351,7 +355,7 @@ coderStrippedState =
 | 
			
		|||
            { fieldName = "sender"
 | 
			
		||||
            , toField = .sender
 | 
			
		||||
            , description = [ "The sender for the event." ]
 | 
			
		||||
            , coder = Json.string
 | 
			
		||||
            , coder = User.coder
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        (Json.field.required
 | 
			
		||||
| 
						 | 
				
			
			@ -492,7 +496,7 @@ coderSyncStateEvent =
 | 
			
		|||
            { fieldName = "sender"
 | 
			
		||||
            , toField = .sender
 | 
			
		||||
            , description = [ "Contains the fully-qualified ID of the user who sent this event." ]
 | 
			
		||||
            , coder = Json.string
 | 
			
		||||
            , coder = User.coder
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        (Json.field.required
 | 
			
		||||
| 
						 | 
				
			
			@ -640,7 +644,7 @@ coderSyncRoomEvent =
 | 
			
		|||
            { fieldName = "sender"
 | 
			
		||||
            , toField = .sender
 | 
			
		||||
            , description = [ "Contains the fully-qualified ID of the user who sent this event." ]
 | 
			
		||||
            , coder = Json.string
 | 
			
		||||
            , coder = User.coder
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        (Json.field.required
 | 
			
		||||
| 
						 | 
				
			
			@ -801,7 +805,7 @@ coderToDeviceEvent =
 | 
			
		|||
            { fieldName = "sender"
 | 
			
		||||
            , toField = .sender
 | 
			
		||||
            , description = [ "The Matrix user ID of the user who sent this event." ]
 | 
			
		||||
            , coder = Json.string
 | 
			
		||||
            , coder = User.coder
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        (Json.field.optional.value
 | 
			
		||||
| 
						 | 
				
			
			@ -813,16 +817,37 @@ coderToDeviceEvent =
 | 
			
		|||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
updateSyncResponse : SyncResponse -> ( E.EnvelopeUpdate V.VaultUpdate, List Log )
 | 
			
		||||
updateSyncResponse response =
 | 
			
		||||
    -- TODO: Add account data
 | 
			
		||||
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, [] )
 | 
			
		||||
    , Just ( E.SetNextBatch response.nextBatch, [] )
 | 
			
		||||
 | 
			
		||||
    -- TODO: Add presence
 | 
			
		||||
    -- Rooms
 | 
			
		||||
    , Maybe.map (updateRooms >> Tuple.mapFirst E.ContentUpdate) response.rooms
 | 
			
		||||
    , Maybe.map
 | 
			
		||||
        (updateRooms { filter = filter, nextBatch = response.nextBatch, since = since }
 | 
			
		||||
            >> Tuple.mapFirst E.ContentUpdate
 | 
			
		||||
        )
 | 
			
		||||
        response.rooms
 | 
			
		||||
 | 
			
		||||
    -- TODO: Add to_device
 | 
			
		||||
    ]
 | 
			
		||||
| 
						 | 
				
			
			@ -832,8 +857,8 @@ updateSyncResponse response =
 | 
			
		|||
        |> Tuple.mapSecond List.concat
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
updateRooms : Rooms -> ( V.VaultUpdate, List Log )
 | 
			
		||||
updateRooms rooms =
 | 
			
		||||
updateRooms : { filter : Filter, nextBatch : String, since : Maybe String } -> Rooms -> ( V.VaultUpdate, List Log )
 | 
			
		||||
updateRooms { filter, nextBatch, since } rooms =
 | 
			
		||||
    let
 | 
			
		||||
        ( roomUpdate, roomLogs ) =
 | 
			
		||||
            rooms.join
 | 
			
		||||
| 
						 | 
				
			
			@ -843,7 +868,13 @@ updateRooms rooms =
 | 
			
		|||
                    (\( roomId, room ) ->
 | 
			
		||||
                        let
 | 
			
		||||
                            ( u, l ) =
 | 
			
		||||
                                updateJoinedRoom room
 | 
			
		||||
                                updateJoinedRoom
 | 
			
		||||
                                    { filter = filter
 | 
			
		||||
                                    , nextBatch = nextBatch
 | 
			
		||||
                                    , roomId = roomId
 | 
			
		||||
                                    , since = since
 | 
			
		||||
                                    }
 | 
			
		||||
                                    room
 | 
			
		||||
                        in
 | 
			
		||||
                        ( V.MapRoom roomId u, l )
 | 
			
		||||
                    )
 | 
			
		||||
| 
						 | 
				
			
			@ -869,8 +900,8 @@ updateRooms rooms =
 | 
			
		|||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
updateJoinedRoom : JoinedRoom -> ( R.RoomUpdate, List Log )
 | 
			
		||||
updateJoinedRoom room =
 | 
			
		||||
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
 | 
			
		||||
| 
						 | 
				
			
			@ -888,8 +919,55 @@ updateJoinedRoom room =
 | 
			
		|||
 | 
			
		||||
        -- TODO: Add state
 | 
			
		||||
        -- TODO: Add RoomSummary
 | 
			
		||||
        -- TODO: Add timeline
 | 
			
		||||
        , room.timeline
 | 
			
		||||
            |> Maybe.andThen
 | 
			
		||||
                (updateTimeline data)
 | 
			
		||||
            |> R.Optional
 | 
			
		||||
 | 
			
		||||
        -- TODO: Add unread notifications
 | 
			
		||||
        ]
 | 
			
		||||
    , []
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
updateTimeline : { filter : Filter, nextBatch : String, roomId : String, since : Maybe String } -> Timeline -> Maybe R.RoomUpdate
 | 
			
		||||
updateTimeline { filter, nextBatch, roomId, since } timeline =
 | 
			
		||||
    timeline.events
 | 
			
		||||
        |> Maybe.map
 | 
			
		||||
            (\events ->
 | 
			
		||||
                R.AddSync
 | 
			
		||||
                    { events = List.map (toEvent roomId) events
 | 
			
		||||
                    , filter = filter
 | 
			
		||||
                    , start =
 | 
			
		||||
                        case timeline.prevBatch of
 | 
			
		||||
                            Just _ ->
 | 
			
		||||
                                timeline.prevBatch
 | 
			
		||||
 | 
			
		||||
                            Nothing ->
 | 
			
		||||
                                since
 | 
			
		||||
                    , end = nextBatch
 | 
			
		||||
                    }
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
toEvent : String -> SyncRoomEvent -> Event.Event
 | 
			
		||||
toEvent roomId event =
 | 
			
		||||
    { content = event.content
 | 
			
		||||
    , eventId = event.eventId
 | 
			
		||||
    , originServerTs = event.originServerTs
 | 
			
		||||
    , roomId = roomId
 | 
			
		||||
    , sender = event.sender
 | 
			
		||||
    , stateKey = Nothing
 | 
			
		||||
    , eventType = event.eventType
 | 
			
		||||
    , unsigned = Maybe.map toUnsigned event.unsigned
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
toUnsigned : UnsignedData -> Event.UnsignedData
 | 
			
		||||
toUnsigned u =
 | 
			
		||||
    Event.UnsignedData
 | 
			
		||||
        { age = u.age
 | 
			
		||||
        , prevContent = Nothing
 | 
			
		||||
        , redactedBecause = Nothing
 | 
			
		||||
        , transactionId = u.transactionId
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,9 +13,19 @@ v1.3.
 | 
			
		|||
 | 
			
		||||
-}
 | 
			
		||||
 | 
			
		||||
import FastDict exposing (Dict)
 | 
			
		||||
import FastDict as Dict exposing (Dict)
 | 
			
		||||
import Internal.Api.Sync.V1 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.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 =
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +72,7 @@ type alias InviteState =
 | 
			
		|||
 | 
			
		||||
type alias StrippedStateEvent =
 | 
			
		||||
    { content : Json.Value
 | 
			
		||||
    , sender : String
 | 
			
		||||
    , sender : User
 | 
			
		||||
    , stateKey : String
 | 
			
		||||
    , eventType : String
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -89,8 +99,8 @@ type alias State =
 | 
			
		|||
type alias ClientEventWithoutRoomID =
 | 
			
		||||
    { content : Json.Value
 | 
			
		||||
    , eventId : String
 | 
			
		||||
    , originServerTs : Int
 | 
			
		||||
    , sender : String
 | 
			
		||||
    , originServerTs : Timestamp
 | 
			
		||||
    , sender : User
 | 
			
		||||
    , stateKey : Maybe String
 | 
			
		||||
    , eventType : String
 | 
			
		||||
    , unsigned : Maybe UnsignedData
 | 
			
		||||
| 
						 | 
				
			
			@ -153,7 +163,7 @@ type alias ToDevice =
 | 
			
		|||
 | 
			
		||||
type alias ToDeviceEvent =
 | 
			
		||||
    { content : Maybe Json.Value
 | 
			
		||||
    , sender : Maybe String
 | 
			
		||||
    , sender : Maybe User
 | 
			
		||||
    , eventType : Maybe String
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -387,14 +397,14 @@ coderClientEventWithoutRoomID =
 | 
			
		|||
            { fieldName = "origin_server_ts"
 | 
			
		||||
            , toField = .originServerTs
 | 
			
		||||
            , description = [ "Required: Timestamp (in milliseconds since the unix epoch) on originating homeserver when this event was sent." ]
 | 
			
		||||
            , coder = Json.int
 | 
			
		||||
            , coder = Timestamp.coder
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        (Json.field.required
 | 
			
		||||
            { fieldName = "sender"
 | 
			
		||||
            , toField = .sender
 | 
			
		||||
            , description = [ "Required: Contains the fully-qualified ID of the user who sent this event." ]
 | 
			
		||||
            , coder = Json.string
 | 
			
		||||
            , coder = User.coder
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        (Json.field.optional.value
 | 
			
		||||
| 
						 | 
				
			
			@ -557,3 +567,191 @@ coderToDevice =
 | 
			
		|||
coderToDeviceEvent : Json.Coder ToDeviceEvent
 | 
			
		||||
coderToDeviceEvent =
 | 
			
		||||
    PV.coderToDeviceEvent
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
        ]
 | 
			
		||||
    , []
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
            , prevContent = Nothing
 | 
			
		||||
            , redactedBecause = Just e
 | 
			
		||||
            , transactionId = Nothing
 | 
			
		||||
            }
 | 
			
		||||
                |> Event.UnsignedData
 | 
			
		||||
                |> Just
 | 
			
		||||
 | 
			
		||||
        ( _, Just (UnsignedData u) ) ->
 | 
			
		||||
            { age = u.age
 | 
			
		||||
            , prevContent = u.prevContent
 | 
			
		||||
            , redactedBecause = ev
 | 
			
		||||
            , transactionId = u.transactionId
 | 
			
		||||
            }
 | 
			
		||||
                |> Event.UnsignedData
 | 
			
		||||
                |> Just
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,9 +18,18 @@ versions:
 | 
			
		|||
 | 
			
		||||
-}
 | 
			
		||||
 | 
			
		||||
import FastDict exposing (Dict)
 | 
			
		||||
import FastDict as Dict exposing (Dict)
 | 
			
		||||
import Internal.Api.Sync.V2 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.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 exposing (User)
 | 
			
		||||
import Internal.Values.Vault as V
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
type alias SyncResponse =
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +76,7 @@ type alias InviteState =
 | 
			
		|||
 | 
			
		||||
type alias StrippedStateEvent =
 | 
			
		||||
    { content : Json.Value
 | 
			
		||||
    , sender : String
 | 
			
		||||
    , sender : User
 | 
			
		||||
    , stateKey : String
 | 
			
		||||
    , eventType : String
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -95,8 +104,8 @@ type alias State =
 | 
			
		|||
type alias ClientEventWithoutRoomID =
 | 
			
		||||
    { content : Json.Value
 | 
			
		||||
    , eventId : String
 | 
			
		||||
    , originServerTs : Int
 | 
			
		||||
    , sender : String
 | 
			
		||||
    , originServerTs : Timestamp
 | 
			
		||||
    , sender : User
 | 
			
		||||
    , stateKey : Maybe String
 | 
			
		||||
    , eventType : String
 | 
			
		||||
    , unsigned : Maybe UnsignedData
 | 
			
		||||
| 
						 | 
				
			
			@ -160,7 +169,7 @@ type alias ToDevice =
 | 
			
		|||
 | 
			
		||||
type alias ToDeviceEvent =
 | 
			
		||||
    { content : Maybe Json.Value
 | 
			
		||||
    , sender : Maybe String
 | 
			
		||||
    , sender : Maybe User
 | 
			
		||||
    , eventType : Maybe String
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -441,3 +450,131 @@ coderToDevice =
 | 
			
		|||
coderToDeviceEvent : Json.Coder ToDeviceEvent
 | 
			
		||||
coderToDeviceEvent =
 | 
			
		||||
    PV.coderToDeviceEvent
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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 =
 | 
			
		||||
    PV.updateTimeline
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
toEvent : String -> ClientEventWithoutRoomID -> Event.Event
 | 
			
		||||
toEvent =
 | 
			
		||||
    PV.toEvent
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
toUnsigned : Maybe Event.Event -> Maybe UnsignedData -> Maybe Event.UnsignedData
 | 
			
		||||
toUnsigned =
 | 
			
		||||
    PV.toUnsigned
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -638,6 +638,7 @@ logs :
 | 
			
		|||
    , sendEvent : Maybe String -> String
 | 
			
		||||
    , serverReturnedInvalidJSON : String -> String
 | 
			
		||||
    , serverReturnedUnknownJSON : String -> String
 | 
			
		||||
    , syncAccountDataFound : Int -> String
 | 
			
		||||
    }
 | 
			
		||||
logs =
 | 
			
		||||
    { baseUrlFound =
 | 
			
		||||
| 
						 | 
				
			
			@ -675,6 +676,8 @@ logs =
 | 
			
		|||
                    "Sent event, event id not known - make sure to check transaction id"
 | 
			
		||||
    , serverReturnedInvalidJSON = (++) "The server returned invalid JSON: "
 | 
			
		||||
    , serverReturnedUnknownJSON = (++) "The server returned JSON that doesn't seem to live up to spec rules: "
 | 
			
		||||
    , syncAccountDataFound =
 | 
			
		||||
        \n -> String.concat [ "Found ", String.fromInt n, " account data updates" ]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue