mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-03-30 12:25:40 +00:00
Compare commits
14 Commits
refactor/m
...
fix/update
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e5516c282 | ||
|
|
206d9bd64a | ||
|
|
3f54632b07 | ||
|
|
609b12541e | ||
|
|
4369e58a3c | ||
|
|
8ef321bf70 | ||
|
|
bee705d5d8 | ||
|
|
cedf79ff83 | ||
|
|
9944d50e76 | ||
|
|
9b2ad91512 | ||
|
|
6740e53c18 | ||
|
|
d538d2f3e7 | ||
|
|
1453fb6492 | ||
|
|
5cc6064e11 |
26
.github/workflows/deploy.yml
vendored
26
.github/workflows/deploy.yml
vendored
@@ -17,7 +17,7 @@ on:
|
||||
- 'docs/**'
|
||||
|
||||
concurrency:
|
||||
group: deploy
|
||||
group: deploy-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
@@ -41,10 +41,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Go 1.22
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.22'
|
||||
cache-dependency-path: |
|
||||
@@ -124,7 +124,7 @@ jobs:
|
||||
|
||||
- name: Upload Go coverage badges
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: go-badges
|
||||
path: .badges/go-*.json
|
||||
@@ -139,12 +139,12 @@ jobs:
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: Set up Node.js 22
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '22'
|
||||
|
||||
@@ -265,7 +265,7 @@ jobs:
|
||||
|
||||
- name: Upload Node.js test badges
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: node-badges
|
||||
path: .badges/
|
||||
@@ -282,10 +282,10 @@ jobs:
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Node.js 22
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '22'
|
||||
|
||||
@@ -307,7 +307,7 @@ jobs:
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Start staging on port 82
|
||||
run: |
|
||||
@@ -352,18 +352,18 @@ jobs:
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Download Go coverage badges
|
||||
continue-on-error: true
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: go-badges
|
||||
path: .badges/
|
||||
|
||||
- name: Download Node.js test badges
|
||||
continue-on-error: true
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: node-badges
|
||||
path: .badges/
|
||||
|
||||
144
RELEASE-v3.1.0.md
Normal file
144
RELEASE-v3.1.0.md
Normal file
@@ -0,0 +1,144 @@
|
||||
# v3.1.0 — Now It's CoreScope
|
||||
|
||||
MeshCore Analyzer has a new name: **CoreScope**. Same mesh analysis you rely on, sharper identity, and a boatload of fixes and performance wins since v3.0.0.
|
||||
|
||||
48 commits, 30+ issues closed. Here's what changed.
|
||||
|
||||
---
|
||||
|
||||
## 🏷️ Renamed to CoreScope
|
||||
|
||||
The project is now **CoreScope** — frontend, backend, Docker images, manage.sh, docs, CI — everything has been updated. The URL, the API, the database, and your config all stay the same. Just a better name for the tool the community built.
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Performance
|
||||
|
||||
| What | Before | After |
|
||||
|------|--------|-------|
|
||||
| Subpath analytics | 900 ms | **5 ms** (precomputed at ingest) |
|
||||
| Distance analytics | 1.2 s | **15 ms** (precomputed at ingest) |
|
||||
| Packet ingest (prepend) | O(n) slice copy | **O(1) append** |
|
||||
| Go runtime stats | GC stop-the-world on every call | **cached ReadMemStats** |
|
||||
| All analytics endpoints | computed per-request | **TTL-cached** |
|
||||
|
||||
The in-memory store now precomputes subpaths and distance data as packets arrive, eliminating expensive full-table scans on the analytics endpoints. The O(n) slice prepend on every ingest — the single hottest line in the server — is gone. `ReadMemStats` calls are cached to prevent GC pause spikes under load.
|
||||
|
||||
---
|
||||
|
||||
## 🆕 New Features
|
||||
|
||||
### Telemetry Decode
|
||||
Sensor nodes now report **battery voltage** and **temperature** parsed from advert payloads. Telemetry is gated on the sensor flag — only real sensors emit data, and 0°C is no longer falsely reported. Safe migration with `PRAGMA` column checks.
|
||||
|
||||
### Channel Decryption for Custom Channels
|
||||
The `hashChannels` config now works in the Go ingestor. Key derivation has been ported from Node.js with full AES-128-ECB support and garbage text detection — wrong keys silently fail instead of producing garbled output.
|
||||
|
||||
### Node Pruning
|
||||
Stale nodes are automatically moved to an `inactive_nodes` table after the configurable retention window. Pruning runs hourly. Your active node list stays clean. (#202)
|
||||
|
||||
### Duplicate Node Name Badges
|
||||
Nodes with the same display name but different public keys are flagged with a badge so you can spot collisions instantly.
|
||||
|
||||
### Sortable Channels Table
|
||||
Channel columns are now sortable with click-to-sort headers. Sort preferences persist in `localStorage` across sessions. (#167)
|
||||
|
||||
### Go Runtime Metrics
|
||||
The performance page exposes goroutine count, heap allocation, GC pause percentiles, and memory breakdown when connected to a Go backend.
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Bug Fixes
|
||||
|
||||
- **Channel decryption regression** (#176) — full AES-128-ECB in Go, garbage text detection, hashChannels key derivation ported correctly (#218)
|
||||
- **Packets page not live-updating** (#172) — WebSocket broadcast now includes the nested packet object and timestamp fields the frontend expects; multiple fixes across broadcast and render paths
|
||||
- **Node detail page crashes** (#190) — `Number()` casts and `Array.isArray` guards prevent rendering errors on unexpected data shapes
|
||||
- **Observation count staleness** (#174) — trace page and packet detail now show correct observation counts
|
||||
- **Phantom node cleanup** (#133) — `autoLearnHopNodes` no longer creates fake nodes from 1-byte repeater IDs
|
||||
- **Advert count inflation** (#200) — counts unique transmissions, not total observations (8 observers × 1 advert = 1, not 8)
|
||||
- **SQLite BUSY contention** (#214) — `MaxOpenConns(1)` + `MaxIdleConns(1)` serializes writes; load-tested under concurrent ingest
|
||||
- **Decoder bounds check** (#183) — corrupt/malformed packets no longer crash the decoder with buffer overruns
|
||||
- **noise_floor / battery_mv type mismatches** — consistent `float64` scanning handles SQLite REAL values correctly
|
||||
- **packetsLastHour always zero** (#182) — early `break` in observer loop prevented counting
|
||||
- **Channels stale messages** (#171) — latest message sorted by observation timestamp, not first-seen
|
||||
- **pprof port conflict** — non-fatal bind with separate ports prevents Go server crash on startup
|
||||
|
||||
---
|
||||
|
||||
## ♿ Accessibility & 📱 Mobile
|
||||
|
||||
### WCAG AA Compliance (10 fixes)
|
||||
- Search results keyboard-accessible with `tabindex`, `role`, and arrow-key navigation (#208)
|
||||
- 40+ table headers given `scope` attributes (#211)
|
||||
- 9 Chart.js canvases given accessible names (#210)
|
||||
- Form inputs in customizer/filters paired with labels (#212)
|
||||
|
||||
### Mobile Responsive
|
||||
- **Live page**: bottom-sheet panel instead of full-screen overlay (#203)
|
||||
- **Perf page**: responsive layout with stacked cards (#204)
|
||||
- **Nodes table**: column hiding at narrow viewports (#205)
|
||||
- **Analytics/Compare**: horizontal scroll wrappers (#206)
|
||||
- **VCR bar**: 44px minimum touch targets (#207)
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Infrastructure
|
||||
|
||||
### manage.sh Refactored (#230)
|
||||
`manage.sh` is now a thin wrapper around `docker compose` — no custom container management, no divergent logic. It reads `.env` for data paths, matching how `docker-compose.yml` works. One source of truth.
|
||||
|
||||
### .env Support
|
||||
Data directory, ports, and image tags are configured via `.env`. Both `docker compose` and `manage.sh` read the same file.
|
||||
|
||||
### Branch Protection & CI on PRs
|
||||
- Branch protection enabled on `master` — CI must pass, PRs required
|
||||
- CI now triggers on `pull_request`, not just `push` — catch failures before merge (#199)
|
||||
|
||||
### Protobuf API Contract
|
||||
10 `.proto` files, 33 golden fixtures, CI validation on every push. API shape drift is caught automatically.
|
||||
|
||||
### pprof Profiling
|
||||
Controlled by `ENABLE_PPROF` env var. When enabled, exposes Go profiling endpoints on separate ports — zero overhead when off.
|
||||
|
||||
### Test Coverage
|
||||
- Go backend: **92%+** coverage
|
||||
- **49 Playwright E2E tests**
|
||||
- Both tracks gate deploy in CI
|
||||
|
||||
---
|
||||
|
||||
## 📦 Upgrading
|
||||
|
||||
```bash
|
||||
git pull
|
||||
./manage.sh stop
|
||||
./manage.sh setup
|
||||
```
|
||||
|
||||
That's it. Your existing `config.json` and database work as-is. The rename is cosmetic — no schema changes, no API changes, no config changes.
|
||||
|
||||
### Verify
|
||||
|
||||
```bash
|
||||
curl -s http://localhost/api/health | grep engine
|
||||
# "engine": "go"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Breaking Changes
|
||||
|
||||
**None.** All API endpoints, WebSocket messages, and config options are backwards-compatible. The rename affects branding only — Docker image names, page titles, and documentation.
|
||||
|
||||
---
|
||||
|
||||
## 🙏 Thank You
|
||||
|
||||
- **efiten** — PR #222 performance fix (O(n) slice prepend elimination)
|
||||
- **jade-on-mesh**, **lincomatic**, **LitBomb**, **mibzzer15** — ongoing testing, feedback, and issue reports
|
||||
|
||||
And to everyone running CoreScope on their mesh networks — your real-world data drives every fix and feature in this release. 48 commits since v3.0.0, and every one of them came from something the community found, reported, or requested.
|
||||
|
||||
---
|
||||
|
||||
*Previous release: [v3.0.0](RELEASE-v3.0.0.md)*
|
||||
@@ -33,6 +33,11 @@ type Server struct {
|
||||
memStatsMu sync.Mutex
|
||||
memStatsCache runtime.MemStats
|
||||
memStatsCachedAt time.Time
|
||||
|
||||
// Cached /api/stats response — recomputed at most once every 10s
|
||||
statsMu sync.Mutex
|
||||
statsCache *StatsResponse
|
||||
statsCachedAt time.Time
|
||||
}
|
||||
|
||||
// PerfStats tracks request performance.
|
||||
@@ -380,6 +385,17 @@ func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (s *Server) handleStats(w http.ResponseWriter, r *http.Request) {
|
||||
const statsTTL = 10 * time.Second
|
||||
|
||||
s.statsMu.Lock()
|
||||
if s.statsCache != nil && time.Since(s.statsCachedAt) < statsTTL {
|
||||
cached := s.statsCache
|
||||
s.statsMu.Unlock()
|
||||
writeJSON(w, cached)
|
||||
return
|
||||
}
|
||||
s.statsMu.Unlock()
|
||||
|
||||
var stats *Stats
|
||||
var err error
|
||||
if s.store != nil {
|
||||
@@ -392,7 +408,7 @@ func (s *Server) handleStats(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
counts := s.db.GetRoleCounts()
|
||||
writeJSON(w, StatsResponse{
|
||||
resp := &StatsResponse{
|
||||
TotalPackets: stats.TotalPackets,
|
||||
TotalTransmissions: &stats.TotalTransmissions,
|
||||
TotalObservations: stats.TotalObservations,
|
||||
@@ -411,7 +427,14 @@ func (s *Server) handleStats(w http.ResponseWriter, r *http.Request) {
|
||||
Companions: counts["companions"],
|
||||
Sensors: counts["sensors"],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
s.statsMu.Lock()
|
||||
s.statsCache = resp
|
||||
s.statsCachedAt = time.Now()
|
||||
s.statsMu.Unlock()
|
||||
|
||||
writeJSON(w, resp)
|
||||
}
|
||||
|
||||
func (s *Server) handlePerf(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -98,6 +98,11 @@ type PacketStore struct {
|
||||
// computed during Load() and incrementally updated on ingest.
|
||||
distHops []distHopRecord
|
||||
distPaths []distPathRecord
|
||||
|
||||
// Cached GetNodeHashSizeInfo result — recomputed at most once every 15s
|
||||
hashSizeInfoMu sync.Mutex
|
||||
hashSizeInfoCache map[string]*hashSizeNodeInfo
|
||||
hashSizeInfoAt time.Time
|
||||
}
|
||||
|
||||
// Precomputed distance records for fast analytics aggregation.
|
||||
@@ -3722,8 +3727,26 @@ type hashSizeNodeInfo struct {
|
||||
Inconsistent bool
|
||||
}
|
||||
|
||||
// GetNodeHashSizeInfo scans advert packets to compute per-node hash size data.
|
||||
// GetNodeHashSizeInfo returns cached per-node hash size data, recomputing at most every 15s.
|
||||
func (s *PacketStore) GetNodeHashSizeInfo() map[string]*hashSizeNodeInfo {
|
||||
const ttl = 15 * time.Second
|
||||
s.hashSizeInfoMu.Lock()
|
||||
if s.hashSizeInfoCache != nil && time.Since(s.hashSizeInfoAt) < ttl {
|
||||
cached := s.hashSizeInfoCache
|
||||
s.hashSizeInfoMu.Unlock()
|
||||
return cached
|
||||
}
|
||||
s.hashSizeInfoMu.Unlock()
|
||||
result := s.computeNodeHashSizeInfo()
|
||||
s.hashSizeInfoMu.Lock()
|
||||
s.hashSizeInfoCache = result
|
||||
s.hashSizeInfoAt = time.Now()
|
||||
s.hashSizeInfoMu.Unlock()
|
||||
return result
|
||||
}
|
||||
|
||||
// computeNodeHashSizeInfo scans advert packets to compute per-node hash size data.
|
||||
func (s *PacketStore) computeNodeHashSizeInfo() map[string]*hashSizeNodeInfo {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
|
||||
services:
|
||||
prod:
|
||||
build: .
|
||||
image: corescope:latest
|
||||
container_name: corescope-prod
|
||||
restart: unless-stopped
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
ports:
|
||||
- "${PROD_HTTP_PORT:-80}:${PROD_HTTP_PORT:-80}"
|
||||
- "${PROD_HTTPS_PORT:-443}:${PROD_HTTPS_PORT:-443}"
|
||||
@@ -26,9 +29,12 @@ services:
|
||||
retries: 3
|
||||
|
||||
staging:
|
||||
build: .
|
||||
image: corescope:latest
|
||||
container_name: corescope-staging
|
||||
restart: unless-stopped
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
ports:
|
||||
- "${STAGING_HTTP_PORT:-81}:${STAGING_HTTP_PORT:-81}"
|
||||
- "${STAGING_MQTT_PORT:-1884}:1883"
|
||||
@@ -57,6 +63,8 @@ services:
|
||||
image: corescope-go:latest
|
||||
container_name: corescope-staging-go
|
||||
restart: unless-stopped
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
ports:
|
||||
- "${STAGING_GO_HTTP_PORT:-82}:80"
|
||||
- "${STAGING_GO_MQTT_PORT:-1885}:1883"
|
||||
|
||||
101
docs/rename-migration.md
Normal file
101
docs/rename-migration.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# CoreScope Migration Guide
|
||||
|
||||
MeshCore Analyzer has been renamed to **CoreScope**. This document covers what you need to update.
|
||||
|
||||
## What Changed
|
||||
|
||||
- **Repository name**: `meshcore-analyzer` → `corescope`
|
||||
- **Docker image name**: `meshcore-analyzer:latest` → `corescope:latest`
|
||||
- **Docker container prefixes**: `meshcore-*` → `corescope-*`
|
||||
- **Default site name**: "MeshCore Analyzer" → "CoreScope"
|
||||
|
||||
## What Did NOT Change
|
||||
|
||||
- **Data directories** — `~/meshcore-data/` stays as-is
|
||||
- **Database filename** — `meshcore.db` is unchanged
|
||||
- **MQTT topics** — `meshcore/#` topics are protocol-level and unchanged
|
||||
- **Browser state** — Favorites, localStorage keys, and settings are preserved
|
||||
- **Config file format** — `config.json` structure is the same
|
||||
|
||||
---
|
||||
|
||||
## 1. Git Remote Update
|
||||
|
||||
Update your local clone to point to the new repository URL:
|
||||
|
||||
```bash
|
||||
git remote set-url origin https://github.com/Kpa-clawbot/corescope.git
|
||||
git pull
|
||||
```
|
||||
|
||||
## 2. Docker (manage.sh) Users
|
||||
|
||||
Rebuild with the new image name:
|
||||
|
||||
```bash
|
||||
./manage.sh stop
|
||||
git pull
|
||||
./manage.sh setup
|
||||
```
|
||||
|
||||
The new image is `corescope:latest`. You can clean up the old image:
|
||||
|
||||
```bash
|
||||
docker rmi meshcore-analyzer:latest
|
||||
```
|
||||
|
||||
## 3. Docker Compose Users
|
||||
|
||||
Rebuild containers with the new names:
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
git pull
|
||||
docker compose build
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Container names change from `meshcore-*` to `corescope-*`. Old containers are removed by `docker compose down`.
|
||||
|
||||
## 4. Data Directories
|
||||
|
||||
**No action required.** The data directory `~/meshcore-data/` and database file `meshcore.db` are unchanged. Your existing data carries over automatically.
|
||||
|
||||
## 5. Config
|
||||
|
||||
If you customized `branding.siteName` in your `config.json`, update it to your preferred name. Otherwise the new default "CoreScope" applies automatically.
|
||||
|
||||
No other config keys changed.
|
||||
|
||||
## 6. MQTT
|
||||
|
||||
**No action required.** MQTT topics (`meshcore/#`) are protocol-level and are not affected by the rename.
|
||||
|
||||
## 7. Browser
|
||||
|
||||
**No action required.** Bookmarks/favorites will continue to work at the same host and port. localStorage keys are unchanged, so your settings and preferences are preserved.
|
||||
|
||||
## 8. CI/CD
|
||||
|
||||
If you have custom CI/CD pipelines that reference:
|
||||
|
||||
- The old repository URL (`meshcore-analyzer`)
|
||||
- The old Docker image name (`meshcore-analyzer:latest`)
|
||||
- Old container names (`meshcore-*`)
|
||||
|
||||
Update those references to use the new names.
|
||||
|
||||
---
|
||||
|
||||
## Summary Checklist
|
||||
|
||||
| Item | Action Required? | What to Do |
|
||||
|------|-----------------|------------|
|
||||
| Git remote | ✅ Yes | `git remote set-url origin …corescope.git` |
|
||||
| Docker image | ✅ Yes | Rebuild; optionally `docker rmi` old image |
|
||||
| Docker Compose | ✅ Yes | `docker compose down && build && up` |
|
||||
| Data directories | ❌ No | Unchanged |
|
||||
| Config | ⚠️ Maybe | Only if you customized `branding.siteName` |
|
||||
| MQTT | ❌ No | Topics unchanged |
|
||||
| Browser | ❌ No | Settings preserved |
|
||||
| CI/CD | ⚠️ Maybe | Update if referencing old repo/image names |
|
||||
Reference in New Issue
Block a user