github.com/geniusesgroup/libgo@v0.0.0-20220713101832-828057a9d3d4/achaemenid/application.go (about)

     1  /* For license and copyright information please see LEGAL file in repository */
     2  
     3  package achaemenid
     4  
     5  import (
     6  	goos "os"
     7  	"os/signal"
     8  	"sync"
     9  	"syscall"
    10  	"time"
    11  
    12  	"../connection"
    13  	er "../error"
    14  	"../ganjine"
    15  	"../log"
    16  	"../node"
    17  	"../protocol"
    18  	"../service"
    19  )
    20  
    21  // App is the base object that use by other part of app and platforms!
    22  // It is implement protocol.Application interface
    23  var App appStructure
    24  
    25  // appStructure represents application (server or client) requirements data to serving some functionality such as networks, ...
    26  type appStructure struct {
    27  	softwareStatus    protocol.SoftwareStatus
    28  	state             protocol.ApplicationState
    29  	stateListeners    []chan protocol.ApplicationState
    30  	stateChangeLocker sync.Mutex
    31  
    32  	Cryptography cryptography
    33  
    34  	ganjine.Cluster
    35  	log.Logger
    36  	node.Nodes
    37  	service.Services
    38  	er.Errors
    39  	connection.Connections
    40  
    41  	netAppMux
    42  }
    43  
    44  func (app *appStructure) SoftwareStatus() protocol.SoftwareStatus { return app.softwareStatus }
    45  func (app *appStructure) Status() protocol.ApplicationState       { return app.state }
    46  func (app *appStructure) NotifyState(notifyBy chan protocol.ApplicationState) {
    47  	app.stateListeners = append(app.stateListeners, notifyBy)
    48  }
    49  
    50  // Init method use to initialize app object with default data in second phase.
    51  func (app *appStructure) Init() {
    52  	defer app.PanicHandler()
    53  
    54  	protocol.App.Log(log.InfoEvent(domainEnglish, "-----------------------------Achaemenid Application-----------------------------"))
    55  	protocol.App.Log(log.InfoEvent(domainEnglish, "Try to initialize application..."))
    56  
    57  	app.changeState(protocol.ApplicationStateStarting)
    58  
    59  	if app.Manifest.DataNodes.TotalZones < 3 {
    60  		protocol.App.Log(protocol.Log_Warning, "ReplicationNumber set below 3! Loose write ability until two replication available again on replication failure!")
    61  	}
    62  
    63  	app.Services.Init()
    64  	app.Errors.Init()
    65  	app.Connections.Init()
    66  
    67  	// Get UserGivenPermission from OS
    68  
    69  	app.Manifest.init()
    70  	app.Cryptography.init()
    71  
    72  	registerServices()
    73  }
    74  
    75  // Start will start the app and block caller until app shutdown.
    76  func (app *appStructure) Start() {
    77  	protocol.App.Log(log.InfoEvent(domainEnglish, "Try to start application ..."))
    78  
    79  	app.changeState(protocol.ApplicationStateRunning)
    80  
    81  	protocol.App.Log(log.InfoEvent(domainEnglish, "Application start successfully, Now listen to any OS signals ..."))
    82  
    83  	// Block main goroutine to handle OS signals.
    84  	var sig = make(chan goos.Signal, 1024)
    85  	signal.Notify(sig)
    86  	app.HandleOSSignals(sig)
    87  }
    88  
    89  // HandleOSSignals use to handle OS signals! Caller will block until app terminate or exit.
    90  // https://en.wikipedia.org/wiki/Signal_(IPC)
    91  func (app *appStructure) HandleOSSignals(sigChannel chan goos.Signal) {
    92  	for {
    93  		var sig = <-sigChannel
    94  		switch sig {
    95  		case syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGKILL:
    96  			protocol.App.Log(log.InfoEvent(domainEnglish, "Caught signal to stop app"))
    97  			if app.State() == protocol.ApplicationStateRunning {
    98  				go app.Shutdown()
    99  			}
   100  		case syscall.Signal(0x17): // syscall.SIGURG:
   101  			protocol.App.Log(protocol.Log_Warning, "Caught urgened signal: "+sig)
   102  		case syscall.Signal(10): // syscall.SIGUSR1
   103  			protocol.App.Log(log.InfoEvent(domainEnglish, "Caught signal to reload app"))
   104  			app.Reload()
   105  		// case syscall.Signal(12): // syscall.SIGUSR2
   106  		default:
   107  			protocol.App.Log(protocol.Log_Warning, "Caught un-managed signal: "+sig)
   108  		}
   109  	}
   110  }
   111  
   112  // Reload use to reload app
   113  func (app *appStructure) Reload() {}
   114  
   115  // Shutdown use to graceful stop app
   116  func (app *appStructure) Shutdown() {
   117  	app.changeState(protocol.ApplicationStateStopping)
   118  	protocol.App.Log(log.InfoEvent(domainEnglish, "Waiting for app to finish and release proccess, It will take up to 60 seconds"))
   119  
   120  	app.changeState(protocol.ApplicationStateStopping)
   121  
   122  	app.Cryptography.shutdown()
   123  	app.Connections.Shutdown()
   124  	app.Nodes.Shutdown()
   125  
   126  	// write files to storage device if any change made
   127  
   128  	// Wait to finish above logic, or kill app in --- second
   129  	// time.Sleep(10 * time.Second)
   130  	var timer = time.NewTimer(app.Manifest.TechnicalInfo.ShutdownDelay)
   131  	select {
   132  	case <-timer.C:
   133  		if app.Status() == protocol.ApplicationStateStopping {
   134  			protocol.App.Log(log.InfoEvent(domainEnglish, "Application can't finish shutdown and release proccess in"+app.Manifest.TechnicalInfo.ShutdownDelay.String()))
   135  			goos.Exit(1)
   136  		} else {
   137  			protocol.App.Log(log.InfoEvent(domainEnglish, "Application stopped successfully"))
   138  			goos.Exit(0)
   139  		}
   140  	}
   141  
   142  }
   143  
   144  // Shutdown use to graceful stop app
   145  func (app *appStructure) changeState(state protocol.ApplicationState) {
   146  	app.stateChangeLocker.Lock()
   147  	app.state = state
   148  	for _, listener := range app.stateListeners {
   149  		listener <- state
   150  	}
   151  	app.stateChangeLocker.Unlock()
   152  }