~emersion/soju-dev

Truncate message times to the second when using the FS message store v1 APPLIED

delthas: 1
 Truncate message times to the second when using the FS message store

 4 files changed, 25 insertions(+), 5 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~emersion/soju-dev/patches/36190/mbox | git am -3
Learn more about email & git

[PATCH] Truncate message times to the second when using the FS message store Export this patch

The FS message store truncates message times to the second.

This means that a message sent out as 2020-01-01T00:00:00.123Z could be
sent later as part of a CHATHISTORY batch as 2020-01-01T00:00:00.000Z,
which could cause issues in clients.

One such issue is a client sending a MARKREAD for
2020-01-01T00:00:00.000Z, with another client considering the
2020-01-01T00:00:00.123Z message it has as unread.

This fixes the issue by truncating all message times to the second when
using the FS message store.
---
 downstream.go  |  6 +++---
 msgstore/fs.go |  5 +++++
 upstream.go    |  8 ++++++--
 user.go        | 11 +++++++++++
 4 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/downstream.go b/downstream.go
index 6302a5c..45c8576 100644
--- a/downstream.go
+++ b/downstream.go
@@ -2280,7 +2280,7 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
				dc.logger.Printf("broadcasting bouncer-wide %v: %v", msg.Command, text)

				broadcastTags := tags.Copy()
				broadcastTags["time"] = irc.TagValue(xirc.FormatServerTime(time.Now()))
				broadcastTags["time"] = irc.TagValue(dc.user.FormatServerTime(time.Now()))
				broadcastMsg := &irc.Message{
					Tags:    broadcastTags,
					Prefix:  servicePrefix,
@@ -2306,7 +2306,7 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
			if casemapASCII(name) == serviceNickCM {
				if dc.caps.IsEnabled("echo-message") {
					echoTags := tags.Copy()
					echoTags["time"] = irc.TagValue(xirc.FormatServerTime(time.Now()))
					echoTags["time"] = irc.TagValue(dc.user.FormatServerTime(time.Now()))
					dc.SendMessage(&irc.Message{
						Tags:    echoTags,
						Prefix:  dc.prefix(),
@@ -2350,7 +2350,7 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
				}

				echoTags := tags.Copy()
				echoTags["time"] = irc.TagValue(xirc.FormatServerTime(time.Now()))
				echoTags["time"] = irc.TagValue(dc.user.FormatServerTime(time.Now()))
				if uc.account != "" {
					echoTags["account"] = irc.TagValue(uc.account)
				}
diff --git a/msgstore/fs.go b/msgstore/fs.go
index 53f9977..65db04e 100644
--- a/msgstore/fs.go
+++ b/msgstore/fs.go
@@ -96,6 +96,11 @@ var (
	_ RenameNetworkStore = (*fsMessageStore)(nil)
)

func IsFSStore(store Store) bool {
	_, ok := store.(*fsMessageStore)
	return ok
}

func NewFSStore(root string, user *database.User) *fsMessageStore {
	return &fsMessageStore{
		root:  filepath.Join(root, escapeFilename(user.Username)),
diff --git a/upstream.go b/upstream.go
index e1030a2..4aa3ff9 100644
--- a/upstream.go
+++ b/upstream.go
@@ -485,8 +485,12 @@ func (uc *upstreamConn) handleMessage(ctx context.Context, msg *irc.Message) err
		msg.Prefix = uc.serverPrefix
	}

	if _, ok := msg.Tags["time"]; !ok && !isNumeric(msg.Command) {
		msg.Tags["time"] = irc.TagValue(xirc.FormatServerTime(time.Now()))
	if !isNumeric(msg.Command) {
		t, err := time.Parse(xirc.ServerTimeLayout, string(msg.Tags["time"]))
		if err != nil {
			t = time.Now()
		}
		msg.Tags["time"] = irc.TagValue(uc.user.FormatServerTime(t))
	}

	switch msg.Command {
diff --git a/user.go b/user.go
index 7468483..43ea79a 100644
--- a/user.go
+++ b/user.go
@@ -13,6 +13,8 @@ import (
	"strings"
	"time"

	"git.sr.ht/~emersion/soju/xirc"

	"github.com/SherClockHolmes/webpush-go"
	"gopkg.in/irc.v3"

@@ -1114,6 +1116,15 @@ func (u *user) hasPersistentMsgStore() bool {
	return !msgstore.IsMemoryStore(u.msgStore)
}

func (u *user) FormatServerTime(t time.Time) string {
	if u.msgStore != nil && msgstore.IsFSStore(u.msgStore) {
		// The FS message store truncates message timestamps to the second,
		// so truncate them here to get consistent timestamps.
		t = t.Truncate(time.Second)
	}
	return xirc.FormatServerTime(t)
}

// localAddrForHost returns the local address to use when connecting to host.
// A nil address is returned when the OS should automatically pick one.
func (u *user) localTCPAddrForHost(ctx context.Context, host string) (*net.TCPAddr, error) {

base-commit: 90be9a8ab95a06d7e622852bf312116c7e199d48
-- 
2.17.1
Pushed, thanks!