From 1a819cbe3957aa085439859f9f47127c015388bf Mon Sep 17 00:00:00 2001 From: Bram Date: Sun, 24 Dec 2023 00:03:07 +0100 Subject: [PATCH] Add exposed Event module --- elm.json | 1 + src/Internal/Values/Event.elm | 50 ++++++------ src/Matrix/Event.elm | 142 ++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+), 23 deletions(-) create mode 100644 src/Matrix/Event.elm diff --git a/elm.json b/elm.json index f2c7767..72bead6 100644 --- a/elm.json +++ b/elm.json @@ -6,6 +6,7 @@ "version": "2.0.0", "exposed-modules": [ "Matrix", + "Matrix.Event", "Matrix.Settings", "Internal.Config.Default", "Internal.Config.Leaks", diff --git a/src/Internal/Values/Event.elm b/src/Internal/Values/Event.elm index e0ad27f..954e935 100644 --- a/src/Internal/Values/Event.elm +++ b/src/Internal/Values/Event.elm @@ -66,7 +66,7 @@ type UnsignedData = UnsignedData { age : Maybe Int , prevContent : Maybe E.Value - , redactedBecause : Maybe Event + , redactedBecause : Maybe IEvent , transactionId : Maybe String } @@ -95,6 +95,11 @@ content = -} decoder : D.Decoder Event decoder = + Envelope.decoder decoderInternal + + +decoderInternal : D.Decoder IEvent +decoderInternal = D.map8 IEvent (D.field "content" D.value) (D.field "eventId" D.string) @@ -104,7 +109,6 @@ decoder = (D.opField "stateKey" D.string) (D.field "eventType" D.string) (D.opField "unsigned" decoderUnsignedData) - |> Envelope.decoder {-| Decode Unsigned Data from a JSON value. @@ -114,29 +118,30 @@ decoderUnsignedData = D.map4 (\a b c d -> UnsignedData { age = a, prevContent = b, redactedBecause = c, transactionId = d }) (D.opField "age" D.int) (D.opField "prevContent" D.value) - (D.opField "redactedBecause" (D.lazy (\_ -> decoder))) + (D.opField "redactedBecause" (D.lazy (\_ -> decoderInternal))) (D.opField "transactionId" D.string) {-| Encode an Event into a JSON value. -} encode : Event -> E.Value -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 = + Envelope.encode encodeInternal + + +encodeInternal : IEvent -> E.Value +encodeInternal 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 Unsigned Data into a JSON value. @@ -146,7 +151,7 @@ encodeUnsignedData (UnsignedData data) = E.maybeObject [ ( "age", Maybe.map E.int data.age ) , ( "prevContent", data.prevContent ) - , ( "redactedBecause", Maybe.map encode data.redactedBecause ) + , ( "redactedBecause", Maybe.map encodeInternal data.redactedBecause ) , ( "transactionId", Maybe.map E.string data.transactionId ) ] @@ -204,14 +209,13 @@ prevContent envelope = redacted it here. -} redactedBecause : Event -> Maybe Event -redactedBecause envelope = - Envelope.extract +redactedBecause = + Envelope.mapMaybe (\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 diff --git a/src/Matrix/Event.elm b/src/Matrix/Event.elm new file mode 100644 index 0000000..016df69 --- /dev/null +++ b/src/Matrix/Event.elm @@ -0,0 +1,142 @@ +module Matrix.Event exposing + ( Event, content, eventType, stateKey + , eventId, originServerTs, roomId, sender + , previousContent, redactedBecause + ) + +{-| + + +# Matrix Events + +This module contains all the functions necessary to view and manipulate Matrix +events. + + +## Event + +@docs Event, content, eventType, stateKey + + +## Metadata + +@docs eventId, originServerTs, roomId, sender + + +## Optional data + +Occasionally, the Event might bring some extra information. Given how this +information isn't always applicable, it doesn't always exist. + +@docs previousContent, redactedBecause + +-} + +import Internal.Values.Event as Internal +import Json.Encode +import Time +import Types exposing (Event(..)) + + +{-| In Matrix, the primary form of communication is to send JSON values to one +another. These JSON values, together with their metadata, are bundled into Event +types. They contain information like: + + - Who sent the JSON value + - How they intend you to decode it + - When they sent it + - In what room they sent it + +-} +type alias Event = + Types.Event + + +{-| Receive the body of an Event, as created by the user that sent it. +-} +content : Event -> Json.Encode.Value +content (Event event) = + Internal.content event + + +{-| Determine the globally unique identifier for an event. +-} +eventId : Event -> String +eventId (Event event) = + Internal.eventId event + + +{-| 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 (Event event) = + Internal.eventType event + + +{-| Determine the timestamp of at what time the event was originally received by +the original homeserver. + +Generally, this timestamp offers a relatively 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 -> Time.Posix +originServerTs (Event event) = + Internal.originServerTs event + + +{-| Determine the previous `content` value for this event. This field is only a +`Just value` if the event is a state event, and the Matrix Vault has permission +to see the previous content. +-} +previousContent : Event -> Maybe Json.Encode.Value +previousContent (Event event) = + Internal.prevContent event + + +{-| If the event has been redacted, the homeserver can display the event that +redacted it here. +-} +redactedBecause : Event -> Maybe Event +redactedBecause (Event event) = + Internal.redactedBecause event + |> Maybe.map Event + + +{-| Unique id assigned to the Matrix room. You can use this room id to reference +or look up rooms. +-} +roomId : Event -> String +roomId (Event event) = + Internal.roomId event + + +{-| Determine the fully-qualified ID of the user who sent an event. +-} +sender : Event -> String +sender (Event event) = + Internal.sender event + + +{-| Determine an event's state key. + +It is present if, and only if, the event is a _state_ event. The key makes the +piece of state unique in the room. Note that it is often `Just ""`. If it is not +present, its value is `Nothing`. + +State keys starting with an `@` are reserved for referencing user IDs, such as +room members. With the exception of a few events, state events set with a given +user'd ID as the state key can only be set by that user. + +-} +stateKey : Event -> Maybe String +stateKey (Event event) = + Internal.stateKey event