terminal

package
v0.4.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 16, 2022 License: AGPL-3.0 Imports: 18 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DefaultQueueSize = 50000
	MaxQueueSize     = 1000000
)

Flow Queue Configuration.

View Source
const CounterOpType string = "debug/count"

CounterOpType is the type ID for the Counter Operation.

View Source
const DefaultOperationTimeout = 10 * time.Second

DefaultOperationTimeout is the default time duration after which an idle operation times out and is ended or regarded as failed.

View Source
const (
	// MaxSubmitControlSize is the maximum size for submit control channels.
	MaxSubmitControlSize = 1000
)

Variables

View Source
var (
	// ErrUnknownError is the default error.
	ErrUnknownError = registerError(0, errors.New("unknown error"))

	ErrStopping    = registerError(2, errors.New("stopping"))
	ErrExplicitAck = registerError(3, errors.New("explicit ack"))
	ErrNoActivity  = registerError(4, errors.New("no activity"))

	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"))
	ErrPermissinDenied        = 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"))
	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"))
	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)
)

Terminal Errors.

Functions

func AddIDType

func AddIDType(c *container.Container, id uint32, msgType MsgType)

AddIDType prepends the ID and Type header to the message.

func MakeDirectDeliveryDeliverFunc added in v0.4.8

func MakeDirectDeliveryDeliverFunc(
	ctx context.Context,
	deliver chan *container.Container,
) func(c *container.Container) *Error

MakeDirectDeliveryDeliverFunc creates a submit upstream function with the given delivery channel.

func MakeDirectDeliveryRecvFunc added in v0.4.8

func MakeDirectDeliveryRecvFunc(
	deliver chan *container.Container,
) func() <-chan *container.Container

MakeDirectDeliveryRecvFunc makes a delivery receive function with the given delivery channel.

func MakeMsg

func MakeMsg(c *container.Container, id uint32, msgType MsgType)

MakeMsg prepends the ID and Type header and the length of the message.

func NewCounterOp

func NewCounterOp(t OpTerminal, opts CounterOpts) (*CounterOp, *Error)

NewCounterOp returns a new CounterOp.

func NewLocalBaseTerminal

func NewLocalBaseTerminal(
	ctx context.Context,
	id uint32,
	parentID string,
	remoteHub *hub.Hub,
	initMsg *TerminalOpts,
	submitUpstream func(*container.Container) *Error,
	addTerminalIDType bool,
) (
	t *TerminalBase,
	initData *container.Container,
	err *Error,
)

NewLocalBaseTerminal creates a new local terminal base for use with inheriting terminals.

func NewLocalTestTerminal added in v0.3.11

func NewLocalTestTerminal(
	ctx context.Context,
	id uint32,
	parentID string,
	remoteHub *hub.Hub,
	initMsg *TerminalOpts,
	submitUpstream func(*container.Container) *Error,
) (*TestTerminal, *container.Container, *Error)

NewLocalTestTerminal returns a new local test terminal.

func NewRemoteBaseTerminal

func NewRemoteBaseTerminal(
	ctx context.Context,
	id uint32,
	parentID string,
	identity *cabin.Identity,
	initData *container.Container,
	submitUpstream func(*container.Container) *Error,
	addTerminalIDType bool,
) (
	t *TerminalBase,
	initMsg *TerminalOpts,
	err *Error,
)

NewRemoteBaseTerminal creates a new remote terminal base for use with inheriting terminals.

func NewRemoteTestTerminal added in v0.3.11

func NewRemoteTestTerminal(
	ctx context.Context,
	id uint32,
	parentID string,
	identity *cabin.Identity,
	initData *container.Container,
	submitUpstream func(*container.Container) *Error,
) (*TestTerminal, *TerminalOpts, *Error)

NewRemoteTestTerminal returns a new remote test terminal.

func ParseTerminalOpts

func ParseTerminalOpts(c *container.Container) (*TerminalOpts, *Error)

ParseTerminalOpts parses terminal options from the container and checks if they are valid.

