/
kurafuto.go
133 lines (112 loc) · 2.37 KB
/
kurafuto.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package main
import (
"errors"
"fmt"
"net"
"sync"
"github.com/dchest/uniuri"
"github.com/kurafuto/kyubu/modern/minimal"
)
type Kurafuto struct {
Players []*Player
mutex sync.Mutex
salt string
Name string
Motd string
Hub *Server
Config *Config
Listener net.Listener
Done chan bool
Running bool
rMut sync.Mutex
}
func (ku *Kurafuto) Quit() {
ku.rMut.Lock()
if !ku.Running {
ku.rMut.Unlock()
return
}
ku.Running = false
ku.rMut.Unlock()
// So we don't take on any new players.
ku.Listener.Close()
for len(ku.Players) > 0 {
for _, p := range ku.Players {
disc, _ := classic.NewDisconnectPlayer("Server shutting down.")
p.Client.C <- disc
p.Quit()
}
}
ku.Done <- true
}
func (ku *Kurafuto) Run() {
ku.rMut.Lock()
ku.Running = true
ku.rMut.Unlock()
for {
ku.rMut.Lock()
if !ku.Running {
ku.rMut.Unlock()
break
}
ku.rMut.Unlock()
c, err := ku.Listener.Accept()
if err != nil && !ku.Running {
break
} else if err != nil {
Fatal(err)
}
p, err := NewPlayer(c, ku)
if err != nil {
c.Close()
continue
}
ku.Players = append(ku.Players, p)
Infof("New connection from %s (%d clients)", c.RemoteAddr().String(), len(ku.Players))
Debugf("(%s) New connection from %s", p.Id, c.RemoteAddr().String())
go p.Parse()
}
}
func (ku *Kurafuto) Remove(p *Player) bool {
ku.mutex.Lock()
defer ku.mutex.Unlock()
for i, player := range ku.Players {
if player != p {
continue
}
p.Quit() // just in case
// Remove and zero player to allow GC to collect it.
copy(ku.Players[i:], ku.Players[i+1:])
ku.Players[len(ku.Players)-1] = nil
ku.Players = ku.Players[:len(ku.Players)-1]
f := "%s (%s) disconnected"
if p.Name == "" {
f = "%s(%s) disconnected"
}
Infof(f, p.Name, p.Remote())
Debugf("(%s) %s disconnected from slot %d", p.Id, p.Remote(), i)
return true
}
return false
}
func NewKurafuto(config *Config) (ku *Kurafuto, err error) {
if len(config.Servers) < 1 {
err = errors.New("kurafuto: Need at least 1 server in config.")
return
}
listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", config.Address, config.Port))
if err != nil {
return
}
ku = &Kurafuto{
Players: []*Player{},
mutex: sync.Mutex{},
salt: uniuri.New(),
Hub: &config.Servers[0],
Config: config,
Listener: listener,
Done: make(chan bool, 1),
rMut: sync.Mutex{},
}
return
}