Public Access
IRC: edit server settings as a draft, applied under the service lock
The IRC App edited the live config while the IRC task could be reading it to connect. The App now edits a copy; applyConfig() validates it and swaps it in under the lock, and the task connects from a snapshot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
@@ -48,15 +48,19 @@ int IrcService::totalUnread() {
|
||||
return session_->totalUnread();
|
||||
}
|
||||
|
||||
std::string IrcService::saveConfig() {
|
||||
std::string error = config_.save();
|
||||
IrcConfig IrcService::draftConfig() {
|
||||
Lock l(lock_);
|
||||
return config_;
|
||||
}
|
||||
|
||||
std::string IrcService::applyConfig(const IrcConfig& draft) {
|
||||
std::string error = draft.validate();
|
||||
if (!error.empty()) return error;
|
||||
if (wanted_) {
|
||||
restart_ = true; // the task reconnects with a fresh session
|
||||
} else {
|
||||
Lock l(lock_);
|
||||
session_.reset(new IrcSession(config_)); // a new server or nick starts a fresh session
|
||||
}
|
||||
Lock l(lock_);
|
||||
config_.copySettingsFrom(draft);
|
||||
config_.save();
|
||||
if (wanted_) restart_ = true; // the task reconnects with a fresh session
|
||||
else session_.reset(new IrcSession(config_));
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -72,14 +76,15 @@ void IrcService::scheduleRetry(const std::string& why) {
|
||||
|
||||
bool IrcService::open() {
|
||||
status_ = Status::Connecting;
|
||||
bool pinning = config_.tls && config_.allowSelfSigned;
|
||||
conn_ = config_.tls ? static_cast<NetworkClient*>(&tlsClient_) : &plainClient_;
|
||||
if (config_.tls) {
|
||||
IrcConfig settings = draftConfig(); // a snapshot: the UI may apply new settings meanwhile
|
||||
bool pinning = settings.tls && settings.allowSelfSigned;
|
||||
conn_ = settings.tls ? static_cast<NetworkClient*>(&tlsClient_) : &plainClient_;
|
||||
if (settings.tls) {
|
||||
tlsClient_.setTimeout(15); // seconds, for the handshake
|
||||
if (pinning) tlsClient_.setInsecure();
|
||||
else tlsClient_.useBuiltinCACertBundle();
|
||||
}
|
||||
if (!conn_->connect(config_.host.c_str(), config_.port)) return false;
|
||||
if (!conn_->connect(settings.host.c_str(), settings.port)) return false;
|
||||
|
||||
if (pinning) {
|
||||
uint8_t sha[32];
|
||||
@@ -88,10 +93,11 @@ bool IrcService::open() {
|
||||
return false;
|
||||
}
|
||||
std::string fingerprint = hex(sha, sizeof(sha));
|
||||
if (config_.pinnedSha256.empty()) {
|
||||
if (settings.pinnedSha256.empty()) {
|
||||
Lock l(lock_);
|
||||
config_.pinnedSha256 = fingerprint; // trust on first use
|
||||
config_.save();
|
||||
} else if (config_.pinnedSha256 != fingerprint) {
|
||||
} else if (settings.pinnedSha256 != fingerprint) {
|
||||
tlsClient_.stop();
|
||||
Lock l(lock_);
|
||||
session_->disconnected(clock_.utcNow(), "server certificate changed: not connecting");
|
||||
@@ -145,6 +151,11 @@ void IrcService::flushEffects() {
|
||||
if (open_) conn_->print((line + "\r\n").c_str());
|
||||
|
||||
std::string date = clock_.localDate();
|
||||
std::string host;
|
||||
{
|
||||
Lock l(lock_);
|
||||
host = config_.host;
|
||||
}
|
||||
for (auto& entry : fx.logs) {
|
||||
const IrcLine& l = entry.line;
|
||||
std::string when = l.utc >= 0 ? ClockModel::formatLocalTime(l.utc) : "--:--";
|
||||
@@ -156,7 +167,7 @@ void IrcService::flushEffects() {
|
||||
case IrcLine::Kind::Info: text = l.text; break;
|
||||
default: text = "<" + l.nick + "> " + l.text; break;
|
||||
}
|
||||
storage_.appendLine(storage::dailyLogPath({"irc", config_.host, entry.buffer}, date), when + " " + text);
|
||||
storage_.appendLine(storage::dailyLogPath({"irc", host, entry.buffer}, date), when + " " + text);
|
||||
}
|
||||
for (auto& n : fx.notifications)
|
||||
bus_.publish(Event::withText(EventType::Notification, n.c_str(), static_cast<int32_t>(NotificationLevel::Message)));
|
||||
@@ -202,7 +213,7 @@ void IrcService::loop() {
|
||||
retryAtMs_ = now; // reconnect as soon as Wi-Fi is back
|
||||
} else if (!open_) {
|
||||
if (static_cast<int32_t>(now - retryAtMs_) >= 0) {
|
||||
if (!open()) scheduleRetry("could not connect to " + config_.host);
|
||||
if (!open()) scheduleRetry("could not connect to " + draftConfig().host);
|
||||
}
|
||||
} else if (!conn_->connected()) {
|
||||
close("");
|
||||
|
||||
Reference in New Issue
Block a user