feat(M1): TCP/TLS control plane -- auth, channels, ephemeral text
Implements the full M1 milestone. Two clients authenticate over TLS 1.3 (guest + Argon2id password) and exchange channel + private text messages through a real server. All five ctest --preset m1-dev tests pass in ~1 s. Key components added: - vcpkg baseline + m1-dev preset (protobuf/mbedTLS/libsodium/asio/sqlite3) - FrameCodec feed+emit, encode/decode_envelope, protobuf codegen - TcpServerConn with blocking TLS handshake thread + tls_read_loop - TlsContext (mbedTLS 1.3, ECDSA-P256 self-signed cert, TOFU on client) - WorkerPool (3 threads, used for Argon2id) - Database: SQLite + libsodium Argon2id, account lifecycle, bootstrap admin - ServerIdentityManager: Ed25519 key + cert generate/persist/fingerprint - ConnSession state machine: WaitingHello -> WaitingAuth -> Authenticated - SessionRegistry: channel tree, user map, text routing, broadcast - vc_client full M1 C ABI: connect/TLS/handshake/auth/text/disconnect - voicecat-admin CLI: account add/reset/del/list - test_m1_integration: M1 exit criterion, verified green Bug fixed: double-framing in ConnSession::send_envelope -- encode_envelope was adding the [4-byte len] prefix, then TcpServerConn::send_frame added a second one, causing the client to parse [len][proto] as protobuf (silent failure). Fixed by serializing raw protobuf bytes in send_envelope and letting send_frame apply the single length prefix. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,8 @@
|
||||
/*
|
||||
* session/session.h — domain model: channels, users, streams, permissions, text.
|
||||
* session/session.h — client-side mirror of the server's channel/user state.
|
||||
*
|
||||
* Design: docs/protocol.md §5, docs/architecture.md §5. Shared by client (local mirror of
|
||||
* server state) and server (authoritative). Text is ephemeral (no history). Accounts are
|
||||
* admin-provisioned.
|
||||
*
|
||||
* STATUS: M0 stub.
|
||||
* Populated from ServerStateSnapshot (full snapshot) and incremental UserEvent /
|
||||
* ChannelEvent messages. Not thread-safe — always called from io_thread_.
|
||||
*/
|
||||
#ifndef VOICECAT_SESSION_SESSION_H
|
||||
#define VOICECAT_SESSION_SESSION_H
|
||||
@@ -14,40 +11,52 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef VOICECAT_HAS_NET
|
||||
#include "proto/voicecat.pb.h"
|
||||
#endif
|
||||
|
||||
namespace voicecat::session {
|
||||
|
||||
struct Channel {
|
||||
uint32_t id = 0;
|
||||
uint32_t parent_id = 0;
|
||||
uint32_t id{0};
|
||||
uint32_t parent_id{0};
|
||||
std::string name;
|
||||
bool password_protected = false;
|
||||
uint32_t max_users = 0;
|
||||
bool password_protected{false};
|
||||
uint32_t max_users{0};
|
||||
};
|
||||
|
||||
struct Stream {
|
||||
uint32_t stream_id = 0;
|
||||
uint32_t ssrc = 0;
|
||||
int kind = 0; // vc_stream_kind
|
||||
uint32_t stream_id{0};
|
||||
uint32_t ssrc{0};
|
||||
int kind{0};
|
||||
std::string label;
|
||||
};
|
||||
|
||||
struct User {
|
||||
uint32_t id = 0;
|
||||
std::string nickname;
|
||||
bool is_guest = true;
|
||||
uint32_t channel_id = 0;
|
||||
uint32_t id{0};
|
||||
std::string nickname;
|
||||
bool is_guest{true};
|
||||
uint32_t channel_id{0};
|
||||
std::vector<Stream> streams;
|
||||
};
|
||||
|
||||
// Mirror/authority for the channel tree + user list. TODO(M1): snapshot + delta apply.
|
||||
class SessionModel {
|
||||
public:
|
||||
const std::vector<Channel>& channels() const { return channels_; }
|
||||
const std::vector<User>& users() const { return users_; }
|
||||
const std::vector<User>& users() const { return users_; }
|
||||
|
||||
const Channel* find_channel(uint32_t id) const;
|
||||
const User* find_user(uint32_t id) const;
|
||||
|
||||
#ifdef VOICECAT_HAS_NET
|
||||
void apply_snapshot(const voicecat::v1::ServerStateSnapshot& snap);
|
||||
void apply_user_event(const voicecat::v1::UserEvent& ev);
|
||||
void apply_channel_event(const voicecat::v1::ChannelEvent& ev);
|
||||
#endif
|
||||
|
||||
private:
|
||||
std::vector<Channel> channels_;
|
||||
std::vector<User> users_;
|
||||
std::vector<User> users_;
|
||||
};
|
||||
|
||||
} // namespace voicecat::session
|
||||
|
||||
Reference in New Issue
Block a user