Skip to content

Commit 25238f7

Browse files
committed
Add 'builds' field to /api/stats
1 parent d137ead commit 25238f7

File tree

2 files changed

+182
-3
lines changed

2 files changed

+182
-3
lines changed

pkg/web/api/stats.go

Lines changed: 179 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
package api
22

33
import (
4-
"net/http"
5-
4+
"archive/zip"
5+
"bytes"
6+
"encoding/json"
7+
"encoding/xml"
8+
"errors"
9+
"io"
610
"meteor-server/pkg/core"
711
"meteor-server/pkg/db"
12+
"net/http"
13+
"strconv"
14+
"strings"
15+
"sync"
16+
"time"
817
)
918

1019
type Stats struct {
@@ -15,6 +24,22 @@ type Stats struct {
1524
Downloads int `json:"downloads"`
1625
OnlinePlayers int `json:"onlinePlayers"`
1726
OnlineUUIDs int `json:"onlineUUIDs"`
27+
28+
Builds map[string]int `json:"builds"`
29+
}
30+
31+
var builds map[string]int
32+
33+
func InitStats() {
34+
t := time.NewTicker(time.Minute)
35+
36+
go func() {
37+
for {
38+
builds = getBuildNumbers()
39+
40+
<-t.C
41+
}
42+
}()
1843
}
1944

2045
func StatsHandler(w http.ResponseWriter, r *http.Request) {
@@ -23,7 +48,14 @@ func StatsHandler(w http.ResponseWriter, r *http.Request) {
2348
if date == "" {
2449
g := db.GetGlobal()
2550

26-
core.Json(w, Stats{Config: core.GetConfig(), Date: core.GetDate(), DevBuild: g.DevBuild, Downloads: g.Downloads, OnlinePlayers: GetPlayingCount()})
51+
core.Json(w, Stats{
52+
Config: core.GetConfig(),
53+
Date: core.GetDate(),
54+
DevBuild: g.DevBuild,
55+
Downloads: g.Downloads,
56+
OnlinePlayers: GetPlayingCount(),
57+
Builds: builds,
58+
})
2759
} else {
2860
stats, err := db.GetJoinStats(date)
2961

@@ -35,3 +67,147 @@ func StatsHandler(w http.ResponseWriter, r *http.Request) {
3567
core.Json(w, stats)
3668
}
3769
}
70+
71+
func RecheckMavenHandler(w http.ResponseWriter, _ *http.Request) {
72+
builds = getBuildNumbers()
73+
74+
core.Json(w, struct{}{})
75+
}
76+
77+
// Maven
78+
79+
type MavenSnapshotVersion struct {
80+
Extension string `xml:"extension"`
81+
Classifier string `xml:"classifier"`
82+
Value string `xml:"value"`
83+
}
84+
85+
type MavenVersioning struct {
86+
Versions []string `xml:"versions>version"`
87+
SnapshotVersions []MavenSnapshotVersion `xml:"snapshotVersions>snapshotVersion"`
88+
}
89+
90+
type MavenMetadata struct {
91+
Versioning MavenVersioning `xml:"versioning"`
92+
}
93+
94+
type FabricMod struct {
95+
Version string `json:"version"`
96+
}
97+
98+
func getBuildNumbers() map[string]int {
99+
builds := make(map[string]int)
100+
101+
res, err := http.Get("https://maven.meteordev.org/snapshots/meteordevelopment/meteor-client/maven-metadata.xml")
102+
if err != nil {
103+
return builds
104+
}
105+
106+
var metadata MavenMetadata
107+
err = xml.NewDecoder(res.Body).Decode(&metadata)
108+
if err != nil {
109+
return builds
110+
}
111+
112+
mutex := sync.Mutex{}
113+
group := sync.WaitGroup{}
114+
115+
for _, version := range metadata.Versioning.Versions {
116+
version := version
117+
group.Add(1)
118+
119+
go func() {
120+
i := strings.IndexRune(version, '-')
121+
mcVersion := version[:i]
122+
123+
if !strings.HasPrefix(mcVersion, "0") {
124+
build, err := getBuildNumber(version)
125+
126+
if err == nil {
127+
mutex.Lock()
128+
builds[mcVersion] = build
129+
mutex.Unlock()
130+
}
131+
}
132+
133+
group.Done()
134+
}()
135+
}
136+
137+
group.Wait()
138+
139+
return builds
140+
}
141+
142+
func getBuildNumber(version string) (int, error) {
143+
res, err := http.Get("https://maven.meteordev.org/snapshots/meteordevelopment/meteor-client/" + version + "/maven-metadata.xml")
144+
if err != nil {
145+
return -1, err
146+
}
147+
148+
//goland:noinspection GoUnhandledErrorResult
149+
defer res.Body.Close()
150+
151+
var metadata MavenMetadata
152+
err = xml.NewDecoder(res.Body).Decode(&metadata)
153+
if err != nil {
154+
return -1, err
155+
}
156+
157+
var filename = ""
158+
159+
for _, version := range metadata.Versioning.SnapshotVersions {
160+
if version.Classifier == "" && version.Extension == "jar" {
161+
filename = "meteor-client-" + version.Value + ".jar"
162+
break
163+
}
164+
}
165+
166+
res, err = http.Get("https://maven.meteordev.org/snapshots/meteordevelopment/meteor-client/" + version + "/" + filename)
167+
if err != nil {
168+
return -1, err
169+
}
170+
171+
//goland:noinspection GoUnhandledErrorResult
172+
defer res.Body.Close()
173+
174+
body, err := io.ReadAll(res.Body)
175+
if err != nil {
176+
return -1, err
177+
}
178+
179+
jar, err := zip.NewReader(bytes.NewReader(body), int64(len(body)))
180+
if err != nil {
181+
return -1, err
182+
}
183+
184+
var mod FabricMod
185+
186+
for _, file := range jar.File {
187+
if file.Name == "fabric.mod.json" {
188+
reader, err := file.Open()
189+
if err != nil {
190+
continue
191+
}
192+
193+
_ = json.NewDecoder(reader).Decode(&mod)
194+
195+
_ = reader.Close()
196+
197+
break
198+
}
199+
}
200+
201+
if mod.Version != "" {
202+
i := strings.IndexRune(mod.Version, '-')
203+
204+
build, err := strconv.ParseInt(mod.Version[i+1:], 10, 32)
205+
if err != nil {
206+
return -1, err
207+
}
208+
209+
return int(build), nil
210+
}
211+
212+
return -1, errors.New("unknown build")
213+
}

pkg/web/web.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ func Main() {
4646
}
4747
}()
4848

49+
api.InitStats()
50+
4951
// Middlewares
5052
r.Use(middleware.RealIP)
5153

@@ -77,6 +79,7 @@ func Main() {
7779
r.Get("/capeowners", api.CapeOwnersHandler)
7880

7981
r.Post("/uploadDevBuild", auth.TokenAuth(api.UploadDevBuildHandler))
82+
r.Post("/recheckMaven", auth.TokenAuth(api.RecheckMavenHandler))
8083

8184
// /api/account
8285
r.Route("/account", func(r chi.Router) {

0 commit comments

Comments
 (0)