123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- package server
- import (
- "log"
- // "io"
- "net"
- // "errors"
- "os"
- "math/rand"
- "time"
- "fmt"
- "path/filepath"
- "github.com/beoran/woe/monolog"
- )
- var MSSP map[string] string
- const MAX_CLIENTS = 1000
- func init() {
- MSSP = map[string] string {
- "NAME" : "Workers Of Eruta",
- "UPTIME" : string(time.Now().Unix()),
- "PLAYERS" : "0",
- "CRAWL DELAY" : "0",
- "CODEBASE" : "WOE",
- "CONTACT" : "beoran@gmail.com",
- "CREATED" : "2015",
- "ICON" : "None",
- "LANGUAGE" : "English",
- "LOCATION" : "USA",
- "MINIMUM AGE" : "18",
- "WEBSITE" : "beoran.net",
- "FAMILY" : "Custom",
- "GENRE" : "Science Fiction",
- "GAMEPLAY" : "Adventure",
- "STATUS" : "Alpha",
- "GAMESYSTEM" : "Custom",
- "INTERMUD" : "",
- "SUBGENRE" : "None",
- "AREAS" : "0",
- "HELPFILES" : "0",
- "MOBILES" : "0",
- "OBJECTS" : "0",
- "ROOMS" : "1",
- "CLASSES" : "0",
- "LEVELS" : "0",
- "RACES" : "3",
- "SKILLS" : "900",
- "ANSI" : "1",
- "MCCP" : "1",
- "MCP" : "0",
- "MSDP" : "0",
- "MSP" : "0",
- "MXP" : "0",
- "PUEBLO" : "0",
- "UTF-8" : "1",
- "VT100" : "1",
- "XTERM 255 COLORS" : "1",
- "PAY TO PLAY" : "0",
- "PAY FOR PERKS" : "0",
- "HIRING BUILDERS" : "0",
- "HIRING CODERS" : "0" }
- }
- type Server struct {
- address string
- listener net.Listener
- logger * log.Logger
- logfile * os.File
- clients map[int] * Client
- tickers map[string] * Ticker
- alive bool
- }
- type Ticker struct {
- * time.Ticker
- Server * Server
- Name string
- Milliseconds int
- callback func(me * Ticker, t time.Time) (stop bool)
- }
- func NewServer(address string) (server * Server, err error) {
- listener, err := net.Listen("tcp", address);
- if (err != nil) {
- return nil, err
- }
-
- logfile, err := os.OpenFile("log.woe", os.O_WRONLY | os.O_APPEND | os.O_CREATE, 0660)
- if (err != nil) {
- return nil, err
- }
-
- logger := log.New(logfile, "woe", log.Llongfile | log.LstdFlags)
- clients := make(map[int] * Client)
- tickers := make(map[string] * Ticker)
- server = &Server{address, listener, logger, logfile, clients, tickers, true}
- server.AddDefaultTickers()
-
- return server, nil
- }
- func (me * Server) Close() {
- me.logfile.Close();
- }
- func NewTicker(server * Server, name string, milliseconds int, callback func (me * Ticker, t time.Time) bool) (* Ticker) {
- ticker := time.NewTicker(time.Millisecond * time.Duration(milliseconds))
- return &Ticker {ticker, server, name, milliseconds, callback}
- }
- func (me * Ticker) Run() {
- OUTER:
- for me.Server.alive {
- for tick := range me.C {
- if (!me.callback(me, tick)) {
- break OUTER;
- }
- }
- }
- }
- func (me * Server) RemoveTicker(name string) {
- ticker, have := me.tickers[name]
- if (!have) {
- return
- }
- ticker.Stop()
- delete(me.tickers, name)
- }
- func (me * Server) StopTicker(name string) {
- ticker, have := me.tickers[name]
- if (!have) {
- return
- }
- ticker.Stop();
- }
- func (me * Server) AddTicker(name string, milliseconds int, callback func (me * Ticker, t time.Time) bool) (* Ticker) {
- _, have := me.tickers[name]
-
- if have {
- me.RemoveTicker(name)
- }
-
- ticker := NewTicker(me, name, milliseconds, callback)
- me.tickers[name] = ticker
- go ticker.Run();
-
- return ticker
- }
- func onWeatherTicker (me * Ticker, t time.Time) bool {
- monolog.Info("Weather Ticker tick tock.")
- return true
- }
- func (me * Server) AddDefaultTickers() {
- me.AddTicker("weather", 10000, onWeatherTicker)
- }
- func (me * Server) handleDisconnectedClients() {
- for {
- time.Sleep(1)
- for id, client := range me.clients {
- if (!client.IsAlive()) {
- monolog.Info("Client %d has disconnected.", client.id)
- client.Close()
- delete(me.clients, id);
- }
- }
- }
- }
- func (me * Server) findFreeID() (id int, err error) {
- for id = 0 ; id < MAX_CLIENTS ; id++ {
- client, have := me.clients[id]
- if (!have) || (client == nil) {
- return id, nil
- }
- }
- return -1, fmt.Errorf("Too many clients!");
- }
- func (me * Server) onConnect(conn net.Conn) (err error) {
- id, err := me.findFreeID()
- if err != nil {
- monolog.Info("Refusing connection because no ID is available for %s. ", conn.RemoteAddr().String())
- conn.Close()
- return nil
- }
- monolog.Info("New client connected from %s, id %d. ", conn.RemoteAddr().String(), id)
- client := NewClient(me, id, conn)
- me.clients[id] = client
- return client.Serve()
- }
- func (me * Server) Serve() (err error) {
- // Setup random seed here, or whatever
- rand.Seed(time.Now().UTC().UnixNano())
-
- go me.handleDisconnectedClients()
-
- for (me.alive) {
- conn, err := me.listener.Accept()
- if err != nil {
- return err
- }
- go me.onConnect(conn)
- }
- return nil
- }
- func (me * Server) Broadcast(message string) {
- for _, client := range me.clients {
- if (client.IsAlive()) {
- client.WriteString(message)
- }
- }
- }
- // Returns the data path of the server
- func (me * Server) DataPath() string {
- //
- cwd, err := os.Getwd();
- if err != nil {
- cwd = "."
- }
-
- return filepath.Join(cwd, "data", "var")
- }
- // Returns the script path of the server
- func (me * Server) ScriptPath() string {
- //
- cwd, err := os.Getwd();
- if err != nil {
- cwd = "."
- }
-
- return filepath.Join(cwd, "data", "script")
- }
|