multiserver/media.go

431 lines
9.7 KiB
Go
Raw Normal View History

2021-01-24 05:00:26 -08:00
package main
2021-01-16 10:14:31 -08:00
import (
"encoding/binary"
2021-01-21 05:35:48 -08:00
"encoding/hex"
2021-03-02 08:47:07 -08:00
"errors"
2021-01-21 05:35:48 -08:00
"io/ioutil"
2021-01-16 10:14:31 -08:00
"log"
"net"
2021-01-21 05:35:48 -08:00
"os"
"strings"
"github.com/anon55555/mt/rudp"
2021-01-16 10:14:31 -08:00
)
var media map[string]*mediaFile
2021-02-09 23:35:14 -08:00
var nodedefs map[string][]byte
var itemdefs map[string][]byte
2021-01-16 10:31:07 -08:00
var detachedinvs map[string][][]byte
2021-01-16 10:14:31 -08:00
var movement []byte
var timeofday []byte
type mediaFile struct {
digest []byte
data []byte
}
func (p *Peer) fetchMedia() {
if !p.IsSrv() {
return
}
for {
pkt, err := p.Recv()
if err != nil {
2021-03-02 08:47:07 -08:00
if errors.Is(err, net.ErrClosed) {
2021-01-16 10:14:31 -08:00
return
}
log.Print(err)
continue
}
switch cmd := binary.BigEndian.Uint16(pkt.Data[0:2]); cmd {
case ToClientNodedef:
2021-03-09 13:23:41 -08:00
servers := ConfKey("servers").(map[interface{}]interface{})
2021-02-09 23:35:14 -08:00
var srvname string
for server := range servers {
2021-03-09 13:23:41 -08:00
if ConfKey("servers:"+server.(string)+":address") == p.Addr().String() {
2021-02-09 23:35:14 -08:00
srvname = server.(string)
break
2021-02-09 23:35:14 -08:00
}
}
nodedefs[srvname] = pkt.Data[6:]
2021-01-16 10:14:31 -08:00
case ToClientItemdef:
2021-03-09 13:23:41 -08:00
servers := ConfKey("servers").(map[interface{}]interface{})
var srvname string
for server := range servers {
2021-03-09 13:23:41 -08:00
if ConfKey("servers:"+server.(string)+":address") == p.Addr().String() {
srvname = server.(string)
break
}
}
itemdefs[srvname] = pkt.Data[6:]
2021-01-16 10:14:31 -08:00
case ToClientMovement:
movement = pkt.Data[2:]
case ToClientDetachedInventory:
2021-03-09 13:23:41 -08:00
servers := ConfKey("servers").(map[interface{}]interface{})
2021-01-16 10:31:07 -08:00
var srvname string
for server := range servers {
2021-03-09 13:23:41 -08:00
if ConfKey("servers:"+server.(string)+":address") == p.Addr().String() {
2021-01-16 10:31:07 -08:00
srvname = server.(string)
break
2021-01-16 10:31:07 -08:00
}
}
detachedinvs[srvname] = append(detachedinvs[srvname], pkt.Data[2:])
2021-01-16 10:14:31 -08:00
case ToClientTimeOfDay:
timeofday = pkt.Data[2:]
case ToClientAnnounceMedia:
var rq []string
count := binary.BigEndian.Uint16(pkt.Data[2:4])
si := uint32(4)
2021-01-16 10:14:31 -08:00
for i := uint16(0); i < count; i++ {
2021-01-16 10:31:07 -08:00
namelen := binary.BigEndian.Uint16(pkt.Data[si : 2+si])
name := pkt.Data[2+si : 2+si+uint32(namelen)]
diglen := binary.BigEndian.Uint16(pkt.Data[2+si+uint32(namelen) : 4+si+uint32(namelen)])
digest := pkt.Data[4+si+uint32(namelen) : 4+si+uint32(namelen)+uint32(diglen)]
2021-01-16 10:14:31 -08:00
2021-01-21 05:35:48 -08:00
if media[string(name)] == nil && !isCached(string(name), digest) {
2021-01-16 10:14:31 -08:00
rq = append(rq, string(name))
media[string(name)] = &mediaFile{digest: digest}
}
si += 4 + uint32(namelen) + uint32(diglen)
2021-01-16 10:14:31 -08:00
}
// Request the media
pktlen := 0
for f := range rq {
2021-01-16 10:31:07 -08:00
pktlen += 2 + len(rq[f])
2021-01-16 10:14:31 -08:00
}
data := make([]byte, 4+pktlen)
data[0] = uint8(0x00)
data[1] = uint8(ToServerRequestMedia)
binary.BigEndian.PutUint16(data[2:4], uint16(len(rq)))
sj := 4
for f := range rq {
binary.BigEndian.PutUint16(data[sj:2+sj], uint16(len(rq[f])))
copy(data[2+sj:2+sj+len(rq[f])], []byte(rq[f]))
2021-01-16 10:31:07 -08:00
sj += 2 + len(rq[f])
2021-01-16 10:14:31 -08:00
}
_, err := p.Send(rudp.Pkt{Data: data, ChNo: 1})
2021-01-16 10:14:31 -08:00
if err != nil {
log.Print(err)
continue
}
case ToClientMedia:
bunchcount := binary.BigEndian.Uint16(pkt.Data[2:4])
bunch := binary.BigEndian.Uint16(pkt.Data[4:6])
filecount := binary.BigEndian.Uint32(pkt.Data[6:10])
si := uint32(10)
for i := uint32(0); i < filecount; i++ {
2021-01-16 10:31:07 -08:00
namelen := binary.BigEndian.Uint16(pkt.Data[si : 2+si])
name := pkt.Data[2+si : 2+si+uint32(namelen)]
datalen := binary.BigEndian.Uint32(pkt.Data[2+si+uint32(namelen) : 6+si+uint32(namelen)])
data := pkt.Data[6+si+uint32(namelen) : 6+uint32(si)+uint32(namelen)+datalen]
2021-01-16 10:14:31 -08:00
if media[string(name)] != nil && len(media[string(name)].data) == 0 {
media[string(name)].data = data
}
2021-01-16 10:31:07 -08:00
si += 6 + uint32(namelen) + datalen
2021-01-16 10:14:31 -08:00
}
if bunch >= bunchcount-1 {
p.SendDisco(0, true)
p.Close()
return
}
}
}
}
2021-01-20 12:44:35 -08:00
func (p *Peer) updateDetachedInvs(srvname string) {
for i := range detachedinvs[srvname] {
data := make([]byte, 2+len(detachedinvs[srvname][i]))
data[0] = uint8(0x00)
data[1] = uint8(ToClientDetachedInventory)
copy(data[2:], detachedinvs[srvname][i])
ack, err := p.Send(rudp.Pkt{Data: data})
if err != nil {
log.Print(err)
continue
}
<-ack
}
}
2021-01-16 10:14:31 -08:00
func (p *Peer) announceMedia() {
2021-03-09 13:23:41 -08:00
srvname, ok := ConfKey("default_server").(string)
2021-01-19 09:57:58 -08:00
if !ok {
2021-01-16 10:31:07 -08:00
log.Print("Default server name not set or not a string")
return
}
2021-02-09 23:35:14 -08:00
data := make([]byte, 6+len(nodedef))
data[0] = uint8(0x00)
data[1] = uint8(ToClientNodedef)
binary.BigEndian.PutUint32(data[2:6], uint32(len(nodedef)))
copy(data[6:], nodedef)
2021-01-16 10:14:31 -08:00
2021-02-09 23:35:14 -08:00
ack, err := p.Send(rudp.Pkt{Data: data})
if err != nil {
log.Print(err)
2021-01-16 10:14:31 -08:00
}
2021-02-09 23:35:14 -08:00
<-ack
2021-01-16 10:14:31 -08:00
2021-02-10 22:40:42 -08:00
data = make([]byte, 6+len(itemdef))
data[0] = uint8(0x00)
data[1] = uint8(ToClientItemdef)
binary.BigEndian.PutUint32(data[2:6], uint32(len(itemdef)))
copy(data[6:], itemdef)
2021-01-16 10:14:31 -08:00
2021-02-10 22:40:42 -08:00
ack, err = p.Send(rudp.Pkt{Data: data})
if err != nil {
log.Print(err)
2021-01-16 10:14:31 -08:00
}
2021-02-10 22:40:42 -08:00
<-ack
2021-01-16 10:14:31 -08:00
2021-01-20 12:44:35 -08:00
p.updateDetachedInvs(srvname)
2021-01-16 10:14:31 -08:00
2021-02-09 23:35:14 -08:00
data = make([]byte, 2+len(movement))
2021-01-16 10:14:31 -08:00
data[0] = uint8(0x00)
data[1] = uint8(ToClientMovement)
copy(data[2:], movement)
2021-02-09 23:35:14 -08:00
ack, err = p.Send(rudp.Pkt{Data: data})
2021-01-16 10:14:31 -08:00
if err != nil {
log.Print(err)
}
<-ack
data = make([]byte, 2+len(timeofday))
data[0] = uint8(0x00)
data[1] = uint8(ToClientTimeOfDay)
copy(data[2:], timeofday)
ack, err = p.Send(rudp.Pkt{Data: data})
2021-01-16 10:14:31 -08:00
if err != nil {
log.Print(err)
}
<-ack
2021-03-09 13:23:41 -08:00
csmrf, ok := ConfKey("csm_restriction_flags").(int)
2021-01-22 09:31:57 -08:00
if !ok {
csmrf = 0
}
data = make([]byte, 14)
data[0] = uint8(0x00)
data[1] = uint8(ToClientCsmRestrictionFlags)
binary.BigEndian.PutUint32(data[2:6], uint32(0))
binary.BigEndian.PutUint32(data[6:10], uint32(csmrf))
binary.BigEndian.PutUint32(data[10:], uint32(0))
ack, err = p.Send(rudp.Pkt{Data: data})
if err != nil {
log.Print(err)
}
<-ack
2021-01-16 10:14:31 -08:00
pktlen := 0
for f := range media {
2021-01-16 10:31:07 -08:00
pktlen += 4 + len(f) + len(media[f].digest)
2021-01-16 10:14:31 -08:00
}
data = make([]byte, 6+pktlen)
data[0] = uint8(0x00)
data[1] = uint8(ToClientAnnounceMedia)
binary.BigEndian.PutUint16(data[2:4], uint16(len(media)))
si := 4
for f := range media {
binary.BigEndian.PutUint16(data[si:2+si], uint16(len(f)))
copy(data[2+si:2+si+len(f)], []byte(f))
binary.BigEndian.PutUint16(data[2+si+len(f):4+si+len(f)], uint16(len(media[f].digest)))
copy(data[4+si+len(f):4+si+len(f)+len(media[f].digest)], media[f].digest)
2021-01-16 10:31:07 -08:00
si += 4 + len(f) + len(media[f].digest)
2021-01-16 10:14:31 -08:00
}
data[si] = uint8(0x00)
data[1+si] = uint8(0x00)
ack, err = p.Send(rudp.Pkt{Data: data})
2021-01-16 10:14:31 -08:00
if err != nil {
log.Print(err)
return
}
<-ack
}
func (p *Peer) sendMedia(rqdata []byte) {
var rq []string
count := binary.BigEndian.Uint16(rqdata[0:2])
si := uint16(2)
for i := uint16(0); i < count; i++ {
2021-01-16 10:31:07 -08:00
namelen := binary.BigEndian.Uint16(rqdata[si : 2+si])
name := rqdata[2+si : 2+si+namelen]
2021-01-16 10:14:31 -08:00
rq = append(rq, string(name))
2021-01-16 10:31:07 -08:00
si += 2 + namelen
2021-01-16 10:14:31 -08:00
}
pktlen := 0
for f := range rq {
2021-01-16 10:31:07 -08:00
pktlen += 6 + len(rq[f]) + len(media[rq[f]].data)
2021-01-16 10:14:31 -08:00
}
data := make([]byte, 12+pktlen)
data[0] = uint8(0x00)
data[1] = uint8(ToClientMedia)
data[2] = uint8(0x00)
data[3] = uint8(0x01)
data[4] = uint8(0x00)
data[5] = uint8(0x00)
binary.BigEndian.PutUint32(data[6:10], uint32(len(rq)))
sj := 10
for f := range rq {
binary.BigEndian.PutUint16(data[sj:2+sj], uint16(len(rq[f])))
copy(data[2+sj:2+sj+len(rq[f])], rq[f])
binary.BigEndian.PutUint32(data[2+sj+len(rq[f]):6+sj+len(rq[f])], uint32(len(media[rq[f]].data)))
copy(data[6+sj+len(rq[f]):6+sj+len(rq[f])+len(media[rq[f]].data)], media[rq[f]].data)
2021-01-16 10:31:07 -08:00
sj += 6 + len(rq[f]) + len(media[rq[f]].data)
2021-01-16 10:14:31 -08:00
}
data[sj] = uint8(0x00)
data[1+sj] = uint8(0x00)
ack, err := p.Send(rudp.Pkt{Data: data, ChNo: 2})
2021-01-16 10:14:31 -08:00
if err != nil {
log.Print(err)
return
}
<-ack
}
2021-01-21 05:35:48 -08:00
func loadMediaCache() error {
2021-03-09 08:07:10 -08:00
os.Mkdir("cache", 0777)
2021-01-21 05:35:48 -08:00
files, err := ioutil.ReadDir("cache")
if err != nil {
return err
}
for _, file := range files {
if !file.IsDir() {
meta := strings.Split(file.Name(), "#")
if len(meta) != 2 {
os.Remove("cache/" + file.Name())
continue
}
data, err := ioutil.ReadFile("cache/" + file.Name())
if err != nil {
continue
}
media[meta[0]] = &mediaFile{digest: stringToDigest(meta[1]), data: data}
}
}
return nil
}
func isCached(name string, digest []byte) bool {
2021-03-09 08:07:10 -08:00
os.Mkdir("cache", 0777)
2021-01-21 05:35:48 -08:00
_, err := os.Stat("cache/" + name + "#" + digestToString(digest))
if os.IsNotExist(err) {
return false
}
return true
}
func updateMediaCache() {
2021-03-09 08:07:10 -08:00
os.Mkdir("cache", 0777)
2021-01-21 05:35:48 -08:00
for mfname, mfile := range media {
cfname := "cache/" + mfname + "#" + digestToString(mfile.digest)
_, err := os.Stat(cfname)
if os.IsNotExist(err) {
ioutil.WriteFile(cfname, mfile.data, 0664)
}
}
}
func digestToString(d []byte) string {
return hex.EncodeToString(d)
}
func stringToDigest(s string) []byte {
r, err := hex.DecodeString(s)
if err != nil {
return []byte{}
}
return r
}
2021-03-06 07:29:14 -08:00
func loadMedia(servers map[string]struct{}) {
2021-01-16 10:14:31 -08:00
log.Print("Fetching media")
media = make(map[string]*mediaFile)
2021-01-16 10:31:07 -08:00
detachedinvs = make(map[string][][]byte)
2021-01-16 10:14:31 -08:00
2021-01-21 05:35:48 -08:00
loadMediaCache()
2021-01-30 03:24:37 -08:00
clt := &Peer{username: "media"}
2021-01-16 10:14:31 -08:00
for server := range servers {
2021-03-09 13:23:41 -08:00
straddr := ConfKey("servers:" + server + ":address")
2021-01-16 10:14:31 -08:00
srvaddr, err := net.ResolveUDPAddr("udp", straddr.(string))
if err != nil {
log.Fatal(err)
}
conn, err := net.DialUDP("udp", nil, srvaddr)
if err != nil {
log.Fatal(err)
}
srv, err := Connect(conn, conn.RemoteAddr())
if err != nil {
log.Print(err)
2021-01-16 10:14:31 -08:00
continue
}
2021-01-20 12:44:35 -08:00
fin := make(chan *Peer) // close-only
2021-01-16 10:14:31 -08:00
go Init(clt, srv, false, true, fin)
<-fin
2021-01-21 01:46:09 -08:00
srv.fetchMedia()
2021-01-16 10:14:31 -08:00
}
2021-01-21 05:35:48 -08:00
2021-03-06 07:54:46 -08:00
if err := mergeNodedefs(nodedefs); err != nil {
log.Fatal(err)
2021-02-09 23:35:14 -08:00
}
2021-02-10 22:40:42 -08:00
if err := mergeItemdefs(itemdefs); err != nil {
log.Fatal(err)
}
2021-01-21 05:35:48 -08:00
updateMediaCache()
}
func init() {
2021-03-06 07:54:46 -08:00
nodedefs = make(map[string][]byte)
2021-03-06 07:29:14 -08:00
itemdefs = make(map[string][]byte)
2021-03-09 13:23:41 -08:00
servers, ok := ConfKey("servers").(map[interface{}]interface{})
if !ok {
2021-03-06 07:29:14 -08:00
log.Fatal("Server list inexistent or not a dictionary")
}
2021-03-06 07:29:14 -08:00
srvs := make(map[string]struct{})
for server := range servers {
srvs[server.(string)] = struct{}{}
}
2021-03-06 07:29:14 -08:00
loadMedia(srvs)
2021-01-16 10:14:31 -08:00
}