server.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. package server
  2. import (
  3. "log"
  4. // "io"
  5. "net"
  6. // "errors"
  7. "os"
  8. "time"
  9. "fmt"
  10. "github.com/beoran/woe/monolog"
  11. )
  12. var MSSP map[string] string
  13. const MAX_CLIENTS = 1000
  14. func init() {
  15. MSSP = map[string] string {
  16. "NAME" : "Workers Of Eruta",
  17. "UPTIME" : string(time.Now().Unix()),
  18. "PLAYERS" : "0",
  19. "CRAWL DELAY" : "0",
  20. "CODEBASE" : "WOE",
  21. "CONTACT" : "beoran@gmail.com",
  22. "CREATED" : "2015",
  23. "ICON" : "None",
  24. "LANGUAGE" : "English",
  25. "LOCATION" : "USA",
  26. "MINIMUM AGE" : "18",
  27. "WEBSITE" : "beoran.net",
  28. "FAMILY" : "Custom",
  29. "GENRE" : "Science Fiction",
  30. "GAMEPLAY" : "Adventure",
  31. "STATUS" : "Alpha",
  32. "GAMESYSTEM" : "Custom",
  33. "INTERMUD" : "",
  34. "SUBGENRE" : "None",
  35. "AREAS" : "0",
  36. "HELPFILES" : "0",
  37. "MOBILES" : "0",
  38. "OBJECTS" : "0",
  39. "ROOMS" : "1",
  40. "CLASSES" : "0",
  41. "LEVELS" : "0",
  42. "RACES" : "3",
  43. "SKILLS" : "900",
  44. "ANSI" : "1",
  45. "MCCP" : "1",
  46. "MCP" : "0",
  47. "MSDP" : "0",
  48. "MSP" : "0",
  49. "MXP" : "0",
  50. "PUEBLO" : "0",
  51. "UTF-8" : "1",
  52. "VT100" : "1",
  53. "XTERM 255 COLORS" : "1",
  54. "PAY TO PLAY" : "0",
  55. "PAY FOR PERKS" : "0",
  56. "HIRING BUILDERS" : "0",
  57. "HIRING CODERS" : "0" }
  58. }
  59. type Server struct {
  60. address string
  61. listener net.Listener
  62. logger * log.Logger
  63. logfile * os.File
  64. clients map[int] * Client
  65. tickers map[string] * Ticker
  66. alive bool
  67. }
  68. type Ticker struct {
  69. * time.Ticker
  70. Server * Server
  71. Name string
  72. Milliseconds int
  73. callback func(me * Ticker, t time.Time) (stop bool)
  74. }
  75. func NewServer(address string) (server * Server, err error) {
  76. listener, err := net.Listen("tcp", address);
  77. if (err != nil) {
  78. return nil, err
  79. }
  80. logfile, err := os.OpenFile("log.woe", os.O_WRONLY | os.O_APPEND | os.O_CREATE, 0660)
  81. if (err != nil) {
  82. return nil, err
  83. }
  84. logger := log.New(logfile, "woe", log.Llongfile | log.LstdFlags)
  85. clients := make(map[int] * Client)
  86. tickers := make(map[string] * Ticker)
  87. server = &Server{address, listener, logger, logfile, clients, tickers, true}
  88. server.AddDefaultTickers()
  89. return server, nil
  90. }
  91. func (me * Server) Close() {
  92. me.logfile.Close();
  93. }
  94. func NewTicker(server * Server, name string, milliseconds int, callback func (me * Ticker, t time.Time) bool) (* Ticker) {
  95. ticker := time.NewTicker(time.Millisecond * time.Duration(milliseconds))
  96. return &Ticker {ticker, server, name, milliseconds, callback}
  97. }
  98. func (me * Ticker) Run() {
  99. OUTER:
  100. for me.Server.alive {
  101. for tick := range me.C {
  102. if (!me.callback(me, tick)) {
  103. break OUTER;
  104. }
  105. }
  106. }
  107. }
  108. func (me * Server) RemoveTicker(name string) {
  109. ticker, have := me.tickers[name]
  110. if (!have) {
  111. return
  112. }
  113. ticker.Stop()
  114. delete(me.tickers, name)
  115. }
  116. func (me * Server) StopTicker(name string) {
  117. ticker, have := me.tickers[name]
  118. if (!have) {
  119. return
  120. }
  121. ticker.Stop();
  122. }
  123. func (me * Server) AddTicker(name string, milliseconds int, callback func (me * Ticker, t time.Time) bool) (* Ticker) {
  124. _, have := me.tickers[name]
  125. if have {
  126. me.RemoveTicker(name)
  127. }
  128. ticker := NewTicker(me, name, milliseconds, callback)
  129. me.tickers[name] = ticker
  130. go ticker.Run();
  131. return ticker
  132. }
  133. func onWeatherTicker (me * Ticker, t time.Time) bool {
  134. monolog.Info("Weather Ticker tick tock.")
  135. return true
  136. }
  137. func (me * Server) AddDefaultTickers() {
  138. me.AddTicker("weather", 10000, onWeatherTicker)
  139. }
  140. func (me * Server) handleDisconnectedClients() {
  141. for {
  142. time.Sleep(1)
  143. for id, client := range me.clients {
  144. if (!client.IsAlive()) {
  145. monolog.Info("Client %d has disconnected.", client.id)
  146. client.Close()
  147. delete(me.clients, id);
  148. }
  149. }
  150. }
  151. }
  152. func (me * Server) findFreeID() (id int, err error) {
  153. for id = 0 ; id < MAX_CLIENTS ; id++ {
  154. client, have := me.clients[id]
  155. if (!have) || (client == nil) {
  156. return id, nil
  157. }
  158. }
  159. return -1, fmt.Errorf("Too many clients!");
  160. }
  161. func (me * Server) onConnect(conn net.Conn) (err error) {
  162. id, err := me.findFreeID()
  163. if err != nil {
  164. monolog.Info("Refusing connection because no ID is available for %s. ", conn.RemoteAddr().String())
  165. conn.Close()
  166. return nil
  167. }
  168. monolog.Info("New client connected from %s, id %d. ", conn.RemoteAddr().String(), id)
  169. client := NewClient(me, id, conn)
  170. me.clients[id] = client
  171. return client.Serve()
  172. }
  173. func (me * Server) Serve() (err error) {
  174. go me.handleDisconnectedClients()
  175. for (me.alive) {
  176. conn, err := me.listener.Accept()
  177. if err != nil {
  178. return err
  179. }
  180. go me.onConnect(conn)
  181. }
  182. return nil
  183. }
  184. func (me * Server) Broadcast(message string) {
  185. for _, client := range me.clients {
  186. if (client.IsAlive()) {
  187. client.WriteString(message)
  188. }
  189. }
  190. }