func RegisterOpType

func RegisterOpType(params OpParams)

RegisterOpType registers a new operation type and may only be called during Go's init and a module's prep phase.

Types

type AuthorizingTerminal

type AuthorizingTerminal interface {
	GrantPermission(grant Permission)
	HasPermission(required Permission) bool
}

AuthorizingTerminal is an interface for terminals that support authorization.

type CounterOp

type CounterOp struct {
	ClientCounter uint64
	ServerCounter uint64

	Error error
	// contains filtered or unexported fields
}

CounterOp sends increasing numbers on both sides.

func (*CounterOp) CounterWorker

func (op *CounterOp) CounterWorker(ctx context.Context) error

CounterWorker is a worker that sends counters.

func (*CounterOp) Deliver

func (op *CounterOp) Deliver(data *container.Container) *Error

Deliver delivers data to the operation.

func (*CounterOp) End

func (op *CounterOp) End(err *Error)

End ends the operation.

func (*CounterOp) HasEnded

func (op *CounterOp) HasEnded(end bool) bool

HasEnded returns whether the operation has ended.

func (*CounterOp) ID

func (op *CounterOp) ID() uint32

ID returns the ID of the operation.

func (*CounterOp) SendCounter

func (op *CounterOp) SendCounter() *Error

SendCounter sends the next counter.

func (*CounterOp) SetID

func (op *CounterOp) SetID(id uint32)

SetID sets the ID of the operation.

func (*CounterOp) Type

func (op *CounterOp) Type() string

Type returns the type ID.

func (*CounterOp) Wait

func (op *CounterOp) Wait()

Wait waits for the Counter Op to finish.

type CounterOpts

type CounterOpts struct {
	ClientCountTo uint64
	ServerCountTo uint64
	Wait          time.Duration
	Flush         bool
	// contains filtered or unexported fields
}

CounterOpts holds the options for CounterOp.

type DuplexFlowQueue

type DuplexFlowQueue struct {
	// contains filtered or unexported fields
}

DuplexFlowQueue is a duplex flow control mechanism using queues.

func NewDuplexFlowQueue

func NewDuplexFlowQueue(
	ctx context.Context,
	queueSize uint32,
	submitUpstream func(*container.Container) *Error,
) *DuplexFlowQueue

NewDuplexFlowQueue returns a new duplex flow queue.

func (*DuplexFlowQueue) Deliver

func (dfq *DuplexFlowQueue) Deliver(c *container.Container) *Error

Deliver submits a container for receiving from upstream.

func (*DuplexFlowQueue) FlowHandler

func (dfq *DuplexFlowQueue) FlowHandler(_ context.Context) error

FlowHandler handles all flow queue internals and must be started as a worker in the module where it is used.

func (*DuplexFlowQueue) FlowStats

func (dfq *DuplexFlowQueue) FlowStats() string

FlowStats returns a k=v formatted string of internal stats.

func (*DuplexFlowQueue) Flush

func (dfq *DuplexFlowQueue) Flush()

Flush waits for all waiting data to be sent.

func (*DuplexFlowQueue) ReadyToSend

func (dfq *DuplexFlowQueue) ReadyToSend() <-chan struct{}

ReadyToSend returns a channel that can be read when data can be sent.

func (*DuplexFlowQueue) Receive

func (dfq *DuplexFlowQueue) Receive() <-chan *container.Container

Receive receives a container from the recv queue.

func (*DuplexFlowQueue) Send

func (dfq *DuplexFlowQueue) Send(c *container.Container) *Error

Send adds the given container to the send queue.

func (*DuplexFlowQueue) StartWorkers added in v0.4.8

func (dfq *DuplexFlowQueue) StartWorkers(m *modules.Module, terminalName string)

StartWorkers starts the necessary workers to operate the flow queue.

type Error

type Error struct {
	// contains filtered or unexported fields
}

Error is a terminal error.

func NewExternalError

func NewExternalError(id uint8) *Error

NewExternalError creates an external error based on the given ID.

