From a3499c2734f338d01b9a7ce0292d8651c186750e Mon Sep 17 00:00:00 2001 From: Josscoder Date: Wed, 28 May 2025 10:13:16 -0500 Subject: [PATCH 1/2] feat: impl ProcessFallback processor --- session/handler.go | 11 +++++++++++ session/processor.go | 3 +++ 2 files changed, 14 insertions(+) diff --git a/session/handler.go b/session/handler.go index 0d13fcc..790598f 100644 --- a/session/handler.go +++ b/session/handler.go @@ -31,6 +31,17 @@ loop: } server.CloseWithError(fmt.Errorf("failed to read packet from server: %w", err)) + + s.serverMu.RLock() + origin := s.serverAddr + s.serverMu.RUnlock() + + ctx := NewContext() + s.Processor().ProcessFallback(ctx, &origin, err) + if ctx.Cancelled() { + continue loop + } + if err := s.fallback(); err != nil { s.CloseWithError(fmt.Errorf("fallback failed: %w", err)) break loop diff --git a/session/processor.go b/session/processor.go index 69391f7..9dbfecb 100644 --- a/session/processor.go +++ b/session/processor.go @@ -49,6 +49,8 @@ type Processor interface { ProcessCache(ctx *Context, new *[]byte) // ProcessDisconnection is called when the player disconnects from the proxy. ProcessDisconnection(ctx *Context, message *string) + // ProcessFallback is called when a fallback is triggered due to a server error from the given origin. + ProcessFallback(ctx *Context, origin *string, err error) } // NopProcessor is a no-operation implementation of the Processor interface. @@ -68,3 +70,4 @@ func (NopProcessor) ProcessTransferFailure(_ *Context, _ *string, _ *string) {} func (NopProcessor) ProcessPostTransfer(_ *Context, _ *string, _ *string) {} func (NopProcessor) ProcessCache(_ *Context, _ *[]byte) {} func (NopProcessor) ProcessDisconnection(_ *Context, _ *string) {} +func (NopProcessor) ProcessFallback(_ *Context, _ *string, _ error) {} From cbf6c25bb6d94e7779b77fe3e5cd359f2ab58792 Mon Sep 17 00:00:00 2001 From: Josscoder Date: Wed, 28 May 2025 11:33:27 -0500 Subject: [PATCH 2/2] feat: improve fallback processors --- session/handler.go | 11 ----------- session/processor.go | 34 ++++++++++++++++++++-------------- session/session.go | 15 +++++++++++++++ 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/session/handler.go b/session/handler.go index 790598f..0d13fcc 100644 --- a/session/handler.go +++ b/session/handler.go @@ -31,17 +31,6 @@ loop: } server.CloseWithError(fmt.Errorf("failed to read packet from server: %w", err)) - - s.serverMu.RLock() - origin := s.serverAddr - s.serverMu.RUnlock() - - ctx := NewContext() - s.Processor().ProcessFallback(ctx, &origin, err) - if ctx.Cancelled() { - continue loop - } - if err := s.fallback(); err != nil { s.CloseWithError(fmt.Errorf("fallback failed: %w", err)) break loop diff --git a/session/processor.go b/session/processor.go index 9dbfecb..2bd60ad 100644 --- a/session/processor.go +++ b/session/processor.go @@ -49,8 +49,12 @@ type Processor interface { ProcessCache(ctx *Context, new *[]byte) // ProcessDisconnection is called when the player disconnects from the proxy. ProcessDisconnection(ctx *Context, message *string) - // ProcessFallback is called when a fallback is triggered due to a server error from the given origin. - ProcessFallback(ctx *Context, origin *string, err error) + // ProcessPreFallback is called before transferring the player to a fallback server. + ProcessPreFallback(ctx *Context, origin *string, target *string) + // ProcessFallbackFailure is called when the fallback transfer fails. + ProcessFallbackFailure(ctx *Context, origin *string, target *string, err error) + // ProcessPostFallback is called after transferring the player to a fallback server. + ProcessPostFallback(ctx *Context, origin *string, target *string) } // NopProcessor is a no-operation implementation of the Processor interface. @@ -59,15 +63,17 @@ type NopProcessor struct{} // Ensure that NopProcessor satisfies the Processor interface. var _ Processor = NopProcessor{} -func (NopProcessor) ProcessStartGame(_ *Context, _ *minecraft.GameData) {} -func (NopProcessor) ProcessServer(_ *Context, _ *packet.Packet) {} -func (NopProcessor) ProcessServerEncoded(_ *Context, _ *[]byte) {} -func (NopProcessor) ProcessClient(_ *Context, _ *packet.Packet) {} -func (NopProcessor) ProcessClientEncoded(_ *Context, _ *[]byte) {} -func (NopProcessor) ProcessFlush(_ *Context) {} -func (NopProcessor) ProcessPreTransfer(_ *Context, _ *string, _ *string) {} -func (NopProcessor) ProcessTransferFailure(_ *Context, _ *string, _ *string) {} -func (NopProcessor) ProcessPostTransfer(_ *Context, _ *string, _ *string) {} -func (NopProcessor) ProcessCache(_ *Context, _ *[]byte) {} -func (NopProcessor) ProcessDisconnection(_ *Context, _ *string) {} -func (NopProcessor) ProcessFallback(_ *Context, _ *string, _ error) {} +func (NopProcessor) ProcessStartGame(_ *Context, _ *minecraft.GameData) {} +func (NopProcessor) ProcessServer(_ *Context, _ *packet.Packet) {} +func (NopProcessor) ProcessServerEncoded(_ *Context, _ *[]byte) {} +func (NopProcessor) ProcessClient(_ *Context, _ *packet.Packet) {} +func (NopProcessor) ProcessClientEncoded(_ *Context, _ *[]byte) {} +func (NopProcessor) ProcessFlush(_ *Context) {} +func (NopProcessor) ProcessPreTransfer(_ *Context, _ *string, _ *string) {} +func (NopProcessor) ProcessTransferFailure(_ *Context, _ *string, _ *string) {} +func (NopProcessor) ProcessPostTransfer(_ *Context, _ *string, _ *string) {} +func (NopProcessor) ProcessCache(_ *Context, _ *[]byte) {} +func (NopProcessor) ProcessDisconnection(_ *Context, _ *string) {} +func (NopProcessor) ProcessPreFallback(_ *Context, _ *string, _ *string) {} +func (NopProcessor) ProcessFallbackFailure(_ *Context, _ *string, _ *string, _ error) {} +func (NopProcessor) ProcessPostFallback(_ *Context, _ *string, _ *string) {} diff --git a/session/session.go b/session/session.go index c4129ab..fce5475 100644 --- a/session/session.go +++ b/session/session.go @@ -321,15 +321,30 @@ func (s *Session) fallback() error { return errors.New("already in fallback") } + s.serverMu.RLock() + origin := s.serverAddr + s.serverMu.RUnlock() + + processorCtx := NewContext() + addr, err := s.discovery.DiscoverFallback(s.client) if err != nil { + s.Processor().ProcessFallbackFailure(processorCtx, &origin, nil, err) return fmt.Errorf("discovery failed: %w", err) } + s.Processor().ProcessPreFallback(processorCtx, &origin, &addr) + if processorCtx.Cancelled() { + return errors.New("processor failed") + } + s.logger.Debug("transferring session to a fallback server", "addr", addr) if err := s.Transfer(addr); err != nil { + s.Processor().ProcessFallbackFailure(processorCtx, &origin, &addr, err) return fmt.Errorf("transfer failed: %w", err) } + + s.Processor().ProcessPostFallback(processorCtx, &origin, &addr) return nil }