package server import ( pb "FRMS/internal/pkg/grpc" "FRMS/internal/pkg/logging" "FRMS/internal/pkg/manager" "time" "context" "github.com/spf13/viper" ) // MaxConnectionAttempts is the max number of tries to allow // when connecting to a reactor. const MaxConnectionAttempts = 10 // Manager is an interface requiring a structure that can be started // and stopped as well as provide timeouts in milliseconds. type Manager interface { Start() error // status checks Stop() error Timeout() (time.Duration, error) // TO Generator } // NewManager returns a manager fulfilling the Manager interface as well as // any potential errors. func NewManager(max int) (Manager, error) { return manager.New(max) } // ReactorManager contains a base manager, client, global // config, and error channel. // The ReactorManager can be started/stopped as clients connect/disconnect. // Also serves as handler for gRPC requests from reactors. // Can be extended to write changes to config. type ReactorManager struct { Manager // base manager interface *Client Config *viper.Viper // global config to maintain Err chan error } // NewReactorManager takes in a client, config and channel to pass errors on. // Returns a new reactor manager as well as any errors that occured during // creation. // Uses MaxConnectionAttempts which defaults to 10 to prevent // unnessecary network load and/or timeout lengths. func NewReactorManager( cl *Client, config *viper.Viper, errCh chan error, ) (*ReactorManager, error) { m, err := NewManager(MaxConnectionAttempts) if err != nil { return &ReactorManager{}, err } r := &ReactorManager{ Manager: m, Client: cl, Config: config, Err: errCh, } return r, err } // Start logs the start and calls start on the embedded manager. func (r *ReactorManager) Start() error { logging.Debug(logging.DStart, "RMA %v starting", r.Id) return r.Manager.Start() } // Stop logs the stop and calls stop on the embedded manager. func (r *ReactorManager) Stop() error { logging.Debug(logging.DExit, "RMA %v stopping", r.Id) return r.Manager.Stop() } // UpdateClient is used to change the underlying manager client if there // changes to its data. // // BUG(Keegan): Client is not protected by a lock and may lead to races func (r *ReactorManager) UpdateClient(cl *Client) error { logging.Debug(logging.DClient, "RMA %v updating client", r.Id) r.Client = cl return nil } // ReactorStatusHandler implements a gRPC handler that is called by reactors. // Takes in a context and request which has reactor and device information. // For now, loops over devices and logs information about their status. func (r *ReactorManager) ReactorStatusHandler( ctx context.Context, req *pb.ReactorStatusPing, ) (*pb.ReactorStatusResponse, error) { logging.Debug(logging.DClient, "RMA %v recieved ping", r.Id) for _, dev := range req.GetDevices() { logging.Debug( logging.DClient, "RMA %v device %v is %v", r.Id, dev.GetAddr(), dev.GetStatus().String(), ) } return &pb.ReactorStatusResponse{Id: int32(r.Id)}, nil }