rust
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
(ns wiktlarp.main
|
||||
(:require [clojure.java.io :as io]
|
||||
[clojure.core.match :refer [match]]
|
||||
[cheshire.core :as json]
|
||||
[babashka.fs :as fs]
|
||||
[babashka.process :as p]
|
||||
[progrock.core :as prog]
|
||||
[clj-rcon.core :as rcon]
|
||||
[clojure.tools.logging :as l]
|
||||
[clojure.string :as str]
|
||||
[hawk.core :as hawk]
|
||||
[next.jdbc :as sql]
|
||||
[integrant.core :as ig])
|
||||
(:import (java.time Instant Duration)
|
||||
(java.time.temporal ChronoUnit))
|
||||
(:gen-class))
|
||||
|
||||
(def chat-message-regexp #"(\*사망\* )?(.*?) : (.*)")
|
||||
|
||||
(def ^:dynamic *rcon*)
|
||||
|
||||
(def ^:dynamic *db*)
|
||||
|
||||
(def cooldown 3)
|
||||
|
||||
(def last-sent (atom (.minusSeconds (Instant/now) 3)))
|
||||
|
||||
(defmacro with-conn [[conn] & body]
|
||||
`(let [ds# (sql/get-datasource
|
||||
{:dbtype "sqlite"
|
||||
:dbname "db/words.db"})]
|
||||
(with-open [~conn (sql/get-connection ds#)]
|
||||
~@body)))
|
||||
|
||||
(defn query-word [word]
|
||||
(->> (sql/execute! *db* ["select info from words where word = ?"
|
||||
word])
|
||||
(map #(json/parse-string (:words/info %) keyword))))
|
||||
|
||||
(defn parse-fuckyou [x]
|
||||
(cond (= x "peggle")
|
||||
"(slang, Tiny Kitty Girl Pound) a video game, i think. idfk."
|
||||
(and (re-find #"chimpanzee" x)
|
||||
(re-find #"segway" x))
|
||||
"(slang, Tiny Kitty Girl Pound) chimpanzeee sirdnway"
|
||||
:else nil))
|
||||
|
||||
(defn gloss-word [word]
|
||||
(if-some [fuckyou (parse-fuckyou word)]
|
||||
fuckyou
|
||||
(->> word
|
||||
query-word
|
||||
(mapcat :senses)
|
||||
(mapcat (some-fn :raw_glosses :glosses))
|
||||
first)))
|
||||
|
||||
(defn etymology-word [word]
|
||||
(->> word
|
||||
query-word
|
||||
(map :etymology_text)
|
||||
first))
|
||||
|
||||
(defn parse-chat-message [x]
|
||||
(when-let [[_ _dead? author body]
|
||||
(re-matches chat-message-regexp x)]
|
||||
{:author author :body body}))
|
||||
|
||||
(defn say [s]
|
||||
(let [now (Instant/now)]
|
||||
(when (< (compare (Duration/ofSeconds 3)
|
||||
(Duration/between @last-sent now))
|
||||
0)
|
||||
(reset! last-sent now)
|
||||
(->> s
|
||||
(take 128) ; truncate to 128 chars
|
||||
(apply str)
|
||||
(format "say \"%s\"")
|
||||
(rcon/exec *rcon*)))))
|
||||
|
||||
(defn find-word [s]
|
||||
(some-> (or (re-find #"\[\[([^]]+)]]" s)
|
||||
(re-find #"define\s+(\w+)" s))
|
||||
second))
|
||||
|
||||
(defn find-etymology [s]
|
||||
(some-> (or (and (re-find #"ety(?:m(?:ology)?)?" s)
|
||||
(re-find #"\[\[([^]]+)]]" s))
|
||||
(re-find #"etymology of \s+(\w+)" s))
|
||||
second))
|
||||
|
||||
(defn parse-command [s]
|
||||
(if-let [x (find-etymology s)]
|
||||
[:etymology x]
|
||||
(if-let [x (find-word s)]
|
||||
[:define x]
|
||||
nil)))
|
||||
|
||||
(defn do-definition [w]
|
||||
(l/infof "looking up word: %s" w)
|
||||
(let [r (gloss-word w)]
|
||||
(if r
|
||||
(l/infof "found word! %s" r)
|
||||
(l/infof "no entry... %s" w))
|
||||
(Thread/sleep 750) ; avoid ratelimit lol
|
||||
(say (format "%s: %s"
|
||||
w (or r "no entry found (u_u)")))))
|
||||
|
||||
(defn do-etymology [w]
|
||||
(l/infof "looking up word: %s" w)
|
||||
(let [r (etymology-word w)]
|
||||
(if r
|
||||
(l/infof "found word! %s" r)
|
||||
(l/infof "no entry... %s" w))
|
||||
(Thread/sleep 750) ; avoid ratelimit lol
|
||||
(say (format "%s: %s"
|
||||
w (or r "no entry found (u_u)")))))
|
||||
|
||||
(defn rcon-connect [host port password]
|
||||
(l/info "attempting rcon connection...")
|
||||
(or (try (let [c @(rcon/connect host port password)]
|
||||
@(rcon/exec c "echo \"wikilarper connected!\"")
|
||||
(l/info "connected to rcon!")
|
||||
c)
|
||||
(catch java.net.ConnectException e
|
||||
(l/info (ex-message e))
|
||||
nil))
|
||||
(do (Thread/sleep 5000)
|
||||
(recur host port password))))
|
||||
|
||||
(defn handle-console-event [s]
|
||||
(l/infof "! %s" s)
|
||||
(when-let [{:keys [author body]} (parse-chat-message s)]
|
||||
(match (parse-command s)
|
||||
[:define x] (do-definition x)
|
||||
[:etymology x] (do-etymology x)
|
||||
:else nil)))
|
||||
|
||||
(def ^:dynamic *prev-size*)
|
||||
|
||||
(defn console-handler [log-file]
|
||||
(let [prev @*prev-size*
|
||||
content (slurp log-file)
|
||||
size (count content)]
|
||||
(try (cond (< prev size) (-> content
|
||||
(subs prev)
|
||||
str/trim-newline
|
||||
handle-console-event)
|
||||
(< size prev) (l/warn "log file shrunk?")
|
||||
:else nil)
|
||||
(finally (reset! *prev-size* size)))))
|
||||
|
||||
|
||||
|
||||
(def config
|
||||
{:rcon/connection {:ip "127.0.0.1"
|
||||
:port 27015
|
||||
:password "monitor"}
|
||||
:database/connection {:dbtype "sqlite"
|
||||
:dbname "db/words.db"}
|
||||
:console/watcher
|
||||
{:log-file
|
||||
(-> (str "~/.local/share/Steam/steamapps/common/Team Fortress 2/"
|
||||
"tf/console.log")
|
||||
fs/expand-home
|
||||
fs/file)
|
||||
:handler (ig/ref :wikilinker/handler)}
|
||||
:wikilinker/handler {:rcon (ig/ref :rcon/connection)
|
||||
:db (ig/ref :database/connection)}})
|
||||
|
||||
(defmethod ig/init-key :rcon/connection [_ {:keys [ip port password]}]
|
||||
(rcon-connect ip port password))
|
||||
|
||||
(defmethod ig/halt-key! :rcon/connection [_ conn]
|
||||
(.close conn))
|
||||
|
||||
(defmethod ig/init-key :database/connection [_ dsinfo]
|
||||
(sql/get-datasource dsinfo))
|
||||
|
||||
(defmethod ig/halt-key! :database/connection [_ conn]
|
||||
(.close conn))
|
||||
|
||||
(defmethod ig/init-key :console/watcher [_ {:keys [log-file handler]}]
|
||||
(l/infof "watching file %s" log-file)
|
||||
(hawk/watch!
|
||||
[{:paths [(str log-file)]
|
||||
:handler
|
||||
(binding [*prev-size* (atom (if (fs/exists? log-file)
|
||||
(-> log-file slurp count)
|
||||
0))]
|
||||
(bound-fn [_ctx ev]
|
||||
(try (handler log-file)
|
||||
(catch Exception e
|
||||
(l/errorf e "exception in console handler")
|
||||
(throw e)))))}]))
|
||||
|
||||
(defmethod ig/halt-key! :console/watcher [_ watcher]
|
||||
(hawk/stop! watcher))
|
||||
|
||||
(defmethod ig/init-key :wikilinker/handler
|
||||
[_ {:keys [rcon db]}]
|
||||
(binding [*rcon* rcon
|
||||
*db* db]
|
||||
(bound-fn [log-file] (console-handler log-file))))
|
||||
|
||||
|
||||
|
||||
(defn -main []
|
||||
(let [system (ig/init config)]
|
||||
(.addShutdownHook (Runtime/getRuntime)
|
||||
(Thread. #(do (ig/halt! system)
|
||||
(binding [*out* *err*]
|
||||
(println "shutting down")))))))
|
||||
Reference in New Issue
Block a user