From 9af66920a9b8e82c34a8301e4d134a3bbeb0eb41 Mon Sep 17 00:00:00 2001 From: aleteoryx Date: Thu, 7 Nov 2024 18:31:12 -0500 Subject: [PATCH] core database initialization --- cap.tcl | 6 ++--- db/main.tcl | 24 ++++++++++++++++++++ irc/main.tcl | 5 +++++ main.tcl | 58 +++++++++++++++++++++++++++--------------------- migrate_core.tcl | 48 +++++++++++++++++++++++++++++++++++++++ plugins.tcl | 16 +++++++++++++ threads.tcl | 31 +++++++++++++++++++++----- 7 files changed, 155 insertions(+), 33 deletions(-) create mode 100644 irc/main.tcl create mode 100644 migrate_core.tcl create mode 100644 plugins.tcl diff --git a/cap.tcl b/cap.tcl index c7212db..fb03c8a 100644 --- a/cap.tcl +++ b/cap.tcl @@ -9,9 +9,9 @@ # handling for CAP-related things namespace eval ::cap { - variable log [logger::init tclircc::cap] - variable logp [logger::init tclircc::cap::parser] - variable logh [logger::init tclircc::cap::dispatch] + variable log [logger::init irc::cap] + variable logp [logger::init irc::cap::parser] + variable logh [logger::init irc::cap::dispatch] proc value_dict str { set ret {} foreach pair [split $str ","] { diff --git a/db/main.tcl b/db/main.tcl index ddd1a0d..a137a48 100644 --- a/db/main.tcl +++ b/db/main.tcl @@ -3,3 +3,27 @@ package require logger set log [logger::init tclircc::db] +switch -- [set tcl_platform(platform)] { + "windows" { + set data_dir "[set env(APPDATA)][file separator]tclircc" + } + "unix" { + if [info exists env(XDG_CONFIG_HOME)] { + set data_dir "[set env(XDG_CONFIG_HOME)][file separator]tclircc" + } elseif [info exists env(HOME)] { + set data_dir "[set env(HOME)][file separator].config[file separator]tclircc" + } else { + return -code error {Missing $HOME or $XDG_CONFIG_HOME, can't store config!} + } + } + default { + return -code error {Unknown platform, can't store config.} + } +} + +file mkdir $data_dir + +proc path_to_core {} { + global data_dir + return "$data_dir[file separator]core.db" +} diff --git a/irc/main.tcl b/irc/main.tcl new file mode 100644 index 0000000..05e554a --- /dev/null +++ b/irc/main.tcl @@ -0,0 +1,5 @@ +package require logger + +source "$path[file separator]irc.tcl" +source "$path[file separator]cap.tcl" + diff --git a/main.tcl b/main.tcl index aba2ee5..12f8749 100755 --- a/main.tcl +++ b/main.tcl @@ -6,40 +6,48 @@ set version v0.0.1 package require Thread package require logger set log [logger::init tclircc::main] +package require sqlite3 ${log}::info "tclircc $version " ${log}::info "running from $path" source threads.tcl -${log}::debug "starting db thread..." -set db_thread [thread::create -preserved] -threads::manage $db_thread tclircc::db -thread::send $db_thread [list variable path $path version $version] -if {[thread::send $db_thread [list source "$path[file separator]db[file separator]main.tcl"] result] == 1} { - ${log}::critical "couldn't start db thread: $result" - exit -1 -} -${log}::debug "started db thread." - -${log}::debug "starting ui thread..." -set ui_thread [thread::create -preserved] -threads::manage $ui_thread tclircc::ui -thread::send $ui_thread [list variable path $path version $version] -if {[thread::send $ui_thread [list source "$path[file separator]ui[file separator]main.tcl"] result] == 1} { - ${log}::critical "couldn't start ui thread: $result" - exit -1 -} -${log}::debug "started ui thread." +proc start_thread {name} { + global path + global version + global log + + ${log}::debug "starting $name thread..." + + set thread [thread::create -preserved] + threads::manage $thread tclircc::$name + thread::send $thread [list variable path $path version $version] + + if {[thread::send $thread [list source "$path[file separator]$name[file separator]main.tcl"] result] == 1} { + ${log}::critical "couldn't start $name thread: $result" + exit -1 + } -update -foreach key [array names threads::ns] { - ${log}::debug "thread \"$key\" has id [set threads::ns($key)]" + ${log}::debug "started $name thread." } -${log}::debug "opening main window..." -thread::send $ui_thread {mk_toplevel name; return $name} mainwin -${log}::debug "main window opened: $mainwin" +start_thread db + +thread::send [t::ns tclircc::db] {path_to_core} core_db_path +sqlite3 core_db $core_db_path -create true -fullmutex true +source migrate_core.tcl + +source plugins.tcl + +start_thread irc +start_thread ui + +${log}::debug "opening initial window..." +thread::send [t::ns tclircc::ui] {mk_toplevel name; return $name} initial +${log}::debug "initial window opened: $initial" + +threads::debug ${log}::info "entering event loop" vwait nil diff --git a/migrate_core.tcl b/migrate_core.tcl new file mode 100644 index 0000000..fe0663c --- /dev/null +++ b/migrate_core.tcl @@ -0,0 +1,48 @@ +# TODO: make this more robust maybe + +interp create migrator + +migrator eval { + lappend migrations 0 {init plugins} { +-- init plugins +CREATE TABLE plugins (slug TEXT PRIMARY KEY, + version INTEGER, + hashes TEXT, + trusted BOOL, + priority INTEGER); + } +} + +migrator alias db core_db +migrator eval { + package require logger + package require Tk + wm withdraw . + + set log [logger::init tclircc::db::migrate] + + ${log}::debug "starting migrations" + if ![db eval { + SELECT count(*) FROM sqlite_master WHERE name="_migrations"}] { + ${log}::info "initializing core db!" + db eval {CREATE TABLE _migrations (id INTEGER PRIMARY KEY, date TEXT)} + } + + foreach {id name contents} $migrations { + # TODO: debug interpolation? + if ![db eval "SELECT count(*) FROM _migrations WHERE id=$id"] { + ${log}::info "performing migration $id: $name" + db eval BEGIN + set migrationdate [clock seconds] + db eval $contents + db eval "INSERT INTO _migrations (id, date) VALUES ($id, $migrationdate)" + set last $id + db eval COMMIT + } elseif [info exists last] { + ${log}::warn "completed migrations exist after incomplete migration $last, core database may be corrupted!" + } + } + + ${log}::info "core db migrated!" +} +interp delete migrator diff --git a/plugins.tcl b/plugins.tcl new file mode 100644 index 0000000..d9cdae8 --- /dev/null +++ b/plugins.tcl @@ -0,0 +1,16 @@ +package require sha256 + +# plugin manifest format: +# tcl script that must return the following + +namespace eval plugins { + variable plugins + + proc load {dir} { + set mf_fd [open "$dir[file separator]manifest.tcl"] + set manifest [read $mf_fd] + close $mf_fd + + + } +} diff --git a/threads.tcl b/threads.tcl index 057b060..89e6646 100644 --- a/threads.tcl +++ b/threads.tcl @@ -2,8 +2,6 @@ namespace eval threads { variable threads [list main [thread::id]] variable log [logger::init tclircc::threads] - variable ns - proc manage {tid name} { variable threads variable log @@ -11,12 +9,16 @@ namespace eval threads { ${log}::debug "managing thread $tid as \"$name\"" thread::send -head $tid { - namespace eval threads { + namespace eval t { variable ns proc update {} { variable ns thread::send -head [set ns(main)] threads::update } + proc ns {name} { + variable ns + set ns($name) + } } } @@ -35,11 +37,30 @@ namespace eval threads { if ![thread::exists $tid] {dict unset $threads $name} } dict for {name tid} $threads { - set payload {array unset threads::ns; } + set payload {array unset t::ns; } dict for {n t} $threads { - append payload {set threads::ns(} $n {) } $t {; } + append payload {set t::ns(} $n {) } $t {; } } thread::send -head $tid $payload } + ::update + } + proc debug {} { + variable log + update + foreach key [array names threads::ns] { + ${log}::debug "thread \"$key\" has id [set threads::ns($key)]" + } + } +} +namespace eval t { + variable ns + proc update {} { + variable ns + thread::send -head [set ns(main)] threads::update + } + proc ns {name} { + variable ns + set ns($name) } } -- 2.45.2