internal/langserver/session/session.go (100 lines of code) (raw):

package session import ( "context" "fmt" "time" "github.com/creachadair/jrpc2" ) type session struct { initializeReq *jrpc2.Request initializeReqTime time.Time initializedReq *jrpc2.Request initializedReqTime time.Time downReq *jrpc2.Request downReqTime time.Time state sessionState exitFunc context.CancelFunc } func (s *session) isPrepared() bool { return s.state == statePrepared } func (s *session) Prepare() error { if s.state != stateEmpty { return &unexpectedSessionState{ ExpectedState: stateInitializedConfirmed, CurrentState: s.state, } } s.state = statePrepared return nil } func (s *session) IsInitializedUnconfirmed() bool { return s.state == stateInitializedUnconfirmed } func (s *session) Initialize(req *jrpc2.Request) error { if s.state != statePrepared { if s.IsInitializedUnconfirmed() { return SessionAlreadyInitializedErr(s.initializeReq.ID()) } return fmt.Errorf("session is not ready to be initalized. State: %s", s.state) } s.initializeReq = req s.initializeReqTime = time.Now() s.state = stateInitializedUnconfirmed return nil } func (s *session) isInitializationConfirmed() bool { return s.state == stateInitializedConfirmed } func (s *session) CheckInitializationIsConfirmed() error { if !s.isInitializationConfirmed() { return SessionNotInitializedErr(s.State()) } return nil } func (s *session) ConfirmInitialization(req *jrpc2.Request) error { if s.state != stateInitializedUnconfirmed { if s.isInitializationConfirmed() { return fmt.Errorf("session was already confirmed as initalized at %s via request %s", s.initializedReqTime, s.initializedReq.ID()) } return fmt.Errorf("session is not ready to be confirmed as initialized (%s)", s.state) } s.initializedReq = req s.initializedReqTime = time.Now() s.state = stateInitializedConfirmed return nil } func (s *session) Shutdown(req *jrpc2.Request) error { if s.isDown() { return SessionAlreadyDownErr(s.downReq.ID()) } s.downReq = req s.downReqTime = time.Now() s.state = stateDown return nil } func (s *session) Exit() error { if !s.isExitable() { return fmt.Errorf("Cannot exit as session is %s", s.State()) } s.exitFunc() return nil } func (s *session) isExitable() bool { return s.isDown() || s.isPrepared() } func (s *session) isDown() bool { return s.state == stateDown } func (s *session) State() sessionState { return s.state } func NewSession(exitFunc context.CancelFunc) *session { return &session{ state: stateEmpty, exitFunc: exitFunc, } }