This commit is contained in:
umorist 2026-02-23 05:28:35 +03:00
commit 5680d76e8b
8 changed files with 1964 additions and 0 deletions

View file

@ -0,0 +1,10 @@
import QtQuick
import org.kde.plasma.configuration
ConfigModel {
ConfigCategory {
name: "General"
icon: Qt.resolvedUrl("../images/dogfood.svg")
source: "config/General.qml"
}
}

View file

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name=""/>
<group name="General">
<entry name="RoutesAutoUp" type="Bool">
<default>true</default>
</entry>
<entry name="RoutesUpInt" type="Int">
<default>60</default>
<min>1</min>
<max>1440</max>
</entry>
<entry name="StatsAutoUp" type="Bool">
<default>true</default>
</entry>
<entry name="StatsUpInt" type="Int">
<default>1</default>
<min>1</min>
<max>1440</max>
</entry>
<entry name="ProfileAutoUp" type="Bool">
<default>true</default>
</entry>
<entry name="ProfileUpInt" type="Int">
<default>60</default>
<min>1</min>
<max>1440</max>
</entry>
<entry name="AutoPing" type="Bool">
<default>false</default>
</entry>
<entry name="AutoPingInt" type="Int">
<default>5</default>
<min>5</min>
<max>20</max>
</entry>
<entry name="OnErrorRefresh" type="Bool">
<default>true</default>
</entry>
<entry name="BIinit" type="Bool">
<default>true</default>
</entry>
<entry name="BIrefresh" type="Bool">
<default>true</default>
</entry>
<entry name="BIpostcountry" type="Bool">
<default>true</default>
</entry>
<entry name="BIpostshare" type="Bool">
<default>true</default>
</entry>
<entry name="BIpostebalka" type="Bool">
<default>true</default>
</entry>
<entry name="BIdevicesupdate" type="Bool">
<default>true</default>
</entry>
<entry name="BIfeaturesupdate" type="Bool">
<default>true</default>
</entry>
<entry name="BIautoupdate" type="Bool">
<default>true</default>
</entry>
<entry name="SBdisplay" type="Bool">
<default>true</default>
</entry>
<entry name="ExtraLayout" type="Bool">
<default>false</default>
</entry>
<entry name="StringLayoutPlacement" type="String">
<default>meow_icon iflag_extra provider</default>
</entry>
</group>
</kcfg>

