-
Parity Analysis
-
- Detection of discrepancies between AfterTouch local
- responses and official Bose Cloud responses for mirrored
- endpoints.
-
-
-
-
-
Parity Mismatches
-
-
-
-
-
-
-
-
-
-
- | Time |
- Method |
- Path |
- Reasons |
- Action |
-
-
-
-
- |
- Loading mismatches...
- |
-
-
-
-
-
-
-
-
-
- Mismatch Detail:
-
-
-
-
-
-
-
-
- ⚠️ Large Payload: Rich diff highlighting is disabled to prevent a browser freeze. Showing raw comparison instead.
-
-
-
-
-
-
-
-
+
Local Account Details
diff --git a/pkg/service/handlers/web/js/script.js b/pkg/service/handlers/web/js/script.js
index 5e5a55e..1028b66 100644
--- a/pkg/service/handlers/web/js/script.js
+++ b/pkg/service/handlers/web/js/script.js
@@ -275,18 +275,6 @@ async function fetchSettings() {
dnsCurrentUpstream.innerText = "";
}
- if (settings.mirror_enabled !== undefined) {
- document.getElementById("mirror-enabled").checked = settings.mirror_enabled;
- }
- if (settings.preferred_source !== undefined) {
- document.getElementById("preferred-source-upstream").checked = settings.preferred_source === "upstream";
- }
- if (settings.mirror_endpoints) {
- document.getElementById("mirror-endpoints").value = settings.mirror_endpoints.join("\n");
- }
- if (settings.skip_mirror_endpoints) {
- document.getElementById("skip-mirror-endpoints").value = settings.skip_mirror_endpoints.join("\n");
- }
if (settings.internal_paths) {
document.getElementById("internal-paths").value = settings.internal_paths.join("\n");
}
@@ -373,18 +361,6 @@ async function updateSettings() {
dns_enabled: document.getElementById("dns-enabled").checked,
dns_upstream: document.getElementById("dns-upstream").value,
dns_bind_addr: document.getElementById("dns-bind").value,
- mirror_enabled: document.getElementById("mirror-enabled").checked,
- preferred_source: document.getElementById("preferred-source-upstream").checked ? "upstream" : "local",
- mirror_endpoints: document
- .getElementById("mirror-endpoints")
- .value.split("\n")
- .map((s) => s.trim())
- .filter((s) => s !== ""),
- skip_mirror_endpoints: document
- .getElementById("skip-mirror-endpoints")
- .value.split("\n")
- .map((s) => s.trim())
- .filter((s) => s !== ""),
internal_paths: document
.getElementById("internal-paths")
.value.split("\n")
@@ -527,10 +503,6 @@ function openTab(evt, tabId) {
fetchDNSDiscoveries();
}
- if (tabId === "tab-parity") {
- fetchParityMismatches();
- }
-
if (tabId === "tab-account") {
fetchAccountList();
}
@@ -1525,122 +1497,6 @@ async function fetchDeviceEvents(deviceId) {
list.innerHTML = `| Error loading events: ${error.message} |
`;
}
}
-
-async function fetchParityMismatches() {
- const list = document.getElementById("parity-mismatches-list");
- list.innerHTML = '| Loading mismatches... |
';
-
- try {
- const response = await fetch("/setup/parity-mismatches");
- const mismatches = await response.json();
-
- list.innerHTML = "";
- if (!mismatches || mismatches.length === 0) {
- list.innerHTML = '| No parity mismatches detected yet. |
';
- return;
- }
-
- mismatches.forEach((m) => {
- const tr = document.createElement("tr");
- tr.style.borderBottom = "1px solid #eee";
-
- const time = m.timestamp || "";
- const method = m.method || "";
- const path = m.path || "";
- const reasons = (m.reasons || []).join(", ");
-
- tr.innerHTML = `
- ${time} |
- ${method} |
- ${path} |
- ${reasons} |
- |
- `;
- list.appendChild(tr);
- });
- } catch (error) {
- list.innerHTML = `| Error loading mismatches: ${error.message} |
`;
- }
-}
-
-async function clearParityMismatches() {
- if (!confirm("Are you sure you want to clear all parity mismatch records?")) return;
- try {
- await fetch("/setup/parity-mismatches", {method: "DELETE"});
- fetchParityMismatches();
- document.getElementById("parity-diff-view").style.display = "none";
- } catch (error) {
- alert("Failed to clear mismatches: " + error.message);
- }
-}
-
-function viewParityMismatch(m, forceRichDiff = false) {
- document.getElementById("diff-path-display").innerText = m.method + " " + m.path;
- const reasonsList = document.getElementById("diff-reasons-list");
- reasonsList.innerHTML = "";
- (m.reasons || []).forEach((r) => {
- const li = document.createElement("li");
- li.innerText = r;
- reasonsList.appendChild(li);
- });
-
- document.getElementById("diff-local-meta").innerText = `Status: ${m.local.status}`;
- document.getElementById("diff-upstream-meta").innerText = `Status: ${m.upstream.status}`;
-
- const localCT = (m.local.headers && m.local.headers["Content-Type"]) ? m.local.headers["Content-Type"][0] : "";
- const upstreamCT = (m.upstream.headers && m.upstream.headers["Content-Type"]) ? m.upstream.headers["Content-Type"][0] : "";
-
- const localBody = formatBody(m.local.body, localCT);
- const upstreamBody = formatBody(m.upstream.body, upstreamCT);
-
- const diffSizeThreshold = 50000; // 50KB
- const isLarge = localBody.length > diffSizeThreshold || upstreamBody.length > diffSizeThreshold;
- const warningEl = document.getElementById("diff-size-warning");
-
- if (isLarge && !forceRichDiff) {
- warningEl.style.display = "block";
- const forceBtn = document.getElementById("force-rich-diff-btn");
- forceBtn.onclick = () => viewParityMismatch(m, true);
-
- document.getElementById("diff-local-body").innerText = localBody;
- document.getElementById("diff-upstream-body").innerText = upstreamBody;
- } else {
- warningEl.style.display = "none";
- if (typeof Diff !== 'undefined') {
- const diff = Diff.diffChars(localBody, upstreamBody);
- const localEl = document.getElementById("diff-local-body");
- const upstreamEl = document.getElementById("diff-upstream-body");
-
- localEl.innerHTML = "";
- upstreamEl.innerHTML = "";
-
- diff.forEach((part) => {
- const span = document.createElement('span');
- if (part.added) {
- span.className = 'diff-added';
- span.innerText = part.value;
- upstreamEl.appendChild(span);
- } else if (part.removed) {
- span.className = 'diff-removed';
- span.innerText = part.value;
- localEl.appendChild(span);
- } else {
- localEl.appendChild(document.createTextNode(part.value));
- upstreamEl.appendChild(document.createTextNode(part.value));
- }
- });
- } else {
- document.getElementById("diff-local-body").innerText = localBody;
- document.getElementById("diff-upstream-body").innerText = upstreamBody;
- }
- }
-
- document.getElementById("parity-diff-view").style.display = "block";
- document
- .getElementById("parity-diff-view")
- .scrollIntoView({behavior: "smooth"});
-}
-
function formatBody(body, contentType) {
if (!body) return "";
contentType = (contentType || "").toLowerCase();
@@ -1698,7 +1554,6 @@ document.addEventListener("DOMContentLoaded", () => {
fetchDevices();
triggerDiscovery();
fetchVersion();
- fetchParityMismatches();
const syncBtn = document.getElementById("sync-now-btn");
if (syncBtn) syncBtn.onclick = startSync;
diff --git a/pkg/service/setup/setup.go b/pkg/service/setup/setup.go
index 7d799b2..c5b89ef 100644
--- a/pkg/service/setup/setup.go
+++ b/pkg/service/setup/setup.go
@@ -104,11 +104,6 @@ type MigrationSummary struct {
// observe the SSH-ping cost in the wild.
ResolveIPDurationMS int64 `json:"resolve_ip_duration_ms,omitempty"`
- MirrorEnabled bool `json:"mirror_enabled"`
- MirrorEndpoints []string `json:"mirror_endpoints,omitempty"`
- SkipMirrorEndpoints []string `json:"skip_mirror_endpoints,omitempty"`
- PreferredSource string `json:"preferred_source,omitempty"`
-
// Telnet (port 17000) preflight state — populated when the user is about to
// or has just used MigrationMethodTelnet.
TelnetReachable bool `json:"telnet_reachable"`
@@ -348,17 +343,6 @@ func (m *Manager) GetMigrationSummary(deviceIP, targetURL, proxyURL string, opti
// 3. Provide HTTPS URL for testing (consumed by the migration UI)
summary.ServerHTTPSURL = m.buildServerHTTPSURL(targetURL)
- // 4. Mirroring settings
- if m.DataStore != nil {
- settings, err := m.DataStore.GetSettings()
- if err == nil {
- summary.MirrorEnabled = settings.MirrorEnabled
- summary.MirrorEndpoints = settings.MirrorEndpoints
- summary.SkipMirrorEndpoints = settings.SkipMirrorEndpoints
- summary.PreferredSource = settings.PreferredSource
- }
- }
-
// 5. Merge telnet preflight results (started in parallel at the top).
telnetResult := <-telnetCh
summary.TelnetReachable = telnetResult.TelnetReachable
diff --git a/pkg/service/setup/setup_test.go b/pkg/service/setup/setup_test.go
index 4d749bd..c1a0142 100644
--- a/pkg/service/setup/setup_test.go
+++ b/pkg/service/setup/setup_test.go
@@ -380,45 +380,6 @@ func TestGetMigrationSummary_WithProxyOptions(t *testing.T) {
}
}
-func TestGetMigrationSummary_MirrorSettings(t *testing.T) {
- tempDir, err := os.MkdirTemp("", "st-test-mirror-*")
- if err != nil {
- t.Fatalf("Failed to create temp dir: %v", err)
- }
- defer os.RemoveAll(tempDir)
-
- ds := datastore.NewDataStore(tempDir)
- settings := datastore.Settings{
- MirrorEnabled: true,
- MirrorEndpoints: []string{"/recent", "/presets"},
- }
- if err := ds.SaveSettings(settings); err != nil {
- t.Fatalf("Failed to save settings: %v", err)
- }
-
- m := NewManager("http://localhost:8000", ds, nil)
-
- // Mock server for live info
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "application/xml")
- _, _ = fmt.Fprint(w, `Test`)
- }))
- defer server.Close()
-
- summary, err := m.GetMigrationSummary(server.Listener.Addr().String(), "", "", nil)
- if err != nil {
- t.Fatalf("GetMigrationSummary failed: %v", err)
- }
-
- if !summary.MirrorEnabled {
- t.Error("Expected MirrorEnabled to be true in summary")
- }
-
- if len(summary.MirrorEndpoints) != 2 || summary.MirrorEndpoints[0] != "/recent" {
- t.Errorf("Expected MirrorEndpoints [/recent /presets], got %v", summary.MirrorEndpoints)
- }
-}
-
func TestCheckCACertTrusted(t *testing.T) {
tempDir, err := os.MkdirTemp("", "ca-trust-test")
if err != nil {