Skip to content

Commit c340348

Browse files
committed
Setup the RpcServer path in Settings and environment
* Handle DELTACHAR_RPC_SERVER environment * Save the path in settings to avoid startup scans * Advanced section in settings to customize it
1 parent 62f129e commit c340348

3 files changed

Lines changed: 141 additions & 6 deletions

File tree

src/account_finder.vala

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,17 @@ namespace Dc {
1111

1212
/**
1313
* Return an absolute path to deltachat-rpc-server, or null if none found.
14+
*
15+
* When `override_path` is non-empty, it is used exclusively: if it is
16+
* not executable, null is returned so the caller can surface a
17+
* "configured path is broken" error instead of silently falling back
18+
* to the scan.
1419
*/
15-
public static string? find_rpc_server () {
20+
public static string? find_rpc_server (string? override_path = null) {
21+
if (override_path != null && override_path.length > 0) {
22+
return FileUtils.test (override_path, FileTest.IS_EXECUTABLE) ? override_path : null;
23+
}
24+
1625
/* PATH first — covers distro packages, /usr/local, and ~/.local/bin
1726
* when the user has it exported. */
1827
string? in_path = Environment.find_program_in_path (RPC_BIN);

src/settings_dialog.vala

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ namespace Dc {
88
public bool markdown_rendering { get; set; default = false; }
99
public bool shift_enter_sends { get; set; default = false; }
1010
public bool notifications_enabled { get; set; default = true; }
11+
public string rpc_server_path { get; set; default = ""; }
1112

1213
public static string get_config_path () {
1314
return Path.build_filename (
@@ -24,6 +25,7 @@ namespace Dc {
2425
Markdown.enabled = markdown_rendering;
2526
shift_enter_sends = kf_bool (kf, "shift_enter_sends", false);
2627
notifications_enabled = kf_bool (kf, "notifications_enabled", true);
28+
rpc_server_path = kf_str (kf, "rpc_server_path", "");
2729
}
2830

2931
private static int kf_int (KeyFile kf, string k, int d) {
@@ -34,6 +36,10 @@ namespace Dc {
3436
try { return kf.get_boolean ("General", k); } catch { return d; }
3537
}
3638

39+
private static string kf_str (KeyFile kf, string k, string d) {
40+
try { return kf.get_string ("General", k); } catch { return d; }
41+
}
42+
3743
public void save_double_click_action (int v) {
3844
double_click_action = v;
3945
save_to_file ((kf) => { kf.set_integer ("General", "double_click_action", v); });
@@ -54,6 +60,11 @@ namespace Dc {
5460
save_to_file ((kf) => { kf.set_boolean ("General", "notifications_enabled", v); });
5561
}
5662

63+
public void save_rpc_server_path (string v) {
64+
rpc_server_path = v;
65+
save_to_file ((kf) => { kf.set_string ("General", "rpc_server_path", v); });
66+
}
67+
5768
public void save_to_file (SettingWriter writer) {
5869
var kf = new KeyFile ();
5970
try {
@@ -76,6 +87,8 @@ namespace Dc {
7687
private Gtk.ListBox accounts_list;
7788
private Gtk.Box content;
7889
private unowned Window app_window;
90+
private Adw.ActionRow rpc_row;
91+
private Gtk.Switch rpc_custom_switch;
7992

8093
public signal void account_changed ();
8194

@@ -196,6 +209,39 @@ namespace Dc {
196209
behavior_list.append (notif_row);
197210
content.append (behavior_list);
198211

212+
/* Advanced section */
213+
var advanced_label = new Gtk.Label ("Advanced");
214+
advanced_label.add_css_class ("title-3");
215+
advanced_label.halign = Gtk.Align.START;
216+
content.append (advanced_label);
217+
218+
var advanced_list = new Gtk.ListBox ();
219+
advanced_list.selection_mode = Gtk.SelectionMode.NONE;
220+
advanced_list.add_css_class ("boxed-list");
221+
222+
rpc_row = new Adw.ActionRow ();
223+
rpc_row.title = "deltachat-rpc-server";
224+
225+
var rpc_choose_btn = new Gtk.Button.with_label ("Choose…");
226+
rpc_choose_btn.valign = Gtk.Align.CENTER;
227+
rpc_choose_btn.add_css_class ("flat");
228+
rpc_choose_btn.tooltip_text = "Pick a deltachat-rpc-server binary";
229+
rpc_choose_btn.clicked.connect (() => { on_browse_rpc_server.begin (); });
230+
rpc_row.add_suffix (rpc_choose_btn);
231+
232+
rpc_custom_switch = new Gtk.Switch ();
233+
rpc_custom_switch.valign = Gtk.Align.CENTER;
234+
rpc_custom_switch.tooltip_text = "Use a custom deltachat-rpc-server binary";
235+
rpc_custom_switch.active = app_window.settings.rpc_server_path.length > 0;
236+
rpc_custom_switch.notify["active"].connect (on_rpc_switch_toggled);
237+
rpc_custom_switch.bind_property ("active", rpc_choose_btn, "sensitive",
238+
BindingFlags.SYNC_CREATE);
239+
rpc_row.add_suffix (rpc_custom_switch);
240+
241+
advanced_list.append (rpc_row);
242+
content.append (advanced_list);
243+
update_rpc_row ();
244+
199245
var scroll = new Gtk.ScrolledWindow ();
200246
scroll.vexpand = true;
201247
scroll.hscrollbar_policy = Gtk.PolicyType.NEVER;
@@ -373,6 +419,58 @@ namespace Dc {
373419
"remove", "Remove", () => { do_remove_account.begin (acct_id); });
374420
}
375421

422+
private void update_rpc_row () {
423+
string custom = app_window.settings.rpc_server_path;
424+
if (custom.length > 0) {
425+
bool ok = FileUtils.test (custom, FileTest.IS_EXECUTABLE);
426+
rpc_row.subtitle = ok ? "Custom" : "❌ Custom path is not executable";
427+
rpc_row.tooltip_text = custom;
428+
} else {
429+
string? found = AccountFinder.find_rpc_server ();
430+
rpc_row.subtitle = found != null ? "Auto-detected" : "❌ Not found";
431+
rpc_row.tooltip_text = found ?? "No deltachat-rpc-server binary in the default locations";
432+
}
433+
}
434+
435+
private void on_rpc_switch_toggled () {
436+
if (rpc_custom_switch.active) {
437+
on_browse_rpc_server.begin ();
438+
} else if (app_window.settings.rpc_server_path.length > 0) {
439+
app_window.settings.save_rpc_server_path ("");
440+
app_window.show_toast ("Using auto-detected RPC server. Restart to apply.");
441+
update_rpc_row ();
442+
}
443+
}
444+
445+
private async void on_browse_rpc_server () {
446+
var dlg = new Gtk.FileDialog ();
447+
dlg.title = "Locate deltachat-rpc-server";
448+
dlg.modal = true;
449+
450+
string start = app_window.settings.rpc_server_path;
451+
if (start.length == 0) start = AccountFinder.find_rpc_server () ?? "";
452+
if (start.length > 0) dlg.initial_file = File.new_for_path (start);
453+
454+
try {
455+
var file = yield dlg.open (app_window, null);
456+
if (file != null) {
457+
string? path = file.get_path ();
458+
if (path != null && FileUtils.test (path, FileTest.IS_EXECUTABLE)) {
459+
app_window.settings.save_rpc_server_path (path);
460+
app_window.show_toast ("RPC server path saved. Restart to apply.");
461+
} else {
462+
show_error (app_window, "Selected file is not an executable binary.");
463+
}
464+
}
465+
} catch (Error e) {
466+
if (!(e is Gtk.DialogError) && !(e is IOError.CANCELLED))
467+
show_error (app_window, e.message);
468+
}
469+
/* Sync switch to actual state — reverts the toggle if nothing was saved. */
470+
rpc_custom_switch.active = app_window.settings.rpc_server_path.length > 0;
471+
update_rpc_row ();
472+
}
473+
376474
private async void do_remove_account (int acct_id) {
377475
try {
378476
yield rpc.remove_account (acct_id);

src/window.vala

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,11 +211,16 @@ namespace Dc {
211211
private async void try_connect () {
212212
rpc = ((Dc.Application) this.application).rpc;
213213

214-
/* Find the RPC server binary */
215-
string? rpc_path = AccountFinder.find_rpc_server ();
214+
/* Reset any error widget left from a previous failed attempt. */
215+
empty_status.child = null;
216+
empty_status.icon_name = "mail-send-receive-symbolic";
217+
empty_status.title = "Delta Chat";
218+
empty_status.description = "Select a chat to start messaging,\nor wait for the connection…";
219+
220+
/* Find the RPC server binary — user override then auto-scan. */
221+
string? rpc_path = AccountFinder.find_rpc_server (settings.rpc_server_path);
216222
if (rpc_path == null) {
217-
show_toast ("Delta Chat RPC server not found. Install deltachat-rpc-server.");
218-
empty_status.description = "deltachat-rpc-server not found.\nInstall it with: pip install deltachat-rpc-server";
223+
show_rpc_not_found ();
219224
return;
220225
}
221226

@@ -271,6 +276,24 @@ namespace Dc {
271276
}
272277
}
273278

279+
private void show_rpc_not_found () {
280+
empty_status.icon_name = "dialog-error-symbolic";
281+
empty_status.title = "RPC server not found";
282+
empty_status.description = settings.rpc_server_path.length > 0
283+
? "Configured path is missing or not executable:\n" + settings.rpc_server_path
284+
: "deltachat-rpc-server was not found.\nOpen Settings to locate it, or install it.";
285+
286+
var btn = new Gtk.Button.with_label ("Open Settings…");
287+
btn.add_css_class ("suggested-action");
288+
btn.add_css_class ("pill");
289+
btn.halign = Gtk.Align.CENTER;
290+
btn.clicked.connect (show_settings_dialog);
291+
empty_status.child = btn;
292+
293+
content_stack.visible_child_name = "empty";
294+
show_toast ("Delta Chat RPC server not found");
295+
}
296+
274297
/* ================================================================
275298
* Chat List
276299
* ================================================================ */
@@ -568,7 +591,12 @@ namespace Dc {
568591

569592
var dialog = new SettingsDialog (rpc, this);
570593
active_modal = dialog;
571-
dialog.closed.connect (() => { active_modal = null; });
594+
dialog.closed.connect (() => {
595+
active_modal = null;
596+
if (!rpc.is_connected && settings.rpc_server_path.length > 0) {
597+
try_connect.begin ();
598+
}
599+
});
572600
dialog.account_changed.connect (() => {
573601
reload_active_account.begin ();
574602
});

0 commit comments

Comments
 (0)