2023-07-23 21:31:13 +00:00
using SharpChat.Events ;
using SharpChat.EventStorage ;
2022-08-30 15:00:58 +00:00
using SharpChat.Packet ;
using System ;
using System.Collections.Generic ;
2023-02-10 06:07:59 +00:00
using System.Linq ;
2023-02-16 22:33:48 +00:00
using System.Net ;
2023-02-19 22:27:08 +00:00
using System.Threading ;
2022-08-30 15:00:58 +00:00
2024-05-09 21:31:19 +00:00
namespace SharpChat {
2023-02-10 06:07:59 +00:00
public class ChatContext {
2023-02-17 19:02:35 +00:00
public record ChannelUserAssoc ( long UserId , string ChannelName ) ;
2023-02-19 22:27:08 +00:00
public readonly SemaphoreSlim ContextAccess = new ( 1 , 1 ) ;
2022-08-30 15:00:58 +00:00
2024-05-19 02:17:51 +00:00
public Dictionary < string , ChannelInfo > Channels { get ; } = new ( ) ;
public List < ConnectionInfo > Connections { get ; } = new ( ) ;
public Dictionary < long , UserInfo > Users { get ; } = new ( ) ;
2023-02-10 06:07:59 +00:00
public IEventStorage Events { get ; }
2023-02-17 19:02:35 +00:00
public HashSet < ChannelUserAssoc > ChannelUsers { get ; } = new ( ) ;
2023-02-19 22:27:08 +00:00
public Dictionary < long , RateLimiter > UserRateLimiters { get ; } = new ( ) ;
2024-05-19 02:17:51 +00:00
public Dictionary < long , ChannelInfo > UserLastChannel { get ; } = new ( ) ;
2023-02-17 19:02:35 +00:00
2023-02-10 06:07:59 +00:00
public ChatContext ( IEventStorage evtStore ) {
2024-05-19 01:53:14 +00:00
Events = evtStore ;
2022-08-30 15:00:58 +00:00
}
2023-07-23 21:31:13 +00:00
public void DispatchEvent ( IChatEvent eventInfo ) {
if ( eventInfo is MessageCreateEvent mce ) {
if ( mce . IsBroadcast ) {
2024-05-14 22:17:25 +00:00
Send ( new MessageBroadcastPacket ( mce . MessageText ) ) ;
2023-07-23 21:31:13 +00:00
} else if ( mce . IsPrivate ) {
// The channel name returned by GetDMChannelName should not be exposed to the user, instead @<Target User> should be displayed
// e.g. nook sees @Arysil and Arysil sees @nook
// this entire routine is garbage, channels should probably in the db
2024-05-10 19:18:55 +00:00
if ( mce . ChannelName ? . StartsWith ( "@" ) ! = true )
2023-07-23 21:31:13 +00:00
return ;
2024-05-19 01:53:14 +00:00
long [ ] targetIds = mce . ChannelName [ 1. . ] . Split ( '-' , 3 ) . Select ( u = > long . TryParse ( u , out long up ) ? up : - 1 ) . ToArray ( ) ;
if ( targetIds . Length ! = 2 )
2023-07-23 21:31:13 +00:00
return ;
2024-05-19 02:17:51 +00:00
UserInfo [ ] users = Users . Where ( kvp = > targetIds . Contains ( kvp . Key ) ) . Select ( kvp = > kvp . Value ) . ToArray ( ) ;
UserInfo ? target = users . FirstOrDefault ( u = > u . UserId ! = mce . SenderId ) ;
2023-07-23 21:31:13 +00:00
if ( target = = null )
return ;
2024-05-19 02:17:51 +00:00
foreach ( UserInfo user in users )
2024-05-14 22:17:25 +00:00
SendTo ( user , new MessageAddPacket (
2023-07-23 21:31:13 +00:00
mce . MessageId ,
DateTimeOffset . Now ,
mce . SenderId ,
mce . SenderId = = user . UserId ? $"{target.LegacyName} {mce.MessageText}" : mce . MessageText ,
mce . IsAction ,
true
) ) ;
} else {
2024-05-19 02:17:51 +00:00
ChannelInfo ? channel = Channels . Values . FirstOrDefault ( c = > c . NameEquals ( mce . ChannelName ) ) ;
2024-05-10 19:18:55 +00:00
if ( channel ! = null )
2024-05-14 22:17:25 +00:00
SendTo ( channel , new MessageAddPacket (
2024-05-10 19:18:55 +00:00
mce . MessageId ,
DateTimeOffset . Now ,
mce . SenderId ,
mce . MessageText ,
mce . IsAction ,
false
) ) ;
2023-07-23 21:31:13 +00:00
}
Events . AddEvent (
mce . MessageId , "msg:add" ,
mce . ChannelName ,
mce . SenderId , mce . SenderName , mce . SenderColour , mce . SenderRank , mce . SenderNickName , mce . SenderPerms ,
new { text = mce . MessageText } ,
( mce . IsBroadcast ? StoredEventFlags . Broadcast : 0 )
| ( mce . IsAction ? StoredEventFlags . Action : 0 )
| ( mce . IsPrivate ? StoredEventFlags . Private : 0 )
) ;
return ;
}
}
2022-08-30 15:00:58 +00:00
public void Update ( ) {
2024-05-19 02:17:51 +00:00
foreach ( ConnectionInfo conn in Connections )
2023-02-19 22:27:08 +00:00
if ( ! conn . IsDisposed & & conn . HasTimedOut ) {
conn . Dispose ( ) ;
Logger . Write ( $"Nuked connection {conn.Id} associated with {conn.User}." ) ;
}
2024-05-19 01:53:14 +00:00
int removed = Connections . RemoveAll ( conn = > conn . IsDisposed ) ;
if ( removed > 0 )
Logger . Write ( $"Removed {removed} nuked connections from the list." ) ;
2023-02-19 22:27:08 +00:00
2024-05-19 02:17:51 +00:00
foreach ( UserInfo user in Users . Values )
2023-02-19 22:27:08 +00:00
if ( ! Connections . Any ( conn = > conn . User = = user ) ) {
2024-05-19 02:17:51 +00:00
HandleDisconnect ( user , UserDisconnectReason . TimeOut ) ;
2023-02-19 22:27:08 +00:00
Logger . Write ( $"Timed out {user} (no more connections)." ) ;
}
}
public void SafeUpdate ( ) {
ContextAccess . Wait ( ) ;
try {
Update ( ) ;
} finally {
ContextAccess . Release ( ) ;
2023-02-16 22:33:48 +00:00
}
2022-08-30 15:00:58 +00:00
}
2024-05-19 02:17:51 +00:00
public bool IsInChannel ( UserInfo ? user , ChannelInfo ? channel ) {
2024-05-10 19:18:55 +00:00
return user ! = null
& & channel ! = null
& & ChannelUsers . Contains ( new ChannelUserAssoc ( user . UserId , channel . Name ) ) ;
2023-02-17 19:02:35 +00:00
}
2024-05-19 02:17:51 +00:00
public string [ ] GetUserChannelNames ( UserInfo user ) {
2023-02-19 22:27:08 +00:00
return ChannelUsers . Where ( cu = > cu . UserId = = user . UserId ) . Select ( cu = > cu . ChannelName ) . ToArray ( ) ;
2023-02-17 19:02:35 +00:00
}
2024-05-19 02:17:51 +00:00
public ChannelInfo [ ] GetUserChannels ( UserInfo user ) {
2023-02-17 19:02:35 +00:00
string [ ] names = GetUserChannelNames ( user ) ;
2024-05-19 01:53:14 +00:00
return Channels . Values . Where ( c = > names . Any ( n = > c . NameEquals ( n ) ) ) . ToArray ( ) ;
2023-02-17 19:02:35 +00:00
}
2024-05-19 02:17:51 +00:00
public long [ ] GetChannelUserIds ( ChannelInfo channel ) {
2023-02-19 22:27:08 +00:00
return ChannelUsers . Where ( cu = > channel . NameEquals ( cu . ChannelName ) ) . Select ( cu = > cu . UserId ) . ToArray ( ) ;
2023-02-17 19:02:35 +00:00
}
2024-05-19 02:17:51 +00:00
public UserInfo [ ] GetChannelUsers ( ChannelInfo channel ) {
2024-05-19 01:53:14 +00:00
long [ ] targetIds = GetChannelUserIds ( channel ) ;
return Users . Values . Where ( u = > targetIds . Contains ( u . UserId ) ) . ToArray ( ) ;
2023-02-17 19:02:35 +00:00
}
2023-02-22 00:28:53 +00:00
public void UpdateUser (
2024-05-19 02:17:51 +00:00
UserInfo user ,
2024-05-10 19:18:55 +00:00
string? userName = null ,
string? nickName = null ,
2024-05-19 02:17:51 +00:00
Colour ? colour = null ,
UserStatus ? status = null ,
2024-05-10 19:18:55 +00:00
string? statusText = null ,
2023-02-22 00:28:53 +00:00
int? rank = null ,
2024-05-19 02:17:51 +00:00
UserPermissions ? perms = null ,
2023-11-07 14:49:12 +00:00
bool? isSuper = null ,
2023-02-22 00:28:53 +00:00
bool silent = false
) {
bool hasChanged = false ;
2024-05-10 19:18:55 +00:00
string? previousName = null ;
2023-02-22 00:28:53 +00:00
if ( userName ! = null & & ! user . UserName . Equals ( userName ) ) {
user . UserName = userName ;
hasChanged = true ;
}
if ( nickName ! = null & & ! user . NickName . Equals ( nickName ) ) {
if ( ! silent )
previousName = string . IsNullOrWhiteSpace ( user . NickName ) ? user . UserName : user . NickName ;
user . NickName = nickName ;
hasChanged = true ;
}
2024-05-19 01:53:14 +00:00
if ( colour . HasValue & & user . Colour . Equals ( colour . Value ) ) {
2023-02-22 00:28:53 +00:00
user . Colour = colour . Value ;
hasChanged = true ;
}
if ( status . HasValue & & user . Status ! = status . Value ) {
user . Status = status . Value ;
hasChanged = true ;
}
if ( statusText ! = null & & ! user . StatusText . Equals ( statusText ) ) {
user . StatusText = statusText ;
hasChanged = true ;
}
if ( rank ! = null & & user . Rank ! = rank ) {
user . Rank = ( int ) rank ;
hasChanged = true ;
}
if ( perms . HasValue & & user . Permissions ! = perms ) {
user . Permissions = perms . Value ;
hasChanged = true ;
}
2023-11-07 14:49:12 +00:00
if ( isSuper . HasValue ) {
user . IsSuper = isSuper . Value ;
hasChanged = true ;
}
2024-05-10 15:07:56 +00:00
if ( hasChanged ) {
if ( previousName ! = null )
SendToUserChannels ( user , new UserUpdateNotificationPacket ( previousName , user . LegacyNameWithStatus ) ) ;
2024-05-10 18:29:48 +00:00
SendToUserChannels ( user , new UserUpdatePacket (
user . UserId ,
user . LegacyNameWithStatus ,
user . Colour ,
user . Rank ,
user . Permissions
) ) ;
2024-05-10 15:07:56 +00:00
}
2023-02-22 00:28:53 +00:00
}
2024-05-19 02:17:51 +00:00
public void BanUser ( UserInfo user , TimeSpan duration , UserDisconnectReason reason = UserDisconnectReason . Kicked ) {
2024-05-09 21:31:19 +00:00
if ( duration > TimeSpan . Zero ) {
2023-07-23 21:45:10 +00:00
DateTimeOffset expires = duration > = TimeSpan . MaxValue ? DateTimeOffset . MaxValue : DateTimeOffset . Now + duration ;
2024-05-10 17:28:52 +00:00
SendTo ( user , new ForceDisconnectPacket ( expires ) ) ;
2023-07-23 21:45:10 +00:00
} else
2024-05-10 17:28:52 +00:00
SendTo ( user , new ForceDisconnectPacket ( ) ) ;
2023-02-16 22:33:48 +00:00
2024-05-19 02:17:51 +00:00
foreach ( ConnectionInfo conn in Connections )
2023-02-19 22:27:08 +00:00
if ( conn . User = = user )
conn . Dispose ( ) ;
2024-05-19 01:53:14 +00:00
Connections . RemoveAll ( conn = > conn . IsDisposed ) ;
2022-08-30 15:00:58 +00:00
2023-02-17 19:02:35 +00:00
HandleDisconnect ( user , reason ) ;
2022-08-30 15:00:58 +00:00
}
2024-05-14 22:56:56 +00:00
public void HandleChannelEventLog ( string channelName , Action < IServerPacket > handler ) {
foreach ( StoredEventInfo msg in Events . GetChannelEventLog ( channelName ) )
handler ( msg . Type switch {
"user:connect" = > new UserConnectLogPacket ( msg . Created , msg . Sender ? . LegacyName ? ? string . Empty ) ,
"user:disconnect" = > new UserDisconnectLogPacket (
msg . Created ,
msg . Sender ? . LegacyNameWithStatus ? ? string . Empty ,
2024-05-19 02:17:51 +00:00
( UserDisconnectReason ) msg . Data . RootElement . GetProperty ( "reason" ) . GetByte ( )
2024-05-14 22:56:56 +00:00
) ,
_ = > new MessagePopulatePacket ( msg ) ,
} ) ;
}
2024-05-19 02:17:51 +00:00
public void HandleJoin ( UserInfo user , ChannelInfo chan , ConnectionInfo conn , int maxMsgLength ) {
2023-02-19 22:27:08 +00:00
if ( ! IsInChannel ( user , chan ) ) {
2024-05-10 18:29:48 +00:00
SendTo ( chan , new UserConnectPacket (
DateTimeOffset . Now ,
user . UserId ,
user . LegacyNameWithStatus ,
user . Colour ,
user . Rank ,
user . Permissions
) ) ;
2023-02-23 21:46:49 +00:00
Events . AddEvent ( "user:connect" , user , chan , flags : StoredEventFlags . Log ) ;
2023-02-19 22:27:08 +00:00
}
2022-08-30 15:00:58 +00:00
2024-05-10 18:29:48 +00:00
conn . Send ( new AuthSuccessPacket (
user . UserId ,
user . LegacyNameWithStatus ,
user . Colour ,
user . Rank ,
user . Permissions ,
chan . Name ,
maxMsgLength
) ) ;
2024-05-14 22:17:25 +00:00
conn . Send ( new UsersPopulatePacket ( GetChannelUsers ( chan ) . Except ( new [ ] { user } ) . Select (
user = > new UsersPopulatePacket . ListEntry ( user . UserId , user . LegacyNameWithStatus , user . Colour , user . Rank , user . Permissions , true )
2024-05-10 18:29:48 +00:00
) . OrderByDescending ( user = > user . Rank ) . ToArray ( ) ) ) ;
2022-08-30 15:00:58 +00:00
2024-05-14 22:56:56 +00:00
HandleChannelEventLog ( chan . Name , p = > conn . Send ( p ) ) ;
2022-08-30 15:00:58 +00:00
2024-05-19 01:53:14 +00:00
conn . Send ( new ChannelsPopulatePacket ( Channels . Values . Where ( c = > c . Rank < = user . Rank ) . Select (
2024-05-14 22:17:25 +00:00
channel = > new ChannelsPopulatePacket . ListEntry ( channel . Name , channel . HasPassword , channel . IsTemporary )
2024-05-10 18:29:48 +00:00
) . ToArray ( ) ) ) ;
2022-08-30 15:00:58 +00:00
2024-05-19 01:53:14 +00:00
Users . Add ( user . UserId , user ) ;
2023-02-17 19:02:35 +00:00
2023-02-19 22:27:08 +00:00
ChannelUsers . Add ( new ChannelUserAssoc ( user . UserId , chan . Name ) ) ;
2023-02-22 00:28:53 +00:00
UserLastChannel [ user . UserId ] = chan ;
2022-08-30 15:00:58 +00:00
}
2024-05-19 02:17:51 +00:00
public void HandleDisconnect ( UserInfo user , UserDisconnectReason reason = UserDisconnectReason . Leave ) {
UpdateUser ( user , status : UserStatus . Offline ) ;
2024-05-19 01:53:14 +00:00
Users . Remove ( user . UserId ) ;
2023-02-22 00:28:53 +00:00
UserLastChannel . Remove ( user . UserId ) ;
2022-08-30 15:00:58 +00:00
2024-05-19 02:17:51 +00:00
ChannelInfo [ ] channels = GetUserChannels ( user ) ;
2022-08-30 15:00:58 +00:00
2024-05-19 02:17:51 +00:00
foreach ( ChannelInfo chan in channels ) {
2023-02-19 22:27:08 +00:00
ChannelUsers . Remove ( new ChannelUserAssoc ( user . UserId , chan . Name ) ) ;
2023-02-17 19:02:35 +00:00
2024-05-10 18:29:48 +00:00
SendTo ( chan , new UserDisconnectPacket ( DateTimeOffset . Now , user . UserId , user . LegacyNameWithStatus , reason ) ) ;
2023-02-23 21:46:49 +00:00
Events . AddEvent ( "user:disconnect" , user , chan , new { reason = ( int ) reason } , StoredEventFlags . Log ) ;
2023-02-17 19:02:35 +00:00
2023-02-22 00:28:53 +00:00
if ( chan . IsTemporary & & chan . IsOwner ( user ) )
2023-02-19 22:27:08 +00:00
RemoveChannel ( chan ) ;
2023-02-10 06:07:59 +00:00
}
2022-08-30 15:00:58 +00:00
}
2024-05-19 02:17:51 +00:00
public void SwitchChannel ( UserInfo user , ChannelInfo chan , string password ) {
if ( UserLastChannel . TryGetValue ( user . UserId , out ChannelInfo ? ulc ) & & chan = = ulc ) {
2023-02-16 22:33:48 +00:00
ForceChannel ( user ) ;
2022-08-30 15:00:58 +00:00
return ;
}
2024-05-19 02:17:51 +00:00
if ( ! user . Permissions . HasFlag ( UserPermissions . JoinAnyChannel ) & & chan . IsOwner ( user ) ) {
2023-02-07 15:01:56 +00:00
if ( chan . Rank > user . Rank ) {
2024-05-14 22:17:25 +00:00
SendTo ( user , new ChannelRankTooLowErrorPacket ( chan . Name ) ) ;
2023-02-16 22:33:48 +00:00
ForceChannel ( user ) ;
2022-08-30 15:00:58 +00:00
return ;
}
2024-05-14 22:17:25 +00:00
if ( ! string . IsNullOrEmpty ( chan . Password ) & & chan . Password . Equals ( password ) ) {
SendTo ( user , new ChannelPasswordWrongErrorPacket ( chan . Name ) ) ;
2023-02-16 22:33:48 +00:00
ForceChannel ( user ) ;
2022-08-30 15:00:58 +00:00
return ;
}
}
ForceChannelSwitch ( user , chan ) ;
}
2024-05-19 02:17:51 +00:00
public void ForceChannelSwitch ( UserInfo user , ChannelInfo chan ) {
2024-05-19 01:53:14 +00:00
if ( ! Channels . ContainsValue ( chan ) )
2023-02-19 22:27:08 +00:00
return ;
2022-08-30 15:00:58 +00:00
2024-05-19 02:17:51 +00:00
ChannelInfo oldChan = UserLastChannel [ user . UserId ] ;
2022-08-30 15:00:58 +00:00
2024-05-10 18:29:48 +00:00
SendTo ( oldChan , new UserChannelLeavePacket ( user . UserId ) ) ;
2023-02-23 21:46:49 +00:00
Events . AddEvent ( "chan:leave" , user , oldChan , flags : StoredEventFlags . Log ) ;
2024-05-10 18:29:48 +00:00
SendTo ( chan , new UserChannelJoinPacket ( user . UserId , user . LegacyNameWithStatus , user . Colour , user . Rank , user . Permissions ) ) ;
2023-02-23 21:46:49 +00:00
Events . AddEvent ( "chan:join" , user , oldChan , flags : StoredEventFlags . Log ) ;
2022-08-30 15:00:58 +00:00
2024-05-13 20:55:54 +00:00
SendTo ( user , new ContextClearPacket ( ContextClearPacket . ClearMode . MessagesUsers ) ) ;
2024-05-14 22:17:25 +00:00
SendTo ( user , new UsersPopulatePacket ( GetChannelUsers ( chan ) . Except ( new [ ] { user } ) . Select (
user = > new UsersPopulatePacket . ListEntry ( user . UserId , user . LegacyNameWithStatus , user . Colour , user . Rank , user . Permissions , true )
2024-05-10 18:29:48 +00:00
) . OrderByDescending ( u = > u . Rank ) . ToArray ( ) ) ) ;
2022-08-30 15:00:58 +00:00
2024-05-14 22:56:56 +00:00
HandleChannelEventLog ( chan . Name , p = > SendTo ( user , p ) ) ;
2023-02-19 22:27:08 +00:00
ForceChannel ( user , chan ) ;
2023-02-17 19:02:35 +00:00
2023-02-19 22:27:08 +00:00
ChannelUsers . Remove ( new ChannelUserAssoc ( user . UserId , oldChan . Name ) ) ;
ChannelUsers . Add ( new ChannelUserAssoc ( user . UserId , chan . Name ) ) ;
2023-02-22 00:28:53 +00:00
UserLastChannel [ user . UserId ] = chan ;
2022-08-30 15:00:58 +00:00
2023-02-22 00:28:53 +00:00
if ( oldChan . IsTemporary & & oldChan . IsOwner ( user ) )
2023-02-19 22:27:08 +00:00
RemoveChannel ( oldChan ) ;
2022-08-30 15:00:58 +00:00
}
2023-02-10 06:07:59 +00:00
public void Send ( IServerPacket packet ) {
2024-05-19 02:17:51 +00:00
foreach ( ConnectionInfo conn in Connections )
2023-02-19 22:27:08 +00:00
if ( conn . IsAuthed )
conn . Send ( packet ) ;
2023-02-16 22:33:48 +00:00
}
2024-05-19 02:17:51 +00:00
public void SendTo ( UserInfo user , IServerPacket packet ) {
foreach ( ConnectionInfo conn in Connections )
2023-02-19 22:27:08 +00:00
if ( conn . IsAlive & & conn . User = = user )
conn . Send ( packet ) ;
2023-02-16 22:33:48 +00:00
}
2024-05-19 02:17:51 +00:00
public void SendTo ( ChannelInfo channel , IServerPacket packet ) {
2023-02-17 19:02:35 +00:00
// might be faster to grab the users first and then cascade into that SendTo
2024-05-19 02:17:51 +00:00
IEnumerable < ConnectionInfo > conns = Connections . Where ( c = > c . IsAuthed & & IsInChannel ( c . User , channel ) ) ;
foreach ( ConnectionInfo conn in conns )
2023-02-19 22:27:08 +00:00
conn . Send ( packet ) ;
2023-02-16 22:33:48 +00:00
}
2024-05-19 02:17:51 +00:00
public void SendToUserChannels ( UserInfo user , IServerPacket packet ) {
IEnumerable < ChannelInfo > chans = Channels . Values . Where ( c = > IsInChannel ( user , c ) ) ;
IEnumerable < ConnectionInfo > conns = Connections . Where ( conn = > conn . IsAuthed & & ChannelUsers . Any ( cu = > cu . UserId = = conn . User ? . UserId & & chans . Any ( chan = > chan . NameEquals ( cu . ChannelName ) ) ) ) ;
foreach ( ConnectionInfo conn in conns )
2023-02-22 00:28:53 +00:00
conn . Send ( packet ) ;
}
2024-05-19 02:17:51 +00:00
public IPAddress [ ] GetRemoteAddresses ( UserInfo user ) {
2023-02-19 22:27:08 +00:00
return Connections . Where ( c = > c . IsAlive & & c . User = = user ) . Select ( c = > c . RemoteAddress ) . Distinct ( ) . ToArray ( ) ;
2023-02-16 22:33:48 +00:00
}
2024-05-19 02:17:51 +00:00
public void ForceChannel ( UserInfo user , ChannelInfo ? chan = null ) {
2023-02-22 00:28:53 +00:00
if ( chan = = null & & ! UserLastChannel . TryGetValue ( user . UserId , out chan ) )
throw new ArgumentException ( "no channel???" ) ;
2024-05-10 18:29:48 +00:00
SendTo ( user , new UserChannelForceJoinPacket ( chan . Name ) ) ;
2023-02-10 06:07:59 +00:00
}
2022-08-30 15:00:58 +00:00
2024-05-10 19:18:55 +00:00
public void UpdateChannel (
2024-05-19 02:17:51 +00:00
ChannelInfo channel ,
2024-05-10 19:18:55 +00:00
bool? temporary = null ,
int? minRank = null ,
string? password = null
) {
2024-05-19 01:53:14 +00:00
if ( ! Channels . ContainsValue ( channel ) )
2023-02-10 06:07:59 +00:00
throw new ArgumentException ( "Provided channel is not registered with this manager." , nameof ( channel ) ) ;
2022-08-30 15:00:58 +00:00
2024-05-10 18:29:48 +00:00
string prevName = channel . Name ;
2023-02-10 06:07:59 +00:00
if ( temporary . HasValue )
channel . IsTemporary = temporary . Value ;
2024-05-10 18:29:48 +00:00
if ( minRank . HasValue )
channel . Rank = minRank . Value ;
2023-02-10 06:07:59 +00:00
if ( password ! = null )
channel . Password = password ;
2022-08-30 15:00:58 +00:00
2024-05-10 18:29:48 +00:00
// TODO: Users that no longer have access to the channel/gained access to the channel by the rank change should receive delete and create packets respectively
2024-05-19 02:17:51 +00:00
foreach ( UserInfo user in Users . Values . Where ( u = > u . Rank > = channel . Rank ) ) {
2024-05-10 18:29:48 +00:00
SendTo ( user , new ChannelUpdatePacket ( prevName , channel . Name , channel . HasPassword , channel . IsTemporary ) ) ;
2023-02-19 22:27:08 +00:00
}
2023-02-06 20:14:50 +00:00
}
2022-08-30 15:00:58 +00:00
2024-05-19 02:17:51 +00:00
public void RemoveChannel ( ChannelInfo channel ) {
2023-02-10 06:07:59 +00:00
if ( channel = = null | | ! Channels . Any ( ) )
return ;
2024-05-19 02:17:51 +00:00
ChannelInfo ? defaultChannel = Channels . Values . FirstOrDefault ( ) ;
2023-02-10 06:07:59 +00:00
if ( defaultChannel = = null )
2022-08-30 15:00:58 +00:00
return ;
2023-02-10 06:07:59 +00:00
// Remove channel from the listing
2024-05-19 01:53:14 +00:00
Channels . Remove ( channel . Name ) ;
2023-02-10 06:07:59 +00:00
// Move all users back to the main channel
// TODO: Replace this with a kick. SCv2 supports being in 0 channels, SCv1 should force the user back to DefaultChannel.
2024-05-19 02:17:51 +00:00
foreach ( UserInfo user in GetChannelUsers ( channel ) )
2023-02-10 06:07:59 +00:00
SwitchChannel ( user , defaultChannel , string . Empty ) ;
// Broadcast deletion of channel
2024-05-19 02:17:51 +00:00
foreach ( UserInfo user in Users . Values . Where ( u = > u . Rank > = channel . Rank ) )
2024-05-10 18:29:48 +00:00
SendTo ( user , new ChannelDeletePacket ( channel . Name ) ) ;
2022-08-30 15:00:58 +00:00
}
}
}