Skip to content

Commit d48d611

Browse files
committed
release: v1.3.0
1 parent 0dde2e5 commit d48d611

32 files changed

Lines changed: 2965 additions & 575 deletions

AdGuardVpnI18n.qml

Lines changed: 141 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,26 @@ import QtQuick
44
import qs.Services
55
import "./i18n/en.js" as En
66
import "./i18n/pt_BR.js" as PtBR
7+
import "./i18n/es_ES.js" as EsES
8+
import "./i18n/zh_CN.js" as ZhCN
9+
import "./i18n/hi_IN.js" as HiIN
10+
import "./i18n/ar.js" as Ar
11+
import "./i18n/bn_BD.js" as BnBD
12+
import "./i18n/fr_FR.js" as FrFR
13+
import "./i18n/de_DE.js" as DeDE
14+
import "./i18n/ja_JP.js" as JaJP
15+
import "./i18n/ru_RU.js" as RuRU
16+
import "./i18n/ko_KR.js" as KoKR
17+
import "./i18n/id_ID.js" as IdID
18+
import "./i18n/tr_TR.js" as TrTR
19+
import "./i18n/vi_VN.js" as ViVN
20+
import "./i18n/it_IT.js" as ItIT
21+
import "./i18n/pl_PL.js" as PlPL
22+
import "./i18n/nl_NL.js" as NlNL
23+
import "./i18n/fa_IR.js" as FaIR
24+
import "./i18n/th_TH.js" as ThTH
25+
import "./i18n/ur_PK.js" as UrPK
26+
import "./i18n/ms_MY.js" as MsMY
727

828
QtObject {
929
id: root
@@ -32,13 +52,133 @@ QtObject {
3252
if (lower.indexOf("pt") === 0) {
3353
return "pt_BR";
3454
}
55+
if (lower.indexOf("es") === 0) {
56+
return "es_ES";
57+
}
58+
if (lower.indexOf("zh") === 0) {
59+
return "zh_CN";
60+
}
61+
if (lower.indexOf("hi") === 0) {
62+
return "hi_IN";
63+
}
64+
if (lower.indexOf("ar") === 0) {
65+
return "ar";
66+
}
67+
if (lower.indexOf("bn") === 0) {
68+
return "bn_BD";
69+
}
70+
if (lower.indexOf("fr") === 0) {
71+
return "fr_FR";
72+
}
73+
if (lower.indexOf("de") === 0) {
74+
return "de_DE";
75+
}
76+
if (lower.indexOf("ja") === 0) {
77+
return "ja_JP";
78+
}
79+
if (lower.indexOf("ru") === 0) {
80+
return "ru_RU";
81+
}
82+
if (lower.indexOf("ko") === 0) {
83+
return "ko_KR";
84+
}
85+
if (lower.indexOf("id") === 0 || lower.indexOf("in") === 0) {
86+
return "id_ID";
87+
}
88+
if (lower.indexOf("tr") === 0) {
89+
return "tr_TR";
90+
}
91+
if (lower.indexOf("vi") === 0) {
92+
return "vi_VN";
93+
}
94+
if (lower.indexOf("it") === 0) {
95+
return "it_IT";
96+
}
97+
if (lower.indexOf("pl") === 0) {
98+
return "pl_PL";
99+
}
100+
if (lower.indexOf("nl") === 0) {
101+
return "nl_NL";
102+
}
103+
if (lower.indexOf("fa") === 0) {
104+
return "fa_IR";
105+
}
106+
if (lower.indexOf("th") === 0) {
107+
return "th_TH";
108+
}
109+
if (lower.indexOf("ur") === 0) {
110+
return "ur_PK";
111+
}
112+
if (lower.indexOf("ms") === 0) {
113+
return "ms_MY";
114+
}
35115
return "en_US";
36116
}
37117

38118
function getBundle(locale) {
39119
if (locale === "pt_BR") {
40120
return PtBR.translations;
41121
}
122+
if (locale === "es_ES") {
123+
return EsES.translations;
124+
}
125+
if (locale === "zh_CN") {
126+
return ZhCN.translations;
127+
}
128+
if (locale === "hi_IN") {
129+
return HiIN.translations;
130+
}
131+
if (locale === "ar") {
132+
return Ar.translations;
133+
}
134+
if (locale === "bn_BD") {
135+
return BnBD.translations;
136+
}
137+
if (locale === "fr_FR") {
138+
return FrFR.translations;
139+
}
140+
if (locale === "de_DE") {
141+
return DeDE.translations;
142+
}
143+
if (locale === "ja_JP") {
144+
return JaJP.translations;
145+
}
146+
if (locale === "ru_RU") {
147+
return RuRU.translations;
148+
}
149+
if (locale === "ko_KR") {
150+
return KoKR.translations;
151+
}
152+
if (locale === "id_ID") {
153+
return IdID.translations;
154+
}
155+
if (locale === "tr_TR") {
156+
return TrTR.translations;
157+
}
158+
if (locale === "vi_VN") {
159+
return ViVN.translations;
160+
}
161+
if (locale === "it_IT") {
162+
return ItIT.translations;
163+
}
164+
if (locale === "pl_PL") {
165+
return PlPL.translations;
166+
}
167+
if (locale === "nl_NL") {
168+
return NlNL.translations;
169+
}
170+
if (locale === "fa_IR") {
171+
return FaIR.translations;
172+
}
173+
if (locale === "th_TH") {
174+
return ThTH.translations;
175+
}
176+
if (locale === "ur_PK") {
177+
return UrPK.translations;
178+
}
179+
if (locale === "ms_MY") {
180+
return MsMY.translations;
181+
}
42182
return En.translations;
43183
}
44184

@@ -56,9 +196,7 @@ QtObject {
56196
}
57197

58198
for (const param in params) {
59-
const value = params[param] === undefined || params[param] === null
60-
? ""
61-
: params[param].toString();
199+
const value = params[param] === undefined || params[param] === null ? "" : params[param].toString();
62200
text = text.replace(new RegExp("\\{" + param + "\\}", "g"), value);
63201
}
64202
return text;

AdGuardVpnService.qml

Lines changed: 120 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ Item {
6363
property string routingMode: ""
6464
property bool changeSystemDns: false
6565
readonly property string tunnelLogPath: "$HOME/.local/share/adguardvpn-cli/tunnel.log"
66+
readonly property string controlSocketPath: "$HOME/.local/share/adguardvpn-cli/vpn.socket"
6667

6768
property var locations: []
6869
property string lastError: ""
@@ -520,7 +521,9 @@ Item {
520521
function connectFastest() {
521522
const args = buildArgs(["connect", "-f"], true);
522523

523-
runAction("connectFastest", args, t("app.title", "AdGuard VPN"), t("toast.fastest_selected", "Fastest location selected"));
524+
runAction("connectFastest", args, t("app.title", "AdGuard VPN"), t("toast.fastest_selected", "Fastest location selected"), {
525+
prepareDisconnectedRuntime: true
526+
});
524527
}
525528

526529
function resolveLocationTarget(locationText) {
@@ -561,7 +564,9 @@ Item {
561564

562565
runAction("connectLocation", args, t("app.title", "AdGuard VPN"), t("toast.connecting_to", "Connecting to {location}", {
563566
location: rawTarget
564-
}));
567+
}), {
568+
prepareDisconnectedRuntime: true
569+
});
565570
}
566571

567572
function disconnect() {
@@ -737,7 +742,64 @@ Item {
737742
}, 100);
738743
}
739744

