Proto/speed.go
2023-09-26 22:39:30 +02:00

172 lines
2.9 KiB
Go

package main
import (
"net"
"os"
"fmt"
"time"
"encoding/binary"
)
var BE = binary.BigEndian
type SpeedMessage interface {
serialize() []byte
}
type ErrorMessage struct {
err string
}
func (m ErrorMessage) serialize() []byte {
return []byte{0x10}
}
type HeartbeatMessage struct {}
func (m HeartbeatMessage) serialize() []byte {
return []byte{0x41}
}
type SpeedServer struct {
port uint16
tickQ chan bool
clients map[uint]*SpeedClient
numClients uint
}
func NewSpeedServer(port uint16) *SpeedServer {
s := &SpeedServer{
port,
make(chan bool),
make(map[uint]*SpeedClient),
0,
}
return s
}
type SpeedClient struct {
clientId uint
con net.Conn
q chan SpeedMessage
ctype uint8
lastHeartbeat int64
heartbeat int64
}
func NewSpeedClient(clientId uint, con net.Conn) *SpeedClient {
return &SpeedClient{
clientId,
con,
make(chan SpeedMessage),
0,
0,
0,
}
}
func (s *SpeedServer) tick() {
cur := time.Now().UnixMilli()
m := HeartbeatMessage{}
for _, c := range s.clients {
if c.heartbeat == 0 { continue }
if c.lastHeartbeat + c.heartbeat < cur {
c.q <- m
c.lastHeartbeat = cur
}
}
}
func (s *SpeedServer) ticker() {
for {
s.tickQ <- true
time.Sleep(100 * time.Millisecond)
}
}
func (s *SpeedServer) main() {
for {
select {
case _ = <- s.tickQ: s.tick()
}
}
}
func (s *SpeedServer) Run() {
go s.listen()
go s.ticker()
s.main()
}
func (s *SpeedServer) listen() {
addr := fmt.Sprintf("0.0.0.0:%d", s.port)
server, err := net.Listen("tcp", addr)
if err != nil {
fmt.Println("Error listening:", err.Error())
os.Exit(1)
}
defer server.Close()
fmt.Println("SpeedServer waiting for client...")
for {
connection, err := server.Accept()
if err != nil {
fmt.Println("Error accepting: ", err.Error())
os.Exit(1)
}
s.start(connection)
}
}
func (s *SpeedServer) start(con net.Conn) {
c := NewSpeedClient(s.numClients, con)
s.clients[s.numClients] = c
s.numClients += 1
go c.sender()
go c.receiver()
}
func (c *SpeedClient) sender() {
for m := range c.q {
c.con.Write(m.serialize())
}
c.con.Close()
fmt.Printf("Client %d closed\n", c.clientId)
}
func (c *SpeedClient) receiver() {
var err error
fmt.Printf("client %d connected\n", c.clientId)
for {
var mType uint8
err = binary.Read(c.con, BE, &mType);
if err != nil { break }
switch mType {
case 0x40: err = c.hdlWantHeartbeat()
default: err = fmt.Errorf("Unknown message type 0x%x", mType)
}
if err != nil { break }
}
if err != nil {
fmt.Printf("Client %d error %s\n", c.clientId, err)
} else {
fmt.Printf("Client %d closing\n", c.clientId)
}
close(c.q)
}
func (c *SpeedClient) hdlWantHeartbeat() error {
var wantedHb uint32
err := binary.Read(c.con, BE, &wantedHb)
if err != nil { return err }
c.heartbeat = int64(wantedHb) * 100
fmt.Printf("heartbeat for %d set to %d\n", c.clientId, wantedHb)
return nil
}