generated from ElnuDev/go-project
Rearrange repo as monorepo
This commit is contained in:
parent
2a59a96493
commit
848175efde
11 changed files with 216 additions and 172 deletions
34
shiritori/api/events.go
Normal file
34
shiritori/api/events.go
Normal file
|
@ -0,0 +1,34 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"git.elnu.com/ElnuDev/shiritori-go/httputils"
|
||||
. "git.elnu.com/ElnuDev/shiritori-go/shiritori"
|
||||
)
|
||||
|
||||
func GenerateApiEvents(clients *ClientSet) httputils.Handler {
|
||||
return httputils.GenerateSseHandler(func(w http.ResponseWriter, r *http.Request) {
|
||||
sendEvent := func(events ...httputils.SseEvent) {
|
||||
for _, event := range events {
|
||||
fmt.Fprint(w, event.Encode())
|
||||
}
|
||||
w.(http.Flusher).Flush()
|
||||
}
|
||||
sendEvent(clients.PlayerCountEvent(1))
|
||||
ctx := r.Context()
|
||||
channel := make(Client)
|
||||
clients.Connect(channel)
|
||||
outer:
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
clients.Disconnect(channel)
|
||||
break outer
|
||||
case events := <-channel:
|
||||
sendEvent(events...)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
20
shiritori/api/submit.go
Normal file
20
shiritori/api/submit.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"git.elnu.com/ElnuDev/shiritori-go/httputils"
|
||||
. "git.elnu.com/ElnuDev/shiritori-go/shiritori"
|
||||
)
|
||||
|
||||
func GenerateApiSubmit(clients *ClientSet) httputils.Handler {
|
||||
return httputils.GenerateHandler(
|
||||
"",
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseMultipartForm(0)
|
||||
clients.BroadcastWord(r.FormValue("word"))
|
||||
},
|
||||
nil,
|
||||
[]string{http.MethodPost},
|
||||
)
|
||||
}
|
76
shiritori/clientset.go
Normal file
76
shiritori/clientset.go
Normal file
|
@ -0,0 +1,76 @@
|
|||
package shiritori
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.elnu.com/ElnuDev/shiritori-go/httputils"
|
||||
)
|
||||
|
||||
type Client = chan []httputils.SseEvent
|
||||
|
||||
const EventWord = "word"
|
||||
const EventPlayerCount = "players"
|
||||
const EventNavigate = "navigate"
|
||||
|
||||
type ClientSet struct {
|
||||
clients map[Client]bool
|
||||
}
|
||||
|
||||
func NewClientSet() ClientSet {
|
||||
return ClientSet{make(map[Client]bool)}
|
||||
}
|
||||
|
||||
func (clients ClientSet) Broadcast(events ...httputils.SseEvent) {
|
||||
for client := range clients.clients {
|
||||
client <- events
|
||||
}
|
||||
}
|
||||
|
||||
func (clients ClientSet) PlayerCount() int {
|
||||
return len(clients.clients)
|
||||
}
|
||||
|
||||
func (clients ClientSet) PlayerCountEvent(offset int) httputils.SseEvent {
|
||||
playerCount := clients.PlayerCount() + offset
|
||||
var data string
|
||||
if playerCount == 0 {
|
||||
data = "No players online."
|
||||
} else {
|
||||
data = fmt.Sprintf("%d player%s online.", playerCount, map[bool]string{true: "", false: "s"}[playerCount == 1])
|
||||
}
|
||||
return httputils.SseEvent{EventName: EventPlayerCount, Data: data}
|
||||
}
|
||||
|
||||
func (clients ClientSet) BroadcastPlayerCount(offset int) {
|
||||
clients.Broadcast(clients.PlayerCountEvent(offset))
|
||||
}
|
||||
|
||||
func (clients ClientSet) BroadcastWord(word string) {
|
||||
clients.Broadcast(
|
||||
httputils.SseEvent{
|
||||
EventName: EventWord,
|
||||
Data: fmt.Sprintf("<div>%s</div>", word),
|
||||
},
|
||||
httputils.SseEvent{
|
||||
EventName: EventNavigate,
|
||||
Data: fmt.Sprintf("https://jisho.org/search/%s", word),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func (clients ClientSet) Connect(client Client) {
|
||||
// Channels are blocking.
|
||||
// Client initialization is waiting for connect() to complete.
|
||||
// If we try to braodcast to it before connect() is done,
|
||||
// the channel handling logic wouldn't have started yet,
|
||||
// and broadcast() would be freeze.
|
||||
// Therefore, we must broadcast an offset player count first,
|
||||
// then actually add the client.
|
||||
clients.BroadcastPlayerCount(1)
|
||||
clients.clients[client] = true
|
||||
}
|
||||
|
||||
func (clients ClientSet) Disconnect(client Client) {
|
||||
delete(clients.clients, client)
|
||||
clients.BroadcastPlayerCount(0)
|
||||
}
|
Reference in a new issue