package main
import (
- "github.com/Shopify/go-lua"
- "github.com/anon55555/mt"
+ "github.com/yuin/gopher-lua"
"reflect"
"time"
)
-func l_poll(l *lua.State) int {
- clients := make([]*Client, 0)
-
- lua.CheckType(l, 1, lua.TypeTable)
- i := 1
- for {
- l.RawGetInt(1, i)
- if l.IsNil(-1) {
- l.Pop(1)
- break
- }
-
- clients = append(clients, l.ToUserData(-1).(*Client))
- i++
- }
+type Event interface {
+ handle(l *lua.LState, val lua.LValue)
+}
- var timeout time.Duration
- hasTimeout := false
- if l.IsNumber(3) {
- timeout = time.Duration(lua.CheckNumber(l, 3) * float64(time.Second))
- hasTimeout = true
- }
+type EventTimeout struct{}
- for {
- cases := make([]reflect.SelectCase, 0, len(clients)+2)
+func (evt EventTimeout) handle(l *lua.LState, val lua.LValue) {
+ l.SetField(val, "type", lua.LString("timeout"))
+}
- for _, client := range clients {
- if client.state != csConnected {
- continue
- }
+type EventInterrupt struct{}
- cases = append(cases, reflect.SelectCase{
- Dir: reflect.SelectRecv,
- Chan: reflect.ValueOf(client.queue),
- })
- }
+func (evt EventInterrupt) handle(l *lua.LState, val lua.LValue) {
+ l.SetField(val, "type", lua.LString("interrupt"))
+}
- offset := len(cases)
+func doPoll(l *lua.LState, clients []*Client) int {
+ cases := make([]reflect.SelectCase, 0, len(clients)+2)
- if offset < 1 {
- l.PushBoolean(false)
- return 1
+ for _, client := range clients {
+ if client.state != csConnected {
+ continue
}
cases = append(cases, reflect.SelectCase{
Dir: reflect.SelectRecv,
- Chan: reflect.ValueOf(signalChannel()),
+ Chan: reflect.ValueOf(client.queue),
})
+ }
- if hasTimeout {
- cases = append(cases, reflect.SelectCase{
- Dir: reflect.SelectRecv,
- Chan: reflect.ValueOf(time.After(timeout)),
- })
- }
+ offset := len(cases)
- idx, value, ok := reflect.Select(cases)
+ if offset < 1 {
+ return 0
+ }
- if idx >= offset {
- l.PushBoolean(true)
- return 1
- }
+ cases = append(cases, reflect.SelectCase{
+ Dir: reflect.SelectRecv,
+ Chan: reflect.ValueOf(signalChannel),
+ })
- client := clients[idx]
+ if l.GetTop() > 1 {
+ timeout := time.After(time.Duration(float64(l.ToNumber(2)) * float64(time.Second)))
- var pkt *mt.Pkt = nil
- if ok {
- pkt = value.Interface().(*mt.Pkt)
- } else {
- client.state = csDisconnected
- }
+ cases = append(cases, reflect.SelectCase{
+ Dir: reflect.SelectRecv,
+ Chan: reflect.ValueOf(timeout),
+ })
+ }
- for _, handler := range client.handlers {
- handler.handle(pkt, l, idx+1)
- }
+ idx, value, _ := reflect.Select(cases)
+
+ var evt Event
+ tbl := l.NewTable()
+
+ if idx > offset {
+ evt = EventTimeout{}
+ } else if idx == offset {
+ evt = EventInterrupt{}
+ } else {
+ evt = value.Interface().(Event)
+ l.SetField(tbl, "client", clients[idx].userdata)
}
- panic("impossible")
- return 0
+ evt.handle(l, tbl)
+
+ l.Push(tbl)
+ return 1
}