From d1c48b9b31c428322ba43a0834f74115feadbfad Mon Sep 17 00:00:00 2001 From: Aine Date: Sat, 27 Aug 2022 22:10:22 +0300 Subject: [PATCH 1/8] add per-room mutex, possibly fixes #8 --- bot/bot.go | 2 ++ bot/email.go | 2 ++ bot/mutext.go | 26 ++++++++++++++++++++++++++ e2e/send-stress | 8 ++++++++ 4 files changed, 38 insertions(+) create mode 100644 bot/mutext.go create mode 100755 e2e/send-stress diff --git a/bot/bot.go b/bot/bot.go index 83826be..56d25c8 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -22,6 +22,7 @@ type Bot struct { rooms sync.Map log *logger.Logger lp *linkpearl.Linkpearl + mu map[id.RoomID]*sync.Mutex handledMembershipEvents sync.Map } @@ -35,6 +36,7 @@ func New(lp *linkpearl.Linkpearl, log *logger.Logger, prefix, domain string, noo rooms: sync.Map{}, log: log, lp: lp, + mu: map[id.RoomID]*sync.Mutex{}, } } diff --git a/bot/email.go b/bot/email.go index e4849af..b82f9d5 100644 --- a/bot/email.go +++ b/bot/email.go @@ -49,6 +49,8 @@ func (b *Bot) Send(ctx context.Context, email *utils.Email) error { if !ok { return errors.New("room not found") } + b.lock(roomID) + defer b.unlock(roomID) cfg, err := b.getSettings(roomID) if err != nil { diff --git a/bot/mutext.go b/bot/mutext.go new file mode 100644 index 0000000..8bc091d --- /dev/null +++ b/bot/mutext.go @@ -0,0 +1,26 @@ +package bot + +import ( + "sync" + + "maunium.net/go/mautrix/id" +) + +func (b *Bot) lock(roomID id.RoomID) { + _, ok := b.mu[roomID] + if !ok { + b.mu[roomID] = &sync.Mutex{} + } + + b.mu[roomID].Lock() +} + +func (b *Bot) unlock(roomID id.RoomID) { + _, ok := b.mu[roomID] + if !ok { + return + } + + b.mu[roomID].Unlock() + delete(b.mu, roomID) +} diff --git a/e2e/send-stress b/e2e/send-stress new file mode 100755 index 0000000..e4b5da9 --- /dev/null +++ b/e2e/send-stress @@ -0,0 +1,8 @@ +#!/bin/bash + +for i in {0..10..1}; do + echo "#${i}..." + ssmtp test@localhost < $1 +done + +echo "done" From 6eae1a65c4aabbfcd368b648ff47914458b477bf Mon Sep 17 00:00:00 2001 From: Aine Date: Sat, 27 Aug 2022 22:38:23 +0300 Subject: [PATCH 2/8] add utils.UnwrapError() to provide meaningful error messages --- bot/email.go | 2 +- bot/settings.go | 4 ++-- utils/matrix.go | 27 +++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/bot/email.go b/bot/email.go index b82f9d5..4c142b9 100644 --- a/bot/email.go +++ b/bot/email.go @@ -68,7 +68,7 @@ func (b *Bot) Send(ctx context.Context, email *utils.Email) error { content := email2content(email, cfg, threadID) eventID, serr := b.lp.Send(roomID, content) if serr != nil { - return serr + return utils.UnwrapError(serr) } if threadID == "" && !cfg.NoThreads() { diff --git a/bot/settings.go b/bot/settings.go index ad37899..bc933ed 100644 --- a/bot/settings.go +++ b/bot/settings.go @@ -112,9 +112,9 @@ func (b *Bot) getSettings(roomID id.RoomID) (settings, error) { } } - return config, err + return config, utils.UnwrapError(err) } func (b *Bot) setSettings(roomID id.RoomID, cfg settings) error { - return b.lp.GetClient().SetRoomAccountData(roomID, settingskey, cfg) + return utils.UnwrapError(b.lp.GetClient().SetRoomAccountData(roomID, settingskey, cfg)) } diff --git a/utils/matrix.go b/utils/matrix.go index faa2a54..0115996 100644 --- a/utils/matrix.go +++ b/utils/matrix.go @@ -1,6 +1,7 @@ package utils import ( + "maunium.net/go/mautrix" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" ) @@ -24,3 +25,29 @@ func RelatesTo(noThreads bool, parentID id.EventID) *event.RelatesTo { EventID: parentID, } } + +// UnwrapError tries to unwrap a error into something meaningful, like mautrix.HTTPError or mautrix.RespError +func UnwrapError(err error) error { + switch err.(type) { + case nil: + return nil + case mautrix.HTTPError: + return unwrapHTTPError(err) + default: + return err + } +} + +func unwrapHTTPError(err error) error { + httperr, ok := err.(mautrix.HTTPError) + if !ok { + return err + } + + uwerr := httperr.Unwrap() + if uwerr != nil { + return uwerr + } + + return httperr +} From 13776ad7a6a39f3829f4d3425fbdac7c8960ff2b Mon Sep 17 00:00:00 2001 From: Aine Date: Sun, 28 Aug 2022 09:37:18 +0300 Subject: [PATCH 3/8] properly update mailbox, fixes #9 --- bot/bot.go | 14 -------------- bot/command.go | 7 ++++++- bot/email.go | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/bot/bot.go b/bot/bot.go index 56d25c8..42db622 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -78,20 +78,6 @@ func (b *Bot) Start(statusMsg string) error { return b.lp.Start(statusMsg) } -// GetMappings returns mapping of mailbox = room -func (b *Bot) GetMapping(mailbox string) (id.RoomID, bool) { - v, ok := b.rooms.Load(mailbox) - if !ok { - return "", ok - } - roomID, ok := v.(id.RoomID) - if !ok { - return "", ok - } - - return roomID, ok -} - // Stop the bot func (b *Bot) Stop() { err := b.lp.GetClient().SetPresence(event.PresenceOffline) diff --git a/bot/command.go b/bot/command.go index ea19740..40438e0 100644 --- a/bot/command.go +++ b/bot/command.go @@ -256,11 +256,16 @@ func (b *Bot) setOption(ctx context.Context, name, value string) { return } + old := cfg.Get(name) cfg.Set(name, value) + if name == optionMailbox { - value = fmt.Sprintf("%s@%s", value, b.domain) cfg.Set(optionOwner, evt.Sender.String()) + if old != "" { + b.rooms.Delete(old) + } b.rooms.Store(value, evt.RoomID) + value = fmt.Sprintf("%s@%s", value, b.domain) } err = b.setSettings(evt.RoomID, cfg) diff --git a/bot/email.go b/bot/email.go index 4c142b9..4b13e80 100644 --- a/bot/email.go +++ b/bot/email.go @@ -43,6 +43,25 @@ func email2content(email *utils.Email, cfg settings, threadID id.EventID) *event return &content } +// GetMapping returns mapping of mailbox = room +func (b *Bot) GetMapping(mailbox string) (id.RoomID, bool) { + b.rooms.Range(func(key, value any) bool { + b.log.Debug("MAPPING %v=%v", key, value) + + return true + }) + v, ok := b.rooms.Load(mailbox) + if !ok { + return "", ok + } + roomID, ok := v.(id.RoomID) + if !ok { + return "", ok + } + + return roomID, ok +} + // Send email to matrix room func (b *Bot) Send(ctx context.Context, email *utils.Email) error { roomID, ok := b.GetMapping(utils.Mailbox(email.To)) From 9b1eb161e756cd51b10897f239dd81cd5b818507 Mon Sep 17 00:00:00 2001 From: Aine Date: Sun, 28 Aug 2022 09:37:32 +0300 Subject: [PATCH 4/8] remove debug --- bot/email.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/bot/email.go b/bot/email.go index 4b13e80..cf8b10a 100644 --- a/bot/email.go +++ b/bot/email.go @@ -45,11 +45,6 @@ func email2content(email *utils.Email, cfg settings, threadID id.EventID) *event // GetMapping returns mapping of mailbox = room func (b *Bot) GetMapping(mailbox string) (id.RoomID, bool) { - b.rooms.Range(func(key, value any) bool { - b.log.Debug("MAPPING %v=%v", key, value) - - return true - }) v, ok := b.rooms.Load(mailbox) if !ok { return "", ok From 0e33107a4a27a9827b05474a11bcda157476ffc7 Mon Sep 17 00:00:00 2001 From: Aine Date: Sun, 28 Aug 2022 17:18:22 +0300 Subject: [PATCH 5/8] add usage section in readme --- README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/README.md b/README.md index 3a5ecf1..3132b45 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,36 @@ env vars You can find default values in [config/defaults.go](config/defaults.go) +## Usage + +### How to start + +1. Invite the bot into a room you want to use as mailbox +2. Read the bot's introduction +3. Set mailbox using `!pm mailbox NAME` where `NAME` is part of email (e.g. `NAME@example.com`) +4. Done. Mailbox owner and other options will be set automatically when you configure mailbox. +If you want to change them - check available options in the help message (`!pm help`) + +### Commands + +The following commands are supported + +* **!pm help** - Show help message +* **!pm stop** - Disable bridge for the room and clear all configuration + +--- + +* **!pm mailbox** - Get or set mailbox of the room +* **!pm owner** - Get or set owner of the room + +--- + +* **!pm nosender** - Get or set `nosender` of the room (`true` - hide email sender; `false` - show email sender) +* **!pm nosubject** - Get or set `nosubject` of the room (`true` - hide email subject; `false` - show email subject) +* **!pm nohtml** - Get or set `nohtml` of the room (`true` - ignore HTML in email; `false` - parse HTML in emails) +* **!pm nothreads** - Get or set `nothreads` of the room (`true` - ignore email threads; `false` - convert email threads into matrix threads) +* **!pm nofiles** - Get or set `nofiles` of the room (`true` - ignore email attachments; `false` - upload email attachments) + ## Where to get [docker registry](https://gitlab.com/etke.cc/postmoogle/container_registry), [etke.cc](https://etke.cc) From 67fbc98c018d610bcd481dbcfdb575df1329c421 Mon Sep 17 00:00:00 2001 From: Aine Date: Sun, 28 Aug 2022 17:34:02 +0300 Subject: [PATCH 6/8] [skip ci] update readme --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3132b45..dddc98e 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,8 @@ env vars * **POSTMOOGLE_DOMAIN** - SMTP domain to listen for new emails * **POSTMOOGLE_PORT** - SMTP port to listen for new emails -### optional +
+other optional config parameters * **POSTMOOGLE_NOOWNER** - allow change room settings by any room partisipant * **POSTMOOGLE_FEDERATION** - allow usage of Postmoogle by users from others homeservers @@ -47,6 +48,8 @@ env vars You can find default values in [config/defaults.go](config/defaults.go) +
+ ## Usage ### How to start From a150ada5c4d52910f6c5ae8a11deb33bd31455db Mon Sep 17 00:00:00 2001 From: Aine Date: Sun, 28 Aug 2022 17:35:15 +0300 Subject: [PATCH 7/8] [skip ci] update readme --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index dddc98e..b34d4b2 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,6 @@ An Email to Matrix bridge env vars -### mandatory - * **POSTMOOGLE_HOMESERVER** - homeserver url, eg: `https://matrix.example.com` * **POSTMOOGLE_LOGIN** - user login/localpart, eg: `moogle` * **POSTMOOGLE_PASSWORD** - user password @@ -60,7 +58,8 @@ You can find default values in [config/defaults.go](config/defaults.go) 4. Done. Mailbox owner and other options will be set automatically when you configure mailbox. If you want to change them - check available options in the help message (`!pm help`) -### Commands +
+Full list of available commands The following commands are supported @@ -80,6 +79,9 @@ The following commands are supported * **!pm nothreads** - Get or set `nothreads` of the room (`true` - ignore email threads; `false` - convert email threads into matrix threads) * **!pm nofiles** - Get or set `nofiles` of the room (`true` - ignore email attachments; `false` - upload email attachments) +
+ + ## Where to get [docker registry](https://gitlab.com/etke.cc/postmoogle/container_registry), [etke.cc](https://etke.cc) From 3174b21aece58494919755a17c0dc84138c6ccea Mon Sep 17 00:00:00 2001 From: Aine Date: Sun, 28 Aug 2022 17:35:53 +0300 Subject: [PATCH 8/8] [skip ci] update readme --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index b34d4b2..b43ad0c 100644 --- a/README.md +++ b/README.md @@ -61,8 +61,6 @@ If you want to change them - check available options in the help message (`!pm h
Full list of available commands -The following commands are supported - * **!pm help** - Show help message * **!pm stop** - Disable bridge for the room and clear all configuration