mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
157 lines
4.2 KiB
QML
157 lines
4.2 KiB
QML
pragma Singleton
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
import qs.Commons
|
|
import qs.Services.Compositor
|
|
import qs.Services.Noctalia
|
|
import qs.Services.System
|
|
|
|
Singleton {
|
|
id: root
|
|
|
|
property bool initialized: false
|
|
property bool isSending: false
|
|
property int totalRamGb: 0
|
|
property string instanceId: ""
|
|
|
|
readonly property string telemetryEndpoint: Quickshell.env("NOCTALIA_TELEMETRY_ENDPOINT") || "https://api.noctalia.dev/ping"
|
|
|
|
function init() {
|
|
if (initialized)
|
|
return;
|
|
|
|
initialized = true;
|
|
|
|
if (!Settings.data.general.telemetryEnabled) {
|
|
Logger.d("Telemetry", "Telemetry disabled by user");
|
|
return;
|
|
}
|
|
|
|
// Get or generate instance ID from ShellState
|
|
instanceId = ShellState.getTelemetryInstanceId();
|
|
if (!instanceId) {
|
|
instanceId = generateRandomId();
|
|
ShellState.setTelemetryInstanceId(instanceId);
|
|
Logger.d("Telemetry", "Generated new random instance ID");
|
|
} else {
|
|
Logger.d("Telemetry", "Using stored instance ID");
|
|
}
|
|
|
|
// Read RAM info, then send ping
|
|
memInfoProcess.running = true;
|
|
}
|
|
|
|
function generateRandomId() {
|
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
const r = Math.random() * 16 | 0;
|
|
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
return v.toString(16);
|
|
});
|
|
}
|
|
|
|
function getInstanceId() {
|
|
return instanceId;
|
|
}
|
|
|
|
Process {
|
|
id: memInfoProcess
|
|
command: ["sh", "-c", "grep MemTotal /proc/meminfo | awk '{print int($2/1048576)}'"]
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
const ramGb = parseInt(text.trim()) || 0;
|
|
root.totalRamGb = ramGb;
|
|
root.sendPing();
|
|
}
|
|
}
|
|
|
|
onExited: function (exitCode) {
|
|
if (exitCode !== 0) {
|
|
// Still send ping even if RAM detection fails
|
|
root.sendPing();
|
|
}
|
|
}
|
|
}
|
|
|
|
function sendPing() {
|
|
if (isSending)
|
|
return;
|
|
|
|
isSending = true;
|
|
|
|
const payload = {
|
|
instanceId: instanceId,
|
|
version: UpdateService.currentVersion,
|
|
compositor: getCompositorType(),
|
|
os: HostService.osPretty || "Unknown",
|
|
ramGb: totalRamGb,
|
|
monitors: getMonitorInfo(),
|
|
ui: {
|
|
scaleRatio: Settings.data.general.scaleRatio,
|
|
fontDefaultScale: Settings.data.ui.fontDefaultScale,
|
|
fontFixedScale: Settings.data.ui.fontFixedScale
|
|
}
|
|
};
|
|
|
|
Logger.d("Telemetry", "Sending anonymous ping:", JSON.stringify(payload));
|
|
|
|
const request = new XMLHttpRequest();
|
|
request.onreadystatechange = function () {
|
|
if (request.readyState === XMLHttpRequest.DONE) {
|
|
if (request.status >= 200 && request.status < 300) {
|
|
Logger.d("Telemetry", "Ping sent successfully");
|
|
} else {
|
|
Logger.d("Telemetry", "Ping failed with status:", request.status);
|
|
}
|
|
isSending = false;
|
|
}
|
|
};
|
|
|
|
request.open("POST", telemetryEndpoint);
|
|
request.setRequestHeader("Content-Type", "application/json");
|
|
request.send(JSON.stringify(payload));
|
|
}
|
|
|
|
function getMonitorInfo() {
|
|
const monitors = [];
|
|
const screens = Quickshell.screens || [];
|
|
const scales = CompositorService.displayScales || {};
|
|
|
|
for (let i = 0; i < screens.length; i++) {
|
|
const screen = screens[i];
|
|
const name = screen.name || "Unknown";
|
|
const scaleData = scales[name];
|
|
// Extract just the numeric scale value
|
|
const scaleValue = (typeof scaleData === "object" && scaleData !== null) ? (scaleData.scale || 1.0) : (scaleData || 1.0);
|
|
monitors.push({
|
|
width: screen.width || 0,
|
|
height: screen.height || 0,
|
|
scale: scaleValue
|
|
});
|
|
}
|
|
|
|
return monitors;
|
|
}
|
|
|
|
function getCompositorType() {
|
|
if (CompositorService.isHyprland)
|
|
return "Hyprland";
|
|
if (CompositorService.isNiri)
|
|
return "Niri";
|
|
if (CompositorService.isScroll)
|
|
return "Scroll";
|
|
if (CompositorService.isSway)
|
|
return "Sway";
|
|
if (CompositorService.isMango)
|
|
return "MangoWC";
|
|
if (CompositorService.isLabwc)
|
|
return "LabWC";
|
|
if (CompositorService.isExtWorkspace)
|
|
return "ExtWorkspace";
|
|
return "Unknown";
|
|
}
|
|
}
|