aboutsummaryrefslogtreecommitdiff
path: root/client.go
diff options
context:
space:
mode:
Diffstat (limited to 'client.go')
-rw-r--r--client.go172
1 files changed, 172 insertions, 0 deletions
diff --git a/client.go b/client.go
new file mode 100644
index 0000000..a57e032
--- /dev/null
+++ b/client.go
@@ -0,0 +1,172 @@
+package main
+
+import (
+ "errors"
+ "github.com/Shopify/go-lua"
+ "github.com/anon55555/mt"
+ "net"
+)
+
+type clientState uint8
+
+const (
+ csNew clientState = iota
+ csConnected
+ csDisconnected
+)
+
+type Handler interface {
+ create(client *Client)
+ push(l *lua.State)
+ canConnect() (bool, string)
+ connect()
+ handle(pkt *mt.Pkt, l *lua.State, idx int)
+}
+
+type Client struct {
+ address string
+ state clientState
+ handlers map[string]Handler
+ conn mt.Peer
+ queue chan *mt.Pkt
+}
+
+func getClient(l *lua.State) *Client {
+ return lua.CheckUserData(l, 1, "hydra.client").(*Client)
+}
+
+func l_client(l *lua.State) int {
+ client := &Client{
+ address: lua.CheckString(l, 1),
+ state: csNew,
+ handlers: map[string]Handler{},
+ }
+
+ l.PushUserData(client)
+
+ if lua.NewMetaTable(l, "hydra.client") {
+ lua.NewLibrary(l, []lua.RegistryFunction{
+ {Name: "address", Function: l_client_address},
+ {Name: "state", Function: l_client_state},
+ {Name: "handler", Function: l_client_handler},
+ {Name: "connect", Function: l_client_connect},
+ {Name: "disconnect", Function: l_client_disconnect},
+ })
+ l.SetField(-2, "__index")
+ }
+ l.SetMetaTable(-2)
+
+ return 1
+}
+
+func l_client_address(l *lua.State) int {
+ client := getClient(l)
+ l.PushString(client.address)
+ return 1
+}
+
+func l_client_state(l *lua.State) int {
+ client := getClient(l)
+ switch client.state {
+ case csNew:
+ l.PushString("new")
+ case csConnected:
+ l.PushString("connected")
+ case csDisconnected:
+ l.PushString("disconnected")
+ }
+ return 1
+}
+
+func l_client_handler(l *lua.State) int {
+ client := getClient(l)
+ name := lua.CheckString(l, 2)
+
+ handler, exists := client.handlers[name]
+ if !exists {
+ switch name {
+ case "callbacks":
+ handler = &Callbacks{}
+
+ case "auth":
+ handler = &Auth{}
+
+ default:
+ return 0
+ }
+
+ client.handlers[name] = handler
+ handler.create(client)
+ }
+
+ handler.push(l)
+ return 1
+}
+
+func l_client_connect(l *lua.State) int {
+ client := getClient(l)
+
+ if client.state != csNew {
+ l.PushBoolean(false)
+ l.PushString("invalid state")
+ return 2
+ }
+
+ for _, handler := range client.handlers {
+ ok, err := handler.canConnect()
+
+ if !ok {
+ l.PushBoolean(false)
+ l.PushString(err)
+ return 2
+ }
+ }
+
+ addr, err := net.ResolveUDPAddr("udp", client.address)
+ if err != nil {
+ l.PushBoolean(false)
+ l.PushString(err.Error())
+ return 2
+ }
+
+ conn, err := net.DialUDP("udp", nil, addr)
+ if err != nil {
+ l.PushBoolean(false)
+ l.PushString(err.Error())
+ return 2
+ }
+
+ client.state = csConnected
+ client.conn = mt.Connect(conn)
+ client.queue = make(chan *mt.Pkt, 1024)
+
+ for _, handler := range client.handlers {
+ handler.connect()
+ }
+
+ go func() {
+ for {
+ pkt, err := client.conn.Recv()
+
+ if err == nil {
+ client.queue <- &pkt
+ } else if errors.Is(err, net.ErrClosed) {
+ close(client.queue)
+ return
+ }
+ }
+ }()
+
+ l.PushBoolean(true)
+ return 1
+}
+
+func l_client_disconnect(l *lua.State) int {
+ client := getClient(l)
+
+ if client.state == csConnected {
+ client.conn.Close()
+ }
+
+ return 0
+}