功能已基本完成,现投入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 {
|
||||
panic("Stack: pop")
|
||||
}
|
||||
ret := s.items[l]
|
||||
ret := s.items[l-1]
|
||||
s.items = s.items[:l-1]
|
||||
return ret
|
||||
}
|
||||
|
||||
103
fsm.go
103
fsm.go
@ -73,7 +73,34 @@ func handleRunningToWaiting() {
|
||||
}
|
||||
|
||||
// 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() {
|
||||
defer close(waitChan)
|
||||
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
|
||||
)
|
||||
|
||||
selectCases := make([]reflect.SelectCase, SIZE)
|
||||
selectCases[CHANCHAN] = reflect.SelectCase{
|
||||
Dir: reflect.SelectRecv, // readonly
|
||||
Chan: reflect.ValueOf(ChanChan),
|
||||
}
|
||||
selectCases[EVENTCHAN] = reflect.SelectCase{
|
||||
Dir: reflect.SelectRecv, // readonly
|
||||
Chan: reflect.ValueOf(eventChan),
|
||||
}
|
||||
selectCases := make([]reflect.SelectCase, 1)
|
||||
//selectCases[CHANCHAN] = reflect.SelectCase{
|
||||
// Dir: reflect.SelectRecv, // readonly
|
||||
// Chan: reflect.ValueOf(ChanChan),
|
||||
//}
|
||||
//selectCases[EVENTCHAN] = reflect.SelectCase{
|
||||
// Dir: reflect.SelectRecv, // readonly
|
||||
// Chan: reflect.ValueOf(eventChan),
|
||||
//}
|
||||
//selectCases[CMDCHAN] = reflect.SelectCase{
|
||||
// Dir: reflect.SelectRecv,
|
||||
// Chan: reflect.ValueOf(cmdChan),
|
||||
//}
|
||||
packagedChan := make(QueryChan)
|
||||
selectCases[0] = reflect.SelectCase{
|
||||
Dir: reflect.SelectRecv,
|
||||
Chan: reflect.ValueOf(packagedChan),
|
||||
}
|
||||
addChan := func(Chan QueryChan) {
|
||||
logger.Debug("handleState():adding new chanchan")
|
||||
logger.Debug("addChan(): adding new chan from chanchan")
|
||||
nelem := reflect.SelectCase{
|
||||
Dir: reflect.SelectDefault,
|
||||
Dir: reflect.SelectRecv,
|
||||
Chan: reflect.ValueOf(Chan),
|
||||
}
|
||||
logger.Debug("addChan(): done")
|
||||
if unused.IsEmpty() {
|
||||
selectCases = append(selectCases, nelem)
|
||||
} else {
|
||||
selectCases[unused.Pop()] = nelem
|
||||
}
|
||||
}
|
||||
logger.Debug("handleState(): ready")
|
||||
const SIGNAL = 114514
|
||||
queryThread := func() {
|
||||
prevId := -1
|
||||
for {
|
||||
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 {
|
||||
unused.Push(id)
|
||||
continue
|
||||
}
|
||||
switch id {
|
||||
case CHANCHAN:
|
||||
nchan := *(*QueryChan)(recv.UnsafePointer())
|
||||
if id != 0 {
|
||||
packagedChan <- MCState(recv.Int())
|
||||
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)
|
||||
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
|
||||
event := globalConnEvent(recv.Int())
|
||||
switch event {
|
||||
case INCOMING:
|
||||
switch state {
|
||||
case STOPPED:
|
||||
handleStoppedToBooting()
|
||||
// case STOPPING: // it shouldn't be there, too, should be handled with conn.go
|
||||
// case BOOTING: //shouldn't be there too
|
||||
case WAITING:
|
||||
handleWaitingToRunning()
|
||||
default:
|
||||
panic("handleState():written wrong!")
|
||||
panic("handleState():written wrong!" + stateToStr[state])
|
||||
}
|
||||
case EMPTY:
|
||||
switch state {
|
||||
case RUNNING:
|
||||
handleRunningToWaiting()
|
||||
case BOOTING:
|
||||
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 {
|
||||
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