Skip to content

Commit 326693e

Browse files
committed
refactor: update error handling in service and repository classes to use structured initialization for error messages, enhancing clarity and consistency across the codebase
1 parent 1bb031c commit 326693e

16 files changed

Lines changed: 92 additions & 68 deletions

lib/vox_admin/admin_service.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ ServerStats AdminService::GetServerStats() {
5858
common::VoidResult AdminService::DeleteUser(const common::UserId& user_id) {
5959
auto user = users_.FindById(user_id);
6060
if (!user) {
61-
return std::unexpected(common::Error{common::ErrorCode::kNotFound, "User not found"});
61+
return std::unexpected(common::Error{.code = common::ErrorCode::kNotFound, .message = "User not found"});
6262
}
6363

6464
auto now = Now();
@@ -102,7 +102,7 @@ common::VoidResult AdminService::DeleteUser(const common::UserId& user_id) {
102102

103103
txn.commit();
104104
} catch (const SQLite::Exception& e) {
105-
return std::unexpected(common::Error{common::ErrorCode::kInternal, e.what()});
105+
return std::unexpected(common::Error{.code = common::ErrorCode::kInternal, .message = e.what()});
106106
}
107107

108108
spdlog::info("User deleted: {} ({})", user->username, user_id);
@@ -112,7 +112,7 @@ common::VoidResult AdminService::DeleteUser(const common::UserId& user_id) {
112112
common::VoidResult AdminService::ForceLogout(const common::UserId& user_id) {
113113
auto user = users_.FindById(user_id);
114114
if (!user) {
115-
return std::unexpected(common::Error{common::ErrorCode::kNotFound, "User not found"});
115+
return std::unexpected(common::Error{.code = common::ErrorCode::kNotFound, .message = "User not found"});
116116
}
117117
auto now = Now();
118118
auto revoke_result = sessions_.RevokeAllForUser(user_id, now);

lib/vox_attachments/attachment_service.cpp

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,24 @@ common::Result<InitUploadResponse> AttachmentService::InitUpload(const common::U
2121
std::int64_t file_size,
2222
const std::string& mime_hint) {
2323
if (file_size <= 0) {
24-
return std::unexpected(common::Error{common::ErrorCode::kInvalidArgument, "File size must be positive"});
24+
return std::unexpected(
25+
common::Error{.code = common::ErrorCode::kInvalidArgument, .message = "File size must be positive"});
2526
}
2627
if (file_size > static_cast<std::int64_t>(config_.max_upload_size_bytes)) {
27-
return std::unexpected(common::Error{common::ErrorCode::kQuotaExceeded, "File exceeds maximum upload size"});
28+
return std::unexpected(
29+
common::Error{.code = common::ErrorCode::kQuotaExceeded, .message = "File exceeds maximum upload size"});
2830
}
2931

3032
auto used = attachments_.GetStorageUsedByUser(user_id);
3133
if (used + file_size > static_cast<std::int64_t>(config_.max_storage_per_user_bytes)) {
32-
return std::unexpected(common::Error{common::ErrorCode::kQuotaExceeded, "User storage quota exceeded"});
34+
return std::unexpected(
35+
common::Error{.code = common::ErrorCode::kQuotaExceeded, .message = "User storage quota exceeded"});
3336
}
3437

3538
bool is_member = conversations_.IsUserInConversation(conversation_id, user_id);
3639
if (!is_member) {
37-
return std::unexpected(common::Error{common::ErrorCode::kForbidden, "User is not a member of this conversation"});
40+
return std::unexpected(
41+
common::Error{.code = common::ErrorCode::kForbidden, .message = "User is not a member of this conversation"});
3842
}
3943

4044
auto now = Now();
@@ -58,31 +62,32 @@ common::Result<InitUploadResponse> AttachmentService::InitUpload(const common::U
5862
return std::unexpected(result.error());
5963
}
6064

61-
return InitUploadResponse{attachment_id, blob_path.string()};
65+
return InitUploadResponse{.attachment_id = attachment_id, .blob_path = blob_path.string()};
6266
}
6367

6468
common::VoidResult AttachmentService::WriteChunk(const common::AttachmentId& attachment_id,
6569
std::int64_t offset,
6670
const std::string& data) {
6771
auto meta = attachments_.GetAttachmentMeta(attachment_id);
6872
if (!meta) {
69-
return std::unexpected(common::Error{common::ErrorCode::kNotFound, "Attachment not found"});
73+
return std::unexpected(common::Error{.code = common::ErrorCode::kNotFound, .message = "Attachment not found"});
7074
}
7175
if (meta->upload_complete) {
72-
return std::unexpected(common::Error{common::ErrorCode::kInvalidArgument, "Upload already complete"});
76+
return std::unexpected(
77+
common::Error{.code = common::ErrorCode::kInvalidArgument, .message = "Upload already complete"});
7378
}
7479

7580
std::ofstream file(meta->blob_path, std::ios::binary | std::ios::in | std::ios::out);
7681
if (!file.is_open()) {
7782
file.open(meta->blob_path, std::ios::binary | std::ios::out);
7883
}
7984
if (!file.is_open()) {
80-
return std::unexpected(common::Error{common::ErrorCode::kInternal, "Cannot open blob file"});
85+
return std::unexpected(common::Error{.code = common::ErrorCode::kInternal, .message = "Cannot open blob file"});
8186
}
8287
file.seekp(offset);
8388
file.write(data.data(), static_cast<std::streamsize>(data.size()));
8489
if (!file.good()) {
85-
return std::unexpected(common::Error{common::ErrorCode::kInternal, "Failed to write chunk"});
90+
return std::unexpected(common::Error{.code = common::ErrorCode::kInternal, .message = "Failed to write chunk"});
8691
}
8792
return {};
8893
}
@@ -91,14 +96,16 @@ common::VoidResult AttachmentService::FinalizeUpload(const common::AttachmentId&
9196
const std::string& ciphertext_hash) {
9297
auto meta = attachments_.GetAttachmentMeta(attachment_id);
9398
if (!meta) {
94-
return std::unexpected(common::Error{common::ErrorCode::kNotFound, "Attachment not found"});
99+
return std::unexpected(common::Error{.code = common::ErrorCode::kNotFound, .message = "Attachment not found"});
95100
}
96101
if (meta->upload_complete) {
97-
return std::unexpected(common::Error{common::ErrorCode::kInvalidArgument, "Upload already finalized"});
102+
return std::unexpected(
103+
common::Error{.code = common::ErrorCode::kInvalidArgument, .message = "Upload already finalized"});
98104
}
99105

100106
if (!std::filesystem::exists(meta->blob_path)) {
101-
return std::unexpected(common::Error{common::ErrorCode::kInternal, "Blob file not found on disk"});
107+
return std::unexpected(
108+
common::Error{.code = common::ErrorCode::kInternal, .message = "Blob file not found on disk"});
102109
}
103110

104111
return attachments_.MarkUploadComplete(attachment_id, ciphertext_hash);
@@ -108,15 +115,17 @@ common::Result<std::filesystem::path> AttachmentService::GetAttachment(const com
108115
const common::UserId& user_id) {
109116
auto meta = attachments_.GetAttachmentMeta(attachment_id);
110117
if (!meta) {
111-
return std::unexpected(common::Error{common::ErrorCode::kNotFound, "Attachment not found"});
118+
return std::unexpected(common::Error{.code = common::ErrorCode::kNotFound, .message = "Attachment not found"});
112119
}
113120
if (!meta->upload_complete) {
114-
return std::unexpected(common::Error{common::ErrorCode::kNotFound, "Attachment upload not complete"});
121+
return std::unexpected(
122+
common::Error{.code = common::ErrorCode::kNotFound, .message = "Attachment upload not complete"});
115123
}
116124

117125
bool is_member = conversations_.IsUserInConversation(meta->conversation_id, user_id);
118126
if (!is_member) {
119-
return std::unexpected(common::Error{common::ErrorCode::kForbidden, "Not authorized to access this attachment"});
127+
return std::unexpected(
128+
common::Error{.code = common::ErrorCode::kForbidden, .message = "Not authorized to access this attachment"});
120129
}
121130

122131
return std::filesystem::path(meta->blob_path);

lib/vox_auth/auth_service.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ AuthService::AuthService(store::UserRepository& users,
1818

1919
common::Result<RegisterResponse> AuthService::Register(const RegisterRequest& request) {
2020
if (request.username.empty() || request.password_derived_value.empty()) {
21-
return std::unexpected(common::Error{common::ErrorCode::kInvalidArgument, "Username and password are required"});
21+
return std::unexpected(
22+
common::Error{.code = common::ErrorCode::kInvalidArgument, .message = "Username and password are required"});
2223
}
2324

2425
auto existing = users_.FindByUsername(request.username);
2526
if (existing) {
26-
return std::unexpected(common::Error{common::ErrorCode::kAlreadyExists, "Username already taken"});
27+
return std::unexpected(
28+
common::Error{.code = common::ErrorCode::kAlreadyExists, .message = "Username already taken"});
2729
}
2830

2931
auto hash_future = cpu_pool_.Submit([this, &request]() { return hasher_.Hash(request.password_derived_value); });
@@ -65,17 +67,17 @@ common::Result<RegisterResponse> AuthService::Register(const RegisterRequest& re
6567
}
6668

6769
spdlog::info("User registered: {} ({})", request.username, user_id);
68-
return RegisterResponse{user_id, *token_result};
70+
return RegisterResponse{.user_id = user_id, .tokens = *token_result};
6971
}
7072

7173
common::Result<LoginResponse> AuthService::Login(const LoginRequest& request) {
7274
auto user = users_.FindByUsername(request.username);
7375
if (!user) {
74-
return std::unexpected(common::Error{common::ErrorCode::kUnauthorized, "Invalid credentials"});
76+
return std::unexpected(common::Error{.code = common::ErrorCode::kUnauthorized, .message = "Invalid credentials"});
7577
}
7678

7779
if (user->disabled_at.has_value()) {
78-
return std::unexpected(common::Error{common::ErrorCode::kForbidden, "Account is disabled"});
80+
return std::unexpected(common::Error{.code = common::ErrorCode::kForbidden, .message = "Account is disabled"});
7981
}
8082

8183
auto verify_future = cpu_pool_.Submit([this, &request, &user]() {
@@ -84,7 +86,7 @@ common::Result<LoginResponse> AuthService::Login(const LoginRequest& request) {
8486
bool valid = verify_future.get();
8587

8688
if (!valid) {
87-
return std::unexpected(common::Error{common::ErrorCode::kUnauthorized, "Invalid credentials"});
89+
return std::unexpected(common::Error{.code = common::ErrorCode::kUnauthorized, .message = "Invalid credentials"});
8890
}
8991

9092
auto now = Now();
@@ -107,7 +109,7 @@ common::Result<LoginResponse> AuthService::Login(const LoginRequest& request) {
107109
}
108110

109111
spdlog::info("User logged in: {} ({})", request.username, user->user_id);
110-
return LoginResponse{user->user_id, *token_result};
112+
return LoginResponse{.user_id = user->user_id, .tokens = *token_result};
111113
}
112114

113115
common::VoidResult AuthService::Logout(const std::string& session_id) {

lib/vox_auth/password_hasher.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,12 @@ common::Result<HashResult> PasswordHasher::Hash(const std::string& password_deri
6666
hash_bytes.size());
6767

6868
if (result != ARGON2_OK) {
69-
return std::unexpected(common::Error{common::ErrorCode::kInternal,
70-
fmt::format("Argon2 hash failed: {}", argon2_error_message(result))});
69+
return std::unexpected(
70+
common::Error{.code = common::ErrorCode::kInternal,
71+
.message = fmt::format("Argon2 hash failed: {}", argon2_error_message(result))});
7172
}
7273

73-
return HashResult{BytesToHex(salt_bytes), BytesToHex(hash_bytes)};
74+
return HashResult{.salt = BytesToHex(salt_bytes), .verifier = BytesToHex(hash_bytes)};
7475
}
7576

7677
bool PasswordHasher::Verify(const std::string& password_derived_value,

lib/vox_auth/token_manager.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ common::Result<store::SessionRecord> TokenManager::ValidateAccessToken(const std
6767
auto hash = HashToken(access_token);
6868
auto session = sessions_.FindByAccessToken(hash);
6969
if (!session) {
70-
return std::unexpected(common::Error{common::ErrorCode::kUnauthorized, "Invalid access token"});
70+
return std::unexpected(common::Error{.code = common::ErrorCode::kUnauthorized, .message = "Invalid access token"});
7171
}
7272
if (session->access_expires_at <= now) {
73-
return std::unexpected(common::Error{common::ErrorCode::kExpired, "Access token expired"});
73+
return std::unexpected(common::Error{.code = common::ErrorCode::kExpired, .message = "Access token expired"});
7474
}
7575
return *session;
7676
}
@@ -81,13 +81,14 @@ common::Result<TokenPair> TokenManager::RefreshTokens(const std::string& refresh
8181
auto hash = HashToken(refresh_token);
8282
auto session = sessions_.FindByRefreshToken(hash);
8383
if (!session) {
84-
return std::unexpected(common::Error{common::ErrorCode::kUnauthorized, "Invalid refresh token"});
84+
return std::unexpected(common::Error{.code = common::ErrorCode::kUnauthorized, .message = "Invalid refresh token"});
8585
}
8686
if (session->refresh_expires_at <= now) {
87-
return std::unexpected(common::Error{common::ErrorCode::kExpired, "Refresh token expired"});
87+
return std::unexpected(common::Error{.code = common::ErrorCode::kExpired, .message = "Refresh token expired"});
8888
}
8989
if (session->device_id != device_id) {
90-
return std::unexpected(common::Error{common::ErrorCode::kForbidden, "Device mismatch on refresh"});
90+
return std::unexpected(
91+
common::Error{.code = common::ErrorCode::kForbidden, .message = "Device mismatch on refresh"});
9192
}
9293

9394
auto revoke_result = sessions_.RevokeSession(session->session_id, now);

lib/vox_relay/delivery_manager.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ common::VoidResult DeliveryManager::Enqueue(const common::DeviceId& device_id, c
1616

1717
if (queue.pending.size() >= max_queue_per_device_) {
1818
spdlog::warn("Queue overflow for device {}, switching to offline", device_id);
19-
return std::unexpected(common::Error{common::ErrorCode::kQueueFull, "Device queue full, use offline delivery"});
19+
return std::unexpected(
20+
common::Error{.code = common::ErrorCode::kQueueFull, .message = "Device queue full, use offline delivery"});
2021
}
2122

2223
queue.pending.push_back(envelope);

lib/vox_relay/relay_service.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,36 +17,39 @@ RelayService::RelayService(store::EnvelopeRepository& envelopes,
1717

1818
common::Result<SendMessageResponse> RelayService::SendMessage(const SendMessageRequest& request) {
1919
if (request.ciphertext.empty()) {
20-
return std::unexpected(common::Error{common::ErrorCode::kInvalidArgument, "Ciphertext is required"});
20+
return std::unexpected(
21+
common::Error{.code = common::ErrorCode::kInvalidArgument, .message = "Ciphertext is required"});
2122
}
2223

2324
auto sender_device = devices_.FindById(request.sender_device_id);
2425
if (!sender_device) {
25-
return std::unexpected(common::Error{common::ErrorCode::kUnauthorized, "Sender device not found"});
26+
return std::unexpected(
27+
common::Error{.code = common::ErrorCode::kUnauthorized, .message = "Sender device not found"});
2628
}
2729

2830
auto conv = conversations_.FindById(request.conversation_id);
2931
if (!conv) {
30-
return std::unexpected(common::Error{common::ErrorCode::kNotFound, "Conversation not found"});
32+
return std::unexpected(common::Error{.code = common::ErrorCode::kNotFound, .message = "Conversation not found"});
3133
}
3234

3335
bool is_member = conversations_.IsUserInConversation(request.conversation_id, sender_device->user_id);
3436
if (!is_member) {
35-
return std::unexpected(common::Error{common::ErrorCode::kForbidden, "Sender is not a member of this conversation"});
37+
return std::unexpected(
38+
common::Error{.code = common::ErrorCode::kForbidden, .message = "Sender is not a member of this conversation"});
3639
}
3740

3841
if (conv->type == common::ConversationType::kChannel) {
3942
auto member = conversations_.GetMember(request.conversation_id, sender_device->user_id);
4043
if (!member || (member->role != common::MemberRole::kOwner && member->role != common::MemberRole::kAdmin)) {
41-
return std::unexpected(
42-
common::Error{common::ErrorCode::kForbidden, "Only admins/owners can publish to channels"});
44+
return std::unexpected(common::Error{.code = common::ErrorCode::kForbidden,
45+
.message = "Only admins/owners can publish to channels"});
4346
}
4447
}
4548

4649
auto envelope_id = request.envelope_id.empty() ? common::GenerateUuid() : request.envelope_id;
4750

4851
if (envelopes_.CheckDuplicate(envelope_id)) {
49-
return std::unexpected(common::Error{common::ErrorCode::kDuplicate, "Duplicate envelope"});
52+
return std::unexpected(common::Error{.code = common::ErrorCode::kDuplicate, .message = "Duplicate envelope"});
5053
}
5154

5255
auto now = Now();
@@ -99,7 +102,8 @@ common::Result<SendMessageResponse> RelayService::SendMessage(const SendMessageR
99102
}
100103
}
101104

102-
return SendMessageResponse{envelope_id, now, delivered_count};
105+
return SendMessageResponse{
106+
.envelope_id = envelope_id, .server_timestamp = now, .delivered_to_count = delivered_count};
103107
}
104108

105109
std::vector<store::EnvelopeRecord> RelayService::SyncOffline(const common::DeviceId& device_id, std::size_t limit) {

lib/vox_store/attachment_repository.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ common::VoidResult AttachmentRepository::CreateAttachmentMeta(const AttachmentRe
3636
stmt.exec();
3737
return {};
3838
} catch (const SQLite::Exception& e) {
39-
return std::unexpected(common::Error{common::ErrorCode::kInternal, e.what()});
39+
return std::unexpected(common::Error{.code = common::ErrorCode::kInternal, .message = e.what()});
4040
}
4141
}
4242

@@ -73,7 +73,7 @@ common::VoidResult AttachmentRepository::MarkUploadComplete(const common::Attach
7373
stmt.bind(2, attachment_id);
7474
int rows = stmt.exec();
7575
if (rows == 0) {
76-
return std::unexpected(common::Error{common::ErrorCode::kNotFound, "Attachment not found"});
76+
return std::unexpected(common::Error{.code = common::ErrorCode::kNotFound, .message = "Attachment not found"});
7777
}
7878
return {};
7979
}
@@ -84,7 +84,7 @@ common::VoidResult AttachmentRepository::DeleteAttachment(const common::Attachme
8484
stmt.bind(1, attachment_id);
8585
int rows = stmt.exec();
8686
if (rows == 0) {
87-
return std::unexpected(common::Error{common::ErrorCode::kNotFound, "Attachment not found"});
87+
return std::unexpected(common::Error{.code = common::ErrorCode::kNotFound, .message = "Attachment not found"});
8888
}
8989
return {};
9090
}

lib/vox_store/conversation_repository.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ common::VoidResult ConversationRepository::CreateConversation(const Conversation
3131
return {};
3232
} catch (const SQLite::Exception& e) {
3333
if (e.getErrorCode() == SQLITE_CONSTRAINT) {
34-
return std::unexpected(common::Error{common::ErrorCode::kAlreadyExists, "Conversation already exists"});
34+
return std::unexpected(
35+
common::Error{.code = common::ErrorCode::kAlreadyExists, .message = "Conversation already exists"});
3536
}
36-
return std::unexpected(common::Error{common::ErrorCode::kInternal, e.what()});
37+
return std::unexpected(common::Error{.code = common::ErrorCode::kInternal, .message = e.what()});
3738
}
3839
}
3940

@@ -72,7 +73,7 @@ common::VoidResult ConversationRepository::AddMember(const common::ConversationI
7273
stmt.exec();
7374
return {};
7475
} catch (const SQLite::Exception& e) {
75-
return std::unexpected(common::Error{common::ErrorCode::kInternal, e.what()});
76+
return std::unexpected(common::Error{.code = common::ErrorCode::kInternal, .message = e.what()});
7677
}
7778
}
7879

@@ -187,7 +188,7 @@ common::VoidResult ConversationRepository::Subscribe(const common::ConversationI
187188
stmt.exec();
188189
return {};
189190
} catch (const SQLite::Exception& e) {
190-
return std::unexpected(common::Error{common::ErrorCode::kInternal, e.what()});
191+
return std::unexpected(common::Error{.code = common::ErrorCode::kInternal, .message = e.what()});
191192
}
192193
}
193194

0 commit comments

Comments
 (0)