Compare commits

..

No commits in common. "e0380e44c3dafaae37fbe920fc6374e99baa4e1d" and "65caea328b48ba9c53b321b3032ea941f18d4c98" have entirely different histories.

11 changed files with 326 additions and 469 deletions

107
app/app.go Normal file
View File

@ -0,0 +1,107 @@
package main
import (
"github.com/haleyrom/skia-go"
"image/color"
"log"
"runtime"
"github.com/go-gl/gl/v3.3-core/gl"
"github.com/go-gl/glfw/v3.3/glfw"
)
func init() {
// GLFW event handling must run on the main OS thread
runtime.LockOSThread()
}
func main() {
// Initialize GLFW
if err := glfw.Init(); err != nil {
log.Fatalf("failed to initialize GLFW: %v", err)
}
defer glfw.Terminate()
// Create GLFW window
glfw.WindowHint(glfw.ContextVersionMajor, 3)
glfw.WindowHint(glfw.ContextVersionMinor, 3)
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
window, err := glfw.CreateWindow(800, 600, "GLFW + Skia Demo", nil, nil)
if err != nil {
log.Fatalf("failed to create GLFW window: %v", err)
}
window.MakeContextCurrent()
// Initialize OpenGL
if err := gl.Init(); err != nil {
log.Fatalf("failed to initialize OpenGL: %v", err)
}
// Set up Skia surface
glInterface := skia.NewNativeGrGlinterface()
if glInterface == nil {
log.Fatalf("failed to create Skia OpenGL interface")
}
grContext := skia.NewGLGrContext(glInterface)
if grContext == nil {
log.Fatalf("failed to create Skia GrContext")
}
// Get framebuffer info
var framebufferInfo skia.GrGlFramebufferinfo
var fboID int32
gl.GetIntegerv(gl.FRAMEBUFFER_BINDING, &fboID)
framebufferInfo.FFBOID = uint32(fboID)
framebufferInfo.FFormat = gl.RGBA8
width, height := window.GetSize()
renderTarget := skia.NewGlGrBackendrendertarget(int32(width), int32(height), 1, 8, &framebufferInfo)
if renderTarget == nil {
log.Fatalf("failed to create Skia render target")
}
surface := skia.NewSurfaceBackendRenderTarget(grContext, renderTarget, skia.GR_SURFACE_ORIGIN_BOTTOM_LEFT, skia.SK_COLORTYPE_RGBA_8888, nil, nil)
if surface == nil {
log.Fatalf("failed to create Skia surface")
}
defer surface.Unref()
c := color.RGBA{R: 255, G: 100, B: 50, A: 255}
f := skia.NewColor4f(c)
colorWhite := f.ToColor()
for !window.ShouldClose() {
gl.ClearColor(0.3, 0.3, 0.3, 1.0)
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
canvas := surface.GetCanvas()
paint := skia.NewPaint()
paint.SetColor(0xffff0000)
// Clear the canvas with white color
canvas.Clear(colorWhite)
// Create a rectangle and draw it
rect := skia.Rect{
Left: 100,
Top: 100,
Right: 300,
Bottom: 300,
}
canvas.DrawRect(&rect, paint)
grContext.Flush()
// Swap OpenGL buffers
window.SwapBuffers()
// Poll for GLFW events
glfw.PollEvents()
}
// Cleanup
surface.Unref()
grContext.Unref()
}

View File

@ -1,8 +0,0 @@
package main
var key = "ccebff0f-939a-4afe-b5b3-30a7a665ee38"
func main() {
var demoApp = NewDemoApp(key)
demoApp.Start()
}

View File

