mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-05-11 12:24:44 +00:00
83881e6b71
## Summary Auto-discovers previously-unknown hashtag channels by scanning decoded channel message text for `#name` mentions and surfacing them via `GetChannels`. Workflow (per the issue): 1. New channel message arrives on a known channel 2. Decoded text is scanned for `#hashtag` mentions 3. Any mention that doesn't match an existing channel is surfaced as a discovered channel (`discovered: true`, `messageCount: 0`) 4. Future traffic on that channel will populate the entry once it has its own packets ## Changes - `cmd/server/discovered_channels.go` — new file. `extractHashtagsFromText` parses `#name` mentions from free text, deduped, order-preserving. Trailing punctuation is excluded by the character class. - `cmd/server/store.go` — `GetChannels` now scans CHAN packet text for hashtags after building the primary channel map, and appends any unseen hashtag mentions as discovered entries. - `cmd/server/discovered_channels_test.go` — new tests covering parser edge cases (single, multi, dedup, punctuation, none, bare `#`) and end-to-end discovery via `GetChannels`. ## TDD - Red: `34f1817` — stub returns `nil`, both new tests fail on assertion (verified). - Green: `d27b3ed` — real implementation, full `cmd/server` test suite passes (21.7s). ## Notes - Discovered channels carry `messageCount: 0` and `lastActivity` set to the most recent mention's `firstSeen`, so they sort naturally alongside real channels. - Names are matched against existing entries by both `#name` and bare `name` so a channel that already has decoded traffic isn't double-listed. - The existing `channelsCache` (15s) covers the new code path; no separate invalidation needed since the source data (`byPayloadType[5]`) drives both maps. Fixes #688 --------- Co-authored-by: corescope-bot <bot@corescope.local>
51 lines
1.7 KiB
Go
51 lines
1.7 KiB
Go
// Package main — discovered channels (#688).
|
|
//
|
|
// When a decoded channel message text mentions a previously-unknown hashtag
|
|
// channel (e.g. "Hey, I created new channel called #mesh, please join"), we
|
|
// auto-register that hashtag so future traffic can be displayed. This file
|
|
// owns the parsing helper plus the integration glue exposed via GetChannels.
|
|
package main
|
|
|
|
import "regexp"
|
|
|
|
// hashtagRE matches MeshCore-style hashtag channel mentions inside free text.
|
|
// A valid channel name starts with '#', followed by one or more letters,
|
|
// digits, underscore, or dash. Trailing punctuation (.,!?:;) is excluded by
|
|
// the character class.
|
|
var hashtagRE = regexp.MustCompile(`#[A-Za-z0-9_\-]+`)
|
|
|
|
// extractHashtagsFromText scans a decoded message text and returns the unique
|
|
// hashtag channel mentions found, in first-seen order. The leading '#' is
|
|
// preserved so callers can match against canonical channel names directly.
|
|
//
|
|
// Examples:
|
|
// extractHashtagsFromText("hi #mesh and #fun") => []string{"#mesh", "#fun"}
|
|
// extractHashtagsFromText("nothing here") => nil
|
|
// extractHashtagsFromText("dup #x and #x again") => []string{"#x"}
|
|
//
|
|
func extractHashtagsFromText(text string) []string {
|
|
if text == "" {
|
|
return nil
|
|
}
|
|
matches := hashtagRE.FindAllString(text, -1)
|
|
if len(matches) == 0 {
|
|
return nil
|
|
}
|
|
seen := make(map[string]struct{}, len(matches))
|
|
out := make([]string, 0, len(matches))
|
|
for _, m := range matches {
|
|
if len(m) < 2 { // bare '#' guard (regex requires 1+ chars but be defensive)
|
|
continue
|
|
}
|
|
if _, ok := seen[m]; ok {
|
|
continue
|
|
}
|
|
seen[m] = struct{}{}
|
|
out = append(out, m)
|
|
}
|
|
if len(out) == 0 {
|
|
return nil
|
|
}
|
|
return out
|
|
}
|