aboutsummaryrefslogtreecommitdiff
path: root/cmd/mobius-hotline-server/main.go
AgeCommit message (Collapse)Author
2026-07-08Add --file-store flag to select the file library backendJeff Halter
Wire an os|memory selector mirroring the existing Redis-vs-file backend selection. This marks the seam where a future object-store backend (e.g. Cloudflare R2 / S3) slots in via hotline.WithFileStore.
2026-06-25Introduce PresenceTracker interface for online-user trackingJeff Halter
Replace the leaky *redis.Client field on Server with a PresenceTracker interface that receives connect/rename/disconnect lifecycle events. This removes Redis-specific set encoding from hotline/server.go and the session handlers, and drops the redis dependency from the hotline package. The Redis implementation moves to mobius.RedisPresenceTracker, which owns the legacy "login::ip"/"login:nickname:ip" set encoding so existing deployments keep working. The API server reads online users through a new OnlineLister interface and falls back to the in-memory ClientMgr when no presence tracker is configured. Startup clearing of stale online state now happens unconditionally when Redis is configured, not only when the API server is enabled.
2026-06-12Add Reloader interface to remove type assertions from reload pathJeff Halter
main.go's reloadFunc reached through the server's interface fields with concrete type assertions (srv.MessageBoard.(*mobius.FlatNews), etc.) to trigger SIGHUP/API reloads, leaking storage implementation details past the manager interfaces. Storage backends now implement a one-method Reloader interface, with compile-time assertions for FlatNews, BanFile, ThreadedNewsYAML, and Agreement. BanFile.Load and ThreadedNewsYAML.Load are renamed Reload for a uniform method set, matching FlatNews's existing convention of using Reload for the initial load as well. main.go registers each backend in a named reloader list as it is constructed, and reloadFunc iterates the list. The banner reload is a ReloaderFunc that also performs the initial load, and the Redis-backed ban list simply registers no reloader, replacing the old type-switch special case.
2026-06-12Fix data races on ClientConn state, banner reload, and rate limiter growthJeff Halter
ClientConn's mutable session state (Flags, UserName, Icon, IdleTime, AutoReply) was guarded inconsistently: two mutexes (FlagsMU and mu) covered some paths while others mutated or read the fields with no locking at all, including HandleSetClientUserInfo, HandleUpdateUser (which writes other clients' admin flag), the login flow, the HTTP API handlers, and the keepalive loop. Consolidate on a single mutex with accessor methods (SetFlag/IsFlagSet/FlagBytes, SetUserName/GetUserName, and so on) used by all production code; direct field access remains for test construction. The idle/away logic moves into incrementIdleTime and clearIdleAndAway helpers that report whether a notification is needed, so SendAll is no longer called while holding the lock. HandleRejectChatInvite also no longer appends to the username slice, which could write past its length into the backing buffer. The server banner is now behind Banner/SetBanner with an RWMutex: the SIGHUP reload previously reassigned the field while banner download goroutines read it, and nilled it when the file read failed. Reload now keeps the previous banner on failure. Per-IP rate limiter entries now record a last-seen time, and the keepalive ticker evicts entries idle for over seven days, so the map no longer grows unboundedly with each unique client IP.
2026-06-12Shut down gracefully instead of exiting from library codeJeff Halter
ListenAndServe previously started each listener in a goroutine that called log.Fatal on any error, which skipped deferred cleanup and made errors unobservable to callers, and Server.Shutdown terminated the process with os.Exit. Context cancellation was also ineffective: Serve only checked ctx between Accept calls, which block indefinitely. ListenAndServe now binds its listeners up front and returns bind errors, closes every listener when the context is canceled so accept loops unblock and return, and reports the first serve loop error to the caller. Shutdown closes a lazily-initialized channel that cancels ListenAndServe's context, so the shutdown API works race-free even though it starts before ListenAndServe. "Server shutting down" is logged once by ListenAndServe rather than per accept loop, which produced duplicate or missing lines depending on scheduling. main.go now treats context.Canceled as a clean exit, logs other server errors and exits nonzero, and runs deferred cleanup (e.g. Bonjour shutdown) on the way out.
2026-06-01Improve startup logging and logging consistencyJeff Halter
Startup log: - Add interface, port, and fileTransferPort fields to the "Hotline server started" line so operators can see what the server bound to. - Resolve an empty -interface flag to 0.0.0.0 for display. Levels: - Demote the two Redis startup messages (ban management, cleared online users) from Info to Debug. Consistency: - Standardize the error field key to "err" (was "Err" in a few account handlers) and lowercase "Account" -> "account". - Standardize the remote-address key to "remoteAddr" (was "RemoteAddr"). - Replace fmt.Sprintf in the tracker-registration message and string concatenation in the config-dir-init and ban-disconnect messages with structured fields; use the standard "err" key. - Give the two bare rLogger.Error(err.Error()) file-transfer calls a descriptive message and an "err" field. logger.go: - Only attach the rotating lumberjack file writer when --log-file is set. An empty Filename made lumberjack write to a temp file by default.
2026-03-14Refactor ban management behind BanMgr interfaceJeff Halter
Extract ban logic into a BanMgr interface with two implementations: - BanFile: file-based YAML storage with support for IP, username, and nickname bans (backwards-compatible with legacy format) - RedisBanMgr: Redis-backed implementation with permanent and temporary ban support, using fail-safe deny-on-error behavior This replaces scattered Redis calls in API handlers, transaction handlers, and server connection logic with unified interface calls, removing the Redis dependency from the API server constructor and enabling ban functionality for both file-only and Redis deployments.
2025-11-29Ran goimports -w . to tidy upJeff Halter
2025-11-22Add optional TLS support for encrypted client connectionsJeff Halter
- Add TLSConfig and TLSPort fields to Server struct - Add WithTLS option function for configuration - Add ServeWithTLS and ServeFileTransfersWithTLS methods - Update ListenAndServe to start TLS listeners when configured - Add -tls-cert, -tls-key, -tls-port command-line flags - Fix data race in rateLimiters map access with mutex - Add TLS documentation with certificate generation instructions
2025-07-04Fix file handle close warnings by ignoring return valuesJeff Halter
Updated all file close operations to use anonymous functions that ignore return values to satisfy golangci-lint errcheck warnings.
2025-06-30Improve error handling consistency in main.goJeff Halter
- Fix incorrect error message for banner loading - Convert all error logging to structured format - Remove server shutdown during config reload failures
2025-06-26Replace filepath.Join with path.Join for Windows compatibilityJeff Halter
Replace all instances of filepath.Join with path.Join across the codebase to improve Windows compatibility following the guidance from https://github.com/golang/go/issues/44305. Key changes: - Replaced filepath.Join with path.Join in 14 files - Updated import statements appropriately - Resolved variable shadowing issues where function parameters named 'path' were conflicting with the path package - Maintained filepath imports where needed for OS-specific functions like filepath.Walk, filepath.IsAbs, filepath.Dir, and filepath.Base All tests pass, confirming the changes maintain functionality while improving cross-platform compatibility.
2025-06-25Refactor copyDir and findConfigPath functions in main.goJeff Halter
- Refactor copyDir: Add proper error handling, resource cleanup with defer, true recursion, better permissions (0755), and separation of concerns - Refactor configSearchPaths -> findConfigPath: Add directory validation, better naming, and clearer documentation - Add comprehensive test suite for all functions with 100% test coverage - Remove panic in copyDir, replace with proper error propagation - Fix resource leaks by using defer for file cleanup
2025-05-22Update main.goTheo Knez
2024-07-27Fix missing version in Docker and Makefile buildJeff Halter
2024-07-26Make Bonjour optional and disabled by defaultJeff Halter
Bonjour doesn't seem happy inside Docker, so I'm making it optional and off by default.
2024-07-26Register server address on local network with BonjourJeff Halter
2024-07-21Clean up loggingJeff Halter
2024-07-18Add initial HTTP API endpointsJeff Halter
2024-07-17Extensive refactor, quality of life enhancementsJeff Halter
* Added ability to reload config, agreement, news, and user accounts without restarting the server by sending SIGHUP to the running process * Added ability to use modern unix or windows line breaks in Agreement.txt and MessageBoard.txt instead of classic MacOS `\r` breaks. * Extensive refactor towards swappable backends for the active server state * Extensive refactored towards making the hotline package generic and re-usable for alternate server implemenations * Fix bug where users whose accounts have been deleted would not be disconnected
2024-07-09Extensive refactor and clean upJeff Halter
2024-06-26Fix Windows compatibility for -init flagJeff Halter
2024-06-24Refactoring, cleanup, test backfillingJeff Halter
2024-06-17Clean up various linter warningsJeff Halter
2024-06-15Replace hardcoded version with ldflag usageJeff Halter
2024-06-15Refactoring and cleanupJeff Halter
* Split CLI client into separate project * Convert more functions to follow common Golang idioms e.g io.Reader, io.Writer * Use ldflags for versioning * Misc cleanup and simplification
2024-06-10Replace zap logger with slogJeff Halter
2024-06-01If no predefined default path for server config, look in the current dirCharlotte Koch
2024-03-28Add cmdline flag to specify network interfaceJeff Halter
2023-04-19Ran 'golangci-lint run -E gocritic,whitespace --fix' 🤞Jeff Halter
2023-04-19Replace deprecated rand.Seed usageJeff Halter
2022-11-03Add optional logging to fileJeff Halter
2022-07-04Add basic stat countersJeff Halter
2022-06-20Convert hardcoded path separators to filepath.JoinJeff Halter
2022-06-20Add initial support for resource and info forksJeff Halter
2022-06-19Mobius 38 - improve config dir flag.Ben Abernathy
2022-06-12Simplify the behavior of init with an existing configJeff Halter
Old behavior: if config dir found, exit with message New behavior: if config dir found, log a message and continue This simplifies the process for new users.
2022-06-10Add cmdline arg to initialize a default configJeff Halter
2022-06-08Add flag to enable optional stats HTTP endpointJeff Halter
re: #29 TODO: add more stat counters Usage: ``` ./mobius-hotline-server -stats-port 5503 ``` ``` ❯ curl -s localhost:5503 | jq . { "LoginCount": 0, "StartTime": "2022-06-08T20:49:10.183921-07:00", "DownloadCounter": 0, "UploadCounter": 0 } ```
2022-06-08Refactor filestore to simplify testingJeff Halter
2022-06-06Handle both possible brew install pathsJeff Halter
2022-06-06Seed the random number generatorJeff Halter
2022-05-28Misc cleanupJeff Halter
* Removed some unnecessary user of pointers * Removed dead cruft * Reorganized code
2021-08-15Tests and minor fixesJeff Halter
2021-07-29Re-organize cmd pathsJeff Halter