740-
function runAction(operation, args, toastTitle, toastMessage) {
745+
function prepareDisconnectedRuntime(callback) {
746+
const tunPreflightRequired = (currentMode || "").toString().toLowerCase() !== "socks";
747+
const prepScript = `
748+
resolve_home() {
749+
if [ -n "$HOME" ]; then
750+
printf '%s' "$HOME"
751+
return
752+
fi
753+
getent passwd "$(id -u)" | cut -d: -f6
754+
}
755+
756+
HOME_DIR="$(resolve_home)"
757+
SOCKET_PATH="${controlSocketPath}"
758+
case "$SOCKET_PATH" in
759+
'$HOME'/*)
760+
SOCKET_PATH="$HOME_DIR/\${SOCKET_PATH#'$HOME'/}"
761+
;;
762+
esac
763+
764+
if [ "${tunPreflightRequired ? "1" : "0"}" = "1" ] && command -v ip >/dev/null 2>&1; then
765+
DEFAULT_ROUTE_COUNT="$(ip -o route show to default | wc -l | tr -d ' ')"
766+
if [ "\${DEFAULT_ROUTE_COUNT:-0}" -gt 1 ]; then
767+
printf 'multi-default'
768+
exit 44
769+
fi
770+
fi
771+
772+
if [ ! -S "$SOCKET_PATH" ]; then
773+
printf 'clean'
774+
exit 0
775+
fi
776+
777+
if command -v adguardvpn-cli >/dev/null 2>&1; then
778+
adguardvpn-cli disconnect >/dev/null 2>&1 || true
779+
sleep 1
780+
fi
781+
782+
if command -v lsof >/dev/null 2>&1 && lsof -nP "$SOCKET_PATH" >/dev/null 2>&1; then
783+
printf 'busy'
784+
exit 42
785+
fi
786+
787+
rm -f "$SOCKET_PATH" >/dev/null 2>&1 || true
788+
789+
if [ -S "$SOCKET_PATH" ]; then
790+
printf 'stale'
791+
exit 43
792+
fi
793+
794+
printf 'cleaned'
795+
`;
796+
797+
Proc.runCommand(`${pluginId}.prepareRuntime.${Date.now()}`, ["sh", "-lc", prepScript], (stdout, exitCode) => {
798+
callback(cleanOutput(stdout), exitCode);
799+
}, 100);
800+
}
801+
802+
function runAction(operation, args, toastTitle, toastMessage, options) {
741803
if (!cliAvailable) {
742804
ToastService.showError(t("app.title", "AdGuard VPN"), t("toast.cli_unavailable", "adguardvpn-cli is unavailable"));
743805
return;
@@ -753,38 +815,66 @@ Item {
753815
lastError = "";
754816
suspendPolling();
755817

756-
runCli(operation, args, (stdout, exitCode) => {
757-
commandRunning = false;
758-
runningCommand = "";
759-
resumePolling();
760-
761-
const clean = cleanOutput(stdout);
762-
recordLastCommand(args, exitCode, clean);
763-
if (exitCode === 0) {
764-
if (toastTitle) {
765-
const firstLine = clean.split("\n").map(line => line.trim()).filter(Boolean)[0];
766-
ToastService.showInfo(toastTitle, firstLine || toastMessage || t("toast.done", "Done"));
818+
const executeAction = () => {
819+
runningCommand = operation;
820+
821+
runCli(operation, args, (stdout, exitCode) => {
822+
commandRunning = false;
823+
runningCommand = "";
824+
resumePolling();
825+
826+
const clean = cleanOutput(stdout);
827+
recordLastCommand(args, exitCode, clean);
828+
if (exitCode === 0) {
829+
if (toastTitle) {
830+
const firstLine = clean.split("\n").map(line => line.trim()).filter(Boolean)[0];
831+
ToastService.showInfo(toastTitle, firstLine || toastMessage || t("toast.done", "Done"));
832+
}
833+
834+
Qt.callLater(() => {
835+
refreshStatus();
836+
refreshConfig();
837+
refreshLicense();
838+
});
839+
return;
767840
}
768841

769-
Qt.callLater(() => {
770-
refreshStatus();
771-
refreshConfig();
772-
refreshLicense();
842+
lastError = clean || t("toast.operation_failed", "{operation} failed (code {code})", {
843+
operation: operation,
844+
code: exitCode
773845
});
774-
return;
775-
}
846+
const hint = buildLocationHelpHint(lastError);
847+
if (hint) {
848+
lastError = `${lastError}\n${hint}`;
849+
}
850+
ToastService.showError(t("app.title", "AdGuard VPN"), lastError);
851+
refreshStatus();
852+
});
853+
};
776854

777-
lastError = clean || t("toast.operation_failed", "{operation} failed (code {code})", {
778-
operation: operation,
779-
code: exitCode
855+
if (options && options.prepareDisconnectedRuntime) {
856+
runningCommand = `${operation}.prepare`;
857+
prepareDisconnectedRuntime((prepStatus, prepExitCode) => {
858+
if (prepExitCode === 0) {
859+
executeAction();
860+
return;
861+
}
862+
863+
commandRunning = false;
864+
runningCommand = "";
865+
resumePolling();
866+
lastError = prepStatus === "multi-default"
867+
? t("toast.multiple_default_routes", "Multiple default routes are active. Disconnect the redundant network interface before connecting in TUN mode.")
868+
: (prepStatus === "busy"
869+
? t("toast.runtime_busy", "AdGuard VPN runtime is still busy after cleanup. Try again in a few seconds.")
870+
: t("toast.runtime_cleanup_failed", "Could not recover the AdGuard VPN runtime before connecting."));
871+
ToastService.showError(t("app.title", "AdGuard VPN"), lastError);
872+
refreshStatus();
780873
});
781-
const hint = buildLocationHelpHint(lastError);
782-
if (hint) {
783-
lastError = `${lastError}\n${hint}`;
784-
}
785-
ToastService.showError(t("app.title", "AdGuard VPN"), lastError);
786-
refreshStatus();
787-
});
874+
return;
875+
}
876+
877+
executeAction();
788878
}
789879

790880
Timer {

0 commit comments

Comments
 (0)