Guest User

Untitled

a guest
Jul 7th, 2015
251
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.19 KB | None | 0 0
  1. package main
  2.  
  3. import (
  4. "bufio"
  5. "flag"
  6. "fmt"
  7. "log"
  8. "net"
  9. "strings"
  10. )
  11.  
  12. func main() {
  13. log.SetPrefix("chat server: ")
  14. addr := flag.String("addr", ":4000", "listen address")
  15. flag.Parse()
  16. s := &server{
  17. addUsername: make(chan *client),
  18. addToChannel: make(chan *client),
  19. remUsername: make(chan *client),
  20. remFromChannel: make(chan *client),
  21. remChannel: make(chan bool)}
  22. log.Fatal(s.listenAndServe(*addr))
  23. }
  24.  
  25. type server struct {
  26. addToChannel chan *client
  27. addUsername chan *client
  28. remUsername chan *client
  29. remFromChannel chan *client
  30. remChannel chan bool
  31. }
  32.  
  33. type channel struct {
  34. name string
  35. server *server
  36. addClient chan *client
  37. remClient chan *client
  38. broadcast chan string
  39. }
  40.  
  41. type client struct {
  42. username string
  43. id string
  44. conn *net.Conn
  45. channel *channel
  46. reader *bufio.Reader
  47. server *server
  48. chanName string
  49. message chan string
  50. ok chan bool
  51. }
  52.  
  53. func (server *server) listenAndServe(addr string) error {
  54. ln, err := net.Listen("tcp", addr)
  55. if err != nil {
  56. return err
  57. }
  58. log.Printf("listening on %s\n", addr)
  59. defer ln.Close()
  60. go server.manageServer()
  61. for {
  62. conn, err := ln.Accept()
  63. if err != nil {
  64. return err
  65. }
  66. log.Printf("new connection from %s\n", conn.RemoteAddr().String())
  67. go server.initializeClient(&conn)
  68. }
  69. }
  70.  
  71. func (server *server) initializeClient(conn *net.Conn) {
  72. client := client{
  73. conn: conn,
  74. reader: bufio.NewReader(*conn),
  75. server: server,
  76. id: "@" + (*conn).RemoteAddr().String(),
  77. message: make(chan string, 20),
  78. ok: make(chan bool)}
  79. go client.writeLoop()
  80. client.message <- "welcome to the chat server\n"
  81. go client.manageClient()
  82. }
  83.  
  84. func (client *client) writeLoop() {
  85. for {
  86. message := <-client.message
  87. _, err := fmt.Fprint(*client.conn, message)
  88. if err != nil {
  89. return
  90. }
  91. }
  92. }
  93.  
  94. func (client *client) shutdown() {
  95. if client.channel != nil {
  96. client.server.remFromChannel <- client
  97. <-client.ok
  98. }
  99. if client.username != "" {
  100. client.server.remUsername <- client
  101. }
  102. (*client.conn).Close()
  103. }
  104.  
  105. func (c *client) getTrimmed(what string) (fromUser string, err error) {
  106. c.message <- what + ": "
  107. fromUser, err = c.reader.ReadString('\n')
  108. if err != nil {
  109. return
  110. }
  111. return strings.TrimSpace(fromUser), err
  112. }
  113.  
  114. func (client *client) manageClient() {
  115. var err error
  116. for {
  117. client.username, err = client.getTrimmed("username")
  118. if err != nil {
  119. client.shutdown()
  120. return
  121. }
  122. client.server.addUsername <- client
  123. if ok := <-client.ok; ok {
  124. break
  125. }
  126. }
  127. client.chanName = "/chch"
  128. for {
  129. client.chanName = strings.TrimSpace(client.chanName[5:])
  130. if client.chanName == "" {
  131. client.chanName, err = client.getTrimmed("channel")
  132. if err != nil {
  133. client.shutdown()
  134. return
  135. }
  136. }
  137. client.server.addToChannel <- client
  138. for {
  139. message, err := client.reader.ReadString('\n')
  140. if err != nil {
  141. client.shutdown()
  142. return
  143. }
  144. if strings.HasPrefix(message, "/chch") {
  145. client.server.remFromChannel <- client
  146. client.chanName = message
  147. <-client.ok
  148. break
  149. }
  150. client.channel.broadcast <- ">>> " + client.username + ": " + message
  151. }
  152. }
  153. }
  154.  
  155. func (server *server) manageServer() {
  156. usernameList := make(map[string]*client)
  157. channelList := make(map[string]*channel)
  158.  
  159. for {
  160. select {
  161. case c := <-server.addUsername:
  162. if _, used := usernameList[c.username]; used {
  163. c.message <- "username " + c.username + " is not available\n"
  164. c.ok <- false
  165. break
  166. }
  167. usernameList[c.username] = c
  168. c.id = c.username + c.id
  169. c.ok <- true
  170. case c := <-server.addToChannel:
  171. if channel, exists := channelList[c.chanName]; exists {
  172. c.channel = channel
  173. channel.addClient <- c
  174. break
  175. }
  176. c.channel = &channel{name: c.chanName, server: c.server,
  177. addClient: make(chan *client),
  178. remClient: make(chan *client),
  179. broadcast: make(chan string)}
  180. channelList[c.channel.name] = c.channel
  181. go c.channel.manageChannel()
  182. c.channel.addClient <- c
  183. case c := <-server.remUsername:
  184. delete(usernameList, c.username)
  185. case c := <-server.remFromChannel:
  186. c.channel.remClient <- c
  187. if true, _ := <-server.remChannel; true {
  188. delete(channelList, c.channel.name)
  189. }
  190. c.ok <- true
  191. }
  192. }
  193. }
  194.  
  195. func (channel *channel) manageChannel() {
  196. clientList := make(map[string]*client)
  197. broadcast := func(message string) {
  198. for _, c := range clientList {
  199. select {
  200. case c.message <- message:
  201. default:
  202. (*c.conn).Close()
  203. }
  204. }
  205. }
  206. for {
  207. select {
  208. case client := <-channel.addClient:
  209. client.message <- "joining channel " + channel.name + "\n"
  210. clientList[client.username] = client
  211. broadcast("+++ " + client.username + " has joined the channel\n")
  212. case message := <-channel.broadcast:
  213. broadcast(message)
  214. case client := <-channel.remClient:
  215. client.message <- "leaving channel " + channel.name + "\n"
  216. delete(clientList, client.username)
  217. broadcast("--- " + client.username + " has left the channel\n")
  218. if len(clientList) == 0 {
  219. channel.server.remChannel <- true
  220. } else {
  221. channel.server.remChannel <- false
  222. }
  223. }
  224. }
  225. }
Advertisement
Add Comment
Please, Sign In to add comment