From 98abbd524b68064c368d935360bd16a4eefd06f8 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Sat, 20 Apr 2024 06:17:20 -0600 Subject: [PATCH] Added protobuf support to MCStatus and simplified the response behaviour (to be offloaded to the actual site) --- Makefile | 3 + modules/game_server_status/service.go | 4 +- modules/game_server_status/types.go | 12 +- modules/mcstatus/handler.go | 32 ++- modules/mcstatus/service.go | 18 +- modules/mcstatus/types.go | 236 +++++++-------- modules/proto/mcstatuspb/mcstatus.pb.go | 365 ++++++++++++++++++++++++ proto/mcstatus.proto | 27 ++ public/api/v1/openapi.json | 244 ++++++---------- responses/problem.go | 3 +- responses/response.go | 4 +- 11 files changed, 647 insertions(+), 301 deletions(-) create mode 100644 modules/proto/mcstatuspb/mcstatus.pb.go create mode 100644 proto/mcstatus.proto diff --git a/Makefile b/Makefile index d19d52e..f2dc4a2 100644 --- a/Makefile +++ b/Makefile @@ -4,3 +4,6 @@ gen: protoc -I=./proto --go_out=./modules/proto ./proto/problem.proto sed -i 's/json:"\(.*\),omitempty"/json:"\1,omitempty" xml:"\1,omitempty"/g' ./modules/proto/problempb/problem.pb.go + + protoc -I=./proto --go_out=./modules/proto ./proto/mcstatus.proto + sed -i 's/json:"\(.*\),omitempty"/json:"\1" xml:"\1"/g' ./modules/proto/mcstatuspb/mcstatus.pb.go diff --git a/modules/game_server_status/service.go b/modules/game_server_status/service.go index 2f88c7b..b2e3b15 100644 --- a/modules/game_server_status/service.go +++ b/modules/game_server_status/service.go @@ -92,11 +92,11 @@ func (s *service) QueryGameServer(game string, host string, port int) (*GameServ for _, v := range MinecraftList { if v == game { isBedrock := game != "minecraft" - response, err := mcstatus.NewService().GetServerStatus(host, port, isBedrock, true) + response, err := mcstatus.NewService().GetServerStatus(host, port, isBedrock, true, port) if err != nil { return nil, err } - return (*mcstatusResponse)(response).Normalize(), nil + return (*mcServerStatus)(response).Normalize(), nil } } for _, v := range GameQList { diff --git a/modules/game_server_status/types.go b/modules/game_server_status/types.go index d621674..8f1c22e 100644 --- a/modules/game_server_status/types.go +++ b/modules/game_server_status/types.go @@ -61,22 +61,22 @@ type GameQResponse struct { } // Type alias -type mcstatusResponse mcstatus.MCStatusResponse +type mcServerStatus mcstatus.MCServerStatus // Normalize - Normalize Minecraft response -func (mc *mcstatusResponse) Normalize() *GameServerStatus { +func (mc *mcServerStatus) Normalize() *GameServerStatus { players := make([]Player, len(mc.Players)) for i, v := range mc.Players { - players[i] = Player{Name: v.Name, ID: v.UUID.String()} + players[i] = Player{Name: v.Name, ID: v.Uuid} } return &GameServerStatus{ Host: mc.Host, - Port: mc.Port, + Port: int(mc.Port), Name: mc.Name, MapName: mc.Map, - MaxPlayers: mc.MaxPlayers, - NumPlayers: mc.NumPlayers, + MaxPlayers: int(mc.MaxPlayers), + NumPlayers: int(mc.NumPlayers), Players: players, QueryType: QueryTypeMinecraft, Raw: mc.Raw, diff --git a/modules/mcstatus/handler.go b/modules/mcstatus/handler.go index 76ef842..89fb637 100644 --- a/modules/mcstatus/handler.go +++ b/modules/mcstatus/handler.go @@ -4,6 +4,7 @@ import ( "image/png" "net/http" "strconv" + "strings" "github.com/NeuralNexusDev/neuralnexus-api/responses" ) @@ -16,14 +17,14 @@ func ApplyRoutes(mux *http.ServeMux) *http.ServeMux { return mux } -// Route that returns the server status +// GetServerStatus - Route that returns the server status func GetServerStatus(s MCStatusService) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { host := r.PathValue("host") isBedrock := r.URL.Query().Get("bedrock") == "true" queryEnabled := r.URL.Query().Get("query") == "true" raw := r.URL.Query().Get("raw") == "true" - port, err := strconv.Atoi(r.URL.Query().Get("port")) + port, err := strconv.Atoi(host[strings.LastIndex(host, ":")+1:]) if err != nil { if isBedrock { port = 19132 @@ -31,38 +32,39 @@ func GetServerStatus(s MCStatusService) http.HandlerFunc { port = 25565 } } + queryPort, err := strconv.Atoi(r.URL.Query().Get("query_port")) + if err != nil { + queryPort = port + } - status, err := s.GetServerStatus(host, port, isBedrock, queryEnabled) + status, err := s.GetServerStatus(host, port, isBedrock, queryEnabled, queryPort) if err != nil { - responses.SendAndEncodeInternalServerError(w, r, err.Error()) + responses.SendAndEncodeNotFound(w, r, err.Error()) return } if !raw { status.Raw = nil } - responses.SendAndEncodeStruct(w, r, http.StatusOK, status) } } -// Route that returns the server icon as a PNG (base64 encoded string didn't work for some reason) +// GetIcon - Route that returns the server icon as a PNG func GetIcon(s MCStatusService) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { host := r.PathValue("host") isBedrock := r.URL.Query().Get("bedrock") == "true" - queryEnabled := r.URL.Query().Get("query") == "true" - port, err := strconv.Atoi(r.URL.Query().Get("port")) + if isBedrock { + responses.SendAndEncodeBadRequest(w, r, "Bedrock servers do not have icons.") + } + port, err := strconv.Atoi(host[strings.LastIndex(host, ":")+1:]) if err != nil { - if isBedrock { - port = 19132 - } else { - port = 25565 - } + port = 25565 } - status, err := s.GetServerStatus(host, port, isBedrock, queryEnabled) + status, err := s.GetJavaServerStatus(host, port, false, 0) if err != nil { - responses.SendAndEncodeInternalServerError(w, r, err.Error()) + responses.SendAndEncodeNotFound(w, r, err.Error()) return } diff --git a/modules/mcstatus/service.go b/modules/mcstatus/service.go index 4791b0a..aa6425c 100644 --- a/modules/mcstatus/service.go +++ b/modules/mcstatus/service.go @@ -11,9 +11,9 @@ import ( // MCStatusService - Minecraft Status service type MCStatusService interface { - GetJavaServerStatus(host string, port int, queryEnabled bool) (*MCStatusResponse, error) - GetBedrockServerStatus(host string, port int) (*MCStatusResponse, error) - GetServerStatus(host string, port int, isBedrock bool, queryEnabled bool) (*MCStatusResponse, error) + GetJavaServerStatus(host string, port int, queryEnabled bool, queryPort int) (*MCServerStatus, error) + GetBedrockServerStatus(host string, port int) (*MCServerStatus, error) + GetServerStatus(host string, port int, isBedrock bool, queryEnabled bool, queryPort int) (*MCServerStatus, error) } // service - Minecraft Status service implementation @@ -25,14 +25,14 @@ func NewService() MCStatusService { } // GetJavaServerStatus - Get Java server status -func (s *service) GetJavaServerStatus(host string, port int, queryEnabled bool) (*MCStatusResponse, error) { +func (s *service) GetJavaServerStatus(host string, port int, queryEnabled bool, queryPort int) (*MCServerStatus, error) { pinger := minequery.NewPinger( minequery.WithTimeout(5*time.Second), minequery.WithProtocolVersion16(minequery.Ping16ProtocolVersion162), minequery.WithProtocolVersion17(minequery.Ping17ProtocolVersion119), ) - var status *MCStatusResponse = nil + var status *MCServerStatus = nil s17, err := pinger.Ping17(host, port) if err == nil { status = GetPing17Status(s17) @@ -62,14 +62,14 @@ func (s *service) GetJavaServerStatus(host string, port int, queryEnabled bool) } if status != nil { status.Host = host - status.Port = port + status.Port = int32(port) return status, nil } return nil, errors.New("failed to get java server status") } // GetBedrockServerStatus - Get Bedrock server status -func (s *service) GetBedrockServerStatus(host string, port int) (*MCStatusResponse, error) { +func (s *service) GetBedrockServerStatus(host string, port int) (*MCServerStatus, error) { connect := host + ":" + fmt.Sprint(port) status, err := bedrockping.Query(connect, 5*time.Second, 150*time.Millisecond) if err != nil { @@ -79,9 +79,9 @@ func (s *service) GetBedrockServerStatus(host string, port int) (*MCStatusRespon } // GetServerStatus - Get server status -func (s *service) GetServerStatus(host string, port int, isBedrock bool, queryEnabled bool) (*MCStatusResponse, error) { +func (s *service) GetServerStatus(host string, port int, isBedrock bool, queryEnabled bool, queryPort int) (*MCServerStatus, error) { if isBedrock { return s.GetBedrockServerStatus(host, port) } - return s.GetJavaServerStatus(host, port, queryEnabled) + return s.GetJavaServerStatus(host, port, queryEnabled, queryPort) } diff --git a/modules/mcstatus/types.go b/modules/mcstatus/types.go index f96783f..3a50edc 100644 --- a/modules/mcstatus/types.go +++ b/modules/mcstatus/types.go @@ -9,34 +9,19 @@ import ( "regexp" "strings" + "github.com/NeuralNexusDev/neuralnexus-api/modules/proto/mcstatuspb" "github.com/ZeroErrors/go-bedrockping" "github.com/dreamscached/minequery/v2" - "github.com/google/uuid" ) -// MCStatusResponse - Minecraft Status response -type MCStatusResponse struct { - Host string `json:"host" xml:"host"` - Port int `json:"port" xml:"port"` - Name string `json:"name" xml:"name"` - MOTD string `json:"motd" xml:"motd"` - Map string `json:"map" xml:"map"` - MaxPlayers int `json:"max_players" xml:"max_players"` - NumPlayers int `json:"num_players" xml:"num_players"` - Players []Player `json:"players" xml:"players"` - Version string `json:"version" xml:"version"` - Favicon string `json:"favicon" xml:"favicon"` +// MCServerStatus - Minecraft Status response +type MCServerStatus struct { + mcstatuspb.ServerStatus ServerType ServerType `json:"server_type" xml:"server_type"` Raw interface{} `json:"raw,omitempty" xml:"raw,omitempty"` Icon image.Image `json:"-" xml:"-"` } -// Player - Player info -type Player struct { - Name string `json:"name" xml:"name"` - UUID uuid.UUID `json:"uuid" xml:"uuid"` -} - // ServerType - Server type enum type ServerType string @@ -46,6 +31,28 @@ const ( ServerTypeBedrock ServerType = "bedrock" ) +// NewServerStatus - Create a new server status +func NewServerStatus(host string, port int, name string, motd string, mapName string, maxPlayers int, numPlayers int, players []*mcstatuspb.Player, version string, favicon string, serverType ServerType, raw interface{}, icon image.Image) *MCServerStatus { + return &MCServerStatus{ + ServerStatus: mcstatuspb.ServerStatus{ + Host: host, + Port: int32(port), + Name: name, + Motd: motd, + Map: mapName, + MaxPlayers: int32(maxPlayers), + NumPlayers: int32(numPlayers), + Players: players, + Version: version, + Favicon: favicon, + ServerType: mcstatuspb.ServerType(mcstatuspb.ServerType_value[strings.ToUpper(string(serverType))]), + }, + ServerType: serverType, + Raw: raw, + Icon: icon, + } +} + // MOTDToName - Convert MOTD to name func MOTDToName(motd string) string { name := strings.ReplaceAll(motd, "\n", " ") @@ -56,6 +63,9 @@ func MOTDToName(motd string) string { // ImgToBase64 - Convert image.Image to base64 string func ImgToBase64(i image.Image) string { + if i == nil { + return "" + } var buff bytes.Buffer png.Encode(&buff, i) var encodedString string = base64.StdEncoding.EncodeToString(buff.Bytes()) @@ -81,106 +91,121 @@ func LoadImgFromFile(path string) (image.Image, error) { } // GetPing17Status - Get the Java server status -func GetPing17Status(s *minequery.Status17) *MCStatusResponse { +func GetPing17Status(s *minequery.Status17) *MCServerStatus { icon := s.Icon s.Icon = nil // TODO: Parse the motd and keep data motd := s.Description.String() - var playerList []Player = []Player{} + playerList := []*mcstatuspb.Player{} for _, player := range s.SamplePlayers { - playerList = append(playerList, Player{ + playerList = append(playerList, &mcstatuspb.Player{ Name: player.Nickname, - UUID: player.UUID, + Uuid: player.UUID.String(), }) } - return &MCStatusResponse{ - Name: MOTDToName(motd), - MOTD: strings.ReplaceAll(motd, "\n", "\\n"), - MaxPlayers: s.MaxPlayers, - NumPlayers: s.OnlinePlayers, - Players: playerList, - Favicon: ImgToBase64(icon), - ServerType: ServerTypeJava, - Icon: icon, - Raw: s, - } + return NewServerStatus( + "", 0, + MOTDToName(motd), + strings.ReplaceAll(motd, "\n", "\\n"), + "", + s.MaxPlayers, + s.OnlinePlayers, + playerList, + s.VersionName, + ImgToBase64(icon), + ServerTypeJava, + s, + icon, + ) } // GetPing16Status - Get the Java server status -func GetPing16Status(s *minequery.Status16) *MCStatusResponse { +func GetPing16Status(s *minequery.Status16) *MCServerStatus { motd := s.MOTD - return &MCStatusResponse{ - Name: MOTDToName(motd), - MOTD: strings.ReplaceAll(motd, "\n", "\\n"), - MaxPlayers: s.MaxPlayers, - NumPlayers: s.OnlinePlayers, - Players: []Player{}, - Favicon: LegacyIcon, - ServerType: ServerTypeJava, - Icon: ImgLegacyIcon, - Raw: s, - } + return NewServerStatus( + "", 0, + MOTDToName(motd), + strings.ReplaceAll(motd, "\n", "\\n"), + "", + s.MaxPlayers, + s.OnlinePlayers, + []*mcstatuspb.Player{}, + "1.6", + "", + ServerTypeJava, + s, + nil, + ) } // GetPing14Status - Get the Java server status -func GetPing14Status(s *minequery.Status14) *MCStatusResponse { +func GetPing14Status(s *minequery.Status14) *MCServerStatus { motd := s.MOTD - return &MCStatusResponse{ - Name: MOTDToName(motd), - MOTD: strings.ReplaceAll(motd, "\n", "\\n"), - MaxPlayers: s.MaxPlayers, - NumPlayers: s.OnlinePlayers, - Players: []Player{}, - Favicon: LegacyIcon, - ServerType: ServerTypeJava, - Icon: ImgLegacyIcon, - Raw: s, - } + return NewServerStatus( + "", 0, + MOTDToName(motd), + strings.ReplaceAll(motd, "\n", "\\n"), + "", + s.MaxPlayers, + s.OnlinePlayers, + []*mcstatuspb.Player{}, + "1.4-1.5", + "", + ServerTypeJava, + s, + nil, + ) } // GetBeta18Status - Get the Java server status -func GetBeta18Status(s *minequery.StatusBeta18) *MCStatusResponse { +func GetBeta18Status(s *minequery.StatusBeta18) *MCServerStatus { motd := s.MOTD - return &MCStatusResponse{ - Name: MOTDToName(motd), - MOTD: strings.ReplaceAll(motd, "\n", "\\n"), - MaxPlayers: s.MaxPlayers, - NumPlayers: s.OnlinePlayers, - Players: []Player{}, - Favicon: LegacyIcon, - ServerType: ServerTypeJava, - Icon: ImgLegacyIcon, - Raw: s, - } + return NewServerStatus( + "", 0, + MOTDToName(motd), + strings.ReplaceAll(motd, "\n", "\\n"), + "", + s.MaxPlayers, + s.OnlinePlayers, + []*mcstatuspb.Player{}, + "b1.8-1.3", + "", + ServerTypeJava, + s, + nil, + ) } // GetQueryStatus - Get the Java server status -func GetQueryStatus(s *minequery.FullQueryStatus) *MCStatusResponse { +func GetQueryStatus(s *minequery.FullQueryStatus) *MCServerStatus { motd := s.MOTD - var playerList []Player = []Player{} + playerList := []*mcstatuspb.Player{} for _, player := range s.SamplePlayers { - playerList = append(playerList, Player{ + playerList = append(playerList, &mcstatuspb.Player{ Name: player, }) } - return &MCStatusResponse{ - Name: MOTDToName(motd), - MOTD: strings.ReplaceAll(motd, "\n", "\\n"), - MaxPlayers: s.MaxPlayers, - NumPlayers: s.OnlinePlayers, - Players: playerList, - Favicon: LegacyIcon, - ServerType: ServerTypeJava, - Icon: ImgLegacyIcon, - Raw: s, - } + return NewServerStatus( + "", 0, + MOTDToName(motd), + strings.ReplaceAll(motd, "\n", "\\n"), + "", + s.MaxPlayers, + s.OnlinePlayers, + playerList, + s.Version, + "", + ServerTypeJava, + s, + nil, + ) } // GetBedrockStatus - Get the Bedrock server status -func GetBedrockStatus(s bedrockping.Response) *MCStatusResponse { +func GetBedrockStatus(s bedrockping.Response) *MCServerStatus { motd := s.ServerName if len(s.Extra) > 1 { motd += "\\n" + s.Extra[1] @@ -191,31 +216,18 @@ func GetBedrockStatus(s bedrockping.Response) *MCStatusResponse { mapName = s.Extra[2] } - return &MCStatusResponse{ - Name: MOTDToName(motd), - MOTD: strings.ReplaceAll(motd, "\n", "\\n"), - Map: mapName, - MaxPlayers: s.MaxPlayers, - NumPlayers: s.PlayerCount, - Players: []Player{}, - Favicon: BedrockIcon, - ServerType: ServerTypeBedrock, - Icon: ImgBedrockIcon, - Raw: s, - } + return NewServerStatus( + "", 0, + MOTDToName(motd), + strings.ReplaceAll(motd, "\n", "\\n"), + mapName, + s.MaxPlayers, + s.PlayerCount, + []*mcstatuspb.Player{}, + s.MCPEVersion, + "", + ServerTypeJava, + s, + nil, + ) } - -// DefaultIcon - Default icon -const DefaultIcon = "data:image/png;base64,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" - -// LegacyIcon - Legacy icon -const LegacyIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAABX1BMVEVHcExIcj1bj05aQSxiRS9dRC9HMyJUfUdeQy1NekFvUDZUg0h4WUFMNiVIMiF4Vjt7WDxmSDJcj05LUDA1JhkqPyRBYjdcQi1XPippo1qPZkc6VzJUhUhraGVSUlL///9hQkVKNCNhRC5bQi1RgEVjRjBSgkZPfURGMSFpSjJONyVaQCtIMyJKdT5VPClYiUpXPipwUDd4VjtOe0JWhklUhEhsTTVMeUFQOCZajExeQi1mSDFLdz9MNSQySyssQiY2JRlTOyhIcTxhllJAYjc6VzFyUjh1VDk9XTReklAvRyhcj042Ui5CLh87KRs+Kx0pPiNGbTuCXUGJYkNlnFZCZzlKOy+OZkd6Vzw0KRt+WT6TaUlTT0tDPCYwMR4wOyM1JRkoNh89QihfRzU3MSI7SCuVa0tsp1tDRitnVERCXDVORDtCQD48NC5kTj1mWlBuY1pra2tsbW1raGZHcEzZxmpuAAAAdXRSTlMA0nGTk3GTGhpyk9JxdNKT0tLSU5SUlNLS0ZOTHtLSGv///////////////////////////////////////////////////////////////////////////////////////////////////////////////wA/Eef4AAAJCUlEQVRYw5yWV5Mb1xGFSVrWcsmyJJO2qyTrZe7knHPABGAGg0HOGZsDl6Ro//8H99DaoCpZlnifNtT9uvuc0xd49uw3z4/Hxz8++/Jz9OK1WX3/4uiLr7+RKUKeTl8ffwni6Pi5bVC0TrgypT//wwiobqapaNupSMkGpQd/DHF0/NqQqUAndDsQRZswDDqgf/8g0HxKGwZhy5lMmyYdBLYuprqe/r4uQHnatg3Z1UeBSwcm6EjogU0bVBDor/+vIzB7WRm6TbmVS8iVSVdZ6Rq0qANFTANK/m0EVDcInZDLrKoLE5QdUG5W0Wlqw290IFKVbP5vLWB2SpYp25jCgeI0QdsBYQLSqGRaDGgTyKVL2L+uxdGL7ysCyslGOXVNN8sqShylMDxhyFU2zfRUpOWqLCuT+DVEXT0rZVembdMFESA/ppjSskvB5ISuu246SwPaKLNMzq4zyn3zCy2Ojt+4lFG6oJNIgHy0SJgUZUyvp7It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" - -// BedrockIcon - Bedrock icon -const BedrockIcon = "data:image/png;base64,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" - -var ( - ImgDefaultIcon, _ = LoadImgFromFile("public/mcstatus/icons/default.png") - ImgLegacyIcon, _ = LoadImgFromFile("public/mcstatus/icons/legacy.png") - ImgBedrockIcon, _ = LoadImgFromFile("public/mcstatus/icons/bedrock.png") -) diff --git a/modules/proto/mcstatuspb/mcstatus.pb.go b/modules/proto/mcstatuspb/mcstatus.pb.go new file mode 100644 index 0000000..6b718d7 --- /dev/null +++ b/modules/proto/mcstatuspb/mcstatus.pb.go @@ -0,0 +1,365 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v5.26.1 +// source: mcstatus.proto + +package mcstatuspb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type ServerType int32 + +const ( + ServerType_JAVA ServerType = 0 + ServerType_BEDROCK ServerType = 1 +) + +// Enum value maps for ServerType. +var ( + ServerType_name = map[int32]string{ + 0: "JAVA", + 1: "BEDROCK", + } + ServerType_value = map[string]int32{ + "JAVA": 0, + "BEDROCK": 1, + } +) + +func (x ServerType) Enum() *ServerType { + p := new(ServerType) + *p = x + return p +} + +func (x ServerType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ServerType) Descriptor() protoreflect.EnumDescriptor { + return file_mcstatus_proto_enumTypes[0].Descriptor() +} + +func (ServerType) Type() protoreflect.EnumType { + return &file_mcstatus_proto_enumTypes[0] +} + +func (x ServerType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ServerType.Descriptor instead. +func (ServerType) EnumDescriptor() ([]byte, []int) { + return file_mcstatus_proto_rawDescGZIP(), []int{0} +} + +type ServerStatus struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Host string `protobuf:"bytes,1,opt,name=host,proto3" json:"host" xml:"host"` + Port int32 `protobuf:"varint,2,opt,name=port,proto3" json:"port" xml:"port"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name" xml:"name"` + Motd string `protobuf:"bytes,4,opt,name=motd,proto3" json:"motd" xml:"motd"` + Map string `protobuf:"bytes,5,opt,name=map,proto3" json:"map" xml:"map"` + MaxPlayers int32 `protobuf:"varint,6,opt,name=max_players,json=maxPlayers,proto3" json:"max_players" xml:"max_players"` + NumPlayers int32 `protobuf:"varint,7,opt,name=num_players,json=numPlayers,proto3" json:"num_players" xml:"num_players"` + Players []*Player `protobuf:"bytes,8,rep,name=players,proto3" json:"players" xml:"players"` + Version string `protobuf:"bytes,9,opt,name=version,proto3" json:"version" xml:"version"` + Favicon string `protobuf:"bytes,10,opt,name=favicon,proto3" json:"favicon" xml:"favicon"` + ServerType ServerType `protobuf:"varint,11,opt,name=server_type,json=serverType,proto3,enum=mcstatuspb.ServerType" json:"server_type" xml:"server_type"` +} + +func (x *ServerStatus) Reset() { + *x = ServerStatus{} + if protoimpl.UnsafeEnabled { + mi := &file_mcstatus_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ServerStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerStatus) ProtoMessage() {} + +func (x *ServerStatus) ProtoReflect() protoreflect.Message { + mi := &file_mcstatus_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerStatus.ProtoReflect.Descriptor instead. +func (*ServerStatus) Descriptor() ([]byte, []int) { + return file_mcstatus_proto_rawDescGZIP(), []int{0} +} + +func (x *ServerStatus) GetHost() string { + if x != nil { + return x.Host + } + return "" +} + +func (x *ServerStatus) GetPort() int32 { + if x != nil { + return x.Port + } + return 0 +} + +func (x *ServerStatus) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ServerStatus) GetMotd() string { + if x != nil { + return x.Motd + } + return "" +} + +func (x *ServerStatus) GetMap() string { + if x != nil { + return x.Map + } + return "" +} + +func (x *ServerStatus) GetMaxPlayers() int32 { + if x != nil { + return x.MaxPlayers + } + return 0 +} + +func (x *ServerStatus) GetNumPlayers() int32 { + if x != nil { + return x.NumPlayers + } + return 0 +} + +func (x *ServerStatus) GetPlayers() []*Player { + if x != nil { + return x.Players + } + return nil +} + +func (x *ServerStatus) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *ServerStatus) GetFavicon() string { + if x != nil { + return x.Favicon + } + return "" +} + +func (x *ServerStatus) GetServerType() ServerType { + if x != nil { + return x.ServerType + } + return ServerType_JAVA +} + +type Player struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name" xml:"name"` + Uuid string `protobuf:"bytes,2,opt,name=uuid,proto3" json:"uuid" xml:"uuid"` +} + +func (x *Player) Reset() { + *x = Player{} + if protoimpl.UnsafeEnabled { + mi := &file_mcstatus_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Player) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Player) ProtoMessage() {} + +func (x *Player) ProtoReflect() protoreflect.Message { + mi := &file_mcstatus_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Player.ProtoReflect.Descriptor instead. +func (*Player) Descriptor() ([]byte, []int) { + return file_mcstatus_proto_rawDescGZIP(), []int{1} +} + +func (x *Player) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Player) GetUuid() string { + if x != nil { + return x.Uuid + } + return "" +} + +var File_mcstatus_proto protoreflect.FileDescriptor + +var file_mcstatus_proto_rawDesc = []byte{ + 0x0a, 0x0e, 0x6d, 0x63, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x0a, 0x6d, 0x63, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x70, 0x62, 0x22, 0xcd, 0x02, 0x0a, + 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, + 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, + 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x74, + 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x74, 0x64, 0x12, 0x10, 0x0a, + 0x03, 0x6d, 0x61, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x61, 0x70, 0x12, + 0x1f, 0x0a, 0x0b, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, + 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x75, 0x6d, 0x5f, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6e, 0x75, 0x6d, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, + 0x73, 0x12, 0x2c, 0x0a, 0x07, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x63, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x70, 0x62, 0x2e, + 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x07, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x12, + 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x76, + 0x69, 0x63, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x76, 0x69, + 0x63, 0x6f, 0x6e, 0x12, 0x37, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x6d, 0x63, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, + 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x22, 0x30, 0x0a, 0x06, + 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x2a, 0x23, + 0x0a, 0x0a, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, + 0x4a, 0x41, 0x56, 0x41, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x45, 0x44, 0x52, 0x4f, 0x43, + 0x4b, 0x10, 0x01, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2f, 0x6d, 0x63, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_mcstatus_proto_rawDescOnce sync.Once + file_mcstatus_proto_rawDescData = file_mcstatus_proto_rawDesc +) + +func file_mcstatus_proto_rawDescGZIP() []byte { + file_mcstatus_proto_rawDescOnce.Do(func() { + file_mcstatus_proto_rawDescData = protoimpl.X.CompressGZIP(file_mcstatus_proto_rawDescData) + }) + return file_mcstatus_proto_rawDescData +} + +var file_mcstatus_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_mcstatus_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_mcstatus_proto_goTypes = []interface{}{ + (ServerType)(0), // 0: mcstatuspb.ServerType + (*ServerStatus)(nil), // 1: mcstatuspb.ServerStatus + (*Player)(nil), // 2: mcstatuspb.Player +} +var file_mcstatus_proto_depIdxs = []int32{ + 2, // 0: mcstatuspb.ServerStatus.players:type_name -> mcstatuspb.Player + 0, // 1: mcstatuspb.ServerStatus.server_type:type_name -> mcstatuspb.ServerType + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_mcstatus_proto_init() } +func file_mcstatus_proto_init() { + if File_mcstatus_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_mcstatus_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ServerStatus); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_mcstatus_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Player); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_mcstatus_proto_rawDesc, + NumEnums: 1, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_mcstatus_proto_goTypes, + DependencyIndexes: file_mcstatus_proto_depIdxs, + EnumInfos: file_mcstatus_proto_enumTypes, + MessageInfos: file_mcstatus_proto_msgTypes, + }.Build() + File_mcstatus_proto = out.File + file_mcstatus_proto_rawDesc = nil + file_mcstatus_proto_goTypes = nil + file_mcstatus_proto_depIdxs = nil +} diff --git a/proto/mcstatus.proto b/proto/mcstatus.proto new file mode 100644 index 0000000..96b1348 --- /dev/null +++ b/proto/mcstatus.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; +package mcstatuspb; +option go_package = "./mcstatuspb"; + +message ServerStatus { + string host = 1; + int32 port = 2; + string name = 3; + string motd = 4; + string map = 5; + int32 max_players = 6; + int32 num_players = 7; + repeated Player players = 8; + string version = 9; + string favicon = 10; + ServerType server_type = 11; +} + +message Player { + string name = 1; + string uuid = 2; +} + +enum ServerType { + JAVA = 0; + BEDROCK = 1; +} diff --git a/public/api/v1/openapi.json b/public/api/v1/openapi.json index 835c9a5..c3e2ea7 100644 --- a/public/api/v1/openapi.json +++ b/public/api/v1/openapi.json @@ -268,38 +268,9 @@ "get": { "summary": "Get Minecraft server status", "description": "Get Minecraft server status", - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "address" - ], - "properties": { - "address": { - "type": "string" - }, - "port": { - "type": "integer" - }, - "query_port": { - "type": "integer" - }, - "is_bedrock": { - "type": "boolean" - }, - "query_enabled": { - "type": "boolean" - } - } - } - } - } - }, "parameters": [ { - "name": "address", + "name": "host", "in": "path", "description": "Minecraft server address", "required": true, @@ -308,36 +279,36 @@ } }, { - "name": "port", + "name": "bedrock", "in": "query", - "description": "Minecraft server port", + "description": "Is the server bedrock edition", "required": false, "schema": { - "type": "integer" + "type": "boolean" } }, { - "name": "query_port", + "name": "query", "in": "query", - "description": "Minecraft server query port", + "description": "Is query enabled on the server", "required": false, "schema": { - "type": "integer" + "type": "boolean" } }, { - "name": "is_bedrock", + "name": "query_port", "in": "query", - "description": "Is the server bedrock edition", + "description": "Minecraft server query port", "required": false, "schema": { - "type": "boolean" + "type": "integer" } }, { - "name": "query_enabled", + "name": "raw", "in": "query", - "description": "Is the server query enabled", + "description": "Return raw server status", "required": false, "schema": { "type": "boolean" @@ -350,39 +321,17 @@ "content": { "application/json": { "schema": { - "type": "object", - "required": [ - "name", - "map", - "maxplayers", - "players", - "connect", - "version", - "favicon" - ], - "properties": { - "name": { - "type": "string" - }, - "map": { - "type": "string" - }, - "maxplayers": { - "type": "integer" - }, - "players": { - "type": "integer" - }, - "connect": { - "type": "string" - }, - "version": { - "type": "string" - }, - "favicon": { - "type": "string" - } - } + "$ref": "#/components/schemas/MCServerStatus" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/MCServerStatus" + } + }, + "application/x-protobuf": { + "schema": { + "$ref": "#/components/schemas/MCServerStatus" } } } @@ -425,16 +374,6 @@ } } } - }, - "500": { - "description": "Internal Server Error", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } } } } @@ -443,29 +382,6 @@ "get": { "summary": "Get Minecraft server icon", "description": "Get Minecraft server icon", - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "address" - ], - "properties": { - "address": { - "type": "string" - }, - "port": { - "type": "integer" - }, - "is_bedrock": { - "type": "boolean" - } - } - } - } - } - }, "parameters": [ { "name": "address", @@ -475,24 +391,6 @@ "schema": { "type": "string" } - }, - { - "name": "port", - "in": "query", - "description": "Minecraft server port", - "required": false, - "schema": { - "type": "integer" - } - }, - { - "name": "is_bedrock", - "in": "query", - "description": "Is the server bedrock edition", - "required": false, - "schema": { - "type": "boolean" - } } ], "responses": { @@ -507,37 +405,8 @@ } } }, - "204": { - "description": "No Content, bedrock server detected, so a png of a bedrock block is returned", - "content": { - "image/png": { - "schema": { - "type": "string", - "format": "binary" - } - } - } - }, "404": { - "description": "Not Found, returns generic offline server icon", - "content": { - "image/png": { - "schema": { - "type": "string", - "format": "binary" - } - } - } - }, - "500": { - "description": "Internal Server Error", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } + "$ref": "#/components/responses/404NotFound" } } } @@ -618,6 +487,71 @@ "type": "string" } } + }, + "MCServerStatus": { + "type": "object", + "required": [ + "host", + "port", + "name", + "motd", + "map", + "max_players", + "num_players", + "version", + "favicon", + "server_type" + ], + "properties": { + "host": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "motd": { + "type": "string" + }, + "map": { + "type": "string" + }, + "max_players": { + "type": "integer" + }, + "num_players": { + "type": "integer" + }, + "players": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "uuid": { + "type": "string" + } + } + } + }, + "version": { + "type": "string" + }, + "favicon": { + "type": "string" + }, + "server_type": { + "type": "string", + "enum": [ + "java", + "bedrock" + ] + } + } } }, "parameters": { diff --git a/responses/problem.go b/responses/problem.go index 78435e0..989cc77 100644 --- a/responses/problem.go +++ b/responses/problem.go @@ -42,7 +42,8 @@ func (problem *problem) SendAndEncodeProblem(w http.ResponseWriter, r *http.Requ case "application/xml": content += "xml" structBytes, _ = xml.Marshal(problem) - default: + } + if structBytes == nil { content += "json" structBytes, _ = json.Marshal(problem) } diff --git a/responses/response.go b/responses/response.go index 0b1e1fe..a3dcff3 100644 --- a/responses/response.go +++ b/responses/response.go @@ -23,10 +23,12 @@ func SendAndEncodeStruct[T any](w http.ResponseWriter, r *http.Request, statusCo case "application/xml": content += "xml" structBytes, _ = xml.Marshal(data) - default: + } + if structBytes == nil { content += "json" structBytes, _ = json.Marshal(data) } + w.Header().Set("Content-Type", content) w.WriteHeader(statusCode) w.Write(structBytes)