package tetris import ( "context" "io" "time" tea "github.com/charmbracelet/bubbletea" "git.t-juice.club/torjus/oubliette/internal/shell" ) const sessionTimeout = 10 * time.Minute // TetrisShell is a Tetris game TUI for the honeypot. type TetrisShell struct{} // NewTetrisShell returns a new TetrisShell instance. func NewTetrisShell() *TetrisShell { return &TetrisShell{} } func (t *TetrisShell) Name() string { return "tetris" } func (t *TetrisShell) Description() string { return "Tetris game TUI" } func (t *TetrisShell) Handle(ctx context.Context, sess *shell.SessionContext, rw io.ReadWriteCloser) error { ctx, cancel := context.WithTimeout(ctx, sessionTimeout) defer cancel() difficulty := configString(sess.ShellConfig, "difficulty", "normal") m := newModel(sess, difficulty) p := tea.NewProgram(m, tea.WithInput(rw), tea.WithOutput(rw), tea.WithAltScreen(), ) done := make(chan error, 1) go func() { _, err := p.Run() done <- err }() select { case err := <-done: return err case <-ctx.Done(): p.Quit() <-done return nil } } // configString reads a string from the shell config map with a default. func configString(cfg map[string]any, key, defaultVal string) string { if cfg == nil { return defaultVal } if v, ok := cfg[key]; ok { if s, ok := v.(string); ok && s != "" { return s } } return defaultVal }