irc-fun-client-0.2.0.0: src/Network/IRC/Fun/Client/NickTracker.hs
{- This file is part of irc-fun-client.
-
- Written in 2015 by fr33domlover <fr33domlover@rel4tion.org>.
-
- ♡ Copying is an act of love. Please copy, reuse and share.
-
- The author(s) have dedicated all copyright and related and neighboring
- rights to this software to the public domain worldwide. This software is
- distributed without any warranty.
-
- You should have received a copy of the CC0 Public Domain Dedication along
- with this software. If not, see
- <http://creativecommons.org/publicdomain/zero/1.0/>.
-}
-- | Using the tools provided here, you can track which users are members of
-- which channels. This functionality has a variety of uses, e.g. displaying
-- user lists in client UI and logging/displaying quit messages in the correct
-- channel logs/buffers.
module Network.IRC.Fun.Client.NickTracker
( ChannelTracker (..)
, NetworkTracker (..)
, isMemberOf
, isInChannel
, presence
, newChannel
, newNetwork
, addMember
, addToChannel
, changeNick
, addChannel
, removeMember
, removeFromChannel
, removeFromNetwork
, removeChannel
, removeChannels
)
where
import qualified Data.HashMap.Lazy as M
import qualified Data.HashSet as S
import Network.IRC.Fun.Messages.TypeAliases
newtype ChannelTracker = ChannelTracker (S.HashSet NickName)
newtype NetworkTracker = NetworkTracker (M.HashMap ChannelName ChannelTracker)
-- | Check whether a nickname is present in a channel.
isMemberOf :: NickName -> ChannelTracker -> Bool
nick `isMemberOf` (ChannelTracker nicks) = nick `S.member` nicks
-- | Check whether a nickname is present in a channel.
isInChannel :: NickName -> ChannelName -> NetworkTracker -> Bool
isInChannel nick chan (NetworkTracker cts) =
case M.lookup chan cts of
Nothing -> False
Just ct -> nick `isMemberOf` ct
applySnd :: (b -> c) -> (a, b) -> (a, c)
applySnd f (x, y) = (x, f y)
-- | Check in which channels a nickname is present.
presence :: NickName -> NetworkTracker -> [ChannelName]
presence nick (NetworkTracker cts) =
[ chan | (chan, True) <- map (applySnd (nick `isMemberOf`)) $ M.toList cts]
-- | Record a channel with the given present nicknames.
newChannel :: [NickName] -> ChannelTracker
newChannel nicks = ChannelTracker $ S.fromList nicks
-- | Create new tracker.
newNetwork :: NetworkTracker
newNetwork = NetworkTracker $ M.empty
-- | Record a nickname being present in a channel.
addMember :: NickName -> ChannelTracker -> ChannelTracker
addMember nick (ChannelTracker nicks) = ChannelTracker $ S.insert nick nicks
-- | Record a nickname being present in a channel.
addToChannel :: ChannelName -> NickName -> NetworkTracker -> NetworkTracker
addToChannel chan nick (NetworkTracker cts) = NetworkTracker $ f cts
where
f chans =
case M.lookup chan chans of
Nothing ->
let ct = ChannelTracker $ S.singleton nick
in M.insert chan ct chans
Just (ChannelTracker nicks) ->
let ct = ChannelTracker $ S.insert nick nicks
in M.insert chan ct chans
-- | Record a nickname change. Remove old nickname from the channels in which
-- it's present, and add the new nickname to them.
changeNick :: NickName -> NickName -> NetworkTracker -> NetworkTracker
changeNick old new (NetworkTracker cts) = NetworkTracker $ f cts
where
f chans =
let chansP = M.filter (old `isMemberOf`) chans
chansR = M.map (removeMember old) chansP
chansN = M.map (addMember new) chansR
in chansN `M.union` chans
-- | Record a channel with the given present nicknames.
addChannel :: ChannelName -> [NickName] -> NetworkTracker -> NetworkTracker
addChannel chan nicks (NetworkTracker cts) = NetworkTracker $ f cts
where
f = M.insert chan $ newChannel nicks
-- | Record a channel not having a given nickname anymore.
removeMember :: NickName -> ChannelTracker -> ChannelTracker
removeMember nick (ChannelTracker nicks) = ChannelTracker $ S.delete nick nicks
-- | Record a channel not having a given nickname anymore.
removeFromChannel :: ChannelName
-> NickName
-> NetworkTracker
-> NetworkTracker
removeFromChannel chan nick (NetworkTracker cts) = NetworkTracker $ f cts
where
f chans = M.adjust (removeMember nick) chan chans
-- | Record a nickname not being present in any channel anymore.
removeFromNetwork :: NickName -> NetworkTracker -> NetworkTracker
removeFromNetwork nick (NetworkTracker cts) = NetworkTracker $ f cts
where
f = M.map (removeMember nick)
-- | Remove a channel from the tracker.
removeChannel :: ChannelName -> NetworkTracker -> NetworkTracker
removeChannel chan (NetworkTracker cts) = NetworkTracker $ f cts
where
f = M.delete chan
-- | Remove channels from the tracker.
removeChannels :: [ChannelName] -> NetworkTracker -> NetworkTracker
removeChannels chans (NetworkTracker cts) = NetworkTracker $ f cts
where
f ts = ts `M.difference` M.fromList (zip chans (repeat ()))