summaryrefslogtreecommitdiff
path: root/ymux.go
diff options
context:
space:
mode:
authorKeuin <[email protected]>2024-02-12 18:16:16 +0800
committerKeuin <[email protected]>2024-02-12 18:18:45 +0800
commita89cbe5a93aede3703cd5981ea71827b55db0866 (patch)
tree165089cb6c94e00c5f00d57da1a83e84c46722cb /ymux.go
initial version
Diffstat (limited to 'ymux.go')
-rw-r--r--ymux.go104
1 files changed, 104 insertions, 0 deletions
diff --git a/ymux.go b/ymux.go
new file mode 100644
index 0000000..8b09fc8
--- /dev/null
+++ b/ymux.go
@@ -0,0 +1,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
+}