mirror of
https://github.com/unclebob/more-speech.git
synced 2024-09-30 10:30:56 +00:00
Swing begins.
This commit is contained in:
parent
6760ba48a8
commit
df415f8181
@ -14,15 +14,15 @@
|
||||
["e" "0002" "anotherurl"]]
|
||||
"content" "the content"
|
||||
"sig" "dddddd"})
|
||||
(with state {:application
|
||||
{:text-event-map {}
|
||||
:chronological-text-events (make-chronological-text-events)
|
||||
}
|
||||
})
|
||||
(with state
|
||||
{:text-event-map {}
|
||||
:chronological-text-events (make-chronological-text-events)
|
||||
}
|
||||
)
|
||||
(it "creates the map of text events by id"
|
||||
(let [state (process-text-event @state @event)
|
||||
event-map (get-in state [:application :text-event-map])
|
||||
text-events (get-in state [:application :chronological-text-events])
|
||||
event-map (get-in state [:text-event-map])
|
||||
text-events (get-in state [:chronological-text-events])
|
||||
event (get event-map 0xdeadbeef :not-in-map)]
|
||||
(should= 1 (count event-map))
|
||||
(should= 1 (count text-events))
|
||||
@ -38,10 +38,10 @@
|
||||
|
||||
(it "adds references to tagged articles."
|
||||
(let [state (assoc-in @state
|
||||
[:application :text-event-map 2]
|
||||
[:text-event-map 2]
|
||||
{:id 2})
|
||||
state (process-references state (translate-text-event @event))
|
||||
text-event-map (get-in state [:application :text-event-map])
|
||||
text-event-map (get-in state [:text-event-map])
|
||||
article (get text-event-map 2)]
|
||||
(should= [0xdeadbeef] (:references article)))
|
||||
)
|
||||
@ -49,31 +49,31 @@
|
||||
(context "sorted set for handling events"
|
||||
(it "adds one element"
|
||||
(let [state (add-event @state {:id 10 :created-at 0})]
|
||||
(should= #{[10 0]} (get-in state [:application :chronological-text-events]))
|
||||
(should= {10 {:id 10 :created-at 0}} (get-in state [:application :text-event-map]))))
|
||||
(should= #{[10 0]} (get-in state [:chronological-text-events]))
|
||||
(should= {10 {:id 10 :created-at 0}} (get-in state [:text-event-map]))))
|
||||
|
||||
(it "adds two elements in chronological order, should be reversed"
|
||||
(let [state (add-event @state {:id 10 :created-at 0})
|
||||
state (add-event state {:id 20 :created-at 1})
|
||||
]
|
||||
(should= [[20 1] [10 0]] (seq (get-in state [:application :chronological-text-events])))
|
||||
(should= [[20 1] [10 0]] (seq (get-in state [:chronological-text-events])))
|
||||
(should= {10 {:id 10 :created-at 0}
|
||||
20 {:id 20 :created-at 1}} (get-in state [:application :text-event-map])))
|
||||
20 {:id 20 :created-at 1}} (get-in state [:text-event-map])))
|
||||
)
|
||||
(it "adds two elements in reverse chronological order, should remain."
|
||||
(let [state (add-event @state {:id 10 :created-at 1})
|
||||
state (add-event state {:id 20 :created-at 0})
|
||||
]
|
||||
(should= [[10 1] [20 0]] (seq (get-in state [:application :chronological-text-events])))
|
||||
(should= [[10 1] [20 0]] (seq (get-in state [:chronological-text-events])))
|
||||
(should= {10 {:id 10 :created-at 1}
|
||||
20 {:id 20 :created-at 0}} (get-in state [:application :text-event-map])))
|
||||
20 {:id 20 :created-at 0}} (get-in state [:text-event-map])))
|
||||
)
|
||||
|
||||
(it "adds two elements with equal ids"
|
||||
(let [state (add-event @state {:id 10 :created-at 1})
|
||||
state (add-event state {:id 10 :created-at 0})
|
||||
event-map (get-in state [:application :text-event-map])]
|
||||
(should= [[10 1]] (seq (get-in state [:application :chronological-text-events])))
|
||||
event-map (get-in state [:text-event-map])]
|
||||
(should= [[10 1]] (seq (get-in state [:chronological-text-events])))
|
||||
(should= 1 (count event-map))
|
||||
)
|
||||
)
|
||||
@ -90,13 +90,13 @@
|
||||
now (quot (System/currentTimeMillis) 1000)]
|
||||
(should= "EVENT" (first event))
|
||||
(should= (ecc/bytes->hex-string public-key) pubkey)
|
||||
(should (<= 0 (- now created_at) 1 )) ;within one second.
|
||||
(should (<= 0 (- now created_at) 1)) ;within one second.
|
||||
(should= 1 kind)
|
||||
(should= [] tags)
|
||||
(should= text content)
|
||||
(should (ecc/do-verify (ecc/hex-string->bytes id)
|
||||
public-key
|
||||
(ecc/hex-string->bytes sig)))))
|
||||
public-key
|
||||
(ecc/hex-string->bytes sig)))))
|
||||
|
||||
(it "composes a reply."
|
||||
(let [private-key (ecc/num->bytes 64 42)
|
||||
@ -108,31 +108,31 @@
|
||||
now (quot (System/currentTimeMillis) 1000)]
|
||||
(should= "EVENT" (first event))
|
||||
(should= (ecc/bytes->hex-string public-key) pubkey)
|
||||
(should (<= 0 (- now created_at) 1)) ;within one second.
|
||||
(should (<= 0 (- now created_at) 1)) ;within one second.
|
||||
(should= 1 kind)
|
||||
(should= [[:e (ecc/bytes->hex-string reply-to)]] tags)
|
||||
(should= text content)
|
||||
(should (ecc/do-verify (ecc/hex-string->bytes id)
|
||||
public-key
|
||||
(ecc/hex-string->bytes sig)))))
|
||||
(should= text content)
|
||||
(should (ecc/do-verify (ecc/hex-string->bytes id)
|
||||
public-key
|
||||
(ecc/hex-string->bytes sig)))))
|
||||
|
||||
(it "composes a message with a slash."
|
||||
(let [private-key (ecc/num->bytes 64 42)
|
||||
public-key (ecc/get-pub-key private-key)
|
||||
reply-to nil
|
||||
text "message/text"
|
||||
event (compose-text-event private-key text reply-to)
|
||||
{:keys [pubkey created_at kind tags content id sig]} (second event)
|
||||
now (quot (System/currentTimeMillis) 1000)]
|
||||
(should= "EVENT" (first event))
|
||||
(should= (ecc/bytes->hex-string public-key) pubkey)
|
||||
(should (<= 0 (- now created_at) 1)) ;within one second.
|
||||
(should= 1 kind)
|
||||
(should= [] tags)
|
||||
(should= text content)
|
||||
(should (ecc/do-verify (ecc/hex-string->bytes id)
|
||||
public-key
|
||||
(ecc/hex-string->bytes sig)))))
|
||||
(let [private-key (ecc/num->bytes 64 42)
|
||||
public-key (ecc/get-pub-key private-key)
|
||||
reply-to nil
|
||||
text "message/text"
|
||||
event (compose-text-event private-key text reply-to)
|
||||
{:keys [pubkey created_at kind tags content id sig]} (second event)
|
||||
now (quot (System/currentTimeMillis) 1000)]
|
||||
(should= "EVENT" (first event))
|
||||
(should= (ecc/bytes->hex-string public-key) pubkey)
|
||||
(should (<= 0 (- now created_at) 1)) ;within one second.
|
||||
(should= 1 kind)
|
||||
(should= [] tags)
|
||||
(should= text content)
|
||||
(should (ecc/do-verify (ecc/hex-string->bytes id)
|
||||
public-key
|
||||
(ecc/hex-string->bytes sig)))))
|
||||
)
|
||||
|
||||
(describe "json"
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
(ns more-speech.core
|
||||
(:require [quil.core :as q]
|
||||
[quil.middleware :as m]
|
||||
[clojure.core.async :as async]
|
||||
[more-speech.nostr.events :as nostr]
|
||||
[more-speech.ui.widget :refer [draw-widget
|
||||
@ -26,8 +25,10 @@
|
||||
[more-speech.ui.application :refer [map->application]]
|
||||
[more-speech.ui.graphics :as g]
|
||||
[more-speech.ui.widget :as w]
|
||||
[more-speech.ui.config :as config]
|
||||
[more-speech.nostr.protocol :as protocol]))
|
||||
[more-speech.nostr.protocol :as protocol]
|
||||
[more-speech.ui.swing.main-window :as swing]
|
||||
[more-speech.nostr.events :as events])
|
||||
)
|
||||
|
||||
(def events (atom []))
|
||||
(def send-chan (async/chan))
|
||||
@ -80,25 +81,29 @@
|
||||
(draw-widget application state)
|
||||
)
|
||||
|
||||
(declare more-speech)
|
||||
(declare more-speech setup-jframe)
|
||||
(defn ^:export -main [& args]
|
||||
(q/defsketch more-speech
|
||||
:title "More Speech"
|
||||
:size [(q/screen-width) (- (q/screen-height) config/window-margin)]
|
||||
:setup setup
|
||||
:update update-state
|
||||
:draw draw-state
|
||||
:mouse-wheel w/mouse-wheel
|
||||
:mouse-pressed w/mouse-pressed
|
||||
:mouse-released w/mouse-released
|
||||
:mouse-moved w/mouse-moved
|
||||
:mouse-dragged w/mouse-dragged
|
||||
:key-pressed w/key-pressed
|
||||
:middleware [m/fun-mode]
|
||||
:on-close protocol/close-connection)
|
||||
;(q/defsketch more-speech
|
||||
; :title "More Speech"
|
||||
; :size [(q/screen-width) (- (q/screen-height) config/window-margin)]
|
||||
; :setup setup
|
||||
; :update update-state
|
||||
; :draw draw-state
|
||||
; :mouse-wheel w/mouse-wheel
|
||||
; :mouse-pressed w/mouse-pressed
|
||||
; :mouse-released w/mouse-released
|
||||
; :mouse-moved w/mouse-moved
|
||||
; :mouse-dragged w/mouse-dragged
|
||||
; :key-pressed w/key-pressed
|
||||
; :middleware [m/fun-mode]
|
||||
; :on-close protocol/close-connection)
|
||||
|
||||
;(reset! events (read-string (slurp "nostr-messages")))
|
||||
(protocol/get-events events send-chan)
|
||||
(let [event-agent (events/make-event-agent)]
|
||||
(swing/setup-jframe event-agent send-chan)
|
||||
(protocol/get-events event-agent send-chan))
|
||||
args
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
(:require [clojure.spec.alpha :as s]
|
||||
[clojure.data.json :as json]
|
||||
[more-speech.nostr.util :refer [hex-string->num]]
|
||||
[more-speech.ui.widget :as w]
|
||||
[more-speech.nostr.elliptic-signature :as ecc])
|
||||
(:import (java.nio.charset StandardCharsets)))
|
||||
(s/def ::id number?)
|
||||
@ -23,34 +22,42 @@
|
||||
(declare process-text-event
|
||||
process-name-event)
|
||||
|
||||
(defn make-event-agent []
|
||||
(agent {:chronological-text-events []
|
||||
:nicknames {}
|
||||
:text-event-map {}
|
||||
:update false}))
|
||||
|
||||
(defn updated [event-state]
|
||||
(assoc event-state :update false))
|
||||
|
||||
(defn to-json [o]
|
||||
(json/write-str o :escape-slash false :escape-unicode false))
|
||||
|
||||
(defn process-event [{:keys [application] :as state} event]
|
||||
(let [{:keys [_articles nicknames]} application
|
||||
_name-of (fn [pubkey] (get nicknames pubkey pubkey))
|
||||
(defn process-event [{:keys [nicknames] :as event-state} event]
|
||||
(let [_name-of (fn [pubkey] (get nicknames pubkey pubkey))
|
||||
[_name _subscription-id inner-event :as _decoded-msg] event
|
||||
{:strs [_id _pubkey _created_at kind _tags _content _sig]} inner-event]
|
||||
(condp = kind
|
||||
0 (process-name-event state inner-event)
|
||||
0 (process-name-event event-state inner-event)
|
||||
3 (do
|
||||
;(printf "%s: %s %s %s\n" kind (f/format-time created_at) (name-of pubkey) content)
|
||||
state)
|
||||
event-state)
|
||||
1 (do
|
||||
;(printf "%s: %s %s %s\n" kind (f/format-time created_at) (name-of pubkey) (subs content 0 (min 50 (count content))))
|
||||
(process-text-event state inner-event))
|
||||
(process-text-event event-state inner-event))
|
||||
4 (do
|
||||
;(printf "%s: %s %s %s\n" kind (f/format-time created_at) (name-of pubkey) content)
|
||||
state)
|
||||
event-state)
|
||||
(do (prn "unknown event: " event)
|
||||
state))))
|
||||
event-state))))
|
||||
|
||||
(defn process-name-event [state {:strs [_id pubkey _created_at _kind _tags content _sig]}]
|
||||
(defn process-name-event [event-state {:strs [_id pubkey _created_at _kind _tags content _sig]}]
|
||||
(let [pubkey (hex-string->num pubkey)
|
||||
name (get (json/read-str content) "name" "tilt")
|
||||
state (w/redraw-widget state [:application :author-window])]
|
||||
(update-in
|
||||
state [:application :nicknames] assoc pubkey name)))
|
||||
name (get (json/read-str content) "name" "tilt")]
|
||||
(-> event-state
|
||||
(update-in [:nicknames] assoc pubkey name)
|
||||
(assoc :update true))))
|
||||
|
||||
(defn process-tag [[type arg1 arg2]]
|
||||
[(keyword type) arg1 arg2])
|
||||
@ -67,7 +74,7 @@
|
||||
state state]
|
||||
(if (empty? refs)
|
||||
state
|
||||
(let [referent-path [:application :text-event-map (first refs)]]
|
||||
(let [referent-path [:text-event-map (first refs)]]
|
||||
(if (nil? (get-in state referent-path))
|
||||
(recur (rest refs) state)
|
||||
(recur (rest refs)
|
||||
@ -87,18 +94,20 @@
|
||||
:sig sig
|
||||
:tags (process-tags (get event "tags"))}))
|
||||
|
||||
(defn add-event [state event]
|
||||
(defn add-event [event-state event]
|
||||
(let [id (:id event)
|
||||
time (:created-at event)
|
||||
state (assoc-in state [:application :text-event-map id] event)
|
||||
state (update-in state [:application :chronological-text-events] conj [id time])]
|
||||
state))
|
||||
time (:created-at event)]
|
||||
(-> event-state
|
||||
(assoc-in [:text-event-map id] event)
|
||||
(update-in [:chronological-text-events] conj [id time]))))
|
||||
|
||||
(defn process-text-event [state event]
|
||||
(let [event (translate-text-event event)
|
||||
state (add-event state event)
|
||||
state (w/redraw-widget state [:application :header-window])]
|
||||
(process-references state event)))
|
||||
(defn process-text-event [event-state event]
|
||||
(let [event (translate-text-event event)]
|
||||
(-> event-state
|
||||
(add-event event)
|
||||
(process-references event)
|
||||
(assoc :update true)
|
||||
)))
|
||||
|
||||
(defn chronological-event-comparator [[i1 t1] [i2 t2]]
|
||||
(if (= i1 i2)
|
||||
|
@ -21,7 +21,6 @@
|
||||
"ws://nostr-pub.wellorder.net:7000"
|
||||
])
|
||||
|
||||
|
||||
(defn send-to [^WebSocket conn msg]
|
||||
(let [msg (events/to-json msg)]
|
||||
(println "sending:" msg)
|
||||
@ -57,14 +56,14 @@
|
||||
(defn unsubscribe [^WebSocket conn id]
|
||||
(send-to conn ["CLOSE" id]))
|
||||
|
||||
(defrecord listener [buffer events]
|
||||
(defrecord listener [buffer event-agent]
|
||||
WebSocket$Listener
|
||||
(onOpen [_this _webSocket]
|
||||
(prn 'open))
|
||||
(onText [_this webSocket data last]
|
||||
(.append buffer (.toString data))
|
||||
(when last
|
||||
(swap! events conj (json/read-str (.toString buffer)))
|
||||
(send event-agent events/process-event (json/read-str (.toString buffer)))
|
||||
(.delete buffer 0 (.length buffer)))
|
||||
(.request webSocket 1)
|
||||
)
|
||||
@ -85,10 +84,10 @@
|
||||
)
|
||||
)
|
||||
|
||||
(defn connect-to-relay ^WebSocket [url events]
|
||||
(defn connect-to-relay ^WebSocket [url event-agent]
|
||||
(let [client (HttpClient/newHttpClient)
|
||||
cl (.newWebSocketBuilder client)
|
||||
cws (.buildAsync cl (URI/create url) (->listener (StringBuffer.) events))
|
||||
cws (.buildAsync cl (URI/create url) (->listener (StringBuffer.) event-agent))
|
||||
ws (.get cws)
|
||||
]
|
||||
ws)
|
||||
@ -96,15 +95,14 @@
|
||||
|
||||
(def private-key (ecc/sha-256 (.getBytes "I am Bob.")))
|
||||
|
||||
(defn get-events [events send-chan]
|
||||
(let [conn (connect-to-relay (get relays 0) events)
|
||||
(defn get-events [event-agent send-chan]
|
||||
(let [conn (connect-to-relay (get relays 0) event-agent)
|
||||
id "more-speech"
|
||||
date (make-date "04/01/2022")
|
||||
date (make-date "04/25/2022")
|
||||
]
|
||||
(prn date (format-time date))
|
||||
(unsubscribe conn id)
|
||||
(subscribe conn id date)
|
||||
;(send-to conn ["EVENT" {:pubkey "2ef93f01cd2493e04235a6b87b10d3c4a74e2a7eb7c3caf168268f6af73314b5", :created_at 1649969311, :kind 1, :tags [], :content "Hello from more-speech.", :id "b05141aecb7d975ae7df861a13082d98ad76e9f46accc046ba221533877b69c6", :sig "e80411eee168aa620b035ce16622eda24d059859562276305a1c8900559b3bc5ae0505754e5d0f352891717eb34f4495771bcf11c80d01cdd19025a51e99979d"}])
|
||||
(loop [msg (async/<!! send-chan)]
|
||||
(condp = (first msg)
|
||||
:closed nil
|
||||
@ -114,7 +112,7 @@
|
||||
(recur (async/<!! send-chan)))))
|
||||
(unsubscribe conn id)
|
||||
(.get (.sendClose conn WebSocket/NORMAL_CLOSURE "done"))
|
||||
(Thread/sleep 1000))
|
||||
(Thread/sleep 100))
|
||||
(prn 'done)
|
||||
)
|
||||
|
||||
|
79
src/more_speech/ui/swing/main_window.clj
Normal file
79
src/more_speech/ui/swing/main_window.clj
Normal file
@ -0,0 +1,79 @@
|
||||
(ns more-speech.ui.swing.main-window
|
||||
(:require [clojure.core.async :as async]
|
||||
[more-speech.nostr.util :as util]
|
||||
[more-speech.ui.formatters :as formatters]
|
||||
[more-speech.nostr.events :as events])
|
||||
(:import (javax.swing JFrame SwingUtilities Timer JScrollPane JTextPane)
|
||||
(java.awt BorderLayout Toolkit Font)
|
||||
(java.awt.event ActionListener WindowListener)))
|
||||
|
||||
(declare display-jframe action-event draw-events)
|
||||
|
||||
(defn setup-jframe [event-agent output-channel]
|
||||
(SwingUtilities/invokeLater #(display-jframe event-agent output-channel)))
|
||||
|
||||
(defmacro with-action [component event & body]
|
||||
`(.addActionListener ~component
|
||||
(proxy [ActionListener] []
|
||||
(actionPerformed [~event] ~@body))))
|
||||
|
||||
(defn display-jframe [event-agent output-channel]
|
||||
(let [frame (JFrame. "More Speech")
|
||||
text-area (doto
|
||||
(JTextPane.)
|
||||
(.setContentType "text/html")
|
||||
(.setText "<br><br><br><br><br><br><br><br><br><br>"))
|
||||
scroll-pane (JScrollPane. text-area)
|
||||
content (.getContentPane frame)
|
||||
timer (Timer. 100 nil)
|
||||
screen-size (.getScreenSize (Toolkit/getDefaultToolkit))
|
||||
font (Font. "Courier New" Font/PLAIN, 14)]
|
||||
|
||||
(.addWindowListener frame (proxy [WindowListener] []
|
||||
(windowActivated [_e])
|
||||
(windowOpened [_e])
|
||||
(windowClosed [_e])
|
||||
(windowDeactivated [_e])
|
||||
(windowClosing [_e]
|
||||
(.stop timer)
|
||||
(async/>!! output-channel [:closed])
|
||||
(.dispose frame))))
|
||||
|
||||
(with-action timer action-event
|
||||
(draw-events text-area event-agent)
|
||||
)
|
||||
(.setSize frame (.getWidth screen-size) (.getHeight screen-size))
|
||||
(.setSize text-area (.getWidth screen-size) (.getHeight screen-size))
|
||||
(.setFont text-area font)
|
||||
(.add content scroll-pane BorderLayout/NORTH)
|
||||
(.setVisible frame true)
|
||||
(.start timer)))
|
||||
|
||||
(declare format-events append-event format-event)
|
||||
|
||||
(defn draw-events [text-area event-agent]
|
||||
(prn "tick")
|
||||
(when (:update @event-agent)
|
||||
(let [event-state @event-agent
|
||||
formatted-events (format-events event-state)]
|
||||
(.setText text-area formatted-events)
|
||||
(send event-agent events/updated))))
|
||||
|
||||
(defn format-events [{:keys [chronological-text-events nicknames text-event-map]}]
|
||||
(let [header-ids (map first chronological-text-events)
|
||||
headers (map #(get text-event-map %) header-ids)]
|
||||
(reduce #(append-event nicknames %1 %2) "" headers)))
|
||||
|
||||
(defn append-event [nicknames formatted-events event]
|
||||
(str formatted-events (format-event nicknames event)))
|
||||
|
||||
(defn format-event [nicknames {:keys [pubkey created-at content]}]
|
||||
(str "<p>"
|
||||
(formatters/abbreviate
|
||||
(get nicknames pubkey (util/num->hex-string pubkey))
|
||||
20)
|
||||
" "
|
||||
(formatters/format-time created-at)
|
||||
" "
|
||||
(formatters/abbreviate content 50)
|
||||
"</b><<hr>"))
|
Loading…
Reference in New Issue
Block a user