View file

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
id="Layer_1"
enable-background="new 0 0 100 100"
viewBox="0 0 100 100"
version="1.1"
sodipodi:docname="paw-symbolic.svg"
inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs5" />
<sodipodi:namedview
id="namedview5"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="7.59"
inkscape:cx="47.826087"
inkscape:cy="50.658762"
inkscape:window-width="1920"
inkscape:window-height="967"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" />
<path
d="m27.6905899 34.1743889c.9704494 1.2511063 2.1611538 2.3145294 3.5135574 3.13797 1.38694.8570976 2.9807472 1.3211365 4.6110115 1.3424988.1997375.0000038.4011307-.0078316.6041718-.0234947 3.8116875-.310936 6.1308937-2.867218 7.5821838-5.6768723 1.6625671-3.5959549 2.2095757-7.6075706 1.5704727-11.517374-.2743645-1.8115234-.7711143-3.5822926-1.4790039-5.2722015-1.1606598-3.0347385-3.2719154-5.6125736-6.0184402-7.3484879-1.3880882-.8690901-2.9876938-1.3414187-4.6252327-1.3657351-.2005539 0-.4051476.0075498-.6137772.0226517-1.7313862.1293359-3.3765545.8068542-4.6968994 1.9342899-2.4161568 2.0348511-3.8965454 5.0749979-4.4730568 8.943635-.2927074 2.1026497-.2779732 4.2366943.0437298 6.335104.4657421 3.4588127 1.8394318 6.7325172 3.9812832 9.4880161z"
id="path1"
style="fill:#232629;fill-opacity:1" />
<path
d="m21.4703159 56.1579819c2.0682297-1.9989548 3.3843727-5.1062546 3.3843727-9.2130203.0130386-3.490139-.9501381-6.9143829-2.7807293-9.8859406-1.4948139-2.61026-3.7439079-4.7075806-6.4520836-6.0166683-1.2700024-.5838051-2.6496677-.8907719-4.0473957-.9005203-.3707933.0017223-.7410603.0281696-1.1083336.0791683-1.5750589.2012596-3.0501838.8818207-4.2255216 1.949482-2.1869798 1.8901024-3.5130196 4.9182281-3.7406242 8.935936v1.2963524c.1490023 3.4176598 1.1969333 6.7355309 3.0380213 9.6187515 1.5524182 2.5812492 3.8794909 4.6070518 6.6499987 5.7890625 1.157259.4549332 2.3883362.6931038 3.6317701.7026024.5487375.0028381 1.0961809-.0535583 1.6328115-.1682281 1.5218431-.3270227 2.9169275-1.0864183 4.0177137-2.1869775z"
id="path2"
style="fill:#232629;fill-opacity:1" />
<path
d="m63.5806808 38.631382c.2028122.0158882.4042015.0237198.6041641.0234947 1.6302719-.0213699 3.2240829-.4854126 4.6110153-1.3425217 1.352417-.8234253 2.5431213-1.8868484 3.5135574-3.13797 2.1418533-2.7554951 3.5155334-6.0292034 3.9812851-9.4880161.3217926-2.098402.3365173-4.2324619.0437241-6.335104-.5765076-3.8686361-2.0569-6.9087858-4.473053-8.9436369-1.320343-1.1274357-2.9655075-1.8049541-4.6968994-1.9342899-.2084732-.0153394-.413063-.0228896-.6137772-.0226517-1.637558.0243373-3.2371864.4966717-4.6253052 1.3657541-2.7465363 1.7359219-4.8577957 4.3137703-6.0184517 7.3485222-.7078896 1.689909-1.2046356 3.46068-1.4790001 5.2722034-.6390991 3.9098015-.0920944 7.9214191 1.5704689 11.517374 1.4513742 2.8096239 3.7705957 5.3659021 7.5822717 5.6768419z"
id="path3"
style="fill:#232629;fill-opacity:1" />
<path
d="m93.7593765 32.1704826c-1.1753311-1.0676613-2.6504593-1.7482224-4.2255173-1.949482-.3672714-.0509987-.7375412-.077446-1.1083374-.0791683-1.3977203.0097485-2.7773895.3167152-4.0473938.9005203-2.708168 1.3090916-4.9572678 3.4064083-6.4520798 6.0166683-1.8305893 2.9715576-2.7937622 6.3957977-2.7807236 9.8859367 0 4.1067696 1.3161469 7.2140617 3.3843765 9.2130165 1.1007843 1.1005592 2.4958649 1.8599472 4.0177002 2.1869774.5366364.1146698 1.0840836.1710663 1.6328125.1682281 1.2434387-.0094986 2.4745102-.2476692 3.6317749-.7026024 2.7705078-1.1820107 5.09758-3.2078133 6.6500015-5.7890625 1.8410797-2.8832207 2.8889999-6.201088 3.0380096-9.6187439v-1.2963524c-.2276075-4.0177076-1.5536421-7.0458334-3.7406233-8.9359358z"
id="path4"
style="fill:#232629;fill-opacity:1" />
<path
d="m83.0666504 82.109375c-.9733047 3.7200546-3.4400253 6.8533554-6.8266602 8.6666718-1.8133163 1.0533829-3.8666153 1.6666641-5.9599609 1.7732697h-1.5733185c-1.1333847-.0665665-2.2666855-.2265625-3.3867188-.4664688-5.2799492-1.1201172-9.7999687-3.1868515-16.119957-3.1868515-2.2666817.0400391-4.5066719.3867188-6.6800117 1.0400391-2.0400391.5467148-4.0133476 1.1201172-6.079998 1.6266327-2.2133751.6000977-4.4800587.9200821-6.7733536.9467773-2.1466465.0265274-4.2666836-.533371-6.1333008-1.6000977-1.5866699-.9199219-2.9867344-2.1598358-4.0933418-3.6266327-1.1733398-1.5598907-2.0266933-3.3466797-2.5066738-5.2399063-.546711-2.2932968-.6133614-4.6800156-.1866856-7.0133438.7466621-3.8666992 2.4799805-7.4534531 5.0533028-10.4401016.5866699-.7200546 1.1733398-1.3999062 1.8133965-2.0533867.6399727-.6399765 1.3465977-1.2265625 2.0266094-1.8531914 1.333334-1.2400703 2.5866699-2.5734062 3.746664-3.9866524 2.2800293-2.8001328 4.3333321-5.9733086 6.546711-8.9733086 2.1599922-2.9200821 4.4799805-5.9467773 7.7866211-7.6666641 1.7466621-.9334335 3.706707-1.413414 5.6800117-1.4000664.2133789 0 .4400253 0 .6533203.0133476 2.1866875.0533829 4.3466797.5200195 6.3466797 1.3867188 3.546711 1.5999336 5.8266602 4.4666328 7.8933105 7.586586 2.0800781 3.1067696 3.9733887 6.3867188 6.2666855 9.2133789 1.1467285 1.4265938 2.4133301 2.7599297 3.7733536 3.9733086 1.3733673 1.2000313 2.6533203 2.5066719 3.8266602 3.9200859 2.5599747 2.9733047 4.3066406 6.5465469 5.093338 10.3865509.4266816 2.3199844.3600312 4.6933593-.1866836 6.9733047z"
id="path5"
style="fill:#232629;fill-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 5.8 KiB

