Skip to content

Commit 089fc82

Browse files
authored
Merge pull request #73 from Sportinger/tray-log-ui-master
feat: add tray live log and visitor grouping
2 parents 01d5847 + e290bb1 commit 089fc82

5 files changed

Lines changed: 636 additions & 142 deletions

File tree

functions/_middleware.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,32 @@ interface VisitEntry {
3939
city?: string;
4040
ua?: string;
4141
referer?: string;
42+
visitorId?: string;
4243
}
4344

4445
function buildVisitKey(ts: number): string {
4546
const newestFirst = String(9_999_999_999_999 - ts).padStart(13, '0');
4647
return `visit2:${newestFirst}:${ts}:${crypto.randomUUID().slice(0, 8)}`;
4748
}
4849

50+
async function buildVisitorId(request: Request, secret?: string): Promise<string | undefined> {
51+
const ip = request.headers.get('cf-connecting-ip')?.trim();
52+
if (!ip || !secret) {
53+
return undefined;
54+
}
55+
56+
const payload = new TextEncoder().encode(`${secret}:${ip}`);
57+
const digest = await crypto.subtle.digest('SHA-256', payload);
58+
const bytes = Array.from(new Uint8Array(digest));
59+
return bytes.map((byte) => byte.toString(16).padStart(2, '0')).join('').slice(0, 16);
60+
}
61+
4962
async function trackVisit(context: AppContext): Promise<void> {
5063
try {
5164
const request = context.request;
5265
const url = new URL(request.url);
5366
const cfData = (request as unknown as { cf?: Record<string, string> }).cf;
67+
const visitorId = await buildVisitorId(request, context.env.VISITOR_NOTIFY_SECRET);
5468

5569
const entry: VisitEntry = {
5670
ts: Date.now(),
@@ -59,6 +73,7 @@ async function trackVisit(context: AppContext): Promise<void> {
5973
city: cfData?.city,
6074
ua: (request.headers.get('user-agent') ?? '').slice(0, 200),
6175
referer: request.headers.get('referer') ?? undefined,
76+
visitorId,
6277
};
6378

6479
// Store newest-first keys so polling clients can read the latest visits efficiently.

functions/api/visits.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ interface VisitEntry {
88
city?: string;
99
ua?: string;
1010
referer?: string;
11+
visitorId?: string;
1112
}
1213

1314
interface ListedVisitKey {
@@ -42,6 +43,7 @@ async function loadVisitEntry(context: AppContext, key: ListedVisitKey): Promise
4243
referer: metadata.referer,
4344
ts: metadata.ts,
4445
ua: metadata.ua,
46+
visitorId: metadata.visitorId,
4547
};
4648
}
4749
}

tools/visitor-tray/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ ALERT_SECONDS=10
66
ENABLE_SOUND=true
77
ENABLE_BALLOON=true
88
OPEN_SITE_ON_BALLOON_CLICK=true
9+
HISTORY_LIMIT=200

tools/visitor-tray/README.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ The script loads config in this order:
2828

2929
Later sources override earlier ones.
3030

31+
Optional config:
32+
33+
- `HISTORY_LIMIT`: how many recent visits should be kept in the live log window. Default: `200`
34+
3135
## Required Cloudflare Secret
3236

3337
The tray app reads from `/api/visits`, which requires `VISITOR_NOTIFY_SECRET`.
@@ -64,18 +68,18 @@ Remove autostart:
6468
powershell -ExecutionPolicy Bypass -File tools\visitor-tray\Uninstall-Startup.ps1
6569
```
6670

67-
## Tray Menu
71+
## Tray UI
6872

69-
- Open MasterSelects
70-
- Poll now
71-
- Pause / Resume polling
72-
- Exit
73+
- Right-click the tray icon to open the live log window.
74+
- The live log shows recent visits in a scrollable list.
75+
- Repeated hits from the same tracked visitor are grouped into expandable rows when a stable visitor id is available.
76+
- Double-click the tray icon still opens MasterSelects in the browser.
7377

7478
On a new visit the app:
7579

7680
- plays a Windows notification sound
7781
- switches the tray icon to a warning icon for a few seconds
78-
- shows a balloon notification
82+
- shows a balloon notification with the country flag when available
7983

8084
Clicking the balloon opens the latest visited path on the site.
8185

0 commit comments

Comments
 (0)