From 9d7946cbad4102dbd547a6e5e67ee870f6a2e42d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Madeleine=20Sydney=20=C5=9Alaga?= Date: Fri, 10 Apr 2026 16:51:12 -0600 Subject: [PATCH] hawkeye -> hawk --- deps-lock.json | 20 ++++++ deps.edn | 3 +- flake.lock | 23 ++++++- flake.nix | 6 ++ make-db/.gitignore | 1 + make-db/Makefile | 13 ++++ make-db/default.nix | 17 +++++ make-db/make-db.c | 45 +++++++++++++ make-db/progressbar.nix | 5 ++ src/wiktionary_tf2/main.clj | 124 ++++++++++++++++++++++++++---------- 10 files changed, 222 insertions(+), 35 deletions(-) create mode 100644 make-db/.gitignore create mode 100644 make-db/Makefile create mode 100644 make-db/default.nix create mode 100644 make-db/make-db.c create mode 100644 make-db/progressbar.nix diff --git a/deps-lock.json b/deps-lock.json index a014731..3356885 100644 --- a/deps-lock.json +++ b/deps-lock.json @@ -190,6 +190,16 @@ "mvn-repo": "https://repo.clojars.org/", "hash": "sha256-q4PzoWHUY53W2TZWihPpw+qXB4QWWVnS1iW3WlvIxFg=" }, + { + "mvn-path": "integrant/integrant/1.0.1/integrant-1.0.1.jar", + "mvn-repo": "https://repo.clojars.org/", + "hash": "sha256-dHxoCJNqPEcXakMdx6T89cQKH7ZQf9LmZtMO4fzr7f0=" + }, + { + "mvn-path": "integrant/integrant/1.0.1/integrant-1.0.1.pom", + "mvn-repo": "https://repo.clojars.org/", + "hash": "sha256-zaEWby3a9q8gwevhNdchEwERgzbUG9NgqSBQ83C3Wdo=" + }, { "mvn-path": "io/aleph/dirigiste/0.1.3/dirigiste-0.1.3.jar", "mvn-repo": "https://repo1.maven.org/maven2/", @@ -564,6 +574,16 @@ "mvn-path": "tigris/tigris/0.1.2/tigris-0.1.2.pom", "mvn-repo": "https://repo.clojars.org/", "hash": "sha256-H9VZA1l1INzUrnbmoz7/XjWmFUIrutKo7ZrDMqr75KA=" + }, + { + "mvn-path": "weavejester/dependency/1.0.0/dependency-1.0.0.jar", + "mvn-repo": "https://repo.clojars.org/", + "hash": "sha256-XxpuyFNiyj3VVUj25hocVNmbLc0vv9/EdIBK5m0TbpI=" + }, + { + "mvn-path": "weavejester/dependency/1.0.0/dependency-1.0.0.pom", + "mvn-repo": "https://repo.clojars.org/", + "hash": "sha256-5NIafyzna3LBsVI8OHFubwOWmDYklwz18sPRfLp9WzY=" } ] } diff --git a/deps.edn b/deps.edn index 1218c50..48da4c9 100644 --- a/deps.edn +++ b/deps.edn @@ -10,5 +10,6 @@ hawk/hawk {:mvn/version "0.2.11"} ch.qos.logback/logback-classic #:mvn{:version "1.1.3"} io.github.anteoas/hawkeye - {:git/sha "5b3f5a99e9edfe482174258a864b577f7a4eeb47"}} + {:git/sha "5b3f5a99e9edfe482174258a864b577f7a4eeb47"} + integrant/integrant {:mvn/version "1.0.1"}} :paths ["src" "resources"]} diff --git a/flake.lock b/flake.lock index 775c268..511b747 100644 --- a/flake.lock +++ b/flake.lock @@ -128,7 +128,28 @@ "root": { "inputs": { "clj-nix": "clj-nix", - "nixpkgs": "nixpkgs_2" + "nixpkgs": "nixpkgs_2", + "sydpkgs": "sydpkgs" + } + }, + "sydpkgs": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1775943619, + "narHash": "sha256-UwowTI+MSA4SD+Oebxnj02vAou8GNjvZYrCQBwKe5q0=", + "ref": "refs/heads/main", + "rev": "e44c957573baa6a196e8de107cfc5bba31caf29a", + "revCount": 39, + "type": "git", + "url": "https://git.deertopia.net/msyds/sydpkgs" + }, + "original": { + "type": "git", + "url": "https://git.deertopia.net/msyds/sydpkgs" } } }, diff --git a/flake.nix b/flake.nix index 0440e4d..9bdbf48 100644 --- a/flake.nix +++ b/flake.nix @@ -2,6 +2,10 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; clj-nix.url = "github:jlesquembre/clj-nix"; + sydpkgs = { + url = "git+https://git.deertopia.net/msyds/sydpkgs"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = { self, nixpkgs, clj-nix, ... }@inputs: @@ -29,10 +33,12 @@ packages = each-system ({ pkgs, ... }: { default = pkgs.callPackage ./default.nix {}; + make-db = pkgs.callPackage ./make-db {}; }); devShells = each-system ({ pkgs, system, ... }: { default = pkgs.mkShell { + inputsFrom = [ self.packages.${system}.make-db ]; packages = with pkgs; [ zprint clojure diff --git a/make-db/.gitignore b/make-db/.gitignore new file mode 100644 index 0000000..29bb07d --- /dev/null +++ b/make-db/.gitignore @@ -0,0 +1 @@ +make-db \ No newline at end of file diff --git a/make-db/Makefile b/make-db/Makefile new file mode 100644 index 0000000..08361f3 --- /dev/null +++ b/make-db/Makefile @@ -0,0 +1,13 @@ +CFLAGS= \ + -std=c99 \ + -Wall \ + -O3 \ + -Wextra +LIBS=ncurses sqlite3 +CFLAGS+=$(shell pkg-config --cflags $(LIBS)) +LDFLAGS+=$(shell pkg-config --libs $(LIBS)) + +SOURCES=$(wildcard *.c) +EXECUTABLES=$(patsubst %.c,%,$(SOURCES)) + +all: $(EXECUTABLES) diff --git a/make-db/default.nix b/make-db/default.nix new file mode 100644 index 0000000..cffb8a6 --- /dev/null +++ b/make-db/default.nix @@ -0,0 +1,17 @@ +{ stdenv +, sqlite +, ncurses +, pkg-config +, progressbar +}: + +stdenv.mkDerivation { + pname = "make-db"; + version = "0.0.0"; + nativeBuildInputs = [ + sqlite + ncurses + pkg-config + progressbar.dev + ]; +} diff --git a/make-db/make-db.c b/make-db/make-db.c new file mode 100644 index 0000000..e1a8f0c --- /dev/null +++ b/make-db/make-db.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include + +const char *word_db_path = "../words.db"; +const char *word_plaintext_path = "../words.gz"; + +char buf[2048] = ""; + +char *word = buf; + +char *read_entry () { + const char *s = fgets (buf, 2048, stdin); + if (s == NULL) { + return NULL; + } else { + char *r = strchr (buf, '\t'); + if (r != NULL) { + *r = '\0'; + return r + 1; + } else { + return NULL; + } + } +} + +int main () { + if (access (word_db_path, F_OK)) { + remove (word_db_path); + } + + sqlite3 *db = NULL; + if (! sqlite3_open (word_db_path, &db) == SQLITE_OK) { + fprintf (stderr, "couldn't open sqlite: %s\n", sqlite3_errmsg (db)); + } else { + fprintf (stderr, "sqlite open }:3\n"); + char *s = read_entry (); + if (s == NULL) { + printf ("%s: %s\n", word, s); + } + } + + return 0; +} diff --git a/make-db/progressbar.nix b/make-db/progressbar.nix new file mode 100644 index 0000000..bc512c0 --- /dev/null +++ b/make-db/progressbar.nix @@ -0,0 +1,5 @@ +{ stdenv +, ncurses +}: + +stdenv.mkDerivation {} diff --git a/src/wiktionary_tf2/main.clj b/src/wiktionary_tf2/main.clj index 431ba99..fbf902d 100644 --- a/src/wiktionary_tf2/main.clj +++ b/src/wiktionary_tf2/main.clj @@ -2,10 +2,14 @@ (:require [clojure.java.io :as io] [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] - [hawkeye.core :as hawk]) + [hawk.core :as hawk] + [next.jdbc :as sql] + [integrant.core :as ig]) + (:import (java.util.zip GZIPInputStream)) (:gen-class)) (def log-file @@ -15,29 +19,40 @@ (def words-file "words.gz") +(def words-db-file "words.db") + (def ^:dynamic *rcon*) +(defn parse-plaintext-entry [s] + (when-some [[_ word gloss] (re-matches #"([^\t]*)\t(.*)\n?" s)] + [word gloss])) + +(defn lookup-word-plaintext [word] + (let [r (p/shell {:out :string :continue true} + "zgrep" "-m1" + (format "^%s\t[^[:space:]]" word) + words-file)] + (when (zero? (:exit r)) + (->> r + :out + str/split-lines + (map #(-> % parse-plaintext-entry second)) + (filter #(not (empty? %))) ; remove nil and "" + first)))) + +(defn lookup-word-sql [word]) + (defn lookup-word [word] - (->> (p/shell {:out :string} - "zgrep" - (format "^%s\t" word) - words-file) - :out - str/split-lines - (map #(nth (re-matches #"([^\t]*)\t(.*)\n?" %) - 2 nil)) - (filter #(not (empty? %))) ; remove nil and "" - first)) + (lookup-word-plaintext word)) (defn parse-chat-message [x] (when-let [[_ _dead? author body] (re-matches #"(\*사망\* )?(.*?) : (.*)" x)] {:author author :body body})) -(defn say-word [word] - (->> (format "%s: %s" word (or (lookup-word word) - "no entry found }:(")) - (take 128) +(defn say [s] + (->> s + (take 128) ; truncate to 128 chars (apply str) (format "say \"%s\"") (rcon/exec *rcon*))) @@ -50,7 +65,13 @@ (defn do-definition [s] (when-some [w (find-word s)] (l/infof "looking up word: %s" w) - (say-word w))) + (let [r (lookup-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...") @@ -87,23 +108,60 @@ (finally (reset! prev-size size))))) (defn start-watcher! [] - (hawk/watch (str (fs/parent log-file)) - (bound-fn* (fn [ev] - (when (= (str (fs/file-name log-file)) - (:file ev)) - (handler)))) - (fn [e ctx] - (l/error e "error in watcher")))) + (l/infof "watching file %s" log-file) + (hawk/watch! [{:paths [(str log-file)] + :handler + (bound-fn* + (fn [_ctx ev] + (try (handler) + (catch Exception e + (l/errorf e "exception in handler") + (throw e)))))}])) -(defn start-logger! [] - @(rcon/exec *rcon* (format "con_logfile %s" - (fs/file-name log-file))) - @(rcon/exec *rcon* "echo \"wiktionary logging now\"") - (Thread/sleep 400) - (l/info "logfile has been set up!")) + + +(def config + {:rcon/connection {:ip "127.0.0.1" + :port 27015 + :password "monitor"} + :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) + :dictionary-file "words.gz"}}) + + +(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 :console/watcher [_ {:keys [log-file handler]}] + (hawk/watch! [{:paths [(str log-file)] + :handler + (fn [_ctx _ev] + (try (handler) + (catch Exception e + (l/errorf e "exception in handler") + (throw e))))}])) + +(defmethod ig/halt-key! :console/watcher [_ watcher] + (hawk/stop! watcher)) + +(defmethod ig/init-key :wikilinker/handler [_ {:keys [rcon watcher]}] + (binding [*rcon* rcon] + (bound-fn [] (handler)))) + + (defn -main [] - (binding [*rcon* (rcon-connect "127.0.0.1" 27015 "monitor")] - (start-logger!) - (start-watcher!) - (read-line))) + (let [system (ig/init config)] + (.addShutdownHook (Runtime/getRuntime) + (Thread. #(do (ig/halt! system) + (binding [*out* *err*] + (println "shutting down")))))))