/* * server/conn_session.h — Per-client connection state machine. * * State: WaitingHello → WaitingAuth → Authenticated → Disconnecting * * Design: ConnSession is a pure state machine. It receives frames via on_frame() * (called from TcpServerConn's strand) and sends via a send_fn set after construction. * The server creates the TcpServerConn first (with callbacks referencing the session), * then calls set_tcp() to give the session its send capability. */ #ifndef VOICECAT_SERVER_CONN_SESSION_H #define VOICECAT_SERVER_CONN_SESSION_H #ifdef VOICECAT_HAS_NET #include #include #include #include #include #include #include #include "proto/voicecat.pb.h" namespace voicecat { class WorkerPool; } // defined in core/worker_pool.h namespace voicecat::server { class Database; class SessionRegistry; class ConnSession : public std::enable_shared_from_this { public: enum class State { WaitingHello, WaitingAuth, Authenticated, Disconnecting }; using SendFn = std::function)>; using CloseFn = std::function; ConnSession(std::shared_ptr db, std::shared_ptr registry, std::shared_ptr workers, const std::array& server_fp, bool allow_guests); // Called after construction: gives the session its send + close handles. void set_io(SendFn send_fn, CloseFn close_fn); // Called by server after it has registered the session id. void set_session_id(uint64_t id) { session_id_ = id; } // Entry point: send ServerHello and begin reading. void begin(); // Deliver a received frame (called from TcpServerConn's strand). void on_frame(std::vector frame); // Called when the TCP connection drops. void on_disconnect(); // Thread-safe send. void send_envelope(const voicecat::v1::Envelope& env); // Graceful close (can be called from any thread). void close(); State state() const { return state_.load(); } uint64_t session_id() const { return session_id_; } uint32_t user_id() const { return user_id_; } private: void handle_client_hello(uint64_t req_id, const voicecat::v1::ClientHello& msg); void handle_auth_request(uint64_t req_id, const voicecat::v1::AuthRequest& msg); void handle_join_channel(uint64_t req_id, const voicecat::v1::JoinChannelRequest& msg); void handle_text_message(const voicecat::v1::TextMessage& msg); void handle_ping(const voicecat::v1::Ping& msg); void finish_guest_auth(const voicecat::v1::GuestAuth& guest, uint64_t req_id); void finish_password_auth(const std::string& username, const std::string& password, uint64_t req_id); void send_state_snapshot(); void broadcast_user_joined(const voicecat::v1::User& user); void send_disconnect_and_close(uint32_t code, const std::string& reason); std::shared_ptr db_; std::shared_ptr registry_; std::shared_ptr workers_; std::array server_fp_; bool allow_guests_; SendFn send_fn_; CloseFn close_fn_; std::atomic state_{State::WaitingHello}; uint64_t session_id_{0}; // set once before begin(), then read-only std::atomic user_id_{0}; std::atomic closed_{false}; }; } // namespace voicecat::server #endif // VOICECAT_HAS_NET #endif // VOICECAT_SERVER_CONN_SESSION_H