jim800121chen c54f16fca0 Initial commit: visionA monorepo with local-tool subproject
local-tool/: visionA-local desktop app
- M1: Wails shell + Go server + Next.js UI + Mock mode (macOS dmg ready)
- M2: i18n (zh-TW/en) + Settings 4-tab refactor
- M3: Embedded Python 3.12 runtime (python-build-standalone) + KneronPLUS wheels
- M4: Windows Inno Setup script (build on Windows runner)
- M5: Linux AppImage script + udev rule (build on Linux runner)
- M6: ffmpeg (GPL, pending legal review) + yt-dlp bundled
- Lifecycle: watchServer health check, fatal native dialog,
            Wails IPC raise endpoint, stale process cleanup

.autoflow/: full PRD / Design Spec / Architecture / Testing docs
            (4 rounds tri-party discussion + cross review)
.github/workflows/: macOS / Windows / Linux build CI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:10:38 +08:00

95 lines
1.7 KiB
Go

package inference
import (
"context"
"sync"
"visiona-local/server/internal/device"
"visiona-local/server/internal/driver"
)
type stream struct {
cancel context.CancelFunc
done chan struct{}
}
type Service struct {
deviceMgr *device.Manager
streams map[string]*stream
mu sync.Mutex
}
func NewService(deviceMgr *device.Manager) *Service {
return &Service{
deviceMgr: deviceMgr,
streams: make(map[string]*stream),
}
}
func (s *Service) Start(deviceID string, resultCh chan<- *driver.InferenceResult) error {
session, err := s.deviceMgr.GetDevice(deviceID)
if err != nil {
return err
}
if err := session.Driver.StartInference(); err != nil {
return err
}
ctx, cancel := context.WithCancel(context.Background())
done := make(chan struct{})
s.mu.Lock()
s.streams[deviceID] = &stream{cancel: cancel, done: done}
s.mu.Unlock()
go func() {
defer close(done)
defer session.Driver.StopInference()
for {
select {
case <-ctx.Done():
return
default:
result, err := session.Driver.ReadInference()
if err != nil {
continue
}
select {
case resultCh <- result:
default:
}
}
}
}()
return nil
}
// StopAll stops all running inference streams. Used during graceful shutdown.
func (s *Service) StopAll() {
s.mu.Lock()
ids := make([]string, 0, len(s.streams))
for id := range s.streams {
ids = append(ids, id)
}
s.mu.Unlock()
for _, id := range ids {
_ = s.Stop(id)
}
}
func (s *Service) Stop(deviceID string) error {
s.mu.Lock()
st, ok := s.streams[deviceID]
if ok {
delete(s.streams, deviceID)
}
s.mu.Unlock()
if ok {
st.cancel()
<-st.done // wait for goroutine to finish and StopInference to complete
}
return nil
}