Make sentry report anonymous unique user ids so we can count release adoption

This commit is contained in:
loucass003
2025-12-08 04:27:49 +01:00
parent 176f7e4271
commit 2a19d67974
6 changed files with 96 additions and 57 deletions

View File

@@ -12,7 +12,7 @@
"@react-hookz/deep-equal": "^3.0.3",
"@react-three/drei": "^9.114.3",
"@react-three/fiber": "^8.17.10",
"@sentry/react": "^9.9.0",
"@sentry/react": "^10.29.0",
"@sentry/vite-plugin": "^2.22.7",
"@tailwindcss/typography": "^0.5.15",
"@tanstack/react-query": "^5.48.0",

10
gui/src/hooks/crypto.ts Normal file
View File

@@ -0,0 +1,10 @@
export function hash(str: string) {
let hash = 2166136261;
for (let i = 0; i < str.length; i++) {
hash ^= str.charCodeAt(i);
hash = Math.imul(hash, 16777619); // FNV prime
}
// Convert to unsigned 32-bit integer and normalize (0, 1)
return (hash >>> 0) / 2 ** 32;
};

View File

@@ -3,6 +3,8 @@ import { fetch as tauriFetch } from '@tauri-apps/plugin-http';
import { cacheWrap } from './cache';
import semver from 'semver';
import { hostname, locale, platform, version } from '@tauri-apps/plugin-os';
import { hash } from './crypto';
import { getUserID } from './user';
export interface FirmwareRelease {
name: string;
@@ -12,18 +14,6 @@ export interface FirmwareRelease {
userCanUpdate: boolean;
}
// implemetation of https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
const hash = (str: string) => {
let hash = 2166136261;
for (let i = 0; i < str.length; i++) {
hash ^= str.charCodeAt(i);
hash = Math.imul(hash, 16777619); // FNV prime
}
// Convert to unsigned 32-bit integer and normalize (0, 1)
return (hash >>> 0) / 2 ** 32;
};
const firstAsset = (assets: any[], name: string) =>
assets.find((asset: any) => asset.name === name && asset.browser_download_url);
@@ -67,7 +57,7 @@ const checkUserCanUpdate = async (url: string, fwVersion: string) => {
const todayUpdateRange = todaysRange(deployData);
if (!todayUpdateRange) return false;
const uniqueUserKey = `${await hostname()}-${await locale()}-${platform()}-${version()}`;
const uniqueUserKey = await getUserID();
// Make it so the hash change every version. Prevent the same user from getting the same delay
return hash(`${uniqueUserKey}-${fwVersion}`) <= todayUpdateRange;
};

9
gui/src/hooks/user.ts Normal file
View File

@@ -0,0 +1,9 @@
import { locale } from '@tauri-apps/plugin-os';
import { hostname, platform, version } from 'os';
import { hash } from './crypto';
export async function getUserID() {
// FIXME: This does not support android. It currently return the same id for all android users
return hash(`${hostname()}-${await locale()}-${platform()}-${version()}`);
}

View File

@@ -8,6 +8,7 @@ import {
useNavigationType,
} from 'react-router-dom';
import { DeviceDataT } from 'solarxr-protocol';
import { getUserID } from '@/hooks/user';
export function getSentryOrCompute(enabled = false) {
// if sentry is already initialized - SKIP
@@ -62,6 +63,10 @@ export function getSentryOrCompute(enabled = false) {
log('Initialized the Sentry client');
}
getUserID().then((id) => {
Sentry.setUser({ id })
})
return newClient;
}

111
pnpm-lock.yaml generated
View File

@@ -42,8 +42,8 @@ importers:
specifier: ^8.17.10
version: 8.17.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0)
'@sentry/react':
specifier: ^9.9.0
version: 9.9.0(react@18.3.1)
specifier: ^10.29.0
version: 10.29.0(react@18.3.1)
'@sentry/vite-plugin':
specifier: ^2.22.7
version: 2.22.7
@@ -759,6 +759,9 @@ packages:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
'@jridgewell/gen-mapping@0.3.13':
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
'@jridgewell/gen-mapping@0.3.5':
resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
engines: {node: '>=6.0.0'}
@@ -771,15 +774,21 @@ packages:
resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
engines: {node: '>=6.0.0'}
'@jridgewell/source-map@0.3.6':
resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==}
'@jridgewell/source-map@0.3.11':
resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==}
'@jridgewell/sourcemap-codec@1.4.15':
resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
'@jridgewell/sourcemap-codec@1.5.5':
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
'@jridgewell/trace-mapping@0.3.25':
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
'@mediapipe/tasks-vision@0.10.8':
resolution: {integrity: sha512-Rp7ll8BHrKB3wXaRFKhrltwZl1CiXGdibPxuWXvqGnKTnv8fqa/nvftYNuSbf+pbJWKYCXdBtYTITdAUTGGh0Q==}
@@ -901,7 +910,7 @@ packages:
'@react-hookz/deep-equal@3.0.3':
resolution: {integrity: sha512-SLy+NmiDpncqc2d9TR4Y4R7f8lUFOQK9WbnIq02A6wDxy+dTHfA2Np0dPvj0SFp6i1nqERLmEUe9MxPLuO/IqA==}
engines: {node: '>=18.0.0'}
deprecated: Package is deprecated and will be deleted soon. Use @ver0/deep-equal instead.
deprecated: PACKAGE IS DEPRECATED AND WILL BE DETED SOON, USE @ver0/deep-equal INSTEAD
'@react-spring/animated@9.6.1':
resolution: {integrity: sha512-ls/rJBrAqiAYozjLo5EPPLLOb1LM0lNVQcXODTC1SMtS6DbuBCPaKco5svFUQFMP2dso3O+qcC4k9FsKc0KxMQ==}
@@ -1054,28 +1063,28 @@ packages:
'@rtsao/scc@1.1.0':
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
'@sentry-internal/browser-utils@9.9.0':
resolution: {integrity: sha512-V/YhKLis98JFkqBGZaEBlDNFpJHJjoCvNb05raAYXdITfDIl37Kxqj0zX+IzyRhqnswkQ+DBTyoEoci09IR2bQ==}
'@sentry-internal/browser-utils@10.29.0':
resolution: {integrity: sha512-M3kycMY6f3KY9a8jDYac+yG0E3ZgWVWSxlOEC5MhYyX+g7mqxkwrb3LFQyuxSm/m+CCgMTCaPOOaB2twXP6EQg==}
engines: {node: '>=18'}
'@sentry-internal/feedback@9.9.0':
resolution: {integrity: sha512-hrxuOLm0Xsnx75hTNt3eLgNNjER3egrHZShdRzlMiakfKpA9f2X10z75vlZmT5ZUygDQnp9UVUnu28cDuVb9Zw==}
'@sentry-internal/feedback@10.29.0':
resolution: {integrity: sha512-Y7IRsNeS99cEONu1mZWZc3HvbjNnu59Hgymm0swFFKbdgbCgdT6l85kn2oLsuq4Ew8Dw/pL/Sgpwsl9UgYFpUg==}
engines: {node: '>=18'}
'@sentry-internal/replay-canvas@9.9.0':
resolution: {integrity: sha512-YK0ixGjquahGpNsQskCEVwycdHlwNBLCx9XJr1BmGnlOw6fUCmpyVetaGg/ZyhkzKGNXAGoTa4s7FUFnAG4bKg==}
'@sentry-internal/replay-canvas@10.29.0':
resolution: {integrity: sha512-typY4JrpAQQGPuSyd/BD8+nNCbvTV2UVvKzr+iKgI0m1qc4Dz8tHZ4Nfais2Z8eYn/pL1kqVQN5ERTmJoYFdIw==}
engines: {node: '>=18'}
'@sentry-internal/replay@9.9.0':
resolution: {integrity: sha512-EWczKMu3qiZ0SUUWU3zkGod+AWD/VQCLiQw+tw+PEpdHbRZIdYKsEptengZCFKthrwe2QmYpVCTSRxGvujJ/6g==}
'@sentry-internal/replay@10.29.0':
resolution: {integrity: sha512-45NVw9PwB9TQ8z+xJ6G6Za+wmQ1RTA35heBSzR6U4bknj8LmA04k2iwnobvxCBEQXeLfcJEO1vFgagMoqMZMBw==}
engines: {node: '>=18'}
'@sentry/babel-plugin-component-annotate@2.22.7':
resolution: {integrity: sha512-aa7XKgZMVl6l04NY+3X7BP7yvQ/s8scn8KzQfTLrGRarziTlMGrsCOBQtCNWXOPEbtxAIHpZ9dsrAn5EJSivOQ==}
engines: {node: '>= 14'}
'@sentry/browser@9.9.0':
resolution: {integrity: sha512-pIMdkOC+iggZefBs6ck5fL1mBhbLzjdw/8K99iqSeDh+lLvmlHVZajAhPlmw50xfH8CyQ1s22dhcL+zXbg3NKw==}
'@sentry/browser@10.29.0':
resolution: {integrity: sha512-XdbyIR6F4qoR9Z1JCWTgunVcTJjS9p2Th+v4wYs4ME+ZdLC4tuKKmRgYg3YdSIWCn1CBfIgdI6wqETSf7H6Njw==}
engines: {node: '>=18'}
'@sentry/bundler-plugin-core@2.22.7':
@@ -1128,12 +1137,12 @@ packages:
engines: {node: '>= 10'}
hasBin: true
'@sentry/core@9.9.0':
resolution: {integrity: sha512-GxKvx8PSgoWhLLS+/WBGIXy7rsFcnJBPDqFXIfcAGy89k2j06d9IP0kiIc63qBGStSUkh5FFJLPTakZ5RXiFXA==}
'@sentry/core@10.29.0':
resolution: {integrity: sha512-olQ2DU9dA/Bwsz3PtA9KNXRMqBWRQSkPw+MxwWEoU1K1qtiM9L0j6lbEFb5iSY3d7WYD5MB+1d5COugjSBrHtw==}
engines: {node: '>=18'}
'@sentry/react@9.9.0':
resolution: {integrity: sha512-7BE2Lx5CNtHtlNSS7Z9HxKquohC0xhdFceO3NlMXlx+dZuVCMoQmLISB8SQEcHw+2VO24MvtP3LPEzdeNbkIfg==}
'@sentry/react@10.29.0':
resolution: {integrity: sha512-YGaEUXubzil7qssD1koh1fyt0aS8tHB61/6+oNShJ6xZPg03AB42bNMr2/y8fIFx36kb3MiCA5sFoH/ubF0LnQ==}
engines: {node: '>=18'}
peerDependencies:
react: ^16.14.0 || 17.x || 18.x || 19.x
@@ -2759,6 +2768,7 @@ packages:
got-fetch@5.1.10:
resolution: {integrity: sha512-Gwj/A2htjvLEcY07PKDItv0WCPEs3dV2vWeZ+9TVBSKSTuWEZ4oXaMD0ZAOsajwx2orahQWN4HI0MfRyWSZsbg==}
engines: {node: '>=14.0.0'}
deprecated: please use built-in fetch in nodejs
peerDependencies:
got: ^12.0.0
@@ -5448,6 +5458,12 @@ snapshots:
wrap-ansi: 8.1.0
wrap-ansi-cjs: wrap-ansi@7.0.0
'@jridgewell/gen-mapping@0.3.13':
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
'@jridgewell/trace-mapping': 0.3.31
optional: true
'@jridgewell/gen-mapping@0.3.5':
dependencies:
'@jridgewell/set-array': 1.2.1
@@ -5458,19 +5474,28 @@ snapshots:
'@jridgewell/set-array@1.2.1': {}
'@jridgewell/source-map@0.3.6':
'@jridgewell/source-map@0.3.11':
dependencies:
'@jridgewell/gen-mapping': 0.3.5
'@jridgewell/trace-mapping': 0.3.25
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
optional: true
'@jridgewell/sourcemap-codec@1.4.15': {}
'@jridgewell/sourcemap-codec@1.5.5':
optional: true
'@jridgewell/trace-mapping@0.3.25':
dependencies:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.4.15
'@jridgewell/trace-mapping@0.3.31':
dependencies:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
optional: true
'@mediapipe/tasks-vision@0.10.8': {}
'@mgit-at/typescript-flatbuffers-codegen@0.1.3':
@@ -5755,33 +5780,33 @@ snapshots:
'@rtsao/scc@1.1.0': {}
'@sentry-internal/browser-utils@9.9.0':
'@sentry-internal/browser-utils@10.29.0':
dependencies:
'@sentry/core': 9.9.0
'@sentry/core': 10.29.0
'@sentry-internal/feedback@9.9.0':
'@sentry-internal/feedback@10.29.0':
dependencies:
'@sentry/core': 9.9.0
'@sentry/core': 10.29.0
'@sentry-internal/replay-canvas@9.9.0':
'@sentry-internal/replay-canvas@10.29.0':
dependencies:
'@sentry-internal/replay': 9.9.0
'@sentry/core': 9.9.0
'@sentry-internal/replay': 10.29.0
'@sentry/core': 10.29.0
'@sentry-internal/replay@9.9.0':
'@sentry-internal/replay@10.29.0':
dependencies:
'@sentry-internal/browser-utils': 9.9.0
'@sentry/core': 9.9.0
'@sentry-internal/browser-utils': 10.29.0
'@sentry/core': 10.29.0
'@sentry/babel-plugin-component-annotate@2.22.7': {}
'@sentry/browser@9.9.0':
'@sentry/browser@10.29.0':
dependencies:
'@sentry-internal/browser-utils': 9.9.0
'@sentry-internal/feedback': 9.9.0
'@sentry-internal/replay': 9.9.0
'@sentry-internal/replay-canvas': 9.9.0
'@sentry/core': 9.9.0
'@sentry-internal/browser-utils': 10.29.0
'@sentry-internal/feedback': 10.29.0
'@sentry-internal/replay': 10.29.0
'@sentry-internal/replay-canvas': 10.29.0
'@sentry/core': 10.29.0
'@sentry/bundler-plugin-core@2.22.7':
dependencies:
@@ -5837,12 +5862,12 @@ snapshots:
- encoding
- supports-color
'@sentry/core@9.9.0': {}
'@sentry/core@10.29.0': {}
'@sentry/react@9.9.0(react@18.3.1)':
'@sentry/react@10.29.0(react@18.3.1)':
dependencies:
'@sentry/browser': 9.9.0
'@sentry/core': 9.9.0
'@sentry/browser': 10.29.0
'@sentry/core': 10.29.0
hoist-non-react-statics: 3.3.2
react: 18.3.1
@@ -9774,7 +9799,7 @@ snapshots:
terser@5.31.1:
dependencies:
'@jridgewell/source-map': 0.3.6
'@jridgewell/source-map': 0.3.11
acorn: 8.15.0
commander: 2.20.3
source-map-support: 0.5.21