quickshell: use curl to fetch instead of XMLHttpRequest
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Services
|
||||
import qs.Utils
|
||||
pragma Singleton
|
||||
|
||||
@@ -14,44 +15,35 @@ Singleton {
|
||||
property string geoURLToken: ""
|
||||
|
||||
function fetchIP() {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.timeout = fetchTimeout * 1000;
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
if (xhr.status === 200) {
|
||||
try {
|
||||
const response = JSON.parse(xhr.responseText);
|
||||
if (response && response.ip) {
|
||||
let newIP = response.ip;
|
||||
Logger.log("IpService", "Fetched IP: " + newIP);
|
||||
if (newIP !== ip) {
|
||||
ip = newIP;
|
||||
fetchGeoInfo(); // Fetch geo info only if IP has changed
|
||||
}
|
||||
} else {
|
||||
ip = "N/A";
|
||||
countryCode = "N/A";
|
||||
Logger.error("IpService", "IP response does not contain 'ip' field");
|
||||
curl.fetch(ipURL, function(success, data) {
|
||||
if (success) {
|
||||
try {
|
||||
const response = JSON.parse(data);
|
||||
if (response && response.ip) {
|
||||
let newIP = response.ip;
|
||||
Logger.log("IpService", "Fetched IP: " + newIP);
|
||||
if (newIP !== ip) {
|
||||
ip = newIP;
|
||||
fetchGeoInfo(); // Fetch geo info only if IP has changed
|
||||
SendNotification.show("New IP", `IP: ${ip}\nCountry: ${countryCode}`);
|
||||
cacheFile.writeAdapter();
|
||||
}
|
||||
} catch (e) {
|
||||
} else {
|
||||
ip = "N/A";
|
||||
countryCode = "N/A";
|
||||
Logger.error("IpService", "Failed to parse IP response: " + e);
|
||||
Logger.error("IpService", "IP response does not contain 'ip' field");
|
||||
}
|
||||
} else {
|
||||
} catch (e) {
|
||||
ip = "N/A";
|
||||
countryCode = "N/A";
|
||||
Logger.error("IpService", "Failed to fetch IP, status: " + xhr.status);
|
||||
Logger.error("IpService", "Failed to parse IP response: " + e);
|
||||
}
|
||||
} else {
|
||||
ip = "N/A";
|
||||
countryCode = "N/A";
|
||||
Logger.error("IpService", "Failed to fetch IP");
|
||||
}
|
||||
};
|
||||
xhr.ontimeout = function() {
|
||||
ip = "N/A";
|
||||
countryCode = "N/A";
|
||||
Logger.error("IpService", "Fetch IP request timed out");
|
||||
};
|
||||
xhr.open("GET", ipURL);
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
function fetchGeoInfo() {
|
||||
@@ -59,47 +51,35 @@ Singleton {
|
||||
countryCode = "N/A";
|
||||
return ;
|
||||
}
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.timeout = fetchTimeout * 1000;
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
if (xhr.status === 200) {
|
||||
try {
|
||||
const response = JSON.parse(xhr.responseText);
|
||||
if (response && response.country_code) {
|
||||
let newCountryCode = response.country_code;
|
||||
Logger.log("IpService", "Fetched country code: " + newCountryCode);
|
||||
if (newCountryCode !== countryCode) {
|
||||
countryCode = newCountryCode;
|
||||
SendNotification.show("New IP", `IP: ${ip}\nCountry: ${newCountryCode}`);
|
||||
}
|
||||
} else {
|
||||
countryCode = "N/A";
|
||||
Logger.error("IpService", "Geo response does not contain 'country' field");
|
||||
}
|
||||
cacheFileAdapter.ip = ip;
|
||||
cacheFileAdapter.geoInfo = response;
|
||||
cacheFile.writeAdapter();
|
||||
} catch (e) {
|
||||
countryCode = "N/A";
|
||||
Logger.error("IpService", "Failed to parse geo response: " + e);
|
||||
}
|
||||
} else {
|
||||
countryCode = "N/A";
|
||||
Logger.error("IpService", "Failed to fetch geo info, status: " + xhr.status);
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.ontimeout = function() {
|
||||
countryCode = "N/A";
|
||||
Logger.error("IpService", "Fetch geo info request timed out");
|
||||
};
|
||||
let url = geoURL + ip;
|
||||
if (geoURLToken)
|
||||
url += "?token=" + geoURLToken;
|
||||
|
||||
xhr.open("GET", url);
|
||||
xhr.send();
|
||||
curl.fetch(url, function(success, data) {
|
||||
if (success) {
|
||||
try {
|
||||
const response = JSON.parse(data);
|
||||
if (response && response.country_code) {
|
||||
let newCountryCode = response.country_code;
|
||||
Logger.log("IpService", "Fetched country code: " + newCountryCode);
|
||||
if (newCountryCode !== countryCode)
|
||||
countryCode = newCountryCode;
|
||||
|
||||
} else {
|
||||
countryCode = "N/A";
|
||||
Logger.error("IpService", "Geo response does not contain 'country_code' field");
|
||||
}
|
||||
cacheFileAdapter.ip = ip;
|
||||
cacheFileAdapter.geoInfo = response;
|
||||
} catch (e) {
|
||||
countryCode = "N/A";
|
||||
Logger.error("IpService", "Failed to parse geo response: " + e);
|
||||
}
|
||||
} else {
|
||||
countryCode = "N/A";
|
||||
Logger.error("IpService", "Failed to fetch geo info");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
@@ -112,6 +92,10 @@ Singleton {
|
||||
Component.onCompleted: {
|
||||
}
|
||||
|
||||
NetworkFetch {
|
||||
id: curl
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: tokenFile
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Constants
|
||||
import qs.Services
|
||||
import qs.Utils
|
||||
pragma Singleton
|
||||
|
||||
@@ -96,57 +97,47 @@ Singleton {
|
||||
function _geocodeLocation(locationName, callback, errorCallback) {
|
||||
Logger.log("Location", "Geocoding location name");
|
||||
var geoUrl = "https://assets.noctalia.dev/geocode.php?city=" + encodeURIComponent(locationName) + "&language=en&format=json";
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
if (xhr.status === 200) {
|
||||
try {
|
||||
var geoData = JSON.parse(xhr.responseText);
|
||||
if (geoData.lat != null)
|
||||
callback(geoData.lat, geoData.lng, geoData.name, geoData.country);
|
||||
else
|
||||
errorCallback("Location", "could not resolve location name");
|
||||
} catch (e) {
|
||||
errorCallback("Location", "Failed to parse geocoding data: " + e);
|
||||
}
|
||||
} else {
|
||||
errorCallback("Location", "Geocoding error: " + xhr.status);
|
||||
curl.fetch(geoUrl, function(success, data) {
|
||||
if (success) {
|
||||
try {
|
||||
var geoData = JSON.parse(data);
|
||||
if (geoData.lat != null)
|
||||
callback(geoData.lat, geoData.lng, geoData.name, geoData.country);
|
||||
else
|
||||
errorCallback("Location", "could not resolve location name");
|
||||
} catch (e) {
|
||||
errorCallback("Location", "Failed to parse geocoding data: " + e);
|
||||
}
|
||||
} else {
|
||||
errorCallback("Location", "Geocoding error");
|
||||
}
|
||||
};
|
||||
xhr.open("GET", geoUrl);
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
// --------------------------------
|
||||
function _fetchWeather(latitude, longitude, errorCallback) {
|
||||
Logger.log("Location", "Fetching weather from api.open-meteo.com");
|
||||
var url = "https://api.open-meteo.com/v1/forecast?latitude=" + latitude + "&longitude=" + longitude + "¤t_weather=true¤t=relativehumidity_2m,surface_pressure&daily=temperature_2m_max,temperature_2m_min,weathercode&timezone=auto";
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
if (xhr.status === 200) {
|
||||
try {
|
||||
var weatherData = JSON.parse(xhr.responseText);
|
||||
// Save core data
|
||||
data.weather = weatherData;
|
||||
data.weatherLastFetch = Time.timestamp;
|
||||
// Update stable display values only when complete and successful
|
||||
root.stableLatitude = data.latitude = weatherData.latitude.toString();
|
||||
root.stableLongitude = data.longitude = weatherData.longitude.toString();
|
||||
root.coordinatesReady = true;
|
||||
isFetchingWeather = false;
|
||||
Logger.log("Location", "Cached weather to disk - stable coordinates updated");
|
||||
} catch (e) {
|
||||
errorCallback("Location", "Failed to parse weather data");
|
||||
}
|
||||
} else {
|
||||
errorCallback("Location", "Weather fetch error: " + xhr.status);
|
||||
curl.fetch(url, function(success, data) {
|
||||
if (success) {
|
||||
try {
|
||||
var weatherData = JSON.parse(data);
|
||||
// Save core data
|
||||
data.weather = weatherData;
|
||||
data.weatherLastFetch = Time.timestamp;
|
||||
// Update stable display values only when complete and successful
|
||||
root.stableLatitude = data.latitude = weatherData.latitude.toString();
|
||||
root.stableLongitude = data.longitude = weatherData.longitude.toString();
|
||||
root.coordinatesReady = true;
|
||||
isFetchingWeather = false;
|
||||
Logger.log("Location", "Cached weather to disk - stable coordinates updated");
|
||||
} catch (e) {
|
||||
errorCallback("Location", "Failed to parse weather data: " + e);
|
||||
}
|
||||
} else {
|
||||
errorCallback("Location", "Weather fetch error");
|
||||
}
|
||||
};
|
||||
xhr.open("GET", url);
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
// --------------------------------
|
||||
@@ -320,4 +311,8 @@ Singleton {
|
||||
onTriggered: locationFileView.writeAdapter()
|
||||
}
|
||||
|
||||
NetworkFetch {
|
||||
id: curl
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
66
quickshell/Services/NetworkFetch.qml
Normal file
66
quickshell/Services/NetworkFetch.qml
Normal file
@@ -0,0 +1,66 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Utils
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property real fetchTimeout: 10 // in seconds
|
||||
property string fetchedData: ""
|
||||
property var fetchingCallback: null
|
||||
|
||||
function fetch(url, callback) {
|
||||
if (curlProcess.running) {
|
||||
Logger.log("NetworkFetch", "A fetch operation is already in progress.");
|
||||
return ;
|
||||
}
|
||||
fetchedData = "";
|
||||
fetchingCallback = callback;
|
||||
curlProcess.command = ["curl", "-s", "-L", "-m", fetchTimeout.toString(), url];
|
||||
curlProcess.running = true;
|
||||
}
|
||||
|
||||
function fakeFetch(resp, callback) {
|
||||
if (curlProcess.running) {
|
||||
Logger.log("NetworkFetch", "A fetch operation is already in progress.");
|
||||
return ;
|
||||
}
|
||||
fetchedData = "";
|
||||
fetchingCallback = callback;
|
||||
curlProcess.command = ["echo", resp];
|
||||
curlProcess.running = true;
|
||||
}
|
||||
|
||||
Process {
|
||||
id: curlProcess
|
||||
|
||||
running: false
|
||||
onStarted: {
|
||||
Logger.log("NetworkFetch", "Process started with command: " + curlProcess.command.join(" "));
|
||||
}
|
||||
onExited: function(exitCode, exitStatus) {
|
||||
if (!fetchingCallback) {
|
||||
Logger.error("NetworkFetch", "No callback defined for fetch operation.");
|
||||
return ;
|
||||
}
|
||||
if (exitCode === 0) {
|
||||
Logger.log("NetworkFetch", "Fetch completed successfully.");
|
||||
Logger.log("NetworkFetch", "Fetched data: " + fetchedData);
|
||||
fetchingCallback(true, fetchedData);
|
||||
} else {
|
||||
Logger.error("NetworkFetch", "Fetch failed with exit code: " + exitCode);
|
||||
fetchingCallback(false, "");
|
||||
}
|
||||
}
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: ""
|
||||
onRead: (data) => {
|
||||
fetchedData += data;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user