package main
import (
"context"
"log"
"sync"
"time"
"github.com/robinbraemer/event"
"go.minekube.com/common/minecraft/component"
"go.minekube.com/gate/pkg/edition/java/proxy"
)
type MyPlugin struct {
proxy *proxy.Proxy
db *Database
workers *WorkerPool
shutdown chan struct{}
wg sync.WaitGroup
}
func NewPlugin(p *proxy.Proxy) *MyPlugin {
plugin := &MyPlugin{
proxy: p,
shutdown: make(chan struct{}),
}
plugin.registerLifecycleEvents()
return plugin
}
func (p *MyPlugin) registerLifecycleEvents() {
mgr := p.proxy.Event()
// Handle proxy ready
event.Subscribe(mgr, 0, func(e *proxy.ReadyEvent) {
log.Printf("Proxy ready on %s", e.Addr())
// Initialize database
var err error
p.db, err = ConnectDatabase("postgres://...")
if err != nil {
log.Printf("Failed to connect to database: %v", err)
return
}
log.Println("Database connected")
// Start background workers
p.workers = NewWorkerPool(5)
p.workers.Start()
// Start periodic tasks
p.wg.Add(1)
go p.runPeriodicTasks()
log.Println("Plugin fully initialized")
})
// Handle pre-shutdown
event.Subscribe(mgr, 0, func(e *proxy.PreShutdownEvent) {
log.Println("Pre-shutdown initiated")
// Set a friendly disconnect message
e.SetReason(&component.Text{
Content: "Server is restarting\nPlease reconnect in 30 seconds",
S: component.Style{
Color: component.Gold,
},
})
// Save all player data
if err := p.saveAllPlayers(); err != nil {
log.Printf("Error saving player data: %v", err)
}
log.Println("Pre-shutdown complete")
})
// Handle shutdown
event.Subscribe(mgr, 0, func(e *proxy.ShutdownEvent) {
log.Println("Shutdown initiated")
// Signal shutdown to background tasks
close(p.shutdown)
// Wait for background tasks to complete (with timeout)
done := make(chan struct{})
go func() {
p.wg.Wait()
close(done)
}()
select {
case <-done:
log.Println("Background tasks completed")
case <-time.After(10 * time.Second):
log.Println("Background tasks timed out")
}
// Stop workers
if p.workers != nil {
p.workers.Stop()
}
// Close database
if p.db != nil {
if err := p.db.Close(); err != nil {
log.Printf("Error closing database: %v", err)
} else {
log.Println("Database closed")
}
}
log.Println("Shutdown complete")
})
}
func (p *MyPlugin) runPeriodicTasks() {
defer p.wg.Done()
ticker := time.NewTicker(1 * time.Minute)
defer ticker.Stop()
for {
select {
case <-ticker.C:
// Perform periodic task
p.cleanupOldData()
case <-p.shutdown:
log.Println("Stopping periodic tasks")
return
}
}
}
func (p *MyPlugin) saveAllPlayers() error {
for _, player := range p.proxy.Players() {
if err := p.db.SavePlayer(player); err != nil {
return err
}
}
return nil
}
func (p *MyPlugin) cleanupOldData() {
// Periodic cleanup logic
}