diff --git a/ConfigurationDB/CheckConfiguration.go b/ConfigurationDB/CheckConfiguration.go index c3b340c..2a5b69e 100644 --- a/ConfigurationDB/CheckConfiguration.go +++ b/ConfigurationDB/CheckConfiguration.go @@ -30,6 +30,7 @@ func checkConfiguration() { CheckSingleConfigurationPresentsAndAddIfMissing(`NumGenGetHandler`, `http://localhost:80/next/number`) CheckSingleConfigurationPresentsAndAddIfMissing(`NumGenBufferSize`, `12`) CheckSingleConfigurationPresentsAndAddIfMissing(`OceanHostnameAndPort`, `:60000`) + CheckSingleConfigurationPresentsAndAddIfMissing(`OceanServerPort`, `60000`) CheckSingleConfigurationPresentsAndAddIfMissing(`OceanUtilizeCPUs`, `2`) CheckSingleConfigurationPresentsAndAddIfMissing(`FilenameWebResources`, `web.zip`) CheckSingleConfigurationPresentsAndAddIfMissing(`MapStaticFiles2Root`, `false`) diff --git a/ConfigurationDB/Init.go b/ConfigurationDB/Init.go index 2722111..76cae61 100644 --- a/ConfigurationDB/Init.go +++ b/ConfigurationDB/Init.go @@ -26,6 +26,12 @@ func init() { return } + // In case of write operations, wait for the majority of servers to be done: + session.SetSafe(&mgo.Safe{WMode: "majority"}) + + // Set the consistency mode to read from any secondary server and write to the primary. + session.SetMode(mgo.Eventual, true) + // Get the collection: collection = db.C(config.ConfigDBConfigurationCollection) diff --git a/ICCC/HTTPConnector.go b/ICCC/HTTPConnector.go index a6fea9a..7039df8 100644 --- a/ICCC/HTTPConnector.go +++ b/ICCC/HTTPConnector.go @@ -14,6 +14,13 @@ func ICCCHandler(response http.ResponseWriter, request *http.Request) { } messageData := map[string][]string(request.PostForm) + + if len(messageData) < 3 { + Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityCritical, LM.ImpactCritical, LM.MessageNameNETWORK, `The ICCC message contains not enough data: At least the channel, command and password is required!`) + http.NotFound(response, request) + return + } + channel := messageData[`channel`][0] command := messageData[`command`][0] password := messageData[`InternalCommPassword`][0] diff --git a/ICCC/Init.go b/ICCC/Init.go index 818d05b..45cdc38 100644 --- a/ICCC/Init.go +++ b/ICCC/Init.go @@ -1,9 +1,7 @@ package ICCC -import "strings" import "container/list" import "github.com/SommerEngineering/Ocean/Tools" -import "github.com/SommerEngineering/Ocean/ConfigurationDB" import "github.com/SommerEngineering/Ocean/Log" import LM "github.com/SommerEngineering/Ocean/Log/Meta" @@ -14,13 +12,9 @@ func init() { cacheListenerDatabase = list.New() listeners = make(map[string]func(data map[string][]string)) - allHostsIPAddresses := Tools.ReadAllIPAddresses4ThisHost() - oceanHostnameAndPort := ConfigurationDB.Read(`OceanHostnameAndPort`) - port := oceanHostnameAndPort[strings.Index(oceanHostnameAndPort, `:`):] - correctAddressWithPort = allHostsIPAddresses[0] + port + // Using the local IP address and NOT the configuration "OceanHostnameAndPort": + correctAddressWithPort = Tools.LocalIPAddressAndPort() initDB() registerHost2Database() - cacheTimerLogic(false) - initCacheTimer() } diff --git a/ICCC/ListenerCache.go b/ICCC/ListenerCache.go index 4fc95d4..cff4dbb 100644 --- a/ICCC/ListenerCache.go +++ b/ICCC/ListenerCache.go @@ -8,7 +8,31 @@ import "github.com/SommerEngineering/Ocean/ICCC/Scheme" import "github.com/SommerEngineering/Ocean/Log" import LM "github.com/SommerEngineering/Ocean/Log/Meta" +func InitCacheNow() { + startCacheTimerLock.Lock() + defer startCacheTimerLock.Unlock() + + if cacheTimerRunning { + return + } + + cacheTimerLogic(false) +} + +func StartCacheTimer() { + initCacheTimer() +} + func initCacheTimer() { + startCacheTimerLock.Lock() + defer startCacheTimerLock.Unlock() + + if cacheTimerRunning { + return + } else { + cacheTimerRunning = true + } + go func() { for { cacheTimerLogic(true) diff --git a/ICCC/Message2Data.go b/ICCC/Message2Data.go index d5dd614..fa01fbe 100644 --- a/ICCC/Message2Data.go +++ b/ICCC/Message2Data.go @@ -5,18 +5,17 @@ import "reflect" import "strconv" func message2Data(channel, command string, message interface{}) (data map[string][]string) { + data = make(map[string][]string) + data[`command`] = []string{command} + data[`channel`] = []string{channel} + if message == nil { - data = make(map[string][]string) return } element := reflect.ValueOf(message) elementType := element.Type() - data = make(map[string][]string) - data[`command`] = []string{command} - data[`channel`] = []string{channel} - for i := 0; i < element.NumField(); i++ { field := element.Field(i) keyName := elementType.Field(i).Name diff --git a/ICCC/Variables.go b/ICCC/Variables.go index c8e25ed..db65050 100644 --- a/ICCC/Variables.go +++ b/ICCC/Variables.go @@ -24,5 +24,7 @@ var ( listenersLock sync.RWMutex = sync.RWMutex{} cacheListenerDatabase *list.List = nil cacheListenerDatabaseLock sync.RWMutex = sync.RWMutex{} + startCacheTimerLock sync.Mutex = sync.Mutex{} + cacheTimerRunning bool = false correctAddressWithPort string = `` ) diff --git a/System/ICCCStart.go b/System/ICCCStart.go index 503cd1c..ca8135b 100644 --- a/System/ICCCStart.go +++ b/System/ICCCStart.go @@ -1,8 +1,11 @@ package System +import "github.com/SommerEngineering/Ocean/ICCC" import "github.com/SommerEngineering/Ocean/Log" import LM "github.com/SommerEngineering/Ocean/Log/Meta" func icccSystemStart(data map[string][]string) { - Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `The system is now up and ready.`) + _, _, obj := ICCC.Data2Message(&ICCCStartUpMessage{}, data) + messageData := obj.(*ICCCStartUpMessage) + Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `ICCC message: The server is now up and ready.`, messageData.IPAddressAndPort) } diff --git a/System/ICCCStartUp.go b/System/ICCCStartUp.go new file mode 100644 index 0000000..3acee47 --- /dev/null +++ b/System/ICCCStartUp.go @@ -0,0 +1,5 @@ +package System + +type ICCCStartUpMessage struct { + IPAddressAndPort string +} diff --git a/System/Init.go b/System/Init.go index 761f795..58783d9 100644 --- a/System/Init.go +++ b/System/Init.go @@ -84,13 +84,17 @@ func initSystem() { // * then, these system handlers are called (order: last comed, first served) // * and finally, the logging device / system gets closed Shutdown.InitShutdown() - Shutdown.AddShutdownHandler(ICCC.ShutdownFunction{}) - Shutdown.AddShutdownHandler(NumGen.ShutdownFunction{}) Shutdown.AddShutdownHandler(ConfigurationDB.ShutdownFunction{}) Shutdown.AddShutdownHandler(CustomerDB.ShutdownFunction{}) + Shutdown.AddShutdownHandler(ICCC.ShutdownFunction{}) + Shutdown.AddShutdownHandler(NumGen.ShutdownFunction{}) // The logging subsystem is not registered here, because it will be automated called at the end // Register all system ICCC commands: ICCC.Registrar(ICCC.ChannelSYSTEM, `System::Start`, icccSystemStart) + + // Start the ICCC Listener Cache: + ICCC.InitCacheNow() // Blocking, until the job is done + ICCC.StartCacheTimer() } diff --git a/System/Start.go b/System/Start.go index 11aa38e..dd763ec 100644 --- a/System/Start.go +++ b/System/Start.go @@ -1,18 +1,20 @@ package System import "net/http" -import "github.com/SommerEngineering/Ocean/ConfigurationDB" +import "github.com/SommerEngineering/Ocean/Tools" import "github.com/SommerEngineering/Ocean/ICCC" import "github.com/SommerEngineering/Ocean/Log" import LM "github.com/SommerEngineering/Ocean/Log/Meta" func StartAndBlockForever() { - oceanHostnameAndPort := ConfigurationDB.Read(`OceanHostnameAndPort`) + ipAddressPort := Tools.LocalIPAddressAndPort() - // Init ICCC: - ICCC.WriteMessage2All(ICCC.ChannelSYSTEM, `System::Start`, nil) + // Tell the whole cluster, that we are up and ready: + data := ICCCStartUpMessage{} + data.IPAddressAndPort = ipAddressPort + ICCC.WriteMessage2All(ICCC.ChannelSYSTEM, `System::Start`, data) // Start and block: - Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `Web server is now listening.`, `Configuration for hostname and port.`, oceanHostnameAndPort) - http.ListenAndServe(oceanHostnameAndPort, nil) + Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `Web server is now listening.`, `Configuration for hostname and port.`, ipAddressPort) + http.ListenAndServe(ipAddressPort, nil) } diff --git a/Templates/Init.go b/Templates/Init.go index 2262d3b..9da9537 100644 --- a/Templates/Init.go +++ b/Templates/Init.go @@ -6,6 +6,7 @@ import "html/template" import "io/ioutil" import "archive/zip" import "github.com/SommerEngineering/Ocean/CustomerDB" +import "github.com/SommerEngineering/Ocean/Tools" import "github.com/SommerEngineering/Ocean/Log" import LM "github.com/SommerEngineering/Ocean/Log/Meta" @@ -21,6 +22,7 @@ func init() { return } else { defer gridFile.Close() + Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameCONFIGURATION, `Read the templates.zip file from the grid file system.`, `Upload time UTC: `+Tools.FormatTime(gridFile.UploadDate().UTC())) if data, ioError := ioutil.ReadAll(gridFile); ioError != nil { Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityCritical, LM.ImpactCritical, LM.MessageNameDATABASE, `Was not able to read the templates.`, ioError.Error()) return diff --git a/Tools/FormatTime.go b/Tools/FormatTime.go new file mode 100644 index 0000000..f135765 --- /dev/null +++ b/Tools/FormatTime.go @@ -0,0 +1,58 @@ +package Tools + +import "time" +import "fmt" +import "strconv" + +func FormatTime(t1 time.Time) (result string) { + var year int = t1.Year() + var month int = int(t1.Month()) + var day int = int(t1.Day()) + var minutes int = int(t1.Minute()) + var hours int = int(t1.Hour()) + var seconds int = int(t1.Second()) + var milliseconds int = int(float64(t1.Nanosecond()) / 1000000.0) + + var monthText, dayText, minutesText, hoursText, secondsText, millisecondsText string + + if month >= 1 && month <= 9 { + monthText = fmt.Sprintf(`0%d`, month) + } else { + monthText = strconv.Itoa(month) + } + + if day >= 1 && day <= 9 { + dayText = fmt.Sprintf(`0%d`, day) + } else { + dayText = strconv.Itoa(day) + } + + if minutes >= 0 && minutes <= 9 { + minutesText = fmt.Sprintf(`0%d`, minutes) + } else { + minutesText = strconv.Itoa(minutes) + } + + if hours >= 0 && hours <= 9 { + hoursText = fmt.Sprintf(`0%d`, hours) + } else { + hoursText = strconv.Itoa(hours) + } + + if seconds >= 0 && seconds <= 9 { + secondsText = fmt.Sprintf(`0%d`, seconds) + } else { + secondsText = strconv.Itoa(seconds) + } + + if milliseconds >= 0 && milliseconds <= 9 { + millisecondsText = fmt.Sprintf(`00%d`, milliseconds) + } else if milliseconds >= 10 && milliseconds <= 99 { + millisecondsText = fmt.Sprintf(`0%d`, milliseconds) + } else { + millisecondsText = strconv.Itoa(milliseconds) + } + + result = fmt.Sprintf(`%d%s%s %s%s%s.%s`, year, monthText, dayText, hoursText, minutesText, secondsText, millisecondsText) + return +} diff --git a/Tools/Init.go b/Tools/Init.go index bfc73ea..6debea6 100644 --- a/Tools/Init.go +++ b/Tools/Init.go @@ -24,4 +24,9 @@ func init() { // Set the seed for random: rand.Seed(time.Now().Unix()) + + // Build the local IP address and port: + allHostsIPAddresses := ReadAllIPAddresses4ThisHost() + port := ConfigurationDB.Read(`OceanServerPort`) + localIPAddressAndPort = allHostsIPAddresses[0] + `:` + port } diff --git a/Tools/LocalIPAddressAndPort.go b/Tools/LocalIPAddressAndPort.go new file mode 100644 index 0000000..b5d0067 --- /dev/null +++ b/Tools/LocalIPAddressAndPort.go @@ -0,0 +1,6 @@ +package Tools + +func LocalIPAddressAndPort() (address string) { + address = localIPAddressAndPort + return +} diff --git a/Tools/Variables.go b/Tools/Variables.go index d1711ac..f9e8a54 100644 --- a/Tools/Variables.go +++ b/Tools/Variables.go @@ -3,8 +3,9 @@ package Tools import LM "github.com/SommerEngineering/Ocean/Log/Meta" var ( - senderName LM.Sender = `System::Tools` - hostname string = `unknown` - ipAddresses []string = nil - internalCommPassword string = `` + senderName LM.Sender = `System::Tools` + hostname string = `unknown` + localIPAddressAndPort string = `127.0.0.1:60000` + ipAddresses []string = nil + internalCommPassword string = `` )