Fix: various bug fix
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
game
|
game
|
||||||
|
inp2025
|
||||||
logs/
|
logs/
|
||||||
|
|||||||
5
Makefile
5
Makefile
@@ -1,4 +1,4 @@
|
|||||||
.PHONY: all clean
|
.PHONY: all clean play
|
||||||
|
|
||||||
GO_ARGS += CGO_ENABLED=0
|
GO_ARGS += CGO_ENABLED=0
|
||||||
|
|
||||||
@@ -12,3 +12,6 @@ $(TARGET): $(SOURCE)
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
-rm -f $(TARGET)
|
-rm -f $(TARGET)
|
||||||
|
|
||||||
|
play:
|
||||||
|
go run . player
|
||||||
|
|||||||
@@ -2,10 +2,5 @@
|
|||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
- Lobby
|
|
||||||
- Login count
|
|
||||||
- Logout and duplicate login
|
|
||||||
- Connection
|
- Connection
|
||||||
- Scan port
|
- Scan port
|
||||||
- Game
|
|
||||||
- Game end reason
|
|
||||||
|
|||||||
@@ -6,11 +6,14 @@ import (
|
|||||||
"gitea.konchin.com/ytshih/inp2025/middlewares"
|
"gitea.konchin.com/ytshih/inp2025/middlewares"
|
||||||
"gitea.konchin.com/ytshih/inp2025/models"
|
"gitea.konchin.com/ytshih/inp2025/models"
|
||||||
"gitea.konchin.com/ytshih/inp2025/types"
|
"gitea.konchin.com/ytshih/inp2025/types"
|
||||||
"gitea.konchin.com/ytshih/inp2025/utils"
|
|
||||||
|
|
||||||
"github.com/uptrace/bunrouter"
|
"github.com/uptrace/bunrouter"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PostLoginOutput struct {
|
||||||
|
LoginCount int `msgpack:"loginCount"`
|
||||||
|
}
|
||||||
|
|
||||||
func (self *Handlers) PostLogin(
|
func (self *Handlers) PostLogin(
|
||||||
w http.ResponseWriter,
|
w http.ResponseWriter,
|
||||||
req bunrouter.Request,
|
req bunrouter.Request,
|
||||||
@@ -25,11 +28,12 @@ func (self *Handlers) PostLogin(
|
|||||||
}
|
}
|
||||||
|
|
||||||
res, err := self.db.NewUpdate().
|
res, err := self.db.NewUpdate().
|
||||||
Model((*models.User)(nil)).
|
Model(&user).
|
||||||
Set("login_count = login_count + ?", 1).
|
Set("login_count = login_count + ?", 1).
|
||||||
Set("is_logged = ?", true).
|
Set("is_logged = ?", true).
|
||||||
Where("is_logged = ?", false).
|
Where("is_logged = ?", false).
|
||||||
Where("username = ?", user.Username).
|
Where("username = ?", user.Username).
|
||||||
|
Returning("*").
|
||||||
Exec(ctx)
|
Exec(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return middlewares.HTTPError{
|
return middlewares.HTTPError{
|
||||||
@@ -46,8 +50,6 @@ func (self *Handlers) PostLogin(
|
|||||||
OriginError: err,
|
OriginError: err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// debug
|
|
||||||
return utils.Success(w)
|
|
||||||
if cnt == 0 {
|
if cnt == 0 {
|
||||||
return middlewares.HTTPError{
|
return middlewares.HTTPError{
|
||||||
StatusCode: http.StatusUnauthorized,
|
StatusCode: http.StatusUnauthorized,
|
||||||
@@ -55,5 +57,7 @@ func (self *Handlers) PostLogin(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return utils.Success(w)
|
return bunrouter.JSON(w, PostLoginOutput{
|
||||||
|
LoginCount: user.LoginCount,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ func (self *Handlers) PostLogout(
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err := self.db.NewUpdate().
|
_, err := self.db.NewUpdate().
|
||||||
|
Model((*models.User)(nil)).
|
||||||
Set("is_logged = ?", false).
|
Set("is_logged = ?", false).
|
||||||
Where("username = ?", user.Username).
|
Where("username = ?", user.Username).
|
||||||
Exec(ctx)
|
Exec(ctx)
|
||||||
|
|||||||
@@ -11,6 +11,11 @@ import (
|
|||||||
"github.com/uptrace/bunrouter"
|
"github.com/uptrace/bunrouter"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PostRegisterInput struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
func (self *Handlers) PostRegister(
|
func (self *Handlers) PostRegister(
|
||||||
w http.ResponseWriter,
|
w http.ResponseWriter,
|
||||||
req bunrouter.Request,
|
req bunrouter.Request,
|
||||||
@@ -26,15 +31,20 @@ func (self *Handlers) PostRegister(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var user models.User
|
var input PostRegisterInput
|
||||||
if err := json.Unmarshal(b, &user); err != nil {
|
if err := json.Unmarshal(b, &input); err != nil {
|
||||||
return middlewares.HTTPError{
|
return middlewares.HTTPError{
|
||||||
StatusCode: http.StatusBadRequest,
|
StatusCode: http.StatusBadRequest,
|
||||||
Message: "failed to unmarshal json into user",
|
Message: "failed to unmarshal json",
|
||||||
OriginError: err,
|
OriginError: err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
user := models.User{
|
||||||
|
Username: input.Username,
|
||||||
|
Password: input.Password,
|
||||||
|
LoginCount: 0,
|
||||||
|
}
|
||||||
res, err := self.db.NewInsert().
|
res, err := self.db.NewInsert().
|
||||||
Model(&user).
|
Model(&user).
|
||||||
On("CONFLICT (username) DO NOTHING").
|
On("CONFLICT (username) DO NOTHING").
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ func (self *Handlers) GetState(
|
|||||||
w http.ResponseWriter,
|
w http.ResponseWriter,
|
||||||
req bunrouter.Request,
|
req bunrouter.Request,
|
||||||
) error {
|
) error {
|
||||||
// fmt.Fprintf(os.Stderr, "GET /api/state\n")
|
|
||||||
c, err := self.upgrader.Upgrade(w, req.Request, nil)
|
c, err := self.upgrader.Upgrade(w, req.Request, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return middlewares.HTTPError{
|
return middlewares.HTTPError{
|
||||||
|
|||||||
@@ -22,15 +22,14 @@ func (op *OperationSubs) Run(self *Handlers) error {
|
|||||||
if !ok {
|
if !ok {
|
||||||
self.state.History[op.Username] = [types.GUESS_COUNT_LIMIT]types.Guess{}
|
self.state.History[op.Username] = [types.GUESS_COUNT_LIMIT]types.Guess{}
|
||||||
}
|
}
|
||||||
// fmt.Fprintf(os.Stderr, "[DEBUG] %+v\n", self.state.History)
|
|
||||||
self.subs = append(self.subs, op.SubsCh)
|
self.subs = append(self.subs, op.SubsCh)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type OperationGuess struct {
|
type OperationGuess struct {
|
||||||
Username string `msgpack:"username"`
|
Username string
|
||||||
Guess string `msgpack:"guess"`
|
Guess string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (op *OperationGuess) Run(self *Handlers) error {
|
func (op *OperationGuess) Run(self *Handlers) error {
|
||||||
@@ -57,6 +56,13 @@ func (op *OperationGuess) Run(self *Handlers) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OperationEnd struct{}
|
||||||
|
|
||||||
|
func (op *OperationEnd) Run(self *Handlers) error {
|
||||||
|
self.state.GameEnd = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type Handlers struct {
|
type Handlers struct {
|
||||||
ans string
|
ans string
|
||||||
state types.WordleState
|
state types.WordleState
|
||||||
@@ -90,7 +96,6 @@ func (self *Handlers) GameFlow() {
|
|||||||
panic(fmt.Errorf("game flow operation failed, %w", err))
|
panic(fmt.Errorf("game flow operation failed, %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// fmt.Fprintf(os.Stderr, "[DEBUG] %+v\n", self.state.History)
|
|
||||||
for _, ch := range self.subs {
|
for _, ch := range self.subs {
|
||||||
*ch <- self.state
|
*ch <- self.state
|
||||||
}
|
}
|
||||||
|
|||||||
16
handlers/wordle/postEnd.go
Normal file
16
handlers/wordle/postEnd.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package wordle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"gitea.konchin.com/ytshih/inp2025/utils"
|
||||||
|
"github.com/uptrace/bunrouter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (self *Handlers) PostEnd(
|
||||||
|
w http.ResponseWriter,
|
||||||
|
req bunrouter.Request,
|
||||||
|
) error {
|
||||||
|
self.opCh <- &OperationEnd{}
|
||||||
|
return utils.Success(w)
|
||||||
|
}
|
||||||
20
player.go
20
player.go
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"gitea.konchin.com/ytshih/inp2025/stages"
|
"gitea.konchin.com/ytshih/inp2025/stages"
|
||||||
|
"gitea.konchin.com/ytshih/inp2025/types"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
@@ -10,17 +11,16 @@ import (
|
|||||||
var playerCmd = &cobra.Command{
|
var playerCmd = &cobra.Command{
|
||||||
Use: "player",
|
Use: "player",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
queue := []*tea.Program{}
|
base := stages.NewBaseModel(viper.GetString("auth-endpoint"))
|
||||||
|
p := tea.NewProgram(stages.NewLandingModel(base))
|
||||||
|
base.Push(types.Program{
|
||||||
|
Run: func() error { _, err := p.Run(); return err },
|
||||||
|
Stage: types.StageLanding,
|
||||||
|
})
|
||||||
|
|
||||||
base := stages.NewBaseModel(&queue, viper.GetString("auth-endpoint"))
|
for base.Size() > 0 {
|
||||||
queue = append(queue,
|
p := base.Pop()
|
||||||
tea.NewProgram(stages.NewLandingModel(base)))
|
if err := p.Run(); err != nil {
|
||||||
|
|
||||||
for len(queue) > 0 {
|
|
||||||
program := queue[0]
|
|
||||||
queue = queue[1:]
|
|
||||||
_, err := program.Run()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,52 @@
|
|||||||
package stages
|
package stages
|
||||||
|
|
||||||
import (
|
import (
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
"gitea.konchin.com/ytshih/inp2025/types"
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BaseModel struct {
|
type BaseModel struct {
|
||||||
queue *[]*tea.Program
|
stack []types.Program
|
||||||
client *resty.Client
|
client *resty.Client
|
||||||
|
|
||||||
|
// after login
|
||||||
|
loginCount int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBaseModel(
|
func NewBaseModel(
|
||||||
queue *[]*tea.Program,
|
|
||||||
endpoint string,
|
endpoint string,
|
||||||
) *BaseModel {
|
) *BaseModel {
|
||||||
return &BaseModel{
|
return &BaseModel{
|
||||||
queue: queue,
|
stack: []types.Program{},
|
||||||
client: resty.New().
|
client: resty.New().
|
||||||
SetBaseURL(endpoint).
|
SetBaseURL(endpoint).
|
||||||
SetDisableWarn(true),
|
SetDisableWarn(true),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *BaseModel) Size() int {
|
||||||
|
return len(m.stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *BaseModel) Pop() types.Program {
|
||||||
|
stack := m.stack[:]
|
||||||
|
var ret types.Program
|
||||||
|
ret, stack = stack[len(stack)-1], stack[:len(stack)-1]
|
||||||
|
m.stack = stack
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *BaseModel) Push(program types.Program) error {
|
||||||
|
stack := m.stack[:]
|
||||||
|
for len(stack) > 0 && stack[len(stack)-1].Stage > program.Stage {
|
||||||
|
var p types.Program
|
||||||
|
p, stack = stack[len(stack)-1], stack[:len(stack)-1]
|
||||||
|
|
||||||
|
if err := p.Run(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stack = append(stack, program)
|
||||||
|
m.stack = stack
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gitea.konchin.com/ytshih/inp2025/models"
|
"gitea.konchin.com/ytshih/inp2025/handlers/auth"
|
||||||
|
"gitea.konchin.com/ytshih/inp2025/types"
|
||||||
"github.com/charmbracelet/bubbles/textinput"
|
"github.com/charmbracelet/bubbles/textinput"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
type landingOperationType int
|
type landingOperationType int
|
||||||
@@ -73,14 +75,18 @@ type postLoginMsg struct{}
|
|||||||
|
|
||||||
func (m *LandingModel) postLogin() tea.Cmd {
|
func (m *LandingModel) postLogin() tea.Cmd {
|
||||||
return func() tea.Msg {
|
return func() tea.Msg {
|
||||||
resp, err := m.BaseModel.client.R().
|
var res auth.PostLoginOutput
|
||||||
|
resp, err := m.client.R().
|
||||||
|
SetResult(&res).
|
||||||
|
ForceContentType("application/json").
|
||||||
SetBasicAuth(m.username.Value(), m.password.Value()).
|
SetBasicAuth(m.username.Value(), m.password.Value()).
|
||||||
Post("/auth/login")
|
Post("/auth/login")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
switch resp.StatusCode() {
|
switch resp.StatusCode() {
|
||||||
case http.StatusOK:
|
case http.StatusOK:
|
||||||
m.BaseModel.client.SetBasicAuth(
|
m.client.SetBasicAuth(
|
||||||
m.username.Value(), m.password.Value())
|
m.username.Value(), m.password.Value())
|
||||||
|
m.loginCount = res.LoginCount
|
||||||
m.info = "login success.\n"
|
m.info = "login success.\n"
|
||||||
m.err = nil
|
m.err = nil
|
||||||
case http.StatusUnauthorized:
|
case http.StatusUnauthorized:
|
||||||
@@ -101,8 +107,8 @@ type postRegisterMsg struct{}
|
|||||||
|
|
||||||
func (m *LandingModel) postRegister() tea.Cmd {
|
func (m *LandingModel) postRegister() tea.Cmd {
|
||||||
return func() tea.Msg {
|
return func() tea.Msg {
|
||||||
resp, err := m.BaseModel.client.R().
|
resp, err := m.client.R().
|
||||||
SetBody(models.User{
|
SetBody(auth.PostRegisterInput{
|
||||||
Username: m.username.Value(),
|
Username: m.username.Value(),
|
||||||
Password: m.password.Value(),
|
Password: m.password.Value(),
|
||||||
}).
|
}).
|
||||||
@@ -193,8 +199,22 @@ func (m *LandingModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
}
|
}
|
||||||
case postLoginMsg:
|
case postLoginMsg:
|
||||||
if m.err == nil {
|
if m.err == nil {
|
||||||
*m.queue = append(*m.queue,
|
m.Push(types.Program{
|
||||||
tea.NewProgram(NewLobbyModel(m.BaseModel)))
|
Run: func() error {
|
||||||
|
m.client.SetBaseURL(viper.GetString("auth-endpoint"))
|
||||||
|
_, err := m.client.R().
|
||||||
|
Post("/auth/logout")
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
Stage: types.StageLanding,
|
||||||
|
})
|
||||||
|
|
||||||
|
program := tea.NewProgram(NewLobbyModel(m.BaseModel))
|
||||||
|
m.Push(types.Program{
|
||||||
|
Run: func() error { _, err := program.Run(); return err },
|
||||||
|
Stage: types.StageLobby,
|
||||||
|
})
|
||||||
|
|
||||||
return m, tea.Quit
|
return m, tea.Quit
|
||||||
} else {
|
} else {
|
||||||
m.reset()
|
m.reset()
|
||||||
|
|||||||
@@ -172,6 +172,7 @@ func (m *LobbyModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "ctrl+c":
|
case "ctrl+c":
|
||||||
|
m.shutdown()
|
||||||
return m, tea.Quit
|
return m, tea.Quit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -207,10 +208,25 @@ func (m *LobbyModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
case serverSendReplyMsg:
|
case serverSendReplyMsg:
|
||||||
if m.err == nil {
|
if m.err == nil {
|
||||||
m.shutdown()
|
m.shutdown()
|
||||||
|
|
||||||
m.client.SetBaseURL("http://" + m.remote)
|
m.client.SetBaseURL("http://" + m.remote)
|
||||||
shutdown := workflows.WordleServer(m.listener)
|
shutdown := workflows.WordleServer(m.listener)
|
||||||
*m.queue = append(*m.queue,
|
m.Push(types.Program{
|
||||||
tea.NewProgram(NewWordleClientModel(m.BaseModel, shutdown)))
|
Run: func() error { shutdown(); return nil },
|
||||||
|
Stage: types.StageGaming,
|
||||||
|
})
|
||||||
|
|
||||||
|
m.Push(types.Program{
|
||||||
|
Run: func() error { m.client.R().Post("/api/end"); return nil },
|
||||||
|
Stage: types.StageGaming,
|
||||||
|
})
|
||||||
|
|
||||||
|
p := tea.NewProgram(NewWordleClientModel(m.BaseModel))
|
||||||
|
m.Push(types.Program{
|
||||||
|
Run: func() error { _, err := p.Run(); return err },
|
||||||
|
Stage: types.StageGaming,
|
||||||
|
})
|
||||||
|
|
||||||
return m, tea.Quit
|
return m, tea.Quit
|
||||||
} else {
|
} else {
|
||||||
m.op = lobbyOperationServerWaiting
|
m.op = lobbyOperationServerWaiting
|
||||||
@@ -229,17 +245,29 @@ func (m *LobbyModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
m.cursor = (m.cursor + 1) % n
|
m.cursor = (m.cursor + 1) % n
|
||||||
}
|
}
|
||||||
case "enter":
|
case "enter":
|
||||||
m.remote = m.endpoints[m.cursor]
|
if n := len(m.endpoints); n > 0 && m.cursor < n {
|
||||||
cmds = append(cmds, m.clientJoin())
|
m.remote = m.endpoints[m.cursor]
|
||||||
|
cmds = append(cmds, m.clientJoin())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case clientScanMsg:
|
case clientScanMsg:
|
||||||
cmds = append(cmds, m.clientScan())
|
cmds = append(cmds, m.clientScan())
|
||||||
case clientJoinMsg:
|
case clientJoinMsg:
|
||||||
if m.err == nil && m.remote != "" {
|
if m.err == nil && m.remote != "" {
|
||||||
m.shutdown()
|
m.shutdown()
|
||||||
|
|
||||||
m.client.SetBaseURL("http://" + m.remote)
|
m.client.SetBaseURL("http://" + m.remote)
|
||||||
*m.BaseModel.queue = append(*m.BaseModel.queue,
|
m.Push(types.Program{
|
||||||
tea.NewProgram(NewWordleClientModel(m.BaseModel, func() {})))
|
Run: func() error { m.client.R().Post("/api/end"); return nil },
|
||||||
|
Stage: types.StageGaming,
|
||||||
|
})
|
||||||
|
|
||||||
|
p := tea.NewProgram(NewWordleClientModel(m.BaseModel))
|
||||||
|
m.Push(types.Program{
|
||||||
|
Run: func() error { _, err := p.Run(); return err },
|
||||||
|
Stage: types.StageGaming,
|
||||||
|
})
|
||||||
|
|
||||||
return m, tea.Quit
|
return m, tea.Quit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,13 +279,16 @@ func (m *LobbyModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
func (m *LobbyModel) View() string {
|
func (m *LobbyModel) View() string {
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
|
|
||||||
|
fmt.Fprintf(&b, "Login as '%s' for '%d' times\n",
|
||||||
|
m.client.UserInfo.Username, m.loginCount)
|
||||||
|
|
||||||
switch m.op {
|
switch m.op {
|
||||||
case lobbyOperationChoose:
|
case lobbyOperationChoose:
|
||||||
b.WriteString("Choose Role\n(S)erver / (C)lient\n")
|
b.WriteString("Choose Role\n(S)erver / (C)lient\n")
|
||||||
case lobbyOperationServerWaiting:
|
case lobbyOperationServerWaiting:
|
||||||
b.WriteString("Wait for user to join...\n")
|
b.WriteString("Wait for user to join...\n")
|
||||||
case lobbyOperationServerChoose:
|
case lobbyOperationServerChoose:
|
||||||
fmt.Fprintf(&b, "Receive Join Request by '%s'\nAccept (Y)/N\n",
|
fmt.Fprintf(&b, "Receive Join Request by '%s'\nAccept (Y) / (n)\n",
|
||||||
m.remoteUser)
|
m.remoteUser)
|
||||||
case lobbyOperationClientScannning:
|
case lobbyOperationClientScannning:
|
||||||
b.WriteString("Scanning server...\nChoose one to join\n")
|
b.WriteString("Scanning server...\nChoose one to join\n")
|
||||||
|
|||||||
@@ -22,9 +22,8 @@ const (
|
|||||||
|
|
||||||
type WordleClientModel struct {
|
type WordleClientModel struct {
|
||||||
*BaseModel
|
*BaseModel
|
||||||
conn *websocket.Conn
|
conn *websocket.Conn
|
||||||
state types.WordleState
|
state types.WordleState
|
||||||
shutdown types.ShutdownFunc
|
|
||||||
|
|
||||||
input textinput.Model
|
input textinput.Model
|
||||||
err error
|
err error
|
||||||
@@ -32,7 +31,6 @@ type WordleClientModel struct {
|
|||||||
|
|
||||||
func NewWordleClientModel(
|
func NewWordleClientModel(
|
||||||
base *BaseModel,
|
base *BaseModel,
|
||||||
shutdown types.ShutdownFunc,
|
|
||||||
) *WordleClientModel {
|
) *WordleClientModel {
|
||||||
input := textinput.New()
|
input := textinput.New()
|
||||||
input.Focus()
|
input.Focus()
|
||||||
@@ -41,7 +39,6 @@ func NewWordleClientModel(
|
|||||||
return &WordleClientModel{
|
return &WordleClientModel{
|
||||||
BaseModel: base,
|
BaseModel: base,
|
||||||
input: input,
|
input: input,
|
||||||
shutdown: shutdown,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,14 +115,15 @@ func (m *WordleClientModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "ctrl+c":
|
case "ctrl+c":
|
||||||
m.conn.Close()
|
m.conn.Close()
|
||||||
m.shutdown()
|
|
||||||
return m, tea.Quit
|
return m, tea.Quit
|
||||||
case "enter":
|
case "enter":
|
||||||
if m.state.GameEnd {
|
if m.state.GameEnd {
|
||||||
m.conn.Close()
|
m.conn.Close()
|
||||||
m.shutdown()
|
p := tea.NewProgram(NewLobbyModel(m.BaseModel))
|
||||||
*m.queue = append(*m.queue,
|
m.Push(types.Program{
|
||||||
tea.NewProgram(NewLobbyModel(m.BaseModel)))
|
Run: func() error { _, err := p.Run(); return err },
|
||||||
|
Stage: types.StageLobby,
|
||||||
|
})
|
||||||
return m, tea.Quit
|
return m, tea.Quit
|
||||||
}
|
}
|
||||||
if len(m.input.Value()) == types.GUESS_WORD_LENGTH {
|
if len(m.input.Value()) == types.GUESS_WORD_LENGTH {
|
||||||
|
|||||||
@@ -2,4 +2,19 @@ package types
|
|||||||
|
|
||||||
type ShutdownFunc func()
|
type ShutdownFunc func()
|
||||||
|
|
||||||
|
type RunFunc func() error
|
||||||
|
|
||||||
|
type StageType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
StageLanding StageType = iota
|
||||||
|
StageLobby
|
||||||
|
StageGaming
|
||||||
|
)
|
||||||
|
|
||||||
|
type Program struct {
|
||||||
|
Run RunFunc
|
||||||
|
Stage StageType
|
||||||
|
}
|
||||||
|
|
||||||
type UsernameType = string
|
type UsernameType = string
|
||||||
|
|||||||
@@ -64,6 +64,8 @@ func WordleServer(listener net.Listener) types.ShutdownFunc {
|
|||||||
wordleHandlers.GetState)
|
wordleHandlers.GetState)
|
||||||
apiGroup.POST("/guess",
|
apiGroup.POST("/guess",
|
||||||
wordleHandlers.PostGuess)
|
wordleHandlers.PostGuess)
|
||||||
|
apiGroup.POST("/end",
|
||||||
|
wordleHandlers.PostEnd)
|
||||||
|
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
Handler: http.Handler(router),
|
Handler: http.Handler(router),
|
||||||
|
|||||||
Reference in New Issue
Block a user