diff --git a/ICCC/ICCCRegisterCommand.go b/ICCC/ICCCRegisterCommand.go new file mode 100644 index 0000000..65eedfa --- /dev/null +++ b/ICCC/ICCCRegisterCommand.go @@ -0,0 +1,45 @@ +package ICCC + +import ( + "fmt" + "github.com/SommerEngineering/Ocean/ICCC/SystemMessages" + "github.com/SommerEngineering/Ocean/Log" + LM "github.com/SommerEngineering/Ocean/Log/Meta" +) + +// The receiver function for the ICCC message, that registers a command. +func ICCCRegisterCommand(data map[string][]string) (result map[string][]string) { + + // Recover from errors: + defer func() { + if err := recover(); err != nil { + Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, fmt.Sprintf("Was not able to execute the ICCC register command message. %s", err)) + result = make(map[string][]string, 0) + return + } + }() + + // Converts the HTTP form data into an object: + _, _, obj := Data2Message(SystemMessages.ICCCRegisterListener{}, data) + + // Was it possible to convert the data? + if obj != nil { + // Cast the object to the right type: + messageData := obj.(SystemMessages.ICCCRegisterListener) + + // Provide a log entry: + Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `ICCC message: Should register another command.`, `channel=`+messageData.Channel, `command=`+messageData.Command, `IPAddressPort=`+messageData.IPAddressPort, fmt.Sprintf(`isActive=%v`, messageData.IsActive)) + + // Execute the command: + registerCommand2Database(messageData.Channel, messageData.Command, messageData.IPAddressPort, messageData.IsActive) + + // An answer is necessary: + return Message2Data(``, ``, SystemMessages.AnswerACK) + } else { + Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `ICCC message: Was not able to create the message.`) + } + + // In any other error case: + result = make(map[string][]string, 0) + return +} diff --git a/ICCC/ICCCRegisterHost.go b/ICCC/ICCCRegisterHost.go new file mode 100644 index 0000000..d4aeb1d --- /dev/null +++ b/ICCC/ICCCRegisterHost.go @@ -0,0 +1,45 @@ +package ICCC + +import ( + "fmt" + "github.com/SommerEngineering/Ocean/ICCC/SystemMessages" + "github.com/SommerEngineering/Ocean/Log" + LM "github.com/SommerEngineering/Ocean/Log/Meta" +) + +// The receiver function for the ICCC message, that registers a host. +func ICCCRegisterHost(data map[string][]string) (result map[string][]string) { + + // Recover from errors: + defer func() { + if err := recover(); err != nil { + Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, fmt.Sprintf("Was not able to execute the ICCC register host message. %s", err)) + result = make(map[string][]string, 0) + return + } + }() + + // Converts the HTTP form data into an object: + _, _, obj := Data2Message(SystemMessages.ICCCRegisterHost{}, data) + + // Was it possible to convert the data? + if obj != nil { + // Cast the object to the right type: + messageData := obj.(SystemMessages.ICCCRegisterHost) + + // Provide a log entry: + Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `ICCC message: Should register another host.`, messageData.Hostname, messageData.IPAddressPort) + + // Execute the command: + registerHost2Database(messageData.Hostname, messageData.IPAddressPort) + + // An answer is necessary: + return Message2Data(``, ``, SystemMessages.AnswerACK) + } else { + Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `ICCC message: Was not able to create the message.`) + } + + // In any other error case: + result = make(map[string][]string, 0) + return +} diff --git a/ICCC/Init.go b/ICCC/Init.go index f7fee95..53578c4 100644 --- a/ICCC/Init.go +++ b/ICCC/Init.go @@ -25,5 +25,5 @@ func init() { initDB() // Register this server to the listener (if not present): - registerHost2Database() + registerThisHost2Database() } diff --git a/ICCC/Register2Database.go b/ICCC/Register2Database.go deleted file mode 100644 index e19e3d6..0000000 --- a/ICCC/Register2Database.go +++ /dev/null @@ -1,56 +0,0 @@ -package ICCC - -import ( - "github.com/SommerEngineering/Ocean/ICCC/Scheme" - "github.com/SommerEngineering/Ocean/Log" - LM "github.com/SommerEngineering/Ocean/Log/Meta" - "gopkg.in/mgo.v2/bson" -) - -// The internal function to register a command to ICCC. -func register2Database(channel, command string) { - Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `Register this ICCC command in to the database.`, `channel=`+channel, `command=`+command) - - // - // Case: Exist and active :) - // - emptyEntry := Scheme.Listener{} - selection := bson.D{{`Channel`, channel}, {`Command`, command}, {`IPAddressPort`, correctAddressWithPort}, {`IsActive`, true}} - count1, _ := collectionListener.Find(selection).Count() - - if count1 == 1 { - Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.SeverityHigh, LM.ImpactHigh, LM.MessageNameSTARTUP, `This ICCC command is already known and active.`, `Please shutdown the system next time!`) - return - } - - // - // Case: Exist but not active - // - selection = bson.D{{`Channel`, channel}, {`Command`, command}, {`IPAddressPort`, correctAddressWithPort}, {`IsActive`, false}} - notActiveEntry := Scheme.Listener{} - collectionListener.Find(selection).One(¬ActiveEntry) - - if notActiveEntry != emptyEntry { - notActiveEntry.IsActive = true - collectionListener.Update(selection, notActiveEntry) - Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.SeverityNone, LM.ImpactNone, LM.MessageNameSTARTUP, `This ICCC command is already known but it was not active.`, `The command is active now!`) - return - } - - // - // Case: Not exist - // - Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelWARN, LM.SeverityCritical, LM.ImpactNone, LM.MessageNameCONFIGURATION, `This ICCC command is not known.`, `Create now a new entry!`) - - entry := Scheme.Listener{} - entry.Channel = channel - entry.Command = command - entry.IsActive = true - entry.IPAddressPort = correctAddressWithPort - - if err := collectionListener.Insert(entry); err != nil { - Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityCritical, LM.ImpactCritical, LM.MessageNameDATABASE, `It was not possible to add this ICCC command!`, err.Error(), `channel=`+channel, `command=`+command) - } else { - Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameCONFIGURATION, `This ICCC command is now known and active.`) - } -} diff --git a/ICCC/RegisterCommand2Database.go b/ICCC/RegisterCommand2Database.go new file mode 100644 index 0000000..15f3ed6 --- /dev/null +++ b/ICCC/RegisterCommand2Database.go @@ -0,0 +1,44 @@ +package ICCC + +import ( + "fmt" + "github.com/SommerEngineering/Ocean/ICCC/Scheme" + "github.com/SommerEngineering/Ocean/Log" + LM "github.com/SommerEngineering/Ocean/Log/Meta" + "gopkg.in/mgo.v2/bson" +) + +// The internal function to register a command to ICCC. +func registerCommand2Database(channel, command, ipAddressPort string, isActive bool) { + Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `Register this ICCC command in to the database.`, `channel=`+channel, `command=`+command, `IPAddressPort=`+ipAddressPort, fmt.Sprintf("isActive=%v", isActive)) + + entry := Scheme.Listener{} + entry.Channel = channel + entry.Command = command + entry.IsActive = isActive + entry.IPAddressPort = ipAddressPort + + // + // Case: Exists? + // + selection := bson.D{{`Channel`, channel}, {`Command`, command}, {`IPAddressPort`, ipAddressPort}} + count1, _ := collectionListener.Find(selection).Count() + if count1 == 1 { + // + // Case: Exist but maybe not active + // + collectionListener.Update(selection, entry) + Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameCONFIGURATION, `Updating the existing ICCC command.`, `channel=`+channel, `command=`+command, `IPAddressPort=`+ipAddressPort) + return + } + + // + // Case: Not exist + // + Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelWARN, LM.SeverityCritical, LM.ImpactNone, LM.MessageNameCONFIGURATION, `This ICCC command is not known.`, `Create now a new entry!`, `channel=`+channel, `command=`+command, `IPAddressPort=`+ipAddressPort) + if err := collectionListener.Insert(entry); err != nil { + Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityCritical, LM.ImpactCritical, LM.MessageNameDATABASE, `It was not possible to add this ICCC command!`, err.Error(), `channel=`+channel, `command=`+command, `IPAddressPort=`+ipAddressPort) + } else { + Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameCONFIGURATION, `This ICCC command is now known and active.`, `channel=`+channel, `command=`+command, `IPAddressPort=`+ipAddressPort) + } +} diff --git a/ICCC/RegisterHost2Database.go b/ICCC/RegisterHost2Database.go index df8ba78..d8cd2d8 100644 --- a/ICCC/RegisterHost2Database.go +++ b/ICCC/RegisterHost2Database.go @@ -4,17 +4,16 @@ import ( "github.com/SommerEngineering/Ocean/ICCC/Scheme" "github.com/SommerEngineering/Ocean/Log" LM "github.com/SommerEngineering/Ocean/Log/Meta" - "github.com/SommerEngineering/Ocean/Tools" "gopkg.in/mgo.v2/bson" ) -// Function to register this server to the ICCC. -func registerHost2Database() { +// Function to register a server to the ICCC. +func registerHost2Database(hostname, ipAddressPort string) { // Create the host entry: host := Scheme.Host{} - host.Hostname = Tools.ThisHostname() - host.IPAddressPort = correctAddressWithPort + host.Hostname = hostname + host.IPAddressPort = ipAddressPort // The query to find already existing entries: selection := bson.D{{`Hostname`, host.Hostname}, {`IPAddressPort`, host.IPAddressPort}} diff --git a/ICCC/RegisterLocalCommand2Database.go b/ICCC/RegisterLocalCommand2Database.go new file mode 100644 index 0000000..ea4472c --- /dev/null +++ b/ICCC/RegisterLocalCommand2Database.go @@ -0,0 +1,12 @@ +package ICCC + +// The internal function to register a local command to ICCC. +func registerLocalCommand2Database(channel, command string) { + /* + Cannot use here the ICCC command to register this command. + Because, this host is maybe the first one. In that case, + there would be no server which can execute the ICCC command. + Therefore, every Ocean server registers the own commans directly. + */ + registerCommand2Database(channel, command, correctAddressWithPort, true) +} diff --git a/ICCC/RegisterThisHost2Database.go b/ICCC/RegisterThisHost2Database.go new file mode 100644 index 0000000..841c26c --- /dev/null +++ b/ICCC/RegisterThisHost2Database.go @@ -0,0 +1,16 @@ +package ICCC + +import ( + "github.com/SommerEngineering/Ocean/Tools" +) + +// Function to register this server to the ICCC. +func registerThisHost2Database() { + /* + Cannot use here the ICCC command to register this host. + Because, this host is maybe the first one. In that case, + there would be no server which can execute the ICCC command. + Therefore, every Ocean server registers the own host directly. + */ + registerHost2Database(Tools.ThisHostname(), correctAddressWithPort) +} diff --git a/ICCC/Registrar.go b/ICCC/Registrar.go index 4330235..c0b41cc 100644 --- a/ICCC/Registrar.go +++ b/ICCC/Registrar.go @@ -12,7 +12,7 @@ func Registrar(channel, command string, callback func(data map[string][]string) defer listenersLock.Unlock() // Write the command to the database: - register2Database(channel, command) + registerLocalCommand2Database(channel, command) // Register the command at the local cache: listeners[fmt.Sprintf(`%s::%s`, channel, command)] = callback diff --git a/ICCC/SystemMessages/ICCCNumGen.go b/ICCC/SystemMessages/ICCCNumGen.go new file mode 100644 index 0000000..ebe07e6 --- /dev/null +++ b/ICCC/SystemMessages/ICCCNumGen.go @@ -0,0 +1,10 @@ +package SystemMessages + +// The message to request a new number from NumGen package. +type ICCCNumGenNext struct { +} + +// The response to the Numgen request. +type ICCCAnswerNumGen struct { + Number int64 +} diff --git a/ICCC/SystemMessages/ICCCRegisterHost.go b/ICCC/SystemMessages/ICCCRegisterHost.go new file mode 100644 index 0000000..0ba54ba --- /dev/null +++ b/ICCC/SystemMessages/ICCCRegisterHost.go @@ -0,0 +1,7 @@ +package SystemMessages + +// The message to register a host to ICCC. +type ICCCRegisterHost struct { + Hostname string // The hostname for the end-point + IPAddressPort string // The IP address and port for the end-point +} diff --git a/ICCC/SystemMessages/ICCCRegisterListener.go b/ICCC/SystemMessages/ICCCRegisterListener.go new file mode 100644 index 0000000..4f0378e --- /dev/null +++ b/ICCC/SystemMessages/ICCCRegisterListener.go @@ -0,0 +1,9 @@ +package SystemMessages + +// The message to register a command/listener to ICCC. +type ICCCRegisterListener struct { + Channel string // The channel for the provided command + Command string // The provided command + IsActive bool // Is the command active? + IPAddressPort string // The IP address and port for the end-point +} diff --git a/ICCC/SystemMessages/ICCCStartup.go b/ICCC/SystemMessages/ICCCStartup.go index 5aa99b7..9dd2cd9 100644 --- a/ICCC/SystemMessages/ICCCStartup.go +++ b/ICCC/SystemMessages/ICCCStartup.go @@ -2,6 +2,6 @@ package SystemMessages // Message type for the startup message: type ICCCStartUpMessage struct { - PublicIPAddressAndPort string - AdminIPAddressAndPort string + PublicIPAddressAndPort string // The public web server's IP address and port + AdminIPAddressAndPort string // The private admin server's IP address and port } diff --git a/NumGen/ICCCNextNumber.go b/NumGen/ICCCNextNumber.go new file mode 100644 index 0000000..31e1d57 --- /dev/null +++ b/NumGen/ICCCNextNumber.go @@ -0,0 +1,45 @@ +package NumGen + +import ( + "fmt" + "github.com/SommerEngineering/Ocean/ICCC" + "github.com/SommerEngineering/Ocean/ICCC/SystemMessages" + "github.com/SommerEngineering/Ocean/Log" + LM "github.com/SommerEngineering/Ocean/Log/Meta" +) + +// The receiver function for the ICCC message, that registers a command. +func ICCCNextNumber(data map[string][]string) (result map[string][]string) { + + // Recover from errors: + defer func() { + if err := recover(); err != nil { + Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, fmt.Sprintf("Was not able to execute the ICCC next number command message. %s", err)) + result = make(map[string][]string, 0) + return + } + }() + + // Converts the HTTP form data into an object: + _, _, obj := ICCC.Data2Message(SystemMessages.ICCCNumGenNext{}, data) + + // Was it possible to convert the data? + if obj != nil { + // Cast the object to the right type (just as check): + _ = obj.(SystemMessages.ICCCNumGenNext) + + // Execute the command: + nextNumber := GetUniqueID() + + // An answer is necessary: + answer := SystemMessages.ICCCAnswerNumGen{} + answer.Number = nextNumber + return ICCC.Message2Data(``, ``, answer) + } else { + Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `ICCC message: Was not able to create the message.`) + } + + // In any other error case: + result = make(map[string][]string, 0) + return +} diff --git a/System/InitSystem.go b/System/InitSystem.go index 8d15d40..bf98703 100644 --- a/System/InitSystem.go +++ b/System/InitSystem.go @@ -98,6 +98,9 @@ func initSystem() { // Register all system ICCC commands: ICCC.Registrar(ICCC.ChannelSYSTEM, `System::Start`, icccSystemStart) + ICCC.Registrar(ICCC.ChannelICCC, `ICCC::RegisterHost`, ICCC.ICCCRegisterHost) + ICCC.Registrar(ICCC.ChannelICCC, `ICCC::RegisterCommand`, ICCC.ICCCRegisterCommand) + ICCC.Registrar(ICCC.ChannelNUMGEN, `NumGen::Next`, NumGen.ICCCNextNumber) // Start the ICCC Listener Cache: ICCC.InitCacheNow() // Blocking, until the job is done