M cap.tcl => cap.tcl +3 -3
@@ 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 ","] {
M db/main.tcl => db/main.tcl +24 -0
@@ 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"
+}
A irc/main.tcl => irc/main.tcl +5 -0
@@ 0,0 1,5 @@
+package require logger
+
+source "$path[file separator]irc.tcl"
+source "$path[file separator]cap.tcl"
+
M main.tcl => main.tcl +33 -25
@@ 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 <https://amehut.dev/~aleteoryx/tclircc>"
${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
A migrate_core.tcl => migrate_core.tcl +48 -0
@@ 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
A plugins.tcl => plugins.tcl +16 -0
@@ 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
+
+
+ }
+}
M threads.tcl => threads.tcl +26 -5
@@ 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)
}
}