func ParseExternalError

func ParseExternalError(id []byte) (*Error, error)

ParseExternalError parses an external error.

func (*Error) AsExternal

func (e *Error) AsExternal() *Error

AsExternal creates and returns an external version of the error.

func (*Error) Error

func (e *Error) Error() string

Error returns the human readable format of the error.

func (*Error) ID

func (e *Error) ID() uint8

ID returns the internal ID of the error.

func (*Error) Is

func (e *Error) Is(target error) bool

Is returns whether the given error is of the same type.

func (*Error) IsError added in v0.3.11

func (e *Error) IsError() bool

IsError returns if the error represents an erronous condition.

func (*Error) IsExternal

func (e *Error) IsExternal() bool

IsExternal returns whether the error occurred externally.

func (*Error) IsOK added in v0.3.11

func (e *Error) IsOK() bool

IsOK returns if the error represents a "OK" or success status.

func (*Error) Pack

func (e *Error) Pack() []byte

Pack returns the serialized internal error ID. The additional message is lost and is replaced with the default message upon parsing.

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap returns the wrapped error.

func (*Error) With

func (e *Error) With(format string, a ...interface{}) *Error

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 (*Error) Wrap

func (e *Error) Wrap(format string, a ...interface{}) *Error

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().

type FairChannel added in v0.4.8

type FairChannel struct {
	// contains filtered or unexported fields
}

FairChannel is a submit control using a fairly queued channel.

func NewFairChannel added in v0.4.8

func NewFairChannel(ctx context.Context, size int) *FairChannel

NewFairChannel returns a new FairChannel.

func (*FairChannel) Recv added in v0.4.8

func (fc *FairChannel) Recv() <-chan SubmitControlItem

Recv returns a receive-channel to receive an item from the submit control channel.

func (*FairChannel) Submit added in v0.4.8

func (fc *FairChannel) Submit(data *container.Container, timeout time.Duration) *Error

Submit submits data to the channel.

type FairChannelItem added in v0.4.8

type FairChannelItem struct {
	// contains filtered or unexported fields
}

FairChannelItem is an item for the FairChannel.

func (*FairChannelItem) Accept added in v0.4.8

func (fci *FairChannelItem) Accept() *container.Container

Accept is called by the channel owner when an item from the channel is accepted to receive the data.

type FlowControl added in v0.4.8

type FlowControl interface {
	Deliver(c *container.Container) *Error
	Receive() <-chan *container.Container
	Send(c *container.Container) *Error
	ReadyToSend() <-chan struct{}
	Flush()
	StartWorkers(m *modules.Module, terminalName string)
}

FlowControl defines the flow control interface.

type FlowControlType added in v0.4.8

type FlowControlType uint8

FlowControlType represents a flow control type.

const (
	FlowControlDefault FlowControlType = 0
	FlowControlDFQ     FlowControlType = 1
	FlowControlNone    FlowControlType = 2
)

Flow Control Types.

func (FlowControlType) DefaultSize added in v0.4.8

func (fct FlowControlType) DefaultSize() uint32

DefaultSize returns the default flow control size.

type MsgType

type MsgType uint8

MsgType is the message type for both terminals and operations.

const (
	// MsgTypeInit is used to establish a new terminal or run a new operation.
	MsgTypeInit MsgType = 1

	// MsgTypeData is used to send data to a terminal or operation.
	MsgTypeData MsgType = 2

	// MsgTypeStop is used to abandon a terminal or end an operation, with an optional error.
	MsgTypeStop MsgType = 3
)

func ParseIDType

func ParseIDType(c *container.Container) (id uint32, msgType MsgType, err error)

ParseIDType parses the combined message ID and type.

type OpBase

type OpBase struct {
	// contains filtered or unexported fields
}

OpBase is a base for quickly building operations.

func (*OpBase) HasEnded

func (op *OpBase) HasEnded(end bool) bool

HasEnded returns whether the operation has ended.

func (*OpBase) ID

func (op *OpBase) ID() uint32

