Add credential extraction registry for generate

Protocols like Xiaomi need credentials (tokens) in a separate top-level
YAML section, not in the stream URL itself. Introduce a registry pattern
mirroring streams.HandleFunc / tester.RegisterSource:

- pkg/generate/registry.go: ExtractFunc + RegisterExtract
- Extractors clean the URL (strip ?token=...) and return section/key/value
- writeCredentials emits sorted sections between go2rtc: and cameras:
- upsertCredentials in addToConfig merges into existing sections:
  * replaces value if key exists (token refresh)
  * inserts in sorted order if new
  * creates new top-level section before cameras: if missing

Xiaomi registers its extractor from internal/xiaomi/xiaomi.go. Adding
Tapo/Ring/Roborock later is one line + a small function in their
internal/*/ module -- zero changes in pkg/generate/.
This commit is contained in:
eduard256
2026-04-18 08:36:48 +00:00
parent 8294736bcb
commit 12780d7803
5 changed files with 271 additions and 4 deletions
+33
View File
@@ -2,6 +2,7 @@ package generate
import (
"fmt"
"sort"
"strings"
)
@@ -17,6 +18,38 @@ func writeStreamLines(b *strings.Builder, info *cameraInfo) {
b.WriteByte('\n')
}
// writeCredentials writes top-level credential sections (xiaomi, tapo, ring, ...)
// populated by registered ExtractFunc handlers. Sorted by section, then by key.
// ex.
// xiaomi:
// "4161148305": V1:9d2w...
func writeCredentials(b *strings.Builder, creds map[string]map[string]string) {
if len(creds) == 0 {
return
}
sections := make([]string, 0, len(creds))
for s := range creds {
sections = append(sections, s)
}
sort.Strings(sections)
for _, section := range sections {
fmt.Fprintf(b, "%s:\n", section)
keys := make([]string, 0, len(creds[section]))
for k := range creds[section] {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fmt.Fprintf(b, " %q: %s\n", k, creds[section][k])
}
b.WriteByte('\n')
}
}
func writeCameraBlock(b *strings.Builder, info *cameraInfo, req *Request) {
fmt.Fprintf(b, " %s:\n", info.CameraName)