Skip to content

Commit 898cca9

Browse files
feat(webview): add proxy config to MiniApp/QuickBrowser
- Proxy settings belong to the launch site, not the caller; threading them through WebViewWidget::create keeps the contract explicit and avoids hidden global state that would break concurrent instances. - Persisting last-used proxy in ApplicationSettings lets QuickBrowser restore the user's choice across sessions without extra plumbing. - BrowserProxyArgs is extracted as a pure function so the arg-building logic can be unit-tested without spinning up a WebView environment. - Removed the duplicate usage_update handler whose flat shape was superseded by the structured usageObj path already present above it.
1 parent 55e399d commit 898cca9

20 files changed

Lines changed: 395 additions & 45 deletions

src/AcpConnection.cpp

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -788,30 +788,6 @@ void AcpConnection::handleInboundNotification(const QString &method, const QJson
788788
usage.maxTokens = usageObj.value(QStringLiteral("maxTokens")).toInt();
789789
}
790790
emit usageUpdated(usage);
791-
} else if (kind == QLatin1String("usage_update")) {
792-
// Flat shape: { sessionUpdate: "usage_update", used: N, size: N, cost: {...} }
793-
// The agent treats this as the authoritative running total, so it
794-
// replaces the snapshot (see AcpConnection::usageReplaced docs).
795-
AcpProtocol::AcpUsage usage;
796-
if (update.contains(QStringLiteral("used"))) {
797-
usage.totalTokens = update.value(QStringLiteral("used")).toInt();
798-
}
799-
if (update.contains(QStringLiteral("size"))) {
800-
usage.maxTokens = update.value(QStringLiteral("size")).toInt();
801-
}
802-
const QJsonValue costVal = update.value(QStringLiteral("cost"));
803-
if (costVal.isObject()) {
804-
const QJsonObject costObj = costVal.toObject();
805-
const QJsonValue amount = costObj.value(QStringLiteral("amount"));
806-
if (amount.isDouble()) {
807-
usage.costAmount = amount.toDouble();
808-
}
809-
const QJsonValue currency = costObj.value(QStringLiteral("currency"));
810-
if (currency.isString()) {
811-
usage.costCurrency = currency.toString();
812-
}
813-
}
814-
emit usageReplaced(usage);
815791
} else if (kind == QLatin1String("prompt_start")) {
816792
beginPrompt();
817793
} else if (kind == QLatin1String("prompt_end")) {

src/ApplicationSettings.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,13 @@ CREATE_SETTING(Terminal, TerminalFont, terminalFont, QString, []() {
9494
return QFontDatabase::systemFont(QFontDatabase::FixedFont).toString();
9595
})
9696

97+
// --- Quick Browser last-used proxy settings ------------------------------------
98+
99+
CREATE_SETTING(QuickBrowser, LastProxyType, lastProxyType, int, 0)
100+
CREATE_SETTING(QuickBrowser, LastProxyHost, lastProxyHost, QString, QStringLiteral(""))
101+
CREATE_SETTING(QuickBrowser, LastProxyPort, lastProxyPort, int, 0)
102+
CREATE_SETTING(QuickBrowser, LastProxyBypassList, lastProxyBypassList, QString, QStringLiteral(""))
103+
97104
CREATE_SETTING(Git, SyntaxHighlightDiffEnabled, syntaxHighlightDiffEnabled, bool, true)
98105

99106
// Files-tab decoration master toggle — see file-tree-git-decorations spec.

src/ApplicationSettings.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ class ApplicationSettings : public QSettings
135135
DEFINE_SETTING(ShellCommand, shellCommand, QString)
136136
DEFINE_SETTING(TerminalFont, terminalFont, QString)
137137

138+
DEFINE_SETTING(LastProxyType, lastProxyType, int)
139+
DEFINE_SETTING(LastProxyHost, lastProxyHost, QString)
140+
DEFINE_SETTING(LastProxyPort, lastProxyPort, int)
141+
DEFINE_SETTING(LastProxyBypassList, lastProxyBypassList, QString)
142+
138143
// Per-workspace task registry. Stored as a single JSON object:
139144
// { "<cleanPath>": [{"name":"...","command":"..."},...], ... }
140145
// Never deleted — tasks survive workspace close/removal.

src/BrowserProxyArgs.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* This file is part of NotepadAI.
3+
* Copyright 2024 NotepadAI contributors
4+
*
5+
* SPDX-License-Identifier: GPL-3.0-or-later
6+
*/
7+
8+
#include "BrowserProxyArgs.h"
9+
10+
#include <QStringList>
11+
#include <QLatin1String>
12+
13+
QString buildBrowserArgs(int debugPort, int proxyType, const QString &proxyHost,
14+
int proxyPort, const QString &proxyBypassList)
15+
{
16+
QStringList args;
17+
18+
if (debugPort > 0)
19+
args << QStringLiteral("--remote-debugging-port=%1").arg(debugPort);
20+
21+
if (proxyType > 0) {
22+
const QString host = proxyHost.trimmed();
23+
if (!host.isEmpty()) {
24+
static const char *schemes[] = {"http", "https", "socks4", "socks5"};
25+
const int idx = qBound(0, proxyType - 1, 3);
26+
27+
QString proxyUrl = QStringLiteral("%1://%2")
28+
.arg(QLatin1String(schemes[idx]), host);
29+
if (proxyPort > 0 && proxyPort <= 65535)
30+
proxyUrl += QStringLiteral(":%1").arg(proxyPort);
31+
32+
args << QStringLiteral("--proxy-server=%1").arg(proxyUrl);
33+
34+
const QString bypass = proxyBypassList.trimmed();
35+
if (!bypass.isEmpty())
36+
args << QStringLiteral("--proxy-bypass-list=%1").arg(bypass);
37+
}
38+
}
39+
40+
return args.join(QLatin1Char(' '));
41+
}

src/BrowserProxyArgs.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* This file is part of NotepadAI.
3+
* Copyright 2024 NotepadAI contributors
4+
*
5+
* SPDX-License-Identifier: GPL-3.0-or-later
6+
*/
7+
8+
#pragma once
9+
10+
#include <QString>
11+
12+
// Builds Chromium command-line arguments for proxy configuration and CDP debug port.
13+
// proxyType: 0=None, 1=HTTP, 2=HTTPS, 3=SOCKS4, 4=SOCKS5.
14+
// Returns empty string if proxy is disabled or host is empty.
15+
// debugPort > 0 appends --remote-debugging-port.
16+
QString buildBrowserArgs(int debugPort, int proxyType = 0, const QString &proxyHost = QString(),
17+
int proxyPort = 0, const QString &proxyBypassList = QString());

src/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ qt_add_executable(NotepadAI
1515
GoalAgent.h
1616
GoalAgentSettings.h
1717
GoalPromptRenderer.h
18+
BrowserProxyArgs.h
1819
ByteArrayUtils.h
1920
ColorPickerDelegate.h
2021
ComboBoxDelegate.h
@@ -91,6 +92,7 @@ qt_add_executable(NotepadAI
9192
GoalAgent.cpp
9293
GoalAgentSettings.cpp
9394
GoalPromptRenderer.cpp
95+
BrowserProxyArgs.cpp
9496
ColorPickerDelegate.cpp
9597
ComboBoxDelegate.cpp
9698
Converter.cpp

src/MiniAppDefinition.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ struct MiniAppDefinition
2222
int healthTimeoutMs = 30000; // Timeout in ms (range 5000-300000)
2323
int debugPort = 0; // CDP debug port (0 = disabled, 1-65535 = enabled)
2424
bool autoKillOnClose = true; // Kill process on tab close
25+
int proxyType = 0; // 0=None, 1=HTTP, 2=HTTPS, 3=SOCKS4, 4=SOCKS5
26+
QString proxyHost;
27+
int proxyPort = 0; // 0 = use scheme default
28+
QString proxyBypassList;
2529

2630
bool isValid() const { return !name.isEmpty() && !url.isEmpty(); }
2731

src/MiniAppInstance.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,8 @@ void MiniAppInstance::onHealthPoll()
292292

293293
void MiniAppInstance::createWebView()
294294
{
295-
m_webView = WebViewWidget::create(m_def.id, QUrl(m_def.url), m_def.debugPort, nullptr);
295+
m_webView = WebViewWidget::create(m_def.id, QUrl(m_def.url), m_def.debugPort, nullptr, QString(),
296+
m_def.proxyType, m_def.proxyHost, m_def.proxyPort, m_def.proxyBypassList);
296297
if (!m_webView) {
297298
// Platform doesn't support embedded webview (Linux)
298299
setState(Running);

src/MiniAppManager.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,9 @@ void MiniAppManager::sweepStaleQuickBrowserData()
245245
}
246246
}
247247

248-
void MiniAppManager::launchQuickBrowser(const QUrl &url, bool enableCdp)
248+
void MiniAppManager::launchQuickBrowser(const QUrl &url, bool enableCdp,
249+
int proxyType, const QString &proxyHost,
250+
int proxyPort, const QString &proxyBypassList)
249251
{
250252
#ifdef Q_OS_LINUX
251253
QDesktopServices::openUrl(url);
@@ -294,7 +296,8 @@ void MiniAppManager::launchQuickBrowser(const QUrl &url, bool enableCdp)
294296
}
295297
}
296298

297-
auto *webView = WebViewWidget::create(appId, url, debugPort, nullptr, userDataPath);
299+
auto *webView = WebViewWidget::create(appId, url, debugPort, nullptr, userDataPath,
300+
proxyType, proxyHost, proxyPort, proxyBypassList);
298301
if (!webView)
299302
return;
300303

src/MiniAppManager.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ class MiniAppManager : public QObject
4040
~MiniAppManager() override;
4141

4242
void launchApp(const MiniAppDefinition &def);
43-
void launchQuickBrowser(const QUrl &url, bool enableCdp = true);
43+
void launchQuickBrowser(const QUrl &url, bool enableCdp = true,
44+
int proxyType = 0, const QString &proxyHost = QString(),
45+
int proxyPort = 0, const QString &proxyBypassList = QString());
4446
void shutdown();
4547

4648
int runningCount() const { return m_instances.size(); }

0 commit comments

Comments
 (0)