JCS-pub/coordinator/internal/repl/repl.go

99 lines
1.9 KiB
Go

package repl
import (
"context"
"os"
"strings"
"github.com/c-bata/go-prompt"
"github.com/spf13/cobra"
"gitlink.org.cn/cloudream/common/pkgs/async"
"gitlink.org.cn/cloudream/jcs-pub/coordinator/internal/accesstoken"
"gitlink.org.cn/cloudream/jcs-pub/coordinator/internal/db"
"gitlink.org.cn/cloudream/jcs-pub/coordinator/internal/ticktock"
"golang.org/x/term"
)
var (
cmdCtxKey = &CommandContext{}
)
type ReplEventChan = async.UnboundChannel[ReplEvent]
type ReplEvent interface {
IsReplEvent() bool
}
type ExitEvent struct {
ReplEvent
}
type Repl struct {
prompt *prompt.Prompt
evtCh *ReplEventChan
db *db.DB
tktk *ticktock.TickTock
accessToken *accesstoken.Cache
}
func New(db *db.DB, ticktock *ticktock.TickTock, accessToken *accesstoken.Cache) *Repl {
r := &Repl{
evtCh: async.NewUnboundChannel[ReplEvent](),
db: db,
tktk: ticktock,
accessToken: accessToken,
}
return r
}
func (r *Repl) Start() *ReplEventChan {
go func() {
if term.IsTerminal(int(os.Stdin.Fd())) {
r.prompt = prompt.New(
r.executor,
r.completer,
prompt.OptionPrefix(">>> "),
prompt.OptionTitle("JCS Coordinator REPL"),
prompt.OptionSetExitCheckerOnInput(r.exitChecker),
)
r.prompt.Run()
r.evtCh.Send(ExitEvent{})
}
}()
return r.evtCh
}
func (r *Repl) completer(d prompt.Document) []prompt.Suggest {
return nil
}
func (r *Repl) executor(input string) {
fields := strings.Fields(input)
if len(fields) == 0 {
return
}
RootCmd.SetArgs(fields)
RootCmd.ExecuteContext(context.WithValue(context.Background(), cmdCtxKey, &CommandContext{
repl: r,
}))
}
func (r *Repl) exitChecker(input string, breakline bool) bool {
if breakline && input == "exit" {
return true
}
return false
}
var RootCmd = &cobra.Command{}
type CommandContext struct {
repl *Repl
}
func GetCmdCtx(cmd *cobra.Command) *CommandContext {
return cmd.Context().Value(cmdCtxKey).(*CommandContext)
}