281 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			281 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package main
 | 
						|
 | 
						|
import (
 | 
						|
	"bufio"
 | 
						|
	"encoding/binary"
 | 
						|
	"net"
 | 
						|
	"regexp"
 | 
						|
	"strconv"
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
type Client struct {
 | 
						|
	ClientID  uint32
 | 
						|
	Name      string
 | 
						|
	Address   string
 | 
						|
	CompanyID uint8
 | 
						|
}
 | 
						|
 | 
						|
func main() {
 | 
						|
	var (
 | 
						|
		clients     map[uint32]*Client
 | 
						|
		paused      bool = true
 | 
						|
		forcePaused bool = true
 | 
						|
	)
 | 
						|
 | 
						|
	clients = make(map[uint32]*Client)
 | 
						|
 | 
						|
	conn, err := net.Dial("tcp", "poop.siteop.biz:3977")
 | 
						|
	failError(err, "net.Dial")
 | 
						|
	logInfoDebug("Connected to poop.siteop.biz:3977")
 | 
						|
 | 
						|
	//send auth
 | 
						|
	p := PacketAdminJoin{
 | 
						|
		Packet:     Packet{PType: AdminPacketAdminJoin},
 | 
						|
		Password:   "plop",
 | 
						|
		AppName:    "gottdad",
 | 
						|
		AppVersion: "alpha",
 | 
						|
	}
 | 
						|
	_, err = conn.Write(p.Bytes())
 | 
						|
	failError(err, "conn.Write")
 | 
						|
	logInfoDebug("Authentication sent (%v)", p.Bytes())
 | 
						|
	r := bufio.NewReader(conn)
 | 
						|
	b := make([]byte, 0xFFFF)
 | 
						|
	read := 0
 | 
						|
	n := 0
 | 
						|
 | 
						|
	for {
 | 
						|
		p := Packet{}
 | 
						|
 | 
						|
		for {
 | 
						|
			if read >= 3 {
 | 
						|
				//logInfoDebug("Packet read")
 | 
						|
				break
 | 
						|
			}
 | 
						|
			n, err = r.Read(b[read:])
 | 
						|
			logErrorDebug(err, "r.Read")
 | 
						|
			read += n
 | 
						|
			//logInfoDebug("Waiting for packet, read %d bytes.", read)
 | 
						|
 | 
						|
		}
 | 
						|
		p.PLength = binary.LittleEndian.Uint16(b[0:])
 | 
						|
		p.PType = b[2]
 | 
						|
		if p.PLength <= 3 {
 | 
						|
			logInfoAlert("Wrong packet length")
 | 
						|
			break
 | 
						|
		}
 | 
						|
 | 
						|
		//logInfoDebug("Waiting for packet data : len : %d / type : %d", p.PLength, p.PType)
 | 
						|
 | 
						|
		for {
 | 
						|
			if read >= int(p.PLength) {
 | 
						|
				//logInfoDebug("Data read")
 | 
						|
				break
 | 
						|
			}
 | 
						|
			n, err = r.Read(b[read:])
 | 
						|
			logErrorDebug(err, "r.Read")
 | 
						|
			read += n
 | 
						|
			//logInfoDebug("Waiting for data, read %d/%d bytes.", read, p.PLength)
 | 
						|
 | 
						|
		}
 | 
						|
 | 
						|
		switch p.PType {
 | 
						|
		case AdminPacketServerProtocol:
 | 
						|
			sp := PacketServerProtocol{
 | 
						|
				Packet: p,
 | 
						|
			}
 | 
						|
			sp.Read(b[:p.PLength])
 | 
						|
			logInfoDebug("AdminPacketServerProtocol :\n-  ProtocolVersion: %v\n-  FurtherData: %v\n-  UpdatePacketType: %v\n-  FrequenciesAllowed: %b", sp.ProtocolVersion, sp.FurtherData, sp.UpdatePacketType, sp.FrequenciesAllowed)
 | 
						|
		case AdminPacketServerWelcome:
 | 
						|
			sp := PacketServerWelcome{
 | 
						|
				Packet: p,
 | 
						|
			}
 | 
						|
			sp.Read(b[:p.PLength])
 | 
						|
			logInfoDebug("AdminPacketServerWelcome :\n-  ServerName: %v\n-  OpenTTDVersion: %v\n-  Dedicated: %v\n-  MapSeed: %x\n-  MapLandscape: %v\n-  MapStartDate: %v\n-  Size: %v x %v", sp.ServerName, sp.OpenTTDVersion, sp.Dedicated, sp.MapSeed, sp.MapLandscape, sp.MapStartDate, sp.MapX, sp.MapY)
 | 
						|
			px := PacketAdminUpdateFrequency{
 | 
						|
				Packet:          Packet{PType: AdminPacketAdminUpdateFrequency},
 | 
						|
				UpdateType:      AdminUpdateDate,
 | 
						|
				UpdateFrequency: AdminFrequencyDaily,
 | 
						|
			}
 | 
						|
			_, err = conn.Write(px.Bytes())
 | 
						|
 | 
						|
			px = PacketAdminUpdateFrequency{
 | 
						|
				Packet:          Packet{PType: AdminPacketAdminUpdateFrequency},
 | 
						|
				UpdateType:      AdminUpdateClientInfo,
 | 
						|
				UpdateFrequency: AdminFrequencyAutomatic,
 | 
						|
			}
 | 
						|
			_, err = conn.Write(px.Bytes())
 | 
						|
 | 
						|
			px = PacketAdminUpdateFrequency{
 | 
						|
				Packet:          Packet{PType: AdminPacketAdminUpdateFrequency},
 | 
						|
				UpdateType:      AdminUpdateCompanyInfo,
 | 
						|
				UpdateFrequency: AdminFrequencyAutomatic,
 | 
						|
			}
 | 
						|
			_, err = conn.Write(px.Bytes())
 | 
						|
 | 
						|
			px = PacketAdminUpdateFrequency{
 | 
						|
				Packet:          Packet{PType: AdminPacketAdminUpdateFrequency},
 | 
						|
				UpdateType:      AdminUpdateChat,
 | 
						|
				UpdateFrequency: AdminFrequencyAutomatic,
 | 
						|
			}
 | 
						|
			_, err = conn.Write(px.Bytes())
 | 
						|
 | 
						|
			px = PacketAdminUpdateFrequency{
 | 
						|
				Packet:          Packet{PType: AdminPacketAdminUpdateFrequency},
 | 
						|
				UpdateType:      AdminUpdateConsole,
 | 
						|
				UpdateFrequency: AdminFrequencyAutomatic,
 | 
						|
			}
 | 
						|
			_, err = conn.Write(px.Bytes())
 | 
						|
		case AdminPacketServerDate:
 | 
						|
			sp := PacketServerDate{
 | 
						|
				Packet: p,
 | 
						|
			}
 | 
						|
			sp.Read(b[:p.PLength])
 | 
						|
			logInfoDebug("AdminPacketServerDate :\n-  Date: %d\n-  RealDate : %v", sp.Date, toDate(sp.Date))
 | 
						|
			paused = false
 | 
						|
		case AdminPacketServerClientJoin:
 | 
						|
			sp := PacketServerClientJoin{
 | 
						|
				Packet: p,
 | 
						|
			}
 | 
						|
			sp.Read(b[:p.PLength])
 | 
						|
			logInfoDebug("AdminPacketServerClientJoin :\n-  ClientID: %d", sp.ClientID)
 | 
						|
		case AdminPacketServerClientInfo:
 | 
						|
			sp := PacketServerClientInfo{
 | 
						|
				Packet: p,
 | 
						|
			}
 | 
						|
			sp.Read(b[:p.PLength])
 | 
						|
			//logInfoDebug("AdminPacketServerClientInfo :\n-  ClientID: %d\n-  Address: %s\n-  Name: %s\n-  Lang: %d\n-  Date: %d\n-  CompanyID: %d", sp.ClientID, sp.Address, sp.Name, sp.Lang, sp.Date, sp.CompanyID)
 | 
						|
			clt := Client{
 | 
						|
				ClientID:  sp.ClientID,
 | 
						|
				Name:      sp.Name,
 | 
						|
				Address:   sp.Address,
 | 
						|
				CompanyID: sp.CompanyID,
 | 
						|
			}
 | 
						|
			clients[sp.ClientID] = &clt
 | 
						|
			logInfoDebug("Clients : %v", clients)
 | 
						|
		case AdminPacketServerClientError:
 | 
						|
			sp := PacketServerClientError{
 | 
						|
				Packet: p,
 | 
						|
			}
 | 
						|
			sp.Read(b[:p.PLength])
 | 
						|
			logInfoDebug("AdminPacketServerClientError :\n-  ClientID: %d\n-  ErrorID: %d", sp.ClientID, sp.ErrorID)
 | 
						|
		case AdminPacketServerClientQuit:
 | 
						|
			sp := PacketServerClientQuit{
 | 
						|
				Packet: p,
 | 
						|
			}
 | 
						|
			sp.Read(b[:p.PLength])
 | 
						|
			logInfoDebug("AdminPacketServerClientQuit :\n-  ClientID: %d", sp.ClientID)
 | 
						|
			delete(clients, sp.ClientID)
 | 
						|
		case AdminPacketServerChat:
 | 
						|
			sp := PacketServerChat{
 | 
						|
				Packet: p,
 | 
						|
			}
 | 
						|
			sp.Read(b[:p.PLength])
 | 
						|
 | 
						|
			if sp.Message == "!unpause" {
 | 
						|
				logInfoDebug("AdminPacketServerChat : Unpausing")
 | 
						|
				forcePaused = false
 | 
						|
			} else if sp.Message == "!pause" {
 | 
						|
				logInfoDebug("AdminPacketServerChat : Pausing")
 | 
						|
				forcePaused = true
 | 
						|
			} else {
 | 
						|
				logInfoDebug("AdminPacketServerChat :\n-  ActionID: %d\n-  DestinationID: %d\n-  ClientID: %d\n-  Message: %s\n-  Amount: %d", sp.ActionID, sp.DestinationID, sp.ClientID, sp.Message, sp.Amount)
 | 
						|
			}
 | 
						|
		case AdminPacketServerConsole:
 | 
						|
			sp := PacketServerConsole{
 | 
						|
				Packet: p,
 | 
						|
			}
 | 
						|
			sp.Read(b[:p.PLength])
 | 
						|
 | 
						|
			ok, err := regexp.MatchString("\\[udp\\] queried from .*", sp.Text)
 | 
						|
			logErrorDebug(err, "queried from")
 | 
						|
			if sp.Origin != "net" || ok == false {
 | 
						|
				logInfoDebug("AdminPacketServerConsole :\n-  Origin: %q\n-  Text: %s", sp.Origin, sp.Text)
 | 
						|
			}
 | 
						|
		case AdminPacketServerRCon:
 | 
						|
			sp := PacketServerRCon{
 | 
						|
				Packet: p,
 | 
						|
			}
 | 
						|
			sp.Read(b[:p.PLength])
 | 
						|
 | 
						|
			ok, _ := regexp.MatchString("Client #[0-9]+  name: '.*'  company: [0-9]+  IP: .*", sp.Output)
 | 
						|
			if ok {
 | 
						|
				clt := Client{}
 | 
						|
				r, _ := regexp.Compile("Client #(?P<ClientID>[0-9]+)  name: '(?P<Name>.*)'  company: (?P<CompanyID>[0-9]+)  IP: (?P<Address>.*)")
 | 
						|
				ID64, _ := strconv.ParseInt(r.ReplaceAllString(sp.Output, "${ClientID}"), 10, 32)
 | 
						|
				clt.ClientID = uint32(ID64)
 | 
						|
				clt.Name = r.ReplaceAllString(sp.Output, "${Name}")
 | 
						|
				if clt.Name == "" {
 | 
						|
					clt.Name = "server"
 | 
						|
				}
 | 
						|
				ID64, _ = strconv.ParseInt(r.ReplaceAllString(sp.Output, "${CompanyID}"), 10, 8)
 | 
						|
				clt.CompanyID = uint8(ID64)
 | 
						|
				clt.Address = r.ReplaceAllString(sp.Output, "${Address}")
 | 
						|
				clients[clt.ClientID] = &clt
 | 
						|
			} else {
 | 
						|
				logInfoDebug("AdminPacketServerRCon :\n-  ColorID: %d\n-  Output: %s", sp.ColorID, sp.Output)
 | 
						|
			}
 | 
						|
		case AdminPacketServerRConEnd:
 | 
						|
			sp := PacketServerRConEnd{
 | 
						|
				Packet: p,
 | 
						|
			}
 | 
						|
			sp.Read(b[:p.PLength])
 | 
						|
 | 
						|
			if sp.Command == "clients" {
 | 
						|
				for k, v := range clients {
 | 
						|
					logInfoDebug("Client[%d] : %s - %d (%s)", k, v.Name, v.CompanyID, v.Address)
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				logInfoDebug("AdminPacketServerRConEnd :\n-  Command: %s", sp.Command)
 | 
						|
			}
 | 
						|
		default:
 | 
						|
			logInfoDebug("Packet fully read : len : %d / type : %d", p.PLength, p.PType)
 | 
						|
		}
 | 
						|
 | 
						|
		c := make([]byte, 0xFFFF)
 | 
						|
		copy(c, b[p.PLength:])
 | 
						|
		b = c
 | 
						|
		read -= int(p.PLength)
 | 
						|
 | 
						|
		if len(clients) == 0 {
 | 
						|
			px := PacketAdminRCon{
 | 
						|
				Packet:  Packet{PType: AdminPacketAdminRCon},
 | 
						|
				Command: "clients",
 | 
						|
			}
 | 
						|
			_, err = conn.Write(px.Bytes())
 | 
						|
		}
 | 
						|
 | 
						|
		if !paused && forcePaused {
 | 
						|
			paused = true
 | 
						|
			px := PacketAdminRCon{
 | 
						|
				Packet:  Packet{PType: AdminPacketAdminRCon},
 | 
						|
				Command: "pause",
 | 
						|
			}
 | 
						|
			_, err = conn.Write(px.Bytes())
 | 
						|
			logInfoDebug("Pause forced")
 | 
						|
			time.Sleep(1 * time.Second)
 | 
						|
		}
 | 
						|
		if paused && !forcePaused && len(clients) > 1 { // server is client #1
 | 
						|
			paused = false
 | 
						|
			px := PacketAdminRCon{
 | 
						|
				Packet:  Packet{PType: AdminPacketAdminRCon},
 | 
						|
				Command: "unpause",
 | 
						|
			}
 | 
						|
			_, err = conn.Write(px.Bytes())
 | 
						|
			logInfoDebug("Unpause forced")
 | 
						|
			time.Sleep(1 * time.Second)
 | 
						|
		}
 | 
						|
		if !paused && len(clients) == 1 { // server is client #1
 | 
						|
			paused = true
 | 
						|
			px := PacketAdminRCon{
 | 
						|
				Packet:  Packet{PType: AdminPacketAdminRCon},
 | 
						|
				Command: "pause",
 | 
						|
			}
 | 
						|
			_, err = conn.Write(px.Bytes())
 | 
						|
			logInfoDebug("Pausing")
 | 
						|
			time.Sleep(1 * time.Second)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
}
 |