no-DB mode implementation #94

Manually merged
jabber.developer merged 34 commits from feat/no-db-mode into master 2026-05-05 19:32:42 +00:00
20 changed files with 4083 additions and 647 deletions
Showing only changes of commit b5fe714a89 - Show all commits

View File

@@ -276,6 +276,7 @@ static Autocomplete logging_group_ac;
static Autocomplete privacy_ac;
static Autocomplete privacy_log_ac;
static Autocomplete history_ac;
static Autocomplete history_switch_ac;
static Autocomplete color_ac;
static Autocomplete correction_ac;
static Autocomplete avatar_ac;
@@ -431,6 +432,7 @@ static Autocomplete* all_acs[] = {
&privacy_ac,
&privacy_log_ac,
&history_ac,
&history_switch_ac,
&color_ac,
&correction_ac,
&avatar_ac,
@@ -1144,10 +1146,14 @@ cmd_ac_init(void)
autocomplete_add(history_ac, "on");
autocomplete_add(history_ac, "off");
autocomplete_add(history_ac, "switch");
autocomplete_add(history_ac, "verify");
autocomplete_add(history_ac, "export");
autocomplete_add(history_ac, "import");
autocomplete_add(history_switch_ac, "sqlite");
autocomplete_add(history_switch_ac, "flatfile");
autocomplete_add(logging_group_ac, "on");
autocomplete_add(logging_group_ac, "off");
autocomplete_add(logging_group_ac, "color");
@@ -1795,6 +1801,11 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ
}
}
result = autocomplete_param_with_ac(input, "/history switch", history_switch_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/history", history_ac, TRUE, previous);
if (result) {
return result;

View File

@@ -1882,17 +1882,20 @@ static const struct cmd_t command_defs[] = {
CMD_TAG_CHAT)
CMD_SYN(
"/history on|off",
"/history switch sqlite|flatfile",
"/history verify [<jid>]",
"/history export [<jid>]",
"/history import [<jid>]")
CMD_DESC(
"Switch chat history on or off, /logging chat will automatically be enabled when this setting is on. "
"When history is enabled, previous messages are shown in chat windows. "
"Use 'switch' to change the active database backend at runtime without reconnecting. "
"Use 'verify' to check integrity of stored message history. "
"Use 'export' to copy messages from SQLite to flat-file format, or 'import' to copy from flat-file to SQLite. "
"Both export and import merge with existing data (duplicates are skipped).")
CMD_ARGS(
{ "on|off", "Enable or disable showing chat history." },
{ "switch sqlite|flatfile", "Switch the active database backend at runtime." },
jabber.developer marked this conversation as resolved Outdated

Does the switch automatically export/import? It is unclear from documentation.

Does the switch automatically export/import? It is unclear from documentation.

documentation-only clarification, queued. /history switch only swaps the active backend; data is not migrated unless the user runs /history export and /history import explicitly.

documentation-only clarification, queued. /history switch only swaps the active backend; data is not migrated unless the user runs /history export and /history import explicitly.
{ "verify [<jid>]", "Verify integrity of message history. Optionally specify a JID to check only one contact." },
jabber.developer marked this conversation as resolved Outdated

How does it align with flatfile manual editability?

How does it align with flatfile manual editability?

needs a doc paragraph explaining that ff_verify_integrity flags timestamp drift, dup IDs, broken LMC refs etc. so manual edits remain auditable. Doc-only follow-up

needs a doc paragraph explaining that ff_verify_integrity flags timestamp drift, dup IDs, broken LMC refs etc. so manual edits remain auditable. Doc-only follow-up
{ "export [<jid>]", "Export SQLite history to flat-file format. Optionally specify a JID to export only one contact." },
{ "import [<jid>]", "Import flat-file history into SQLite. Optionally specify a JID to import only one contact." })

View File

@@ -6735,6 +6735,37 @@ cmd_history(ProfWin* window, const char* const command, gchar** args)
return TRUE;
}
if (g_strcmp0(args[0], "switch") == 0) {
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show_error("You must be connected to switch database backend.");
jabber.developer2 marked this conversation as resolved Outdated

It future, this requirement should be removed as it doesn't make much sense. Offline capabilities are really lacking. But I see why it exists (local SQLite is getting disconnected on disconnect).

Feel free to click "resolve" on this comment.

It future, this requirement should be removed as it doesn't make much sense. Offline capabilities are really lacking. But I see why it exists (local SQLite is getting disconnected on disconnect). Feel free to click "resolve" on this comment.
return TRUE;
}
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (g_strcmp0(args[1], "sqlite") != 0 && g_strcmp0(args[1], "flatfile") != 0) {
jabber.developer2 marked this conversation as resolved Outdated

Nice nesting: everything is flat. Easy to read, easy to maintain.

Resolveable.

Nice nesting: everything is flat. Easy to read, easy to maintain. Resolveable.
cons_show_error("Backend must be 'sqlite' or 'flatfile'.");
return TRUE;
}
if (active_db_backend && g_strcmp0(active_db_backend->name, args[1]) == 0) {
cons_show("Already using '%s' backend.", args[1]);
return TRUE;
}
cons_show("Switching database backend to '%s'...", args[1]);
if (log_database_switch_backend(args[1])) {
cons_show("Database backend switched to '%s'.", args[1]);
} else {
cons_show_error("Failed to switch database backend.");
}
return TRUE;
}
if (g_strcmp0(args[0], "verify") == 0) {
const gchar* contact_jid = args[1]; // may be NULL (verify all)
cons_show("Verifying history integrity...");

View File

@@ -44,6 +44,7 @@
#include "config.h"
#include "database.h"
#include "config/preferences.h"
#include "config/accounts.h"
#include "ui/ui.h"
#include "xmpp/xmpp.h"
#include "xmpp/message.h"
@@ -96,6 +97,34 @@ log_database_close(void)
active_db_backend = NULL;
}
gboolean
log_database_switch_backend(const char* new_backend)
{
// Close current backend
log_database_close();
// Update preference
prefs_set_string(PREF_DBLOG, new_backend);
prefs_save();
jabber.developer marked this conversation as resolved
Review

Typically, prefs are not autosaved and need manual saving via /save command. This place creates an exception, which needs to be discussed (e.g., later we might add /autosave command).

Typically, prefs are not autosaved and need manual saving via `/save` command. This place creates an exception, which needs to be discussed (e.g., later we might add `/autosave` command).

Corrected

Corrected
// Get current account to reinitialize
const char* account_name = session_get_account_name();
if (!account_name) {
log_error("log_database_switch_backend: no active session");
return FALSE;
}
ProfAccount* account = accounts_get_account(account_name);
if (!account) {
log_error("log_database_switch_backend: account '%s' not found", account_name);
return FALSE;
}
gboolean result = log_database_init(account);
account_free(account);
return result;
}
void
log_database_add_incoming(ProfMessage* message)
{

View File

@@ -93,6 +93,7 @@ db_backend_t* db_backend_flatfile(void);
// Public API (dispatches to active_db_backend)
gboolean log_database_init(ProfAccount* account);
gboolean log_database_switch_backend(const char* new_backend);
void log_database_add_incoming(ProfMessage* message);
void log_database_add_outgoing_chat(const char* const id, const char* const barejid, const char* const message, const char* const replace_id, prof_enc_t enc);
void log_database_add_outgoing_muc(const char* const id, const char* const barejid, const char* const message, const char* const replace_id, prof_enc_t enc);

View File

@@ -25,9 +25,14 @@
#include "config.h"
#include "database.h"
#include "database_flatfile.h"
db_backend_t* active_db_backend = NULL;
// The flatfile parser needs this global for path construction.
// In tests we keep it NULL since no real file I/O happens via the backend.
char* g_flatfile_account_jid = NULL;
gboolean
log_database_init(ProfAccount* account)
{
@@ -53,6 +58,11 @@ void
log_database_close(void)
{
}
gboolean
log_database_switch_backend(const char* new_backend)
{
return TRUE;
}
GSList*
log_database_verify_integrity(const gchar* const contact_barejid)
{