@ -1,50 +0,0 @@
package main
import "fmt"
type LogBuffer struct {
strings []string
size int
}
func NewLogBuffer(size int) *LogBuffer {
return &LogBuffer{
strings: make([]string, 0, size),
size: size,
}
}
func (l *LogBuffer) Add(s string) {
if len(l.strings) == l.size {
l.strings = l.strings[1:]
}
l.strings = append(l.strings, s)
}
func (l *LogBuffer) Get() []string {
return l.strings
}
func (l *LogBuffer) GetLast() (string, error) {
if len(l.strings) == 0 {
return "", fmt.Errorf("log buffer is empty")
}
return l.strings[len(l.strings)-1], nil
}
func (l *LogBuffer) GetSecondToLast() (string, error) {
if len(l.strings) < 2 {
return "", fmt.Errorf("log buffer does not have enough lines")
}
return l.strings[len(l.strings)-2], nil
}
func (l *LogBuffer) GetLineStepsBack(x int) (string, error) {
if x < 0 || x >= len(l.strings) {
return "", fmt.Errorf("log buffer does not have enough lines to step back %d times", x)
}
return l.strings[len(l.strings)-1-x], nil
}
//
//var LogBuf = NewLogBuffer(10)

View File

@ -52,7 +52,7 @@ func (c *CustomLogger) Error(msg string) {
} }
// Example usage of the custom logger // Example usage of the custom logger
func showcase() { func main() {
logger := NewCustomLogger() logger := NewCustomLogger()
logger.Info("This is an info message") logger.Info("This is an info message")

View File

@ -1,7 +1,6 @@
package main package main
import ( import (
"bufio"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/google/uuid" "github.com/google/uuid"
@ -10,270 +9,75 @@ import (
"hudly/mcfetch" "hudly/mcfetch"
"log" "log"
"os" "os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"time" "time"
) )
type PlayerWrapper struct { var key = "ccebff0f-939a-4afe-b5b3-30a7a665ee38"
Player hypixel.Player `json:"player"` var UUID = "5328930e-d411-49cb-90ad-4e5c7b27dd86"
}
func replaceCorruptedRune(msg string) string { func demo() {
runes := []rune(msg) // Ensure a username is provided as a command-line argument
for i, r := range runes { if len(os.Args) < 2 {
if r == '<27>' { log.Fatal("Please provide a Minecraft username as a command-line argument.")
runes[i] = '§'
}
} }
return string(runes)
}
func clearTerminal() { // Get the username from the command-line arguments
var cmd *exec.Cmd username := os.Args[1]
if runtime.GOOS == "windows" {
cmd = exec.Command("cmd", "/c", "cls")
} else {
cmd = exec.Command("clear")
}
cmd.Stdout = os.Stdout
cmd.Run()
}
// calculateRatio is a helper function to calculate ratios (e.g., WLR, KDR, etc.) thing := hypixel.NewAPIKey(key)
func calculateRatio(numerator, denominator int) float64 { api := hypixel.NewAPI(*thing)
if denominator == 0 { thing.UsesLeft = 11
return float64(numerator)
}
return float64(numerator) / float64(denominator)
}
type DemoApp struct { // Create a MemoryCache instance
Client *netclient.Client memCache := &mcfetch.MemoryCache{}
API *hypixel.HypixelApi memCache.Init()
MemCache *mcfetch.MemoryCache
LogBuf *LogBuffer
PartyBuilder []map[string]interface{}
}
func NewDemoApp(key string) *DemoApp { // Create a channel to receive the result
var api_key = hypixel.NewAPIKey(key) resultChan := make(chan map[string]interface{})
app := &DemoApp{ errorChan := make(chan error)
API: hypixel.NewAPI(*api_key),
MemCache: &mcfetch.MemoryCache{},
LogBuf: NewLogBuffer(10),
PartyBuilder: []map[string]interface{}{},
}
app.MemCache.Init()
return app
}
func (app *DemoApp) FetchMCPlayer(name string) (*mcfetch.FetchedPlayerResult, error) { // Create an AsyncPlayerFetcher for asynchronous data fetching with MemoryCache
asyncFetcher := mcfetch.NewPlayerFetcher( asyncFetcher := mcfetch.NewAsyncPlayerFetcher(
name, username, // Minecraft username or UUID
app.MemCache, memCache, // Pass the memory cache instance
2, 2, // Number of retries
2*time.Second, 2*time.Second, // Retry delay
5*time.Second, 5*time.Second, // Request timeout
) )
data, err := asyncFetcher.FetchPlayerData()
// Start asynchronous data fetching
asyncFetcher.FetchPlayerData(resultChan, errorChan)
// Non-blocking code execution (do something else while waiting)
fmt.Println("Fetching data asynchronously...")
var userID string
// Block until we receive data or an error
select {
case data := <-resultChan:
fmt.Printf("Player data: %+v\n", data)
// Check if "uuid" exists and is not nil
if uuid, ok := data["id"].(string); ok {
userID = uuid
} else {
fmt.Println(fmt.Sprintf("%+v", data))
log.Fatal("UUID not found or invalid for player")
}
case err := <-errorChan:
log.Fatal(err)
}
// Use the Hypixel API to get additional player data
res, err := api.GetPlayerResponse(userID)
if err != nil { if err != nil {
return nil, err panic(err)
} }
return data, nil fmt.Println(fmt.Sprintf("%+v", res))
} }
func (app *DemoApp) onFileEmit(line string) { func main() {
msg := strings.TrimSpace(line)
if len(msg) < 34 {
return
}
submsg := msg[33:]
if len(submsg) != 0 {
app.LogBuf.Add(submsg)
}
OnlinePrefix := "[CHAT] ONLINE: "
PartyListSeparatorLinePrefix := "[CHAT] -----------------------------------------------------"
//PartyMemberCountPrefix := "[CHAT] Party Members ("
PartyLeaderPrefix := "[CHAT] Party Leader: "
PartyListMembersPrefix := "[CHAT] Party Members: "
if strings.HasPrefix(submsg, OnlinePrefix) { // Online Message
newsubmsg := strings.TrimPrefix(submsg, OnlinePrefix)
players := strings.Split(newsubmsg, ",")
for _, player := range players {
playerName := strings.TrimSpace(player)
plr, err := app.FetchMCPlayer(playerName)
res_name := plr.Name
res_uuid := plr.UUID
if err != nil {
log.Fatalf("Error fetching UUID: %v", err)
return
}
fmt.Printf("UUID of player %s: %s\n", res_name, res_uuid)
//names, err := GetNameFromUUID(playerUUID)
//if err != nil {
// log.Fatalf("Error fetching names from UUID: %v", err)
//}
//fmt.Printf("Name history for UUID %s: %v\n", playerUUID, names)
}
} else if strings.HasPrefix(submsg, PartyListSeparatorLinePrefix) { // Party List
last, _ := app.LogBuf.GetSecondToLast()
// TODO: Check if moderators
if !strings.HasPrefix(last, PartyListMembersPrefix) {
return
}
PartyMembersMsg := strings.TrimPrefix(last, PartyListMembersPrefix)
var ppl []mcfetch.CacheResult
for _, player := range strings.Split(PartyMembersMsg, ",") {
playerName := strings.TrimSpace(strings.TrimSuffix(player, " ?"))
if strings.HasPrefix(playerName, "[") {
playerName = strings.Split(playerName, " ")[1]
}
plr, err := app.FetchMCPlayer(playerName)
if err != nil {
log.Fatalf("Error fetching Player: %v", err)
continue
}
res_name := plr.Name
res_uuid := plr.UUID
res_player := mcfetch.CacheResult{
UUID: plr.UUID,
Name: plr.Name,
}
fmt.Printf("UUID of player %s: %s\n", res_name, res_uuid)
ppl = append(ppl, res_player)
//playerName := strings.TrimSpace(player)
//playerUUID, err := GetUUIDFromName(playerName)
//if err != nil {
// log.Fatalf("Error fetching UUID: %v", err)
// return
//}
//fmt.Printf("UUID of player %s: %s\n", playerName, playerUUID)
//cachedPlayer := CachedUuid{playerUUID, playerName, playerName, time.Now()}
//UuidCache.Add(&cachedPlayer)
}
// Parse Party Leader
leaders_msg, err := app.LogBuf.GetLineStepsBack(2)
if err != nil {
println("Unable to find party leader message")
return
}
PartyLeaderMsg := strings.TrimPrefix(leaders_msg, PartyLeaderPrefix)
playerName := strings.TrimSpace(strings.TrimSuffix(PartyLeaderMsg, " ?"))
if strings.HasPrefix(playerName, "[") {
playerName = strings.Split(playerName, " ")[1]
}
plr, err := app.FetchMCPlayer(playerName)
if err != nil {
log.Fatalf("Error fetching Player: %v", err)
}
res_name := plr.Name
res_uuid := plr.UUID
res_player := mcfetch.CacheResult{
UUID: plr.UUID,
Name: plr.Name,
}
fmt.Printf("UUID of player %s: %s\n", res_name, res_uuid)
ppl = append(ppl, res_player)
// Parse Party Count
//party_count_msg, err := LogBuf.GetLineStepsBack(4)
//if err != nil {
// println("Unable to find party count message")
// return
//}
//PartyCountMsg := strings.TrimPrefix(party_count_msg, PartyMemberCountPrefix)
//count_str := strings.TrimSuffix(PartyCountMsg, ")")
//count, err := strconv.Atoi(count_str)
//if err != nil {
// println("Unable to parse party count message - Invalid number used")
// return
//}
//print("Expected ")
//print(count)
//print(" party members\n")
app.sendPartyList(ppl)
return
}
println(submsg)
}
func (app *DemoApp) tailFile(path string, lineCh chan<- string) {
file, err := os.Open(path)
if err != nil {
log.Fatalf("Failed to open file: %v", err)
}
defer file.Close()
file.Seek(0, 2)
reader := bufio.NewReader(file)
for {
line, err := reader.ReadString('\n')
if err != nil {
time.Sleep(100 * time.Millisecond)
continue
}
lineCh <- line
}
}
func (app *DemoApp) sendPartyList(ppl []mcfetch.CacheResult) {
for _, user := range ppl {
// Fetch player stats
res, err := app.API.GetPlayerResponse(user.UUID)
if err != nil {
log.Fatalf("Failed to get player data: %v", err)
}
// Calculate derived stats
res.Player.Stats.Bedwars.WLR = calculateRatio(res.Player.Stats.Bedwars.Wins, res.Player.Stats.Bedwars.Losses)
res.Player.Stats.Bedwars.KDR = calculateRatio(res.Player.Stats.Bedwars.Kills, res.Player.Stats.Bedwars.Deaths)
res.Player.Stats.Bedwars.FKDR = calculateRatio(res.Player.Stats.Bedwars.FinalKills, res.Player.Stats.Bedwars.FinalDeaths)
res.Player.Stats.Bedwars.BBLR = calculateRatio(res.Player.Stats.Bedwars.BedsBroken, res.Player.Stats.Bedwars.BedsLost)
// Convert player struct to JSON
playerJSON, err := json.Marshal(res)
if err != nil {
log.Fatalf("Failed to marshal player data: %v", err)
}
// Append the player JSON to the stuff list
var playerMap map[string]interface{}
json.Unmarshal(playerJSON, &playerMap)
app.PartyBuilder = append(app.PartyBuilder, playerMap)
// Send the list of JSON objects to the client
message, err := json.Marshal(app.PartyBuilder)
if err != nil {
log.Fatalf("Failed to marshal stuff: %v", err)
}
err = app.Client.SendData(string(message))
if err != nil {
log.Printf("Error sending data: %v", err)
}
fmt.Println("Sent stuff:", app.PartyBuilder)
println("Sending Done!")
}
}
func (app *DemoApp) Start() {
var cmd string var cmd string
fmt.Print(" | CREATE\n | JOIN\nEnter Choice:\n>") fmt.Print(" | CREATE\n | JOIN\nEnter Choice:\n>")
fmt.Scanln(&cmd) fmt.Scanln(&cmd)
@ -283,127 +87,146 @@ func (app *DemoApp) Start() {
return return
} }
var err error client, err := netclient.NewClient("0.0.0.0", uuid.New().String())
app.Client, err = netclient.NewClient("0.0.0.0", uuid.New().String())
if err != nil { if err != nil {
log.Fatalf("Failed to create client: %v", err) log.Fatalf("Failed to create client: %v", err)
return return
} }
var code string
if cmd == "CREATE" { if cmd == "CREATE" {
app.CreateRoom() var err error
} else if cmd == "JOIN" { code, err = client.CreateRoom("")
err := app.JoinRoom()
if err != nil { if err != nil {
log.Fatal(err)
return return
} }
} fmt.Println("Created room:", code)
fmt.Printf("[DEV] Joined Branches\n")
app.Client.ListenForData() err = client.JoinRoom(code, "password")
if err != nil {
log.Fatal(err)
return
}
println("Connected to room")
} else if cmd == "JOIN" {
var password string
fmt.Print("Enter Room Code:\n>")
fmt.Scanln(&code)
fmt.Print("Enter Room Password:\n>")
fmt.Scanln(&password)
err := client.JoinRoom(code, password)
if err != nil {
log.Fatal(err)
return
}
fmt.Println("Joined room:", code)
}
client.ListenForData()
// Handle received data in a separate goroutine // Handle received data in a separate goroutine
go func() { go func() {
for data := range app.Client.DataChannel { for data := range client.DataChannel {
fmt.Printf("Received data: %s\n", data) fmt.Printf("Received data: %s\n", data)
} }
}() }()
for { if cmd == "CREATE" {
select { println("Sleeping...")
case data, ok := <-app.Client.DataChannel: time.Sleep(time.Second * 20)
if !ok { println("Continuing!")
fmt.Println("Data channel closed, exiting...")
return thing := hypixel.NewAPIKey(key)
} api := hypixel.NewAPI(*thing)
app.HandleData(data)
memCache := &mcfetch.MemoryCache{}
memCache.Init()
resultChan := make(chan map[string]interface{})
errorChan := make(chan error)
players := []string{"illyum", "ergopunch"}
stuff := []map[string]interface{}{} // List to hold player JSON objects
println("Getting UUIDs")
for _, player := range players {
asyncFetcher := mcfetch.NewAsyncPlayerFetcher(
player,
memCache,
2,
2*time.Second,
5*time.Second,
)
asyncFetcher.FetchPlayerData(resultChan, errorChan)
} }
var userID string
for i := 0; i < len(players); i++ {
select {
case data := <-resultChan:
if uuid, ok := data["id"].(string); ok {
userID = uuid
} else {
fmt.Println(fmt.Sprintf("%+v", data))
log.Fatal("UUID not found or invalid for player")
}
// Fetch player stats
res, err := api.GetPlayerResponse(userID)
if err != nil {
log.Fatalf("Failed to get player data: %v", err)
}
// Calculate derived stats
res.Player.Stats.Bedwars.WLR = calculateRatio(res.Player.Stats.Bedwars.Wins, res.Player.Stats.Bedwars.Losses)
res.Player.Stats.Bedwars.KDR = calculateRatio(res.Player.Stats.Bedwars.Kills, res.Player.Stats.Bedwars.Deaths)
res.Player.Stats.Bedwars.FKDR = calculateRatio(res.Player.Stats.Bedwars.FinalKills, res.Player.Stats.Bedwars.FinalDeaths)
res.Player.Stats.Bedwars.BBLR = calculateRatio(res.Player.Stats.Bedwars.BedsBroken, res.Player.Stats.Bedwars.BedsLost)
// Convert player struct to JSON
playerJSON, err := json.Marshal(res)
if err != nil {
log.Fatalf("Failed to marshal player data: %v", err)
}
// Append the player JSON to the stuff list
var playerMap map[string]interface{}
json.Unmarshal(playerJSON, &playerMap)
stuff = append(stuff, playerMap)
case err := <-errorChan:
log.Fatal(err)
}
}
println("UUID Done!")
println("Sending data...")
// Send the list of JSON objects to the client
message, err := json.Marshal(stuff)
if err != nil {
log.Fatalf("Failed to marshal stuff: %v", err)
}
err = client.SendData(string(message))
if err != nil {
log.Printf("Error sending data: %v", err)
}
fmt.Println("Sent stuff:", stuff)
println("Sending Done!")
}
select {
case <-client.DataChannel: // This blocks the main goroutine until data is received
fmt.Println("Data received, exiting...")
} }
fmt.Println("Closing app") fmt.Println("Closing app")
} }
func (app *DemoApp) CreateRoom() { // calculateRatio is a helper function to calculate ratios (e.g., WLR, KDR, etc.)
var err error func calculateRatio(numerator, denominator int) float64 {
code, err := app.Client.CreateRoom("") if denominator == 0 {
if err != nil { return float64(numerator)
log.Fatal(err)
return
}
fmt.Println("Created room:", code)
err = app.Client.JoinRoom(code, "password")
if err != nil {
log.Fatal(err)
return
}
println("Connected to room")
path := os.Getenv("USERPROFILE")
logPath := filepath.Join(path, ".lunarclient", "offline", "multiver", "logs", "latest.log")
fmt.Println("Reading log file from:", logPath)
lineCh := make(chan string)
go app.tailFile(logPath, lineCh)
// TODO: Do this in a different goroutine so that you can still listen to data from your own client
for {
select {
case line := <-lineCh:
app.onFileEmit(replaceCorruptedRune(line))
}
} }
} return float64(numerator) / float64(denominator)
func (app *DemoApp) JoinRoom() error {
var code string
var password string
fmt.Print("Enter Room Code:\n>")
fmt.Scanln(&code)
fmt.Print("Enter Room Password:\n>")
fmt.Scanln(&password)
err := app.Client.JoinRoom(code, password)
if err != nil {
log.Fatal(err)
return err
}
fmt.Println("Joined room:", code)
return nil
}
func (app *DemoApp) HandleData(data string) {
var playerWrappers []PlayerWrapper
err := json.Unmarshal([]byte(data), &playerWrappers)
if err != nil {
fmt.Println("Error unmarshalling data:", err)
return
}
var players []*hypixel.Player
for _, wrapper := range playerWrappers {
players = append(players, &wrapper.Player)
}
// Pass the extracted players to DisplayPlayers
app.DisplayPlayers(players)
}
func (app *DemoApp) DisplayPlayers(players []*hypixel.Player) {
clearTerminal()
fmt.Printf("| %-20s | %-10s | %-10s |\n", "Player Name", "Bedwars Level", "FKDR")
fmt.Println("|----------------------|------------|------------|")
for _, player := range players {
fmt.Printf("| %-20s | %-10d | %-10.3f |\n",
player.DisplayName,
player.Achievements.BedwarsLevel,
player.Stats.Bedwars.FKDR)
}
fmt.Println("|----------------------|------------|------------|")
} }

4
go.mod
View File

@ -3,6 +3,10 @@ module hudly
go 1.23.0 go 1.23.0
require ( require (
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/haleyrom/skia-go v0.0.0-20240328095045-3f321a6a6e4d
) )
require github.com/mattn/go-pointer v0.0.0-20190911064623-a0a44394634f // indirect

View File

@ -28,27 +28,24 @@ func NewAsyncPlayerFetcher(playerName string, cache ICache, retries int, retryDe
} }
} }
// FetchPlayerData fetches the player data asynchronously using channels // FetchPlayerData fetches the player data asynchronously
func (pf *AsyncPlayerFetcher) FetchPlayerData(resultChan chan *FetchedPlayerResult, errorChan chan error) { func (pf *AsyncPlayerFetcher) FetchPlayerData(resultChan chan map[string]interface{}, errorChan chan error) {
go func() { go func() {
cachedData, found := pf.cache.Get(pf.playerName) cachedData, found := pf.cache.Get(pf.playerName)
if found { if found {
resultChan <- (*FetchedPlayerResult)(cachedData) resultChan <- cachedData
return return
} }
// If not in cache, make request to Mojang API var data map[string]interface{}
var player FetchedPlayerResult
for i := 0; i < pf.retries; i++ { for i := 0; i < pf.retries; i++ {
resp, err := pf.makeRequest(pf.playerName) resp, err := pf.makeRequest(pf.playerName)
if err == nil { if err == nil {
defer resp.Body.Close() defer resp.Body.Close()
// Decode the response into FetchedPlayerResult if err := json.NewDecoder(resp.Body).Decode(&data); err == nil {
if err := json.NewDecoder(resp.Body).Decode(&player); err == nil { pf.cache.Set(pf.playerName, data)
// Store the result in the cache and return the data
pf.cache.Set(pf.playerName, (*CacheResult)(&player))
pf.cache.Sync() pf.cache.Sync()
resultChan <- &player resultChan <- data
return return
} }
} }

View File

@ -8,16 +8,11 @@ import (
"sync" "sync"
) )
type CacheResult struct {
UUID string `json:"id"`
Name string `json:"name"`
}
type ICache interface { type ICache interface {
Init() Init()
Load() Load()
Get(key string) (*CacheResult, bool) Get(key string) (map[string]interface{}, bool)
Set(key string, data *CacheResult) Set(key string, data map[string]interface{})
Save() Save()
Sync() Sync()
Purge() Purge()
@ -26,31 +21,31 @@ type ICache interface {
// MemoryCache implementation // MemoryCache implementation
type MemoryCache struct { type MemoryCache struct {
cache map[string]*CacheResult cache map[string]interface{}
mu sync.RWMutex mu sync.RWMutex
} }
// Init initializes the cache (no-op for MemoryCache) // Init initializes the cache (no-op for MemoryCache)
func (c *MemoryCache) Init() { func (c *MemoryCache) Init() {
c.cache = make(map[string]*CacheResult) c.cache = make(map[string]interface{})
} }
// Load loads the cache (no-op for MemoryCache) // Load loads the cache (no-op for MemoryCache)
func (c *MemoryCache) Load() {} func (c *MemoryCache) Load() {}
// Get retrieves an item from the cache // Get retrieves an item from the cache
func (c *MemoryCache) Get(key string) (*CacheResult, bool) { func (c *MemoryCache) Get(key string) (map[string]interface{}, bool) {
c.mu.RLock() c.mu.RLock()
defer c.mu.RUnlock() defer c.mu.RUnlock()
value, found := c.cache[key] value, found := c.cache[key]
if !found { if !found {
return nil, false return nil, false
} }
return value, true return value.(map[string]interface{}), true
} }
// Set stores an item in the cache // Set stores an item in the cache
func (c *MemoryCache) Set(key string, data *CacheResult) { func (c *MemoryCache) Set(key string, data map[string]interface{}) {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
c.cache[key] = data c.cache[key] = data
@ -69,19 +64,19 @@ func (c *MemoryCache) Purge() {}
func (c *MemoryCache) Clear() { func (c *MemoryCache) Clear() {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
c.cache = make(map[string]*CacheResult) c.cache = make(map[string]interface{})
} }
// JsonFileCache implementation // JsonFileCache implementation
type JsonFileCache struct { type JsonFileCache struct {
filename string filename string
cache map[CacheResult]interface{} cache map[string]interface{}
mu sync.RWMutex mu sync.RWMutex
} }
// Init initializes the cache // Init initializes the cache
func (c *JsonFileCache) Init() { func (c *JsonFileCache) Init() {
c.cache = make(map[CacheResult]interface{}) c.cache = make(map[string]interface{})
} }
// Load loads the cache from a JSON file // Load loads the cache from a JSON file
@ -109,22 +104,21 @@ func (c *JsonFileCache) Load() {
} }
// Get retrieves an item from the cache // Get retrieves an item from the cache
func (c *JsonFileCache) Get(key string) (*CacheResult, bool) { func (c *JsonFileCache) Get(key string) (map[string]interface{}, bool) {
//c.mu.RLock() c.mu.RLock()
//defer c.mu.RUnlock() defer c.mu.RUnlock()
//value, found := c.cache[key] value, found := c.cache[key]
//if !found { if !found {
// return nil, false return nil, false
//} }
//return value, true return value.(map[string]interface{}), true
return nil, false
} }
// Set stores an item in the cache // Set stores an item in the cache
func (c *JsonFileCache) Set(key string, data *CacheResult) { func (c *JsonFileCache) Set(key string, data map[string]interface{}) {
//c.mu.Lock() c.mu.Lock()
//defer c.mu.Unlock() defer c.mu.Unlock()
//c.cache[key] = data c.cache[key] = data
} }
// Save saves the cache to a JSON file // Save saves the cache to a JSON file
@ -156,5 +150,5 @@ func (c *JsonFileCache) Purge() {}
func (c *JsonFileCache) Clear() { func (c *JsonFileCache) Clear() {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
c.cache = make(map[CacheResult]interface{}) c.cache = make(map[string]interface{})
} }

View File

@ -16,11 +16,6 @@ type PlayerFetcher struct {
cache ICache cache ICache
} }
type FetchedPlayerResult struct {
UUID string `json:"id"`
Name string `json:"name"`
}
// NewPlayerFetcher creates a new PlayerFetcher with an abstract cache (ICache) // NewPlayerFetcher creates a new PlayerFetcher with an abstract cache (ICache)
func NewPlayerFetcher(playerName string, cache ICache, retries int, retryDelay time.Duration, timeout time.Duration) *PlayerFetcher { func NewPlayerFetcher(playerName string, cache ICache, retries int, retryDelay time.Duration, timeout time.Duration) *PlayerFetcher {
cache.Init() cache.Init()
@ -34,21 +29,21 @@ func NewPlayerFetcher(playerName string, cache ICache, retries int, retryDelay t
} }
// FetchPlayerData fetches the player data synchronously // FetchPlayerData fetches the player data synchronously
func (pf *PlayerFetcher) FetchPlayerData() (*FetchedPlayerResult, error) { func (pf *PlayerFetcher) FetchPlayerData() (map[string]interface{}, error) {
//cachedData, found := pf.cache.Get(pf.playerName) cachedData, found := pf.cache.Get(pf.playerName)
//if found { if found {
// return &FetchedPlayerResult{}, nil return cachedData, nil
//} }
var player FetchedPlayerResult var data map[string]interface{}
for i := 0; i < pf.retries; i++ { for i := 0; i < pf.retries; i++ {
resp, err := pf.makeRequest(pf.playerName) resp, err := pf.makeRequest(pf.playerName)
if err == nil { if err == nil {
defer resp.Body.Close() defer resp.Body.Close()
if err := json.NewDecoder(resp.Body).Decode(&player); err == nil { if err := json.NewDecoder(resp.Body).Decode(&data); err == nil {
// pf.cache.Set(pf.playerName, player) pf.cache.Set(pf.playerName, data)
// pf.cache.Sync() pf.cache.Sync()
return &player, nil return data, nil
} }
} }
time.Sleep(pf.retryDelay) time.Sleep(pf.retryDelay)

View File

@ -199,14 +199,12 @@ func handleClient(conn net.Conn) {
} }
func handleConnectRequest(conn net.Conn, packet ConnectionRequestPacket) { func handleConnectRequest(conn net.Conn, packet ConnectionRequestPacket) {
fmt.Println("Incoming connection request")
room := findRoom(packet.RoomCode) room := findRoom(packet.RoomCode)
if room == nil { if room == nil {
writePacket(conn, byte(CONNECT_RESPONSE), encodeResponsePacket(ConnectionResponsePacket{ writePacket(conn, byte(CONNECT_RESPONSE), encodeResponsePacket(ConnectionResponsePacket{
Success: false, Success: false,
Reason: "room does not exist", Reason: "room does not exist",
})) }))
fmt.Println("Attempted room does not exist")
return return
} }
@ -215,7 +213,6 @@ func handleConnectRequest(conn net.Conn, packet ConnectionRequestPacket) {
Success: true, Success: true,
Reason: "", Reason: "",
})) }))
fmt.Println("Invalid password")
return return
} }
@ -223,7 +220,6 @@ func handleConnectRequest(conn net.Conn, packet ConnectionRequestPacket) {
Success: false, Success: false,
Reason: "invalid password", Reason: "invalid password",
})) }))
fmt.Println("Connected user to room ")
} }
func handleCreateRoomRequest(conn net.Conn, packet CreateRoomRequestPacket) { func handleCreateRoomRequest(conn net.Conn, packet CreateRoomRequestPacket) {
@ -301,7 +297,6 @@ func handleJoinRequest(conn net.Conn, packet JoinRequestPacket) {
} }
func handleSendData(conn net.Conn, packet SendDataRequestPacket) { func handleSendData(conn net.Conn, packet SendDataRequestPacket) {
fmt.Println("Incoming send data request")
mu.Lock() mu.Lock()
client, exists := clients[packet.UserID] client, exists := clients[packet.UserID]
mu.Unlock() mu.Unlock()