MAGE Server Migration to Go

Overview

This document outlines the migration of the MAGE (Magic Another Game Engine) server from Java to Go while maintaining API compatibility.

Current Architecture

Communication Protocol

Core Components

Data Layer

Migration Plan

Phase 1: Foundation & Infrastructure

1.1 Protocol Migration Decision

Critical Decision Point: Choose replacement for JBoss Remoting

Option A - gRPC (Recommended)

Option B - Custom TCP + Protocol Buffers

Option C - Hybrid: gRPC + WebSocket

Action Items:

1.2 Database Migration

Replace: H2 + SQLite + ORMLite With: PostgreSQL + pgx/GORM OR keep SQLite + sqlx

Schema Migration:

Tables to Migrate:

Repository Pattern:

1.3 Configuration Management

Replace: XML config + JAXB With: Viper (YAML/JSON) or Go structs with env var support

Config Structure (port from config/config.xml):

type ServerConfig struct {
    ServerAddress        string
    ServerName          string
    Port                int
    SecondaryBindPort   int
    BacklogSize         int
    NumAcceptThreads    int
    MaxPoolSize         int
    LeasePeriod         int
    MaxGameThreads      int
    MaxSecondsIdle      int
    UserNameValidation  UserNameConfig
    PasswordValidation  PasswordConfig
    AuthSettings        AuthConfig
    MailSettings        MailConfig
    PluginPaths         []string
}

Action Items:

1.4 Project Structure

mage-server-go/
├── cmd/
│   └── server/
│       └── main.go                 # Entry point
├── internal/
│   ├── server/
│   │   └── server.go               # Core server (MageServerImpl port)
│   ├── session/
│   │   ├── session.go              # Session management
│   │   └── manager.go              # SessionManager
│   ├── user/
│   │   ├── user.go                 # User domain model
│   │   ├── manager.go              # UserManager
│   │   └── repository.go           # User persistence
│   ├── table/
│   │   ├── controller.go           # TableController port
│   │   └── manager.go              # TableManager
│   ├── game/
│   │   ├── controller.go           # GameController port
│   │   ├── session.go              # Player/watcher sessions
│   │   ├── manager.go              # GameManager
│   │   ├── replay.go               # Replay system
│   │   └── worker.go               # Game execution
│   ├── tournament/
│   │   ├── controller.go           # TournamentController
│   │   ├── session.go              # Tournament sessions
│   │   └── manager.go              # TournamentManager
│   ├── draft/
│   │   ├── controller.go           # DraftController
│   │   ├── session.go              # Draft sessions
│   │   └── manager.go              # DraftManager
│   ├── chat/
│   │   ├── chat.go                 # Chat session
│   │   └── manager.go              # ChatManager
│   ├── repository/
│   │   ├── cards.go                # CardRepository
│   │   ├── users.go                # AuthorizedUserRepository
│   │   ├── stats.go                # UserStatsRepository
│   │   └── records.go              # TableRecordRepository
│   ├── rating/
│   │   └── glicko.go               # GlickoRatingSystem
│   ├── mail/
│   │   ├── client.go               # MailClient interface
│   │   ├── smtp.go                 # SMTP implementation
│   │   └── mailgun.go              # Mailgun implementation
│   ├── auth/
│   │   └── auth.go                 # Authentication/password hashing
│   ├── room/
│   │   ├── room.go                 # Room abstraction
│   │   └── games_room.go           # GamesRoom (main lobby)
│   └── config/
│       └── config.go               # Configuration loader
├── pkg/
│   ├── proto/                      # Generated protobuf (if using gRPC)
│   │   └── mage/
│   │       └── v1/
│   └── models/                     # Shared data models
│       ├── views.go                # Client view models
│       └── enums.go                # Enums (ClientCallbackMethod, etc.)
├── api/
│   └── proto/                      # .proto definitions
│       └── mage/
│           └── v1/
│               ├── server.proto    # Main RPC service
│               ├── game.proto      # Game-related messages
│               └── tournament.proto
├── migrations/                     # Database migrations
│   ├── 001_create_users.sql
│   ├── 002_create_cards.sql
│   └── ...
├── config/
│   └── config.yaml                 # Default configuration
├── plugins/                        # Plugin system (TBD approach)
└── go.mod

Phase 2: Core Services

2.1 Session Management

Port: Session.java (554 lines) → internal/session/session.go

Key Features:

Implementation:

type Session struct {
    SessionID      string
    UserID         string
    Host           string
    IsAdmin        bool
    Connected      bool
    LastActivity   time.Time
    LeasePeriod    time.Duration
    CallbackChan   chan ClientCallback
    mu             sync.RWMutex
}
 
type SessionManager interface {
    CreateSession(sessionID string, host string) *Session
    GetSession(sessionID string) (*Session, bool)
    DisconnectSession(sessionID string, reason DisconnectReason)
    ValidateSession(sessionID string) bool
    CleanupExpiredSessions()
}

Action Items:

2.2 User Management

Port: UserManagerImpl.javainternal/user/manager.go

Responsibilities:

Action Items:

2.3 Authentication & Security

Port: AuthorizedUserRepository.javainternal/auth/auth.go

Current: SHA-256 with 1024 iterations (Apache Shiro) Recommended: bcrypt or Argon2id (Go standard)

Features:

Action Items:

2.4 RPC Method Implementation

Port: 60+ methods from MageServerImpl.java (1,356 lines)

Method Categories:

Authentication (6 methods):

Room/Lobby (5 methods):

Table Management (10 methods):

Game Execution (15 methods):

Draft (6 methods):

