M5: Windows client moderation UI; add C ABI getters for account list, user mute/deafen, channel topic
This commit is contained in:
@@ -425,6 +425,11 @@ void vc_client::handle_envelope(const voicecat::v1::Envelope& env) {
|
||||
break;
|
||||
}
|
||||
case voicecat::v1::Envelope::kListAccountsResult: {
|
||||
{
|
||||
std::lock_guard lk(account_list_mu_);
|
||||
last_account_list_.assign(env.list_accounts_result().accounts().begin(),
|
||||
env.list_accounts_result().accounts().end());
|
||||
}
|
||||
vc_event ev{};
|
||||
ev.type = VC_EVENT_ACCOUNT_LIST;
|
||||
emit(ev);
|
||||
@@ -1303,11 +1308,14 @@ vc_result vc_client::list_channels(vc_channel_list* out) {
|
||||
auto* items = new vc_channel[channels.size()];
|
||||
for (size_t i = 0; i < channels.size(); ++i) {
|
||||
const auto& ch = channels[i];
|
||||
auto* name = new char[ch.name.size() + 1];
|
||||
auto* name = new char[ch.name.size() + 1];
|
||||
auto* topic = new char[ch.topic.size() + 1];
|
||||
std::memcpy(name, ch.name.c_str(), ch.name.size() + 1);
|
||||
std::memcpy(topic, ch.topic.c_str(), ch.topic.size() + 1);
|
||||
items[i].id = ch.id;
|
||||
items[i].parent_id = ch.parent_id;
|
||||
items[i].name = name;
|
||||
items[i].topic = topic;
|
||||
items[i].password_protected = ch.password_protected ? 1 : 0;
|
||||
items[i].max_users = ch.max_users;
|
||||
}
|
||||
@@ -1324,10 +1332,14 @@ vc_result vc_client::list_users(vc_user_list* out) {
|
||||
const auto& u = users[i];
|
||||
auto* nick = new char[u.nickname.size() + 1];
|
||||
std::memcpy(nick, u.nickname.c_str(), u.nickname.size() + 1);
|
||||
items[i].id = u.id;
|
||||
items[i].nickname = nick;
|
||||
items[i].is_guest = u.is_guest ? 1 : 0;
|
||||
items[i].channel_id = u.channel_id;
|
||||
items[i].id = u.id;
|
||||
items[i].nickname = nick;
|
||||
items[i].is_guest = u.is_guest ? 1 : 0;
|
||||
items[i].channel_id = u.channel_id;
|
||||
items[i].self_mic_muted = u.self_mic_muted ? 1 : 0;
|
||||
items[i].self_deafened = u.self_deafened ? 1 : 0;
|
||||
items[i].server_muted = u.server_muted ? 1 : 0;
|
||||
items[i].server_deafened = u.server_deafened ? 1 : 0;
|
||||
}
|
||||
out->items = items;
|
||||
out->count = users.size();
|
||||
@@ -1519,6 +1531,24 @@ vc_result vc_client::list_accounts() {
|
||||
return VC_OK;
|
||||
}
|
||||
|
||||
vc_result vc_client::get_account_list(vc_account_list* out) {
|
||||
if (!out) return VC_ERR_INVALID_ARG;
|
||||
std::lock_guard lk(account_list_mu_);
|
||||
auto* items = new vc_account[last_account_list_.size()];
|
||||
for (size_t i = 0; i < last_account_list_.size(); ++i) {
|
||||
const auto& a = last_account_list_[i];
|
||||
auto* user = new char[a.username().size() + 1];
|
||||
std::memcpy(user, a.username().c_str(), a.username().size() + 1);
|
||||
items[i].username = user;
|
||||
items[i].is_admin = a.is_admin() ? 1 : 0;
|
||||
items[i].created_at_unix_ms = a.created_at_unix_ms();
|
||||
items[i].last_login_unix_ms = a.last_login_unix_ms();
|
||||
}
|
||||
out->items = items;
|
||||
out->count = last_account_list_.size();
|
||||
return VC_OK;
|
||||
}
|
||||
|
||||
vc_result vc_client::get_permissions(vc_permissions* out) {
|
||||
if (!out) return VC_ERR_INVALID_ARG;
|
||||
*out = own_permissions_;
|
||||
@@ -1644,6 +1674,7 @@ vc_result vc_client::create_account(const char*, const char*) { return VC_ERR_NO
|
||||
vc_result vc_client::reset_password(const char*, const char*) { return VC_ERR_NOT_IMPLEMENTED; }
|
||||
vc_result vc_client::delete_account(const char*) { return VC_ERR_NOT_IMPLEMENTED; }
|
||||
vc_result vc_client::list_accounts() { return VC_ERR_NOT_IMPLEMENTED; }
|
||||
vc_result vc_client::get_account_list(vc_account_list*) { return VC_ERR_NOT_IMPLEMENTED; }
|
||||
vc_result vc_client::get_permissions(vc_permissions*) { return VC_ERR_NOT_IMPLEMENTED; }
|
||||
|
||||
#endif // VOICECAT_HAS_NET
|
||||
|
||||
@@ -90,6 +90,7 @@ struct vc_client {
|
||||
vc_result reset_password(const char* username, const char* new_password);
|
||||
vc_result delete_account(const char* username);
|
||||
vc_result list_accounts();
|
||||
vc_result get_account_list(vc_account_list* out);
|
||||
vc_result get_permissions(vc_permissions* out);
|
||||
|
||||
vc_connection_state state() const {
|
||||
@@ -145,6 +146,11 @@ struct vc_client {
|
||||
voicecat::session::SessionModel session_model_;
|
||||
mutable std::mutex session_model_mu_;
|
||||
|
||||
// M5: last ListAccountsResult snapshot, populated on io_thread_ when
|
||||
// VC_EVENT_ACCOUNT_LIST fires and read by vc_get_account_list on caller threads.
|
||||
std::vector<voicecat::v1::AccountEntry> last_account_list_;
|
||||
mutable std::mutex account_list_mu_;
|
||||
|
||||
// ── M4: TOFU server-identity gate ───────────────────────────────────────────
|
||||
std::unique_ptr<voicecat::crypto::TofuStore> tofu_store_; // owns the pin file
|
||||
std::mutex tofu_mu_;
|
||||
|
||||
@@ -58,6 +58,7 @@ void SessionModel::apply_snapshot(const voicecat::v1::ServerStateSnapshot& snap)
|
||||
ch.id = pb.id();
|
||||
ch.parent_id = pb.parent_id();
|
||||
ch.name = pb.name();
|
||||
ch.topic = pb.topic();
|
||||
ch.password_protected = pb.password_protected();
|
||||
ch.max_users = pb.max_users();
|
||||
channels_.push_back(std::move(ch));
|
||||
@@ -70,6 +71,8 @@ void SessionModel::apply_snapshot(const voicecat::v1::ServerStateSnapshot& snap)
|
||||
u.nickname = pb.nickname();
|
||||
u.is_guest = pb.is_guest();
|
||||
u.channel_id = pb.channel_id();
|
||||
u.self_mic_muted = pb.self_mic_muted();
|
||||
u.self_deafened = pb.self_deafened();
|
||||
u.server_muted = pb.server_muted();
|
||||
u.server_deafened = pb.server_deafened();
|
||||
u.streams = copy_streams(pb.streams());
|
||||
@@ -87,6 +90,8 @@ void SessionModel::apply_user_event(const voicecat::v1::UserEvent& ev) {
|
||||
u.nickname = pb.nickname();
|
||||
u.is_guest = pb.is_guest();
|
||||
u.channel_id = pb.channel_id();
|
||||
u.self_mic_muted = pb.self_mic_muted();
|
||||
u.self_deafened = pb.self_deafened();
|
||||
u.server_muted = pb.server_muted();
|
||||
u.server_deafened = pb.server_deafened();
|
||||
u.streams = copy_streams(pb.streams());
|
||||
@@ -113,6 +118,7 @@ void SessionModel::apply_channel_event(const voicecat::v1::ChannelEvent& ev) {
|
||||
ch.id = pb.id();
|
||||
ch.parent_id = pb.parent_id();
|
||||
ch.name = pb.name();
|
||||
ch.topic = pb.topic();
|
||||
ch.password_protected = pb.password_protected();
|
||||
ch.max_users = pb.max_users();
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ struct Channel {
|
||||
uint32_t id{0};
|
||||
uint32_t parent_id{0};
|
||||
std::string name;
|
||||
std::string topic;
|
||||
bool password_protected{false};
|
||||
uint32_t max_users{0};
|
||||
};
|
||||
@@ -51,6 +52,8 @@ struct User {
|
||||
std::string nickname;
|
||||
bool is_guest{true};
|
||||
uint32_t channel_id{0};
|
||||
bool self_mic_muted{false};
|
||||
bool self_deafened{false};
|
||||
bool server_muted{false};
|
||||
bool server_deafened{false};
|
||||
std::vector<Stream> streams;
|
||||
|
||||
@@ -164,7 +164,10 @@ vc_result vc_list_channels(vc_client* c, vc_channel_list* out) {
|
||||
|
||||
void vc_free_channel_list(vc_channel_list* list) {
|
||||
if (list == nullptr || list->items == nullptr) return;
|
||||
for (size_t i = 0; i < list->count; ++i) delete[] list->items[i].name;
|
||||
for (size_t i = 0; i < list->count; ++i) {
|
||||
delete[] list->items[i].name;
|
||||
delete[] list->items[i].topic;
|
||||
}
|
||||
delete[] list->items;
|
||||
list->items = nullptr;
|
||||
list->count = 0;
|
||||
@@ -268,6 +271,19 @@ vc_result vc_list_accounts(vc_client* c) {
|
||||
return c->list_accounts();
|
||||
}
|
||||
|
||||
vc_result vc_get_account_list(vc_client* c, vc_account_list* out) {
|
||||
if (c == nullptr || out == nullptr) return VC_ERR_INVALID_ARG;
|
||||
return c->get_account_list(out);
|
||||
}
|
||||
|
||||
void vc_free_account_list(vc_account_list* list) {
|
||||
if (list == nullptr || list->items == nullptr) return;
|
||||
for (size_t i = 0; i < list->count; ++i) delete[] list->items[i].username;
|
||||
delete[] list->items;
|
||||
list->items = nullptr;
|
||||
list->count = 0;
|
||||
}
|
||||
|
||||
vc_result vc_get_permissions(vc_client* c, vc_permissions* out) {
|
||||
if (c == nullptr || out == nullptr) return VC_ERR_INVALID_ARG;
|
||||
return c->get_permissions(out);
|
||||
|
||||
Reference in New Issue
Block a user