server.go 6.8 KB

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