You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

182 lines
3.5 KiB

7 years ago
  1. package main
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "log"
  7. "bitbucket.org/smcquay/bandwidth"
  8. "code.google.com/p/go.net/websocket"
  9. )
  10. const maxMessageSize = 1024
  11. type protoTalker struct {
  12. ws *websocket.Conn
  13. bw *bandwidth.Bandwidth
  14. send chan Message
  15. buff []byte
  16. Id string
  17. }
  18. func NewProtoTalker(id string, ws *websocket.Conn, bw *bandwidth.Bandwidth) *protoTalker {
  19. return &protoTalker{
  20. send: make(chan Message, 16),
  21. ws: ws,
  22. bw: bw,
  23. Id: id,
  24. buff: make([]byte, maxMessageSize),
  25. }
  26. }
  27. func (pt *protoTalker) sender() {
  28. log.Printf("%s: client launched", pt.Id)
  29. for things := range pt.send {
  30. b, err := json.Marshal(things)
  31. if err != nil {
  32. break
  33. }
  34. n, err := pt.ws.Write(b)
  35. pt.bw.AddTx <- n
  36. if err != nil {
  37. break
  38. }
  39. }
  40. pt.ws.Close()
  41. log.Printf("%s: spectator sender close", pt.Id)
  42. }
  43. func (pt *protoTalker) readJSON() (map[string]Instruction, error) {
  44. msg := map[string]Instruction{}
  45. n, err := pt.ws.Read(pt.buff)
  46. if err != nil {
  47. log.Printf("%s: problem reading from player: %s", pt.Id, err)
  48. return nil, err
  49. }
  50. pt.bw.AddRx <- n
  51. if n == len(pt.buff) {
  52. errMsg := fmt.Sprintf("%s: read buffer overfull: %s", pt.Id, string(pt.buff))
  53. log.Printf(errMsg)
  54. return msg, errors.New(errMsg)
  55. }
  56. err = json.Unmarshal(pt.buff[:n], &msg)
  57. if err != nil {
  58. log.Printf("%s: problem reading from player: %s", pt.Id, err)
  59. return nil, err
  60. }
  61. return msg, nil
  62. }
  63. type player struct {
  64. Robots []*Robot
  65. Instruction Instruction
  66. protoTalker
  67. }
  68. func NewPlayer(id string, ws *websocket.Conn, bw *bandwidth.Bandwidth) *player {
  69. return &player{
  70. Robots: []*Robot{},
  71. protoTalker: *NewProtoTalker(id, ws, bw),
  72. }
  73. }
  74. func (p *player) recv() {
  75. for {
  76. msgs, err := p.readJSON()
  77. if err != nil {
  78. log.Printf("%s: %s", p.Id, err)
  79. break
  80. }
  81. for _, r := range p.Robots {
  82. msg, ok := msgs[r.Id]
  83. if !ok {
  84. continue
  85. }
  86. if msg.Repair != nil && *msg.Repair == true {
  87. r.ActiveScan = false
  88. r.TargetSpeed = 0
  89. r.FireAt = nil
  90. r.MoveTo = nil
  91. if r.RepairCounter <= 0 {
  92. r.RepairCounter = 3.0
  93. }
  94. } else if msg.Scan != nil && *msg.Scan == true {
  95. r.RepairCounter = 0
  96. r.TargetSpeed = 0
  97. r.FireAt = nil
  98. r.MoveTo = nil
  99. r.ActiveScan = true
  100. } else {
  101. r.RepairCounter = 0
  102. r.ActiveScan = false
  103. // Reapiring halts all other activity
  104. if msg.MoveTo != nil {
  105. r.MoveTo = msg.MoveTo
  106. }
  107. if msg.Heading != nil {
  108. r.DesiredHeading = msg.Heading
  109. }
  110. if msg.FireAt != nil {
  111. r.FireAt = msg.FireAt
  112. } else {
  113. r.FireAt = nil
  114. }
  115. if msg.TargetSpeed != nil {
  116. r.TargetSpeed = float32(*msg.TargetSpeed)
  117. } else {
  118. r.TargetSpeed = r.Stats.Speed
  119. }
  120. }
  121. if msg.Probe != nil {
  122. r.Probe = msg.Probe
  123. r.ProbeResult = nil
  124. } else {
  125. r.Probe = nil
  126. }
  127. if msg.Message != nil {
  128. r.Message = *msg.Message
  129. }
  130. }
  131. }
  132. log.Printf("%s: recv close", p.Id)
  133. p.ws.Close()
  134. }
  135. type Spectator struct {
  136. protoTalker
  137. }
  138. func NewSpectator(id string, ws *websocket.Conn, bw *bandwidth.Bandwidth) *Spectator {
  139. return &Spectator{
  140. protoTalker: *NewProtoTalker(id, ws, bw),
  141. }
  142. }
  143. func (s *Spectator) recv() {
  144. for {
  145. _, err := s.readJSON()
  146. if err != nil {
  147. log.Printf("%s: %s", s.Id, err)
  148. break
  149. }
  150. // After the first bit of handshaking, the rest of the messages should
  151. // only be "{}" for spectators, and the following could hold true:
  152. //
  153. // if string(buff[:n]) != "{}" {
  154. // log.Printf("protocol breach!!")
  155. // break
  156. // }
  157. }
  158. log.Printf("%s: recv close", s.Id)
  159. s.ws.Close()
  160. }