diff options
| author | EuAndreh <eu@euandre.org> | 2026-04-26 18:31:39 -0300 |
|---|---|---|
| committer | EuAndreh <eu@euandre.org> | 2026-04-26 18:31:39 -0300 |
| commit | d648097914710316f9f9d5b39cd6e7002a06463e (patch) | |
| tree | 75d0094d7d2d98298d7169f3894c976e62c6ce71 /src/papod.clj | |
| parent | MARKREAD: monotonic timestamps and FAIL on missing params (diff) | |
| download | papod-d648097914710316f9f9d5b39cd6e7002a06463e.tar.gz papod-d648097914710316f9f9d5b39cd6e7002a06463e.tar.xz | |
MARKREAD on JOIN and DM targets
When a client with draft/read-marker JOINs a channel, send a
MARKREAD line with the stored timestamp (or '*' if none) before
the closing RPL_ENDOFNAMES.
Also support MARKREAD against direct-message targets (user
nicknames, not just channels): per-(owner,target) markers are
stored in a new in-memory atom :user-markers.
Diffstat (limited to 'src/papod.clj')
| -rw-r--r-- | src/papod.clj | 93 |
1 files changed, 61 insertions, 32 deletions
diff --git a/src/papod.clj b/src/papod.clj index 27dfad0..0f2001b 100644 --- a/src/papod.clj +++ b/src/papod.clj @@ -2375,6 +2375,27 @@ " " handle " " nick " " (quot (System/currentTimeMillis) 1000)))) + ;; draft/read-marker: send MARKREAD before + ;; RPL_ENDOFNAMES if the client has the cap + (when (and w + (contains? + (or (:caps @client) #{}) + "draft/read-marker")) + (let [stored (when (and conn ch-eid') + (ffirst + (d/q '{:find [?ts] + :in [$ ?ch ?nick] + :where + [[?r :papod.read-marker/channel ?ch] + [?r :papod.read-marker/nick ?nick] + [?r :papod.read-marker/timestamp ?ts]]} + db' ch-eid' nick)))] + (deliver-to-client! w + (str ":" +server-name+ " MARKREAD " + handle " " + (if stored + (str "timestamp=" stored) + "*"))))) (when (and w members) (deliver-to-client! w (str ":" +server-name+ " 353 " nick @@ -2788,34 +2809,48 @@ (let [handle (first params) timestamp (second params) db (when conn (d/db conn)) - chan-eid (when db (resolve-channel db handle)) - ts-rgx #"timestamp=(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)"] + chan? (channel-handle? handle) + chan-eid (when (and db chan?) (resolve-channel db handle)) + ts-rgx #"timestamp=(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)" + user-key (when-not chan? + [(string/lower-case nick) + (string/lower-case handle)]) + stored-fn + (fn [] + (cond + (and chan? db chan-eid) + (ffirst + (d/q '{:find [?ts] + :in [$ ?ch ?nick] + :where + [[?r :papod.read-marker/channel ?ch] + [?r :papod.read-marker/nick ?nick] + [?r :papod.read-marker/timestamp ?ts]]} + db chan-eid nick)) + user-key + (some-> components :user-markers + deref (get user-key))))] (cond ;; SET with valid timestamp=... (and timestamp (re-matches ts-rgx timestamp)) (let [ts-only (second (re-matches ts-rgx timestamp)) - stored (when (and db chan-eid) - (ffirst - (d/q '{:find [?ts] - :in [$ ?ch ?nick] - :where - [[?r :papod.read-marker/channel - ?ch] - [?r :papod.read-marker/nick - ?nick] - [?r :papod.read-marker/timestamp - ?ts]]} - db chan-eid nick))) + stored (stored-fn) advance? (or (nil? stored) (pos? (compare ts-only stored)))] - (when (and advance? conn chan-eid) - @(d/transact conn - [{:papod.read-marker/channel chan-eid - :papod.read-marker/nick nick - :papod.read-marker/timestamp - ts-only}])) + (when advance? + (cond + (and chan? conn chan-eid) + @(d/transact conn + [{:papod.read-marker/channel chan-eid + :papod.read-marker/nick nick + :papod.read-marker/timestamp + ts-only}]) + user-key + (when (:user-markers components) + (swap! (:user-markers components) + assoc user-key ts-only)))) [(str ":" +server-name+ " MARKREAD " handle " timestamp=" (if advance? ts-only stored))]) @@ -2827,16 +2862,9 @@ " " timestamp " :Invalid timestamp")] - ;; GET: MARKREAD #channel + ;; GET :else - (let [stored (when (and db chan-eid) - (ffirst - (d/q '{:find [?ts] - :in [$ ?ch ?nick] - :where [[?r :papod.read-marker/channel ?ch] - [?r :papod.read-marker/nick ?nick] - [?r :papod.read-marker/timestamp ?ts]]} - db chan-eid nick)))] + (let [stored (stored-fn)] [(str ":" +server-name+ " MARKREAD " handle " " (if stored (str "timestamp=" stored) @@ -4162,9 +4190,10 @@ :chan-keys (atom {}) :chan-limits (atom {}) :invites (atom {}) - :whowas (atom []) - :max-users (atom 0) - :n-unreg (atom 0)})) + :whowas (atom []) + :max-users (atom 0) + :n-unreg (atom 0) + :user-markers (atom {})})) (defconst- +idle-timeout-ms+ (if-let [t (System/getenv "PAPOD_IDLE_TIMEOUT")] |
