replace email processing reactions; update deps
This commit is contained in:
@@ -135,15 +135,10 @@ func (b *Bot) Start(statusMsg string) error {
|
|||||||
|
|
||||||
b.initSync()
|
b.initSync()
|
||||||
b.log.Info().Msg("Postmoogle has been started")
|
b.log.Info().Msg("Postmoogle has been started")
|
||||||
return b.lp.Start(statusMsg)
|
return b.lp.Start(ctx, statusMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the bot
|
// Stop the bot
|
||||||
func (b *Bot) Stop() {
|
func (b *Bot) Stop() {
|
||||||
ctx := context.Background()
|
b.lp.Stop(context.Background())
|
||||||
err := b.lp.GetClient().SetPresence(ctx, event.PresenceOffline)
|
|
||||||
if err != nil {
|
|
||||||
b.log.Error().Err(err).Msg("cannot set presence = offline")
|
|
||||||
}
|
|
||||||
b.lp.GetClient().StopSync()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -624,7 +624,6 @@ func (b *Bot) runSendCommand(ctx context.Context, cfg config.Room, tos []string,
|
|||||||
from := cfg.Mailbox() + "@" + domain
|
from := cfg.Mailbox() + "@" + domain
|
||||||
ID := email.MessageID(evt.ID, domain)
|
ID := email.MessageID(evt.ID, domain)
|
||||||
for _, to := range tos {
|
for _, to := range tos {
|
||||||
recipients := []string{to}
|
|
||||||
eml := email.New(ID, "", " "+ID, subject, from, to, to, "", body, htmlBody, nil, nil)
|
eml := email.New(ID, "", " "+ID, subject, from, to, to, "", body, htmlBody, nil, nil)
|
||||||
data := eml.Compose(b.cfg.GetBot(ctx).DKIMPrivateKey())
|
data := eml.Compose(b.cfg.GetBot(ctx).DKIMPrivateKey())
|
||||||
if data == "" {
|
if data == "" {
|
||||||
@@ -634,14 +633,14 @@ func (b *Bot) runSendCommand(ctx context.Context, cfg config.Room, tos []string,
|
|||||||
queued, err := b.Sendmail(ctx, evt.ID, from, to, data)
|
queued, err := b.Sendmail(ctx, evt.ID, from, to, data)
|
||||||
if queued {
|
if queued {
|
||||||
b.log.Warn().Err(err).Msg("email has been queued")
|
b.log.Warn().Err(err).Msg("email has been queued")
|
||||||
b.saveSentMetadata(ctx, queued, evt.ID, recipients, eml, cfg)
|
b.saveSentMetadata(ctx, queued, evt.ID, to, eml, cfg)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Error(ctx, "cannot send email to %s: %v", to, err)
|
b.Error(ctx, "cannot send email to %s: %v", to, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
b.saveSentMetadata(ctx, false, evt.ID, recipients, eml, cfg)
|
b.saveSentMetadata(ctx, false, evt.ID, to, eml, cfg)
|
||||||
}
|
}
|
||||||
if len(tos) > 1 {
|
if len(tos) > 1 {
|
||||||
b.lp.SendNotice(ctx, evt.RoomID, "All emails were sent.", linkpearl.RelatesTo(evt.ID, cfg.NoThreads()))
|
b.lp.SendNotice(ctx, evt.RoomID, "All emails were sent.", linkpearl.RelatesTo(evt.ID, cfg.NoThreads()))
|
||||||
|
|||||||
15
bot/email.go
15
bot/email.go
@@ -280,7 +280,7 @@ func (b *Bot) sendAutoreply(ctx context.Context, roomID id.RoomID, threadID id.E
|
|||||||
queued, err = b.Sendmail(ctx, evt.ID, meta.From, to, data)
|
queued, err = b.Sendmail(ctx, evt.ID, meta.From, to, data)
|
||||||
if queued {
|
if queued {
|
||||||
b.log.Info().Err(err).Str("from", meta.From).Str("to", to).Msg("email has been queued")
|
b.log.Info().Err(err).Str("from", meta.From).Str("to", to).Msg("email has been queued")
|
||||||
b.saveSentMetadata(ctx, queued, meta.ThreadID, recipients, eml, cfg, "Autoreply has been sent to "+to+" (queued)")
|
b.saveSentMetadata(ctx, queued, meta.ThreadID, to, eml, cfg, "Autoreply has been sent to "+to+" (queued)")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,7 +289,7 @@ func (b *Bot) sendAutoreply(ctx context.Context, roomID id.RoomID, threadID id.E
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
b.saveSentMetadata(ctx, queued, meta.ThreadID, recipients, eml, cfg, "Autoreply has been sent to "+to)
|
b.saveSentMetadata(ctx, queued, meta.ThreadID, to, eml, cfg, "Autoreply has been sent to "+to)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,7 +364,7 @@ func (b *Bot) SendEmailReply(ctx context.Context) {
|
|||||||
queued, err = b.Sendmail(ctx, evt.ID, meta.From, to, data)
|
queued, err = b.Sendmail(ctx, evt.ID, meta.From, to, data)
|
||||||
if queued {
|
if queued {
|
||||||
b.log.Info().Err(err).Str("from", meta.From).Str("to", to).Msg("email has been queued")
|
b.log.Info().Err(err).Str("from", meta.From).Str("to", to).Msg("email has been queued")
|
||||||
b.saveSentMetadata(ctx, queued, meta.ThreadID, recipients, eml, cfg)
|
b.saveSentMetadata(ctx, queued, meta.ThreadID, to, eml, cfg)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,7 +373,7 @@ func (b *Bot) SendEmailReply(ctx context.Context) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
b.saveSentMetadata(ctx, queued, meta.ThreadID, recipients, eml, cfg)
|
b.saveSentMetadata(ctx, queued, meta.ThreadID, to, eml, cfg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,11 +538,10 @@ func (b *Bot) getParentEmail(ctx context.Context, evt *event.Event, newFromMailb
|
|||||||
|
|
||||||
// saveSentMetadata used to save metadata from !pm sent and thread reply events to a separate notice message
|
// saveSentMetadata used to save metadata from !pm sent and thread reply events to a separate notice message
|
||||||
// because that metadata is needed to determine email thread relations
|
// because that metadata is needed to determine email thread relations
|
||||||
func (b *Bot) saveSentMetadata(ctx context.Context, queued bool, threadID id.EventID, recipients []string, eml *email.Email, cfg config.Room, textOverride ...string) {
|
func (b *Bot) saveSentMetadata(ctx context.Context, queued bool, threadID id.EventID, to string, eml *email.Email, cfg config.Room, textOverride ...string) {
|
||||||
addrs := strings.Join(recipients, ", ")
|
text := "Email has been sent to " + to
|
||||||
text := "Email has been sent to " + addrs
|
|
||||||
if queued {
|
if queued {
|
||||||
text = "Email to " + addrs + " has been queued"
|
text = "Email to " + to + " has been queued"
|
||||||
}
|
}
|
||||||
if len(textOverride) > 0 {
|
if len(textOverride) > 0 {
|
||||||
text = textOverride[0]
|
text = textOverride[0]
|
||||||
|
|||||||
26
bot/mutex.go
26
bot/mutex.go
@@ -6,26 +6,22 @@ import (
|
|||||||
"maunium.net/go/mautrix/id"
|
"maunium.net/go/mautrix/id"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *Bot) lock(ctx context.Context, roomID id.RoomID, optionalEventID ...id.EventID) {
|
const (
|
||||||
|
reactionLock = "📨"
|
||||||
|
reactionUnlock = "✅"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *Bot) lock(ctx context.Context, roomID id.RoomID, eventID id.EventID) {
|
||||||
b.mu.Lock(roomID.String())
|
b.mu.Lock(roomID.String())
|
||||||
|
|
||||||
if len(optionalEventID) == 0 {
|
if err := b.lp.SendReaction(ctx, roomID, eventID, reactionLock); err != nil {
|
||||||
return
|
b.log.Error().Err(err).Str("roomID", roomID.String()).Str("eventID", eventID.String()).Msg("cannot send reaction on lock")
|
||||||
}
|
|
||||||
evtID := optionalEventID[0]
|
|
||||||
if _, err := b.lp.GetClient().SendReaction(ctx, roomID, evtID, "📨"); err != nil {
|
|
||||||
b.log.Error().Err(err).Str("roomID", roomID.String()).Str("eventID", evtID.String()).Msg("cannot send reaction on lock")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bot) unlock(ctx context.Context, roomID id.RoomID, optionalEventID ...id.EventID) {
|
func (b *Bot) unlock(ctx context.Context, roomID id.RoomID, eventID id.EventID) {
|
||||||
b.mu.Unlock(roomID.String())
|
b.mu.Unlock(roomID.String())
|
||||||
|
if err := b.lp.ReplaceReaction(ctx, roomID, eventID, reactionLock, reactionUnlock); err != nil {
|
||||||
if len(optionalEventID) == 0 {
|
b.log.Error().Err(err).Str("roomID", roomID.String()).Str("eventID", eventID.String()).Msg("cannot send reaction on unlock")
|
||||||
return
|
|
||||||
}
|
|
||||||
evtID := optionalEventID[0]
|
|
||||||
if _, err := b.lp.GetClient().SendReaction(ctx, roomID, evtID, "✅"); err != nil {
|
|
||||||
b.log.Error().Err(err).Str("roomID", roomID.String()).Str("eventID", evtID.String()).Msg("cannot send reaction on unlock")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
go.mod
14
go.mod
@@ -10,7 +10,7 @@ require (
|
|||||||
github.com/archdx/zerolog-sentry v1.8.2
|
github.com/archdx/zerolog-sentry v1.8.2
|
||||||
github.com/emersion/go-msgauth v0.6.8
|
github.com/emersion/go-msgauth v0.6.8
|
||||||
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43
|
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43
|
||||||
github.com/emersion/go-smtp v0.21.0
|
github.com/emersion/go-smtp v0.21.1
|
||||||
github.com/fsnotify/fsnotify v1.7.0
|
github.com/fsnotify/fsnotify v1.7.0
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3
|
github.com/gabriel-vasile/mimetype v1.4.3
|
||||||
github.com/getsentry/sentry-go v0.27.0
|
github.com/getsentry/sentry-go v0.27.0
|
||||||
@@ -24,14 +24,14 @@ require (
|
|||||||
github.com/rs/zerolog v1.32.0
|
github.com/rs/zerolog v1.32.0
|
||||||
gitlab.com/etke.cc/go/env v1.1.0
|
gitlab.com/etke.cc/go/env v1.1.0
|
||||||
gitlab.com/etke.cc/go/fswatcher v1.0.0
|
gitlab.com/etke.cc/go/fswatcher v1.0.0
|
||||||
gitlab.com/etke.cc/go/healthchecks/v2 v2.0.0
|
gitlab.com/etke.cc/go/healthchecks/v2 v2.2.0
|
||||||
gitlab.com/etke.cc/go/mxidwc v1.0.0
|
gitlab.com/etke.cc/go/mxidwc v1.0.0
|
||||||
gitlab.com/etke.cc/go/psd v1.1.1
|
gitlab.com/etke.cc/go/psd v1.1.2
|
||||||
gitlab.com/etke.cc/go/secgen v1.2.0
|
gitlab.com/etke.cc/go/secgen v1.2.0
|
||||||
gitlab.com/etke.cc/go/validator v1.0.7
|
gitlab.com/etke.cc/go/validator v1.0.7
|
||||||
gitlab.com/etke.cc/linkpearl v0.0.0-20240316115913-106577b88942
|
gitlab.com/etke.cc/linkpearl v0.0.0-20240425105001-435ae2720365
|
||||||
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0
|
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f
|
||||||
maunium.net/go/mautrix v0.18.0
|
maunium.net/go/mautrix v0.18.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -56,7 +56,7 @@ require (
|
|||||||
github.com/tidwall/sjson v1.2.5 // indirect
|
github.com/tidwall/sjson v1.2.5 // indirect
|
||||||
github.com/yuin/goldmark v1.7.1 // indirect
|
github.com/yuin/goldmark v1.7.1 // indirect
|
||||||
gitlab.com/etke.cc/go/trysmtp v1.1.3 // indirect
|
gitlab.com/etke.cc/go/trysmtp v1.1.3 // indirect
|
||||||
go.mau.fi/util v0.4.1 // indirect
|
go.mau.fi/util v0.4.2 // indirect
|
||||||
golang.org/x/crypto v0.22.0 // indirect
|
golang.org/x/crypto v0.22.0 // indirect
|
||||||
golang.org/x/net v0.24.0 // indirect
|
golang.org/x/net v0.24.0 // indirect
|
||||||
golang.org/x/sys v0.19.0 // indirect
|
golang.org/x/sys v0.19.0 // indirect
|
||||||
|
|||||||
28
go.sum
28
go.sum
@@ -16,8 +16,8 @@ github.com/emersion/go-msgauth v0.6.8/go.mod h1:YDwuyTCUHu9xxmAeVj0eW4INnwB6NNZo
|
|||||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
|
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
|
||||||
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 h1:hH4PQfOndHDlpzYfLAAfl63E8Le6F2+EL/cdhlkyRJY=
|
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 h1:hH4PQfOndHDlpzYfLAAfl63E8Le6F2+EL/cdhlkyRJY=
|
||||||
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
|
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
|
||||||
github.com/emersion/go-smtp v0.21.0 h1:ZDZmX9aFUuPlD1lpoT0nC/nozZuIkSCyQIyxdijjCy0=
|
github.com/emersion/go-smtp v0.21.1 h1:VQeZSZAKk8ueYii1yR5Zalmy7jI287eWDUqSaJ68vRM=
|
||||||
github.com/emersion/go-smtp v0.21.0/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
|
github.com/emersion/go-smtp v0.21.1/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
@@ -98,26 +98,26 @@ gitlab.com/etke.cc/go/env v1.1.0 h1:nbMhZkMu6C8lysRlb5siIiylWuyVkGAgEvwWEqz/82o=
|
|||||||
gitlab.com/etke.cc/go/env v1.1.0/go.mod h1:e1l4RM5MA1sc0R1w/RBDAESWRwgo5cOG9gx8BKUn2C4=
|
gitlab.com/etke.cc/go/env v1.1.0/go.mod h1:e1l4RM5MA1sc0R1w/RBDAESWRwgo5cOG9gx8BKUn2C4=
|
||||||
gitlab.com/etke.cc/go/fswatcher v1.0.0 h1:uyiVn+1NVCjOLZrXSZouIDBDZBMwVipS4oYuvAFpPzo=
|
gitlab.com/etke.cc/go/fswatcher v1.0.0 h1:uyiVn+1NVCjOLZrXSZouIDBDZBMwVipS4oYuvAFpPzo=
|
||||||
gitlab.com/etke.cc/go/fswatcher v1.0.0/go.mod h1:MqTOxyhXfvaVZQUL9/Ksbl2ow1PTBVu3eqIldvMq0RE=
|
gitlab.com/etke.cc/go/fswatcher v1.0.0/go.mod h1:MqTOxyhXfvaVZQUL9/Ksbl2ow1PTBVu3eqIldvMq0RE=
|
||||||
gitlab.com/etke.cc/go/healthchecks/v2 v2.0.0 h1:/VX2V/I0kH0Yah546EHcOZkuxbEj+8FBmsnb5uOXGUw=
|
gitlab.com/etke.cc/go/healthchecks/v2 v2.2.0 h1:7Y0qm8OAqeJApDNNfGSeA6WFF60q/394gMKinZNbSWE=
|
||||||
gitlab.com/etke.cc/go/healthchecks/v2 v2.0.0/go.mod h1:DdNc1ESc1cAgOdsIwxxV+RUWgn6ewCpfFKzLuF0kSfc=
|
gitlab.com/etke.cc/go/healthchecks/v2 v2.2.0/go.mod h1:DdNc1ESc1cAgOdsIwxxV+RUWgn6ewCpfFKzLuF0kSfc=
|
||||||
gitlab.com/etke.cc/go/mxidwc v1.0.0 h1:6EAlJXvs3nU4RaMegYq6iFlyVvLw7JZYnZmNCGMYQP0=
|
gitlab.com/etke.cc/go/mxidwc v1.0.0 h1:6EAlJXvs3nU4RaMegYq6iFlyVvLw7JZYnZmNCGMYQP0=
|
||||||
gitlab.com/etke.cc/go/mxidwc v1.0.0/go.mod h1:E/0kh45SAN9+ntTG0cwkAEKdaPxzvxVmnjwivm9nmz8=
|
gitlab.com/etke.cc/go/mxidwc v1.0.0/go.mod h1:E/0kh45SAN9+ntTG0cwkAEKdaPxzvxVmnjwivm9nmz8=
|
||||||
gitlab.com/etke.cc/go/psd v1.1.1 h1:UIL0X+thvYaeBTX8/G6lilqAToGCypihujGu5gtK5zQ=
|
gitlab.com/etke.cc/go/psd v1.1.2 h1:nplS8Sc8tV+G/zq0QtC0pfW97EI8v3ZiSoYOYKCTbjY=
|
||||||
gitlab.com/etke.cc/go/psd v1.1.1/go.mod h1:6b444NOkXlZ1n7WLCNazAkOC2bHPgqgfB9earThwKPk=
|
gitlab.com/etke.cc/go/psd v1.1.2/go.mod h1:6b444NOkXlZ1n7WLCNazAkOC2bHPgqgfB9earThwKPk=
|
||||||
gitlab.com/etke.cc/go/secgen v1.2.0 h1:qpV7rUn5Rs6eWxAmbGG/idPCOgsN4HggGmSZ+1R/L70=
|
gitlab.com/etke.cc/go/secgen v1.2.0 h1:qpV7rUn5Rs6eWxAmbGG/idPCOgsN4HggGmSZ+1R/L70=
|
||||||
gitlab.com/etke.cc/go/secgen v1.2.0/go.mod h1:v5L07AIXtNpC/miYiK0TMIn+ZKbiYrTRiXTw6qTL6pw=
|
gitlab.com/etke.cc/go/secgen v1.2.0/go.mod h1:v5L07AIXtNpC/miYiK0TMIn+ZKbiYrTRiXTw6qTL6pw=
|
||||||
gitlab.com/etke.cc/go/trysmtp v1.1.3 h1:e2EHond77onMaecqCg6mWumffTSEf+ycgj88nbeefDI=
|
gitlab.com/etke.cc/go/trysmtp v1.1.3 h1:e2EHond77onMaecqCg6mWumffTSEf+ycgj88nbeefDI=
|
||||||
gitlab.com/etke.cc/go/trysmtp v1.1.3/go.mod h1:lOO7tTdAE0a3ETV3wN3GJ7I1Tqewu7YTpPWaOmTteV0=
|
gitlab.com/etke.cc/go/trysmtp v1.1.3/go.mod h1:lOO7tTdAE0a3ETV3wN3GJ7I1Tqewu7YTpPWaOmTteV0=
|
||||||
gitlab.com/etke.cc/go/validator v1.0.7 h1:4BGDTa9x68vJhbyn7m8W2yX+2Nb5im9+JLRrgoLUlF4=
|
gitlab.com/etke.cc/go/validator v1.0.7 h1:4BGDTa9x68vJhbyn7m8W2yX+2Nb5im9+JLRrgoLUlF4=
|
||||||
gitlab.com/etke.cc/go/validator v1.0.7/go.mod h1:Id0SxRj0J3IPhiKlj0w1plxVLZfHlkwipn7HfRZsDts=
|
gitlab.com/etke.cc/go/validator v1.0.7/go.mod h1:Id0SxRj0J3IPhiKlj0w1plxVLZfHlkwipn7HfRZsDts=
|
||||||
gitlab.com/etke.cc/linkpearl v0.0.0-20240316115913-106577b88942 h1:hhDXBsDcYgAit9gwfvawnPXMIwHNKL9DL1kCCyyzB8A=
|
gitlab.com/etke.cc/linkpearl v0.0.0-20240425105001-435ae2720365 h1:MZnAxKJ5Bwv6ZHfC+HUEQyTDC0HPXVB8Q63ISkZ1lHo=
|
||||||
gitlab.com/etke.cc/linkpearl v0.0.0-20240316115913-106577b88942/go.mod h1:0AIH2o0fi4WoZhMw+tW63rrcI5aERH9c34RVHQXn1Q0=
|
gitlab.com/etke.cc/linkpearl v0.0.0-20240425105001-435ae2720365/go.mod h1:onM3Tge1SUII+oda91/ThDvVvMhkPiSRJ7EOsC2g0yc=
|
||||||
go.mau.fi/util v0.4.1 h1:3EC9KxIXo5+h869zDGf5OOZklRd/FjeVnimTwtm3owg=
|
go.mau.fi/util v0.4.2 h1:RR3TOcRHmCF9Bx/3YG4S65MYfa+nV6/rn8qBWW4Mi30=
|
||||||
go.mau.fi/util v0.4.1/go.mod h1:GjkTEBsehYZbSh2LlE6cWEn+6ZIZTGrTMM/5DMNlmFY=
|
go.mau.fi/util v0.4.2/go.mod h1:PlAVfUUcPyHPrwnvjkJM9UFcPE7qGPDJqk+Oufa1Gtw=
|
||||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||||
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8=
|
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
|
||||||
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
|
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
|
||||||
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||||
@@ -133,5 +133,5 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
maunium.net/go/mautrix v0.18.0 h1:sNsApeSWB8x0hLjGcdmi5JqO6Tvp2PVkiSStz+Yas6k=
|
maunium.net/go/mautrix v0.18.1 h1:a6mUsJixegBNTXUoqC5RQ9gsumIPzKvCubKwF+zmCt4=
|
||||||
maunium.net/go/mautrix v0.18.0/go.mod h1:STwJZ+6CAeiEQs7fYCkd5aC12XR5DXANE6Swy/PBKGo=
|
maunium.net/go/mautrix v0.18.1/go.mod h1:2oHaq792cSXFGvxLvYw3Gf1L4WVVP4KZcYys5HVk/h8=
|
||||||
|
|||||||
1
justfile
1
justfile
@@ -54,3 +54,4 @@ login:
|
|||||||
docker:
|
docker:
|
||||||
docker buildx create --use
|
docker buildx create --use
|
||||||
docker buildx build --pull --provenance=false --platform {{ platforms }} --push -t {{ gitlab_image }} -t {{ etke_image }} .
|
docker buildx build --pull --provenance=false --platform {{ platforms }} --push -t {{ gitlab_image }} -t {{ etke_image }} .
|
||||||
|
docker buildx rm
|
||||||
|
|||||||
13
vendor/github.com/emersion/go-smtp/client.go
generated
vendored
13
vendor/github.com/emersion/go-smtp/client.go
generated
vendored
@@ -44,9 +44,7 @@ type Client struct {
|
|||||||
|
|
||||||
// 30 seconds was chosen as it's the same duration as http.DefaultTransport's
|
// 30 seconds was chosen as it's the same duration as http.DefaultTransport's
|
||||||
// timeout.
|
// timeout.
|
||||||
const defaultTimeout = 30 * time.Second
|
var defaultDialer = net.Dialer{Timeout: 30 * time.Second}
|
||||||
|
|
||||||
var defaultDialer = net.Dialer{Timeout: defaultTimeout}
|
|
||||||
|
|
||||||
// Dial returns a new Client connected to an SMTP server at addr. The addr must
|
// Dial returns a new Client connected to an SMTP server at addr. The addr must
|
||||||
// include a port, as in "mail.example.com:smtp".
|
// include a port, as in "mail.example.com:smtp".
|
||||||
@@ -358,8 +356,13 @@ func (c *Client) Auth(a sasl.Client) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
resp64 := make([]byte, encoding.EncodedLen(len(resp)))
|
var resp64 []byte
|
||||||
encoding.Encode(resp64, resp)
|
if len(resp) > 0 {
|
||||||
|
resp64 = make([]byte, encoding.EncodedLen(len(resp)))
|
||||||
|
encoding.Encode(resp64, resp)
|
||||||
|
} else if resp != nil {
|
||||||
|
resp64 = []byte{'='}
|
||||||
|
}
|
||||||
code, msg64, err := c.cmd(0, strings.TrimSpace(fmt.Sprintf("AUTH %s %s", mech, resp64)))
|
code, msg64, err := c.cmd(0, strings.TrimSpace(fmt.Sprintf("AUTH %s %s", mech, resp64)))
|
||||||
for err == nil {
|
for err == nil {
|
||||||
var msg []byte
|
var msg []byte
|
||||||
|
|||||||
77
vendor/github.com/emersion/go-smtp/conn.go
generated
vendored
77
vendor/github.com/emersion/go-smtp/conn.go
generated
vendored
@@ -232,12 +232,7 @@ func (c *Conn) handleGreet(enhanced bool, arg string) {
|
|||||||
sess, err := c.server.Backend.NewSession(c)
|
sess, err := c.server.Backend.NewSession(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.helo = ""
|
c.helo = ""
|
||||||
|
c.writeError(451, EnhancedCode{4, 0, 0}, err)
|
||||||
if smtpErr, ok := err.(*SMTPError); ok {
|
|
||||||
c.writeResponse(smtpErr.Code, smtpErr.EnhancedCode, smtpErr.Message)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.writeResponse(451, EnhancedCode{4, 0, 0}, err.Error())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,11 +416,7 @@ func (c *Conn) handleMail(arg string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := c.Session().Mail(from, opts); err != nil {
|
if err := c.Session().Mail(from, opts); err != nil {
|
||||||
if smtpErr, ok := err.(*SMTPError); ok {
|
c.writeError(451, EnhancedCode{4, 0, 0}, err)
|
||||||
c.writeResponse(smtpErr.Code, smtpErr.EnhancedCode, smtpErr.Message)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.writeResponse(451, EnhancedCode{4, 0, 0}, err.Error())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -725,11 +716,7 @@ func (c *Conn) handleRcpt(arg string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := c.Session().Rcpt(recipient, opts); err != nil {
|
if err := c.Session().Rcpt(recipient, opts); err != nil {
|
||||||
if smtpErr, ok := err.(*SMTPError); ok {
|
c.writeError(451, EnhancedCode{4, 0, 0}, err)
|
||||||
c.writeResponse(smtpErr.Code, smtpErr.EnhancedCode, smtpErr.Message)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.writeResponse(451, EnhancedCode{4, 0, 0}, err.Error())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.recipients = append(c.recipients, recipient)
|
c.recipients = append(c.recipients, recipient)
|
||||||
@@ -786,21 +773,21 @@ func (c *Conn) handleAuth(arg string) {
|
|||||||
// Parse client initial response if there is one
|
// Parse client initial response if there is one
|
||||||
var ir []byte
|
var ir []byte
|
||||||
if len(parts) > 1 {
|
if len(parts) > 1 {
|
||||||
var err error
|
if parts[1] == "=" {
|
||||||
ir, err = base64.StdEncoding.DecodeString(parts[1])
|
ir = []byte{}
|
||||||
if err != nil {
|
} else {
|
||||||
c.writeResponse(454, EnhancedCode{4, 7, 0}, "Invalid base64 data")
|
var err error
|
||||||
return
|
ir, err = base64.StdEncoding.DecodeString(parts[1])
|
||||||
|
if err != nil {
|
||||||
|
c.writeResponse(454, EnhancedCode{4, 7, 0}, "Invalid base64 data")
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sasl, err := c.auth(mechanism)
|
sasl, err := c.auth(mechanism)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if smtpErr, ok := err.(*SMTPError); ok {
|
c.writeError(454, EnhancedCode{4, 7, 0}, err)
|
||||||
c.writeResponse(smtpErr.Code, smtpErr.EnhancedCode, smtpErr.Message)
|
|
||||||
} else {
|
|
||||||
c.writeResponse(454, EnhancedCode{4, 7, 0}, err.Error())
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -808,11 +795,7 @@ func (c *Conn) handleAuth(arg string) {
|
|||||||
for {
|
for {
|
||||||
challenge, done, err := sasl.Next(response)
|
challenge, done, err := sasl.Next(response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if smtpErr, ok := err.(*SMTPError); ok {
|
c.writeError(454, EnhancedCode{4, 7, 0}, err)
|
||||||
c.writeResponse(smtpErr.Code, smtpErr.EnhancedCode, smtpErr.Message)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.writeResponse(454, EnhancedCode{4, 7, 0}, err.Error())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -837,10 +820,14 @@ func (c *Conn) handleAuth(arg string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err = base64.StdEncoding.DecodeString(encoded)
|
if encoded == "=" {
|
||||||
if err != nil {
|
response = []byte{}
|
||||||
c.writeResponse(454, EnhancedCode{4, 7, 0}, "Invalid base64 data")
|
} else {
|
||||||
return
|
response, err = base64.StdEncoding.DecodeString(encoded)
|
||||||
|
if err != nil {
|
||||||
|
c.writeResponse(454, EnhancedCode{4, 7, 0}, "Invalid base64 data")
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -930,7 +917,7 @@ func (c *Conn) handleData(arg string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
r := newDataReader(c)
|
r := newDataReader(c)
|
||||||
code, enhancedCode, msg := toSMTPStatus(c.Session().Data(r))
|
code, enhancedCode, msg := dataErrorToStatus(c.Session().Data(r))
|
||||||
r.limited = false
|
r.limited = false
|
||||||
io.Copy(ioutil.Discard, r) // Make sure all the data has been consumed
|
io.Copy(ioutil.Discard, r) // Make sure all the data has been consumed
|
||||||
c.writeResponse(code, enhancedCode, msg)
|
c.writeResponse(code, enhancedCode, msg)
|
||||||
@@ -1027,7 +1014,7 @@ func (c *Conn) handleBdat(arg string) {
|
|||||||
// the whole chunk.
|
// the whole chunk.
|
||||||
io.Copy(ioutil.Discard, chunk)
|
io.Copy(ioutil.Discard, chunk)
|
||||||
|
|
||||||
c.writeResponse(toSMTPStatus(err))
|
c.writeResponse(dataErrorToStatus(err))
|
||||||
|
|
||||||
if err == errPanic {
|
if err == errPanic {
|
||||||
c.Close()
|
c.Close()
|
||||||
@@ -1050,11 +1037,11 @@ func (c *Conn) handleBdat(arg string) {
|
|||||||
if c.server.LMTP {
|
if c.server.LMTP {
|
||||||
c.bdatStatus.fillRemaining(err)
|
c.bdatStatus.fillRemaining(err)
|
||||||
for i, rcpt := range c.recipients {
|
for i, rcpt := range c.recipients {
|
||||||
code, enchCode, msg := toSMTPStatus(<-c.bdatStatus.status[i])
|
code, enchCode, msg := dataErrorToStatus(<-c.bdatStatus.status[i])
|
||||||
c.writeResponse(code, enchCode, "<"+rcpt+"> "+msg)
|
c.writeResponse(code, enchCode, "<"+rcpt+"> "+msg)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.writeResponse(toSMTPStatus(err))
|
c.writeResponse(dataErrorToStatus(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == errPanic {
|
if err == errPanic {
|
||||||
@@ -1189,7 +1176,7 @@ func (c *Conn) handleDataLMTP() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, rcpt := range c.recipients {
|
for i, rcpt := range c.recipients {
|
||||||
code, enchCode, msg := toSMTPStatus(<-status.status[i])
|
code, enchCode, msg := dataErrorToStatus(<-status.status[i])
|
||||||
c.writeResponse(code, enchCode, "<"+rcpt+"> "+msg)
|
c.writeResponse(code, enchCode, "<"+rcpt+"> "+msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1200,7 +1187,7 @@ func (c *Conn) handleDataLMTP() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func toSMTPStatus(err error) (code int, enchCode EnhancedCode, msg string) {
|
func dataErrorToStatus(err error) (code int, enchCode EnhancedCode, msg string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if smtperr, ok := err.(*SMTPError); ok {
|
if smtperr, ok := err.(*SMTPError); ok {
|
||||||
return smtperr.Code, smtperr.EnhancedCode, smtperr.Message
|
return smtperr.Code, smtperr.EnhancedCode, smtperr.Message
|
||||||
@@ -1253,6 +1240,14 @@ func (c *Conn) writeResponse(code int, enhCode EnhancedCode, text ...string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Conn) writeError(code int, enhCode EnhancedCode, err error) {
|
||||||
|
if smtpErr, ok := err.(*SMTPError); ok {
|
||||||
|
c.writeResponse(smtpErr.Code, smtpErr.EnhancedCode, smtpErr.Message)
|
||||||
|
} else {
|
||||||
|
c.writeResponse(code, enhCode, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Reads a line of input
|
// Reads a line of input
|
||||||
func (c *Conn) readLine() (string, error) {
|
func (c *Conn) readLine() (string, error) {
|
||||||
if c.server.ReadTimeout != 0 {
|
if c.server.ReadTimeout != 0 {
|
||||||
|
|||||||
4
vendor/github.com/emersion/go-smtp/server.go
generated
vendored
4
vendor/github.com/emersion/go-smtp/server.go
generated
vendored
@@ -12,9 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var ErrServerClosed = errors.New("smtp: server already closed")
|
||||||
ErrServerClosed = errors.New("smtp: server already closed")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Logger interface is used by Server to report unexpected internal errors.
|
// Logger interface is used by Server to report unexpected internal errors.
|
||||||
type Logger interface {
|
type Logger interface {
|
||||||
|
|||||||
38
vendor/gitlab.com/etke.cc/go/healthchecks/v2/README.md
generated
vendored
38
vendor/gitlab.com/etke.cc/go/healthchecks/v2/README.md
generated
vendored
@@ -1,15 +1,37 @@
|
|||||||
# healthchecks
|
# healthchecks
|
||||||
|
|
||||||
A [healthchecks.io](https://github.com/healthchecks/healthchecks) client
|
A fully async [healthchecks.io](https://github.com/healthchecks/healthchecks) golang client, with lots of features, some highlights:
|
||||||
|
|
||||||
check the godoc for information
|
* Highly configurable: `WithHTTPClient()`, `WithBaseURL()`, `WithUserAgent()`, `WithErrLog()`, `WithCheckUUID()`, `WithAutoProvision()`, etc.
|
||||||
|
* Automatic determination of HTTP method (`POST`, `HEAD`) based on body existence
|
||||||
|
* Auto mode: just call `client.Auto(time.Duration)` and client will send `Success()` request automatically with specified frequency
|
||||||
|
* Global mode: init client once with `healthchecks.New()`, and access it from anywhere by calling `healthchecks.Global()`
|
||||||
|
|
||||||
|
Check [godoc](https://pkg.go.dev/gitlab.com/etke.cc/go/healthchecks/v2) for more details.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
hc := healthchecks.New(
|
package main
|
||||||
healthchecks.WithCheckUUID("your-uuid"),
|
|
||||||
)
|
|
||||||
go hc.Auto()
|
|
||||||
|
|
||||||
hc.Log(strings.NewReader("optional body you can attach to any action"))
|
import (
|
||||||
hc.Shutdown()
|
"time"
|
||||||
|
|
||||||
|
"gitlab.com/etke.cc/go/healthchecks/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var hc *healthchecks.Client
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
hc = healthchecks.New(
|
||||||
|
healthchecks.WithCheckUUID("CHECK_UUID")
|
||||||
|
)
|
||||||
|
defer hc.Shutdown()
|
||||||
|
// send basic success request
|
||||||
|
hc.Success()
|
||||||
|
|
||||||
|
// or use auto mode, that will send success request with the specified frequency
|
||||||
|
go hc.Auto(1*time.Minute)
|
||||||
|
|
||||||
|
// need to call the client from another place in your project?
|
||||||
|
// just call healthchecks.Global() and you will get the same client
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
5
vendor/gitlab.com/etke.cc/go/healthchecks/v2/auto.go
generated
vendored
5
vendor/gitlab.com/etke.cc/go/healthchecks/v2/auto.go
generated
vendored
@@ -17,8 +17,3 @@ func (c *Client) Auto(every time.Duration) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shutdown the client
|
|
||||||
func (c *Client) Shutdown() {
|
|
||||||
c.done <- true
|
|
||||||
}
|
|
||||||
|
|||||||
93
vendor/gitlab.com/etke.cc/go/healthchecks/v2/client.go
generated
vendored
93
vendor/gitlab.com/etke.cc/go/healthchecks/v2/client.go
generated
vendored
@@ -5,39 +5,46 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Client for healthchecks
|
// Client for healthchecks
|
||||||
|
// if client initialized without any options, it will be disabled by default,
|
||||||
|
// but you can override it by calling SetEnabled(true).
|
||||||
type Client struct {
|
type Client struct {
|
||||||
http *http.Client
|
wg sync.WaitGroup
|
||||||
log func(string, error)
|
enabled bool
|
||||||
baseURL string
|
http *http.Client
|
||||||
uuid string
|
log func(string, error)
|
||||||
rid string
|
userAgent string
|
||||||
create bool
|
baseURL string
|
||||||
done chan bool
|
uuid string
|
||||||
|
rid string
|
||||||
|
create bool
|
||||||
|
done chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// init client
|
// init client
|
||||||
func (c *Client) init(options ...Option) {
|
func (c *Client) init(options ...Option) {
|
||||||
|
c.enabled = true
|
||||||
|
c.log = DefaultErrLog
|
||||||
|
c.baseURL = DefaultAPI
|
||||||
|
c.userAgent = DefaultUserAgent
|
||||||
|
c.http = &http.Client{Timeout: 10 * time.Second}
|
||||||
|
c.done = make(chan bool, 1)
|
||||||
|
c.uuid = ""
|
||||||
|
|
||||||
|
if len(options) == 0 {
|
||||||
|
c.enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
option(c)
|
option(c)
|
||||||
}
|
}
|
||||||
if c.log == nil {
|
|
||||||
c.log = DefaultErrLog
|
|
||||||
}
|
|
||||||
if c.baseURL == "" {
|
|
||||||
c.baseURL = DefaultAPI
|
|
||||||
}
|
|
||||||
if c.http == nil {
|
|
||||||
c.http = &http.Client{Timeout: 10 * time.Second}
|
|
||||||
}
|
|
||||||
if c.done == nil {
|
|
||||||
c.done = make(chan bool, 1)
|
|
||||||
}
|
|
||||||
if c.uuid == "" {
|
if c.uuid == "" {
|
||||||
randomUUID, _ := uuid.NewRandom()
|
randomUUID, _ := uuid.NewRandom()
|
||||||
c.uuid = randomUUID.String()
|
c.uuid = randomUUID.String()
|
||||||
@@ -46,22 +53,39 @@ func (c *Client) init(options ...Option) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// call API
|
||||||
func (c *Client) call(operation, endpoint string, body ...io.Reader) {
|
func (c *Client) call(operation, endpoint string, body ...io.Reader) {
|
||||||
var err error
|
if !c.enabled {
|
||||||
var resp *http.Response
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.wg.Add(1)
|
||||||
|
defer c.wg.Done()
|
||||||
|
|
||||||
targetURL := fmt.Sprintf("%s/%s%s?rid=%s", c.baseURL, c.uuid, endpoint, c.rid)
|
targetURL := fmt.Sprintf("%s/%s%s?rid=%s", c.baseURL, c.uuid, endpoint, c.rid)
|
||||||
if c.create {
|
if c.create {
|
||||||
targetURL += "&create=1"
|
targetURL += "&create=1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var req *http.Request
|
||||||
|
var err error
|
||||||
if len(body) > 0 {
|
if len(body) > 0 {
|
||||||
resp, err = c.http.Post(targetURL, "text/plain; charset=utf-8", body[0])
|
req, err = http.NewRequest(http.MethodPost, targetURL, body[0])
|
||||||
} else {
|
} else {
|
||||||
resp, err = c.http.Head(targetURL)
|
req, err = http.NewRequest(http.MethodHead, targetURL, http.NoBody)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.log(operation, err)
|
c.log(operation, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
req.Header.Set("User-Agent", c.userAgent)
|
||||||
|
req.Header.Set("Content-Type", "text/plain; charset=utf-8")
|
||||||
|
|
||||||
|
resp, err := c.http.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
c.log(operation, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
|
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
|
||||||
@@ -76,27 +100,40 @@ func (c *Client) call(operation, endpoint string, body ...io.Reader) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetEnabled sets the enabled flag, ignoring the options
|
||||||
|
// if client initialized without any options, it will be disabled by default,
|
||||||
|
// but you can override it by calling SetEnabled(true).
|
||||||
|
func (c *Client) SetEnabled(enabled bool) {
|
||||||
|
c.enabled = enabled
|
||||||
|
}
|
||||||
|
|
||||||
// Start signal means the job started
|
// Start signal means the job started
|
||||||
func (c *Client) Start(optionalBody ...io.Reader) {
|
func (c *Client) Start(optionalBody ...io.Reader) {
|
||||||
c.call("start", "/start", optionalBody...)
|
go c.call("start", "/start", optionalBody...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Success signal means the job has completed successfully (or, a continuously running process is still running and healthy).
|
// Success signal means the job has completed successfully (or, a continuously running process is still running and healthy).
|
||||||
func (c *Client) Success(optionalBody ...io.Reader) {
|
func (c *Client) Success(optionalBody ...io.Reader) {
|
||||||
c.call("success", "", optionalBody...)
|
go c.call("success", "", optionalBody...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fail signal means the job failed
|
// Fail signal means the job failed
|
||||||
func (c *Client) Fail(optionalBody ...io.Reader) {
|
func (c *Client) Fail(optionalBody ...io.Reader) {
|
||||||
c.call("fail", "/fail", optionalBody...)
|
go c.call("fail", "/fail", optionalBody...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log signal just adds an event to the job log, without changing job status
|
// Log signal just adds an event to the job log, without changing job status
|
||||||
func (c *Client) Log(optionalBody ...io.Reader) {
|
func (c *Client) Log(optionalBody ...io.Reader) {
|
||||||
c.call("log", "/log", optionalBody...)
|
go c.call("log", "/log", optionalBody...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExitStatus signal sends job's exit code (0-255)
|
// ExitStatus signal sends job's exit code (0-255)
|
||||||
func (c *Client) ExitStatus(exitCode int, optionalBody ...io.Reader) {
|
func (c *Client) ExitStatus(exitCode int, optionalBody ...io.Reader) {
|
||||||
c.call("exit status", "/"+strconv.Itoa(exitCode), optionalBody...)
|
go c.call("exit status", "/"+strconv.Itoa(exitCode), optionalBody...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown the client
|
||||||
|
func (c *Client) Shutdown() {
|
||||||
|
c.done <- true
|
||||||
|
c.wg.Wait()
|
||||||
}
|
}
|
||||||
|
|||||||
24
vendor/gitlab.com/etke.cc/go/healthchecks/v2/healthchecks.go
generated
vendored
24
vendor/gitlab.com/etke.cc/go/healthchecks/v2/healthchecks.go
generated
vendored
@@ -6,12 +6,19 @@ import (
|
|||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultAPI base url for checks
|
const (
|
||||||
const DefaultAPI = "https://hc-ping.com"
|
// DefaultAPI base url for checks
|
||||||
|
DefaultAPI = "https://hc-ping.com"
|
||||||
|
// DefaultUserAgent for the client
|
||||||
|
DefaultUserAgent = "Go-Healthchecks (lib; +https://gitlab.com/etke.cc/go/healthchecks)"
|
||||||
|
)
|
||||||
|
|
||||||
// ErrLog used to log errors occurred during an operation
|
// ErrLog used to log errors occurred during an operation
|
||||||
type ErrLog func(operation string, err error)
|
type ErrLog func(operation string, err error)
|
||||||
|
|
||||||
|
// global client
|
||||||
|
var global *Client
|
||||||
|
|
||||||
// DefaultErrLog if you don't provide one yourself
|
// DefaultErrLog if you don't provide one yourself
|
||||||
var DefaultErrLog = func(operation string, err error) {
|
var DefaultErrLog = func(operation string, err error) {
|
||||||
fmt.Printf("healtchecks operation %q failed: %v\n", operation, err)
|
fmt.Printf("healtchecks operation %q failed: %v\n", operation, err)
|
||||||
@@ -25,5 +32,18 @@ func New(options ...Option) *Client {
|
|||||||
}
|
}
|
||||||
c.init(options...)
|
c.init(options...)
|
||||||
|
|
||||||
|
if global == nil {
|
||||||
|
global = c
|
||||||
|
}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Global healthchecks client
|
||||||
|
func Global() *Client {
|
||||||
|
if global == nil {
|
||||||
|
global = New()
|
||||||
|
}
|
||||||
|
|
||||||
|
return global
|
||||||
|
}
|
||||||
|
|||||||
15
vendor/gitlab.com/etke.cc/go/healthchecks/v2/options.go
generated
vendored
15
vendor/gitlab.com/etke.cc/go/healthchecks/v2/options.go
generated
vendored
@@ -2,6 +2,7 @@ package healthchecks
|
|||||||
|
|
||||||
import "net/http"
|
import "net/http"
|
||||||
|
|
||||||
|
// Option for healthchecks client
|
||||||
type Option func(*Client)
|
type Option func(*Client)
|
||||||
|
|
||||||
// WithHTTPClient sets the http client
|
// WithHTTPClient sets the http client
|
||||||
@@ -18,6 +19,13 @@ func WithBaseURL(baseURL string) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithUserAgent sets the user agent
|
||||||
|
func WithUserAgent(userAgent string) Option {
|
||||||
|
return func(c *Client) {
|
||||||
|
c.userAgent = userAgent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithErrLog sets the error log
|
// WithErrLog sets the error log
|
||||||
func WithErrLog(errLog ErrLog) Option {
|
func WithErrLog(errLog ErrLog) Option {
|
||||||
return func(c *Client) {
|
return func(c *Client) {
|
||||||
@@ -39,6 +47,13 @@ func WithAutoProvision() Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithGlobal sets this client as the global client
|
||||||
|
func WithGlobal() Option {
|
||||||
|
return func(c *Client) {
|
||||||
|
global = c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithDone sets the done channel
|
// WithDone sets the done channel
|
||||||
func WithDone(done chan bool) Option {
|
func WithDone(done chan bool) Option {
|
||||||
return func(c *Client) {
|
return func(c *Client) {
|
||||||
|
|||||||
6
vendor/gitlab.com/etke.cc/go/psd/client.go
generated
vendored
6
vendor/gitlab.com/etke.cc/go/psd/client.go
generated
vendored
@@ -53,13 +53,17 @@ func (p *Client) GetWithContext(ctx context.Context, identifier string) ([]*Targ
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
req.SetBasicAuth(p.login, p.password)
|
req.SetBasicAuth(p.login, p.password)
|
||||||
req.Header.Set("User-Agent", "Go-psd-client/"+version)
|
req.Header.Set("User-Agent", "Go-PSD-client/"+version)
|
||||||
resp, err := http.DefaultClient.Do(req)
|
resp, err := http.DefaultClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
if resp.StatusCode == http.StatusGone { // not found, to distinguish from reverse proxy 404 error
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
err = fmt.Errorf("%s", resp.Status) //nolint:goerr113 // that's ok
|
err = fmt.Errorf("%s", resp.Status) //nolint:goerr113 // that's ok
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
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:
|
run:
|
||||||
concurrency: 4
|
concurrency: 4
|
||||||
timeout: 5m
|
timeout: 30m
|
||||||
issues-exit-code: 1
|
issues-exit-code: 1
|
||||||
tests: true
|
tests: true
|
||||||
build-tags: []
|
build-tags: []
|
||||||
skip-dirs: []
|
|
||||||
skip-dirs-use-default: true
|
skip-dirs-use-default: true
|
||||||
skip-files: []
|
skip-files: []
|
||||||
modules-download-mode: readonly
|
modules-download-mode: readonly
|
||||||
allow-parallel-runners: false
|
|
||||||
|
|
||||||
output:
|
output:
|
||||||
format: colored-line-number
|
formats:
|
||||||
|
- format: colored-line-number
|
||||||
print-issued-lines: true
|
print-issued-lines: true
|
||||||
print-linter-name: true
|
print-linter-name: true
|
||||||
uniq-by-line: true
|
|
||||||
path-prefix: ""
|
|
||||||
sort-results: true
|
sort-results: true
|
||||||
|
|
||||||
linters-settings:
|
linters-settings:
|
||||||
|
decorder:
|
||||||
|
dec-order:
|
||||||
|
- const
|
||||||
|
- var
|
||||||
|
- type
|
||||||
|
- func
|
||||||
|
dogsled:
|
||||||
|
max-blank-identifiers: 3
|
||||||
errcheck:
|
errcheck:
|
||||||
|
check-type-assertions: true
|
||||||
check-blank: true
|
check-blank: true
|
||||||
gci:
|
errchkjson:
|
||||||
local-prefixes: gitlab.com/etke.cc/linkpearl
|
report-no-exported: true
|
||||||
|
exhaustive:
|
||||||
|
check:
|
||||||
|
- switch
|
||||||
|
- map
|
||||||
|
default-signifies-exhaustive: true
|
||||||
gocognit:
|
gocognit:
|
||||||
min-complexity: 10
|
min-complexity: 15
|
||||||
nestif:
|
nestif:
|
||||||
min-complexity: 4
|
min-complexity: 5
|
||||||
gocritic:
|
gocritic:
|
||||||
enabled-tags:
|
enabled-tags:
|
||||||
|
- diagnostic
|
||||||
|
- style
|
||||||
- performance
|
- performance
|
||||||
|
gofmt:
|
||||||
|
simplify: true
|
||||||
|
rewrite-rules:
|
||||||
|
- pattern: 'interface{}'
|
||||||
|
replacement: 'any'
|
||||||
|
- pattern: 'a[b:len(a)]'
|
||||||
|
replacement: 'a[b:]'
|
||||||
gofumpt:
|
gofumpt:
|
||||||
lang-version: "1.19"
|
extra-rules: true
|
||||||
goimports:
|
grouper:
|
||||||
local-prefixes: gitlab.com/etke.cc/linkpearl
|
const-require-single-const: true
|
||||||
gosimple:
|
import-require-single-import: true
|
||||||
go: "1.19"
|
var-require-single-var: true
|
||||||
checks: [ "all" ]
|
|
||||||
govet:
|
|
||||||
check-shadowing: true
|
|
||||||
enable:
|
|
||||||
- atomicalign
|
|
||||||
- shadow
|
|
||||||
misspell:
|
misspell:
|
||||||
locale: US
|
locale: US
|
||||||
staticcheck:
|
usestdlibvars:
|
||||||
go: "1.19"
|
time-month: true
|
||||||
checks: [ "all" ]
|
time-layout: true
|
||||||
stylecheck:
|
crypto-hash: true
|
||||||
go: "1.19"
|
default-rpc-path: true
|
||||||
|
os-dev-null: true
|
||||||
|
sql-isolation-level: true
|
||||||
|
tls-signature-scheme: true
|
||||||
|
constant-kind: true
|
||||||
unparam:
|
unparam:
|
||||||
check-exported: true
|
check-exported: true
|
||||||
unused:
|
|
||||||
go: "1.19"
|
|
||||||
linters:
|
linters:
|
||||||
disable-all: false
|
disable-all: false
|
||||||
enable:
|
enable:
|
||||||
- megacheck
|
- asasalint
|
||||||
- govet
|
- asciicheck
|
||||||
|
- bidichk
|
||||||
|
- bodyclose
|
||||||
|
- containedctx
|
||||||
|
- decorder
|
||||||
|
- dogsled
|
||||||
|
- dupl
|
||||||
|
- dupword
|
||||||
|
- durationcheck
|
||||||
- errcheck
|
- errcheck
|
||||||
- gci
|
- errchkjson
|
||||||
|
- errname
|
||||||
|
- errorlint
|
||||||
|
- execinquery
|
||||||
|
- exhaustive
|
||||||
|
- exportloopref
|
||||||
|
- forcetypeassert
|
||||||
- gocognit
|
- gocognit
|
||||||
- nestif
|
|
||||||
- gocritic
|
- gocritic
|
||||||
|
- gocyclo
|
||||||
|
- gofmt
|
||||||
- gofumpt
|
- gofumpt
|
||||||
- goimports
|
- goimports
|
||||||
|
- gosec
|
||||||
- gosimple
|
- gosimple
|
||||||
|
- gosmopolitan
|
||||||
- govet
|
- govet
|
||||||
|
- ineffassign
|
||||||
|
- makezero
|
||||||
|
- mirror
|
||||||
- misspell
|
- misspell
|
||||||
|
- nestif
|
||||||
|
- nolintlint
|
||||||
|
- prealloc
|
||||||
|
- predeclared
|
||||||
|
- revive
|
||||||
|
- sqlclosecheck
|
||||||
- staticcheck
|
- staticcheck
|
||||||
- stylecheck
|
- unconvert
|
||||||
- unparam
|
- unparam
|
||||||
- unused
|
- unused
|
||||||
|
- usestdlibvars
|
||||||
|
- wastedassign
|
||||||
fast: false
|
fast: false
|
||||||
|
|
||||||
|
|
||||||
issues:
|
issues:
|
||||||
|
exclude-dirs:
|
||||||
|
- mocks
|
||||||
exclude-rules:
|
exclude-rules:
|
||||||
- path: _test\.go
|
- path: _test\.go
|
||||||
linters:
|
linters:
|
||||||
- gocyclo
|
- gocyclo
|
||||||
|
- gocognit
|
||||||
- errcheck
|
- errcheck
|
||||||
- dupl
|
- dupl
|
||||||
- gosec
|
- gosec
|
||||||
@@ -89,6 +136,9 @@ issues:
|
|||||||
- linters:
|
- linters:
|
||||||
- lll
|
- lll
|
||||||
source: "^//go:generate "
|
source: "^//go:generate "
|
||||||
|
- linters:
|
||||||
|
- revive
|
||||||
|
text: "returns unexported type"
|
||||||
max-issues-per-linter: 0
|
max-issues-per-linter: 0
|
||||||
max-same-issues: 0
|
max-same-issues: 0
|
||||||
new: false
|
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"`
|
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
|
// 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) {
|
func (l *Linkpearl) Threads(ctx context.Context, roomID id.RoomID, fromToken ...string) (*RespThreads, error) {
|
||||||
var from string
|
var from string
|
||||||
@@ -33,8 +39,26 @@ func (l *Linkpearl) Threads(ctx context.Context, roomID id.RoomID, fromToken ...
|
|||||||
return resp, UnwrapError(err)
|
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
|
// 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
|
var from string
|
||||||
if len(fromToken) > 0 {
|
if len(fromToken) > 0 {
|
||||||
from = 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 {
|
for _, msg := range resp.Chunk {
|
||||||
evt, contains := l.eventContains(ctx, msg, field, value)
|
for field, value := range fieldValue {
|
||||||
if contains {
|
evt, contains := l.eventContains(ctx, msg, field, value)
|
||||||
return evt
|
if contains {
|
||||||
|
return evt
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,11 +84,11 @@ func (l *Linkpearl) FindThreadBy(ctx context.Context, roomID id.RoomID, field, v
|
|||||||
return nil
|
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
|
// 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
|
var from string
|
||||||
if len(fromToken) > 0 {
|
if len(fromToken) > 0 {
|
||||||
from = 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 {
|
for _, msg := range resp.Chunk {
|
||||||
evt, contains := l.eventContains(ctx, msg, field, value)
|
for field, value := range fieldValue {
|
||||||
if contains {
|
evt, contains := l.eventContains(ctx, msg, field, value)
|
||||||
return evt
|
if contains {
|
||||||
|
return evt
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +114,7 @@ func (l *Linkpearl) FindEventBy(ctx context.Context, roomID id.RoomID, field, va
|
|||||||
return nil
|
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) {
|
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
|
DefaultAccountDataCache = 1000
|
||||||
// DefaultEventsLimit for methods like lp.Threads() and lp.FindEventBy()
|
// DefaultEventsLimit for methods like lp.Threads() and lp.FindEventBy()
|
||||||
DefaultEventsLimit = 1000
|
DefaultEventsLimit = 1000
|
||||||
|
// DefaultTypingTimeout in seconds for typing notifications
|
||||||
|
DefaultTypingTimeout = 60
|
||||||
)
|
)
|
||||||
|
|
||||||
// Linkpearl object
|
// Linkpearl object
|
||||||
@@ -104,7 +106,7 @@ func New(cfg *Config) (*Linkpearl, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
lp.ch.LoginAs = cfg.LoginAs()
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
lp.api.Crypto = lp.ch
|
lp.api.Crypto = lp.ch
|
||||||
@@ -140,33 +142,33 @@ func (l *Linkpearl) SetPresence(ctx context.Context, presence event.Presence, me
|
|||||||
return err
|
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) {
|
func (l *Linkpearl) SetJoinPermit(value func(context.Context, *event.Event) bool) {
|
||||||
l.joinPermit = value
|
l.joinPermit = value
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start performs matrix /sync
|
// Start performs matrix /sync
|
||||||
func (l *Linkpearl) Start(optionalStatusMsg ...string) error {
|
func (l *Linkpearl) Start(ctx context.Context, optionalStatusMsg ...string) error {
|
||||||
l.initSync()
|
l.initSync()
|
||||||
var statusMsg string
|
var statusMsg string
|
||||||
if len(optionalStatusMsg) > 0 {
|
if len(optionalStatusMsg) > 0 {
|
||||||
statusMsg = optionalStatusMsg[0]
|
statusMsg = optionalStatusMsg[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
err := l.SetPresence(context.Background(), event.PresenceOnline, statusMsg)
|
err := l.SetPresence(ctx, event.PresenceOnline, statusMsg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.log.Error().Err(err).Msg("cannot set presence")
|
l.log.Error().Err(err).Msg("cannot set presence")
|
||||||
}
|
}
|
||||||
defer l.Stop()
|
defer l.Stop(ctx)
|
||||||
|
|
||||||
l.log.Info().Msg("client has been started")
|
l.log.Info().Msg("client has been started")
|
||||||
return l.api.Sync()
|
return l.api.SyncWithContext(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the client
|
// Stop the client
|
||||||
func (l *Linkpearl) Stop() {
|
func (l *Linkpearl) Stop(ctx context.Context) {
|
||||||
l.log.Debug().Msg("stopping the client")
|
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.log.Error().Err(err).Msg("cannot set presence")
|
||||||
}
|
}
|
||||||
l.api.StopSync()
|
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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
"maunium.net/go/mautrix"
|
"maunium.net/go/mautrix"
|
||||||
"maunium.net/go/mautrix/event"
|
"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
|
// Send a message to the roomID and automatically try to encrypt it, if the destination room is encrypted
|
||||||
//
|
//
|
||||||
//nolint:unparam // it's public interface
|
//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")
|
l.log.Debug().Str("roomID", roomID.String()).Any("content", content).Msg("sending event")
|
||||||
resp, err := l.api.SendMessageEvent(ctx, roomID, event.EventMessage, content)
|
resp, err := l.api.SendMessageEvent(ctx, roomID, event.EventMessage, content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -21,6 +22,18 @@ func (l *Linkpearl) Send(ctx context.Context, roomID id.RoomID, content interfac
|
|||||||
return resp.EventID, nil
|
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
|
// SendNotice to a room with optional relations, markdown supported
|
||||||
func (l *Linkpearl) SendNotice(ctx context.Context, roomID id.RoomID, message string, relates ...*event.RelatesTo) {
|
func (l *Linkpearl) SendNotice(ctx context.Context, roomID id.RoomID, message string, relates ...*event.RelatesTo) {
|
||||||
var withRelatesTo bool
|
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.
|
// OnEventType allows callers to be notified when there are new events for the given event type.
|
||||||
// There are no duplicate checks.
|
// There are no duplicate checks.
|
||||||
func (l *Linkpearl) OnEventType(eventType event.Type, callback mautrix.EventHandler) {
|
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
|
// OnSync shortcut to mautrix.DefaultSyncer.OnSync
|
||||||
func (l *Linkpearl) OnSync(callback mautrix.SyncHandler) {
|
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
|
// OnEvent shortcut to mautrix.DefaultSyncer.OnEvent
|
||||||
func (l *Linkpearl) OnEvent(callback mautrix.EventHandler) {
|
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() {
|
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,
|
event.StateEncryption,
|
||||||
func(ctx context.Context, evt *event.Event) {
|
func(ctx context.Context, evt *event.Event) {
|
||||||
go l.onEncryption(ctx, evt)
|
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,
|
event.StateMember,
|
||||||
func(ctx context.Context, evt *event.Event) {
|
func(ctx context.Context, evt *event.Event) {
|
||||||
go l.onMembership(ctx, evt)
|
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
|
package linkpearl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"maunium.net/go/mautrix"
|
"maunium.net/go/mautrix"
|
||||||
"maunium.net/go/mautrix/event"
|
"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
|
// UnwrapError tries to unwrap a error into something meaningful, like mautrix.HTTPError or mautrix.RespError
|
||||||
func UnwrapError(err error) error {
|
func UnwrapError(err error) error {
|
||||||
switch err.(type) {
|
var httpErr mautrix.HTTPError
|
||||||
case nil:
|
if errors.As(err, &httpErr) {
|
||||||
return nil
|
uwerr := httpErr.Unwrap()
|
||||||
case mautrix.HTTPError:
|
if uwerr != nil {
|
||||||
return unwrapHTTPError(err)
|
return uwerr
|
||||||
default:
|
}
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
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
|
|
||||||
}
|
}
|
||||||
|
|||||||
162
vendor/go.mau.fi/util/dbutil/massinsert.go
vendored
Normal file
162
vendor/go.mau.fi/util/dbutil/massinsert.go
vendored
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
// Copyright (c) 2024 Tulir Asokan
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
package dbutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Array is an interface for small fixed-size arrays.
|
||||||
|
// It exists because generics can't specify array sizes: https://github.com/golang/go/issues/44253
|
||||||
|
type Array interface {
|
||||||
|
[1]any | [2]any | [3]any | [4]any | [5]any | [6]any | [7]any | [8]any | [9]any | [10]any | [11]any | [12]any | [13]any | [14]any | [15]any | [16]any | [17]any | [18]any | [19]any | [20]any
|
||||||
|
}
|
||||||
|
|
||||||
|
// MassInsertable represents a struct that contains dynamic values for a mass insert query.
|
||||||
|
type MassInsertable[T Array] interface {
|
||||||
|
GetMassInsertValues() T
|
||||||
|
}
|
||||||
|
|
||||||
|
// MassInsertBuilder contains pre-validated templates for building mass insert SQL queries.
|
||||||
|
type MassInsertBuilder[Item MassInsertable[DynamicParams], StaticParams Array, DynamicParams Array] struct {
|
||||||
|
queryTemplate string
|
||||||
|
placeholderTemplate string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMassInsertBuilder creates a new MassInsertBuilder that can build mass insert database queries.
|
||||||
|
//
|
||||||
|
// Parameters in mass insert queries are split into two types: static parameters
|
||||||
|
// and dynamic parameters. Static parameters are the same for all items being
|
||||||
|
// inserted, while dynamic parameters are different for each item.
|
||||||
|
//
|
||||||
|
// The given query should be a normal INSERT query for a single row. It can also
|
||||||
|
// have ON CONFLICT clauses, as long as the clause uses `excluded` instead of
|
||||||
|
// positional parameters.
|
||||||
|
//
|
||||||
|
// The placeholder template is used to replace the `VALUES` part of the given
|
||||||
|
// query. It should contain a positional placeholder ($1, $2, ...) for each
|
||||||
|
// static placeholder, and a fmt directive (`$%d`) for each dynamic placeholder.
|
||||||
|
//
|
||||||
|
// The given query and placeholder template are validated here and the function
|
||||||
|
// will panic if they're invalid (e.g. if the `VALUES` part of the insert query
|
||||||
|
// can't be found, or if the placeholder template doesn't have the right things).
|
||||||
|
// The idea is to use this function to populate a global variable with the mass
|
||||||
|
// insert builder, so the panic will happen at startup if the query or
|
||||||
|
// placeholder template are invalid (instead of returning an error when trying
|
||||||
|
// to use the query later).
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// type Message struct {
|
||||||
|
// ChatID int
|
||||||
|
// RemoteID string
|
||||||
|
// MXID id.EventID
|
||||||
|
// Timestamp time.Time
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func (msg *Message) GetMassInsertValues() [3]any {
|
||||||
|
// return [3]any{msg.RemoteID, msg.MXID, msg.Timestamp.UnixMilli()}
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// const insertMessageQuery = `INSERT INTO message (chat_id, remote_id, mxid, timestamp) VALUES ($1, $2, $3, $4)`
|
||||||
|
// var massInsertMessageBuilder = dbutil.NewMassInsertBuilder[Message, [2]any](insertMessageQuery, "($1, $%d, $%d, $%d, $%d)")
|
||||||
|
//
|
||||||
|
// func DoMassInsert(ctx context.Context, messages []*Message) error {
|
||||||
|
// query, params := massInsertMessageBuilder.Build([1]any{messages[0].ChatID}, messages)
|
||||||
|
// return db.Exec(ctx, query, params...)
|
||||||
|
// }
|
||||||
|
func NewMassInsertBuilder[Item MassInsertable[DynamicParams], StaticParams Array, DynamicParams Array](
|
||||||
|
singleInsertQuery, placeholderTemplate string,
|
||||||
|
) *MassInsertBuilder[Item, StaticParams, DynamicParams] {
|
||||||
|
var dyn DynamicParams
|
||||||
|
var stat StaticParams
|
||||||
|
totalParams := len(dyn) + len(stat)
|
||||||
|
mainQueryVariablePlaceholderParts := make([]string, totalParams)
|
||||||
|
for i := 0; i < totalParams; i++ {
|
||||||
|
mainQueryVariablePlaceholderParts[i] = fmt.Sprintf(`\$%d`, i+1)
|
||||||
|
}
|
||||||
|
mainQueryVariablePlaceholderRegex := regexp.MustCompile(fmt.Sprintf(`\(\s*%s\s*\)`, strings.Join(mainQueryVariablePlaceholderParts, `\s*,\s*`)))
|
||||||
|
queryPlaceholders := mainQueryVariablePlaceholderRegex.FindAllString(singleInsertQuery, -1)
|
||||||
|
if len(queryPlaceholders) == 0 {
|
||||||
|
panic(fmt.Errorf("invalid insert query: placeholders not found"))
|
||||||
|
} else if len(queryPlaceholders) > 1 {
|
||||||
|
panic(fmt.Errorf("invalid insert query: multiple placeholders found"))
|
||||||
|
}
|
||||||
|
for i := 0; i < len(stat); i++ {
|
||||||
|
if !strings.Contains(placeholderTemplate, fmt.Sprintf("$%d", i+1)) {
|
||||||
|
panic(fmt.Errorf("invalid placeholder template: static placeholder $%d not found", i+1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strings.Contains(placeholderTemplate, fmt.Sprintf("$%d", len(stat)+1)) {
|
||||||
|
panic(fmt.Errorf("invalid placeholder template: non-static placeholder $%d found", len(stat)+1))
|
||||||
|
}
|
||||||
|
fmtParams := make([]any, len(dyn))
|
||||||
|
for i := 0; i < len(dyn); i++ {
|
||||||
|
fmtParams[i] = fmt.Sprintf("$%d", len(stat)+i+1)
|
||||||
|
}
|
||||||
|
formattedPlaceholder := fmt.Sprintf(placeholderTemplate, fmtParams...)
|
||||||
|
if strings.Contains(formattedPlaceholder, "!(EXTRA string=") {
|
||||||
|
panic(fmt.Errorf("invalid placeholder template: extra string found"))
|
||||||
|
}
|
||||||
|
for i := 0; i < len(dyn); i++ {
|
||||||
|
if !strings.Contains(formattedPlaceholder, fmt.Sprintf("$%d", len(stat)+i+1)) {
|
||||||
|
panic(fmt.Errorf("invalid placeholder template: dynamic placeholder $%d not found", len(stat)+i+1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &MassInsertBuilder[Item, StaticParams, DynamicParams]{
|
||||||
|
queryTemplate: strings.Replace(singleInsertQuery, queryPlaceholders[0], "%s", 1),
|
||||||
|
placeholderTemplate: placeholderTemplate,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build constructs a ready-to-use mass insert SQL query using the prepared templates in this builder.
|
||||||
|
//
|
||||||
|
// This method always only produces one query. If there are lots of items,
|
||||||
|
// chunking them beforehand may be required to avoid query parameter limits.
|
||||||
|
// For example, SQLite (3.32+) has a limit of 32766 parameters by default,
|
||||||
|
// while Postgres allows up to 65535. To find out if there are too many items,
|
||||||
|
// divide the maximum number of parameters by the number of dynamic columns in
|
||||||
|
// your data and subtract the number of static columns.
|
||||||
|
//
|
||||||
|
// Example of chunking input data:
|
||||||
|
//
|
||||||
|
// var mib dbutil.MassInsertBuilder
|
||||||
|
// var db *dbutil.Database
|
||||||
|
// func MassInsert(ctx context.Context, ..., data []T) error {
|
||||||
|
// return db.DoTxn(ctx, nil, func(ctx context.Context) error {
|
||||||
|
// for _, chunk := range exslices.Chunk(data, 100) {
|
||||||
|
// query, params := mib.Build(staticParams)
|
||||||
|
// _, err := db.Exec(ctx, query, params...)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
func (mib *MassInsertBuilder[Item, StaticParams, DynamicParams]) Build(static StaticParams, data []Item) (query string, params []any) {
|
||||||
|
var itemValues DynamicParams
|
||||||
|
params = make([]any, len(static)+len(itemValues)*len(data))
|
||||||
|
placeholders := make([]string, len(data))
|
||||||
|
for i := 0; i < len(static); i++ {
|
||||||
|
params[i] = static[i]
|
||||||
|
}
|
||||||
|
fmtParams := make([]any, len(itemValues))
|
||||||
|
for i, item := range data {
|
||||||
|
baseIndex := len(static) + len(itemValues)*i
|
||||||
|
itemValues = item.GetMassInsertValues()
|
||||||
|
for j := 0; j < len(itemValues); j++ {
|
||||||
|
params[baseIndex+j] = itemValues[j]
|
||||||
|
fmtParams[j] = baseIndex + j + 1
|
||||||
|
}
|
||||||
|
placeholders[i] = fmt.Sprintf(mib.placeholderTemplate, fmtParams...)
|
||||||
|
}
|
||||||
|
query = fmt.Sprintf(mib.queryTemplate, strings.Join(placeholders, ", "))
|
||||||
|
return
|
||||||
|
}
|
||||||
30
vendor/go.mau.fi/util/dbutil/reflectscan.go
vendored
Normal file
30
vendor/go.mau.fi/util/dbutil/reflectscan.go
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (c) 2024 Tulir Asokan
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
package dbutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
func reflectScan[T any](row Scannable) (*T, error) {
|
||||||
|
t := new(T)
|
||||||
|
val := reflect.ValueOf(t).Elem()
|
||||||
|
fields := reflect.VisibleFields(val.Type())
|
||||||
|
scanInto := make([]any, len(fields))
|
||||||
|
for i, field := range fields {
|
||||||
|
scanInto[i] = val.FieldByIndex(field.Index).Addr().Interface()
|
||||||
|
}
|
||||||
|
err := row.Scan(scanInto...)
|
||||||
|
return t, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSimpleReflectRowIter creates a new RowIter that uses reflection to scan rows into the given type.
|
||||||
|
//
|
||||||
|
// This is a simplified implementation that always scans to all struct fields. It does not support any kind of struct tags.
|
||||||
|
func NewSimpleReflectRowIter[T any](rows Rows, err error) RowIter[*T] {
|
||||||
|
return ConvertRowFn[*T](reflectScan[T]).NewRowIter(rows, err)
|
||||||
|
}
|
||||||
17
vendor/maunium.net/go/mautrix/CHANGELOG.md
generated
vendored
17
vendor/maunium.net/go/mautrix/CHANGELOG.md
generated
vendored
@@ -1,3 +1,20 @@
|
|||||||
|
## v0.18.1 (2024-04-16)
|
||||||
|
|
||||||
|
* *(format)* Added a `context.Context` field to HTMLParser's Context struct.
|
||||||
|
* *(bridge)* Added support for handling join rules, knocks, invites and bans
|
||||||
|
(thanks to [@maltee1] in [#193] and [#204]).
|
||||||
|
* *(crypto)* Changed forwarded room key handling to only accept keys with a
|
||||||
|
lower first known index than the existing session if there is one.
|
||||||
|
* *(crypto)* Changed key backup restore to assume own device list is up to date
|
||||||
|
to avoid re-requesting device list for every deleted device that has signed
|
||||||
|
key backup.
|
||||||
|
* *(crypto)* Fixed memory cache not being invalidated when storing own
|
||||||
|
cross-signing keys
|
||||||
|
|
||||||
|
[@maltee1]: https://github.com/maltee1
|
||||||
|
[#193]: https://github.com/mautrix/go/pull/193
|
||||||
|
[#204]: https://github.com/mautrix/go/pull/204
|
||||||
|
|
||||||
## v0.18.0 (2024-03-16)
|
## v0.18.0 (2024-03-16)
|
||||||
|
|
||||||
* **Breaking change *(client, bridge, appservice)*** Dropped support for
|
* **Breaking change *(client, bridge, appservice)*** Dropped support for
|
||||||
|
|||||||
18
vendor/maunium.net/go/mautrix/client.go
generated
vendored
18
vendor/maunium.net/go/mautrix/client.go
generated
vendored
@@ -338,6 +338,7 @@ type FullRequest struct {
|
|||||||
SensitiveContent bool
|
SensitiveContent bool
|
||||||
Handler ClientResponseHandler
|
Handler ClientResponseHandler
|
||||||
Logger *zerolog.Logger
|
Logger *zerolog.Logger
|
||||||
|
Client *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
var requestID int32
|
var requestID int32
|
||||||
@@ -424,7 +425,10 @@ func (cli *Client) MakeFullRequest(ctx context.Context, params FullRequest) ([]b
|
|||||||
if len(cli.AccessToken) > 0 {
|
if len(cli.AccessToken) > 0 {
|
||||||
req.Header.Set("Authorization", "Bearer "+cli.AccessToken)
|
req.Header.Set("Authorization", "Bearer "+cli.AccessToken)
|
||||||
}
|
}
|
||||||
return cli.executeCompiledRequest(req, params.MaxAttempts-1, 4*time.Second, params.ResponseJSON, params.Handler)
|
if params.Client == nil {
|
||||||
|
params.Client = cli.Client
|
||||||
|
}
|
||||||
|
return cli.executeCompiledRequest(req, params.MaxAttempts-1, 4*time.Second, params.ResponseJSON, params.Handler, params.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *Client) cliOrContextLog(ctx context.Context) *zerolog.Logger {
|
func (cli *Client) cliOrContextLog(ctx context.Context) *zerolog.Logger {
|
||||||
@@ -435,7 +439,7 @@ func (cli *Client) cliOrContextLog(ctx context.Context) *zerolog.Logger {
|
|||||||
return log
|
return log
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *Client) doRetry(req *http.Request, cause error, retries int, backoff time.Duration, responseJSON interface{}, handler ClientResponseHandler) ([]byte, error) {
|
func (cli *Client) doRetry(req *http.Request, cause error, retries int, backoff time.Duration, responseJSON interface{}, handler ClientResponseHandler, client *http.Client) ([]byte, error) {
|
||||||
log := zerolog.Ctx(req.Context())
|
log := zerolog.Ctx(req.Context())
|
||||||
if req.Body != nil {
|
if req.Body != nil {
|
||||||
if req.GetBody == nil {
|
if req.GetBody == nil {
|
||||||
@@ -453,7 +457,7 @@ func (cli *Client) doRetry(req *http.Request, cause error, retries int, backoff
|
|||||||
Int("retry_in_seconds", int(backoff.Seconds())).
|
Int("retry_in_seconds", int(backoff.Seconds())).
|
||||||
Msg("Request failed, retrying")
|
Msg("Request failed, retrying")
|
||||||
time.Sleep(backoff)
|
time.Sleep(backoff)
|
||||||
return cli.executeCompiledRequest(req, retries-1, backoff*2, responseJSON, handler)
|
return cli.executeCompiledRequest(req, retries-1, backoff*2, responseJSON, handler, client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func readRequestBody(req *http.Request, res *http.Response) ([]byte, error) {
|
func readRequestBody(req *http.Request, res *http.Response) ([]byte, error) {
|
||||||
@@ -535,17 +539,17 @@ func ParseErrorResponse(req *http.Request, res *http.Response) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *Client) executeCompiledRequest(req *http.Request, retries int, backoff time.Duration, responseJSON interface{}, handler ClientResponseHandler) ([]byte, error) {
|
func (cli *Client) executeCompiledRequest(req *http.Request, retries int, backoff time.Duration, responseJSON interface{}, handler ClientResponseHandler, client *http.Client) ([]byte, error) {
|
||||||
cli.RequestStart(req)
|
cli.RequestStart(req)
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
res, err := cli.Client.Do(req)
|
res, err := client.Do(req)
|
||||||
duration := time.Now().Sub(startTime)
|
duration := time.Now().Sub(startTime)
|
||||||
if res != nil {
|
if res != nil {
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if retries > 0 {
|
if retries > 0 {
|
||||||
return cli.doRetry(req, err, retries, backoff, responseJSON, handler)
|
return cli.doRetry(req, err, retries, backoff, responseJSON, handler, client)
|
||||||
}
|
}
|
||||||
err = HTTPError{
|
err = HTTPError{
|
||||||
Request: req,
|
Request: req,
|
||||||
@@ -560,7 +564,7 @@ func (cli *Client) executeCompiledRequest(req *http.Request, retries int, backof
|
|||||||
|
|
||||||
if retries > 0 && retryafter.Should(res.StatusCode, !cli.IgnoreRateLimit) {
|
if retries > 0 && retryafter.Should(res.StatusCode, !cli.IgnoreRateLimit) {
|
||||||
backoff = retryafter.Parse(res.Header.Get("Retry-After"), backoff)
|
backoff = retryafter.Parse(res.Header.Get("Retry-After"), backoff)
|
||||||
return cli.doRetry(req, fmt.Errorf("HTTP %d", res.StatusCode), retries, backoff, responseJSON, handler)
|
return cli.doRetry(req, fmt.Errorf("HTTP %d", res.StatusCode), retries, backoff, responseJSON, handler, client)
|
||||||
}
|
}
|
||||||
|
|
||||||
var body []byte
|
var body []byte
|
||||||
|
|||||||
7
vendor/maunium.net/go/mautrix/crypto/cross_sign_store.go
generated
vendored
7
vendor/maunium.net/go/mautrix/crypto/cross_sign_store.go
generated
vendored
@@ -96,5 +96,12 @@ func (mach *OlmMachine) storeCrossSigningKeys(ctx context.Context, crossSigningK
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear internal cache so that it refreshes from crypto store
|
||||||
|
if userID == mach.Client.UserID && mach.crossSigningPubkeys != nil {
|
||||||
|
log.Debug().Msg("Resetting internal cross-signing key cache")
|
||||||
|
mach.crossSigningPubkeys = nil
|
||||||
|
mach.crossSigningPubkeysFetched = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
vendor/maunium.net/go/mautrix/crypto/cross_sign_validation.go
generated
vendored
2
vendor/maunium.net/go/mautrix/crypto/cross_sign_validation.go
generated
vendored
@@ -32,7 +32,7 @@ func (mach *OlmMachine) ResolveTrustContext(ctx context.Context, device *id.Devi
|
|||||||
}
|
}
|
||||||
theirMSK, ok := theirKeys[id.XSUsageMaster]
|
theirMSK, ok := theirKeys[id.XSUsageMaster]
|
||||||
if !ok {
|
if !ok {
|
||||||
mach.machOrContextLog(ctx).Error().
|
mach.machOrContextLog(ctx).Debug().
|
||||||
Str("user_id", device.UserID.String()).
|
Str("user_id", device.UserID.String()).
|
||||||
Msg("Master key of user not found")
|
Msg("Master key of user not found")
|
||||||
return id.TrustStateUnset, nil
|
return id.TrustStateUnset, nil
|
||||||
|
|||||||
6
vendor/maunium.net/go/mautrix/crypto/keybackup.go
generated
vendored
6
vendor/maunium.net/go/mautrix/crypto/keybackup.go
generated
vendored
@@ -66,8 +66,10 @@ func (mach *OlmMachine) GetAndVerifyLatestKeyBackupVersion(ctx context.Context)
|
|||||||
var key id.Ed25519
|
var key id.Ed25519
|
||||||
if keyName == crossSigningPubkeys.MasterKey.String() {
|
if keyName == crossSigningPubkeys.MasterKey.String() {
|
||||||
key = crossSigningPubkeys.MasterKey
|
key = crossSigningPubkeys.MasterKey
|
||||||
} else if device, err := mach.GetOrFetchDevice(ctx, mach.Client.UserID, id.DeviceID(keyName)); err != nil {
|
} else if device, err := mach.CryptoStore.GetDevice(ctx, mach.Client.UserID, id.DeviceID(keyName)); err != nil {
|
||||||
log.Warn().Err(err).Msg("Failed to fetch device")
|
return nil, fmt.Errorf("failed to get device %s/%s from store: %w", mach.Client.UserID, keyName, err)
|
||||||
|
} else if device == nil {
|
||||||
|
log.Warn().Err(err).Msg("Device does not exist, ignoring signature")
|
||||||
continue
|
continue
|
||||||
} else if !mach.IsDeviceTrusted(device) {
|
} else if !mach.IsDeviceTrusted(device) {
|
||||||
log.Warn().Err(err).Msg("Device is not trusted")
|
log.Warn().Err(err).Msg("Device is not trusted")
|
||||||
|
|||||||
5
vendor/maunium.net/go/mautrix/crypto/keysharing.go
generated
vendored
5
vendor/maunium.net/go/mautrix/crypto/keysharing.go
generated
vendored
@@ -184,6 +184,11 @@ func (mach *OlmMachine) importForwardedRoomKey(ctx context.Context, evt *Decrypt
|
|||||||
MaxMessages: maxMessages,
|
MaxMessages: maxMessages,
|
||||||
IsScheduled: content.IsScheduled,
|
IsScheduled: content.IsScheduled,
|
||||||
}
|
}
|
||||||
|
existingIGS, _ := mach.CryptoStore.GetGroupSession(ctx, igs.RoomID, igs.SenderKey, igs.ID())
|
||||||
|
if existingIGS != nil && existingIGS.Internal.FirstKnownIndex() <= igs.Internal.FirstKnownIndex() {
|
||||||
|
// We already have an equivalent or better session in the store, so don't override it.
|
||||||
|
return false
|
||||||
|
}
|
||||||
err = mach.CryptoStore.PutGroupSession(ctx, content.RoomID, content.SenderKey, content.SessionID, igs)
|
err = mach.CryptoStore.PutGroupSession(ctx, content.RoomID, content.SenderKey, content.SessionID, igs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Failed to store new inbound group session")
|
log.Error().Err(err).Msg("Failed to store new inbound group session")
|
||||||
|
|||||||
3
vendor/maunium.net/go/mautrix/event/events.go
generated
vendored
3
vendor/maunium.net/go/mautrix/event/events.go
generated
vendored
@@ -149,5 +149,6 @@ type Unsigned struct {
|
|||||||
|
|
||||||
func (us *Unsigned) IsEmpty() bool {
|
func (us *Unsigned) IsEmpty() bool {
|
||||||
return us.PrevContent == nil && us.PrevSender == "" && us.ReplacesState == "" && us.Age == 0 &&
|
return us.PrevContent == nil && us.PrevSender == "" && us.ReplacesState == "" && us.Age == 0 &&
|
||||||
us.TransactionID == "" && us.RedactedBecause == nil && us.InviteRoomState == nil && us.Relations == nil
|
us.TransactionID == "" && us.RedactedBecause == nil && us.InviteRoomState == nil && us.Relations == nil &&
|
||||||
|
us.BeeperHSOrder == 0
|
||||||
}
|
}
|
||||||
|
|||||||
9
vendor/maunium.net/go/mautrix/format/htmlparser.go
generated
vendored
9
vendor/maunium.net/go/mautrix/format/htmlparser.go
generated
vendored
@@ -7,6 +7,7 @@
|
|||||||
package format
|
package format
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -33,14 +34,16 @@ func (ts TagStack) Has(tag string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Context struct {
|
type Context struct {
|
||||||
|
Ctx context.Context
|
||||||
ReturnData map[string]any
|
ReturnData map[string]any
|
||||||
TagStack TagStack
|
TagStack TagStack
|
||||||
|
|
||||||
PreserveWhitespace bool
|
PreserveWhitespace bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewContext() Context {
|
func NewContext(ctx context.Context) Context {
|
||||||
return Context{
|
return Context{
|
||||||
|
Ctx: ctx,
|
||||||
ReturnData: map[string]any{},
|
ReturnData: map[string]any{},
|
||||||
TagStack: make(TagStack, 0, 4),
|
TagStack: make(TagStack, 0, 4),
|
||||||
}
|
}
|
||||||
@@ -411,7 +414,7 @@ func HTMLToText(html string) string {
|
|||||||
Newline: "\n",
|
Newline: "\n",
|
||||||
HorizontalLine: "\n---\n",
|
HorizontalLine: "\n---\n",
|
||||||
PillConverter: DefaultPillConverter,
|
PillConverter: DefaultPillConverter,
|
||||||
}).Parse(html, NewContext())
|
}).Parse(html, NewContext(context.TODO()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTMLToMarkdown converts Matrix HTML into markdown with the default settings.
|
// HTMLToMarkdown converts Matrix HTML into markdown with the default settings.
|
||||||
@@ -429,5 +432,5 @@ func HTMLToMarkdown(html string) string {
|
|||||||
}
|
}
|
||||||
return fmt.Sprintf("[%s](%s)", text, href)
|
return fmt.Sprintf("[%s](%s)", text, href)
|
||||||
},
|
},
|
||||||
}).Parse(html, NewContext())
|
}).Parse(html, NewContext(context.TODO()))
|
||||||
}
|
}
|
||||||
|
|||||||
2
vendor/maunium.net/go/mautrix/version.go
generated
vendored
2
vendor/maunium.net/go/mautrix/version.go
generated
vendored
@@ -7,7 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Version = "v0.18.0"
|
const Version = "v0.18.1"
|
||||||
|
|
||||||
var GoModVersion = ""
|
var GoModVersion = ""
|
||||||
var Commit = ""
|
var Commit = ""
|
||||||
|
|||||||
14
vendor/modules.txt
vendored
14
vendor/modules.txt
vendored
@@ -17,7 +17,7 @@ github.com/emersion/go-msgauth/dkim
|
|||||||
# github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43
|
# github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43
|
||||||
## explicit; go 1.12
|
## explicit; go 1.12
|
||||||
github.com/emersion/go-sasl
|
github.com/emersion/go-sasl
|
||||||
# github.com/emersion/go-smtp v0.21.0
|
# github.com/emersion/go-smtp v0.21.1
|
||||||
## explicit; go 1.13
|
## explicit; go 1.13
|
||||||
github.com/emersion/go-smtp
|
github.com/emersion/go-smtp
|
||||||
# github.com/fsnotify/fsnotify v1.7.0
|
# github.com/fsnotify/fsnotify v1.7.0
|
||||||
@@ -136,13 +136,13 @@ gitlab.com/etke.cc/go/env
|
|||||||
# gitlab.com/etke.cc/go/fswatcher v1.0.0
|
# gitlab.com/etke.cc/go/fswatcher v1.0.0
|
||||||
## explicit; go 1.20
|
## explicit; go 1.20
|
||||||
gitlab.com/etke.cc/go/fswatcher
|
gitlab.com/etke.cc/go/fswatcher
|
||||||
# gitlab.com/etke.cc/go/healthchecks/v2 v2.0.0
|
# gitlab.com/etke.cc/go/healthchecks/v2 v2.2.0
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
gitlab.com/etke.cc/go/healthchecks/v2
|
gitlab.com/etke.cc/go/healthchecks/v2
|
||||||
# gitlab.com/etke.cc/go/mxidwc v1.0.0
|
# gitlab.com/etke.cc/go/mxidwc v1.0.0
|
||||||
## explicit; go 1.19
|
## explicit; go 1.19
|
||||||
gitlab.com/etke.cc/go/mxidwc
|
gitlab.com/etke.cc/go/mxidwc
|
||||||
# gitlab.com/etke.cc/go/psd v1.1.1
|
# gitlab.com/etke.cc/go/psd v1.1.2
|
||||||
## explicit; go 1.21.0
|
## explicit; go 1.21.0
|
||||||
gitlab.com/etke.cc/go/psd
|
gitlab.com/etke.cc/go/psd
|
||||||
# gitlab.com/etke.cc/go/secgen v1.2.0
|
# gitlab.com/etke.cc/go/secgen v1.2.0
|
||||||
@@ -154,10 +154,10 @@ gitlab.com/etke.cc/go/trysmtp
|
|||||||
# gitlab.com/etke.cc/go/validator v1.0.7
|
# gitlab.com/etke.cc/go/validator v1.0.7
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
gitlab.com/etke.cc/go/validator
|
gitlab.com/etke.cc/go/validator
|
||||||
# gitlab.com/etke.cc/linkpearl v0.0.0-20240316115913-106577b88942
|
# gitlab.com/etke.cc/linkpearl v0.0.0-20240425105001-435ae2720365
|
||||||
## explicit; go 1.21
|
## explicit; go 1.21
|
||||||
gitlab.com/etke.cc/linkpearl
|
gitlab.com/etke.cc/linkpearl
|
||||||
# go.mau.fi/util v0.4.1
|
# go.mau.fi/util v0.4.2
|
||||||
## explicit; go 1.21
|
## explicit; go 1.21
|
||||||
go.mau.fi/util/base58
|
go.mau.fi/util/base58
|
||||||
go.mau.fi/util/dbutil
|
go.mau.fi/util/dbutil
|
||||||
@@ -182,7 +182,7 @@ golang.org/x/crypto/internal/poly1305
|
|||||||
golang.org/x/crypto/pbkdf2
|
golang.org/x/crypto/pbkdf2
|
||||||
golang.org/x/crypto/ssh
|
golang.org/x/crypto/ssh
|
||||||
golang.org/x/crypto/ssh/internal/bcrypt_pbkdf
|
golang.org/x/crypto/ssh/internal/bcrypt_pbkdf
|
||||||
# golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0
|
# golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f
|
||||||
## explicit; go 1.20
|
## explicit; go 1.20
|
||||||
golang.org/x/exp/constraints
|
golang.org/x/exp/constraints
|
||||||
golang.org/x/exp/maps
|
golang.org/x/exp/maps
|
||||||
@@ -220,7 +220,7 @@ golang.org/x/text/language
|
|||||||
golang.org/x/text/runes
|
golang.org/x/text/runes
|
||||||
golang.org/x/text/transform
|
golang.org/x/text/transform
|
||||||
golang.org/x/text/unicode/norm
|
golang.org/x/text/unicode/norm
|
||||||
# maunium.net/go/mautrix v0.18.0
|
# maunium.net/go/mautrix v0.18.1
|
||||||
## explicit; go 1.21
|
## explicit; go 1.21
|
||||||
maunium.net/go/mautrix
|
maunium.net/go/mautrix
|
||||||
maunium.net/go/mautrix/crypto
|
maunium.net/go/mautrix/crypto
|
||||||
|
|||||||
Reference in New Issue
Block a user