Compare commits

..

2 Commits

Author SHA1 Message Date
9a6748b156 feat: Speed up covanent using bulk
All checks were successful
Build Docker / BuildImage (push) Successful in 39s
Check Code Quality / RuffCheck (push) Successful in 49s
2025-11-21 13:34:19 +11:00
90de6042b1 fix: Cleanup TXT record display 2025-11-21 13:28:50 +11:00
2 changed files with 113 additions and 32 deletions

View File

@@ -198,11 +198,18 @@ def namehash_api(namehash):
@app.route("/api/v1/status")
def api_status():
# Count number of names in database
db = get_db()
cur = db.execute("SELECT COUNT(*) as count FROM names")
row = cur.fetchone()
name_count = row["count"] if row else 0
return jsonify(
{
"status": "ok",
"service": "FireExplorer",
"version": "1.0.0",
"names_cached": name_count,
}
)
@@ -242,6 +249,72 @@ def hip02(domain: str):
@app.route("/api/v1/covenant", methods=["POST"])
def covenant_api():
data = request.get_json()
if isinstance(data, list):
covenants = data
results = []
# Collect all namehashes needed
namehashes = set()
for cov in covenants:
items = cov.get("items", [])
if items:
namehashes.add(items[0])
# Batch DB lookup
db = get_db()
known_names = {}
if namehashes:
placeholders = ",".join("?" for _ in namehashes)
cur = db.execute(
f"SELECT namehash, name FROM names WHERE namehash IN ({placeholders})",
list(namehashes),
)
for row in cur:
known_names[row["namehash"]] = row["name"]
# Identify missing namehashes
missing_hashes = [nh for nh in namehashes if nh not in known_names]
# Fetch missing from HSD
session = requests.Session()
for nh in missing_hashes:
try:
req = session.get(f"https://hsd.hns.au/api/v1/namehash/{nh}")
if req.status_code == 200:
name = req.json().get("result")
if name:
known_names[nh] = name
# Update DB
db.execute(
"INSERT OR REPLACE INTO names (namehash, name) VALUES (?, ?)",
(nh, name),
)
except Exception as e:
print(f"Error fetching namehash {nh}: {e}")
db.commit()
# Build results
for cov in covenants:
action = cov.get("action")
items = cov.get("items", [])
if not action:
results.append({"covenant": cov, "display": "Unknown"})
continue
display = f"{action}"
if items:
nh = items[0]
if nh in known_names:
name = known_names[nh]
display += f' <a href="/name/{name}">{name}</a>'
results.append({"covenant": cov, "display": display})
return jsonify(results)
# Get the covenant data
action = data.get("action")
items = data.get("items", [])

View File

@@ -696,7 +696,7 @@
recordDetails += `<br><span style="font-size: 0.9rem;">KeyTag: ${record.keyTag}, Algorithm: ${record.algorithm}, DigestType: ${record.digestType}</span><br><span class="mono" style="font-size: 0.85rem; color: #b0b0b0; word-break: break-all;">${record.digest}</span>`;
break;
case 'TXT':
recordDetails += `<br><span style="color: #b0b0b0;">${record.txt.map(t => `"${t}"`).join('<br>')}</span>`;
recordDetails += `<br><span style="color: #b0b0b0;">${record.txt.join('<br>')}</span>`;
break;
case 'GLUE4':
case 'GLUE6':
@@ -779,7 +779,7 @@
recordDetails += `<br><span style="font-size: 0.9rem;">KeyTag: ${record.keyTag}, Algorithm: ${record.algorithm}</span>`;
break;
case 'TXT':
recordDetails += `<br><span style="color: #b0b0b0;">${record.txt.map(t => `"${t}"`).join('<br>')}</span>`;
recordDetails += `<br><span style="color: #b0b0b0;">${record.txt.join('<br>')}</span>`;
break;
case 'GLUE4':
case 'GLUE6':
@@ -944,7 +944,8 @@
// Update covenant information from API
async function updateCovenants() {
const elements = document.querySelectorAll('[data-covenant-action]');
const cache = {};
const covenantsToFetch = [];
const elementMap = new Map(); // Map JSON string -> Array of elements
for (const el of elements) {
const action = el.dataset.covenantAction;
@@ -965,39 +966,46 @@
if (!covenantData) continue;
// Create a cache key based on the full covenant data
const cacheKey = JSON.stringify(covenantData);
const key = JSON.stringify(covenantData);
if (!elementMap.has(key)) {
elementMap.set(key, []);
covenantsToFetch.push(covenantData);
}
elementMap.get(key).push(el);
}
let display = action;
if (cache[cacheKey]) {
display = cache[cacheKey];
} else {
try {
const res = await fetch(`/api/v1/covenant`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(covenantData)
});
if (covenantsToFetch.length === 0) return;
if (res.ok) {
const data = await res.json();
display = data.display || action;
cache[cacheKey] = display;
try {
const res = await fetch(`/api/v1/covenant`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(covenantsToFetch)
});
if (res.ok) {
const results = await res.json();
for (const result of results) {
const key = JSON.stringify(result.covenant);
const els = elementMap.get(key);
if (els) {
for (const el of els) {
if (el.classList.contains('tx-covenant')) {
el.innerHTML = `Covenant: ${result.display}`;
} else {
el.innerHTML = result.display;
}
el.dataset.covenantUpdated = "true";
}
}
} catch (e) {
console.error('Failed to fetch covenant info:', e);
}
}
// Check if it's the .tx-covenant div which includes "Covenant: " text
if (el.classList.contains('tx-covenant')) {
el.innerHTML = `Covenant: ${display}`;
} else {
el.textContent = display;
}
el.dataset.covenantUpdated = "true";
} catch (e) {
console.error('Failed to fetch covenant info:', e);
}
}