View file

@ -0,0 +1,163 @@
// functions from main.qml --> reworked
// GET routes
function fetchRoutes() {
isLoading = true;
routeModel.clear();
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://10.7.0.1:7777/routes");
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
isLoading = false;
if (xhr.status === 200) {
var response = JSON.parse(xhr.responseText);
for (var i = 0; i < response.length; i++) {
routeModel.append(response[i]);
}
} else {
console.error("Failed to fetch routes:", xhr.status);
}
}
}
xhr.send();
}
// GET profile
function fetchProfile() {
//isLoading = true;
profileModel.clear();
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://10.7.0.1:7777/me/profile");
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
//isLoading = false;
if (xhr.status === 200) {
profileData = JSON.parse(xhr.responseText);
//for (var i = 0; i < response.length; i++) {
// profileModel.append(response[i]);
//}
} else {
console.error("Failed to fetch profile:", xhr.status);
}
}
}
xhr.send();
}
// GET stats
function fetchStats() {
//isLoading = true;
statsModel.clear();
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://10.7.0.1:7777/stats");
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
//isLoading = false;
if (xhr.status === 200) {
statsData = JSON.parse(xhr.responseText);
//for (var i = 0; i < response.length; i++) {
// profileModel.append(response[i]);
//}
} else {
console.error("Failed to fetch profile:", xhr.status);
}
}
}
xhr.send();
}
// POST select country
function selectCountry(code, provider) {
isLoading = true;
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://10.7.0.1:7777/me/country");
xhr.setRequestHeader("Content-Type", "application/json");
var data = JSON.stringify({
"countryCode": code,
"provider": provider
});
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
isLoading = false;
if (xhr.status === 200) {
console.log("Success: Changed to " + code);
} else {
console.error("POST failed:", xhr.status);
}
}
}
xhr.send(data);
}
// POST switch share
function switchShare(bool) {
//isLoading = true;
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://10.7.0.1:7777/me/profile");
xhr.setRequestHeader("Content-Type", "application/json");
var data = JSON.stringify({
"shareTraffic": bool
});
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
//isLoading = false;
if (xhr.status === 200) {
console.log("Success: Share changed to " + bool);
} else {
console.error("POST failed:", xhr.status);
}
}
}
xhr.send(data);
}
// POST switch ebalka
function switchEbalka(bool, ip) {
//isLoading = true;
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://10.7.0.1:7777/me/ebalka");
xhr.setRequestHeader("Content-Type", "application/json");
var data = JSON.stringify({
"ebalka": bool,
"ip": ip
});
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
//isLoading = false;
if (xhr.status === 200) {
console.log("Success: Ebalka for " + ip + " changed to " + bool);
} else {
console.error("POST failed:", xhr.status);
}
}
}
xhr.send(data);
}
// не смотрите сюда
function getFlag($code) {
if ($code == 'US') return '🇺🇸';
if ($code == 'FI') return '🇫🇮';
if ($code == 'EE') return '🇪🇪';
if ($code == 'DE') return '🇩🇪';
if ($code == 'AM') return '🇦🇲';
if ($code == 'AD') return '🇦🇩';
if ($code == 'GB') return '🇬🇧';
if ($code == 'MC') return '🇲🇨';
if ($code == 'HK') return '🇭🇰';
if ($code == 'ES') return '🇪🇸';
if ($code == 'RU') return '🇷🇺';
if ($code == 'CH') return '🇨🇭';
return '❔';
}

