功能已基本完成,现投入docker进行测试
This commit is contained in:
parent
519c945eff
commit
084f3644ff
71
conn.go
Normal file
71
conn.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
func handle(client net.Conn) {
|
||||||
|
defer client.Close()
|
||||||
|
queryChan := make(QueryChan)
|
||||||
|
ChanChan <- queryChan
|
||||||
|
proceed := func() {
|
||||||
|
server, err := net.Dial("tcp", "127.0.0.1:25565")
|
||||||
|
defer server.Close()
|
||||||
|
if err != nil {
|
||||||
|
GetLogger().Errorf("Failed to connect to MC server: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(2)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
if _, err := io.Copy(server, client); err != nil {
|
||||||
|
GetLogger().Errorf("Error forwarding client to server: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 从服务器到客户端
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
if _, err := io.Copy(client, server); err != nil {
|
||||||
|
GetLogger().Errorf("Error forwarding server to client: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
GetLogger().Infof("Connection from %s closed", client.RemoteAddr())
|
||||||
|
}
|
||||||
|
switch state {
|
||||||
|
case RUNNING:
|
||||||
|
CntChan <- INCREASE
|
||||||
|
defer func() { CntChan <- DECREASE }()
|
||||||
|
proceed()
|
||||||
|
case STOPPED, WAITING:
|
||||||
|
// client.Write([]byte("Server not ready!"))
|
||||||
|
GetLogger().Warnf("Connection queued, server currently at %s state", stateToStr[state])
|
||||||
|
CntChan <- INCREASE
|
||||||
|
defer func() { CntChan <- DECREASE }()
|
||||||
|
<-RunningChan
|
||||||
|
proceed()
|
||||||
|
default:
|
||||||
|
client.Write([]byte("Server not ready!"))
|
||||||
|
GetLogger().Warnf("Connection refused, server currently at %s state", stateToStr[state])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func Listen() {
|
||||||
|
listener, _ := net.Listen("tcp", "0.0.0.0:"+config.Port)
|
||||||
|
defer listener.Close()
|
||||||
|
GetLogger().Infof("Listening on %s", config.Port)
|
||||||
|
for {
|
||||||
|
conn, err := listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
GetLogger().Errorf("ection error: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
GetLogger().Infof("New connection from %s", conn.RemoteAddr())
|
||||||
|
go handle(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
41
daemon.go
41
daemon.go
@ -0,0 +1,41 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
var proc *exec.Cmd
|
||||||
|
var DaemonChanRX = make(chan struct{})
|
||||||
|
var DaemonChanTX = make(chan struct{})
|
||||||
|
|
||||||
|
func Stopped() {
|
||||||
|
<-DaemonChanTX
|
||||||
|
DaemonChanRX <- struct{}{}
|
||||||
|
go Booting()
|
||||||
|
}
|
||||||
|
func Booting() {
|
||||||
|
GetLogger().Info("Starting MC Server")
|
||||||
|
arg := strings.Fields(config.StartCommand)
|
||||||
|
proc = exec.Command(arg[0], arg[1:]...)
|
||||||
|
proc.Stdout = os.Stdout
|
||||||
|
proc.Stderr = os.Stderr
|
||||||
|
proc.Start()
|
||||||
|
DaemonChanRX <- struct{}{}
|
||||||
|
GetLogger().Info("enter RUNNING state")
|
||||||
|
go Running()
|
||||||
|
|
||||||
|
}
|
||||||
|
func Running() {
|
||||||
|
<-DaemonChanTX
|
||||||
|
go Stopping()
|
||||||
|
DaemonChanRX <- struct{}{}
|
||||||
|
}
|
||||||
|
func Stopping() {
|
||||||
|
proc.Process.Signal(syscall.SIGINT)
|
||||||
|
proc.Wait()
|
||||||
|
go Stopped()
|
||||||
|
DaemonChanRX <- struct{}{}
|
||||||
|
}
|
||||||
2
ds.go
2
ds.go
@ -19,7 +19,7 @@ func (s *Stack[T]) Pop() T {
|
|||||||
if l == 0 {
|
if l == 0 {
|
||||||
panic("Stack: pop")
|
panic("Stack: pop")
|
||||||
}
|
}
|
||||||
ret := s.items[l]
|
ret := s.items[l-1]
|
||||||
s.items = s.items[:l-1]
|
s.items = s.items[:l-1]
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|||||||
103
fsm.go
103
fsm.go
@ -73,7 +73,34 @@ func handleRunningToWaiting() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: work with daemon
|
// TODO: work with daemon
|
||||||
func handleWaitingToStopping() {}
|
func handleWaitingToStopping() {
|
||||||
|
go stoppingThread()
|
||||||
|
state = STOPPING
|
||||||
|
}
|
||||||
|
func stoppingThread() {
|
||||||
|
DaemonChanTX <- struct{}{}
|
||||||
|
<-DaemonChanRX
|
||||||
|
handleStoppingToStopped()
|
||||||
|
}
|
||||||
|
func handleStoppingToStopped() {
|
||||||
|
state = STOPPED
|
||||||
|
}
|
||||||
|
func bootingThread() {
|
||||||
|
DaemonChanTX <- struct{}{}
|
||||||
|
<-DaemonChanRX
|
||||||
|
handleBootingToRunning()
|
||||||
|
}
|
||||||
|
|
||||||
|
var RunningChan = make(chan struct{})
|
||||||
|
|
||||||
|
func handleBootingToRunning() {
|
||||||
|
state = RUNNING
|
||||||
|
RunningChan <- struct{}{}
|
||||||
|
}
|
||||||
|
func handleStoppedToBooting() {
|
||||||
|
go bootingThread()
|
||||||
|
state = BOOTING
|
||||||
|
}
|
||||||
func waitingThread() {
|
func waitingThread() {
|
||||||
defer close(waitChan)
|
defer close(waitChan)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(config.Timeout)*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(config.Timeout)*time.Minute)
|
||||||
@ -96,64 +123,98 @@ func handleState() { //goroutine only, handles both write and read
|
|||||||
SIZE
|
SIZE
|
||||||
)
|
)
|
||||||
|
|
||||||
selectCases := make([]reflect.SelectCase, SIZE)
|
selectCases := make([]reflect.SelectCase, 1)
|
||||||
selectCases[CHANCHAN] = reflect.SelectCase{
|
//selectCases[CHANCHAN] = reflect.SelectCase{
|
||||||
Dir: reflect.SelectRecv, // readonly
|
// Dir: reflect.SelectRecv, // readonly
|
||||||
Chan: reflect.ValueOf(ChanChan),
|
// Chan: reflect.ValueOf(ChanChan),
|
||||||
}
|
//}
|
||||||
selectCases[EVENTCHAN] = reflect.SelectCase{
|
//selectCases[EVENTCHAN] = reflect.SelectCase{
|
||||||
Dir: reflect.SelectRecv, // readonly
|
// Dir: reflect.SelectRecv, // readonly
|
||||||
Chan: reflect.ValueOf(eventChan),
|
// Chan: reflect.ValueOf(eventChan),
|
||||||
}
|
//}
|
||||||
//selectCases[CMDCHAN] = reflect.SelectCase{
|
//selectCases[CMDCHAN] = reflect.SelectCase{
|
||||||
// Dir: reflect.SelectRecv,
|
// Dir: reflect.SelectRecv,
|
||||||
// Chan: reflect.ValueOf(cmdChan),
|
// Chan: reflect.ValueOf(cmdChan),
|
||||||
//}
|
//}
|
||||||
|
packagedChan := make(QueryChan)
|
||||||
|
selectCases[0] = reflect.SelectCase{
|
||||||
|
Dir: reflect.SelectRecv,
|
||||||
|
Chan: reflect.ValueOf(packagedChan),
|
||||||
|
}
|
||||||
addChan := func(Chan QueryChan) {
|
addChan := func(Chan QueryChan) {
|
||||||
logger.Debug("handleState():adding new chanchan")
|
logger.Debug("addChan(): adding new chan from chanchan")
|
||||||
nelem := reflect.SelectCase{
|
nelem := reflect.SelectCase{
|
||||||
Dir: reflect.SelectDefault,
|
Dir: reflect.SelectRecv,
|
||||||
Chan: reflect.ValueOf(Chan),
|
Chan: reflect.ValueOf(Chan),
|
||||||
}
|
}
|
||||||
|
logger.Debug("addChan(): done")
|
||||||
if unused.IsEmpty() {
|
if unused.IsEmpty() {
|
||||||
selectCases = append(selectCases, nelem)
|
selectCases = append(selectCases, nelem)
|
||||||
} else {
|
} else {
|
||||||
selectCases[unused.Pop()] = nelem
|
selectCases[unused.Pop()] = nelem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.Debug("handleState(): ready")
|
const SIGNAL = 114514
|
||||||
|
queryThread := func() {
|
||||||
|
prevId := -1
|
||||||
for {
|
for {
|
||||||
id, recv, ok := reflect.Select(selectCases)
|
id, recv, ok := reflect.Select(selectCases)
|
||||||
|
logger.Debugf("queryThread(): recv message from No.%d", id)
|
||||||
|
if prevId != -1 {
|
||||||
|
logger.Debug("queryThread(): clearing previous")
|
||||||
|
selectCases[prevId].Dir = reflect.SelectRecv
|
||||||
|
selectCases[prevId].Send = reflect.Value{}
|
||||||
|
prevId = -1
|
||||||
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
unused.Push(id)
|
unused.Push(id)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch id {
|
if id != 0 {
|
||||||
case CHANCHAN:
|
packagedChan <- MCState(recv.Int())
|
||||||
nchan := *(*QueryChan)(recv.UnsafePointer())
|
state, _ := <-packagedChan
|
||||||
|
selectCases[id].Dir = reflect.SelectSend
|
||||||
|
selectCases[id].Send = reflect.ValueOf(state)
|
||||||
|
prevId = id
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
go queryThread()
|
||||||
|
logger.Debug("handleState(): ready")
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case nchan, _ := <-ChanChan:
|
||||||
addChan(nchan)
|
addChan(nchan)
|
||||||
case EVENTCHAN:
|
packagedChan <- SIGNAL
|
||||||
|
//selectCases[id].Dir = reflect.SelectSend
|
||||||
|
//selectCases[id].Send = reflect.ValueOf(make(QueryChan))
|
||||||
|
//prevId = id
|
||||||
|
case event, _ := <-eventChan:
|
||||||
// wait until transformation finishes
|
// wait until transformation finishes
|
||||||
event := globalConnEvent(recv.Int())
|
|
||||||
switch event {
|
switch event {
|
||||||
case INCOMING:
|
case INCOMING:
|
||||||
switch state {
|
switch state {
|
||||||
case STOPPED:
|
case STOPPED:
|
||||||
|
handleStoppedToBooting()
|
||||||
// case STOPPING: // it shouldn't be there, too, should be handled with conn.go
|
// case STOPPING: // it shouldn't be there, too, should be handled with conn.go
|
||||||
|
// case BOOTING: //shouldn't be there too
|
||||||
case WAITING:
|
case WAITING:
|
||||||
handleWaitingToRunning()
|
handleWaitingToRunning()
|
||||||
default:
|
default:
|
||||||
panic("handleState():written wrong!")
|
panic("handleState():written wrong!" + stateToStr[state])
|
||||||
}
|
}
|
||||||
case EMPTY:
|
case EMPTY:
|
||||||
switch state {
|
switch state {
|
||||||
case RUNNING:
|
case RUNNING:
|
||||||
handleRunningToWaiting()
|
handleRunningToWaiting()
|
||||||
|
case BOOTING:
|
||||||
default:
|
default:
|
||||||
panic("handleState():written wrong!")
|
panic("handleState():written wrong!" + stateToStr[state])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
case <-packagedChan:
|
||||||
|
packagedChan <- state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
4
main.go
4
main.go
@ -10,5 +10,7 @@ func main() {
|
|||||||
if err := LoadConfig("config.yml"); err != nil {
|
if err := LoadConfig("config.yml"); err != nil {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
InitState()
|
||||||
|
go Stopped()
|
||||||
|
Listen()
|
||||||
}
|
}
|
||||||
|
|||||||
4
restart.sh
Normal file
4
restart.sh
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
CGO_ENABLED=0 go build -o bin/minimcd
|
||||||
|
cd bin
|
||||||
|
./minimcd
|
||||||
|
cd ..
|
||||||
Loading…
Reference in New Issue
Block a user