ID returns the ID of the operation.

func (*OpBase) Init

func (op *OpBase) Init()

Init initializes the operation base.

func (*OpBase) SetID

func (op *OpBase) SetID(id uint32)

SetID sets the ID of the operation.

type OpBaseRequest

type OpBaseRequest struct {
	OpBase

	Delivered chan *container.Container
	Ended     chan *Error
}

OpBaseRequest is an extended operation base for request-like operations.

func (*OpBaseRequest) Deliver

func (op *OpBaseRequest) Deliver(data *container.Container) *Error

Deliver delivers data to the operation.

func (*OpBaseRequest) End

func (op *OpBaseRequest) End(err *Error)

End ends the operation.

func (*OpBaseRequest) Init

func (op *OpBaseRequest) Init(deliverQueueSize int)

Init initializes the operation base.

type OpParams

type OpParams struct {
	// Type is the type name of an operation.
	Type string
	// Requires defines the required permissions to run an operation.
	Requires Permission
	// RunOp is the function that start a new operation.
	RunOp OpRunner
}

OpParams defines an operation.

type OpRunner

type OpRunner func(t OpTerminal, opID uint32, initData *container.Container) (Operation, *Error)

OpRunner is used to initialize operations remotely.

type OpTerminal

type OpTerminal interface {
	// OpInit initialized the operation with the given data.
	OpInit(op Operation, data *container.Container) *Error

	// OpSend sends data.
	OpSend(op Operation, data *container.Container) *Error

	// OpSendWithTimeout sends data, but fails after the given timeout passed.
	OpSendWithTimeout(op Operation, data *container.Container, timeout time.Duration) *Error

	// OpEnd sends the end signal and calls End(ErrNil) on the Operation.
	// The Operation should cease operation after calling this function.
	OpEnd(op Operation, err *Error)

	// FmtID returns the formatted ID the Operation's Terminal.
	FmtID() string

	// Flush writes all pending data waiting to be sent.
	Flush()
}

OpTerminal provides Operations with the necessary interface to interact with the Terminal.

type Operation

type Operation interface {
	ID() uint32
	SetID(id uint32)
	Type() string
	Deliver(data *container.Container) *Error
	HasEnded(end bool) bool
	End(err *Error)
}

Operation is an interface for all operations.

type Permission

type Permission uint16

Permission is a bit-map of granted permissions.

const (
	NoPermission      Permission = 0x0
	MayExpand         Permission = 0x1
	MayConnect        Permission = 0x2
	IsHubOwner        Permission = 0x100
	IsHubAdvisor      Permission = 0x200
	IsCraneController Permission = 0x8000
)

Permissions.

func AddPermissions

func AddPermissions(perms ...Permission) Permission

AddPermissions combines multiple permissions.

func (Permission) Has

func (p Permission) Has(required Permission) bool

Has returns if the permission includes the specified permission.

type PlainChannel added in v0.4.8

type PlainChannel struct {
	// contains filtered or unexported fields
}

PlainChannel is a submit control using a plain channel.

func NewPlainChannel added in v0.4.8

func NewPlainChannel(ctx context.Context, size int) *PlainChannel

NewPlainChannel returns a new PlainChannel.

func (*PlainChannel) Recv added in v0.4.8

func (pc *PlainChannel) Recv() <-chan SubmitControlItem

Recv returns a receive-channel to receive an item from the submit control channel.

func (*PlainChannel) Submit added in v0.4.8

func (pc *PlainChannel) Submit(data *container.Container, timeout time.Duration) *Error

Submit submits data to the channel.

type PlainChannelItem added in v0.4.8

type PlainChannelItem struct {
	// contains filtered or unexported fields
}

PlainChannelItem is an item for the PlainChannel.

func (PlainChannelItem) Accept added in v0.4.8

func (pci PlainChannelItem) Accept() *container.Container

Accept is called by the channel owner when an item from the channel is accepted to receive the data.

type SubmitControl added in v0.4.8

