mirror of
https://github.com/safing/portmaster
synced 2025-09-01 18:19:12 +00:00
* Move portbase into monorepo * Add new simple module mgr * [WIP] Switch to new simple module mgr * Add StateMgr and more worker variants * [WIP] Switch more modules * [WIP] Switch more modules * [WIP] swtich more modules * [WIP] switch all SPN modules * [WIP] switch all service modules * [WIP] Convert all workers to the new module system * [WIP] add new task system to module manager * [WIP] Add second take for scheduling workers * [WIP] Add FIXME for bugs in new scheduler * [WIP] Add minor improvements to scheduler * [WIP] Add new worker scheduler * [WIP] Fix more bug related to new module system * [WIP] Fix start handing of the new module system * [WIP] Improve startup process * [WIP] Fix minor issues * [WIP] Fix missing subsystem in settings * [WIP] Initialize managers in constructor * [WIP] Move module event initialization to constrictors * [WIP] Fix setting for enabling and disabling the SPN module * [WIP] Move API registeration into module construction * [WIP] Update states mgr for all modules * [WIP] Add CmdLine operation support * Add state helper methods to module group and instance * Add notification and module status handling to status package * Fix starting issues * Remove pilot widget and update security lock to new status data * Remove debug logs * Improve http server shutdown * Add workaround for cleanly shutting down firewall+netquery * Improve logging * Add syncing states with notifications for new module system * Improve starting, stopping, shutdown; resolve FIXMEs/TODOs * [WIP] Fix most unit tests * Review new module system and fix minor issues * Push shutdown and restart events again via API * Set sleep mode via interface * Update example/template module * [WIP] Fix spn/cabin unit test * Remove deprecated UI elements * Make log output more similar for the logging transition phase * Switch spn hub and observer cmds to new module system * Fix log sources * Make worker mgr less error prone * Fix tests and minor issues * Fix observation hub * Improve shutdown and restart handling * Split up big connection.go source file * Move varint and dsd packages to structures repo * Improve expansion test * Fix linter warnings * Fix interception module on windows * Fix linter errors --------- Co-authored-by: Vladimir Stoilov <vladimir@safing.io>
188 lines
4 KiB
Go
188 lines
4 KiB
Go
package mgr
|
|
|
|
import (
|
|
"slices"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// StateMgr is a simple state manager.
|
|
type StateMgr struct {
|
|
states []State
|
|
statesLock sync.Mutex
|
|
|
|
statesEventMgr *EventMgr[StateUpdate]
|
|
|
|
mgr *Manager
|
|
}
|
|
|
|
// State describes the state of a manager or module.
|
|
type State struct {
|
|
// ID is a program-unique ID.
|
|
// It must not only be unique within the StateMgr, but for the whole program,
|
|
// as it may be re-used with related systems.
|
|
// Required.
|
|
ID string
|
|
|
|
// Name is the name of the state.
|
|
// This may also serve as a notification title.
|
|
// Required.
|
|
Name string
|
|
|
|
// Message is a more detailed message about the state.
|
|
// Optional.
|
|
Message string
|
|
|
|
// Type defines the type of the state.
|
|
// Optional.
|
|
Type StateType
|
|
|
|
// Time is the time when the state was created or the originating incident occurred.
|
|
// Optional, will be set to current time if not set.
|
|
Time time.Time
|
|
|
|
// Data can hold any additional data necessary for further processing of connected systems.
|
|
// Optional.
|
|
Data any
|
|
}
|
|
|
|
// StateType defines commonly used states.
|
|
type StateType string
|
|
|
|
// State Types.
|
|
const (
|
|
StateTypeUndefined = ""
|
|
StateTypeHint = "hint"
|
|
StateTypeWarning = "warning"
|
|
StateTypeError = "error"
|
|
)
|
|
|
|
// Severity returns a number representing the gravity of the state for ordering.
|
|
func (st StateType) Severity() int {
|
|
switch st {
|
|
case StateTypeUndefined:
|
|
return 0
|
|
case StateTypeHint:
|
|
return 1
|
|
case StateTypeWarning:
|
|
return 2
|
|
case StateTypeError:
|
|
return 3
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
// StateUpdate is used to update others about a state change.
|
|
type StateUpdate struct {
|
|
Module string
|
|
States []State
|
|
}
|
|
|
|
// StatefulModule is used for interface checks on modules.
|
|
type StatefulModule interface {
|
|
States() *StateMgr
|
|
}
|
|
|
|
// NewStateMgr returns a new state manager.
|
|
func NewStateMgr(mgr *Manager) *StateMgr {
|
|
return &StateMgr{
|
|
statesEventMgr: NewEventMgr[StateUpdate]("state update", mgr),
|
|
mgr: mgr,
|
|
}
|
|
}
|
|
|
|
// NewStateMgr returns a new state manager.
|
|
func (m *Manager) NewStateMgr() *StateMgr {
|
|
return NewStateMgr(m)
|
|
}
|
|
|
|
// Add adds a state.
|
|
// If a state with the same ID already exists, it is replaced.
|
|
func (m *StateMgr) Add(s State) {
|
|
m.statesLock.Lock()
|
|
defer m.statesLock.Unlock()
|
|
|
|
if s.Time.IsZero() {
|
|
s.Time = time.Now()
|
|
}
|
|
|
|
// Update or add state.
|
|
index := slices.IndexFunc(m.states, func(es State) bool {
|
|
return es.ID == s.ID
|
|
})
|
|
if index >= 0 {
|
|
m.states[index] = s
|
|
} else {
|
|
m.states = append(m.states, s)
|
|
}
|
|
|
|
m.statesEventMgr.Submit(m.export())
|
|
}
|
|
|
|
// Remove removes the state with the given ID.
|
|
func (m *StateMgr) Remove(id string) {
|
|
m.statesLock.Lock()
|
|
defer m.statesLock.Unlock()
|
|
|
|
// Quick check if slice is empty.
|
|
// It is a common pattern to remove a state when no error was encountered at
|
|
// a critical operation. This means that StateMgr.Remove will be called often.
|
|
if len(m.states) == 0 {
|
|
return
|
|
}
|
|
|
|
var entryRemoved bool
|
|
m.states = slices.DeleteFunc(m.states, func(s State) bool {
|
|
if s.ID == id {
|
|
entryRemoved = true
|
|
return true
|
|
}
|
|
return false
|
|
})
|
|
|
|
if entryRemoved {
|
|
m.statesEventMgr.Submit(m.export())
|
|
}
|
|
}
|
|
|
|
// Clear removes all states.
|
|
func (m *StateMgr) Clear() {
|
|
m.statesLock.Lock()
|
|
defer m.statesLock.Unlock()
|
|
|
|
m.states = nil
|
|
|
|
m.statesEventMgr.Submit(m.export())
|
|
}
|
|
|
|
// Export returns the current states.
|
|
func (m *StateMgr) Export() StateUpdate {
|
|
m.statesLock.Lock()
|
|
defer m.statesLock.Unlock()
|
|
|
|
return m.export()
|
|
}
|
|
|
|
// export returns the current states.
|
|
func (m *StateMgr) export() StateUpdate {
|
|
name := ""
|
|
if m.mgr != nil {
|
|
name = m.mgr.name
|
|
}
|
|
|
|
return StateUpdate{
|
|
Module: name,
|
|
States: slices.Clone(m.states),
|
|
}
|
|
}
|
|
|
|
// Subscribe subscribes to state update events.
|
|
func (m *StateMgr) Subscribe(subscriberName string, chanSize int) *EventSubscription[StateUpdate] {
|
|
return m.statesEventMgr.Subscribe(subscriberName, chanSize)
|
|
}
|
|
|
|
// AddCallback adds a callback to state update events.
|
|
func (m *StateMgr) AddCallback(callbackName string, callback EventCallbackFunc[StateUpdate]) {
|
|
m.statesEventMgr.AddCallback(callbackName, callback)
|
|
}
|