feat(v2): T-309 SQLite fall-event persistence (mattn/go-sqlite3)
Persist confirmed fall events to a local SQLite DB under artifacts/: camera host/port/channel + event id/track/source/config version/state/ latency/screenshot path/confirmed-at. Schema stores no password (guarded by test). Wire openRecorder/saveRecord into the alerts loop; failures are non-fatal. Re-applied the SILVER-POSE vendored os_windows.go patch that go mod vendor reverted. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,7 @@ import (
|
||||
"silverpose/v2/internal/monitor"
|
||||
"silverpose/v2/internal/source"
|
||||
"silverpose/v2/internal/spike"
|
||||
"silverpose/v2/internal/store"
|
||||
"silverpose/v2/internal/ui"
|
||||
)
|
||||
|
||||
@@ -129,6 +130,10 @@ func (controller *controller) run(ctx context.Context, cancel func(), runID uint
|
||||
controller.window.ReportIssue("无法启动监控管线")
|
||||
return
|
||||
}
|
||||
recorder := openRecorder(cfg)
|
||||
if recorder != nil {
|
||||
defer recorder.Close()
|
||||
}
|
||||
go monitored.Run(ctx)
|
||||
updates, alerts := monitored.Updates(), monitored.Alerts()
|
||||
for updates != nil || alerts != nil {
|
||||
@@ -145,10 +150,41 @@ func (controller *controller) run(ctx context.Context, cancel func(), runID uint
|
||||
continue
|
||||
}
|
||||
controller.window.PresentAlert(record)
|
||||
saveRecord(recorder, cfg, record)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// openRecorder opens the local SQLite fall database under the event directory.
|
||||
// A failure is logged and monitoring continues without persistence.
|
||||
func openRecorder(cfg config.Config) *store.Store {
|
||||
if err := os.MkdirAll(cfg.Artifacts.EventDirectory, 0o755); err != nil {
|
||||
log.Printf("创建事件目录失败:%v", err)
|
||||
return nil
|
||||
}
|
||||
recorder, err := store.Open(filepath.Join(cfg.Artifacts.EventDirectory, "fall-events.db"))
|
||||
if err != nil {
|
||||
log.Printf("打开摔倒数据库失败:%v", err)
|
||||
return nil
|
||||
}
|
||||
return recorder
|
||||
}
|
||||
|
||||
func saveRecord(recorder *store.Store, cfg config.Config, record alert.Record) {
|
||||
if recorder == nil {
|
||||
return
|
||||
}
|
||||
if err := recorder.Save(store.Record{
|
||||
EventID: record.Event.EventID, TrackID: record.Event.TrackID, SourceID: cfg.Source.ID,
|
||||
CameraHost: cfg.Source.Host, CameraPort: cfg.Source.Port, CameraChannel: cfg.Source.Channel,
|
||||
ConfigVersion: record.Event.ConfigVersion, State: fmt.Sprint(record.Event.State),
|
||||
LatencySeconds: record.Event.LatencySeconds, ScreenshotPath: record.ScreenshotPath,
|
||||
ConfirmedAtUTC: record.CreatedAtUTC.UTC().Format(time.RFC3339),
|
||||
}); err != nil {
|
||||
log.Printf("写入摔倒记录失败:%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func validateStartup(cfg config.Config) error {
|
||||
for _, path := range []string{cfg.Model.ONNXPath, cfg.Model.ONNXRuntimeDLLPath, cfg.Tools.FFmpegPath, cfg.Tools.FFprobePath} {
|
||||
info, err := os.Stat(path)
|
||||
|
||||
Reference in New Issue
Block a user