type SubmitControl interface {
	Submit(data *container.Container, timeout time.Duration) *Error
	Recv() <-chan SubmitControlItem
}

SubmitControl defines the submit control interface.

type SubmitControlItem added in v0.4.8

type SubmitControlItem interface {
	Accept() *container.Container
}

SubmitControlItem defines the submit control item interface.

type SubmitControlType added in v0.4.8

type SubmitControlType uint8

SubmitControlType represents a submit control type.

const (
	SubmitControlDefault SubmitControlType = 0
	SubmitControlPlain   SubmitControlType = 1
	SubmitControlFair    SubmitControlType = 2
)

Submit Control Types.

func (SubmitControlType) DefaultSize added in v0.4.8

func (sct SubmitControlType) DefaultSize() uint32

DefaultSize returns the default flow control size.

type TerminalBase

type TerminalBase struct {

	// Abandoning indicates if the Terminal is being abandoned. The main handlers
	// will keep running until the context has been canceled by the abandon
	// procedure.
	// No new operations should be started.
	// Whoever initiates the abandoning must also start the abandon procedure.
	Abandoning *abool.AtomicBool
	// contains filtered or unexported fields
}

TerminalBase contains the basic functions of a terminal.

func (*TerminalBase) Abandon

func (t *TerminalBase) Abandon(err *Error)

Abandon abandons the Terminal with the given error.

func (*TerminalBase) Ctx

func (t *TerminalBase) Ctx() context.Context

Ctx returns the Terminal's context.

func (*TerminalBase) DeleteActiveOp

func (t *TerminalBase) DeleteActiveOp(opID uint32)

DeleteActiveOp deletes an active operation from the Terminal state.

func (*TerminalBase) Deliver

func (t *TerminalBase) Deliver(c *container.Container) *Error

Deliver on TerminalBase only exists to conform to the interface. It must be overridden by an actual implementation.

func (*TerminalBase) Flush

func (t *TerminalBase) Flush()

Flush sends all data waiting to be sent.

func (*TerminalBase) FmtID

func (t *TerminalBase) FmtID() string

FmtID formats the terminal ID together with the parent's ID.

func (*TerminalBase) GetActiveOp

func (t *TerminalBase) GetActiveOp(opID uint32) (op Operation, ok bool)

GetActiveOp returns the active operation with the given ID from the Terminal state.

func (*TerminalBase) GetActiveOpCount added in v0.3.6

func (t *TerminalBase) GetActiveOpCount() int

GetActiveOpCount returns the amount of active operations.

func (*TerminalBase) GrantPermission

func (t *TerminalBase) GrantPermission(grant Permission)

GrantPermission grants the specified permissions to the Terminal.

func (*TerminalBase) Handler

func (t *TerminalBase) Handler(_ context.Context) error

Handler receives and handles messages and must be started as a worker in the module where the Terminal is used.

func (*TerminalBase) HasPermission

func (t *TerminalBase) HasPermission(required Permission) bool

HasPermission returns if the Terminal has the specified permission.

func (*TerminalBase) ID

func (t *TerminalBase) ID() uint32

ID returns the Terminal's ID.

func (*TerminalBase) OpEnd

func (t *TerminalBase) OpEnd(op Operation, err *Error)

OpEnd sends the end signal with an optional error and then deletes the operation from the Terminal state and calls End(ErrNil) on the Operation. The Operation should cease operation after calling this function. Should only be called by an operation.

func (*TerminalBase) OpInit

func (t *TerminalBase) OpInit(op Operation, data *container.Container) *Error

OpInit initialized the operation with the given data.

func (*TerminalBase) OpSend

func (t *TerminalBase) OpSend(op Operation, data *container.Container) *Error

OpSend sends data.

func (*TerminalBase) OpSendWithTimeout

func (t *TerminalBase) OpSendWithTimeout(op Operation, data *container.Container, timeout time.Duration) *Error

OpSendWithTimeout sends data, but fails after the given timeout passed.

func (*TerminalBase) Sender

func (t *TerminalBase) Sender(_ context.Context) error

