150 lines
3.2 KiB
Go
150 lines
3.2 KiB
Go
package linkpearl
|
|
|
|
import (
|
|
"github.com/rs/zerolog"
|
|
"maunium.net/go/mautrix"
|
|
"maunium.net/go/mautrix/event"
|
|
"maunium.net/go/mautrix/id"
|
|
)
|
|
|
|
// EventRelatesTo uses evt as source for EventParent() and RelatesTo()
|
|
func EventRelatesTo(evt *event.Event) *event.RelatesTo {
|
|
ParseContent(evt, nil)
|
|
relatable, ok := evt.Content.Parsed.(event.Relatable)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
|
|
return RelatesTo(EventParent(evt.ID, relatable))
|
|
}
|
|
|
|
// RelatesTo returns relation object of a matrix event (either threads with reply-to fallback or plain reply-to)
|
|
func RelatesTo(parentID id.EventID, noThreads ...bool) *event.RelatesTo {
|
|
if parentID == "" {
|
|
return nil
|
|
}
|
|
|
|
var nothreads bool
|
|
if len(noThreads) > 0 {
|
|
nothreads = noThreads[0]
|
|
}
|
|
|
|
if nothreads {
|
|
return &event.RelatesTo{
|
|
InReplyTo: &event.InReplyTo{
|
|
EventID: parentID,
|
|
},
|
|
}
|
|
}
|
|
|
|
return &event.RelatesTo{
|
|
Type: event.RelThread,
|
|
EventID: parentID,
|
|
InReplyTo: &event.InReplyTo{
|
|
EventID: parentID,
|
|
},
|
|
IsFallingBack: true,
|
|
}
|
|
}
|
|
|
|
// GetParent is nil-safe version of evt.Content.AsMessage().RelatesTo.(GetThreadParent()|GetReplyTo())
|
|
func GetParent(evt *event.Event) id.EventID {
|
|
ParseContent(evt, nil)
|
|
content, ok := evt.Content.Parsed.(event.Relatable)
|
|
if !ok {
|
|
return ""
|
|
}
|
|
|
|
relation := content.GetRelatesTo()
|
|
if relation == nil {
|
|
return ""
|
|
}
|
|
|
|
if parentID := relation.GetThreadParent(); parentID != "" {
|
|
return parentID
|
|
}
|
|
if parentID := relation.GetReplyTo(); parentID != "" {
|
|
return parentID
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
// EventParent returns parent event ID (either from thread or from reply-to relation), like GetRelatesTo(), but with content and default return value
|
|
func EventParent(currentID id.EventID, content event.Relatable) id.EventID {
|
|
if parentID := GetParent(&event.Event{Content: event.Content{Parsed: content}}); parentID != "" {
|
|
return parentID
|
|
}
|
|
|
|
return currentID
|
|
}
|
|
|
|
// EventContains checks if raw event content contains specified field with specified values
|
|
func EventContains[T comparable](evt *event.Event, field string, value T) bool {
|
|
if evt.Content.Raw == nil {
|
|
return false
|
|
}
|
|
if EventField[T](&evt.Content, field) != value {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// EventField returns field value from raw event content
|
|
func EventField[T comparable](content *event.Content, field string) T {
|
|
var zero T
|
|
raw, ok := content.Raw[field]
|
|
if !ok {
|
|
return zero
|
|
}
|
|
|
|
if raw == nil {
|
|
return zero
|
|
}
|
|
|
|
v, ok := raw.(T)
|
|
if !ok {
|
|
return zero
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
// ParseContent parses event content according to evt.Type
|
|
func ParseContent(evt *event.Event, log *zerolog.Logger) {
|
|
if evt.Content.Parsed != nil {
|
|
return
|
|
}
|
|
perr := evt.Content.ParseRaw(evt.Type)
|
|
if perr != nil && log != nil {
|
|
log.Error().Err(perr).Msg("cannot parse event content")
|
|
}
|
|
}
|
|
|
|
// UnwrapError tries to unwrap a error into something meaningful, like mautrix.HTTPError or mautrix.RespError
|
|
func UnwrapError(err error) error {
|
|
switch err.(type) {
|
|
case nil:
|
|
return nil
|
|
case mautrix.HTTPError:
|
|
return unwrapHTTPError(err)
|
|
default:
|
|
return err
|
|
}
|
|
}
|
|
|
|
func unwrapHTTPError(err error) error {
|
|
httperr, ok := err.(mautrix.HTTPError)
|
|
if !ok {
|
|
return err
|
|
}
|
|
|
|
uwerr := httperr.Unwrap()
|
|
if uwerr != nil {
|
|
return uwerr
|
|
}
|
|
|
|
return httperr
|
|
}
|