Tournament (4 methods):

Chat (7 methods):

Replay (6 methods):

Admin (9 methods):

Server Info (4 methods):

Deck Management (2 methods):

Implementation Strategy:

type MageServer interface {
    // Auth
    ConnectUser(ctx context.Context, req *ConnectUserRequest) (*ConnectUserResponse, error)
    // ... all 60+ methods
}
 
type mageServerImpl struct {
    sessionMgr    session.Manager
    userMgr       user.Manager
    tableMgr      table.Manager
    gameMgr       game.Manager
    tournamentMgr tournament.Manager
    draftMgr      draft.Manager
    chatMgr       chat.Manager
    config        *config.ServerConfig
}

Phase 3: Game Engine Integration

3.1 Table Controller

Port: TableController.java (1,265 lines) → internal/table/controller.go

Responsibilities:

Action Items:

3.2 Game Controller

Port: GameController.java (1,662 lines) → internal/game/controller.go

Critical Component: Interfaces with game engine (separate from server)

Responsibilities:

Action Items:

3.3 Tournament System

Port: TournamentController.javainternal/tournament/controller.go

Types: Swiss, Elimination, Booster Draft, Sealed, etc.

Action Items:

3.4 Draft System

Port: DraftController.javainternal/draft/controller.go

Types: Booster draft, cube draft, Winston draft

Action Items:

Phase 4: Real-Time Communication

4.1 Server-to-Client Callbacks

Port: Callback system from Session.fireCallback()

Current: InvokerCallbackHandler with ClientCallback messages

Callback Types (from ClientCallbackMethod enum):

Implementation Options:

Option A - gRPC Streaming:

service MageServer {
    rpc Subscribe(SubscribeRequest) returns (stream ServerEvent);
}

Option B - WebSocket:

func (s *Session) StartCallbackHandler() {
    conn := s.websocketConn
    for callback := range s.CallbackChan {
        conn.WriteJSON(callback)
    }
}

Action Items:

4.2 Chat System

Port: ChatManagerImpl.javainternal/chat/manager.go

Features:

Action Items:

Phase 5: Data & Persistence

5.1 Card Repository

Port: CardRepository.javainternal/repository/cards.go

Data: ~40,000 Magic cards with expansion info

Action Items:

5.2 User Stats & Records

Port: UserStatsRepository.java (379 lines) → internal/repository/stats.go

Features:

Action Items:

5.3 Table Records

Port: TableRecordRepository.javainternal/repository/records.go

Current: Protocol Buffers serialization (can keep!)

Action Items:

Phase 6: Plugin System

6.1 Plugin Architecture Challenge

Current: Dynamic JAR loading with custom ClassLoader

Problem: Go doesn’t support dynamic loading like Java

Options:

Option A - Go Plugins (Standard Library):

Option B - Pre-compiled Registry:

Option C - gRPC Plugin System (HashiCorp go-plugin):

Recommendation: Option B (pre-compiled) for initial migration, consider Option C if extensibility is critical

Action Items:

Phase 7: Supporting Services

7.1 Email Service

Port: MailClientImpl.java + MailgunClientImpl.javainternal/mail/

Current: SMTP (JavaMail) + Mailgun API (Jersey client)

Go Libraries:

Action Items:

7.2 Feedback Service

Port: FeedbackServiceImpl.java → simple endpoint

Action Items:

7.3 Logging

Replace: Log4j With: Zap (structured, high-performance) or Logrus

Action Items:

Phase 8: Testing & Quality

8.1 Unit Tests

Action Items:

8.2 Integration Tests

Action Items:

8.3 Performance Tests

Action Items:

Phase 9: Deployment & Operations

9.1 Containerization

Action Items:

9.2 Monitoring

Action Items:

9.3 Database Migrations

Action Items:

Migration Dependencies & Recommendations

Core Go Libraries

Alternative Transport Options

Compatibility Strategy

Backward Compatibility with Java Client

Critical: Existing Java clients must continue to work

Approach:

  1. Exact Protocol Matching: Reverse-engineer JBoss Remoting wire format
  2. Proxy Layer: Go server wraps Java server initially, gradually replaces methods
  3. Client Update: Release new Go-compatible client alongside server
  4. Dual-Version Support: Run Java and Go servers in parallel during transition

Recommendation: Unless perfect wire compatibility is required, consider releasing a new client version that uses gRPC/WebSocket.

Risk Mitigation

High-Risk Areas

  1. Game Engine Integration: Ensure game logic (separate module) integrates correctly
  2. Callback System: Server push is critical for real-time experience
  3. Session Management: Lease/ping mechanism must be reliable
  4. Database Migration: Card data, user accounts must migrate cleanly
  5. Plugin System: Loss of dynamic loading may limit extensibility

Mitigation Strategies

Timeline Estimate

Total Estimate: 25-34 weeks (6-8 months) for a team of 2-3 developers

Success Metrics

Open Questions

  1. Client Migration: Will Java clients be updated or must we maintain wire compatibility?
  2. Plugin Priority: Which game types/plugins are most critical to port first?
  3. Database Choice: Stick with SQLite or migrate to PostgreSQL?
  4. Deployment: On-premise or cloud? Single instance or distributed?
  5. Game Engine: Is the game engine (separate from server) also being migrated?

Next Steps

  1. Validate Approach: Review this plan with stakeholders
  2. Prototype Protocol: Build proof-of-concept for chosen RPC mechanism
  3. Database Schema Export: Extract current schemas from H2/SQLite
  4. Set Up Repository: Initialize Go project structure
  5. Begin Phase 1: Start with configuration and database layers