Sender handles sending messages and must be started as a worker in the module where the Terminal is used.

func (*TerminalBase) SetActiveOp

func (t *TerminalBase) SetActiveOp(opID uint32, op Operation)

SetActiveOp saves an active operation to the Terminal state.

func (*TerminalBase) SetTerminalExtension

func (t *TerminalBase) SetTerminalExtension(ext TerminalExtension)

SetTerminalExtension sets the Terminal's extension. This function is not guarded and may only be used during initialization.

func (*TerminalBase) SetTimeout

func (t *TerminalBase) SetTimeout(d time.Duration)

SetTimeout sets the Terminal's idle timeout duration. It is broken down into slots internally.

func (*TerminalBase) StartAbandonProcedure added in v0.4.4

func (t *TerminalBase) StartAbandonProcedure(err *Error, sendError bool, finalizeFunc func())

StartAbandonProcedure sends a stop message with the given error if wanted, ends all operations with a nil error, executes the given finalizeFunc and finally cancels the terminal context. This function is usually not called directly, but at the end of an Abandon() implementation.

func (*TerminalBase) StartWorkers added in v0.4.8

func (t *TerminalBase) StartWorkers(m *modules.Module, terminalName string)

StartWorkers starts the necessary workers to operate the Terminal.

func (*TerminalBase) WaitForFlush

func (t *TerminalBase) WaitForFlush()

WaitForFlush makes the terminal pause all sending until the next call to Flush().

type TerminalExtension

type TerminalExtension interface {
	OpTerminal

	Abandon(err *Error)
}

TerminalExtension is the interface that extended terminal implementations need to adhere to.

type TerminalInterface

type TerminalInterface interface {
	ID() uint32
	Ctx() context.Context
	Deliver(c *container.Container) *Error
	Abandon(err *Error)
	FmtID() string
	Flush()
}

TerminalInterface is the generic interface for upstream implementations.

type TerminalOpts

type TerminalOpts struct {
	Version uint8  `json:"-"`
	Encrypt bool   `json:"e,omitempty"`
	Padding uint16 `json:"p,omitempty"`

	FlowControl     FlowControlType `json:"fc,omitempty"`
	FlowControlSize uint32          `json:"qs,omitempty"` // Previously was "QueueSize".

	SubmitControl     SubmitControlType `json:"sc,omitempty"`
	SubmitControlSize uint32            `json:"ss,omitempty"`
}

TerminalOpts holds configuration for the terminal.

func DefaultCraneControllerOpts added in v0.4.9

func DefaultCraneControllerOpts() *TerminalOpts

DefaultCraneControllerOpts returns the default terminal options for a crane controller terminal.

func DefaultExpansionTerminalOpts added in v0.4.9

func DefaultExpansionTerminalOpts() *TerminalOpts

DefaultExpansionTerminalOpts returns the default terminal options for an expansion terminal.

func DefaultHomeHubTerminalOpts added in v0.4.9

func DefaultHomeHubTerminalOpts() *TerminalOpts

DefaultHomeHubTerminalOpts returns the default terminal options for a crane terminal used for the home hub.

func (*TerminalOpts) Check added in v0.4.8

func (opts *TerminalOpts) Check(useDefaultsForRequired bool) *Error

Check checks if terminal options are valid.

func (*TerminalOpts) Pack

func (opts *TerminalOpts) Pack() (*container.Container, *Error)

Pack serialized the terminal options and checks if they are valid.

type TestTerminal added in v0.3.11

type TestTerminal struct {
	*TerminalBase
}

TestTerminal is a terminal for running tests.

func NewSimpleTestTerminalPair added in v0.3.11

func NewSimpleTestTerminalPair(delay time.Duration, delayQueueSize int, opts *TerminalOpts) (a, b *TestTerminal, err error)

NewSimpleTestTerminalPair provides a simple conntected terminal pair for tests.

func (*TestTerminal) Stop added in v0.4.4

func (t *TestTerminal) Stop(err *Error)

Stop stops the terminal.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL