2024-12-15 13:45:46 +01:00
|
|
|
package hardware
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
2025-01-04 00:36:29 +01:00
|
|
|
"sync"
|
2024-12-15 13:45:46 +01:00
|
|
|
"time"
|
|
|
|
|
|
2024-12-29 13:09:46 +01:00
|
|
|
"github.com/rs/zerolog/log"
|
|
|
|
|
|
2024-12-15 13:45:46 +01:00
|
|
|
"github.com/wailsapp/wails/v2/pkg/runtime"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// PeripheralEvent is trigger by the finders when the scan is complete
|
|
|
|
|
type PeripheralEvent string
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
// PeripheralArrival is triggerd when a peripheral has been connected to the system
|
|
|
|
|
PeripheralArrival PeripheralEvent = "PERIPHERAL_ARRIVAL"
|
|
|
|
|
// PeripheralRemoval is triggered when a peripheral has been disconnected from the system
|
|
|
|
|
PeripheralRemoval PeripheralEvent = "PERIPHERAL_REMOVAL"
|
2025-01-04 12:10:25 +01:00
|
|
|
// debounceDuration = 500 * time.Millisecond
|
2024-12-15 13:45:46 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
debounceTimer *time.Timer
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// HardwareManager is the class who manages the hardware
|
|
|
|
|
type HardwareManager struct {
|
2025-01-04 12:10:25 +01:00
|
|
|
finders map[string]PeripheralFinder // The map of peripherals finders
|
2025-01-04 00:36:29 +01:00
|
|
|
peripherals []Peripheral // The current list of peripherals
|
|
|
|
|
peripheralsScanTrigger chan struct{} // Trigger the peripherals scans
|
|
|
|
|
goWait sync.WaitGroup // Wait for goroutines to terminate
|
2024-12-15 13:45:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewHardwareManager creates a new HardwareManager
|
|
|
|
|
func NewHardwareManager() *HardwareManager {
|
2024-12-29 13:09:46 +01:00
|
|
|
log.Trace().Str("package", "hardware").Msg("Hardware instance created")
|
2024-12-15 13:45:46 +01:00
|
|
|
return &HardwareManager{
|
2025-01-04 12:10:25 +01:00
|
|
|
finders: make(map[string]PeripheralFinder),
|
2025-01-04 00:36:29 +01:00
|
|
|
peripherals: make([]Peripheral, 0),
|
|
|
|
|
peripheralsScanTrigger: make(chan struct{}),
|
2024-12-15 13:45:46 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-29 13:09:46 +01:00
|
|
|
// Start starts to find new peripheral events
|
2024-12-15 13:45:46 +01:00
|
|
|
func (h *HardwareManager) Start(ctx context.Context) error {
|
2025-01-04 12:10:25 +01:00
|
|
|
for finderName, finder := range h.finders {
|
2025-01-04 00:36:29 +01:00
|
|
|
err := finder.Initialize()
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Err(err).Str("file", "hardware").Str("finderName", finderName).Msg("unable to initialize finder")
|
|
|
|
|
return err
|
2024-12-15 13:45:46 +01:00
|
|
|
}
|
2025-01-04 00:36:29 +01:00
|
|
|
err = finder.Start(ctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Err(err).Str("file", "hardware").Str("finderName", finderName).Msg("unable to start finder")
|
|
|
|
|
return err
|
2024-12-29 21:22:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
2025-01-04 12:10:25 +01:00
|
|
|
h.goWait.Add(1)
|
|
|
|
|
go func() {
|
|
|
|
|
defer h.goWait.Done()
|
|
|
|
|
for {
|
|
|
|
|
select {
|
|
|
|
|
case <-ctx.Done():
|
|
|
|
|
return
|
|
|
|
|
case <-h.peripheralsScanTrigger:
|
|
|
|
|
for finderName, finder := range h.finders {
|
|
|
|
|
log.Trace().Str("file", "hardware").Str("finderName", finderName).Msg("force a finder to scan peripherals")
|
|
|
|
|
finder.ForceScan()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}()
|
2025-01-04 00:36:29 +01:00
|
|
|
return nil
|
2024-12-29 21:22:53 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-04 12:10:25 +01:00
|
|
|
// GetFinder returns a register finder
|
|
|
|
|
func (h *HardwareManager) GetFinder(finderName string) (PeripheralFinder, error) {
|
|
|
|
|
finder, exists := h.finders[finderName]
|
2024-12-23 17:22:37 +01:00
|
|
|
if !exists {
|
2025-01-04 12:10:25 +01:00
|
|
|
log.Error().Str("file", "hardware").Str("finderName", finderName).Msg("unable to get the finder")
|
|
|
|
|
return nil, fmt.Errorf("unable to locate the '%s' finder", finderName)
|
2024-12-23 17:22:37 +01:00
|
|
|
}
|
2025-01-04 12:10:25 +01:00
|
|
|
log.Debug().Str("file", "hardware").Str("finderName", finderName).Msg("got finder")
|
|
|
|
|
return finder, nil
|
2024-12-23 17:22:37 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-04 12:10:25 +01:00
|
|
|
// RegisterFinder registers a new peripherals finder
|
|
|
|
|
func (h *HardwareManager) RegisterFinder(finder PeripheralFinder) {
|
|
|
|
|
h.finders[finder.GetName()] = finder
|
|
|
|
|
log.Info().Str("file", "hardware").Str("finderName", finder.GetName()).Msg("finder registered")
|
2024-12-15 13:45:46 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-04 12:10:25 +01:00
|
|
|
// GetPeripheral gets the peripheral object from the parent finder
|
|
|
|
|
func (h *HardwareManager) GetPeripheral(finderName string, peripheralID string) (Peripheral, bool) {
|
|
|
|
|
// Get the finder
|
|
|
|
|
parentFinder, found := h.finders[finderName]
|
|
|
|
|
// If no finder found, return false
|
2024-12-29 13:09:46 +01:00
|
|
|
if !found {
|
2025-01-04 12:10:25 +01:00
|
|
|
log.Error().Str("file", "hardware").Str("finderName", finderName).Msg("unable to get the finder")
|
2024-12-20 17:18:57 +01:00
|
|
|
return nil, false
|
|
|
|
|
}
|
2025-01-04 12:10:25 +01:00
|
|
|
log.Trace().Str("file", "hardware").Str("finderName", parentFinder.GetName()).Msg("finder got")
|
|
|
|
|
// Contact the finder to get the peripheral
|
|
|
|
|
return parentFinder.GetPeripheral(peripheralID)
|
2024-12-20 17:18:57 +01:00
|
|
|
}
|
|
|
|
|
|
2024-12-15 13:45:46 +01:00
|
|
|
// Scan scans all the peripherals for the registered finders
|
2025-01-04 00:36:29 +01:00
|
|
|
func (h *HardwareManager) Scan() error {
|
|
|
|
|
h.peripheralsScanTrigger <- struct{}{}
|
2024-12-15 13:45:46 +01:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-04 00:36:29 +01:00
|
|
|
// Stop stops the hardware manager
|
|
|
|
|
func (h *HardwareManager) Stop() error {
|
|
|
|
|
log.Trace().Str("file", "hardware").Msg("closing the hardware manager")
|
|
|
|
|
// Stop each finder
|
2025-01-04 12:10:25 +01:00
|
|
|
for finderName, finder := range h.finders {
|
2025-01-04 00:36:29 +01:00
|
|
|
err := finder.Stop()
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Err(err).Str("file", "hardware").Str("finderName", finderName).Msg("unable to stop the finder")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Wait for goroutines to finish
|
|
|
|
|
h.goWait.Wait()
|
|
|
|
|
log.Info().Str("file", "hardware").Msg("hardware manager stopped")
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-18 15:24:16 +01:00
|
|
|
// emitPeripheralsChanges compares the old and new peripherals to determine which ones have been added or removed.
|
|
|
|
|
func emitPeripheralsChanges(ctx context.Context, oldPeripherals map[string]Peripheral, newPeripherals map[string]Peripheral) {
|
|
|
|
|
log.Trace().Any("oldList", oldPeripherals).Any("newList", newPeripherals).Msg("emitting peripherals changes to the front")
|
|
|
|
|
|
|
|
|
|
// Identify removed peripherals: present in the old list but not in the new list
|
|
|
|
|
for oldPeriphName := range oldPeripherals {
|
|
|
|
|
if _, exists := newPeripherals[oldPeriphName]; !exists {
|
|
|
|
|
runtime.EventsEmit(ctx, string(PeripheralRemoval), oldPeripherals[oldPeriphName].GetInfo())
|
|
|
|
|
log.Trace().Str("file", "hardware").Str("event", string(PeripheralRemoval)).Msg("emit peripheral removal event")
|
|
|
|
|
}
|
2024-12-15 13:45:46 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-18 15:24:16 +01:00
|
|
|
// Identify added peripherals: present in the new list but not in the old list
|
|
|
|
|
for newPeriphName := range newPeripherals {
|
|
|
|
|
if _, exists := oldPeripherals[newPeriphName]; !exists {
|
|
|
|
|
runtime.EventsEmit(ctx, string(PeripheralArrival), newPeripherals[newPeriphName].GetInfo())
|
|
|
|
|
log.Trace().Str("file", "hardware").Str("event", string(PeripheralArrival)).Msg("emit peripheral arrival event")
|
2024-12-15 13:45:46 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|