diff --git a/pkg/http/http.go b/pkg/http/http.go new file mode 100644 index 0000000..9f77957 --- /dev/null +++ b/pkg/http/http.go @@ -0,0 +1,84 @@ +package http + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" +) + +type Client struct { + core *http.Client +} + +func NewClient() *Client { + return &Client{ + core: http.DefaultClient, + } +} + +func (c *Client) JSONGet(ctx context.Context, url string, header, params map[string]string, resp interface{}) error { + return c.JSONDo(ctx, http.MethodGet, getCompleteURL(url, params), header, nil, resp) +} + +func (c *Client) JSONPost(ctx context.Context, url string, header map[string]string, req, resp interface{}) error { + return c.JSONDo(ctx, http.MethodPost, url, header, req, resp) +} + +func (c *Client) JSONDo(ctx context.Context, method, url string, header map[string]string, req, resp interface{}) error { + var reqReader io.Reader + if req != nil { + body, _ := json.Marshal(req) + reqReader = bytes.NewReader(body) + } + + request, err := http.NewRequestWithContext(ctx, method, url, reqReader) + if err != nil { + return err + } + + if request.Header == nil { + request.Header = make(http.Header) + } + for k, v := range header { + request.Header.Add(k, v) + } + request.Header.Add("Content-Type", "application/json") + + response, err := c.core.Do(request) + if err != nil { + return err + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + return fmt.Errorf("invalid status: %d", response.StatusCode) + } + + if resp == nil { + return nil + } + + respBody, err := io.ReadAll(response.Body) + if err != nil { + return err + } + + return json.Unmarshal(respBody, resp) +} + +func getCompleteURL(origin string, params map[string]string) string { + if len(params) == 0 { + return origin + } + values := url.Values{} + for k, v := range params { + values.Add(k, v) + } + + queriesStr, _ := url.QueryUnescape(values.Encode()) + return fmt.Sprintf("%s?%s", origin, queriesStr) +} diff --git a/services/uniss/fsm.go b/services/uniss/fsm.go new file mode 100644 index 0000000..0c814aa --- /dev/null +++ b/services/uniss/fsm.go @@ -0,0 +1,368 @@ +package uniss + +import ( + "context" + "dashboard/pkg/fsm" + "time" + + "git.zhangshuocauc.cn/redhat/timewheel" + "go.uber.org/zap" +) + +const ( + unisFsmEventReset fsm.EventName = "unisFsmEventReset" + + unisFsmEventOfline fsm.EventName = "unisFsmEventOfline" + unisFsmEventOnline fsm.EventName = "unisFsmEventOnline" + unisFsmEventLoginId fsm.EventName = "unisFsmEventLoginId" + unisFsmEventLoginSync fsm.EventName = "unisFsmEventLoginSync" + unisFsmEventLoginForce fsm.EventName = "unisFsmEventLoginForce" + unisFsmEventLoginServer fsm.EventName = "unisFsmEventLoginServer" + unisFsmEventLogout fsm.EventName = "unisFsmEventLogout" + unisFsmEventLogoutForce fsm.EventName = "unisFsmEventLogoutForce" + unisFsmEventLogoutServer fsm.EventName = "unisFsmEventLogoutServer" + unisFsmEventLogin fsm.EventName = "unisFsmEventLogin" + unisFsmEventLoginSyncFailed fsm.EventName = "unisFsmEventLoginSyncFailed" + unisFsmEventLoginSyncSuccess fsm.EventName = "unisFsmEventLoginSyncSuccess" + + unisFsmEventLoginSuccess fsm.EventName = "unisFsmEventLoginSuccess" + unisFsmEventLoginFailed fsm.EventName = "unisFsmEventLoginFailed" + unisFsmEventLogoutSuccess fsm.EventName = "unisFsmEventLogoutSuccess" + unisFsmEventLogoutFailed fsm.EventName = "unisFsmEventLogoutFailed" +) + +var events = fsm.Events{ + unisFsmEventReset, + unisFsmEventLoginSuccess, + unisFsmEventLoginFailed, + unisFsmEventLogoutSuccess, + unisFsmEventLogoutFailed, +} + +type fsmService struct { + unisMSystemFsm *unisMSystemFsm + unisMStateFsm *unisMStateFsm +} + +func (f *fsmService) reset(ctx context.Context) { + f.unisMSystemFsm.reset(ctx) + f.unisMStateFsm.reset(ctx) +} + +func newfsmService() (fsm *fsmService, err error) { + fsm = &fsmService{} + + fsm.unisMSystemFsm, err = newunisMSystemFsm() + if err != nil { + return + } + + fsm.unisMStateFsm, err = newunisMStateFsm() + if err != nil { + return + } + + return +} + +/*******************************主逻辑在线离线状态机************************************/ +type unisMSystemFsm struct { + fsm *fsm.FSM +} + +const ( + unisMSystem = "unisMSystem" + unisMIdle = "unisMIdle" + unisMOnLine = "unisMOnLine" + unisMOfLine = "unisMOfLine" + + unisMOnLineIdle = "unisMOnLineIdle" + unisMOnLineLoginId = "unisMOnLineLoginId" + unisMOnLineLoginning = "unisMOnLineLoginning" + unisMOnLineLogouting = "unisMOnLineLogouting" + unisMOnLineLoginSync = "unisMOnLineLoginSync" +) + +func newunisMSystemFsm() (*unisMSystemFsm, error) { + res := new(unisMSystemFsm) + + fsm, err := fsm.NewFsm(unisMSystem, unisMIdle, events, []*fsm.StateRule{ + {Name: unisMSystem, Parent: "", InitState: unisMIdle, Processor: res.unisMSystem, Dst: []string{}}, + {Name: unisMIdle, Parent: unisMSystem, InitState: "", Processor: res.unisMIdle, Dst: []string{}}, + {Name: unisMOnLine, Parent: unisMSystem, InitState: unisMOnLineIdle, Processor: res.unisMOnLine, Dst: []string{}}, + {Name: unisMOfLine, Parent: unisMSystem, InitState: "", Processor: res.unisMOfLine, Dst: []string{}}, + + {Name: unisMOnLineIdle, Parent: unisMOnLine, InitState: "", Processor: res.unisMOnLineIdle, Dst: []string{}}, + {Name: unisMOnLineLoginId, Parent: unisMOnLine, InitState: "", Processor: res.unisMOnLineLoginId, Dst: []string{}}, + {Name: unisMOnLineLoginning, Parent: unisMOnLine, InitState: "", Processor: res.unisMOnLineLoginning, Dst: []string{}}, + {Name: unisMOnLineLogouting, Parent: unisMOnLine, InitState: "", Processor: res.unisMOnLineLogouting, Dst: []string{}}, + {Name: unisMOnLineLoginSync, Parent: unisMOnLine, InitState: "", Processor: res.unisMOnLineLoginSync, Dst: []string{}}, + }, zap.NewStdLog(log.Logger)) + + if err != nil { + log.Sugar().Error(err) + return nil, err + } + + res.fsm = fsm + + return res, nil +} + +func (f *unisMSystemFsm) reset(ctx context.Context) { + f.fsm.ExecuteEvent(ctx, unisFsmEventReset, nil) +} + +func (f *unisMSystemFsm) unisMSystem(ctx context.Context, e *fsm.Event) error { + switch e.Event { + case fsm.EventEntry: + case fsm.EventExit: + case unisFsmEventReset: + e.FSM.StateChange(ctx, unisMIdle, nil) + default: + return fsm.EventNoProc + } + + return fsm.EventOK +} + +func (f *unisMSystemFsm) unisMIdle(ctx context.Context, e *fsm.Event) error { + switch e.Event { + case fsm.EventEntry: + case fsm.EventExit: + case unisFsmEventOfline: + e.FSM.StateChange(ctx, unisMOfLine, nil) + case unisFsmEventOnline: + e.FSM.StateChange(ctx, unisMOnLineLoginSync, nil) + default: + return fsm.EventNoProc + } + + return fsm.EventOK +} + +func (f *unisMSystemFsm) unisMOnLine(ctx context.Context, e *fsm.Event) error { + switch e.Event { + case fsm.EventEntry: + case fsm.EventExit: + case unisFsmEventOfline: + e.FSM.StateChange(ctx, unisMOfLine, nil) + case unisFsmEventLoginId: + case unisFsmEventLoginSync: + e.FSM.StateChange(ctx, unisMOnLineLoginSync, nil) + default: + return fsm.EventNoProc + } + + return fsm.EventOK +} + +func (f *unisMSystemFsm) unisMOfLine(ctx context.Context, e *fsm.Event) error { + switch e.Event { + case fsm.EventEntry: + case fsm.EventExit: + case unisFsmEventOnline: + e.FSM.StateChange(ctx, unisMOnLineLoginSync, nil) + default: + return fsm.EventNoProc + } + + return fsm.EventOK +} + +/**********************************主逻辑登录状态机***********************************/ +func (f *unisMSystemFsm) unisMOnLineIdle(ctx context.Context, e *fsm.Event) error { + switch e.Event { + case fsm.EventEntry: + case fsm.EventExit: + case unisFsmEventLoginId: + e.FSM.StateChange(ctx, unisMOnLineLoginId, e.Args) + case unisFsmEventLoginForce: + e.FSM.StateChange(ctx, unisMOnLineLoginning, e.Args) + case unisFsmEventLoginServer: + case unisFsmEventLogout: + e.FSM.StateChange(ctx, unisMOnLineLogouting, e.Args) + case unisFsmEventLogoutForce: + fallthrough + case unisFsmEventLogoutServer: + + default: + return fsm.EventNoProc + } + + return fsm.EventOK +} + +func (f *unisMSystemFsm) unisMOnLineLoginId(ctx context.Context, e *fsm.Event) error { + switch e.Event { + case fsm.EventEntry: + e.FSM.StartEventTimer(ctx, timewheel.TimerTypeOnce, time.Second*5, nil) + case fsm.EventExit: + e.FSM.StopEventTimer() + case unisFsmEventLogin: + e.FSM.StateChange(ctx, unisMOnLineLoginning, e.Args) + case fsm.EventTimeOut: + e.FSM.StateChange(ctx, unisMOnLineIdle, nil) + case unisFsmEventLoginFailed: + e.FSM.StateChange(ctx, unisMOnLineIdle, nil) + default: + return fsm.EventNoProc + } + + return fsm.EventOK +} + +func (f *unisMSystemFsm) unisMOnLineLoginning(ctx context.Context, e *fsm.Event) error { + switch e.Event { + case fsm.EventEntry: + e.FSM.StartEventTimer(ctx, timewheel.TimerTypeOnce, time.Second*5, nil) + case fsm.EventExit: + e.FSM.StopEventTimer() + case fsm.EventTimeOut: + e.FSM.StateChange(ctx, unisMOnLineIdle, nil) + case unisFsmEventLoginFailed: + e.FSM.StateChange(ctx, unisMOnLineIdle, nil) + case unisFsmEventLoginSuccess: + e.FSM.StateChange(ctx, unisMOnLineIdle, nil) + default: + return fsm.EventNoProc + } + + return fsm.EventOK +} + +func (f *unisMSystemFsm) unisMOnLineLogouting(ctx context.Context, e *fsm.Event) error { + switch e.Event { + case fsm.EventEntry: + e.FSM.StartEventTimer(ctx, timewheel.TimerTypeOnce, time.Second*5, nil) + case fsm.EventExit: + e.FSM.StopEventTimer() + case fsm.EventTimeOut: + fallthrough + case unisFsmEventLogoutFailed: + fallthrough + case unisFsmEventLogoutSuccess: + e.FSM.StateChange(ctx, unisMOnLineIdle, nil) + default: + return fsm.EventNoProc + } + + return fsm.EventOK +} + +func (f *unisMSystemFsm) unisMOnLineLoginSync(ctx context.Context, e *fsm.Event) error { + switch e.Event { + case fsm.EventEntry: + e.FSM.StartEventTimer(ctx, timewheel.TimerTypeOnce, time.Second*10, nil) + case fsm.EventExit: + e.FSM.StopEventTimer() + case fsm.EventTimeOut: + + case unisFsmEventLoginSyncFailed: + case unisFsmEventLoginSyncSuccess: + default: + return fsm.EventNoProc + } + + return fsm.EventOK +} + +/***************************主登录状态机********************************************/ +type unisMStateFsm struct { + fsm *fsm.FSM +} + +const ( + unisMState = "unisMState" + unisMStateIdle = "unisMStateIdle" + unisMStateLogin = "unisMStateLogin" + unisMStateLogout = "unisMStateLogout" +) + +func newunisMStateFsm() (*unisMStateFsm, error) { + res := new(unisMStateFsm) + + fsm, err := fsm.NewFsm(unisMState, unisMState, events, []*fsm.StateRule{ + {Name: unisMState, Parent: "", InitState: unisMStateIdle, Processor: res.unisMState, Dst: []string{}}, + {Name: unisMStateIdle, Parent: unisMState, InitState: "", Processor: res.unisMStateIdle, Dst: []string{}}, + {Name: unisMStateLogin, Parent: unisMState, InitState: "", Processor: res.unisMStateLogin, Dst: []string{}}, + {Name: unisMStateLogout, Parent: unisMState, InitState: "", Processor: res.unisMStateLogout, Dst: []string{}}, + {}, + }, zap.NewStdLog(log.Logger)) + + if err != nil { + log.Sugar().Error(err) + return nil, err + } + + res.fsm = fsm + + return res, nil +} + +func (f *unisMStateFsm) reset(ctx context.Context) { + f.fsm.ExecuteEvent(ctx, unisFsmEventReset, nil) +} + +func (f *unisMStateFsm) unisMState(ctx context.Context, e *fsm.Event) error { + switch e.Event { + case fsm.EventEntry: + case fsm.EventExit: + case unisFsmEventReset: + e.FSM.StateChange(ctx, unisMStateIdle, nil) + case unisFsmEventLoginFailed: + case unisFsmEventLogoutFailed: + e.FSM.StateChange(ctx, unisMStateLogout, nil) + default: + return fsm.EventNoProc + } + + return fsm.EventOK +} + +func (f *unisMStateFsm) unisMStateIdle(ctx context.Context, e *fsm.Event) error { + switch e.Event { + case fsm.EventEntry: + + case fsm.EventExit: + case unisFsmEventLoginSuccess: + e.FSM.StateChange(ctx, unisMStateLogin, e.Args) + case unisFsmEventLogoutSuccess: + e.FSM.StateChange(ctx, unisMStateLogout, e.Args) + default: + return fsm.EventNoProc + } + + return fsm.EventOK +} + +func (f *unisMStateFsm) unisMStateLogin(ctx context.Context, e *fsm.Event) error { + switch e.Event { + case fsm.EventEntry: + e.FSM.StartEventTimer(ctx, timewheel.TimerTypeOnce, time.Minute*5, nil) + case fsm.EventExit: + e.FSM.StopEventTimer() + case fsm.EventTimeOut: + e.FSM.StartEventTimer(ctx, timewheel.TimerTypeOnce, time.Minute*5, nil) + case unisFsmEventLoginSuccess: + case unisFsmEventLogoutSuccess: + e.FSM.StateChange(ctx, unisMStateLogout, e.Args) + default: + return fsm.EventNoProc + } + + return fsm.EventOK +} + +func (f *unisMStateFsm) unisMStateLogout(ctx context.Context, e *fsm.Event) error { + switch e.Event { + case fsm.EventEntry: + case fsm.EventExit: + case unisFsmEventLoginSuccess: + e.FSM.StateChange(ctx, unisMStateLogin, e.Args) + default: + return fsm.EventNoProc + } + + return fsm.EventOK +} diff --git a/services/uniss/main.go b/services/uniss/main.go index a57de85..9737bdd 100644 --- a/services/uniss/main.go +++ b/services/uniss/main.go @@ -20,6 +20,7 @@ type UnisStation struct { commonService *commonService communicateService *communicateService dataCenterService *dataCenterService + fsmService *fsmService } func NewUnis(_log *logger.Logger, conf *settings.UnisConfig) (res *UnisStation, err error) { @@ -32,6 +33,11 @@ func NewUnis(_log *logger.Logger, conf *settings.UnisConfig) (res *UnisStation, return } + res.fsmService, err = newfsmService() + if err != nil { + return + } + res.commonService = newcommonService(res) return