Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F665850
channels.ex
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
6 KB
Subscribers
None
channels.ex
View Options
defmodule
ExIrc.Channels
do
@moduledoc
"""
Responsible for managing channel state
"""
use
Irc.Commands
import
String
,
only
:
[
downcase
:
1
]
defmodule
Channel
do
defstruct
name
:
''
,
topic
:
''
,
users
:
[],
modes
:
''
,
type
:
''
end
@doc
"""
Initialize a new Channels data store
"""
def
init
()
do
:gb_trees
.
empty
()
end
##################
# Self JOIN/PART
##################
@doc
"""
Add a channel to the data store when joining a channel
"""
def
join
(
channel_tree
,
channel_name
)
do
name
=
downcase
(
channel_name
)
case
:gb_trees
.
lookup
(
name
,
channel_tree
)
do
{
:value
,
_
}
->
channel_tree
:none
->
:gb_trees
.
insert
(
name
,
%
Channel
{
name
:
name
},
channel_tree
)
end
end
@doc
"""
Remove a channel from the data store when leaving a channel
"""
def
part
(
channel_tree
,
channel_name
)
do
name
=
downcase
(
channel_name
)
case
:gb_trees
.
lookup
(
name
,
channel_tree
)
do
{
:value
,
_
}
->
:gb_trees
.
delete
(
name
,
channel_tree
)
:none
->
channel_tree
end
end
###########################
# Channel Modes/Attributes
###########################
@doc
"""
Update the topic for a tracked channel when it changes
"""
def
set_topic
(
channel_tree
,
channel_name
,
topic
)
do
name
=
downcase
(
channel_name
)
case
:gb_trees
.
lookup
(
name
,
channel_tree
)
do
{
:value
,
channel
}
->
:gb_trees
.
enter
(
name
,
%{
channel
|
:topic
=>
topic
},
channel_tree
)
:none
->
channel_tree
end
end
@doc
"""
Update the type of a tracked channel when it changes
"""
def
set_type
(
channel_tree
,
channel_name
,
channel_type
)
when
is_binary
(
channel_type
)
do
set_type
(
channel_tree
,
channel_name
,
String
.
to_char_list
(
channel_type
))
end
def
set_type
(
channel_tree
,
channel_name
,
channel_type
)
do
name
=
downcase
(
channel_name
)
case
:gb_trees
.
lookup
(
name
,
channel_tree
)
do
{
:value
,
channel
}
->
type
=
case
channel_type
do
'@'
->
:secret
'*'
->
:private
'='
->
:public
end
:gb_trees
.
enter
(
name
,
%{
channel
|
:type
=>
type
},
channel_tree
)
:none
->
channel_tree
end
end
####################################
# Users JOIN/PART/AKAs(namechange)
####################################
@doc
"""
Add a user to a tracked channel when they join
"""
def
user_join
(
channel_tree
,
channel_name
,
nick
)
when
not
is_list
(
nick
)
do
users_join
(
channel_tree
,
channel_name
,
[
nick
])
end
@doc
"""
Add multiple users to a tracked channel (used primarily in conjunction with the NAMES command)
"""
def
users_join
(
channel_tree
,
channel_name
,
nicks
)
do
pnicks
=
strip_rank
(
nicks
)
manipfn
=
fn
(
channel_nicks
)
->
:lists
.
usort
(
channel_nicks
++
pnicks
)
end
users_manip
(
channel_tree
,
channel_name
,
manipfn
)
end
@doc
"""
Remove a user from a tracked channel when they leave
"""
def
user_part
(
channel_tree
,
channel_name
,
nick
)
do
pnick
=
strip_rank
([
nick
])
manipfn
=
fn
(
channel_nicks
)
->
:lists
.
usort
(
channel_nicks
--
pnick
)
end
users_manip
(
channel_tree
,
channel_name
,
manipfn
)
end
@doc
"""
Update the nick of a user in a tracked channel when they change their nick
"""
def
user_rename
(
channel_tree
,
nick
,
new_nick
)
do
manipfn
=
fn
(
channel_nicks
)
->
case
Enum
.
member?
(
channel_nicks
,
nick
)
do
true
->
[
new_nick
|
channel_nicks
--
[
nick
]]
|>
Enum
.
uniq
|>
Enum
.
sort
false
->
channel_nicks
end
end
foldl
=
fn
(
channel_name
,
new_channel_tree
)
->
name
=
downcase
(
channel_name
)
users_manip
(
new_channel_tree
,
name
,
manipfn
)
end
:lists
.
foldl
(
foldl
,
channel_tree
,
channels
(
channel_tree
))
end
################
# Introspection
################
@doc
"""
Get a list of all currently tracked channels
"""
def
channels
(
channel_tree
)
do
(
for
{
channel_name
,
_chan
}
<-
:gb_trees
.
to_list
(
channel_tree
),
do
:
channel_name
)
|>
Enum
.
reverse
end
@doc
"""
Get a list of all users in a tracked channel
"""
def
channel_users
(
channel_tree
,
channel_name
)
do
get_attr
(
channel_tree
,
channel_name
,
fn
(%
Channel
{
:users
=>
users
})
->
users
end
)
|>
Enum
.
reverse
end
@doc
"""
Get the current topic for a tracked channel
"""
def
channel_topic
(
channel_tree
,
channel_name
)
do
case
get_attr
(
channel_tree
,
channel_name
,
fn
(%
Channel
{
:topic
=>
topic
})
->
topic
end
)
do
[]
->
"No topic"
topic
->
topic
end
end
@doc
"""
Get the type of a tracked channel
"""
def
channel_type
(
channel_tree
,
channel_name
)
do
case
get_attr
(
channel_tree
,
channel_name
,
fn
(%
Channel
{
:type
=>
type
})
->
type
end
)
do
[]
->
:unknown
type
->
type
end
end
@doc
"""
Determine if a user is present in a tracked channel
"""
def
channel_has_user?
(
channel_tree
,
channel_name
,
nick
)
do
get_attr
(
channel_tree
,
channel_name
,
fn
(%
Channel
{
:users
=>
users
})
->
:lists
.
member
(
nick
,
users
)
end
)
end
@doc
"""
Get all channel data as a tuple of the channel name and a proplist of metadata.
Example Result:
[{"
#
testchannel", [users: ["userA", "userB"], topic: "Just a test channel.", type: :public] }]
"""
def
to_proplist
(
channel_tree
)
do
for
{
channel_name
,
chan
}
<-
:gb_trees
.
to_list
(
channel_tree
)
do
{
channel_name
,
[
users
:
chan
.
users
,
topic
:
chan
.
topic
,
type
:
chan
.
type
]}
end
|>
Enum
.
reverse
end
####################
# Internal API
####################
defp
users_manip
(
channel_tree
,
channel_name
,
manipfn
)
do
name
=
downcase
(
channel_name
)
case
:gb_trees
.
lookup
(
name
,
channel_tree
)
do
{
:value
,
channel
}
->
channel_list
=
manipfn
.
(
channel
.
users
)
:gb_trees
.
enter
(
channel_name
,
%{
channel
|
:users
=>
channel_list
},
channel_tree
)
:none
->
channel_tree
end
end
defp
strip_rank
(
nicks
)
do
nicks
|>
Enum
.
map
(
fn
(
n
)
->
case
n
do
<<
"@"
,
nick
::
binary
>>
->
nick
<<
"+"
,
nick
::
binary
>>
->
nick
<<
"%"
,
nick
::
binary
>>
->
nick
<<
"&"
,
nick
::
binary
>>
->
nick
<<
"~"
,
nick
::
binary
>>
->
nick
nick
->
nick
end
end
)
end
defp
get_attr
(
channel_tree
,
channel_name
,
getfn
)
do
name
=
downcase
(
channel_name
)
case
:gb_trees
.
lookup
(
name
,
channel_tree
)
do
{
:value
,
channel
}
->
getfn
.
(
channel
)
:none
->
{
:error
,
:no_such_channel
}
end
end
end
File Metadata
Details
Attached
Mime Type
text/x-ruby
Expires
Sat, Feb 28, 9:37 AM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
87061
Default Alt Text
channels.ex (6 KB)
Attached To
rEXIRC ExIRC Fork
Event Timeline
Log In to Comment