mirror of
https://github.com/stoatchat/stoatchat.git
synced 2026-07-14 13:36:59 +00:00
Added groups + ran rust fmt / clippy.
This commit is contained in:
@@ -10,13 +10,18 @@ pub struct Channel {
|
||||
pub last_message: Option<String>,
|
||||
|
||||
// for Direct Messages
|
||||
pub recipients: Option<Vec<String>>,
|
||||
pub active: Option<bool>,
|
||||
|
||||
// for DMs / GDMs
|
||||
pub recipients: Option<Vec<String>>,
|
||||
|
||||
// for GDMs
|
||||
pub owner: Option<String>,
|
||||
|
||||
// for Guilds
|
||||
pub name: Option<String>,
|
||||
pub guild: Option<String>,
|
||||
|
||||
// for Guilds and Group DMs
|
||||
pub name: Option<String>,
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use mongodb::options::FindOneOptions;
|
||||
pub fn find_member_permissions<C: Into<Option<String>>>(
|
||||
id: String,
|
||||
guild: String,
|
||||
channel: C,
|
||||
_channel: C,
|
||||
) -> u32 {
|
||||
let col = get_collection("guilds");
|
||||
|
||||
@@ -46,6 +46,7 @@ pub fn find_member_permissions<C: Into<Option<String>>>(
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Member {
|
||||
pub id: String,
|
||||
pub nickname: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
|
||||
@@ -10,11 +10,11 @@ use num_enum::TryFromPrimitive;
|
||||
#[derive(Debug, PartialEq, Eq, TryFromPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum Relationship {
|
||||
FRIEND = 0,
|
||||
OUTGOING = 1,
|
||||
INCOMING = 2,
|
||||
BLOCKED = 3,
|
||||
BLOCKEDOTHER = 4,
|
||||
Friend = 0,
|
||||
Outgoing = 1,
|
||||
Incoming = 2,
|
||||
Blocked = 3,
|
||||
BlockedOther = 4,
|
||||
NONE = 5,
|
||||
SELF = 6,
|
||||
}
|
||||
@@ -22,16 +22,16 @@ pub enum Relationship {
|
||||
#[derive(Debug, PartialEq, Eq, TryFromPrimitive)]
|
||||
#[repr(u32)]
|
||||
pub enum Permission {
|
||||
ACCESS = 1,
|
||||
CREATE_INVITE = 2,
|
||||
KICK_MEMBERS = 4,
|
||||
BAN_MEMBERS = 8,
|
||||
READ_MESSAGES = 16,
|
||||
SEND_MESSAGES = 32,
|
||||
MANAGE_MESSAGES = 64,
|
||||
MANAGE_CHANNELS = 128,
|
||||
MANAGE_SERVER = 256,
|
||||
MANAGE_ROLES = 512,
|
||||
Access = 1,
|
||||
CreateInvite = 2,
|
||||
KickMembers = 4,
|
||||
BanMembers = 8,
|
||||
ReadMessages = 16,
|
||||
SendMessages = 32,
|
||||
ManageMessages = 64,
|
||||
ManageChannels = 128,
|
||||
ManageServer = 256,
|
||||
ManageRoles = 512,
|
||||
}
|
||||
|
||||
bitfield! {
|
||||
@@ -62,11 +62,11 @@ pub fn get_relationship_internal(
|
||||
for entry in arr {
|
||||
if entry.id == target_id {
|
||||
match entry.status {
|
||||
0 => return Relationship::FRIEND,
|
||||
1 => return Relationship::OUTGOING,
|
||||
2 => return Relationship::INCOMING,
|
||||
3 => return Relationship::BLOCKED,
|
||||
4 => return Relationship::BLOCKEDOTHER,
|
||||
0 => return Relationship::Friend,
|
||||
1 => return Relationship::Outgoing,
|
||||
2 => return Relationship::Incoming,
|
||||
3 => return Relationship::Blocked,
|
||||
4 => return Relationship::BlockedOther,
|
||||
_ => return Relationship::NONE,
|
||||
}
|
||||
}
|
||||
@@ -132,7 +132,7 @@ impl PermissionCalculator {
|
||||
None
|
||||
};
|
||||
|
||||
let mut permissions = 0;
|
||||
let mut permissions: u32 = 0;
|
||||
if let Some(guild) = guild {
|
||||
if let Some(_data) = guild.fetch_data_given(
|
||||
doc! {
|
||||
@@ -148,14 +148,13 @@ impl PermissionCalculator {
|
||||
return u32::MAX;
|
||||
}
|
||||
|
||||
permissions = guild.default_permissions;
|
||||
permissions = guild.default_permissions as u32;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(channel) = &self.channel {
|
||||
match channel.channel_type {
|
||||
0 => {
|
||||
// ? check user is part of the channel
|
||||
if let Some(arr) = &channel.recipients {
|
||||
let mut other_user = "";
|
||||
for item in arr {
|
||||
@@ -170,8 +169,8 @@ impl PermissionCalculator {
|
||||
let relationship =
|
||||
get_relationship_internal(&self.user.id, &other_user, &relationships);
|
||||
|
||||
if relationship == Relationship::BLOCKED
|
||||
|| relationship == Relationship::BLOCKEDOTHER
|
||||
if relationship == Relationship::Blocked
|
||||
|| relationship == Relationship::BlockedOther
|
||||
{
|
||||
permissions = 1;
|
||||
} else if has_mutual_connection(self.user.id, other_user.to_string()) {
|
||||
@@ -179,7 +178,22 @@ impl PermissionCalculator {
|
||||
}
|
||||
}
|
||||
}
|
||||
1 => unreachable!(),
|
||||
1 => {
|
||||
if let Some(id) = &channel.owner {
|
||||
if &self.user.id == id {
|
||||
return u32::MAX;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(arr) = &channel.recipients {
|
||||
for item in arr {
|
||||
if item == &self.user.id {
|
||||
permissions = 49;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
// nothing implemented yet
|
||||
}
|
||||
@@ -187,7 +201,7 @@ impl PermissionCalculator {
|
||||
}
|
||||
}
|
||||
|
||||
permissions as u32
|
||||
permissions
|
||||
}
|
||||
|
||||
pub fn as_permission(self) -> MemberPermissions<[u32; 1]> {
|
||||
|
||||
@@ -16,6 +16,33 @@ pub struct UserRef {
|
||||
}
|
||||
|
||||
impl UserRef {
|
||||
pub fn from(id: String) -> Option<UserRef> {
|
||||
match database::get_collection("users").find_one(
|
||||
doc! { "_id": id },
|
||||
FindOneOptions::builder()
|
||||
.projection(doc! {
|
||||
"_id": 1,
|
||||
"username": 1,
|
||||
"email_verification.verified": 1,
|
||||
})
|
||||
.build(),
|
||||
) {
|
||||
Ok(result) => match result {
|
||||
Some(doc) => Some(UserRef {
|
||||
id: doc.get_str("_id").unwrap().to_string(),
|
||||
username: doc.get_str("username").unwrap().to_string(),
|
||||
email_verified: doc
|
||||
.get_document("email_verification")
|
||||
.unwrap()
|
||||
.get_bool("verified")
|
||||
.unwrap(),
|
||||
}),
|
||||
None => None,
|
||||
},
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fetch_data(&self, projection: Document) -> Option<Document> {
|
||||
database::get_collection("users")
|
||||
.find_one(
|
||||
@@ -126,30 +153,8 @@ impl<'r> FromParam<'r> for UserRef {
|
||||
type Error = &'r RawStr;
|
||||
|
||||
fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
|
||||
let col = database::get_db().collection("users");
|
||||
let result = database::get_collection("users")
|
||||
.find_one(
|
||||
doc! { "_id": param.to_string() },
|
||||
FindOneOptions::builder()
|
||||
.projection(doc! {
|
||||
"_id": 1,
|
||||
"username": 1,
|
||||
"email_verification.verified": 1,
|
||||
})
|
||||
.build(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
if let Some(user) = result {
|
||||
Ok(UserRef {
|
||||
id: user.get_str("_id").unwrap().to_string(),
|
||||
username: user.get_str("username").unwrap().to_string(),
|
||||
email_verified: user
|
||||
.get_document("email_verification")
|
||||
.unwrap()
|
||||
.get_bool("verified")
|
||||
.unwrap(),
|
||||
})
|
||||
if let Some(user) = UserRef::from(param.to_string()) {
|
||||
Ok(user)
|
||||
} else {
|
||||
Err(param)
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ pub struct ChannelRef {
|
||||
// information required for permission calculations
|
||||
pub recipients: Option<Vec<String>>,
|
||||
pub guild: Option<String>,
|
||||
pub owner: Option<String>,
|
||||
}
|
||||
|
||||
impl ChannelRef {
|
||||
|
||||
@@ -7,7 +7,7 @@ use bson::{bson, doc, from_bson, Bson::UtcDatetime};
|
||||
use chrono::prelude::*;
|
||||
use database::user::User;
|
||||
use rand::{distributions::Alphanumeric, Rng};
|
||||
use rocket_contrib::json::{Json, JsonValue};
|
||||
use rocket_contrib::json::Json;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ulid::Ulid;
|
||||
use validator::validate_email;
|
||||
@@ -167,7 +167,7 @@ pub fn resend_email(info: Json<Resend>) -> Response {
|
||||
doc! { "email_verification.target": info.email.clone() },
|
||||
None,
|
||||
)
|
||||
.expect("Failed user lookup")
|
||||
.expect("Failed user lookup.")
|
||||
{
|
||||
let user: User = from_bson(bson::Bson::Document(u)).expect("Failed to unwrap user.");
|
||||
let ev = user.email_verification;
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
use super::Response;
|
||||
use crate::database::{self, message::Message, Permission, PermissionCalculator};
|
||||
use crate::database::{
|
||||
self, get_relationship_internal, message::Message, Permission, PermissionCalculator,
|
||||
Relationship,
|
||||
};
|
||||
use crate::guards::auth::UserRef;
|
||||
use crate::guards::channel::ChannelRef;
|
||||
|
||||
use bson::{bson, doc, from_bson, Bson::UtcDatetime};
|
||||
use bson::{bson, doc, from_bson, Bson, Bson::UtcDatetime};
|
||||
use chrono::prelude::*;
|
||||
use hashbrown::HashSet;
|
||||
use num_enum::TryFromPrimitive;
|
||||
use rocket_contrib::json::Json;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ulid::Ulid;
|
||||
|
||||
const MAXGROUPSIZE: usize = 50;
|
||||
|
||||
#[derive(Debug, TryFromPrimitive)]
|
||||
#[repr(usize)]
|
||||
pub enum ChannelType {
|
||||
@@ -32,6 +38,71 @@ macro_rules! with_permissions {
|
||||
}};
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CreateGroup {
|
||||
name: String,
|
||||
nonce: String,
|
||||
users: Vec<String>,
|
||||
}
|
||||
|
||||
/// create a new group
|
||||
#[post("/create", data = "<info>")]
|
||||
pub fn create_group(user: UserRef, info: Json<CreateGroup>) -> Response {
|
||||
let name: String = info.name.chars().take(32).collect();
|
||||
let nonce: String = info.nonce.chars().take(32).collect();
|
||||
|
||||
let mut set = HashSet::new();
|
||||
set.insert(user.id.clone());
|
||||
for item in &info.users {
|
||||
set.insert(item.clone());
|
||||
}
|
||||
|
||||
if set.len() > MAXGROUPSIZE {
|
||||
return Response::BadRequest(json!({ "error": "Maximum group size is 50." }));
|
||||
}
|
||||
|
||||
let col = database::get_collection("channels");
|
||||
if let Some(_) = col.find_one(doc! { "nonce": nonce.clone() }, None).unwrap() {
|
||||
return Response::BadRequest(json!({ "error": "Group already created!" }));
|
||||
}
|
||||
|
||||
let relationships = user.fetch_relationships();
|
||||
|
||||
let mut users = vec![];
|
||||
for item in set {
|
||||
if let Some(target) = UserRef::from(item) {
|
||||
if get_relationship_internal(&user.id, &target.id, &relationships)
|
||||
!= Relationship::Friend
|
||||
{
|
||||
return Response::BadRequest(json!({ "error": "Not friends with user(s)." }));
|
||||
}
|
||||
|
||||
users.push(Bson::String(target.id));
|
||||
} else {
|
||||
return Response::BadRequest(json!({ "error": "Specified non-existant user(s)." }));
|
||||
}
|
||||
}
|
||||
|
||||
let id = Ulid::new().to_string();
|
||||
if col
|
||||
.insert_one(
|
||||
doc! {
|
||||
"_id": id.clone(),
|
||||
"nonce": nonce,
|
||||
"type": ChannelType::GROUPDM as u32,
|
||||
"recipients": users,
|
||||
"name": name,
|
||||
},
|
||||
None,
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
Response::Success(json!({ "id": id }))
|
||||
} else {
|
||||
Response::InternalServerError(json!({ "error": "Failed to create guild channel." }))
|
||||
}
|
||||
}
|
||||
|
||||
/// fetch channel information
|
||||
#[get("/<target>")]
|
||||
pub fn channel(user: UserRef, target: ChannelRef) -> Option<Response> {
|
||||
@@ -71,20 +142,25 @@ pub fn delete(user: UserRef, target: ChannelRef) -> Option<Response> {
|
||||
let permissions = with_permissions!(user, target);
|
||||
|
||||
if !permissions.get_manage_channels() {
|
||||
return Some(Response::LackingPermission(Permission::MANAGE_CHANNELS));
|
||||
return Some(Response::LackingPermission(Permission::ManageChannels));
|
||||
}
|
||||
|
||||
let col = database::get_collection("channels");
|
||||
match target.channel_type {
|
||||
0 => {
|
||||
if col.update_one(
|
||||
doc! { "_id": target.id },
|
||||
doc! { "$set": { "active": false } },
|
||||
None,
|
||||
).is_ok() {
|
||||
if col
|
||||
.update_one(
|
||||
doc! { "_id": target.id },
|
||||
doc! { "$set": { "active": false } },
|
||||
None,
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
Some(Response::Result(super::Status::Ok))
|
||||
} else {
|
||||
Some(Response::InternalServerError(json!({ "error": "Failed to close channel." })))
|
||||
Some(Response::InternalServerError(
|
||||
json!({ "error": "Failed to close channel." }),
|
||||
))
|
||||
}
|
||||
}
|
||||
1 => {
|
||||
@@ -109,7 +185,7 @@ pub fn messages(user: UserRef, target: ChannelRef) -> Option<Response> {
|
||||
let permissions = with_permissions!(user, target);
|
||||
|
||||
if !permissions.get_read_messages() {
|
||||
return Some(Response::LackingPermission(Permission::READ_MESSAGES));
|
||||
return Some(Response::LackingPermission(Permission::ReadMessages));
|
||||
}
|
||||
|
||||
let col = database::get_collection("messages");
|
||||
@@ -146,7 +222,7 @@ pub fn send_message(
|
||||
let permissions = with_permissions!(user, target);
|
||||
|
||||
if !permissions.get_send_messages() {
|
||||
return Some(Response::LackingPermission(Permission::SEND_MESSAGES));
|
||||
return Some(Response::LackingPermission(Permission::SendMessages));
|
||||
}
|
||||
|
||||
let content: String = message.content.chars().take(2000).collect();
|
||||
@@ -214,7 +290,7 @@ pub fn get_message(user: UserRef, target: ChannelRef, message: Message) -> Optio
|
||||
let permissions = with_permissions!(user, target);
|
||||
|
||||
if !permissions.get_read_messages() {
|
||||
return Some(Response::LackingPermission(Permission::READ_MESSAGES));
|
||||
return Some(Response::LackingPermission(Permission::ReadMessages));
|
||||
}
|
||||
|
||||
let prev =
|
||||
@@ -317,7 +393,7 @@ pub fn delete_message(user: UserRef, target: ChannelRef, message: Message) -> Op
|
||||
|
||||
if !permissions.get_manage_messages() {
|
||||
if message.author != user.id {
|
||||
return Some(Response::LackingPermission(Permission::MANAGE_MESSAGES));
|
||||
return Some(Response::LackingPermission(Permission::ManageMessages));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,11 @@ use crate::database::{
|
||||
self,
|
||||
channel::Channel,
|
||||
guild::{find_member_permissions, Guild},
|
||||
user::User,
|
||||
};
|
||||
use crate::guards::auth::UserRef;
|
||||
|
||||
use bson::{bson, doc, from_bson, Bson};
|
||||
use rocket_contrib::json::{Json, JsonValue};
|
||||
use rocket_contrib::json::Json;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ulid::Ulid;
|
||||
|
||||
@@ -126,7 +125,7 @@ pub fn create_guild(user: UserRef, info: Json<CreateGuild>) -> Response {
|
||||
|
||||
let id = Ulid::new().to_string();
|
||||
let channel_id = Ulid::new().to_string();
|
||||
if let Err(_) = channels.insert_one(
|
||||
if channels.insert_one(
|
||||
doc! {
|
||||
"_id": channel_id.clone(),
|
||||
"type": ChannelType::GUILDCHANNEL as u32,
|
||||
@@ -134,7 +133,7 @@ pub fn create_guild(user: UserRef, info: Json<CreateGuild>) -> Response {
|
||||
"guild": id.clone(),
|
||||
},
|
||||
None,
|
||||
) {
|
||||
).is_err() {
|
||||
return Response::InternalServerError(
|
||||
json!({ "error": "Failed to create guild channel." }),
|
||||
);
|
||||
|
||||
@@ -87,6 +87,7 @@ pub fn mount(rocket: Rocket) -> Rocket {
|
||||
.mount(
|
||||
"/api/channels",
|
||||
routes![
|
||||
channel::create_group,
|
||||
channel::channel,
|
||||
channel::delete,
|
||||
channel::messages,
|
||||
|
||||
@@ -64,7 +64,7 @@ pub fn lookup(user: UserRef, query: Json<Query>) -> Response {
|
||||
if let Ok(doc) = item {
|
||||
let id = doc.get_str("id").unwrap();
|
||||
results.push(json!({
|
||||
"id": id.clone(),
|
||||
"id": id,
|
||||
"username": doc.get_str("username").unwrap(),
|
||||
"relationship": get_relationship_internal(&user.id, &id, &relationships) as u8
|
||||
}));
|
||||
@@ -174,11 +174,11 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response {
|
||||
let col = database::get_collection("users");
|
||||
|
||||
match relationship {
|
||||
Relationship::FRIEND => Response::BadRequest(json!({ "error": "Already friends." })),
|
||||
Relationship::OUTGOING => {
|
||||
Relationship::Friend => Response::BadRequest(json!({ "error": "Already friends." })),
|
||||
Relationship::Outgoing => {
|
||||
Response::BadRequest(json!({ "error": "Already sent a friend request." }))
|
||||
}
|
||||
Relationship::INCOMING => {
|
||||
Relationship::Incoming => {
|
||||
if col
|
||||
.update_one(
|
||||
doc! {
|
||||
@@ -187,7 +187,7 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response {
|
||||
},
|
||||
doc! {
|
||||
"$set": {
|
||||
"relations.$.status": Relationship::FRIEND as i32
|
||||
"relations.$.status": Relationship::Friend as i32
|
||||
}
|
||||
},
|
||||
None,
|
||||
@@ -202,14 +202,14 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response {
|
||||
},
|
||||
doc! {
|
||||
"$set": {
|
||||
"relations.$.status": Relationship::FRIEND as i32
|
||||
"relations.$.status": Relationship::Friend as i32
|
||||
}
|
||||
},
|
||||
None,
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
Response::Success(json!({ "status": Relationship::FRIEND as u8 }))
|
||||
Response::Success(json!({ "status": Relationship::Friend as u8 }))
|
||||
} else {
|
||||
Response::InternalServerError(
|
||||
json!({ "error": "Failed to commit! Try re-adding them as a friend." }),
|
||||
@@ -221,10 +221,10 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response {
|
||||
)
|
||||
}
|
||||
}
|
||||
Relationship::BLOCKED => {
|
||||
Relationship::Blocked => {
|
||||
Response::BadRequest(json!({ "error": "You have blocked this person." }))
|
||||
}
|
||||
Relationship::BLOCKEDOTHER => {
|
||||
Relationship::BlockedOther => {
|
||||
Response::Conflict(json!({ "error": "You have been blocked by this person." }))
|
||||
}
|
||||
Relationship::NONE => {
|
||||
@@ -237,7 +237,7 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response {
|
||||
"$push": {
|
||||
"relations": {
|
||||
"id": target.id.clone(),
|
||||
"status": Relationship::OUTGOING as i32
|
||||
"status": Relationship::Outgoing as i32
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -254,7 +254,7 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response {
|
||||
"$push": {
|
||||
"relations": {
|
||||
"id": user.id,
|
||||
"status": Relationship::INCOMING as i32
|
||||
"status": Relationship::Incoming as i32
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -262,7 +262,7 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response {
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
Response::Success(json!({ "status": Relationship::OUTGOING as u8 }))
|
||||
Response::Success(json!({ "status": Relationship::Outgoing as u8 }))
|
||||
} else {
|
||||
Response::InternalServerError(
|
||||
json!({ "error": "Failed to commit! Try re-adding them as a friend." }),
|
||||
@@ -287,7 +287,7 @@ pub fn remove_friend(user: UserRef, target: UserRef) -> Response {
|
||||
let col = database::get_collection("users");
|
||||
|
||||
match relationship {
|
||||
Relationship::FRIEND | Relationship::OUTGOING | Relationship::INCOMING => {
|
||||
Relationship::Friend | Relationship::Outgoing | Relationship::Incoming => {
|
||||
if col
|
||||
.update_one(
|
||||
doc! {
|
||||
@@ -332,8 +332,8 @@ pub fn remove_friend(user: UserRef, target: UserRef) -> Response {
|
||||
)
|
||||
}
|
||||
}
|
||||
Relationship::BLOCKED
|
||||
| Relationship::BLOCKEDOTHER
|
||||
Relationship::Blocked
|
||||
| Relationship::BlockedOther
|
||||
| Relationship::NONE
|
||||
| Relationship::SELF => Response::BadRequest(json!({ "error": "This has no effect." })),
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ impl Handler for Server {
|
||||
if let Value::String(packet_type) = &data["type"] {
|
||||
match packet_type.as_str() {
|
||||
"authenticate" => {
|
||||
if let Some(_) = self.id {
|
||||
if self.id.is_some() {
|
||||
self.out.send(
|
||||
json!({
|
||||
"type": "authenticate",
|
||||
@@ -152,7 +152,7 @@ impl Handler for Server {
|
||||
|
||||
pub fn launch_server() {
|
||||
unsafe {
|
||||
if let Err(_) = CLIENTS.set(RwLock::new(HashMap::new())) {
|
||||
if CLIENTS.set(RwLock::new(HashMap::new())).is_err() {
|
||||
panic!("Failed to set CLIENTS map!");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user