1
0
Fork 0
mirror of https://github.com/postmannen/ctrl.git synced 2024-12-14 12:37:31 +00:00
ctrl/subscriberMethodTypes.go

233 lines
6.7 KiB
Go
Raw Normal View History

// The structure of how to add new method types to the system.
// -----------------------------------------------------------
// All methods need 3 things:
// - A type definition
// - The type needs a getKind method
// - The type needs a handler method
// Overall structure example shown below.
//
// ---
// type methodCommandCLICommand struct {
// commandOrEvent CommandOrEvent
// }
//
// func (m methodCommandCLICommand) getKind() CommandOrEvent {
// return m.commandOrEvent
// }
//
// func (m methodCommandCLICommand) handler(s *server, message Message, node string) ([]byte, error) {
// ...
// ...
// outMsg := []byte(fmt.Sprintf("confirmed from node: %v: messageID: %v\n---\n%s---", node, message.ID, out))
// return outMsg, nil
// }
//
// ---
// You also need to make a constant for the Method, and add
// that constant as the key in the map, where the value is
// the actual type you want to map it to with a handler method.
// You also specify if it is a Command or Event, and if it is
// ACK or NACK.
// Check out the existing code below for more examples.
package steward
import (
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
)
// ------------------------------------------------------------
// The constants that will be used throughout the system for
// when specifying what kind of Method to send or work with.
const (
// Shell command to be executed via f.ex. bash
CLICommand Method = "CLICommand"
// Send text logging to some host
TextLogging Method = "TextLogging"
// Send Hello I'm here message
SayHello Method = "SayHello"
// Error log methods to centralError
ErrorLog Method = "ErrorLog"
)
// Method is used to specify the actual function/method that
// is represented in a typed manner.
type Method string
// The mapping of all the method constants specified, what type
// it references, and the kind if it is an Event or Command, and
// if it is ACK or NACK.
// Allowed values for the commandOrEvent field are:
// - CommandACK
// - CommandNACK
// - EventACK
// - EventNack
func (m Method) GetMethodsAvailable() MethodsAvailable {
ma := MethodsAvailable{
2021-03-05 12:10:46 +00:00
methodhandlers: map[Method]methodHandler{
CLICommand: methodCommandCLICommand{
commandOrEvent: CommandACK,
},
TextLogging: methodEventTextLogging{
commandOrEvent: EventACK,
},
SayHello: methodEventSayHello{
commandOrEvent: EventNACK,
},
ErrorLog: methodEventErrorLog{
commandOrEvent: EventACK,
},
},
}
return ma
}
// getHandler will check the methodsAvailable map, and return the
// method handler for the method given
// as input argument.
func (m Method) getHandler(method Method) methodHandler {
ma := m.GetMethodsAvailable()
2021-03-05 12:10:46 +00:00
mh := ma.methodhandlers[method]
return mh
}
type MethodsAvailable struct {
2021-03-05 12:10:46 +00:00
methodhandlers map[Method]methodHandler
}
// Check if exists will check if the Method is defined. If true the bool
// value will be set to true, and the methodHandler function for that type
// will be returned.
func (ma MethodsAvailable) CheckIfExists(m Method) (methodHandler, bool) {
2021-03-05 12:10:46 +00:00
mFunc, ok := ma.methodhandlers[m]
if ok {
2021-02-16 03:57:54 +00:00
// fmt.Printf("******THE TOPIC EXISTS: %v******\n", m)
return mFunc, true
} else {
2021-02-16 03:57:54 +00:00
// fmt.Printf("******THE TOPIC DO NOT EXIST: %v******\n", m)
return nil, false
}
}
// ------------------------------------------------------------
// Subscriber method handlers
// ------------------------------------------------------------
type methodHandler interface {
handler(server *server, proc process, message Message, node string) ([]byte, error)
getKind() CommandOrEvent
}
// -----
type methodCommandCLICommand struct {
commandOrEvent CommandOrEvent
}
func (m methodCommandCLICommand) getKind() CommandOrEvent {
return m.commandOrEvent
}
func (m methodCommandCLICommand) handler(s *server, proc process, message Message, node string) ([]byte, error) {
// Since the command to execute is at the first position in the
// slice we need to slice it out. The arguments are at the
// remaining positions.
c := message.Data[0]
a := message.Data[1:]
cmd := exec.Command(c, a...)
//cmd.Stdout = os.Stdout
out, err := cmd.CombinedOutput()
if err != nil {
log.Printf("error: execution of command failed: %v\n", err)
}
outMsg := []byte(fmt.Sprintf("confirmed from node: %v: messageID: %v\n---\n%s---", node, message.ID, out))
return outMsg, nil
}
// -----
type methodEventTextLogging struct {
commandOrEvent CommandOrEvent
}
func (m methodEventTextLogging) getKind() CommandOrEvent {
return m.commandOrEvent
}
func (m methodEventTextLogging) handler(s *server, proc process, message Message, node string) ([]byte, error) {
sub := Subject{
ToNode: string(message.ToNode),
CommandOrEvent: proc.subject.CommandOrEvent,
Method: message.Method,
}
logFile := filepath.Join(s.configuration.SubscribersDataFolder, string(sub.name())+"-"+string(message.FromNode))
f, err := os.OpenFile(logFile, os.O_APPEND|os.O_RDWR|os.O_CREATE, os.ModeAppend)
if err != nil {
log.Printf("error: methodEventTextLogging.handler: failed to open file: %v\n", err)
return nil, err
}
defer f.Close()
for _, d := range message.Data {
_, err := f.Write([]byte(d))
f.Sync()
if err != nil {
log.Printf("error: methodEventTextLogging.handler: failed to write to file: %v\n", err)
}
//s.subscriberServices.logCh <- []byte(d)
}
outMsg := []byte("confirmed from: " + node + ": " + fmt.Sprint(message.ID))
return outMsg, nil
}
// -----
type methodEventSayHello struct {
commandOrEvent CommandOrEvent
}
func (m methodEventSayHello) getKind() CommandOrEvent {
return m.commandOrEvent
}
func (m methodEventSayHello) handler(s *server, proc process, message Message, node string) ([]byte, error) {
2021-03-05 12:10:46 +00:00
//fmt.Printf("-- DEBUG 3.1: %#v, %#v, %#v\n\n", proc.subject.name(), proc.procFunc, proc.procFuncCh)
//pn := processNameGet(proc.subject.name(), processKindSubscriber)
//fmt.Printf("-- DEBUG 3.2: pn = %#v\n\n", pn)
log.Printf("<--- Received hello from %#v\n", message.FromNode)
// Since the handler is only called to handle a specific type of message we need
// to store it elsewhere, and choice for now is under s.metrics.sayHelloNodes
// send the message to the procFuncCh which is running alongside the process
// and can hold registries and handle special things for an individual process.
proc.procFuncCh <- message
outMsg := []byte("confirmed from: " + node + ": " + fmt.Sprint(message.ID))
return outMsg, nil
}
// ---
type methodEventErrorLog struct {
commandOrEvent CommandOrEvent
}
func (m methodEventErrorLog) getKind() CommandOrEvent {
return m.commandOrEvent
}
func (m methodEventErrorLog) handler(s *server, proc process, message Message, node string) ([]byte, error) {
log.Printf("<--- Received error from: %v, containing: %v", message.FromNode, message.Data)
return nil, nil
}