feat: add /history switch for runtime database backend switching
Some checks failed
CI Code / Check coding style (pull_request) Successful in 47s
CI Code / Check spelling (pull_request) Successful in 55s
CI Code / Linux (ubuntu) (pull_request) Failing after 2m46s
CI Code / Code Coverage (pull_request) Failing after 5m17s
CI Code / Linux (debian) (pull_request) Failing after 6m3s
CI Code / Linux (arch) (pull_request) Failing after 7m21s

Add log_database_switch_backend() that closes the current backend,
updates PREF_DBLOG preference, and reinitializes with the new backend
without requiring a reconnect or restart.

New command: /history switch sqlite|flatfile
- Validates connection state and backend name
- Skips if already using the requested backend
- Autocomplete support for the subcommand
This commit is contained in:
2026-02-26 14:04:38 +03:00
parent 899d5dfe61
commit 650686c241
5 changed files with 75 additions and 0 deletions

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." },
{ "verify [<jid>]", "Verify integrity of message history. Optionally specify a JID to check only one contact." },
{ "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.");
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) {
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();
// 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);