src.dualinventive.com/go/devsim/daemon/simulator_service.go

194 lines
5.1 KiB
Go

package daemon
import (
"sync"
"src.dualinventive.com/go/devsim"
"src.dualinventive.com/go/devsim/repository"
"src.dualinventive.com/go/devsim/simulator"
"src.dualinventive.com/go/devsim/transport"
"src.dualinventive.com/go/dinet"
"src.dualinventive.com/go/lib/dilog"
)
type simulatorService struct {
simulatorsMx sync.Mutex
templates map[string]*TemplateTracker
simulators map[string]simulator.Simulator
repService repository.Service
smpEndpoint string
storage Storage
loggerDir string
}
// List return the current managed simulators
func (s *simulatorService) List() []simulator.Simulator {
s.simulatorsMx.Lock()
defer s.simulatorsMx.Unlock()
sims := make([]simulator.Simulator, 0, len(s.simulators))
for _, sim := range s.simulators {
sims = append(sims, sim)
}
return sims
}
// Add adds a new simulator in the list of managed simulators. The simulator is prepared to start, but is
// not started yet.
func (s *simulatorService) Add(uri string, version string) (simulator.Info, error) {
r, err := s.repService.Find(uri)
if err != nil {
return nil, err
}
key, err := r.Key(version)
if err != nil {
return nil, err
}
tracker, err := s.createTemplateIfNotExist(r, key)
if err != nil {
return nil, err
}
deviceUID, err := s.storage.GetNextDeviceUID()
if err != nil {
return nil, err
}
// Indicate that we are using this template. This creates the template if nessesary
tracker.Increment()
tpl := tracker.Info()
templateInfo := &template{Info: tpl, deviceUID: deviceUID}
// Get the driver
driver := s.getDriver(templateInfo)
if driver == nil {
tracker.Decrement()
return nil, ErrInvalidTemplate
}
// Get the model
model, err := s.getModel(deviceUID)
if err != nil {
tracker.Decrement()
return nil, err
}
// Create the simulator
sim, err := simulator.NewSimulator(driver.Name(), model, templateInfo)
if err != nil {
tracker.Decrement()
return nil, err
}
s.simulatorsMx.Lock()
defer s.simulatorsMx.Unlock()
if _, ok := s.simulators[deviceUID]; ok {
tracker.Decrement()
// This should not happen because we requested a deviceUID
return nil, devsim.ErrAlreadyExists
}
s.simulators[deviceUID] = sim
return templateInfo, nil
}
// Get returns the simulator with the given deviceUID or an ErrNotFound it returned when the simulator is
// not found.
func (s *simulatorService) Get(deviceUID string) (simulator.Simulator, error) {
return s.getByDeviceUID(deviceUID)
}
// Remove removes the simulator of the list of managed simulators. This simulator must be stopped in order
// to succeeds. An ErrNotFound is returned when the simulator is not found. An ErrNotStopped is returned when the
// simulator is still running.
func (s *simulatorService) Remove(deviceUID string) error {
sim, err := s.getByDeviceUID(deviceUID)
if err != nil {
return err
}
key := sim.Key()
if tTracker, ok := s.templates[key]; ok {
tTracker.Decrement()
}
// TODO check if simulator is running
delete(s.simulators, deviceUID)
return nil
}
func (s *simulatorService) getByDeviceUID(deviceUID string) (simulator.Simulator, error) {
s.simulatorsMx.Lock()
defer s.simulatorsMx.Unlock()
sim, ok := s.simulators[deviceUID]
if !ok {
return nil, devsim.ErrNotFound
}
return sim, nil
}
// Start starts the simulator with the given deviceUID. An ErrNotFound is returned when the simulator is
// not found. An ErrAlreadyRunning is returned when the simulator is already running.
func (s *simulatorService) Start(deviceUID string) error {
sim, err := s.getByDeviceUID(deviceUID)
if err != nil {
return err
}
// TODO check if simulator is running
return sim.Start()
}
// Stop stops the simulator with the given deviceUID. An ErrNotFound is returned when the simulator is
// not found. An ErrAlreadyStopped is returned when the simulator is already stopped.
func (s *simulatorService) Stop(deviceUID string) error {
sim, err := s.getByDeviceUID(deviceUID)
if err != nil {
return err
}
// TODO check if simulator is running
return sim.Stop()
}
func (s *simulatorService) createTemplateIfNotExist(rep repository.Repository, key string) (*TemplateTracker, error) {
tTracker, ok := s.templates[key]
if !ok {
t, err := rep.Template(key)
if err != nil {
return nil, err
}
tTracker = &TemplateTracker{
usage: 0,
template: t,
}
s.templates[key] = tTracker
}
return tTracker, nil
}
// getDriver returns the first valid driver that can execute the given template info
func (s *simulatorService) getDriver(t simulator.Info) simulator.Driver {
// Search for a valid driver that can execute our template
drivers := simulator.Drivers()
for _, driver := range drivers {
if driver.Valid(t) {
return driver
}
}
return nil
}
// getModel returns the model that can be inserted in the simulator
func (s *simulatorService) getModel(deviceUID string) (simulator.Model, error) {
dStorage := s.storage.GetDeviceStorage(deviceUID)
if dStorage == nil {
return nil, ErrCannotCreateStorage
}
dTransport, err := transport.NewDinet(dinet.TransportLowlevel, deviceUID, s.smpEndpoint)
if err != nil {
return nil, err
}
// TODO get deviceUID logger
discard := dilog.NewNilLogger()
return simulator.NewModel(discard, dStorage, dTransport), nil
}