Skip to content

Commit d53a4d7

Browse files
authored
Refactor SSE data lines creation (#14)
* Refactor: centralizing the line splitting of SSE datalines * Chore: cleaned unused code * Refactor: faster SSE event data-lines creation * Chore: changelog
1 parent 38880a4 commit d53a4d7

File tree

6 files changed

+60
-35
lines changed

6 files changed

+60
-35
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,20 @@
33
## 2025-11-27 - RC5
44

55
### Fixed
6+
67
- Fixed `starfederation.datastar.clojure.adapter.http-kit2/wrap-start-responding`,
78
the async arity was improperly managed.
89

910
### Changes
11+
1012
- The internals of the Ring SSE generator have been reworked. The SSE gen won't error
1113
if a user reuses it for different requests anymore. Documentation is in place to warn
1214
against such reuse and this change makes for much simpler code.
15+
- When creating SSE events we need to split on end of lines the text that will
16+
constitute the data lines of the event. This can prevent SSE event injection
17+
problems. The SSE machinery has been refactored so that this splitting happens
18+
in a code path that all API functions go through instead of doing it in every
19+
d* patch function. This way we can't forget that splitting.
1320

1421
## 2025-10-30 - RC4
1522

libraries/sdk/src/main/starfederation/datastar/clojure/api/common.clj

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
(ns starfederation.datastar.clojure.api.common)
1+
(ns starfederation.datastar.clojure.api.common
2+
(:require
3+
[clojure.string :as string]))
24

35
;; -----------------------------------------------------------------------------
46
;; Option names
@@ -30,7 +32,7 @@
3032
"Add an option `v` line to the transient `data-lines!` vector.
3133
3234
Args:
33-
- `data-lines`: a transient vector of data-lines that will be written in a sse
35+
- `data-lines!`: a transient vector of data-lines that will be written in a sse
3436
event
3537
- `prefix`: The Datastar specific preffix for that line
3638
- `v`: the value for that line
@@ -41,13 +43,13 @@
4143

4244
(defn add-data-lines!
4345
"Add several data-lines to the `data-lines!` transient vector."
44-
[data-lines! prefix lines-seq]
45-
(reduce
46-
(fn [acc part]
47-
(conj! acc (str prefix part)))
48-
data-lines!
49-
lines-seq))
50-
46+
[data-lines! prefix ^String text]
47+
(let [stream (.lines text)
48+
i (.iterator stream)]
49+
(loop [acc data-lines!]
50+
(if (.hasNext i)
51+
(recur (conj! acc (str prefix (.next i))))
52+
acc))))
5153

5254
(defn add-boolean-option?
5355
"Utility used to test whether an boolean option should result in a sse event
@@ -56,6 +58,3 @@
5658
(and
5759
(boolean? val)
5860
(not= val default-val)))
59-
60-
61-

libraries/sdk/src/main/starfederation/datastar/clojure/api/elements.clj

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
(cond-> data-lines!
3131
(and sel (valid-selector? sel))
3232
(common/add-opt-line! consts/selector-dataline-literal sel)
33-
33+
3434
(and patch-mode (add-epm? patch-mode))
3535
(common/add-opt-line! consts/mode-dataline-literal patch-mode)
3636

@@ -47,8 +47,7 @@
4747
[data-lines! element]
4848
(cond-> data-lines!
4949
(u/not-empty-string? element)
50-
(common/add-data-lines! consts/elements-dataline-literal
51-
(string/split-lines element))))
50+
(common/add-data-lines! consts/elements-dataline-literal element)))
5251

5352

5453
(defn ->patch-elements
@@ -91,13 +90,15 @@
9190
(defn conj-patch-elements-seq
9291
"Adds a the data-lines when patching a seq of strings elements."
9392
[data-lines! elements-seq]
94-
(cond-> data-lines!
95-
(seq elements-seq)
96-
(common/add-data-lines! consts/elements-dataline-literal
97-
(eduction
98-
(comp (mapcat string/split-lines)
99-
(remove string/blank?))
100-
elements-seq))))
93+
(if (seq elements-seq)
94+
(reduce
95+
(fn [data-lines! elements]
96+
(if (string/blank? elements)
97+
data-lines!
98+
(common/add-data-lines! data-lines! consts/elements-dataline-literal elements)))
99+
data-lines!
100+
elements-seq)
101+
data-lines!))
101102

102103

103104
(defn ->patch-elements-seq
@@ -146,5 +147,3 @@
146147
(patch-elements! sse-gen "" (assoc opts
147148
common/selector selector
148149
common/patch-mode consts/element-patch-mode-remove)))
149-
150-

libraries/sdk/src/main/starfederation/datastar/clojure/api/signals.clj

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,15 @@
2121
(common/add-opt-line! consts/only-if-missing-dataline-literal oim)
2222

2323
(u/not-empty-string? signals)
24-
(common/add-data-lines! consts/signals-dataline-literal
25-
(string/split-lines signals))))))
24+
(common/add-data-lines! consts/signals-dataline-literal signals)))))
2625

2726

2827

2928
(comment
3029
(= (->patch-signals "{'some': \n 'json'}" {})
3130
["signals {'some': "
3231
"signals 'json'}"]))
33-
32+
3433
(defn patch-signals! [sse-gen signals-content opts]
3534
(try
3635
(sse/send-event! sse-gen
@@ -56,5 +55,3 @@
5655
(if (= :get (:request-method request))
5756
(get-in request [:query-params consts/datastar-key])
5857
(:body request)))
59-
60-

libraries/sdk/src/main/starfederation/datastar/clojure/consts.clj

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
(ns starfederation.datastar.clojure.consts)
33

44

5-
(def datastar-key "datastar")
6-
(def version "1.0.0-RC.1")
5+
(def datastar-key "datastar")
76

87

98
;; -----------------------------------------------------------------------------
@@ -14,10 +13,6 @@
1413
1000)
1514

1615

17-
;; -----------------------------------------------------------------------------
18-
;; Default values
19-
;; -----------------------------------------------------------------------------
20-
2116
;; -----------------------------------------------------------------------------
2217
;; Dataline literals
2318
;; -----------------------------------------------------------------------------

src/dev/bench/split.clj

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
(ns bench.split
2+
(:require
3+
[clojure.string :as string]
4+
[starfederation.datastar.clojure.api.common :as c]))
5+
6+
7+
(defn old-datalines [data-lines! prefix text]
8+
(reduce
9+
(fn [acc part]
10+
(conj! acc (str prefix part)))
11+
data-lines!
12+
(string/split-lines text)))
13+
14+
15+
(def input "hello there\n wold !\r\n How are \ryou \ntoday")
16+
(def input-big (apply str (repeat 100 input)))
17+
18+
(defn bench [f input]
19+
(println "---------------------------------------")
20+
(dotimes [_ 20]
21+
(time
22+
(dotimes [_ 10000]
23+
(f (transient []) "elements " input)))))
24+
25+
26+
(comment
27+
(bench old-datalines input-big)
28+
(bench c/add-data-lines! input-big))

0 commit comments

Comments
 (0)