From ce83d1260f94bf0e48b45b6ff1707bd1f126c147 Mon Sep 17 00:00:00 2001 From: Bram van den Heuvel Date: Fri, 22 Dec 2023 16:59:45 +0100 Subject: [PATCH] Add reader functions for Event types --- src/Internal/Values/Event.elm | 154 +++++++++++++++++++++++++++++----- src/Types.elm | 11 ++- 2 files changed, 142 insertions(+), 23 deletions(-) diff --git a/src/Internal/Values/Event.elm b/src/Internal/Values/Event.elm index fb78c02..15743d5 100644 --- a/src/Internal/Values/Event.elm +++ b/src/Internal/Values/Event.elm @@ -1,5 +1,6 @@ module Internal.Values.Event exposing ( Event + , content, eventId, eventType, originServerTs, roomId, sender, stateKey , UnsignedData, age, prevContent, redactedBecause, transactionId , encode, decoder ) @@ -15,6 +16,11 @@ of a room. @docs Event +## Get information + +@docs content, eventId, eventType, originServerTs, roomId, sender, stateKey + + ## Unsigned data @docs UnsignedData, age, prevContent, redactedBecause, transactionId @@ -30,6 +36,7 @@ import Internal.Config.Default as Default import Internal.Tools.Decode as D import Internal.Tools.Encode as E import Internal.Tools.Timestamp as Timestamp exposing (Timestamp) +import Internal.Values.Envelope as Envelope import Json.Decode as D import Json.Encode as E @@ -37,6 +44,10 @@ import Json.Encode as E {-| The Event type occurs everywhere on a user's timeline. -} type alias Event = + Envelope.Envelope IEvent + + +type alias IEvent = { content : E.Value , eventId : String , originServerTs : Timestamp @@ -63,15 +74,30 @@ type UnsignedData {-| Get the event's age, if at all provided by the homeserver. -} age : Event -> Maybe Int -age event = - Maybe.andThen (\(UnsignedData data) -> data.age) event.unsigned +age envelope = + Envelope.extract + (\event -> + Maybe.andThen + (\(UnsignedData data) -> data.age) + event.unsigned + ) + envelope + + +{-| The Matrix protocol revolves around users being able to send each other +JSON objects. This function reveals the JSON value that the user has sent to +the room. +-} +content : Event -> E.Value +content = + Envelope.extract .content {-| Decode an Event from a JSON value. -} decoder : D.Decoder Event decoder = - D.map8 Event + D.map8 IEvent (D.field "content" D.value) (D.field "eventId" D.string) (D.field "originServerTs" Timestamp.decoder) @@ -80,6 +106,7 @@ decoder = (D.opField "stateKey" D.string) (D.field "eventType" D.string) (D.opField "unsigned" decoderUnsignedData) + |> Envelope.decoder {-| Decode Unsigned Data from a JSON value. @@ -96,18 +123,22 @@ decoderUnsignedData = {-| Encode an Event into a JSON value. -} encode : Event -> E.Value -encode event = - E.maybeObject - [ ( "content", Just event.content ) - , ( "eventId", Just <| E.string event.eventId ) - , ( "originServerTs", Just <| Timestamp.encode event.originServerTs ) - , ( "roomId", Just <| E.string event.roomId ) - , ( "sender", Just <| E.string event.sender ) - , ( "stateKey", Maybe.map E.string event.stateKey ) - , ( "eventType", Just <| E.string event.eventType ) - , ( "unsigned", Maybe.map encodeUnsignedData event.unsigned ) - , ( "version", Just <| E.string Default.currentVersion ) - ] +encode envelope = + Envelope.encode + (\event -> + E.maybeObject + [ ( "content", Just event.content ) + , ( "eventId", Just <| E.string event.eventId ) + , ( "originServerTs", Just <| Timestamp.encode event.originServerTs ) + , ( "roomId", Just <| E.string event.roomId ) + , ( "sender", Just <| E.string event.sender ) + , ( "stateKey", Maybe.map E.string event.stateKey ) + , ( "eventType", Just <| E.string event.eventType ) + , ( "unsigned", Maybe.map encodeUnsignedData event.unsigned ) + , ( "version", Just <| E.string Default.currentVersion ) + ] + ) + envelope {-| Encode Unsigned Data into a JSON value. @@ -122,24 +153,105 @@ encodeUnsignedData (UnsignedData data) = ] +{-| Every event is assigned a unique id in the room. You can use this event id +to reference or look up events. +-} +eventId : Event -> String +eventId = + Envelope.extract .eventId + + +{-| To give a hint what the event's [content](#content) might look like, users +can use this eventType value to hint at how the JSON might be decoded. + +Standard examples of event types are `m.room.message`, `m.room.member` and +`me.noordstar.game.chess.move`. + +-} +eventType : Event -> String +eventType = + Envelope.extract .eventType + + +{-| Timestamp of at what time the event was originally received by the original +homeserver. + +Generally, this timestamp offers a relalatively accurate indicator of when a +message was sent. However, this number isn't completely reliable! The timestamp +can be far in the past due to long network lag, and a (malicious) homeserver can +spoof this number to make it seem like something was sent ridiculously far in +the past - or even in the future. + +-} +originServerTs : Event -> Timestamp +originServerTs = + Envelope.extract .originServerTs + + {-| Get the old content, if the event has changed or it has been edited. -} prevContent : Event -> Maybe E.Value -prevContent event = - Maybe.andThen (\(UnsignedData data) -> data.prevContent) event.unsigned +prevContent envelope = + Envelope.extract + (\event -> + Maybe.andThen + (\(UnsignedData data) -> data.prevContent) + event.unsigned + ) + envelope {-| If the event has been redacted, the homeserver can display the event that redacted it here. -} redactedBecause : Event -> Maybe Event -redactedBecause event = - Maybe.andThen (\(UnsignedData data) -> data.redactedBecause) event.unsigned +redactedBecause envelope = + Envelope.extract + (\event -> + Maybe.andThen + (\(UnsignedData data) -> data.redactedBecause) + event.unsigned + ) + envelope + + +{-| Unique id assigned to the Matrix room. You can use this room id to reference +or look up rooms. +-} +roomId : Event -> String +roomId = + Envelope.extract .roomId + + +{-| User id of the user that sent this event. You can use this user id to +reference or look up users. +-} +sender : Event -> String +sender = + Envelope.extract .sender + + +{-| When an event's state key is `Nothing`, it is an ordinary message event in +the timeline. + +When the state key is `Just ""` or some other `Just string`, then it is a state +event that affects how the room works. TODO: Explain state events. + +-} +stateKey : Event -> Maybe String +stateKey = + Envelope.extract .stateKey {-| If the user has sent this event to the homeserver, then the homeserver might display the original transaction id used for the event. -} transactionId : Event -> Maybe String -transactionId event = - Maybe.andThen (\(UnsignedData data) -> data.transactionId) event.unsigned +transactionId envelope = + Envelope.extract + (\event -> + Maybe.andThen + (\(UnsignedData data) -> data.transactionId) + event.unsigned + ) + envelope diff --git a/src/Types.elm b/src/Types.elm index 022835b..36da9e0 100644 --- a/src/Types.elm +++ b/src/Types.elm @@ -1,4 +1,4 @@ -module Types exposing (Vault(..)) +module Types exposing (Vault(..), Event(..)) {-| The Elm SDK uses a lot of records and values that are easy to manipulate. Yet, the [Elm design guidelines](https://package.elm-lang.org/help/design-guidelines#keep-tags-and-record-constructors-secret) @@ -12,13 +12,20 @@ access their content directly. The opaque types are placed in a central module so all exposed modules can safely access all exposed data types without risking to create circular imports. -@docs Vault +@docs Vault, Event -} +import Internal.Values.Event as Event import Internal.Values.Vault as Vault +{-| Opaque type for Matrix Event +-} +type Event + = Event Event.Event + + {-| Opaque type for Matrix Vault -} type Vault