// Listen to a remote stream func (h *Handler) Listen(conn *message.Conn) { defer (func() { // Will be executed when the connection is closed conn.Close() var session *message.Session if h.ctx.IsServer() { session = h.ctx.Auth.GetSession(conn.Id) if session != nil { h.ctx.Auth.Logout(conn.Id) conn.Broadcast(func(w io.Writer) error { return builder.SendPlayerLeft(w, h.ctx.Clock.GetRelativeTick(), session.Entity.Id) }) } } if h.ctx.IsClient() { session = h.ctx.Me } if session != nil && session.Entity != nil { // TODO: move this elsewhere h.ctx.Entity.Delete(session.Entity.Id, h.ctx.Clock.GetAbsoluteTick()) } })() var msgType message.Type for { err := read(conn, &msgType) if err == io.EOF { log.Println("Connection closed.") return } else if err != nil { log.Println("binary.Read failed:", err) return } done := make(chan error, 1) go func() { done <- h.Handle(msgType, conn) }() select { case err = <-done: if err != nil { log.Printf("Message handling failed for %q: %v\n", message.GetTypeName(msgType), err) return } case <-time.After(time.Second * 15): log.Printf("Message handling timed out for %q\n", message.GetTypeName(msgType)) err = fmt.Errorf("Message handling timed out for %q", message.GetTypeName(msgType)) return } } }
func TestMetaAction_PlayerLeft(t *testing.T) { code := message.MetaActionCodes["player_left"] tick := message.Tick(42) entityId := message.EntityId(69) testMessage(t, message.Types["meta_action"], func(w io.Writer) error { return builder.SendPlayerLeft(w, tick, entityId) }, func(conn *message.Conn, t *testing.T) { rt, id, c, _ := handler.ReadMetaAction(conn) if rt != tick { t.Fatal("Sent tick", tick, "but received", rt) } if id != entityId { t.Fatal("Sent entity id", entityId, "but received", id) } if c != code { t.Fatal("Sent code", code, "but received", c) } }) }