+func IsReady() bool {
+ return Rmr != nil && Rmr.IsReady() && Sdl != nil && Sdl.IsReady()
+}
+
+func SetReadyCB(cb ReadyCB, params interface{}) {
+ readyCb = cb
+ readyCbParams = params
+}
+
+func XappReadyCb(params interface{}) {
+ Alarm = NewAlarmClient(viper.GetString("moId"), viper.GetString("name"))
+ if readyCb != nil {
+ readyCb(readyCbParams)
+ }
+}
+
+func SetShutdownCB(cb ShutdownCB) {
+ shutdownCb = cb
+}
+
+func InstallSignalHandler() {
+ //
+ // Signal handlers to really exit program.
+ // shutdownCb can hang until application has
+ // made all needed gracefull shutdown actions
+ // hardcoded limit for shutdown is 20 seconds
+ //
+ interrupt := make(chan os.Signal, 1)
+ signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
+ //signal handler function
+ go func() {
+ for range interrupt {
+ if atomic.CompareAndSwapInt32(&shutdownFlag, 0, 1) {
+ // close function
+ go func() {
+ timeout := int(20)
+ sentry := make(chan struct{})
+ defer close(sentry)
+
+ // close callback
+ go func() {
+ if shutdownCb != nil {
+ shutdownCb()
+ }
+ sentry <- struct{}{}
+ }()
+ select {
+ case <-time.After(time.Duration(timeout) * time.Second):
+ Logger.Info("xapp-frame shutdown callback took more than %d seconds", timeout)
+ case <-sentry:
+ Logger.Info("xapp-frame shutdown callback handled within %d seconds", timeout)
+ }
+ os.Exit(0)
+ }()
+ } else {
+ newCnt := atomic.AddInt32(&shutdownCnt, 1)
+ Logger.Info("xapp-frame shutdown already ongoing. Forced exit counter %d/%d ", newCnt, 5)
+ if newCnt >= 5 {
+ Logger.Info("xapp-frame shutdown forced exit")
+ os.Exit(0)
+ }
+ continue
+ }
+
+ }
+ }()
+}
+