replace email processing reactions; update deps
This commit is contained in:
116
vendor/gitlab.com/etke.cc/linkpearl/.golangci.yml
generated
vendored
116
vendor/gitlab.com/etke.cc/linkpearl/.golangci.yml
generated
vendored
@@ -1,85 +1,132 @@
|
||||
run:
|
||||
concurrency: 4
|
||||
timeout: 5m
|
||||
timeout: 30m
|
||||
issues-exit-code: 1
|
||||
tests: true
|
||||
build-tags: []
|
||||
skip-dirs: []
|
||||
skip-dirs-use-default: true
|
||||
skip-files: []
|
||||
modules-download-mode: readonly
|
||||
allow-parallel-runners: false
|
||||
|
||||
output:
|
||||
format: colored-line-number
|
||||
formats:
|
||||
- format: colored-line-number
|
||||
print-issued-lines: true
|
||||
print-linter-name: true
|
||||
uniq-by-line: true
|
||||
path-prefix: ""
|
||||
sort-results: true
|
||||
|
||||
linters-settings:
|
||||
decorder:
|
||||
dec-order:
|
||||
- const
|
||||
- var
|
||||
- type
|
||||
- func
|
||||
dogsled:
|
||||
max-blank-identifiers: 3
|
||||
errcheck:
|
||||
check-type-assertions: true
|
||||
check-blank: true
|
||||
gci:
|
||||
local-prefixes: gitlab.com/etke.cc/linkpearl
|
||||
errchkjson:
|
||||
report-no-exported: true
|
||||
exhaustive:
|
||||
check:
|
||||
- switch
|
||||
- map
|
||||
default-signifies-exhaustive: true
|
||||
gocognit:
|
||||
min-complexity: 10
|
||||
min-complexity: 15
|
||||
nestif:
|
||||
min-complexity: 4
|
||||
min-complexity: 5
|
||||
gocritic:
|
||||
enabled-tags:
|
||||
- diagnostic
|
||||
- style
|
||||
- performance
|
||||
gofmt:
|
||||
simplify: true
|
||||
rewrite-rules:
|
||||
- pattern: 'interface{}'
|
||||
replacement: 'any'
|
||||
- pattern: 'a[b:len(a)]'
|
||||
replacement: 'a[b:]'
|
||||
gofumpt:
|
||||
lang-version: "1.19"
|
||||
goimports:
|
||||
local-prefixes: gitlab.com/etke.cc/linkpearl
|
||||
gosimple:
|
||||
go: "1.19"
|
||||
checks: [ "all" ]
|
||||
govet:
|
||||
check-shadowing: true
|
||||
enable:
|
||||
- atomicalign
|
||||
- shadow
|
||||
extra-rules: true
|
||||
grouper:
|
||||
const-require-single-const: true
|
||||
import-require-single-import: true
|
||||
var-require-single-var: true
|
||||
misspell:
|
||||
locale: US
|
||||
staticcheck:
|
||||
go: "1.19"
|
||||
checks: [ "all" ]
|
||||
stylecheck:
|
||||
go: "1.19"
|
||||
usestdlibvars:
|
||||
time-month: true
|
||||
time-layout: true
|
||||
crypto-hash: true
|
||||
default-rpc-path: true
|
||||
os-dev-null: true
|
||||
sql-isolation-level: true
|
||||
tls-signature-scheme: true
|
||||
constant-kind: true
|
||||
unparam:
|
||||
check-exported: true
|
||||
unused:
|
||||
go: "1.19"
|
||||
linters:
|
||||
disable-all: false
|
||||
enable:
|
||||
- megacheck
|
||||
- govet
|
||||
- asasalint
|
||||
- asciicheck
|
||||
- bidichk
|
||||
- bodyclose
|
||||
- containedctx
|
||||
- decorder
|
||||
- dogsled
|
||||
- dupl
|
||||
- dupword
|
||||
- durationcheck
|
||||
- errcheck
|
||||
- gci
|
||||
- errchkjson
|
||||
- errname
|
||||
- errorlint
|
||||
- execinquery
|
||||
- exhaustive
|
||||
- exportloopref
|
||||
- forcetypeassert
|
||||
- gocognit
|
||||
- nestif
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- gofmt
|
||||
- gofumpt
|
||||
- goimports
|
||||
- gosec
|
||||
- gosimple
|
||||
- gosmopolitan
|
||||
- govet
|
||||
- ineffassign
|
||||
- makezero
|
||||
- mirror
|
||||
- misspell
|
||||
- nestif
|
||||
- nolintlint
|
||||
- prealloc
|
||||
- predeclared
|
||||
- revive
|
||||
- sqlclosecheck
|
||||
- staticcheck
|
||||
- stylecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- usestdlibvars
|
||||
- wastedassign
|
||||
fast: false
|
||||
|
||||
|
||||
issues:
|
||||
exclude-dirs:
|
||||
- mocks
|
||||
exclude-rules:
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- gocyclo
|
||||
- gocognit
|
||||
- errcheck
|
||||
- dupl
|
||||
- gosec
|
||||
@@ -89,6 +136,9 @@ issues:
|
||||
- linters:
|
||||
- lll
|
||||
source: "^//go:generate "
|
||||
- linters:
|
||||
- revive
|
||||
text: "returns unexported type"
|
||||
max-issues-per-linter: 0
|
||||
max-same-issues: 0
|
||||
new: false
|
||||
|
||||
48
vendor/gitlab.com/etke.cc/linkpearl/events.go
generated
vendored
48
vendor/gitlab.com/etke.cc/linkpearl/events.go
generated
vendored
@@ -15,6 +15,12 @@ type RespThreads struct {
|
||||
NextBatch string `json:"next_batch"`
|
||||
}
|
||||
|
||||
// RespRelations is response of https://spec.matrix.org/v1.8/client-server-api/#get_matrixclientv1roomsroomidrelationseventidreltype
|
||||
type RespRelations struct {
|
||||
Chunk []*event.Event `json:"chunk"`
|
||||
NextBatch string `json:"next_batch"`
|
||||
}
|
||||
|
||||
// Threads endpoint, ref: https://spec.matrix.org/v1.8/client-server-api/#get_matrixclientv1roomsroomidthreads
|
||||
func (l *Linkpearl) Threads(ctx context.Context, roomID id.RoomID, fromToken ...string) (*RespThreads, error) {
|
||||
var from string
|
||||
@@ -33,8 +39,26 @@ func (l *Linkpearl) Threads(ctx context.Context, roomID id.RoomID, fromToken ...
|
||||
return resp, UnwrapError(err)
|
||||
}
|
||||
|
||||
// Relations returns all relations of the given type for the given event
|
||||
func (l *Linkpearl) Relations(ctx context.Context, roomID id.RoomID, eventID id.EventID, relType string, fromToken ...string) (*RespRelations, error) {
|
||||
var from string
|
||||
if len(fromToken) > 0 {
|
||||
from = fromToken[0]
|
||||
}
|
||||
|
||||
query := map[string]string{
|
||||
"from": from,
|
||||
"limit": "100",
|
||||
}
|
||||
|
||||
var resp *RespRelations
|
||||
urlPath := l.GetClient().BuildURLWithQuery(mautrix.ClientURLPath{"v1", "rooms", roomID, "relations", eventID, relType}, query)
|
||||
_, err := l.GetClient().MakeRequest(ctx, "GET", urlPath, nil, &resp)
|
||||
return resp, UnwrapError(err)
|
||||
}
|
||||
|
||||
// FindThreadBy tries to find thread message event by field and value
|
||||
func (l *Linkpearl) FindThreadBy(ctx context.Context, roomID id.RoomID, field, value string, fromToken ...string) *event.Event {
|
||||
func (l *Linkpearl) FindThreadBy(ctx context.Context, roomID id.RoomID, fieldValue map[string]string, fromToken ...string) *event.Event {
|
||||
var from string
|
||||
if len(fromToken) > 0 {
|
||||
from = fromToken[0]
|
||||
@@ -48,9 +72,11 @@ func (l *Linkpearl) FindThreadBy(ctx context.Context, roomID id.RoomID, field, v
|
||||
}
|
||||
|
||||
for _, msg := range resp.Chunk {
|
||||
evt, contains := l.eventContains(ctx, msg, field, value)
|
||||
if contains {
|
||||
return evt
|
||||
for field, value := range fieldValue {
|
||||
evt, contains := l.eventContains(ctx, msg, field, value)
|
||||
if contains {
|
||||
return evt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,11 +84,11 @@ func (l *Linkpearl) FindThreadBy(ctx context.Context, roomID id.RoomID, field, v
|
||||
return nil
|
||||
}
|
||||
|
||||
return l.FindThreadBy(ctx, roomID, field, value, resp.NextBatch)
|
||||
return l.FindThreadBy(ctx, roomID, fieldValue, resp.NextBatch)
|
||||
}
|
||||
|
||||
// FindEventBy tries to find message event by field and value
|
||||
func (l *Linkpearl) FindEventBy(ctx context.Context, roomID id.RoomID, field, value string, fromToken ...string) *event.Event {
|
||||
func (l *Linkpearl) FindEventBy(ctx context.Context, roomID id.RoomID, fieldValue map[string]string, fromToken ...string) *event.Event {
|
||||
var from string
|
||||
if len(fromToken) > 0 {
|
||||
from = fromToken[0]
|
||||
@@ -76,9 +102,11 @@ func (l *Linkpearl) FindEventBy(ctx context.Context, roomID id.RoomID, field, va
|
||||
}
|
||||
|
||||
for _, msg := range resp.Chunk {
|
||||
evt, contains := l.eventContains(ctx, msg, field, value)
|
||||
if contains {
|
||||
return evt
|
||||
for field, value := range fieldValue {
|
||||
evt, contains := l.eventContains(ctx, msg, field, value)
|
||||
if contains {
|
||||
return evt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +114,7 @@ func (l *Linkpearl) FindEventBy(ctx context.Context, roomID id.RoomID, field, va
|
||||
return nil
|
||||
}
|
||||
|
||||
return l.FindEventBy(ctx, roomID, field, value, resp.End)
|
||||
return l.FindEventBy(ctx, roomID, fieldValue, resp.End)
|
||||
}
|
||||
|
||||
func (l *Linkpearl) eventContains(ctx context.Context, evt *event.Event, field, value string) (*event.Event, bool) {
|
||||
|
||||
18
vendor/gitlab.com/etke.cc/linkpearl/linkpearl.go
generated
vendored
18
vendor/gitlab.com/etke.cc/linkpearl/linkpearl.go
generated
vendored
@@ -21,6 +21,8 @@ const (
|
||||
DefaultAccountDataCache = 1000
|
||||
// DefaultEventsLimit for methods like lp.Threads() and lp.FindEventBy()
|
||||
DefaultEventsLimit = 1000
|
||||
// DefaultTypingTimeout in seconds for typing notifications
|
||||
DefaultTypingTimeout = 60
|
||||
)
|
||||
|
||||
// Linkpearl object
|
||||
@@ -104,7 +106,7 @@ func New(cfg *Config) (*Linkpearl, error) {
|
||||
return nil, err
|
||||
}
|
||||
lp.ch.LoginAs = cfg.LoginAs()
|
||||
if err = lp.ch.Init(context.Background()); err != nil {
|
||||
if err := lp.ch.Init(context.Background()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lp.api.Crypto = lp.ch
|
||||
@@ -140,33 +142,33 @@ func (l *Linkpearl) SetPresence(ctx context.Context, presence event.Presence, me
|
||||
return err
|
||||
}
|
||||
|
||||
// SetJoinPermit sets the the join permit callback function
|
||||
// SetJoinPermit sets the join permit callback function
|
||||
func (l *Linkpearl) SetJoinPermit(value func(context.Context, *event.Event) bool) {
|
||||
l.joinPermit = value
|
||||
}
|
||||
|
||||
// Start performs matrix /sync
|
||||
func (l *Linkpearl) Start(optionalStatusMsg ...string) error {
|
||||
func (l *Linkpearl) Start(ctx context.Context, optionalStatusMsg ...string) error {
|
||||
l.initSync()
|
||||
var statusMsg string
|
||||
if len(optionalStatusMsg) > 0 {
|
||||
statusMsg = optionalStatusMsg[0]
|
||||
}
|
||||
|
||||
err := l.SetPresence(context.Background(), event.PresenceOnline, statusMsg)
|
||||
err := l.SetPresence(ctx, event.PresenceOnline, statusMsg)
|
||||
if err != nil {
|
||||
l.log.Error().Err(err).Msg("cannot set presence")
|
||||
}
|
||||
defer l.Stop()
|
||||
defer l.Stop(ctx)
|
||||
|
||||
l.log.Info().Msg("client has been started")
|
||||
return l.api.Sync()
|
||||
return l.api.SyncWithContext(ctx)
|
||||
}
|
||||
|
||||
// Stop the client
|
||||
func (l *Linkpearl) Stop() {
|
||||
func (l *Linkpearl) Stop(ctx context.Context) {
|
||||
l.log.Debug().Msg("stopping the client")
|
||||
if err := l.api.SetPresence(context.Background(), event.PresenceOffline); err != nil {
|
||||
if err := l.api.SetPresence(ctx, event.PresenceOffline); err != nil {
|
||||
l.log.Error().Err(err).Msg("cannot set presence")
|
||||
}
|
||||
l.api.StopSync()
|
||||
|
||||
71
vendor/gitlab.com/etke.cc/linkpearl/reactions.go
generated
vendored
Normal file
71
vendor/gitlab.com/etke.cc/linkpearl/reactions.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
package linkpearl
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// reactionPrefix is the prefix for all reaction in account data
|
||||
const reactionPrefix = "cc.etke.linkpearl.reaction."
|
||||
|
||||
// SendReaction sends a reaction to a message
|
||||
func (l *Linkpearl) SendReaction(ctx context.Context, roomID id.RoomID, eventID id.EventID, reaction string) error {
|
||||
// Check if the reaction already exists
|
||||
if l.getReactionAD(ctx, roomID, eventID, reaction) != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
resp, err := l.GetClient().SendReaction(ctx, roomID, eventID, reaction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return l.updateReactionsAD(ctx, roomID, eventID, reaction, resp.EventID)
|
||||
}
|
||||
|
||||
// RedactReaction redacts a reaction from a message
|
||||
func (l *Linkpearl) RedactReaction(ctx context.Context, roomID id.RoomID, eventID id.EventID, reaction string) error {
|
||||
existingID := l.getReactionAD(ctx, roomID, eventID, reaction)
|
||||
// Check if the reaction already exists
|
||||
if existingID == "" {
|
||||
return nil
|
||||
}
|
||||
if _, err := l.GetClient().RedactEvent(ctx, roomID, id.EventID(existingID)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return l.updateReactionsAD(ctx, roomID, eventID, reaction, "")
|
||||
}
|
||||
|
||||
// ReplaceReaction replaces a reaction with another
|
||||
func (l *Linkpearl) ReplaceReaction(ctx context.Context, roomID id.RoomID, eventID id.EventID, oldReaction, newReaction string) error {
|
||||
if err := l.RedactReaction(ctx, roomID, eventID, oldReaction); err != nil {
|
||||
return err
|
||||
}
|
||||
return l.SendReaction(ctx, roomID, eventID, newReaction)
|
||||
}
|
||||
|
||||
func (l *Linkpearl) getReactionAD(ctx context.Context, roomID id.RoomID, eventID id.EventID, reaction string) string {
|
||||
adID := reactionPrefix + eventID.String()
|
||||
existing, err := l.GetRoomAccountData(ctx, roomID, adID)
|
||||
if err != nil {
|
||||
l.log.Error().Err(err).Msg("failed to get existing reactions")
|
||||
return ""
|
||||
}
|
||||
return existing[reaction]
|
||||
}
|
||||
|
||||
func (l *Linkpearl) updateReactionsAD(ctx context.Context, roomID id.RoomID, eventID id.EventID, reaction string, reactionID id.EventID) error {
|
||||
adID := reactionPrefix + eventID.String()
|
||||
existing, err := l.GetRoomAccountData(ctx, roomID, adID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if reactionID == "" {
|
||||
delete(existing, reaction)
|
||||
} else {
|
||||
existing[reaction] = reactionID.String()
|
||||
}
|
||||
return l.SetRoomAccountData(ctx, roomID, adID, existing)
|
||||
}
|
||||
15
vendor/gitlab.com/etke.cc/linkpearl/send.go
generated
vendored
15
vendor/gitlab.com/etke.cc/linkpearl/send.go
generated
vendored
@@ -2,6 +2,7 @@ package linkpearl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/event"
|
||||
@@ -12,7 +13,7 @@ import (
|
||||
// Send a message to the roomID and automatically try to encrypt it, if the destination room is encrypted
|
||||
//
|
||||
//nolint:unparam // it's public interface
|
||||
func (l *Linkpearl) Send(ctx context.Context, roomID id.RoomID, content interface{}) (id.EventID, error) {
|
||||
func (l *Linkpearl) Send(ctx context.Context, roomID id.RoomID, content any) (id.EventID, error) {
|
||||
l.log.Debug().Str("roomID", roomID.String()).Any("content", content).Msg("sending event")
|
||||
resp, err := l.api.SendMessageEvent(ctx, roomID, event.EventMessage, content)
|
||||
if err != nil {
|
||||
@@ -21,6 +22,18 @@ func (l *Linkpearl) Send(ctx context.Context, roomID id.RoomID, content interfac
|
||||
return resp.EventID, nil
|
||||
}
|
||||
|
||||
// SendTyping notification
|
||||
func (l *Linkpearl) SendTyping(ctx context.Context, roomID id.RoomID, typing bool, timeout ...int) {
|
||||
ttl := DefaultTypingTimeout
|
||||
if len(timeout) > 0 {
|
||||
ttl = timeout[0]
|
||||
}
|
||||
_, err := l.api.UserTyping(ctx, roomID, typing, time.Duration(ttl)*time.Second)
|
||||
if err != nil {
|
||||
l.log.Warn().Err(err).Bool("typing", typing).Msg("cannot set typing")
|
||||
}
|
||||
}
|
||||
|
||||
// SendNotice to a room with optional relations, markdown supported
|
||||
func (l *Linkpearl) SendNotice(ctx context.Context, roomID id.RoomID, message string, relates ...*event.RelatesTo) {
|
||||
var withRelatesTo bool
|
||||
|
||||
10
vendor/gitlab.com/etke.cc/linkpearl/sync.go
generated
vendored
10
vendor/gitlab.com/etke.cc/linkpearl/sync.go
generated
vendored
@@ -13,27 +13,27 @@ import (
|
||||
// OnEventType allows callers to be notified when there are new events for the given event type.
|
||||
// There are no duplicate checks.
|
||||
func (l *Linkpearl) OnEventType(eventType event.Type, callback mautrix.EventHandler) {
|
||||
l.api.Syncer.(mautrix.ExtensibleSyncer).OnEventType(eventType, callback)
|
||||
l.api.Syncer.(mautrix.ExtensibleSyncer).OnEventType(eventType, callback) //nolint:forcetypeassert // we know it's an ExtensibleSyncer
|
||||
}
|
||||
|
||||
// OnSync shortcut to mautrix.DefaultSyncer.OnSync
|
||||
func (l *Linkpearl) OnSync(callback mautrix.SyncHandler) {
|
||||
l.api.Syncer.(mautrix.ExtensibleSyncer).OnSync(callback)
|
||||
l.api.Syncer.(mautrix.ExtensibleSyncer).OnSync(callback) //nolint:forcetypeassert // we know it's an ExtensibleSyncer
|
||||
}
|
||||
|
||||
// OnEvent shortcut to mautrix.DefaultSyncer.OnEvent
|
||||
func (l *Linkpearl) OnEvent(callback mautrix.EventHandler) {
|
||||
l.api.Syncer.(mautrix.ExtensibleSyncer).OnEvent(callback)
|
||||
l.api.Syncer.(mautrix.ExtensibleSyncer).OnEvent(callback) //nolint:forcetypeassert // we know it's an ExtensibleSyncer
|
||||
}
|
||||
|
||||
func (l *Linkpearl) initSync() {
|
||||
l.api.Syncer.(mautrix.ExtensibleSyncer).OnEventType(
|
||||
l.api.Syncer.(mautrix.ExtensibleSyncer).OnEventType( //nolint:forcetypeassert // we know it's an ExtensibleSyncer
|
||||
event.StateEncryption,
|
||||
func(ctx context.Context, evt *event.Event) {
|
||||
go l.onEncryption(ctx, evt)
|
||||
},
|
||||
)
|
||||
l.api.Syncer.(mautrix.ExtensibleSyncer).OnEventType(
|
||||
l.api.Syncer.(mautrix.ExtensibleSyncer).OnEventType( //nolint:forcetypeassert // we know it's an ExtensibleSyncer
|
||||
event.StateMember,
|
||||
func(ctx context.Context, evt *event.Event) {
|
||||
go l.onMembership(ctx, evt)
|
||||
|
||||
30
vendor/gitlab.com/etke.cc/linkpearl/utils.go
generated
vendored
30
vendor/gitlab.com/etke.cc/linkpearl/utils.go
generated
vendored
@@ -1,6 +1,8 @@
|
||||
package linkpearl
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/event"
|
||||
@@ -120,26 +122,12 @@ func ParseContent(evt *event.Event, log *zerolog.Logger) {
|
||||
|
||||
// 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
|
||||
var httpErr mautrix.HTTPError
|
||||
if errors.As(err, &httpErr) {
|
||||
uwerr := httpErr.Unwrap()
|
||||
if uwerr != nil {
|
||||
return uwerr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func unwrapHTTPError(err error) error {
|
||||
httperr, ok := err.(mautrix.HTTPError)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
||||
uwerr := httperr.Unwrap()
|
||||
if uwerr != nil {
|
||||
return uwerr
|
||||
}
|
||||
|
||||
return httperr
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user