multiserver/media.go

442 lines
8.3 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 (
2021-03-29 09:57:30 -07:00
"bytes"
2021-01-16 10:14:31 -08:00
"encoding/binary"
2021-01-21 05:35:48 -08:00
"encoding/hex"
2021-03-02 08:47:07 -08:00
"errors"
2021-03-29 09:57:30 -07:00
"io"
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
)
2021-04-02 05:47:35 -07:00
const BytesPerBunch = 5000
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
type mediaFile struct {
2021-03-10 10:36:37 -08:00
digest []byte
data []byte
noCache bool
2021-01-16 10:14:31 -08:00
}
2021-03-29 09:57:30 -07:00
func (c *Conn) fetchMedia() {
if !c.IsSrv() {
2021-01-16 10:14:31 -08:00
return
}
for {
2021-03-29 09:57:30 -07:00
pkt, err := c.Recv()
2021-01-16 10:14:31 -08:00
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
}
2021-04-03 07:14:48 -07:00
go func() {
<-LogReady()
log.Print(err)
}()
2021-01-16 10:14:31 -08:00
continue
}
2021-03-29 09:57:30 -07:00
r := ByteReader(pkt)
2021-04-01 11:27:58 -07:00
switch cmd := ReadUint16(r); cmd {
2021-04-02 05:19:11 -07:00
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-29 09:57:30 -07:00
if ConfKey("servers:"+server.(string)+":address") == c.Addr().String() {
2021-02-09 23:35:14 -08:00
srvname = server.(string)
break
2021-02-09 23:35:14 -08:00
}
}
2021-03-29 09:57:30 -07:00
r.Seek(6, io.SeekStart)
nodedefs[srvname] = make([]byte, r.Len())
r.Read(nodedefs[srvname])
2021-04-02 05:19:11 -07: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-29 09:57:30 -07:00
if ConfKey("servers:"+server.(string)+":address") == c.Addr().String() {
srvname = server.(string)
break
}
}
2021-03-29 09:57:30 -07:00
r.Seek(6, io.SeekStart)
itemdefs[srvname] = make([]byte, r.Len())
r.Read(itemdefs[srvname])
2021-01-16 10:14:31 -08:00
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-29 09:57:30 -07:00
if ConfKey("servers:"+server.(string)+":address") == c.Addr().String() {
2021-01-16 10:31:07 -08:00
srvname = server.(string)
break
2021-01-16 10:31:07 -08:00
}
}
2021-03-29 09:57:30 -07:00
inv := make([]byte, r.Len())
r.Read(inv)
detachedinvs[srvname] = append(detachedinvs[srvname], inv)
2021-01-16 10:14:31 -08:00
case ToClientAnnounceMedia:
var rq []string
2021-03-29 09:57:30 -07:00
2021-04-01 11:27:58 -07:00
count := ReadUint16(r)
2021-03-29 09:57:30 -07:00
2021-01-16 10:14:31 -08:00
for i := uint16(0); i < count; i++ {
2021-04-01 11:27:58 -07:00
name := string(ReadBytes16(r))
2021-03-29 09:57:30 -07:00
2021-04-01 11:27:58 -07:00
digest := ReadBytes16(r)
2021-03-29 09:57:30 -07:00
2021-04-01 11:27:58 -07:00
if media[name] == nil && !isCached(name, digest) {
rq = append(rq, name)
media[name] = &mediaFile{digest: digest}
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
}
2021-04-01 11:27:58 -07:00
w := bytes.NewBuffer([]byte{0x00, ToServerRequestMedia})
WriteUint16(w, uint16(len(rq)))
2021-01-16 10:14:31 -08:00
for f := range rq {
2021-04-01 11:27:58 -07:00
WriteBytes16(w, []byte(rq[f]))
2021-01-16 10:14:31 -08:00
}
2021-03-29 09:57:30 -07:00
_, err := c.Send(rudp.Pkt{
2021-04-01 11:27:58 -07:00
Reader: w,
2021-03-29 09:57:30 -07:00
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
2021-01-16 10:14:31 -08:00
if err != nil {
2021-04-03 07:14:48 -07:00
go func() {
<-LogReady()
log.Print(err)
}()
2021-01-16 10:14:31 -08:00
continue
}
case ToClientMedia:
2021-04-01 11:27:58 -07:00
bunchCount := ReadUint16(r)
bunchID := ReadUint16(r)
fileCount := ReadUint32(r)
2021-03-29 09:57:30 -07:00
2021-04-01 11:27:58 -07:00
for i := uint32(0); i < fileCount; i++ {
name := string(ReadBytes16(r))
data := ReadBytes32(r)
2021-01-16 10:14:31 -08:00
2021-04-01 11:27:58 -07:00
if media[name] != nil && len(media[name].data) == 0 {
media[name].data = data
2021-01-16 10:14:31 -08:00
}
}
2021-04-01 11:27:58 -07:00
if bunchID >= bunchCount-1 {
2021-03-29 09:57:30 -07:00
c.Close()
2021-01-16 10:14:31 -08:00
return
}
}
}
}
2021-03-29 09:57:30 -07:00
func (c *Conn) updateDetachedInvs(srvname string) {
2021-01-20 12:44:35 -08:00
for i := range detachedinvs[srvname] {
2021-04-01 11:27:58 -07:00
w := bytes.NewBuffer([]byte{0x00, ToClientDetachedInventory})
w.Write(detachedinvs[srvname][i])
2021-01-20 12:44:35 -08:00
2021-04-01 11:27:58 -07:00
ack, err := c.Send(rudp.Pkt{Reader: w})
2021-01-20 12:44:35 -08:00
if err != nil {
log.Print(err)
continue
}
<-ack
}
}
2021-03-29 09:57:30 -07:00
func (c *Conn) 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)
2021-04-02 05:19:11 -07:00
data[1] = uint8(ToClientNodeDef)
2021-02-09 23:35:14 -08:00
binary.BigEndian.PutUint32(data[2:6], uint32(len(nodedef)))
copy(data[6:], nodedef)
2021-01-16 10:14:31 -08:00
2021-03-29 09:57:30 -07:00
ack, err := c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
2021-02-09 23:35:14 -08:00
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)
2021-04-02 05:19:11 -07:00
data[1] = uint8(ToClientItemDef)
2021-02-10 22:40:42 -08:00
binary.BigEndian.PutUint32(data[2:6], uint32(len(itemdef)))
copy(data[6:], itemdef)
2021-01-16 10:14:31 -08:00
2021-03-29 09:57:30 -07:00
ack, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
2021-01-16 10:14:31 -08:00
if err != nil {
log.Print(err)
}
<-ack
2021-03-29 09:57:30 -07:00
c.updateDetachedInvs(srvname)
2021-01-16 10:14:31 -08:00
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
}
csmnr, ok := ConfKey("csm_restriction_noderange").(int)
if !ok {
csmnr = 8
}
2021-01-22 09:31:57 -08:00
data = make([]byte, 14)
data[0] = uint8(0x00)
2021-04-02 05:19:11 -07:00
data[1] = uint8(ToClientCSMRestrictionFlags)
2021-01-22 09:31:57 -08:00
binary.BigEndian.PutUint32(data[2:6], uint32(0))
binary.BigEndian.PutUint32(data[6:10], uint32(csmrf))
binary.BigEndian.PutUint32(data[10:], uint32(csmnr))
2021-01-22 09:31:57 -08:00
2021-03-29 09:57:30 -07:00
ack, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
2021-01-22 09:31:57 -08:00
if err != nil {
log.Print(err)
}
<-ack
2021-04-01 11:27:58 -07:00
w := bytes.NewBuffer([]byte{0x00, ToClientAnnounceMedia})
WriteUint16(w, uint16(len(media)))
2021-01-16 10:14:31 -08:00
for f := range media {
2021-04-01 11:27:58 -07:00
WriteBytes16(w, []byte(f))
WriteBytes16(w, media[f].digest)
2021-01-16 10:14:31 -08:00
}
remote, ok := ConfKey("remote_media_server").(string)
if !ok {
remote = ""
}
WriteBytes16(w, []byte(remote))
2021-04-01 11:27:58 -07:00
ack, err = c.Send(rudp.Pkt{Reader: w})
2021-01-16 10:14:31 -08:00
if err != nil {
log.Print(err)
return
}
<-ack
}
2021-04-01 11:27:58 -07:00
func (c *Conn) sendMedia(r *bytes.Reader) {
count := ReadUint16(r)
2021-01-16 10:14:31 -08:00
var rq []string
for i := uint16(0); i < count; i++ {
2021-04-01 11:27:58 -07:00
name := string(ReadBytes16(r))
rq = append(rq, name)
2021-01-16 10:14:31 -08:00
}
2021-04-18 06:32:30 -07:00
bunches := []map[string]*mediaFile{make(map[string]*mediaFile)}
2021-04-02 05:47:35 -07:00
var bunchlen int
for _, f := range rq {
2021-04-04 03:02:30 -07:00
bunches[len(bunches)-1][f] = media[f]
2021-04-02 05:47:35 -07:00
bunchlen += len(media[f].data)
if bunchlen >= BytesPerBunch {
2021-04-04 03:02:30 -07:00
bunches = append(bunches, make(map[string]*mediaFile))
bunchlen = 0
2021-04-02 05:47:35 -07:00
}
2021-01-16 10:14:31 -08:00
}
2021-04-01 11:31:34 -07:00
2021-04-02 05:47:35 -07:00
for i, bunch := range bunches {
w := bytes.NewBuffer([]byte{0x00, ToClientMedia})
WriteUint16(w, uint16(len(bunches)))
WriteUint16(w, uint16(i))
WriteUint32(w, uint32(len(bunch)))
for f, m := range bunch {
WriteBytes16(w, []byte(f))
WriteBytes32(w, m.data)
}
2021-03-29 09:57:30 -07:00
2021-04-02 05:47:35 -07:00
ack, err := c.Send(rudp.Pkt{
Reader: w,
PktInfo: rudp.PktInfo{
Channel: 2,
},
})
if err != nil {
log.Print(err)
return
}
<-ack
2021-01-16 10:14:31 -08:00
}
}
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
2021-03-12 08:12:49 -08:00
files, err := os.ReadDir("cache")
2021-01-21 05:35:48 -08:00
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
}
2021-03-12 08:12:49 -08:00
data, err := os.ReadFile("cache/" + file.Name())
2021-01-21 05:35:48 -08:00
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 {
2021-03-10 10:36:37 -08:00
if mfile.noCache {
continue
}
2021-01-21 05:35:48 -08:00
cfname := "cache/" + mfname + "#" + digestToString(mfile.digest)
_, err := os.Stat(cfname)
if os.IsNotExist(err) {
2021-03-12 08:12:49 -08:00
os.WriteFile(cfname, mfile.data, 0666)
2021-01-21 05:35:48 -08:00
}
}
}
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-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 {
2021-04-03 07:14:48 -07:00
go func() {
<-LogReady()
log.Fatal(err)
}()
2021-01-16 10:14:31 -08:00
}
conn, err := net.DialUDP("udp", nil, srvaddr)
if err != nil {
2021-04-03 07:14:48 -07:00
go func() {
<-LogReady()
log.Fatal(err)
}()
2021-01-16 10:14:31 -08:00
}
2021-03-29 09:57:30 -07:00
srv, err := Connect(conn)
if err != nil {
2021-04-03 07:14:48 -07:00
go func() {
<-LogReady()
log.Print(err)
}()
2021-01-16 10:14:31 -08:00
continue
}
2021-04-02 03:38:46 -07:00
clt := &Conn{username: "media"}
2021-03-29 09:57:30 -07:00
fin := make(chan *Conn) // close-only
2021-01-16 10:14:31 -08:00
go Init(clt, srv, false, true, fin)
<-fin
2021-01-16 10:14:31 -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 {
2021-04-03 07:14:48 -07:00
go func() {
<-LogReady()
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 {
2021-04-03 07:14:48 -07:00
go func() {
<-LogReady()
log.Fatal(err)
}()
2021-02-10 22:40:42 -08:00
}
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-04-03 07:14:48 -07:00
go func() {
<-LogReady()
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
}