summaryrefslogtreecommitdiff
path: root/ymux.go
blob: 8b09fc831a9009e2b327108ba6f461a6b13ec003 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package main

import (
	"fmt"
	"github.com/akamensky/argparse"
	"github.com/gin-gonic/gin"
	"github.com/keuin/ymux-go/config"
	"github.com/keuin/ymux-go/yggdrasil"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"os"
	"strings"
)

const applicationJson = "application/json"

func main() {
	p := argparse.NewParser("ymux-go", "Minecraft Yggdrasil server mux")
	configFile := p.String("c", "config", &argparse.Options{
		Required: true,
		Help:     "path to the config file",
	})
	err := p.Parse(os.Args)
	if err != nil {
		fmt.Print(p.Usage(err))
		return
	}

	cfg, err := config.Read(*configFile)
	if err != nil {
		panic(fmt.Errorf("error reading config file: %w", err))
	}
	err = cfg.Validate()
	if err != nil {
		panic(fmt.Errorf("config validation failed: %w", err))
	}
	ss, err := createServers(cfg)
	if err != nil {
		panic(err)
	}
	s := yggdrasil.NewMuxServer(ss...)

	if cfg.Debug {
		log.Logger = log.Logger.Level(zerolog.DebugLevel)
	} else {
		log.Logger = log.Logger.Level(zerolog.InfoLevel)
		gin.SetMode(gin.ReleaseMode)
	}
	log.Debug().Msg("debug mode is enabled")
	r := gin.Default()
	r.GET("/", func(c *gin.Context) {
		// servers with authlib-injector will call this API on boot
		// we need this to make them happy
		c.Data(200, applicationJson, []byte(`{}`))
	})
	r.GET("/sessionserver/session/minecraft/hasJoined", func(c *gin.Context) {
		var args struct {
			Username string `form:"username"`
			ServerID string `form:"serverId"`
		}
		err := c.ShouldBindQuery(&args)
		if err != nil {
			_ = c.AbortWithError(400, err)
			return
		}
		r, err := s.HasJoined(args.Username, args.ServerID)
		if err != nil {
			log.Error().Err(err).Msg("ymux hasJoined API failed")
			_ = c.AbortWithError(500, err)
			return
		}
		log.Info().
			Str("username", args.Username).
			Str("serverId", args.ServerID).
			Str("yggdrasilServer", r.ServerName).
			Bool("hasJoined", r.HasJoined()).
			Msg("ymux hasJoined API OK")
		if r.HasJoined() {
			c.Data(200, applicationJson, r.RawBody)
			return
		}
		c.Status(204)
	})
	err = r.Run(cfg.Listen)
	if err != nil {
		panic(fmt.Errorf("error running http server: %w", err))
	}
}

func createServers(cfg *config.Config) ([]yggdrasil.Server, error) {
	var servers []yggdrasil.Server
	for _, s := range cfg.Servers {
		s.Prefix = strings.TrimRight(s.Prefix, "/")
		ys, err := yggdrasil.NewServer(s.Prefix, yggdrasil.NewServerOptions{
			Name:  s.Name,
			Proxy: s.Proxy,
		})
		if err != nil {
			return nil, fmt.Errorf("parse server `%v`: %w", s.Name, err)
		}
		servers = append(servers, ys)
	}
	return servers, nil
}