@ -8,58 +8,54 @@ import (
"context"
"context"
"errors"
"errors"
"fmt"
"fmt"
"net"
"sync"
"sync"
"github.com/spf13/viper"
"github.com/spf13/viper"
"google.golang.org/grpc"
)
)
// this package creates the central coordiantor and sub coordiantors for clients
// this package creates the central coordiantor and sub coordiantors to route clients
// db client interface
// db client interface
type D B interface {
type D atabase interface {
// getters (all create if doesnt exist)
// getters (all create if doesnt exist)
GetReactorClient ( int ) ( string , string , string , string , error ) // returns (url, org, bucket, token, err)
GetReactorClient ( int ) ( string , string , string , string , error ) // returns (url, org, bucket, token, err)
}
}
func NewD B Admin( config * viper . Viper ) ( D B , error ) {
func NewD atabase Admin( config * viper . Viper ) ( D atabase , error ) {
return influxdb . NewDBAdmin ( config )
return influxdb . NewDBAdmin ( config )
}
}
type CentralCoordinator struct {
type CentralCoordinator struct {
// main coordinator
// main coordinator
ClientConnections * ClientPacket
ClientConnections * ClientPacket
* SubCoordinators
* ReactorCoordinator
//*SystemViewer
Database
DB
Config * viper . Viper
Config * viper . Viper
// from config
// from config
Ports map [ string ] int ` mapstructure:"ports" `
Ports map [ string ] int ` mapstructure:"ports" `
Err chan error
Err chan error
}
}
type SubCoordinators struct {
Directory map [ string ] * SubCoordinator
sync . Mutex
}
func NewCentralCoordinator ( config * viper . Viper , ch chan error ) * CentralCoordinator {
func NewCentralCoordinator ( config * viper . Viper , ch chan error ) * CentralCoordinator {
// create a central coordinator to manage requests
// create a central coordinator to manage requests
db , err := NewD B Admin( config )
db , err := NewDatabaseAdmin ( config )
if err != nil {
if err != nil {
ch <- err
ch <- err
}
}
c := & CentralCoordinator { Err : ch , Config : config , DB : db }
rc , err := NewReactorCoordinator ( ch )
if err != nil {
ch <- err
}
config . UnmarshalKey ( "server.ports" , rc ) // get reactor port
c := & CentralCoordinator { Err : ch , Config : config , Database : db , ReactorCoordinator : rc }
// grab config settings
// grab config settings
if err = config . UnmarshalKey ( "server" , c ) ; err != nil {
if err = config . UnmarshalKey ( "server" , c ) ; err != nil {
ch <- err
ch <- err
}
}
// spawn a systemviewer DECOMIS
//c.SystemViewer = NewSystemViewer()
//.go c.SystemViewer.Start()
// subcoord map
s := make ( map [ string ] * SubCoordinator )
c . SubCoordinators = & SubCoordinators { Directory : s }
// return init coordinator
return c
return c
}
}
@ -67,250 +63,126 @@ func (c *CentralCoordinator) Start() {
// starts up associated funcs
// starts up associated funcs
clientChan := make ( chan * ClientPacket )
clientChan := make ( chan * ClientPacket )
l := NewListener ( clientChan , c . Err )
l := NewListener ( clientChan , c . Err )
// grabs lis port
// grabs lis port
c . Config . UnmarshalKey ( "server.ports" , l )
c . Config . UnmarshalKey ( "server.ports" , l )
// starts client listener routines
go l . Start ( )
// starting reactor coordinator
if err := c . ReactorCoordinator . Start ( ) ; err != nil {
c . Err <- err
}
// starting listener
if err := l . Start ( ) ; err != nil {
c . Err <- err
}
// lastly start client listener
go c . ClientListener ( clientChan )
go c . ClientListener ( clientChan )
}
}
func ( c * CentralCoordinator ) ClientListener ( ch chan * ClientPacket ) {
func ( c * CentralCoordinator ) ClientListener ( ch chan * ClientPacket ) {
for client := range ch {
for client := range ch {
// basically loops until channel is closed
// basically loops until channel is closed
fmt . Printf ( "Incoming client: +%v\n" , client )
client . Response <- c . ClientHandler ( client . Client ) // respond with cred
client . Response <- c . ClientHandler ( client . Client ) // respond with cred
}
}
}
}
func ( c * CentralCoordinator ) ClientHandler ( cl * Client ) * ClientResponse {
func ( c * CentralCoordinator ) ClientHandler ( cl * Client ) * ClientResponse {
// look for sub coord
// returns reactor db info
c . SubCoordinators . Lock ( )
var err error
cr := & ClientResponse { Port : c . Ports [ cl . Type ] }
subcoord , ok := c . SubCoordinators . Directory [ cl . Type ]
if ! ok {
if cl . Type == "reactor" {
// Sub Coordinator does not exists, creating
// get reactor info
fmt . Printf ( "Cl type: %s, Port: %d\n" , cl . Type , c . Ports [ cl . Type ] )
go c . ReactorCoordinator . ClientHandler ( cl )
subcoord = NewSubCoordinator ( cl . Type , c . Ports [ cl . Type ] , c . Err )
// db info
c . SubCoordinators . Directory [ cl . Type ] = subcoord
cr . URL , cr . Org , cr . Token , cr . Bucket , err = c . Database . GetReactorClient ( cl . Id )
fmt . Printf ( "Creating subcord for %s on %d\n" , cl . Type , c . Ports [ cl . Type ] )
} else {
logging . Debug ( logging . DSpawn , "CC0 01 Created %v Coordinator" , cl . Type )
// throw error
err = errors . New ( fmt . Sprintf ( "Client type %s not recognized!" ) )
}
}
// unlocking
// returns based on cl type
c . SubCoordinators . Unlock ( )
// starts sub coord with client credentials
fmt . Printf ( "Starting subcoord client handler\n" )
go subcoord . ClientHandler ( cl )
fmt . Printf ( "Getting db info\n" )
// setting up client response
url , org , token , bucket , err := c . DB . GetReactorClient ( cl . Id )
fmt . Printf ( "Got URL: %s, Org: %s, Token: %s, Bucket: %b\n" , url , org , token , bucket )
if err != nil {
if err != nil {
c . Err <- err
c . Err <- err
}
}
return cr
// returning info
return & ClientResponse { URL : url , Org : org , Token : token , Bucket : bucket , Port : c . Ports [ cl . Type ] }
}
}
type ManagerInterface interface {
type ReactorCoordinator struct {
Start ( )
Port int ` mapstructure:"reactor" `
NewManager ( * Client , chan error ) GeneralManager
* ReactorManagers
GetManager ( int ) ( GeneralManager , bool )
Err chan error
AddManager ( int , GeneralManager )
pb . UnimplementedMonitoringServer
Register ( )
}
}
type GeneralManager interface {
type ReactorManagers struct {
// used by sub coordinator to interact with manager
Directory map [ int ] * ReactorManager
Start ( )
sync . RWMutex
UpdateClient ( * Client )
}
}
type SubCoordinator struct {
func NewReactorCoordinator ( errCh chan error ) ( * ReactorCoordinator , error ) {
Port int // port that we set up gRPC endpoint on
rmap := make ( map [ int ] * ReactorManager )
ManagerInterface // embed an interface to create/manager managers
rm := & ReactorManagers { Directory : rmap }
//*SystemViewer
c := & ReactorCoordinator { Err : errCh , ReactorManagers : rm }
Err chan error
return c , nil
}
}
type Managers struct {
func ( c * ReactorCoordinator ) Start ( ) error {
Directory map [ int ] interface { } // support for either manager
logging . Debug ( logging . DStart , "RCO 01 Starting!" )
sync . RWMutex // potential perf
// register grpc service
return c . Register ( )
}
}
// interface stuff
func ( c * ReactorCoordinator ) ClientHandler ( cl * Client ) {
func NewSubCoordinator ( clientType string , port int , errCh chan error ) * SubCoordinator {
// updates clients if nessecary
c := & SubCoordinator { Err : errCh }
if err := c . UpdateManager ( cl , c . Err ) ; err != nil {
//c.SystemViewer = sys
c . Err <- err
man , err := NewCoordinatorType ( clientType , errCh )
if err != nil {
errCh <- err
}
}
c . ManagerInterface = man
go man . Start ( )
go man . Register ( )
return c
}
}
func ( c * SubCoordinator ) ClientHandler ( cl * Client ) {
func ( m * ReactorManagers ) GetManager ( id int ) ( * ReactorManager , error ) {
// (creates and) notifies manager of client connection
m . RLock ( )
c . UpdateManager ( cl )
defer m . RUnlock ( )
}
func ( c * SubCoordinator ) UpdateManager ( cl * Client ) {
rm , exists := m . Directory [ id ]
// shouldn't happen all that often so should be fine to lock
fmt . Printf ( "Grabbing Manager\n" )
m , exists := c . GetManager ( cl . Id )
if ! exists {
if ! exists {
fmt . Printf ( "Creating Manager\n" )
return & ReactorManager { } , errors . New ( fmt . Sprintf ( "No manager for reactor %d!" , id ) )
m = c . NewManager ( cl , c . Err )
m . UpdateClient ( cl )
go c . AddManager ( cl . Id , m )
go m . Start ( )
}
}
go m . UpdateClient ( cl )
return rm , nil
}
func ( m * Managers ) AddManager ( id int , man GeneralManager ) {
m . Lock ( )
defer m . Unlock ( )
m . Directory [ id ] = man
}
}
func ( m * Managers) GetManager ( id int ) ( GeneralManager , bool ) {
func ( m * ReactorManagers ) UpdateManager ( cl * Client , errCh chan error ) error {
// just read locks and reuturns
// locking
m . RLock ( )
m . RLock ( )
defer m . RUnlock ( )
defer m . RUnlock ( )
man , exists := m . Directory [ id ]
rm , exists := m . Directory [ cl . Id ]
if ! exists {
if ! exists {
return nil , exists
logging . Debug ( logging . DClient , "RCO 01 starting manager for reactor client %v" , cl . Id )
rm = NewReactorManager ( errCh )
if err := rm . Start ( ) ; err != nil {
return err
}
m . Directory [ cl . Id ] = rm
}
}
return man . ( GeneralManager ) , exists
return rm. UpdateClient ( cl )
}
}
func NewCoordinatorType ( clientType string , err chan error ) ( ManagerInterface , error ) {
func ( r * ReactorCoordinator ) Register ( ) error {
lis , err := net . Listen ( "tcp" , fmt . Sprintf ( ":%v" , r . Port ) )
m := make ( map [ int ] interface { } )
if err != nil {
if clientType == "reactor" {
return err
c := & reactorCoordinator { }
//m := make(map[uint32]*ReactorManager)
c . Managers = & Managers { Directory : m }
return c , nil
} else if clientType == "tui" {
c := & reactorCoordinator { }
//m := make(map[uint32]*TUIManager)
//c.Managers = &Managers{Directory: m}
return c , errors . New ( fmt . Sprint ( "error, TUI Not impl" ) )
}
}
return & reactorCoordinator { } , errors . New ( "Unrecognized client type" )
grpcServer := grpc . NewServer ( )
pb . RegisterMonitoringServer ( grpcServer , r )
go grpcServer . Serve ( lis )
logging . Debug ( logging . DClient , "RCO ready for client requests" )
return nil
}
}
// creating sub coordinators for associated gRPC handlers
func ( r * ReactorCoordinator ) ReactorStatusHandler ( ctx context . Context , req * pb . ReactorStatusPing ) ( * pb . ReactorStatusResponse , error ) {
// reactor coordinator
rm , err := r . GetManager ( int ( req . GetId ( ) ) )
type reactorCoordinator struct {
// error checking
* Managers
if err != nil {
pb . UnimplementedMonitoringServer
return & pb . ReactorStatusResponse { } , err
}
func ( r * reactorCoordinator ) Start ( ) {
logging . Debug ( logging . DStart , "RCO 01 Starting!" )
}
func ( r * reactorCoordinator ) NewManager ( cl * Client , err chan error ) GeneralManager {
logging . Debug ( logging . DClient , "RCO 01 starting manager for %v client %v" , cl . Type , cl . Id )
return NewReactorManager ( cl , err )
}
func ( r * reactorCoordinator ) Register ( ) {
//conf := LoadConfig()
/ *
port , err := conf . GetPort ( "reactor" )
if err != nil {
panic ( err )
}
lis , err := net . Listen ( "tcp" , fmt . Sprintf ( ":%v" , port ) )
if err != nil {
panic ( err )
}
grpcServer := grpc . NewServer ( )
pb . RegisterMonitoringServer ( grpcServer , r )
go grpcServer . Serve ( lis )
logging . Debug ( logging . DClient , "RCO ready for client requests" )
* /
}
func ( r * reactorCoordinator ) ReactorStatusHandler ( ctx context . Context , req * pb . ReactorStatusPing ) ( * pb . ReactorStatusResponse , error ) {
m , exists := r . GetManager ( int ( req . GetId ( ) ) )
if ! exists {
return & pb . ReactorStatusResponse { } , errors . New ( "Manager doesn't exists for that client" )
}
rm , ok := m . ( * ReactorManager )
if ! ok {
return & pb . ReactorStatusResponse { } , errors . New ( "Manager is not a reactor manager!" )
}
}
return rm . ReactorStatusHandler ( ctx , req )
return rm . ReactorStatusHandler ( ctx , req )
}
}
// tui coordinator
/ *
type tuiCoordinator struct {
* Managers // by embedding general struct we allow coordinator to still call general funcs
pb . UnimplementedManagementServer
}
func ( t * tuiCoordinator ) Start ( ) {
logging . Debug ( logging . DStart , "TCO 01 Starting!" )
}
func ( t * tuiCoordinator ) NewManager ( cl * Client , err chan error ) GeneralManager {
logging . Debug ( logging . DClient , "TCO 01 starting manager for %v client %v" , cl . Type , cl . Id )
return NewTUIManager ( cl , err )
}
func ( t * tuiCoordinator ) Register ( ) {
/ *
conf := LoadConfig ( )
port , err := conf . GetPort ( "tui" )
if err != nil {
panic ( err )
}
lis , err := net . Listen ( "tcp" , fmt . Sprintf ( ":%v" , port ) )
if err != nil {
// rip
}
grpcServer := grpc . NewServer ( )
pb . RegisterManagementServer ( grpcServer , t )
go grpcServer . Serve ( lis )
logging . Debug ( logging . DClient , "TCO ready for client requests" )
* /
/ *
}
func ( t * tuiCoordinator ) GetDevices ( ctx context . Context , req * pb . GetDevicesRequest ) ( * pb . GetDevicesResponse , error ) {
// grpc handler to fwd to manager
m , exists := t . GetManager ( int ( req . GetClientId ( ) ) )
if ! exists {
// doesnt exist for some reason
return & pb . GetDevicesResponse { } , errors . New ( "Manager doesn't exists for client" )
}
tm , ok := m . ( * TUIManager )
if ! ok {
return & pb . GetDevicesResponse { } , errors . New ( "Manager is not of type TUI" )
}
return tm . GetDevices ( ctx , req )
}
// unimplemented bs for grpc
func ( t * tuiCoordinator ) DeleteReactor ( ctx context . Context , req * pb . DeleteReactorRequest ) ( * pb . DeleteReactorResponse , error ) {
// TODO
return & pb . DeleteReactorResponse { } , nil
}
func ( t * tuiCoordinator ) DeleteReactorDevice ( ctx context . Context , req * pb . DeleteReactorDeviceRequest ) ( * pb . DeleteReactorDeviceResponse , error ) {
// TODO
return & pb . DeleteReactorDeviceResponse { } , nil
}
* /