Initial commit

This commit is contained in:
NI
2019-08-07 15:56:51 +08:00
commit 02f14eb14f
206 changed files with 38863 additions and 0 deletions

176
application/command/fsm.go Normal file
View File

@@ -0,0 +1,176 @@
// Sshwifty - A Web SSH client
//
// Copyright (C) 2019 Rui NI <nirui@gmx.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package command
import (
"errors"
"github.com/niruix/sshwifty/application/rw"
)
// Errors
var (
ErrFSMMachineClosed = errors.New(
"FSM Machine is already closed, it cannot do anything but be released")
)
// FSMError Represents an error from FSM
type FSMError struct {
code StreamError
message string
succeed bool
}
// ToFSMError converts error to FSMError
func ToFSMError(e error, c StreamError) FSMError {
return FSMError{
code: c,
message: e.Error(),
succeed: false,
}
}
// NoFSMError return a FSMError that represents a success operation
func NoFSMError() FSMError {
return FSMError{
code: 0,
message: "No error",
succeed: true,
}
}
// Error return the error message
func (e FSMError) Error() string {
return e.message
}
// Code return the error code
func (e FSMError) Code() StreamError {
return e.code
}
// Succeed returns whether or not current error represents a succeed operation
func (e FSMError) Succeed() bool {
return e.succeed
}
// FSMState represents a state of a machine
type FSMState func(f *FSM, r *rw.LimitedReader, h StreamHeader, b []byte) error
// FSMMachine State machine
type FSMMachine interface {
// Bootup boots up the machine
Bootup(r *rw.LimitedReader, b []byte) (FSMState, FSMError)
// Close stops the machine and get it ready for release.
//
// NOTE: Close function is responsible in making sure the HeaderClose signal
// is sent before it returns.
// (It may not need to send the header by itself, but it have to
// make sure the header is sent)
Close() error
// Release shuts the machine down completely and release it's resources
Release() error
}
// FSM state machine control
type FSM struct {
m FSMMachine
s FSMState
closed bool
}
// newFSM creates a new FSM
func newFSM(m FSMMachine) FSM {
return FSM{
m: m,
s: nil,
closed: false,
}
}
// emptyFSM creates a empty FSM
func emptyFSM() FSM {
return FSM{
m: nil,
s: nil,
}
}
// bootup initialize the machine
func (f *FSM) bootup(r *rw.LimitedReader, b []byte) FSMError {
s, err := f.m.Bootup(r, b)
if s == nil {
panic("FSMState must not be nil")
}
if !err.Succeed() {
return err
}
f.s = s
return err
}
// running returns whether or not current FSM is running
func (f *FSM) running() bool {
return f.s != nil
}
// tick ticks current machine
func (f *FSM) tick(r *rw.LimitedReader, h StreamHeader, b []byte) error {
if f.closed {
return ErrFSMMachineClosed
}
return f.s(f, r, h, b)
}
// Release shuts down current machine and release it's resource
func (f *FSM) release() error {
f.s = nil
if !f.closed {
f.close()
}
rErr := f.m.Release()
f.m = nil
if rErr != nil {
return rErr
}
return nil
}
// Close stops the machine and get it ready to release
func (f *FSM) close() error {
f.closed = true
return f.m.Close()
}
// Switch switch to specificied State for the next tick
func (f *FSM) Switch(s FSMState) {
f.s = s
}