github.com/futurehomeno/fimpgo@v1.14.0/edgeapp/lifecycle.go (about)

     1  package edgeapp
     2  
     3  import (
     4  	log "github.com/sirupsen/logrus"
     5  	"sync"
     6  )
     7  
     8  const (
     9  	SystemEventTypeEvent = "EVENT"
    10  	SystemEventTypeState = "STATE" // APP state
    11  	SystemEventTypeAuthState = "AUTH_STATE" // AUTH state
    12  	SystemEventTypeConfigState = "CONFIG_STATE" // configuration state
    13  	SystemEventTypeConnectionState = "CONNECTION_STATE" // Connection state
    14  
    15  
    16  	AppStateStarting      = "STARTING"
    17  	AppStateStartupError  = "STARTUP_ERROR"
    18  	AppStateNotConfigured = "NOT_CONFIGURED"
    19  	AppStateError         = "ERROR"
    20  	AppStateRunning       = "RUNNING"
    21  	AppStateTerminate     = "TERMINATING"
    22  
    23  	ConfigStateNotConfigured  = "NOT_CONFIGURED"
    24  	ConfigStateConfigured     = "CONFIGURED"
    25  	ConfigStatePartConfigured = "PART_CONFIGURED"
    26  	ConfigStateInProgress     = "IN_PROGRESS"
    27  	ConfigStateNA             = "NA"
    28  
    29  	AuthStateNotAuthenticated = "NOT_AUTHENTICATED"
    30  	AuthStateAuthenticated    = "AUTHENTICATED"
    31  	AuthStateInProgress       = "IN_PROGRESS"
    32  	AuthStateNA               = "NA"
    33  
    34  	ConnStateConnecting   = "CONNECTING"
    35  	ConnStateConnected    = "CONNECTED"
    36  	ConnStateDisconnected = "DISCONNECTED"
    37  	ConnStateNA           = "NA"
    38  
    39  	//EventStarting            = "STARTING"
    40  	EventConfiguring = "CONFIGURING" // All configurations loaded and brokers configured
    41  	EventConfigError = "CONF_ERROR"  // All configurations loaded and brokers configured
    42  	EventConfigured  = "CONFIGURED"  // All configurations loaded and brokers configured
    43  	EventRunning     = "RUNNING"
    44  )
    45  
    46  type State string
    47  
    48  type AppStates struct {
    49  	App           string `json:"app"`
    50  	Connection    string `json:"connection"`
    51  	Config        string `json:"config"`
    52  	Auth          string `json:"auth"`
    53  	LastErrorText string `json:"last_error_text"`
    54  	LastErrorCode string `json:"last_error_code"`
    55  }
    56  
    57  type SystemEvent struct {
    58  	Type   string // Event or State
    59  	Name   string //
    60  	State  State
    61  	Info   string
    62  	Params map[string]string
    63  }
    64  
    65  type SystemEventChannel chan SystemEvent
    66  
    67  type Lifecycle struct {
    68  	busMux           sync.Mutex
    69  	systemEventBus   map[string]SystemEventChannel
    70  	appState         State
    71  	previousAppState State
    72  	connectionState  State
    73  	authState        State
    74  	configState      State
    75  	lastError        string
    76  }
    77  
    78  func NewAppLifecycle() *Lifecycle {
    79  	lf := &Lifecycle{systemEventBus: make(map[string]SystemEventChannel)}
    80  	lf.appState = AppStateStarting
    81  	lf.authState = AuthStateNA
    82  	lf.configState = ConfigStateNotConfigured
    83  	lf.connectionState = ConnStateNA
    84  	return lf
    85  }
    86  
    87  func (al *Lifecycle) GetAllStates() *AppStates {
    88  	appStates := AppStates{
    89  		App:           string(al.appState),
    90  		Connection:    string(al.connectionState),
    91  		Config:        string(al.configState),
    92  		Auth:          string(al.authState),
    93  		LastErrorText: "",
    94  		LastErrorCode: "",
    95  	}
    96  	return &appStates
    97  }
    98  
    99  func (al *Lifecycle) ConfigState() State {
   100  	return al.configState
   101  }
   102  
   103  func (al *Lifecycle) SetConfigState(configState State) {
   104  	log.Debug("<sysEvt> New CONFIG state = ", configState)
   105  	al.configState = configState
   106  	for i := range al.systemEventBus {
   107  		select {
   108  		case al.systemEventBus[i] <- SystemEvent{Type: SystemEventTypeConfigState, State: configState, Info: "sys", Params: nil}:
   109  		default:
   110  			log.Debugf("<sysEvt> Config state listener %s is busy , event dropped", i)
   111  		}
   112  	}
   113  }
   114  
   115  func (al *Lifecycle) AuthState() State {
   116  	return al.authState
   117  }
   118  
   119  func (al *Lifecycle) SetAuthState(authState State) {
   120  	log.Debug("<sysEvt> New AUTH state = ", authState)
   121  	al.authState = authState
   122  
   123  	for i := range al.systemEventBus {
   124  		select {
   125  		case al.systemEventBus[i] <- SystemEvent{Type: SystemEventTypeAuthState, State: authState, Info: "sys", Params: nil}:
   126  		default:
   127  			log.Debugf("<sysEvt> Auth state listener %s is busy , event dropped", i)
   128  		}
   129  	}
   130  }
   131  
   132  func (al *Lifecycle) ConnectionState() State {
   133  	return al.connectionState
   134  }
   135  
   136  func (al *Lifecycle) SetConnectionState(connectivityState State) {
   137  	log.Debug("<sysEvt> New CONNECTION state = ", connectivityState)
   138  	al.connectionState = connectivityState
   139  	for i := range al.systemEventBus {
   140  		select {
   141  		case al.systemEventBus[i] <- SystemEvent{Type: SystemEventTypeConnectionState, State: connectivityState, Info: "sys", Params: nil}:
   142  		default:
   143  			log.Debugf("<sysEvt> Auth state listener %s is busy , event dropped", i)
   144  		}
   145  	}
   146  }
   147  
   148  func (al *Lifecycle) AppState() State {
   149  	return al.appState
   150  }
   151  
   152  func (al *Lifecycle) LastError() string {
   153  	return al.lastError
   154  }
   155  
   156  func (al *Lifecycle) SetLastError(lastError string) {
   157  	al.lastError = lastError
   158  }
   159  
   160  func (al *Lifecycle) SetAppState(currentState State, params map[string]string) {
   161  	al.busMux.Lock()
   162  	al.previousAppState = al.appState
   163  	al.appState = currentState
   164  	log.Debug("<sysEvt> New APP state = ", currentState)
   165  	for i := range al.systemEventBus {
   166  		select {
   167  		case al.systemEventBus[i] <- SystemEvent{Type: SystemEventTypeState, State: currentState, Info: "sys", Params: params}:
   168  		default:
   169  			log.Warnf("<sysEvt> State listener %s is busy , event dropped", i)
   170  		}
   171  
   172  	}
   173  	al.busMux.Unlock()
   174  }
   175  
   176  //PublishSystemEvent - published Application system events
   177  func (al *Lifecycle) PublishSystemEvent(name, src string, params map[string]string) {
   178  	event := SystemEvent{Name: name}
   179  	al.Publish(event, src, params)
   180  }
   181  
   182  func (al *Lifecycle) Publish(event SystemEvent, src string, params map[string]string) {
   183  	al.busMux.Lock()
   184  	event.Type = SystemEventTypeEvent
   185  	event.State = al.AppState()
   186  	event.Params = params
   187  	for i := range al.systemEventBus {
   188  			select {
   189  			case al.systemEventBus[i] <- event:
   190  			default:
   191  				log.Warnf("<sysEvt> Event listener %s is busy , event dropped", i)
   192  			}
   193  
   194  	}
   195  	defer al.busMux.Unlock()
   196  }
   197  
   198  // Subscribe for lifecycle events
   199  func (al *Lifecycle) Subscribe(subId string, bufSize int) SystemEventChannel {
   200  	msgChan := make(SystemEventChannel, bufSize)
   201  	al.busMux.Lock()
   202  	al.systemEventBus[subId] = msgChan
   203  	al.busMux.Unlock()
   204  	return msgChan
   205  }
   206  
   207  // Unsubscribe from for lifecycle events
   208  func (al *Lifecycle) Unsubscribe(subId string) {
   209  	al.busMux.Lock()
   210  	delete(al.systemEventBus, subId)
   211  	al.busMux.Unlock()
   212  }
   213  
   214  // WaitForState blocks until target state is reached
   215  func (al *Lifecycle) WaitForState(subId string,stateType string , targetState State) {
   216  	log.Debugf("<sysEvt> Waiting for state = %s , current state = %s", targetState, al.AppState())
   217  	if al.AppState() == targetState && stateType == SystemEventTypeState ||
   218  	   al.ConfigState() == targetState && stateType == SystemEventTypeConfigState ||
   219  	   al.AuthState() == targetState && stateType == SystemEventTypeAuthState ||
   220  	   al.ConnectionState() == targetState && stateType == SystemEventTypeConnectionState {
   221  		return
   222  	}
   223  	ch := al.Subscribe(subId, 5)
   224  	for evt := range ch {
   225  		if evt.Type == stateType && evt.State == targetState {
   226  			al.Unsubscribe(subId)
   227  			return
   228  		}
   229  	}
   230  }