~whereswaldon/pointstar

5979b35768165fd9793ed58db280495c8b8083b6 — Chris Waldon 1 year, 7 months ago 34ed55e
feat: make client handle disconnection
4 files changed, 74 insertions(+), 20 deletions(-)

A client/log/log.go
M client/main.go
M client/skin.go
M client/uistate.go
A client/log/log.go => client/log/log.go +31 -0
@@ 0,0 1,31 @@
package log

import (
	"fmt"
	stdlog "log"
)

var stream = make(chan interface{}, 1024)

func init() {
	go func() {
		for logLine := range stream {
			stdlog.Print(logLine)
		}
	}()
}
func Printf(format string, args ...interface{}) {
	Println(fmt.Sprintf(format, args...))
}

func Print(data interface{}) {
	Println(data)
}

func Println(line interface{}) {
	select {
	case stream <- line:
	default:
		// if the channel is full, drop the log line
	}
}

M client/main.go => client/main.go +15 -10
@@ 2,7 2,6 @@ package main

import (
	"context"
	"log"

	"gioui.org/app"
	"gioui.org/font/gofont"


@@ 11,6 10,7 @@ import (
	"gioui.org/widget/material"
	"nhooyr.io/websocket"

	"git.sr.ht/~whereswaldon/pointstar/client/log"
	"git.sr.ht/~whereswaldon/pointstar/gamestate"
	"git.sr.ht/~whereswaldon/pointstar/server/protocol"
)


@@ 20,7 20,8 @@ func main() {
	go func() {
		w := app.NewWindow()
		if err := eventLoop(w); err != nil {
			log.Fatal(err)
			log.Println(err)
			return
		}
	}()
	app.Main()


@@ 39,25 40,27 @@ func (w *WSWorker) Run(window *app.Window) {
		log.Printf("websocket error: %v", err)
	}
	p := &protocol.PlayerConn{Conn: socket, Context: ctx}
	w.FromServer <- nil // send something to indicate that we're connected
	window.Invalidate()
	go func() {
		defer close(w.FromServer)
		for {
			if msgs, err := p.Recv(); err != nil {
				log.Printf("failed receiving from server: %v", err)
				window.Invalidate()
				return
			} else {
				for _, msg := range msgs {
					log.Printf("relaying message %v to front end", msg)
					window.Invalidate()
					w.FromServer <- msg
					window.Invalidate()
				}
			}
		}
	}()
	for {
		select {
		case msg := <-w.ToServer:
			if err := p.Send(msg); err != nil {
				log.Printf("Failed sending set name: %v", err)
			}
	for msg := range w.ToServer {
		if err := p.Send(msg); err != nil {
			log.Printf("Failed sending set name: %v", err)
		}
	}
}


@@ 90,7 93,9 @@ func eventLoop(w *app.Window) error {
			return e.Err
		case system.FrameEvent:
			select {
			case msg := <-fromServer:
			case msg, stillOpen := <-fromServer:
				ui.HasConnected = true
				ui.Connected = stillOpen
				log.Printf("front end read %v from server", msg)
				// receive a new game state if one is available
				switch message := msg.(type) {

M client/skin.go => client/skin.go +19 -4
@@ 9,6 9,7 @@ import (
	"gioui.org/text"
	"gioui.org/unit"
	"gioui.org/widget/material"
	"git.sr.ht/~whereswaldon/pointstar/client/log"
	"git.sr.ht/~whereswaldon/pointstar/gamestate"
	"git.sr.ht/~whereswaldon/pointstar/server/protocol"
)


@@ 19,11 20,25 @@ type Skin struct {
}

func (s *Skin) LayoutAll(g *gamestate.GameState, u *UIState, gtx *layout.Context) {
	switch g.Phase {
	case gamestate.Lobby:
		s.LayoutLobby(g, u, gtx)
	switch {
	case !u.Connected && !u.HasConnected:
		log.Println("connecting")
		layout.Center.Layout(gtx, func() {
			s.H3("Connecting to server...").Layout(gtx)
		})
	case !u.Connected && u.HasConnected:
		log.Println("Disconnected")
		layout.Center.Layout(gtx, func() {
			s.H3("Disconnected unexpectedly! Try reloading to play again.").Layout(gtx)
		})
	default:
		s.LayoutTable(g, u, gtx)
		log.Println("rendering")
		switch g.Phase {
		case gamestate.Lobby:
			s.LayoutLobby(g, u, gtx)
		default:
			s.LayoutTable(g, u, gtx)
		}
	}
}


M client/uistate.go => client/uistate.go +9 -6
@@ 8,12 8,15 @@ import (

// UIState maintains the state of widgets in the UI between frame events
type UIState struct {
	PlayButtons [gamestate.MaxHandSize]widget.Button
	PassButton  widget.Button
	StartButton widget.Button
	NameEditor  widget.Editor
	NameSubmit  widget.Button
	PlayerNum   int
	// HasConnected indicates whether the UI has ever connected to a backend,
	// whereas Connected indicates whether it is *currently* connected
	HasConnected, Connected bool
	PlayButtons             [gamestate.MaxHandSize]widget.Button
	PassButton              widget.Button
	StartButton             widget.Button
	NameEditor              widget.Editor
	NameSubmit              widget.Button
	PlayerNum               int

	HandList layout.List