feat: add tetris shell (Tetris game TUI)
Full-screen Tetris game using Bubbletea with title screen, ghost piece, lock delay, NES-style scoring, configurable difficulty (easy/normal/hard), and honeypot event logging. Bumps version to 0.17.0. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
66
internal/shell/tetris/tetris.go
Normal file
66
internal/shell/tetris/tetris.go
Normal file
@@ -0,0 +1,66 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user