Lua -> Go: Chat
parent
32f4185a0f
commit
80f2589332
|
@ -0,0 +1,143 @@
|
|||
package multiserver
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf16"
|
||||
)
|
||||
|
||||
type chatCommand struct {
|
||||
privs map[string]bool
|
||||
function func(*Peer, string)
|
||||
}
|
||||
|
||||
var chatCommands map[string]chatCommand
|
||||
var onChatMsg []func(*Peer, string) bool
|
||||
|
||||
func registerChatCommand(name string, privs map[string]bool, function func(*Peer, string)) {
|
||||
chatCommands[name] = chatCommand{privs: privs, function: function}
|
||||
}
|
||||
|
||||
func registerOnChatMessage(function func(*Peer, string) bool) {
|
||||
onChatMsg = append(onChatMsg, function)
|
||||
}
|
||||
|
||||
func processChatMessage(p *Peer, pkt Pkt) bool {
|
||||
s := string(narrow(pkt.Data[4:]))
|
||||
if strings.HasPrefix(s, "#") {
|
||||
// Chat command
|
||||
s = strings.Replace(s, "#", "", 1)
|
||||
params := strings.Split(s, " ")
|
||||
|
||||
// Priv check
|
||||
allow, err := p.checkPrivs(chatCommands[params[0]].privs)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return true
|
||||
}
|
||||
|
||||
if !allow {
|
||||
str := "You do not have permission to run this command! Required privileges: " + strings.Replace(encodePrivs(chatCommands[params[0]].privs), "|", " ", -1)
|
||||
wstr := wider([]byte(str))
|
||||
|
||||
data := make([]byte, 16+len(wstr))
|
||||
data[0] = uint8(0x00)
|
||||
data[1] = uint8(ToClientChatMessage)
|
||||
data[2] = uint8(0x01)
|
||||
data[3] = uint8(0x00)
|
||||
data[4] = uint8(0x00)
|
||||
data[5] = uint8(0x00)
|
||||
binary.BigEndian.PutUint16(data[6:8], uint16(len(str)))
|
||||
copy(data[8:8+len(wstr)], wstr)
|
||||
data[8+len(wstr)] = uint8(0x00)
|
||||
data[9+len(wstr)] = uint8(0x00)
|
||||
data[10+len(wstr)] = uint8(0x00)
|
||||
data[11+len(wstr)] = uint8(0x00)
|
||||
binary.BigEndian.PutUint32(data[12+len(wstr):16+len(wstr)], uint32(time.Now().Unix()))
|
||||
|
||||
ack, err := p.Send(Pkt{Data: data})
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
<-ack
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Callback
|
||||
chatCommands[params[0]].function(p, strings.Join(params[1:], " "))
|
||||
return true
|
||||
} else {
|
||||
// Regular message
|
||||
forward := true
|
||||
for i := range onChatMsg {
|
||||
if onChatMsg[i](p, s) {
|
||||
forward = false
|
||||
}
|
||||
}
|
||||
return forward
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Peer) sendChatMsg(msg string) {
|
||||
wstr := wider([]byte(msg))
|
||||
|
||||
data := make([]byte, 16+len(wstr))
|
||||
data[0] = uint8(0x00)
|
||||
data[1] = uint8(ToClientChatMessage)
|
||||
data[2] = uint8(0x01)
|
||||
data[3] = uint8(0x00)
|
||||
data[4] = uint8(0x00)
|
||||
data[5] = uint8(0x00)
|
||||
binary.BigEndian.PutUint16(data[6:8], uint16(len(msg)))
|
||||
copy(data[8:8+len(wstr)], wstr)
|
||||
data[8+len(wstr)] = uint8(0x00)
|
||||
data[9+len(wstr)] = uint8(0x00)
|
||||
data[10+len(wstr)] = uint8(0x00)
|
||||
data[11+len(wstr)] = uint8(0x00)
|
||||
binary.BigEndian.PutUint32(data[12+len(wstr):16+len(wstr)], uint32(time.Now().Unix()))
|
||||
|
||||
ack, err := p.Send(Pkt{Data: data})
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
<-ack
|
||||
}
|
||||
|
||||
func chatSendAll(msg string) {
|
||||
l := GetListener()
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
for i := range l.addr2peer {
|
||||
l.addr2peer[i].sendChatMsg(msg)
|
||||
}
|
||||
}
|
||||
|
||||
func narrow(b []byte) []byte {
|
||||
if len(b)%2 != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
e := make([]uint16, len(b)/2)
|
||||
|
||||
for i := 0; i < len(b); i += 2 {
|
||||
e[i/2] = binary.BigEndian.Uint16(b[i : 2+i])
|
||||
}
|
||||
|
||||
return []byte(string(utf16.Decode(e)))
|
||||
}
|
||||
|
||||
func wider(b []byte) []byte {
|
||||
r := make([]byte, len(b)*2)
|
||||
|
||||
e := utf16.Encode([]rune(string(b)))
|
||||
|
||||
for i := range e {
|
||||
binary.BigEndian.PutUint16(r[i*2:2+i*2], e[i])
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
package multiserver
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
const (
|
||||
ToClientHello = 0x02
|
||||
ToClientAuthAccept = 0x03
|
||||
ToClientAcceptSudoMode = 0x04
|
||||
ToClientDenySudoMode = 0x05
|
||||
ToClientAccessDenied = 0x0A
|
||||
ToClientBlockdata = 0x20
|
||||
ToClientAddNode = 0x21
|
||||
ToClientRemoveNode = 0x22
|
||||
ToClientInventory = 0x27
|
||||
ToClientTimeOfDay = 0x29
|
||||
ToClientCsmRestrictionFlags = 0x2A
|
||||
ToClientPlayerSpeed = 0x2B
|
||||
ToClientMediaPush = 0x2C
|
||||
ToClientChatMessage = 0x2F
|
||||
ToClientActiveObjectRemoveAdd = 0x31
|
||||
ToClientActiveObjectMessages = 0x32
|
||||
ToClientHp = 0x33
|
||||
ToClientMovePlayer = 0x34
|
||||
ToClientFov = 0x36
|
||||
ToClientDeathscreen = 0x37
|
||||
ToClientMedia = 0x38
|
||||
ToClientTooldef = 0x39
|
||||
ToClientNodedef = 0x3A
|
||||
ToClientCraftitemdef = 0x3B
|
||||
ToClientAnnounceMedia = 0x3C
|
||||
ToClientItemdef = 0x3D
|
||||
ToClientPlaySound = 0x3F
|
||||
ToClientStopSound = 0x40
|
||||
ToClientPrivileges = 0x41
|
||||
ToClientInventoryFormspec = 0x42
|
||||
ToClientDetachedInventory = 0x43
|
||||
ToClientShowFormspec = 0x44
|
||||
ToClientMovement = 0x45
|
||||
ToClientSpawnParticle = 0x46
|
||||
ToClientAddParticlespawner = 0x47
|
||||
ToClientHudAdd = 0x49
|
||||
ToClientHudRm = 0x4A
|
||||
ToClientHudChange = 0x4B
|
||||
ToClientHudSetFlags = 0x4C
|
||||
ToClientHudSetParam = 0x4D
|
||||
ToClientBreath = 0x4E
|
||||
ToClientSetSky = 0x4F
|
||||
ToClientOverrideDayNightRatio = 0x50
|
||||
ToClientLocalPlayerAnimations = 0x51
|
||||
ToClientEyeOffset = 0x52
|
||||
ToClientDeleteParticlespawner = 0x53
|
||||
ToClientCloudParams = 0x54
|
||||
ToClientFadeSound = 0x55
|
||||
ToClientUpdatePlayerList = 0x56
|
||||
ToClientModchannelMsg = 0x57
|
||||
ToClientModchannelSignal = 0x58
|
||||
ToClientNodeMetaChanged = 0x59
|
||||
ToClientSetSun = 0x5A
|
||||
ToClientSetMoon = 0x5B
|
||||
ToClientSetStars = 0x5C
|
||||
ToClientSrpBytesSB = 0x60
|
||||
ToClientFormspecPrepend = 0x61
|
||||
ToClientMinimapModes = 0x62
|
||||
)
|
||||
|
||||
const (
|
||||
ToServerInit = 0x02
|
||||
ToServerInit2 = 0x11
|
||||
ToServerModchannelJoin = 0x17
|
||||
ToServerModchannelLeave = 0x18
|
||||
ToServerModchannelMsg = 0x19
|
||||
ToServerPlayerPos = 0x23
|
||||
ToServerGotblocks = 0x24
|
||||
ToServerDeletedblocks = 0x25
|
||||
ToServerInventoryAction = 0x31
|
||||
ToServerChatMessage = 0x32
|
||||
ToServerDamage = 0x35
|
||||
ToServerPlayerItem = 0x37
|
||||
ToServerRespawn = 0x38
|
||||
ToServerInteract = 0x39
|
||||
ToServerRemovedSounds = 0x3A
|
||||
ToServerNodeMetaFields = 0x3B
|
||||
ToServerInventoryFields = 0x3C
|
||||
ToServerRequestMedia = 0x40
|
||||
ToServerClientReady = 0x43
|
||||
ToServerFirstSrp = 0x50
|
||||
ToServerSrpBytesA = 0x51
|
||||
ToServerSrpBytesM = 0x52
|
||||
)
|
||||
|
||||
const (
|
||||
AccessDeniedWrongPassword = iota
|
||||
AccessDeniedUnexpectedData
|
||||
AccessDeniedSingleplayer
|
||||
AccessDeniedWrongVersion
|
||||
AccessDeniedWrongCharsInName
|
||||
AccessDeniedWrongName
|
||||
AccessDeniedTooManyUsers
|
||||
AccessDeniedEmptyPassword
|
||||
AccessDeniedAlreadyConnected
|
||||
AccessDeniedServerFail
|
||||
AccessDeniedCustomString
|
||||
AccessDeniedShutdown
|
||||
AccessDeniedCrash
|
||||
)
|
||||
|
||||
func processPktCommand(p *Peer, pkt Pkt) bool {
|
||||
if p.IsSrv() {
|
||||
switch cmd := binary.BigEndian.Uint16(pkt.Data[0:2]); cmd {
|
||||
default:
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
switch cmd := binary.BigEndian.Uint16(pkt.Data[0:2]); cmd {
|
||||
case ToServerChatMessage:
|
||||
return processChatMessage(p, pkt)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
253
l_chatmessage.go
253
l_chatmessage.go
|
@ -1,253 +0,0 @@
|
|||
package multiserver
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"github.com/yuin/gopher-lua"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf16"
|
||||
)
|
||||
|
||||
type chatCommand struct {
|
||||
name string
|
||||
privs map[string]bool
|
||||
function *lua.LFunction
|
||||
}
|
||||
|
||||
var chatCommands []chatCommand
|
||||
var chatMessageHandlers []*lua.LFunction
|
||||
|
||||
func registerChatCommand(L *lua.LState) int {
|
||||
name := L.ToString(1)
|
||||
cmddef := L.ToTable(2)
|
||||
|
||||
privs := cmddef.RawGet(lua.LString("privs")).(*lua.LTable)
|
||||
pmap := make(map[string]bool)
|
||||
privs.ForEach(func(k, v lua.LValue) {
|
||||
if lua.LVAsBool(v) {
|
||||
pmap[k.String()] = true
|
||||
}
|
||||
})
|
||||
|
||||
f := cmddef.RawGet(lua.LString("func")).(*lua.LFunction)
|
||||
|
||||
chatCommands = append(chatCommands, chatCommand{name: name, privs: pmap, function: f})
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func registerOnChatMessage(L *lua.LState) int {
|
||||
f := L.ToFunction(1)
|
||||
chatMessageHandlers = append(chatMessageHandlers, f)
|
||||
return 0
|
||||
}
|
||||
|
||||
func processChatMessage(peerid PeerID, msg []byte) bool {
|
||||
s := string(narrow(msg[4:]))
|
||||
if strings.HasPrefix(s, "/") {
|
||||
// Chat command
|
||||
s = strings.Replace(s, "/", "", 1)
|
||||
params := strings.Split(s, " ")
|
||||
for i := range chatCommands {
|
||||
if chatCommands[i].name == params[0] {
|
||||
// Priv check
|
||||
db, err := initAuthDB()
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return true
|
||||
}
|
||||
|
||||
eprivs, err := readPrivItem(db, string(GetListener().GetPeerByID(peerid).username))
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return true
|
||||
}
|
||||
|
||||
db.Close()
|
||||
|
||||
privs := decodePrivs(eprivs)
|
||||
|
||||
allowAccess := true
|
||||
for priv := range chatCommands[i].privs {
|
||||
if chatCommands[i].privs[priv] && !privs[priv] {
|
||||
allowAccess = false
|
||||
}
|
||||
}
|
||||
|
||||
if !allowAccess {
|
||||
str := "You do not have permission to run this command! Required privileges: " + strings.Replace(encodePrivs(chatCommands[i].privs), "|", " ", -1)
|
||||
wstr := wider([]byte(str))
|
||||
|
||||
data := make([]byte, 16+len(wstr))
|
||||
data[0] = uint8(0x00)
|
||||
data[1] = uint8(0x2F)
|
||||
data[2] = uint8(0x01)
|
||||
data[3] = uint8(0x00)
|
||||
data[4] = uint8(0x00)
|
||||
data[5] = uint8(0x00)
|
||||
binary.BigEndian.PutUint16(data[6:8], uint16(len(str)))
|
||||
copy(data[8:8+len(wstr)], wstr)
|
||||
data[8+len(wstr)] = uint8(0x00)
|
||||
data[9+len(wstr)] = uint8(0x00)
|
||||
data[10+len(wstr)] = uint8(0x00)
|
||||
data[11+len(wstr)] = uint8(0x00)
|
||||
binary.BigEndian.PutUint32(data[12+len(wstr):16+len(wstr)], uint32(time.Now().Unix()))
|
||||
|
||||
ack, err := GetListener().GetPeerByID(peerid).Send(Pkt{Data: data, ChNo: 0, Unrel: false})
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
<-ack
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Callback
|
||||
if err := l.CallByParam(lua.P{Fn: chatCommands[i].function, NRet: 1, Protect: true}, lua.LNumber(peerid), lua.LString(strings.Join(params[1:], " "))); err != nil {
|
||||
log.Print(err)
|
||||
|
||||
go func() {
|
||||
End(true, true)
|
||||
}()
|
||||
}
|
||||
if str, ok := l.Get(-1).(lua.LString); ok {
|
||||
wstr := wider([]byte(str.String()))
|
||||
|
||||
data := make([]byte, 16+len(wstr))
|
||||
data[0] = uint8(0x00)
|
||||
data[1] = uint8(0x2F)
|
||||
data[2] = uint8(0x01)
|
||||
data[3] = uint8(0x00)
|
||||
data[4] = uint8(0x00)
|
||||
data[5] = uint8(0x00)
|
||||
binary.BigEndian.PutUint16(data[6:8], uint16(len(str.String())))
|
||||
copy(data[8:8+len(wstr)], wstr)
|
||||
data[8+len(wstr)] = uint8(0x00)
|
||||
data[9+len(wstr)] = uint8(0x00)
|
||||
data[10+len(wstr)] = uint8(0x00)
|
||||
data[11+len(wstr)] = uint8(0x00)
|
||||
binary.BigEndian.PutUint32(data[12+len(wstr):16+len(wstr)], uint32(time.Now().Unix()))
|
||||
|
||||
ack, err := GetListener().GetPeerByID(peerid).Send(Pkt{Data: data})
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
<-ack
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Regular message
|
||||
for i := range chatMessageHandlers {
|
||||
if err := l.CallByParam(lua.P{Fn: chatMessageHandlers[i], NRet: 1, Protect: true}, lua.LNumber(peerid), lua.LString(s)); err != nil {
|
||||
log.Print(err)
|
||||
End(true, true)
|
||||
}
|
||||
if b, ok := l.Get(-1).(lua.LBool); ok {
|
||||
if lua.LVAsBool(b) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func chatSendPlayer(L *lua.LState) int {
|
||||
id := PeerID(L.ToInt(1))
|
||||
msg := L.ToString(2)
|
||||
l := GetListener()
|
||||
p := l.GetPeerByID(id)
|
||||
|
||||
wstr := wider([]byte(msg))
|
||||
|
||||
data := make([]byte, 16+len(wstr))
|
||||
data[0] = uint8(0x00)
|
||||
data[1] = uint8(0x2F)
|
||||
data[2] = uint8(0x01)
|
||||
data[3] = uint8(0x00)
|
||||
data[4] = uint8(0x00)
|
||||
data[5] = uint8(0x00)
|
||||
binary.BigEndian.PutUint16(data[6:8], uint16(len(msg)))
|
||||
copy(data[8:8+len(wstr)], wstr)
|
||||
data[8+len(wstr)] = uint8(0x00)
|
||||
data[9+len(wstr)] = uint8(0x00)
|
||||
data[10+len(wstr)] = uint8(0x00)
|
||||
data[11+len(wstr)] = uint8(0x00)
|
||||
binary.BigEndian.PutUint32(data[12+len(wstr):16+len(wstr)], uint32(time.Now().Unix()))
|
||||
|
||||
ack, err := p.Send(Pkt{Data: data})
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return 0
|
||||
}
|
||||
<-ack
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func chatSendAll(L *lua.LState) int {
|
||||
msg := L.ToString(1)
|
||||
l := GetListener()
|
||||
|
||||
wstr := wider([]byte(msg))
|
||||
|
||||
data := make([]byte, 16+len(wstr))
|
||||
data[0] = uint8(0x00)
|
||||
data[1] = uint8(0x2F)
|
||||
data[2] = uint8(0x01)
|
||||
data[3] = uint8(0x00)
|
||||
data[4] = uint8(0x00)
|
||||
data[5] = uint8(0x00)
|
||||
binary.BigEndian.PutUint16(data[6:8], uint16(len(msg)))
|
||||
copy(data[8:8+len(wstr)], wstr)
|
||||
data[8+len(wstr)] = uint8(0x00)
|
||||
data[9+len(wstr)] = uint8(0x00)
|
||||
data[10+len(wstr)] = uint8(0x00)
|
||||
data[11+len(wstr)] = uint8(0x00)
|
||||
binary.BigEndian.PutUint32(data[12+len(wstr):16+len(wstr)], uint32(time.Now().Unix()))
|
||||
|
||||
i := PeerIDCltMin
|
||||
for l.id2peer[i].Peer != nil {
|
||||
ack, err := l.id2peer[i].Send(Pkt{Data: data})
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return 0
|
||||
}
|
||||
<-ack
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func narrow(b []byte) []byte {
|
||||
if len(b)%2 != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
e := make([]uint16, len(b)/2)
|
||||
|
||||
for i := 0; i < len(b); i += 2 {
|
||||
e[i/2] = binary.BigEndian.Uint16(b[i : 2+i])
|
||||
}
|
||||
|
||||
return []byte(string(utf16.Decode(e)))
|
||||
}
|
||||
|
||||
func wider(b []byte) []byte {
|
||||
r := make([]byte, len(b)*2)
|
||||
|
||||
e := utf16.Encode([]rune(string(b)))
|
||||
|
||||
for i := range e {
|
||||
binary.BigEndian.PutUint16(r[i*2:2+i*2], e[i])
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
5
lua.go
5
lua.go
|
@ -15,11 +15,6 @@ func InitLua() {
|
|||
addLuaFunc(redirect, "redirect")
|
||||
addLuaFunc(getServers, "get_servers")
|
||||
addLuaFunc(registerOnRedirectDone, "register_on_redirect_done")
|
||||
// chatmessage
|
||||
addLuaFunc(registerChatCommand, "register_chatcommand")
|
||||
addLuaFunc(registerOnChatMessage, "register_on_chatmessage")
|
||||
addLuaFunc(chatSendPlayer, "chat_send_player")
|
||||
addLuaFunc(chatSendAll, "chat_send_all")
|
||||
// player
|
||||
addLuaFunc(getPlayerName, "get_player_name")
|
||||
addLuaFunc(luaGetPeerID, "get_peer_id")
|
||||
|
|
47
privs.go
47
privs.go
|
@ -138,3 +138,50 @@ func init() {
|
|||
modPrivItem(db, admin.(string), newprivs)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Peer) getPrivs() (map[string]bool, error) {
|
||||
db, err := initAuthDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
eprivs, err := readPrivItem(db, string(p.username))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return decodePrivs(eprivs), nil
|
||||
}
|
||||
|
||||
func (p *Peer) setPrivs(privs map[string]bool) error {
|
||||
db, err := initAuthDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
err = modPrivItem(db, string(p.username), encodePrivs(privs))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Peer) checkPrivs(req map[string]bool) (bool, error) {
|
||||
privs, err := p.getPrivs()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
allow := true
|
||||
for priv := range req {
|
||||
if req[priv] && !privs[priv] {
|
||||
allow = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return allow, nil
|
||||
}
|
||||
|
|
7
proxy.go
7
proxy.go
|
@ -34,11 +34,8 @@ func Proxy(src, dst *Peer) {
|
|||
}
|
||||
|
||||
// Process
|
||||
// Chat message
|
||||
if pkt.Data[0] == uint8(0x00) && pkt.Data[1] == uint8(0x32) && !src.IsSrv() {
|
||||
if processChatMessage(src.ID(), pkt.Data) {
|
||||
continue
|
||||
}
|
||||
if processPktCommand(src, pkt) {
|
||||
continue
|
||||
}
|
||||
// Active object remove add
|
||||
if pkt.Data[0] == uint8(0x00) && pkt.Data[1] == uint8(0x31) && src.IsSrv() {
|
||||
|
|
Loading…
Reference in New Issue