Geen omschrijving

client.go 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. package funmow
  2. import (
  3. "bufio"
  4. "fmt"
  5. "log"
  6. "net"
  7. "strings"
  8. "unicode"
  9. )
  10. type Client struct {
  11. conn net.Conn
  12. connectionID int
  13. playerID DBRef
  14. authenticated bool
  15. connected bool
  16. reader *bufio.Reader
  17. commandChan chan string
  18. inbound chan PlayerEvent
  19. outbound chan PlayerEvent
  20. eventDistributor *EventDistributor
  21. db *DB
  22. factory *ObjectFactory
  23. }
  24. func NewClient(conn net.Conn, connectionID int, e *EventDistributor, w *DB) *Client {
  25. c := new(Client)
  26. c.conn = conn
  27. c.connectionID = connectionID
  28. c.reader = bufio.NewReader(conn)
  29. c.authenticated = false
  30. c.connected = true
  31. c.commandChan = make(chan string)
  32. c.inbound = make(chan PlayerEvent)
  33. c.eventDistributor = e
  34. c.db = w
  35. c.factory = NewObjectFactory(w)
  36. return c
  37. }
  38. func (c *Client) Run() {
  39. log.Print("Received connection from ", c.conn.RemoteAddr())
  40. go func() {
  41. for c.connected {
  42. message, err := c.reader.ReadString('\n')
  43. if err != nil {
  44. c.connected = false
  45. return
  46. }
  47. message = strings.TrimSpace(message)
  48. if len(message) > 0 {
  49. c.commandChan <- message
  50. }
  51. }
  52. }()
  53. c.splash()
  54. for c.connected {
  55. select {
  56. case m := <-c.inbound:
  57. c.handleInboundEvent(m)
  58. case cmd := <-c.commandChan:
  59. if c.authenticated {
  60. c.sendCommand(cmd)
  61. } else {
  62. c.handleLoginPhase(cmd)
  63. }
  64. }
  65. }
  66. c.conn.Close()
  67. c.outbound <- PlayerEvent{src: c.playerID, dst: c.playerID, messageType: EventTypeTeardown, connectionID: c.connectionID}
  68. log.Print("Lost connection from ", c.conn.RemoteAddr())
  69. }
  70. func (c *Client) splash() {
  71. c.write("Welcome to...\n")
  72. c.write(" ___ __ __ ___ __ __\n")
  73. c.write(" | __| _ _ _ _ | \\/ | / _ \\ \\ \\ / /\n")
  74. c.write(" | _| | || | | ' \\ | |\\/| | | (_) | \\ \\/\\/ /\n")
  75. c.write(" |_| \\_,_| |_||_| |_| |_| \\___/ \\_/\\_/\n\n")
  76. c.write("use connect <username> <password> to login.\n")
  77. }
  78. func (c *Client) handleLoginPhase(message string) {
  79. fields := strings.FieldsFunc(message, func(c rune) bool {
  80. return unicode.IsSpace(c)
  81. })
  82. switch fields[0] {
  83. case "help":
  84. c.write("Commands:\n\tcon[nect] <username>\n\tquit\n")
  85. case "con":
  86. fallthrough
  87. case "connect":
  88. if len(fields) == 3 {
  89. playerID, err := c.db.GetPlayerID(fields[1])
  90. if err != nil {
  91. c.write("Bad username or password.\n")
  92. break
  93. }
  94. c.playerID = playerID
  95. c.authenticated = true
  96. // when a player authenticates, the ipc channels get turned on
  97. subReq := EventSubscribeRequest{
  98. connectionID: c.connectionID,
  99. playerID: c.playerID,
  100. inbound: c.inbound,
  101. outbound: make(chan chan PlayerEvent),
  102. }
  103. c.outbound = c.eventDistributor.Subscribe(subReq)
  104. c.sendCommand("look")
  105. } else {
  106. c.write("What?\n")
  107. }
  108. case "quit":
  109. c.connected = false
  110. default:
  111. c.write("What?\n")
  112. }
  113. }
  114. func (c *Client) handleInboundEvent(m PlayerEvent) {
  115. switch m.messageType {
  116. case EventTypeOutput:
  117. c.write("%s\n", m.message)
  118. case EventTypeQuit:
  119. c.connected = false
  120. }
  121. }
  122. func (c *Client) write(format string, a ...interface{}) {
  123. fmt.Fprintf(c.conn, format, a...)
  124. }
  125. func (c *Client) sendCommand(message string) {
  126. c.outbound <- PlayerEvent{src: c.playerID, dst: c.playerID, message: message, messageType: EventTypeCommand, connectionID: c.connectionID}
  127. }