Documentation
¶
Index ¶
- Constants
- Variables
- func DevLoginEnabled() bool
- func GenerateRandomNickname() string
- func GenerateRandomNicknameWithSpace() string
- func GrpcAuthContext(userID string) context.Context
- func HandleGRPCError(err error, w http.ResponseWriter, r *http.Request, ...) (error, bool)
- func IsValidNickname(nickname string) bool
- func ThemeFromRequest(req *http.Request) string
- func WrapDevLogin(oneauth *httpauth.OneAuth) func(http.Handler) http.Handler
- type ApiHandler
- type AttackSimulatorPage
- type BasePage
- type ConnectGameSyncServiceAdapter
- type ConnectGamesServiceAdapter
- func (a *ConnectGamesServiceAdapter) CreateGame(ctx context.Context, req *connect.Request[v1.CreateGameRequest]) (*connect.Response[v1.CreateGameResponse], error)
- func (a *ConnectGamesServiceAdapter) DeleteGame(ctx context.Context, req *connect.Request[v1.DeleteGameRequest]) (*connect.Response[v1.DeleteGameResponse], error)
- func (a *ConnectGamesServiceAdapter) GetGame(ctx context.Context, req *connect.Request[v1.GetGameRequest]) (*connect.Response[v1.GetGameResponse], error)
- func (a *ConnectGamesServiceAdapter) GetGameState(ctx context.Context, req *connect.Request[v1.GetGameStateRequest]) (*connect.Response[v1.GetGameStateResponse], error)
- func (a *ConnectGamesServiceAdapter) GetGames(ctx context.Context, req *connect.Request[v1.GetGamesRequest]) (*connect.Response[v1.GetGamesResponse], error)
- func (a *ConnectGamesServiceAdapter) GetOptionsAt(ctx context.Context, req *connect.Request[v1.GetOptionsAtRequest]) (*connect.Response[v1.GetOptionsAtResponse], error)
- func (a *ConnectGamesServiceAdapter) JoinGame(ctx context.Context, req *connect.Request[v1.JoinGameRequest]) (*connect.Response[v1.JoinGameResponse], error)
- func (a *ConnectGamesServiceAdapter) ListGames(ctx context.Context, req *connect.Request[v1.ListGamesRequest]) (*connect.Response[v1.ListGamesResponse], error)
- func (a *ConnectGamesServiceAdapter) ListMoves(ctx context.Context, req *connect.Request[v1.ListMovesRequest]) (*connect.Response[v1.ListMovesResponse], error)
- func (a *ConnectGamesServiceAdapter) ProcessMoves(ctx context.Context, req *connect.Request[v1.ProcessMovesRequest]) (*connect.Response[v1.ProcessMovesResponse], error)
- func (a *ConnectGamesServiceAdapter) SimulateAttack(ctx context.Context, req *connect.Request[v1.SimulateAttackRequest]) (*connect.Response[v1.SimulateAttackResponse], error)
- func (a *ConnectGamesServiceAdapter) SimulateFix(ctx context.Context, req *connect.Request[v1.SimulateFixRequest]) (*connect.Response[v1.SimulateFixResponse], error)
- func (a *ConnectGamesServiceAdapter) UpdateGame(ctx context.Context, req *connect.Request[v1.UpdateGameRequest]) (*connect.Response[v1.UpdateGameResponse], error)
- type ConnectIndexerServiceAdapter
- type ConnectWorldsServiceAdapter
- func (a *ConnectWorldsServiceAdapter) CreateWorld(ctx context.Context, req *connect.Request[v1.CreateWorldRequest]) (*connect.Response[v1.CreateWorldResponse], error)
- func (a *ConnectWorldsServiceAdapter) DeleteWorld(ctx context.Context, req *connect.Request[v1.DeleteWorldRequest]) (*connect.Response[v1.DeleteWorldResponse], error)
- func (a *ConnectWorldsServiceAdapter) GetWorld(ctx context.Context, req *connect.Request[v1.GetWorldRequest]) (*connect.Response[v1.GetWorldResponse], error)
- func (a *ConnectWorldsServiceAdapter) GetWorlds(ctx context.Context, req *connect.Request[v1.GetWorldsRequest]) (*connect.Response[v1.GetWorldsResponse], error)
- func (a *ConnectWorldsServiceAdapter) ListWorlds(ctx context.Context, req *connect.Request[v1.ListWorldsRequest]) (*connect.Response[v1.ListWorldsResponse], error)
- func (a *ConnectWorldsServiceAdapter) UpdateWorld(ctx context.Context, req *connect.Request[v1.UpdateWorldRequest]) (*connect.Response[v1.UpdateWorldResponse], error)
- type CrossingType
- type FixSimulatorPage
- type ForbiddenPage
- type ForgotPasswordPage
- type GameCreatorPage
- type GameDetailPage
- type GameListView
- type GameListingPage
- type GameViewerPage
- func (p *GameViewerPage) GetTerrainDataJSON() string
- func (p *GameViewerPage) GetTerrainUnitPropertiesJSON() string
- func (p *GameViewerPage) GetUnitDataJSON() string
- func (p *GameViewerPage) GetUnitUnitPropertiesJSON() string
- func (p *GameViewerPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
- type GamesGroup
- type GenericPage
- type Header
- type HeaderMenuItem
- type HomePage
- type IndexerAppServer
- type LilBattleApp
- func (n *LilBattleApp) EnsureAuthUser(authtype string, provider string, token *oauth2.Token, userInfo map[string]any) (accounts.User, error)
- func (n *LilBattleApp) GetUserByID(userId string) (accounts.User, error)
- func (a *LilBattleApp) Handler() http.Handler
- func (n *LilBattleApp) ValidateUsernamePassword(username string, password string) (accounts.User, error)
- type LoginPage
- type NotFoundPage
- type PrivacyPolicy
- type ProfilePage
- type RegisterPage
- type ResendEmailSender
- type ResetPasswordPage
- type RootViewsHandler
- type RulesGroup
- type SecurityHeadersMiddleware
- type SelectWorldPage
- type SitemapIndex
- type SitemapIndexEntry
- type SitemapURL
- type StartGamePage
- type TBButton
- type TermsOfService
- type TerrainData
- type TerrainType
- type TerrainType2
- type ThemeManager
- func (tm *ThemeManager) ClearCache()
- func (tm *ThemeManager) GetTerrainIconURL(terrainID int32, useTheme bool, themeName string) string
- func (tm *ThemeManager) GetTerrainName(terrainID int32, defaultName string, useTheme bool, themeName string) string
- func (tm *ThemeManager) GetUnitIconURL(unitID int32, useTheme bool, themeName string) string
- func (tm *ThemeManager) GetUnitName(unitID int32, defaultName string, useTheme bool, themeName string) string
- func (tm *ThemeManager) LoadThemeMapping(themeName string) (*ThemeMapping, error)
- type ThemeMapping
- type ThemeMappingEntry
- type TwitterOAuth2
- type TwitterUserResponse
- type URLSet
- type UnitType
- type UsersHandler
- type WebAppServer
- type WorldCreatePage
- type WorldEditorPage
- type WorldListView
- type WorldListingPage
- type WorldViewerPage
- type WorldsGroup
Constants ¶
const ( // DevLoginParam is the query parameter the middleware inspects when the // gate is on. Visiting any URL with this param sets the session subject // to the param's value, with no password or OAuth round-trip. DevLoginParam = "dev_user" // DevLoginEnvVar is the env var that gates the middleware. Anything // other than "true" disables fake login entirely — the middleware // short-circuits on the env check and passes the request through // unchanged. Default state is OFF; production deploys must keep it // that way. DevLoginEnvVar = "ENABLE_DEV_FAKE_LOGIN" )
const DIST_FOLDER = "./web/dist"
You may have a builder/bundler creating an output folder. Set that path here. It can be absolute or relative to where the executable will be running from
const STATIC_FOLDER = "./web/static"
const ServeGzippedResources = true
const TEMPLATES_FOLDER = "./web/templates"
Variables ¶
var AllowedUnitIDs = []int32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 37, 38, 39, 40, 41, 44}
Functions ¶
func DevLoginEnabled ¶
func DevLoginEnabled() bool
DevLoginEnabled reports whether the gate env var is currently set to "true". Read at request time, not at startup, so changing the env in dev (e.g. via `make devloop ENABLE_DEV_FAKE_LOGIN=true`) takes effect on the next request without restarting tests.
func GenerateRandomNickname ¶
func GenerateRandomNickname() string
GenerateRandomNickname creates a fun random nickname like "HappyPanda" or "SwiftFalcon"
func GenerateRandomNicknameWithSpace ¶
func GenerateRandomNicknameWithSpace() string
GenerateRandomNicknameWithSpace creates a nickname with space like "Happy Panda"
func GrpcAuthContext ¶
GrpcAuthContext creates a gRPC context with user authentication metadata. Use this when calling gRPC services from page handlers to pass the user ID.
func HandleGRPCError ¶
func HandleGRPCError(err error, w http.ResponseWriter, r *http.Request, app *goal.App[*LilBattleApp]) (error, bool)
HandleGRPCError checks if err is a gRPC error and handles it appropriately. For Unauthenticated errors, it redirects to /login with a callback URL. For NotFound errors, it renders the 404 page. For PermissionDenied errors, it renders the 403 page. Returns (error, finished) - if finished is true, the response has been written.
func IsValidNickname ¶
IsValidNickname checks if a nickname is valid (not empty, reasonable length)
func ThemeFromRequest ¶
func WrapDevLogin ¶
WrapDevLogin returns a middleware that intercepts ?dev_user=<handle> on any path and calls oneauth.SetLoggedInSubject with that handle. The handle becomes the session subject, the loggedInSubject cookie value, and the JWT cookie's `sub` claim — identical to what a real login would produce, just without the password / OAuth round-trip.
Callers decide whether to install this middleware based on DevLoginEnabled() at handler-build time, so production handlers never even hold a reference to it. Wire it via:
withDevLogin := routes
if server.DevLoginEnabled() { withDevLogin = WrapDevLogin(oneauth)(routes) }
Session.LoadAndSave(withDevLogin)
The middleware MUST run inside Session.LoadAndSave so the session writes performed by SetLoggedInSubject reach the SCS store.
Every fake-login event emits an slog.Warn line so a production deploy that somehow installed this middleware cannot go unnoticed during log review.
Types ¶
type ApiHandler ¶
type ApiHandler struct {
AuthMiddleware *httpauth.Middleware
ClientMgr *services.ClientMgr
// Here we can have to ways of accessing the services - either via clients or by actual service instead if you are not
// running the services on a dedicated port
DisableIndexer bool
DisableGamesService bool
DisableWorldsService bool
// contains filtered or unexported fields
}
func (*ApiHandler) Handler ¶
func (n *ApiHandler) Handler() http.Handler
func (*ApiHandler) Init ¶
func (a *ApiHandler) Init() error
type AttackSimulatorPage ¶
type AttackSimulatorPage struct {
BasePage
Header Header
// URL parameters for pre-populating form
AttackerUnit string
AttackerTerrain string
AttackerHealth string
DefenderUnit string
DefenderTerrain string
DefenderHealth string
WoundBonus string
NumSimulations string
// Terrain and unit data for dropdowns
AllTerrains []TerrainType
AllUnits []UnitType
Theme string
}
func (*AttackSimulatorPage) Load ¶
func (p *AttackSimulatorPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type BasePage ¶
func (*BasePage) SetCanonicalFromRequest ¶
SetCanonicalFromRequest sets the canonical URL from the app's BaseUrl and request path. Call this in page Load() methods to enable SEO canonical tags.
type ConnectGameSyncServiceAdapter ¶
type ConnectGameSyncServiceAdapter struct {
// contains filtered or unexported fields
}
ConnectGameSyncServiceAdapter adapts the gRPC GameSyncService to Connect's interface This enables multiplayer sync via HTTP/Connect for frontend clients
func NewConnectGameSyncServiceAdapter ¶
func NewConnectGameSyncServiceAdapter(client v1s.GameSyncServiceClient) *ConnectGameSyncServiceAdapter
func (*ConnectGameSyncServiceAdapter) Broadcast ¶
func (a *ConnectGameSyncServiceAdapter) Broadcast(ctx context.Context, req *connect.Request[v1.BroadcastRequest]) (*connect.Response[v1.BroadcastResponse], error)
func (*ConnectGameSyncServiceAdapter) Subscribe ¶
func (a *ConnectGameSyncServiceAdapter) Subscribe(ctx context.Context, req *connect.Request[v1.SubscribeRequest], stream *connect.ServerStream[v1.GameUpdate]) error
type ConnectGamesServiceAdapter ¶
type ConnectGamesServiceAdapter struct {
// contains filtered or unexported fields
}
ConnectGamesServiceAdapter adapts the gRPC GamesService to Connect's interface
func NewConnectGamesServiceAdapter ¶
func NewConnectGamesServiceAdapter(client v1s.GamesServiceClient) *ConnectGamesServiceAdapter
func (*ConnectGamesServiceAdapter) CreateGame ¶
func (a *ConnectGamesServiceAdapter) CreateGame(ctx context.Context, req *connect.Request[v1.CreateGameRequest]) (*connect.Response[v1.CreateGameResponse], error)
func (*ConnectGamesServiceAdapter) DeleteGame ¶
func (a *ConnectGamesServiceAdapter) DeleteGame(ctx context.Context, req *connect.Request[v1.DeleteGameRequest]) (*connect.Response[v1.DeleteGameResponse], error)
func (*ConnectGamesServiceAdapter) GetGame ¶
func (a *ConnectGamesServiceAdapter) GetGame(ctx context.Context, req *connect.Request[v1.GetGameRequest]) (*connect.Response[v1.GetGameResponse], error)
func (*ConnectGamesServiceAdapter) GetGameState ¶
func (a *ConnectGamesServiceAdapter) GetGameState(ctx context.Context, req *connect.Request[v1.GetGameStateRequest]) (*connect.Response[v1.GetGameStateResponse], error)
func (*ConnectGamesServiceAdapter) GetGames ¶
func (a *ConnectGamesServiceAdapter) GetGames(ctx context.Context, req *connect.Request[v1.GetGamesRequest]) (*connect.Response[v1.GetGamesResponse], error)
func (*ConnectGamesServiceAdapter) GetOptionsAt ¶
func (a *ConnectGamesServiceAdapter) GetOptionsAt(ctx context.Context, req *connect.Request[v1.GetOptionsAtRequest]) (*connect.Response[v1.GetOptionsAtResponse], error)
func (*ConnectGamesServiceAdapter) JoinGame ¶
func (a *ConnectGamesServiceAdapter) JoinGame(ctx context.Context, req *connect.Request[v1.JoinGameRequest]) (*connect.Response[v1.JoinGameResponse], error)
func (*ConnectGamesServiceAdapter) ListGames ¶
func (a *ConnectGamesServiceAdapter) ListGames(ctx context.Context, req *connect.Request[v1.ListGamesRequest]) (*connect.Response[v1.ListGamesResponse], error)
func (*ConnectGamesServiceAdapter) ListMoves ¶
func (a *ConnectGamesServiceAdapter) ListMoves(ctx context.Context, req *connect.Request[v1.ListMovesRequest]) (*connect.Response[v1.ListMovesResponse], error)
func (*ConnectGamesServiceAdapter) ProcessMoves ¶
func (a *ConnectGamesServiceAdapter) ProcessMoves(ctx context.Context, req *connect.Request[v1.ProcessMovesRequest]) (*connect.Response[v1.ProcessMovesResponse], error)
func (*ConnectGamesServiceAdapter) SimulateAttack ¶
func (a *ConnectGamesServiceAdapter) SimulateAttack(ctx context.Context, req *connect.Request[v1.SimulateAttackRequest]) (*connect.Response[v1.SimulateAttackResponse], error)
func (*ConnectGamesServiceAdapter) SimulateFix ¶
func (a *ConnectGamesServiceAdapter) SimulateFix(ctx context.Context, req *connect.Request[v1.SimulateFixRequest]) (*connect.Response[v1.SimulateFixResponse], error)
func (*ConnectGamesServiceAdapter) UpdateGame ¶
func (a *ConnectGamesServiceAdapter) UpdateGame(ctx context.Context, req *connect.Request[v1.UpdateGameRequest]) (*connect.Response[v1.UpdateGameResponse], error)
type ConnectIndexerServiceAdapter ¶
type ConnectIndexerServiceAdapter struct {
// contains filtered or unexported fields
}
ConnectIndexerServiceAdapter adapts the gRPC IndexerService to Connect's interface
func NewConnectIndexerServiceAdapter ¶
func NewConnectIndexerServiceAdapter(client v1s.IndexerServiceClient) *ConnectIndexerServiceAdapter
func (*ConnectIndexerServiceAdapter) EnsureIndexState ¶
func (a *ConnectIndexerServiceAdapter) EnsureIndexState(ctx context.Context, req *connect.Request[v1.EnsureIndexStateRequest]) (*connect.Response[v1.EnsureIndexStateResponse], error)
type ConnectWorldsServiceAdapter ¶
type ConnectWorldsServiceAdapter struct {
// contains filtered or unexported fields
}
ConnectWorldsServiceAdapter adapts the gRPC WorldsService to Connect's interface
func NewConnectWorldsServiceAdapter ¶
func NewConnectWorldsServiceAdapter(client v1s.WorldsServiceClient) *ConnectWorldsServiceAdapter
func (*ConnectWorldsServiceAdapter) CreateWorld ¶
func (a *ConnectWorldsServiceAdapter) CreateWorld(ctx context.Context, req *connect.Request[v1.CreateWorldRequest]) (*connect.Response[v1.CreateWorldResponse], error)
func (*ConnectWorldsServiceAdapter) DeleteWorld ¶
func (a *ConnectWorldsServiceAdapter) DeleteWorld(ctx context.Context, req *connect.Request[v1.DeleteWorldRequest]) (*connect.Response[v1.DeleteWorldResponse], error)
func (*ConnectWorldsServiceAdapter) GetWorld ¶
func (a *ConnectWorldsServiceAdapter) GetWorld(ctx context.Context, req *connect.Request[v1.GetWorldRequest]) (*connect.Response[v1.GetWorldResponse], error)
func (*ConnectWorldsServiceAdapter) GetWorlds ¶
func (a *ConnectWorldsServiceAdapter) GetWorlds(ctx context.Context, req *connect.Request[v1.GetWorldsRequest]) (*connect.Response[v1.GetWorldsResponse], error)
func (*ConnectWorldsServiceAdapter) ListWorlds ¶
func (a *ConnectWorldsServiceAdapter) ListWorlds(ctx context.Context, req *connect.Request[v1.ListWorldsRequest]) (*connect.Response[v1.ListWorldsResponse], error)
func (*ConnectWorldsServiceAdapter) UpdateWorld ¶
func (a *ConnectWorldsServiceAdapter) UpdateWorld(ctx context.Context, req *connect.Request[v1.UpdateWorldRequest]) (*connect.Response[v1.UpdateWorldResponse], error)
type CrossingType ¶
type CrossingType struct {
ID string `json:"id"` // "road" or "bridge"
Name string `json:"name"` // Display name
IconDataURL string `json:"iconDataURL"`
}
CrossingType represents a road or bridge crossing
type FixSimulatorPage ¶
type FixSimulatorPage struct {
BasePage
Header Header
// URL parameters for pre-populating form
FixingUnit string
FixingUnitHealth string
InjuredUnit string
NumSimulations string
// Units data for dropdowns
// FixingUnits only includes units with fix_value > 0
FixingUnits []UnitType
// AllUnits includes all units (for injured unit dropdown)
AllUnits []UnitType
Theme string
}
func (*FixSimulatorPage) Load ¶
func (p *FixSimulatorPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type ForbiddenPage ¶
ForbiddenPage is the view data for 403 pages
func (*ForbiddenPage) Load ¶
func (p *ForbiddenPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (error, bool)
type ForgotPasswordPage ¶
ForgotPasswordPage renders the forgot password form.
func (*ForgotPasswordPage) Load ¶
func (p *ForgotPasswordPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type GameCreatorPage ¶
type GameCreatorPage struct {
BasePage
Header Header
Game *protos.Game
Errors map[string]string
AllowCustomId bool
}
func (*GameCreatorPage) Load ¶
func (v *GameCreatorPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
func (*GameCreatorPage) SetupDefaults ¶
func (v *GameCreatorPage) SetupDefaults()
type GameDetailPage ¶
func (*GameDetailPage) Load ¶
func (p *GameDetailPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type GameListView ¶
type GameListView struct {
goal.WithPagination
goal.WithFiltering
Games []*protos.Game
}
func (*GameListView) Load ¶
func (p *GameListView) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type GameListingPage ¶
type GameListingPage struct {
BasePage
Header Header
GameListView GameListView
ListingData *goal.EntityListingData[*protos.Game]
}
func (*GameListingPage) Load ¶
func (m *GameListingPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type GameViewerPage ¶
type GameViewerPage struct {
BasePage
Header Header
GameId string
WorldId string
Game *protos.Game
GameState *protos.GameState
GameHistory *protos.GameMoveHistory
// Game creation parameters from URL
PlayerCount int
MaxTurns int
UnitRestrictions map[string]string // unitId -> restriction level
WasmExecJsPath string
WasmBundlePath string
// Viewer context for Join functionality
ViewerUserId string
}
func (*GameViewerPage) GetTerrainDataJSON ¶
func (p *GameViewerPage) GetTerrainDataJSON() string
GetTerrainDataJSON returns terrain data from rules engine as JSON string
func (*GameViewerPage) GetTerrainUnitPropertiesJSON ¶
func (p *GameViewerPage) GetTerrainUnitPropertiesJSON() string
GetTerrainUnitPropertiesJSON returns terrain-unit interaction properties as JSON string
func (*GameViewerPage) GetUnitDataJSON ¶
func (p *GameViewerPage) GetUnitDataJSON() string
GetUnitDataJSON returns unit data from rules engine as JSON string
func (*GameViewerPage) GetUnitUnitPropertiesJSON ¶
func (p *GameViewerPage) GetUnitUnitPropertiesJSON() string
GetUnitUnitPropertiesJSON returns unit-vs-unit combat properties as JSON string
func (*GameViewerPage) Load ¶
func (p *GameViewerPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type GamesGroup ¶
type GamesGroup struct {
// contains filtered or unexported fields
}
GamesGroup implements goal.PageGroup for /games routes.
func (*GamesGroup) RegisterRoutes ¶
func (g *GamesGroup) RegisterRoutes(app *goal.App[*LilBattleApp]) *http.ServeMux
RegisterRoutes registers all game-related routes using goal.Register.
type GenericPage ¶
func (*GenericPage) Load ¶
func (v *GenericPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type Header ¶
type Header struct {
AppName string
PageData any
HeaderLogo func() template.HTML
LogoTitle string
Styles map[string]any
Width string
HeaderStyleLink string
MenuStyleLink string
FixedHeader bool
ShowHomeButton bool
ShowComposeButton bool
ShowLoginButton bool
ShowLogoutButton bool
HomeButtonImage string
CenterMenuItems []HeaderMenuItem
SpecialMenuItems []HeaderMenuItem
RightMenuItems []HeaderMenuItem
HideCenterMenuItems bool
IsLoggedIn bool
LoggedInUserId string
Username string
DisplayName string // Shown in header: Nickname -> Name -> UserID
}
func (*Header) Load ¶
func (v *Header) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
func (*Header) SetupDefaults ¶
func (h *Header) SetupDefaults()
type HeaderMenuItem ¶
type HomePage ¶
type IndexerAppServer ¶
type IndexerAppServer struct {
goal.WebAppServer
}
type LilBattleApp ¶
type LilBattleApp struct {
// Auth
Auth *httpauth.OneAuth
AuthMiddleware *httpauth.Middleware
AuthService *goalservices.AuthService
UsernameStore accounts.UsernameStore // Username → UserID mapping for login alias
Session *scs.SessionManager
// Services
Api *ApiHandler
ClientMgr *services.ClientMgr
// Views (thin wrapper for page routing)
ViewsRoot *RootViewsHandler
// App config
HideGames bool
HideWorlds bool
// Ad config - all default to enabled, can be disabled per-placement
AdsEnabled bool // Master switch: LILBATTLE_ADS_ENABLED (default: true)
AdsHomeEnabled bool // Homepage mid-section: LILBATTLE_ADS_HOME (default: true)
AdsListingEnabled bool // Listing pages: LILBATTLE_ADS_LISTING (default: true)
AdNetworkId string // Google AdSense publisher ID: LILBATTLE_AD_NETWORK_ID
AdSlotId string // Google AdSense ad unit slot ID: LILBATTLE_AD_SLOT_ID
BaseUrl string
// contains filtered or unexported fields
}
LilBattleApp is the pure application context. It holds all app-specific state without knowing about goapplib. Views access this via app.Context in goal.App[*LilBattleApp].
func NewLilBattleApp ¶
func NewLilBattleApp(clientMgr *services.ClientMgr) (lilbattleApp *LilBattleApp, goalApp *goal.App[*LilBattleApp], err error)
NewLilBattleApp creates a new LilBattleApp and its associated goal.App. Returns the LilBattleApp and the goal.App wrapper.
func (*LilBattleApp) EnsureAuthUser ¶
func (*LilBattleApp) GetUserByID ¶
func (n *LilBattleApp) GetUserByID(userId string) (accounts.User, error)
func (*LilBattleApp) Handler ¶
func (a *LilBattleApp) Handler() http.Handler
Handler returns a configured HTTP handler with all routes.
func (*LilBattleApp) ValidateUsernamePassword ¶
type LoginPage ¶
type LoginPage struct {
goal.SampleLoginPage[*LilBattleApp]
Header Header
EnableTwitterLogin bool
}
LoginPage extends goapplib.SampleLoginPage with app-specific features.
type NotFoundPage ¶
NotFoundPage is the view data for 404 pages
func (*NotFoundPage) Load ¶
func (p *NotFoundPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (error, bool)
type PrivacyPolicy ¶
func (*PrivacyPolicy) Load ¶
func (p *PrivacyPolicy) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type ProfilePage ¶
type ProfilePage struct {
goal.SampleProfilePage[*LilBattleApp]
Header Header
// App-specific user information
User accounts.User
// Username fields - for login alias (stored in UsernameStore)
UsernameNeeded bool // True if user hasn't set a username yet
// Nickname fields (Nickname is in SampleProfilePage base)
NicknameNeeded bool // True if user needs to set their nickname
SuggestedNickname string // Random suggestion for nickname
// Password availability
HasLocalAuth bool // True if user has an email identity (can potentially have password)
HasPassword bool // True if user has a local channel with password set
}
ProfilePage extends goapplib.SampleProfilePage with app-specific features.
func (*ProfilePage) Load ¶
func (p *ProfilePage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type RegisterPage ¶
type RegisterPage struct {
goal.SampleRegisterPage[*LilBattleApp]
Header Header
}
RegisterPage extends goapplib.SampleRegisterPage with app-specific features.
func (*RegisterPage) Load ¶
func (p *RegisterPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type ResendEmailSender ¶
type ResendEmailSender struct {
// contains filtered or unexported fields
}
ResendEmailSender sends emails via the Resend API
func NewResendEmailSender ¶
func NewResendEmailSender(apiKey, fromAddr string) *ResendEmailSender
func (*ResendEmailSender) SendPasswordResetEmail ¶
func (r *ResendEmailSender) SendPasswordResetEmail(to string, resetLink string) error
func (*ResendEmailSender) SendVerificationEmail ¶
func (r *ResendEmailSender) SendVerificationEmail(to string, verificationLink string) error
type ResetPasswordPage ¶
type ResetPasswordPage struct {
BasePage
CustomHeader bool
Token string
InvalidToken bool
Success bool
Error string
}
ResetPasswordPage renders the password reset form.
func (*ResetPasswordPage) Load ¶
func (p *ResetPasswordPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type RootViewsHandler ¶
type RootViewsHandler struct {
LilBattleApp *LilBattleApp // Pure app context
GoalApp *goal.App[*LilBattleApp] // goal.App wrapper for templates/rendering
// contains filtered or unexported fields
}
RootViewsHandler is a thin wrapper for page routing. It references both the LilBattleApp (pure context) and goal.App (templates/rendering).
func NewRootViewsHandler ¶
func NewRootViewsHandler(lilbattleApp *LilBattleApp, goalApp *goal.App[*LilBattleApp]) *RootViewsHandler
NewRootViewsHandler creates a new RootViewsHandler.
func (*RootViewsHandler) HandleError ¶
func (b *RootViewsHandler) HandleError(err error, w io.Writer)
func (*RootViewsHandler) Handler ¶
func (n *RootViewsHandler) Handler() http.Handler
func (*RootViewsHandler) RegisterSEORoutes ¶
func (n *RootViewsHandler) RegisterSEORoutes()
RegisterSEORoutes registers robots.txt and sitemap handlers
type RulesGroup ¶
type RulesGroup struct{}
RulesGroup implements goal.PageGroup for /rules routes.
func (*RulesGroup) RegisterRoutes ¶
func (g *RulesGroup) RegisterRoutes(app *goal.App[*LilBattleApp]) *http.ServeMux
RegisterRoutes registers all rules-related routes using goal.Register.
type SecurityHeadersMiddleware ¶
type SecurityHeadersMiddleware struct {
// IsDevelopment disables some strict policies for local development
IsDevelopment bool
}
SecurityHeadersMiddleware adds security headers to all responses. These headers help protect against common web vulnerabilities.
func NewSecurityHeadersMiddleware ¶
func NewSecurityHeadersMiddleware() *SecurityHeadersMiddleware
NewSecurityHeadersMiddleware creates a new security headers middleware. Set isDevelopment=true to relax some policies for local development.
type SelectWorldPage ¶
type SelectWorldPage struct {
BasePage
Header Header
WorldListView WorldListView
}
func (*SelectWorldPage) Load ¶
func (m *SelectWorldPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type SitemapIndex ¶
type SitemapIndex struct {
XMLName xml.Name `xml:"sitemapindex"`
XMLNS string `xml:"xmlns,attr"`
Sitemaps []SitemapIndexEntry `xml:"sitemap"`
}
type SitemapIndexEntry ¶
type SitemapURL ¶
type StartGamePage ¶
type StartGamePage struct {
BasePage
Header Header
World *protos.World
WorldData *protos.WorldData
WorldId string
UnitTypes []UnitType
GameConfiguration *protos.GameConfiguration
// Form fields (can be pre-filled or from error retry)
GameId string
GameName string
ErrorMessage string // Error message for ID conflicts etc.
}
func (*StartGamePage) Load ¶
func (p *StartGamePage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type TermsOfService ¶
func (*TermsOfService) Load ¶
func (t *TermsOfService) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type TerrainData ¶
type TerrainData struct {
ID int32 // `json:"id"`
Name string // `json:"name"`
BaseMoveCost float64 // `json:"baseMoveCost"` // Base movement cost for this terrain
DefenseBonus float64 // `json:"defenseBonus"`
Type TerrainType2 // `json:"type"` // Nature or Player terrain
Properties []string // `json:"properties,omitempty"`
}
TerrainData represents terrain type information
type TerrainType ¶
type TerrainType struct {
TerrainData
IconDataURL string `json:"iconDataURL"`
HasPlayerColors bool `json:"hasPlayerColors"`
}
type TerrainType2 ¶
type TerrainType2 int32
TerrainType represents whether terrain is nature or player-controllable
const ( TerrainNature TerrainType2 = iota // Natural terrain (grass, mountains, water, etc.) TerrainPlayer // Player-controllable structures (bases, cities, etc.) )
type ThemeManager ¶
type ThemeManager struct {
// contains filtered or unexported fields
}
ThemeManager handles theme asset resolution and caching
func GetThemeManager ¶
func GetThemeManager() *ThemeManager
GetThemeManager returns the singleton theme manager
func (*ThemeManager) ClearCache ¶
func (tm *ThemeManager) ClearCache()
ClearCache clears the theme mapping cache
func (*ThemeManager) GetTerrainIconURL ¶
func (tm *ThemeManager) GetTerrainIconURL(terrainID int32, useTheme bool, themeName string) string
GetTerrainIconURL returns the icon URL for a terrain ID
func (*ThemeManager) GetTerrainName ¶
func (tm *ThemeManager) GetTerrainName(terrainID int32, defaultName string, useTheme bool, themeName string) string
GetTerrainName returns the themed name for a terrain, or the default name if not themed
func (*ThemeManager) GetUnitIconURL ¶
func (tm *ThemeManager) GetUnitIconURL(unitID int32, useTheme bool, themeName string) string
GetUnitIconURL returns the icon URL for a unit ID
func (*ThemeManager) GetUnitName ¶
func (tm *ThemeManager) GetUnitName(unitID int32, defaultName string, useTheme bool, themeName string) string
GetUnitName returns the themed name for a unit, or the default name if not themed
func (*ThemeManager) LoadThemeMapping ¶
func (tm *ThemeManager) LoadThemeMapping(themeName string) (*ThemeMapping, error)
LoadThemeMapping loads and caches a theme's mapping.json
type ThemeMapping ¶
type ThemeMapping struct {
Units map[string]ThemeMappingEntry `json:"units"`
Terrains map[string]ThemeMappingEntry `json:"terrains"`
}
ThemeMapping represents the mapping.json structure
type ThemeMappingEntry ¶
type TwitterOAuth2 ¶
type TwitterOAuth2 struct {
ClientId string
ClientSecret string
CallbackURL string
HandleUser accounts.HandleUserFunc
AuthFailureUrl string
// contains filtered or unexported fields
}
TwitterOAuth2 implements OAuth 2.0 with PKCE for Twitter/X authentication.
func NewTwitterOAuth2 ¶
func NewTwitterOAuth2(clientId, clientSecret, callbackUrl string, handleUser accounts.HandleUserFunc) *TwitterOAuth2
NewTwitterOAuth2 creates a new Twitter OAuth2 handler. Empty parameters will be read from environment variables.
func (*TwitterOAuth2) Handler ¶
func (t *TwitterOAuth2) Handler() http.Handler
type TwitterUserResponse ¶
type TwitterUserResponse struct {
Data struct {
ID string `json:"id"`
Name string `json:"name"`
Username string `json:"username"`
ProfileImageURL string `json:"profile_image_url"`
} `json:"data"`
}
TwitterUserResponse represents the Twitter API v2 user response.
type URLSet ¶
type URLSet struct {
XMLName xml.Name `xml:"urlset"`
XMLNS string `xml:"xmlns,attr"`
URLs []SitemapURL `xml:"url"`
}
type UnitType ¶
type UnitType struct {
*protos.UnitDefinition
IconDataURL string `json:"iconDataURL"`
}
type UsersHandler ¶
type UsersHandler struct {
App *LilBattleApp
}
UsersHandler handles user showcase pages
func NewUsersHandler ¶
func NewUsersHandler(app *LilBattleApp) *UsersHandler
NewUsersHandler creates a new users handler
func (*UsersHandler) Handler ¶
func (h *UsersHandler) Handler() http.Handler
Handler returns an HTTP handler for users routes
type WebAppServer ¶
type WebAppServer struct {
goal.WebAppServer
}
type WorldCreatePage ¶
type WorldCreatePage struct {
BasePage
Header Header
// Form fields (pre-filled on conflict retry)
SuggestedId string
ErrorMessage string
WorldName string
}
func (*WorldCreatePage) Load ¶
func (p *WorldCreatePage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type WorldEditorPage ¶
type WorldEditorPage struct {
BasePage
Header Header
IsOwner bool
WorldId string
World *protos.World
WorldData *protos.WorldData
Errors map[string]string
TBButtons []*TBButton
AllowCustomId bool
NatureTerrains []TerrainType
CityTerrains []TerrainType
UnitTypes []UnitType
Crossings []CrossingType // Road and Bridge crossings
PlayerCount int
Theme string // Theme name from query parameter (default, fantasy, modern)
}
func (*WorldEditorPage) Load ¶
func (v *WorldEditorPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
func (*WorldEditorPage) SetupDefaults ¶
func (v *WorldEditorPage) SetupDefaults()
type WorldListView ¶
type WorldListView struct {
goal.WithPagination
goal.WithFiltering
Worlds []*protos.World
ActionMode string // "manage" or "select"
}
func (*WorldListView) Load ¶
func (p *WorldListView) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type WorldListingPage ¶
type WorldListingPage struct {
BasePage
Header Header
WorldListView WorldListView
ListingData *goal.EntityListingData[*protos.World]
}
func (*WorldListingPage) Load ¶
func (m *WorldListingPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type WorldViewerPage ¶
type WorldViewerPage struct {
BasePage
Header Header
World *protos.World
WorldData *protos.WorldData
WorldId string
}
func (*WorldViewerPage) Load ¶
func (p *WorldViewerPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type WorldsGroup ¶
type WorldsGroup struct {
// contains filtered or unexported fields
}
WorldsGroup implements goal.PageGroup for /worlds routes.
func (*WorldsGroup) RegisterRoutes ¶
func (g *WorldsGroup) RegisterRoutes(app *goal.App[*LilBattleApp]) *http.ServeMux
RegisterRoutes registers all world-related routes using goal.Register.
Source Files
¶
- AttackSimulatorPage.go
- FixSimulatorPage.go
- GameCreatorPage.go
- GameDetailPage.go
- GameListView.go
- GameListingPage.go
- GameViewerPage.go
- GamesGroup.go
- Header.go
- HomePage.go
- LoginPage.go
- ProfilePage.go
- RulesGroup.go
- SelectWorldPage.go
- StartGamePage.go
- Themes.go
- WorldCreatePage.go
- WorldEditorPage.go
- WorldListView.go
- WorldListingPage.go
- WorldViewerPage.go
- WorldsGroup.go
- api.go
- auth.go
- connect.go
- dev_login.go
- password_pages.go
- randoms.go
- resend_email.go
- screenshot_live_handler.go
- securityheaders.go
- seo.go
- twitter_oauth2.go
- user.go
- users_handler.go
- utils.go
- views.go
- webapp.go
- webserver.go