View file

@ -0,0 +1,189 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kcmutils as KCM
import org.kde.plasma.components as PlasmaComponents
KCM.SimpleKCM {
id: generalConfig
property alias cfg_RoutesAutoUp: enableRoutesUpdate.checked
property alias cfg_RoutesUpInt: routesUpdateInterval.value
property alias cfg_StatsAutoUp: enableStatsUpdate.checked
property alias cfg_StatsUpInt: statsUpdateInterval.value
property alias cfg_ProfileAutoUp: enableProfileUpdate.checked
property alias cfg_ProfileUpInt: profileUpdateInterval.value
property alias cfg_AutoPing: enablePing.checked
property alias cfg_AutoPingInt: pingInterval.value
property alias cfg_OnErrorRefresh: enableOnErrorRefresh.checked
property alias cfg_BIinit: showOnInitBI.checked
property alias cfg_BIrefresh: showRefreshBI.checked
property alias cfg_BIpostcountry: showPostCountryBI.checked
property alias cfg_BIpostshare: showSwitchShareBI.checked
property alias cfg_BIpostebalka: showSwitchEbalkaBI.checked
property alias cfg_BIdevicesupdate: showDevicesActionsBI.checked
property alias cfg_BIfeaturesupdate: showFeaturesActionsBI.checked
property alias cfg_BIautoupdate: showAutoUpdateBI.checked
property alias cfg_SBdisplay: showSB.checked
property alias cfg_ExtraLayout: showExtra.checked
property alias cfg_StringLayoutPlacement: extraInput.text
Kirigami.FormLayout {
id: form
Kirigami.Separator {
Kirigami.FormData.isSection: true
Kirigami.FormData.label: i18n("AutoUpdate content")
}
RowLayout {
Kirigami.FormData.label: i18n("Routes")
CheckBox {
id: enableRoutesUpdate
}
SpinBox {
id: routesUpdateInterval
enabled: enableRoutesUpdate.checked
from: 1
to: 1440
textFromValue: function(text) { return text + "m"; }
valueFromText: function(value) { return parseInt(value); }
}
}
RowLayout {
Kirigami.FormData.label: i18n("Stats")
CheckBox {
id: enableStatsUpdate
}
SpinBox {
id: statsUpdateInterval
enabled: enableStatsUpdate.checked
from: 1
to: 1440
textFromValue: function(text) { return text + "m"; }
valueFromText: function(value) { return parseInt(value); }
}
}
RowLayout {
Kirigami.FormData.label: i18n("Profile")
CheckBox {
id: enableProfileUpdate
}
SpinBox {
id: profileUpdateInterval
enabled: enableProfileUpdate.checked
from: 1
to: 1440
textFromValue: function(text) { return text + "m"; }
valueFromText: function(value) { return parseInt(value); }
}
}
RowLayout {
Kirigami.FormData.label: i18n("Ping")
CheckBox {
id: enablePing
}
SpinBox {
id: pingInterval
enabled: enablePing.checked
from: 5
to: 20
textFromValue: function(text) { return text + "s"; }
valueFromText: function(value) { return parseInt(value); }
}
}
RowLayout {
Kirigami.FormData.label: i18n("AutoRefresh on error")
CheckBox {
id: enableOnErrorRefresh
}
}
Kirigami.Separator {
Kirigami.FormData.isSection: true
Kirigami.FormData.label: i18n("Busy indicator")
}
CheckBox {
Kirigami.FormData.label: i18n("Show Busy indicator on actions:")
id: showOnInitBI
text: i18n("Plasmoid Init")
}
CheckBox {
id: showRefreshBI
text: i18n("Refresh button")
}
CheckBox {
id: showPostCountryBI
text: i18n("Select country")
}
CheckBox {
id: showSwitchShareBI
text: i18n("Switch Share")
}
CheckBox {
id: showSwitchEbalkaBI
text: i18n("Switch 80% loss")
}
CheckBox {
id: showDevicesActionsBI
text: i18n("Devices actions")
}
CheckBox {
id: showFeaturesActionsBI
text: i18n("Features actions")
}
CheckBox {
id: showAutoUpdateBI
text: i18n("AutoUpdate actions")
}
Kirigami.Separator {
Kirigami.FormData.isSection: true
Kirigami.FormData.label: i18n("Extra")
}
RowLayout {
Kirigami.FormData.label: i18n("Show scrollbars")
CheckBox {
id: showSB
}
Kirigami.ContextualHelpButton {
toolTipText: i18n(
"If true, scrollbars will be shown as needed"
)
}
}
RowLayout {
Kirigami.FormData.label: i18n("CompactRepresentation extra data display")
CheckBox {
id: showExtra
}
TextField {
id: extraInput
enabled: showExtra.checked
placeholderText: "meow_icon iflag_extra provider ..."
//bottomPadding: Kirigami.Units.gridUnit
wrapMode: Text.Wrap
}
}
PlasmaComponents.Label {
text: (
"meow_icon - plasmoid icon\n" +
"user - your username\n" +
"current_device - current device name\n" +
"current - current country code (US, FI etc.)\n" +
"provider - vpn provider (NORD, WARP etc.)\n" +
"ip - current device ip (MeowRelay local)\n" +
"iflag - current country flag\n" +
"iflag_extra - current country flag + country code (joined)\n" +
"any variable from main.qml (root section)"
)
opacity: 0.7
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,356 @@
// чисто в теории это должно помочь долгой загрузке пакетов (так гемини сказал)
// на деле же хуй знает ибо там иногда хендшейк слетает и он просто заного его шлет
const xhrPool = [];
const MAX_POOL_SIZE = 6; // Qt's typical max concurrent connections
function getXhr() {
// Look for an idle object
for (let i = 0; i < xhrPool.length; i++) {
if (xhrPool[i].readyState === 0 || xhrPool[i].readyState === 4) {
return xhrPool[i];
}
}
// If none idle and we have room, make a new one
if (xhrPool.length < MAX_POOL_SIZE) {
let newXhr = new XMLHttpRequest();
xhrPool.push(newXhr);
return newXhr;
}
// If all busy, return null (you should queue the request)
return null;
}
// KeepAlive ping
function keepAlivePing() {
let xhr = getXhr();
if (!xhr) {
console.log("Pool full, retrying...");
setTimeout(() => keepAlivePing(), 100);
return;
}
xhr.open("HEAD", "http://10.7.0.1:7777/me/profile");
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
//isLoading = false;
if (xhr.status === 200) {
//console.log("ping pong")
}
}
}
xhr.send();
}
// GET routes
function fetchRoutes() {
//isLoading = true;
//routeModel.clear();
let xhr = getXhr();
if (!xhr) {
console.log("Pool full, retrying...");
setTimeout(() => fetchRoutes(), 100);
return;
}
xhr.open("GET", "http://10.7.0.1:7777/routes");
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
//isLoading = false;
if (xhr.status === 200) {
let response = JSON.parse(xhr.responseText);
WorkerScript.sendMessage({ "action": "fetch_routes", "data": response });
//for (var i = 0; i < response.length; i++) {
// routeModel.append(response[i]);
//}
} else {
WorkerScript.sendMessage({ "action": "fetch_routes", "data": [{"code":"ERR","name":"Error, please try again :<","provider":xhr.status}] });
console.error("Failed to fetch routes:", xhr.status);
}
}
}
xhr.send();
}
// GET profile
function fetchProfile() {
//isLoading = true;
//profileModel.clear();
let xhr = getXhr();
if (!xhr) {
console.log("Pool full, retrying...");
setTimeout(() => fetchProfile(), 100);
return;
}
xhr.open("GET", "http://10.7.0.1:7777/me/profile");
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
//isLoading = false;
if (xhr.status === 200) {
let response = JSON.parse(xhr.responseText);
WorkerScript.sendMessage({ "action": "fetch_profile", "data": response });
//for (var i = 0; i < response.length; i++) {
// profileModel.append(response[i]);
//}
} else {
WorkerScript.sendMessage({ "action": "fetch_profile", "data": {"provider":xhr.status, "current_device":"error"} });
console.error("Failed to fetch profile:", xhr.status);
}
}
}
xhr.send();
}
// GET stats
function fetchStats() {
//isLoading = true;
//statsModel.clear();
let xhr = getXhr();
if (!xhr) {
console.log("Pool full, retrying...");
setTimeout(() => fetchStats(), 100);
return;
}
xhr.open("GET", "http://10.7.0.1:7777/stats");
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
//isLoading = false;
if (xhr.status === 200) {
let response = JSON.parse(xhr.responseText);
WorkerScript.sendMessage({ "action": "fetch_stats", "data": response });
//for (var i = 0; i < response.length; i++) {
// profileModel.append(response[i]);
//}
} else {
WorkerScript.sendMessage({ "action": "fetch_stats", "data": {} });
console.error("Failed to fetch profile:", xhr.status);
}
}
}
xhr.send();
}
// POST select country
function selectCountry(code, provider) {
//isLoading = true;
let xhr = getXhr();
if (!xhr) {
console.log("Pool full, retrying...");
setTimeout(() => selectCountry(code, provider), 100);
return;
}
xhr.open("POST", "http://10.7.0.1:7777/me/country");
xhr.setRequestHeader("Content-Type", "application/json");
var data = JSON.stringify({
"countryCode": code,
"provider": provider
});
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
//isLoading = false;
if (xhr.status === 200) {
console.log("Success: Changed to " + code);
WorkerScript.sendMessage({ "action": "post_country", "status": xhr.status});
} else {
console.error("POST failed:", xhr.status);
WorkerScript.sendMessage({ "action": "post_country", "status": xhr.status});
}
}
}
xhr.send(data);
}
// POST switch share
function switchShare(bool) {
//isLoading = true;
let xhr = getXhr();
if (!xhr) {
console.log("Pool full, retrying...");
setTimeout(() => switchShare(bool), 100);
return;
}
xhr.open("POST", "http://10.7.0.1:7777/me/profile");
xhr.setRequestHeader("Content-Type", "application/json");
var data = JSON.stringify({
"shareTraffic": bool
});
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
//isLoading = false;
if (xhr.status === 200) {
console.log("Success: Share changed to " + bool);
WorkerScript.sendMessage({ "action": "post_share", "status": xhr.status});
} else {
console.error("POST failed:", xhr.status);
WorkerScript.sendMessage({ "action": "post_share", "status": xhr.status});
}
}
}
xhr.send(data);
}
// POST switch ebalka
function switchEbalka(bool, ip) {
//isLoading = true;
let xhr = getXhr();
if (!xhr) {
console.log("Pool full, retrying...");
setTimeout(() => switchEbalka(bool, ip), 100);
return;
}
xhr.open("POST", "http://10.7.0.1:7777/me/ebalka");
xhr.setRequestHeader("Content-Type", "application/json");
var data = JSON.stringify({
"ebalka": bool,
"ip": ip
});
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
//isLoading = false;
if (xhr.status === 200) {
console.log("Success: Ebalka for " + ip + " changed to " + bool);
WorkerScript.sendMessage({ "action": "post_ebalka", "status": xhr.status, "ip": ip});
} else {
console.error("POST failed:", xhr.status);
WorkerScript.sendMessage({ "action": "post_ebalka", "status": xhr.status, "ip": ip});
}
}
}
xhr.send(data);
}
// POST switch ebalka
function renameDevice(ip, name) {
//isLoading = true;
let xhr = getXhr();
if (!xhr) {
console.log("Pool full, retrying...");
setTimeout(() => renameDevice(ip, name), 100);
return;
}
xhr.open("POST", "http://10.7.0.1:7777/me/device");
xhr.setRequestHeader("Content-Type", "application/json");
var data = JSON.stringify({
"ip": ip,
"name": name
});
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
//isLoading = false;
if (xhr.status === 200) {
console.log("Success: Name for " + ip + " changed to " + name);
WorkerScript.sendMessage({ "action": "post_name", "status": xhr.status, "ip": ip});
} else {
console.error("POST failed:", xhr.status);
WorkerScript.sendMessage({ "action": "post_name", "status": xhr.status, "ip": ip});
}
}
}
xhr.send(data);
}
// POST feature switch
function switchFeature(name, value) {
//isLoading = true;
let xhr = getXhr();
if (!xhr) {
console.log("Pool full, retrying...");
setTimeout(() => switchFeature(name, value), 100);
return;
}
xhr.open("POST", "http://10.7.0.1:7777/me/feature");
xhr.setRequestHeader("Content-Type", "application/json");
var data = JSON.stringify({
"name": name,
"value": value
});
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
//isLoading = false;
if (xhr.status === 200) {
console.log("Success: Feature " + name + " changed to " + value);
WorkerScript.sendMessage({ "action": "post_feature" });
} else {
console.error("POST failed:", xhr.status);
WorkerScript.sendMessage({ "action": "post_feature" });
}
}
}
xhr.send(data);
}
// POST connect by server id
function connectById(iface) {
//isLoading = true;
let xhr = getXhr();
if (!xhr) {
console.log("Pool full, retrying...");
setTimeout(() => connectById(iface), 100);
return;
}
xhr.open("POST", "http://10.7.0.1:7777/me/connect_by_id");
xhr.setRequestHeader("Content-Type", "application/json");
var data = JSON.stringify({
"iface": iface
});
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
//isLoading = false;
if (xhr.status === 200) {
console.log("Success: Changed to " + iface);
WorkerScript.sendMessage({ "action": "post_idconnect", "status": xhr.status});
} else {
console.error("POST failed:", xhr.status);
WorkerScript.sendMessage({ "action": "post_idconnect", "status": xhr.status});
}
}
}
xhr.send(data);
}
WorkerScript.onMessage = function(message) {
const actions = {
"fetch_routes": () => fetchRoutes(message),
"fetch_stats": () => fetchStats(message),
"fetch_profile": () => fetchProfile(message),
"post_country": () => selectCountry(message.code, message.provider),
"post_share": () => switchShare(message.bool),
"post_ebalka": () => switchEbalka(message.bool, message.ip),
"post_name": () => renameDevice(message.ip, message.name),
"post_feature": () => switchFeature(message.name, message.value),
"post_idconnect": () => connectById(message.iface),
"ping": () => keepAlivePing(message)
};
if (actions[message.action]) {
actions[message.action]();
}
}

View file

@ -0,0 +1,21 @@
{
"KPackageStructure": "Plasma/Applet",
"KPlugin": {
"Authors": [
{
"Email": "me@umorist47.ru",
"Name": "Umorist Kekovich"
}
],
"Category": "System",
"Description": "MeowRelay configurator plasmoid.",
"EnabledByDefault": true,
"Icon": "preferences-system-network-proxy",
"Id": "com.umorist47.meowrelaygui",
"Name": "MeowRelay",
"Version": "1.0",
"Website": "",
"License": "GPL3"
},
"X-Plasma-API-Minimum-Version": "6.0"
}