|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
|
|
|
"strconv"
|
|
|
|
|
|
|
|
"github.com/gorilla/websocket"
|
|
|
|
"github.com/jordanorelli/blammo"
|
|
|
|
)
|
|
|
|
|
|
|
|
type server struct {
|
|
|
|
*blammo.Log
|
|
|
|
host string
|
|
|
|
port int
|
|
|
|
world *room
|
|
|
|
lastSessionID int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *server) listen() error {
|
|
|
|
return http.ListenAndServe(fmt.Sprintf("%s:%d", s.host, s.port), s)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
upgrader := websocket.Upgrader{}
|
|
|
|
|
|
|
|
conn, err := upgrader.Upgrade(w, r, nil)
|
|
|
|
if err != nil {
|
|
|
|
s.Error("upgrade error: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
s.lastSessionID++
|
|
|
|
sn := session{
|
|
|
|
Log: s.Log.Child("sessions").Child(strconv.Itoa(s.lastSessionID)),
|
|
|
|
id: s.lastSessionID,
|
|
|
|
conn: conn,
|
|
|
|
outbox: make(chan response),
|
|
|
|
}
|
|
|
|
go sn.pump(ctx)
|
|
|
|
|
|
|
|
for {
|
|
|
|
t, r, err := conn.NextReader()
|
|
|
|
if err != nil {
|
|
|
|
s.Error("read error: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch t {
|
|
|
|
case websocket.TextMessage:
|
|
|
|
text, err := ioutil.ReadAll(r)
|
|
|
|
if err != nil {
|
|
|
|
s.Error("readall error: %v", err)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
sn.Log.Child("received-frame").Info(string(text))
|
|
|
|
var body requestBody
|
|
|
|
if err := json.Unmarshal(text, &body); err != nil {
|
|
|
|
s.Error("unable to parse request: %v", err)
|
|
|
|
sn.outbox <- errorResponse(0, fmt.Errorf("unable to parse request: %v", err))
|
|
|
|
break
|
|
|
|
}
|
|
|
|
sn.outbox <- ok(body.Seq)
|
|
|
|
case websocket.BinaryMessage:
|
|
|
|
sn.outbox <- errorResponse(0, fmt.Errorf("unable to parse binary frames"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|