mirror of
https://github.com/safing/portmaster
synced 2025-04-19 10:29:11 +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>
221 lines
5.8 KiB
Go
221 lines
5.8 KiB
Go
package terminal
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/safing/structures/varint"
|
|
)
|
|
|
|
// Error is a terminal error.
|
|
type Error struct {
|
|
// id holds the internal error ID.
|
|
id uint8
|
|
// external signifies if the error was received from the outside.
|
|
external bool
|
|
// err holds the wrapped error or the default error message.
|
|
err error
|
|
}
|
|
|
|
// ID returns the internal ID of the error.
|
|
func (e *Error) ID() uint8 {
|
|
return e.id
|
|
}
|
|
|
|
// Error returns the human readable format of the error.
|
|
func (e *Error) Error() string {
|
|
if e.external {
|
|
return "[ext] " + e.err.Error()
|
|
}
|
|
return e.err.Error()
|
|
}
|
|
|
|
// IsExternal returns whether the error occurred externally.
|
|
func (e *Error) IsExternal() bool {
|
|
if e == nil {
|
|
return false
|
|
}
|
|
|
|
return e.external
|
|
}
|
|
|
|
// Is returns whether the given error is of the same type.
|
|
func (e *Error) Is(target error) bool {
|
|
if e == nil || target == nil {
|
|
return false
|
|
}
|
|
|
|
t, ok := target.(*Error) //nolint:errorlint // Error implementation, not usage.
|
|
if !ok {
|
|
return false
|
|
}
|
|
return e.id == t.id
|
|
}
|
|
|
|
// Unwrap returns the wrapped error.
|
|
func (e *Error) Unwrap() error {
|
|
if e == nil || e.err == nil {
|
|
return nil
|
|
}
|
|
return e.err
|
|
}
|
|
|
|
// With adds context and details where the error occurred. The provided
|
|
// message is appended to the error.
|
|
// A new error with the same ID is returned and must be compared with
|
|
// errors.Is().
|
|
func (e *Error) With(format string, a ...interface{}) *Error {
|
|
// Return nil if error is nil.
|
|
if e == nil {
|
|
return nil
|
|
}
|
|
|
|
return &Error{
|
|
id: e.id,
|
|
err: fmt.Errorf(e.Error()+": "+format, a...),
|
|
}
|
|
}
|
|
|
|
// Wrap adds context higher up in the call chain. The provided message is
|
|
// prepended to the error.
|
|
// A new error with the same ID is returned and must be compared with
|
|
// errors.Is().
|
|
func (e *Error) Wrap(format string, a ...interface{}) *Error {
|
|
// Return nil if error is nil.
|
|
if e == nil {
|
|
return nil
|
|
}
|
|
|
|
return &Error{
|
|
id: e.id,
|
|
err: fmt.Errorf(format+": "+e.Error(), a...),
|
|
}
|
|
}
|
|
|
|
// AsExternal creates and returns an external version of the error.
|
|
func (e *Error) AsExternal() *Error {
|
|
// Return nil if error is nil.
|
|
if e == nil {
|
|
return nil
|
|
}
|
|
|
|
return &Error{
|
|
id: e.id,
|
|
err: e.err,
|
|
external: true,
|
|
}
|
|
}
|
|
|
|
// Pack returns the serialized internal error ID. The additional message is
|
|
// lost and is replaced with the default message upon parsing.
|
|
func (e *Error) Pack() []byte {
|
|
// Return nil slice if error is nil.
|
|
if e == nil {
|
|
return nil
|
|
}
|
|
|
|
return varint.Pack8(e.id)
|
|
}
|
|
|
|
// ParseExternalError parses an external error.
|
|
func ParseExternalError(id []byte) (*Error, error) {
|
|
// Return nil for an empty error.
|
|
if len(id) == 0 {
|
|
return ErrStopping.AsExternal(), nil
|
|
}
|
|
|
|
parsedID, _, err := varint.Unpack8(id)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to unpack error ID: %w", err)
|
|
}
|
|
|
|
return NewExternalError(parsedID), nil
|
|
}
|
|
|
|
// NewExternalError creates an external error based on the given ID.
|
|
func NewExternalError(id uint8) *Error {
|
|
err, ok := errorRegistry[id]
|
|
if ok {
|
|
return err.AsExternal()
|
|
}
|
|
|
|
return ErrUnknownError.AsExternal()
|
|
}
|
|
|
|
var errorRegistry = make(map[uint8]*Error)
|
|
|
|
func registerError(id uint8, err error) *Error {
|
|
// Check for duplicate.
|
|
_, ok := errorRegistry[id]
|
|
if ok {
|
|
panic(fmt.Sprintf("error with id %d already registered", id))
|
|
}
|
|
|
|
newErr := &Error{
|
|
id: id,
|
|
err: err,
|
|
}
|
|
|
|
errorRegistry[id] = newErr
|
|
return newErr
|
|
}
|
|
|
|
// func (e *Error) IsSpecial() bool {
|
|
// if e == nil {
|
|
// return false
|
|
// }
|
|
// return e.id > 0 && e.id < 8
|
|
// }
|
|
|
|
// IsOK returns if the error represents a "OK" or success status.
|
|
func (e *Error) IsOK() bool {
|
|
return !e.IsError()
|
|
}
|
|
|
|
// IsError returns if the error represents an erronous condition.
|
|
func (e *Error) IsError() bool {
|
|
if e == nil || e.err == nil {
|
|
return false
|
|
}
|
|
if e.id == 0 || e.id >= 8 {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Terminal Errors.
|
|
var (
|
|
// ErrUnknownError is the default error.
|
|
ErrUnknownError = registerError(0, errors.New("unknown error"))
|
|
|
|
// Error IDs 1-7 are reserved for special "OK" values.
|
|
|
|
ErrStopping = registerError(2, errors.New("stopping"))
|
|
ErrExplicitAck = registerError(3, errors.New("explicit ack"))
|
|
ErrNoActivity = registerError(4, errors.New("no activity"))
|
|
|
|
// Errors IDs 8 and up are for regular errors.
|
|
|
|
ErrInternalError = registerError(8, errors.New("internal error"))
|
|
ErrMalformedData = registerError(9, errors.New("malformed data"))
|
|
ErrUnexpectedMsgType = registerError(10, errors.New("unexpected message type"))
|
|
ErrUnknownOperationType = registerError(11, errors.New("unknown operation type"))
|
|
ErrUnknownOperationID = registerError(12, errors.New("unknown operation id"))
|
|
ErrPermissionDenied = registerError(13, errors.New("permission denied"))
|
|
ErrIntegrity = registerError(14, errors.New("integrity violated"))
|
|
ErrInvalidOptions = registerError(15, errors.New("invalid options"))
|
|
ErrHubNotReady = registerError(16, errors.New("hub not ready"))
|
|
ErrRateLimited = registerError(24, errors.New("rate limited"))
|
|
ErrIncorrectUsage = registerError(22, errors.New("incorrect usage"))
|
|
ErrTimeout = registerError(62, errors.New("timed out"))
|
|
ErrUnsupportedVersion = registerError(93, errors.New("unsupported version"))
|
|
ErrHubUnavailable = registerError(101, errors.New("hub unavailable"))
|
|
ErrAbandonedTerminal = registerError(102, errors.New("terminal is being abandoned"))
|
|
ErrShipSunk = registerError(108, errors.New("ship sunk"))
|
|
ErrDestinationUnavailable = registerError(113, errors.New("destination unavailable"))
|
|
ErrTryAgainLater = registerError(114, errors.New("try again later"))
|
|
ErrConnectionError = registerError(121, errors.New("connection error"))
|
|
ErrQueueOverflow = registerError(122, errors.New("queue overflowed"))
|
|
ErrCanceled = registerError(125, context.Canceled)
|
|
)
|