diff options
author | Théophile Choutri <theophile@choutri.eu> | 2018-01-18 11:02:25 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-18 11:02:25 +0100 |
commit | 4562ee549c7213567585f33e75b8598940b55b86 (patch) | |
tree | 848766537cfb21cfde5b200dcbf4c27ceae8337b | |
parent | Merge pull request #74 from tchoutri/add-whois (diff) |
Fix namespaces and improve internal consistency
-rw-r--r-- | README.md | 46 | ||||
-rw-r--r-- | examples/bot/config/config.exs | 2 | ||||
-rw-r--r-- | examples/bot/lib/bot.ex | 10 | ||||
-rw-r--r-- | examples/ohai/connection_handler.ex | 6 | ||||
-rw-r--r-- | examples/ohai/login_handler.ex | 4 | ||||
-rw-r--r-- | examples/ohai/ohai_handler.ex | 6 | ||||
-rw-r--r-- | examples/ohai/ohai_irc.ex | 2 | ||||
-rw-r--r-- | lib/app.ex | 6 | ||||
-rw-r--r-- | lib/exirc/channels.ex | 4 | ||||
-rw-r--r-- | lib/exirc/client.ex | 111 | ||||
-rw-r--r-- | lib/exirc/commands.ex | 4 | ||||
-rw-r--r-- | lib/exirc/example_handler.ex | 12 | ||||
-rw-r--r-- | lib/exirc/exirc.ex | 30 | ||||
-rw-r--r-- | lib/exirc/irc_message.ex | 2 | ||||
-rw-r--r-- | lib/exirc/logger.ex | 2 | ||||
-rw-r--r-- | lib/exirc/sender_info.ex | 2 | ||||
-rw-r--r-- | lib/exirc/transport.ex | 2 | ||||
-rw-r--r-- | lib/exirc/utils.ex | 18 | ||||
-rw-r--r-- | lib/exirc/whois.ex | 3 | ||||
-rw-r--r-- | mix.exs | 4 | ||||
-rw-r--r-- | test/channels_test.exs | 4 | ||||
-rw-r--r-- | test/client_test.exs | 8 | ||||
-rw-r--r-- | test/commands_test.exs | 6 | ||||
-rw-r--r-- | test/utils_test.exs | 42 |
24 files changed, 178 insertions, 158 deletions
@@ -1,16 +1,16 @@ -# ExIrc +# ExIRC [![Build Status](https://travis-ci.org/bitwalker/exirc.svg?branch=master)](https://travis-ci.org/bitwalker/exirc) [![Hex.pm Version](http://img.shields.io/hexpm/v/exirc.svg?style=flat)](https://hex.pm/packages/exirc) -ExIrc is a IRC client library for Elixir projects. It aims to have a clear, well +ExIRC is a IRC client library for Elixir projects. It aims to have a clear, well documented API, with the minimal amount of code necessary to allow you to connect and communicate with IRC servers effectively. It aims to implement the full RFC2812 protocol, and relevant parts of RFC1459. ## Getting Started -Add ExIrc as a dependency to your project in mix.exs, and add it as an application: +Add ExIRC as a dependency to your project in mix.exs, and add it as an application: ```elixir defp deps do @@ -25,10 +25,10 @@ Add ExIrc as a dependency to your project in mix.exs, and add it as an applicati Then fetch it using `mix deps.get`. -To use ExIrc, you need to start a new client process, and add event handlers. An example event handler module +To use ExIRC, you need to start a new client process, and add event handlers. An example event handler module is located in `lib/exirc/example_handler.ex`. **The example handler is kept up to date with all events you can expect to receive from the client**. A simple module is defined below as an example of how you might -use ExIrc in practice. ExampleHandler here is the one that comes bundled with ExIrc. +use ExIRC in practice. ExampleHandler here is the one that comes bundled with ExIRC. There is also a variety of examples in `examples`, the most up to date of which is `examples/bot`. @@ -50,26 +50,26 @@ defmodule ExampleSupervisor do end def init(state) do - # Start the client and handler processes, the ExIrc supervisor is automatically started when your app runs - {:ok, client} = ExIrc.start_link!() + # Start the client and handler processes, the ExIRC supervisor is automatically started when your app runs + {:ok, client} = ExIRC.start_link!() {:ok, handler} = ExampleHandler.start_link(nil) - # Register the event handler with ExIrc - ExIrc.Client.add_handler client, handler + # Register the event handler with ExIRC + ExIRC.Client.add_handler client, handler # Connect and logon to a server, join a channel and send a simple message - ExIrc.Client.connect! client, state.host, state.port - ExIrc.Client.logon client, state.pass, state.nick, state.user, state.name - ExIrc.Client.join client, "#elixir-lang" - ExIrc.Client.msg client, :privmsg, "#elixir-lang", "Hello world!" + ExIRC.Client.connect! client, state.host, state.port + ExIRC.Client.logon client, state.pass, state.nick, state.user, state.name + ExIRC.Client.join client, "#elixir-lang" + ExIRC.Client.msg client, :privmsg, "#elixir-lang", "Hello world!" {:ok, %{state | :client => client, :handlers => [handler]}} end def terminate(_, state) do # Quit the channel and close the underlying client connection when the process is terminating - ExIrc.Client.quit state.client, "Goodbye, cruel world." - ExIrc.Client.stop! state.client + ExIRC.Client.quit state.client, "Goodbye, cruel world." + ExIRC.Client.stop! state.client :ok end end @@ -88,7 +88,7 @@ defmodule ExampleApplication do def start(_type, _args) do import Supervisor.Spec, warn: false - {:ok, client} = ExIrc.start_link! + {:ok, client} = ExIRC.start_link! children = [ # Define workers and child supervisors to be supervised @@ -120,14 +120,14 @@ defmodule ExampleConnectionHandler do end def init([state]) do - ExIrc.Client.add_handler state.client, self - ExIrc.Client.connect! state.client, state.host, state.port + ExIRC.Client.add_handler state.client, self + ExIRC.Client.connect! state.client, state.host, state.port {:ok, state} end def handle_info({:connected, server, port}, state) do debug "Connected to #{server}:#{port}" - ExIrc.Client.logon state.client, state.pass, state.nick, state.user, state.name + ExIRC.Client.logon state.client, state.pass, state.nick, state.user, state.name {:noreply, state} end @@ -156,13 +156,13 @@ defmodule ExampleLoginHandler do end def init([client, channels]) do - ExIrc.Client.add_handler client, self + ExIRC.Client.add_handler client, self {:ok, {client, channels}} end def handle_info(:logged_in, state = {client, channels}) do debug "Logged in to server" - channels |> Enum.map(&ExIrc.Client.join client, &1) + channels |> Enum.map(&ExIRC.Client.join client, &1) {:noreply, state} end @@ -177,10 +177,10 @@ defmodule ExampleLoginHandler do end ``` -## Projects using ExIrc (in the wild!) +## Projects using ExIRC (in the wild!) Below is a list of projects that we know of (if we've missed anything, -send a PR!) that use ExIrc in the wild. +send a PR!) that use ExIRC in the wild. - [Kuma][kuma] by @ryanwinchester - [Offension][offension] by @shymega diff --git a/examples/bot/config/config.exs b/examples/bot/config/config.exs index e0d35fe..50f23ee 100644 --- a/examples/bot/config/config.exs +++ b/examples/bot/config/config.exs @@ -4,7 +4,7 @@ use Mix.Config config :exirc_example, bots: [ %{:server => "chat.freenode.net", :port => 6667, - :nick => "exirc-example", :user => "exirc-example", :name => "ExIrc Example Bot", + :nick => "exirc-example", :user => "exirc-example", :name => "ExIRC Example Bot", :channel => "##exirc-test"} ] diff --git a/examples/bot/lib/bot.ex b/examples/bot/lib/bot.ex index 12aab5d..453b9e8 100644 --- a/examples/bot/lib/bot.ex +++ b/examples/bot/lib/bot.ex @@ -22,8 +22,8 @@ defmodule Example.Bot do end end - alias ExIrc.Client - alias ExIrc.SenderInfo + alias ExIRC.Client + alias ExIRC.SenderInfo def start_link(%{:nick => nick} = params) when is_map(params) do config = Config.from_params(params) @@ -31,10 +31,10 @@ defmodule Example.Bot do end def init([config]) do - # Start the client and handler processes, the ExIrc supervisor is automatically started when your app runs - {:ok, client} = ExIrc.start_link!() + # Start the client and handler processes, the ExIRC supervisor is automatically started when your app runs + {:ok, client} = ExIRC.start_link!() - # Register the event handler with ExIrc + # Register the event handler with ExIRC Client.add_handler client, self() # Connect and logon to a server, join a channel and send a simple message diff --git a/examples/ohai/connection_handler.ex b/examples/ohai/connection_handler.ex index 2ba5aad..6d0de47 100644 --- a/examples/ohai/connection_handler.ex +++ b/examples/ohai/connection_handler.ex @@ -14,14 +14,14 @@ defmodule ConnectionHandler do end def init([state]) do - ExIrc.Client.add_handler state.client, self - ExIrc.Client.connect! state.client, state.host, state.port + ExIRC.Client.add_handler state.client, self + ExIRC.Client.connect! state.client, state.host, state.port {:ok, state} end def handle_info({:connected, server, port}, state) do debug "Connected to #{server}:#{port}" - ExIrc.Client.logon state.client, state.pass, state.nick, state.user, state.name + ExIRC.Client.logon state.client, state.pass, state.nick, state.user, state.name {:noreply, state} end diff --git a/examples/ohai/login_handler.ex b/examples/ohai/login_handler.ex index 159e191..f7f7d1f 100644 --- a/examples/ohai/login_handler.ex +++ b/examples/ohai/login_handler.ex @@ -11,13 +11,13 @@ defmodule LoginHandler do end def init([client, channels]) do - ExIrc.Client.add_handler client, self + ExIRC.Client.add_handler client, self {:ok, {client, channels}} end def handle_info(:logged_in, state = {client, channels}) do debug "Logged in to server" - channels |> Enum.map(&ExIrc.Client.join client, &1) + channels |> Enum.map(&ExIRC.Client.join client, &1) {:noreply, state} end diff --git a/examples/ohai/ohai_handler.ex b/examples/ohai/ohai_handler.ex index 3d411f0..fe066b3 100644 --- a/examples/ohai/ohai_handler.ex +++ b/examples/ohai/ohai_handler.ex @@ -7,7 +7,7 @@ defmodule OhaiHandler do end def init([client]) do - ExIrc.Client.add_handler client, self + ExIRC.Client.add_handler client, self {:ok, client} end @@ -17,12 +17,12 @@ defmodule OhaiHandler do end def handle_info({:joined, channel, user}, client) do - # ExIrc currently has a bug that doesn't remove the \r\n from the end + # ExIRC currently has a bug that doesn't remove the \r\n from the end # of the channel name with it sends along this kind of message # so we ensure any trailing or leading whitespace is explicitly removed channel = String.strip(channel) debug "#{user} joined #{channel}" - ExIrc.Client.msg(client, :privmsg, channel, "ohai #{user}") + ExIRC.Client.msg(client, :privmsg, channel, "ohai #{user}") {:noreply, client} end diff --git a/examples/ohai/ohai_irc.ex b/examples/ohai/ohai_irc.ex index 27c05a2..83d5d56 100644 --- a/examples/ohai/ohai_irc.ex +++ b/examples/ohai/ohai_irc.ex @@ -6,7 +6,7 @@ defmodule OhaiIrc do def start(_type, _args) do import Supervisor.Spec, warn: false - {:ok, client} = ExIrc.start_client! + {:ok, client} = ExIRC.start_client! children = [ # Define workers and child supervisors to be supervised @@ -1,10 +1,10 @@ -defmodule ExIrc.App do +defmodule ExIRC.App do @moduledoc """ - Entry point for the ExIrc application. + Entry point for the ExIRC application. """ use Application def start(_type, _args) do - ExIrc.start! + ExIRC.start! end end diff --git a/lib/exirc/channels.ex b/lib/exirc/channels.ex index f274ef1..b60e0d8 100644 --- a/lib/exirc/channels.ex +++ b/lib/exirc/channels.ex @@ -1,8 +1,8 @@ -defmodule ExIrc.Channels do +defmodule ExIRC.Channels do @moduledoc """ Responsible for managing channel state """ - use Irc.Commands + use ExIRC.Commands import String, only: [downcase: 1] diff --git a/lib/exirc/client.ex b/lib/exirc/client.ex index 4c49106..4dd4d25 100644 --- a/lib/exirc/client.ex +++ b/lib/exirc/client.ex @@ -1,15 +1,15 @@ -defmodule ExIrc.Client do +defmodule ExIRC.Client do @moduledoc """ Maintains the state and behaviour for individual IRC client connections """ - use Irc.Commands + use ExIRC.Commands use GenServer - import ExIrc.Logger + import ExIRC.Logger - alias ExIrc.Channels - alias ExIrc.Utils - alias ExIrc.SenderInfo - alias ExIrc.Client.Transport + alias ExIRC.Channels + alias ExIRC.Utils + alias ExIRC.SenderInfo + alias ExIRC.Client.Transport # Client internal state defmodule ClientState do @@ -310,7 +310,7 @@ defmodule ExIrc.Client do autoping: autoping, logged_on?: false, debug?: debug, - channels: ExIrc.Channels.init(), + channels: ExIRC.Channels.init(), owner: {owner, ref}}} end @doc """ @@ -503,12 +503,12 @@ defmodule ExIrc.Client do def handle_info({:tcp, _, data}, state) do debug? = state.debug? case Utils.parse(data) do - %IrcMessage{ctcp: true} = msg -> + %ExIRC.Message{ctcp: true} = msg -> handle_data msg, state {:noreply, state} - %IrcMessage{ctcp: false} = msg -> + %ExIRC.Message{ctcp: false} = msg -> handle_data msg, state - %IrcMessage{ctcp: :invalid} = msg when debug? -> + %ExIRC.Message{ctcp: :invalid} = msg when debug? -> send_event msg, state {:noreply, state} _ -> @@ -552,22 +552,23 @@ defmodule ExIrc.Client do ################ @doc """ - Handle IrcMessages received from the server. + Handle ExIRC.Messages received from the server. """ # Called upon successful login - def handle_data(%IrcMessage{cmd: @rpl_welcome}, %ClientState{logged_on?: false} = state) do + def handle_data(%ExIRC.Message{cmd: @rpl_welcome}, %ClientState{logged_on?: false} = state) do if state.debug?, do: debug "SUCCESFULLY LOGGED ON" new_state = %{state | logged_on?: true, login_time: :erlang.timestamp()} send_event :logged_in, new_state {:noreply, new_state} end # Called when the server sends it's current capabilities - def handle_data(%IrcMessage{cmd: @rpl_isupport} = msg, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_isupport} = msg, state) do if state.debug?, do: debug "RECEIVING SERVER CAPABILITIES" {:noreply, Utils.isup(msg.args, state)} end # Called when the client enters a channel - def handle_data(%IrcMessage{nick: nick, cmd: "JOIN"} = msg, %ClientState{nick: nick} = state) do + + def handle_data(%ExIRC.Message{nick: nick, cmd: "JOIN"} = msg, %ClientState{nick: nick} = state) do channel = msg.args |> List.first |> String.trim if state.debug?, do: debug "JOINED A CHANNEL #{channel}" channels = Channels.join(state.channels, channel) @@ -576,7 +577,7 @@ defmodule ExIrc.Client do {:noreply, new_state} end # Called when another user joins a channel the client is in - def handle_data(%IrcMessage{nick: user_nick, cmd: "JOIN", host: host, user: user} = msg, state) do + def handle_data(%ExIRC.Message{nick: user_nick, cmd: "JOIN", host: host, user: user} = msg, state) do sender = %SenderInfo{nick: user_nick, host: host, user: user} channel = msg.args |> List.first |> String.trim if state.debug?, do: debug "ANOTHER USER JOINED A CHANNEL: #{channel} - #{user_nick}" @@ -591,7 +592,7 @@ defmodule ExIrc.Client do # Message with a single argument is not RFC compliant, but is present # to handle poorly written IRC servers which send RPL_TOPIC with an empty # topic (such as Slack's IRC bridge), when they should be sending RPL_NOTOPIC - def handle_data(%IrcMessage{cmd: @rpl_topic} = msg, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_topic} = msg, state) do {channel, topic} = case msg.args do [_nick, channel, topic] -> {channel, topic} [channel, topic] -> {channel, topic} @@ -611,61 +612,69 @@ defmodule ExIrc.Client do ## WHOIS - def handle_data(%IrcMessage{cmd: @rpl_whoisuser, args: [_sender, nickname, username, hostname, _, realname]}, state) do + + def handle_data(%ExIRC.Message{cmd: @rpl_whoisuser, args: [_sender, nickname, username, hostname, _, realname]}, state) do + user = %{nickname: nickname, username: username, hostname: hostname, realname: realname} {:noreply, %ClientState{state|whois_buffers: Map.put(state.whois_buffers, nickname, user)}} end - def handle_data(%IrcMessage{cmd: @rpl_whoiscertfp, args: [_sender, nickname, "has client certificate fingerprint "<> fingerprint]}, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_whoiscertfp, args: [_sender, nickname, "has client certificate fingerprint "<> fingerprint]}, state) do {:noreply, %ClientState{state|whois_buffers: put_in(state.whois_buffers, [nickname, :certfp], fingerprint)}} end - def handle_data(%IrcMessage{cmd: @rpl_whoisregnick, args: [_sender, nickname, _message]}, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_whoisregnick, args: [_sender, nickname, _message]}, state) do {:noreply, %ClientState{state|whois_buffers: put_in(state.whois_buffers, [nickname, :registered_nick?], true)}} end - def handle_data(%IrcMessage{cmd: @rpl_whoishelpop, args: [_sender, nickname, _message]}, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_whoishelpop, args: [_sender, nickname, _message]}, state) do {:noreply, %ClientState{state|whois_buffers: put_in(state.whois_buffers, [nickname, :helpop?], true)}} end - def handle_data(%IrcMessage{cmd: @rpl_whoischannels, args: [_sender, nickname, channels]}, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_whoischannels, args: [_sender, nickname, channels]}, state) do + chans = String.split(channels, " ") {:noreply, %ClientState{state|whois_buffers: put_in(state.whois_buffers, [nickname, :channels], chans)}} end - def handle_data(%IrcMessage{cmd: @rpl_whoisserver, args: [_sender, nickname, server_addr, server_name]}, state) do + + def handle_data(%ExIRC.Message{cmd: @rpl_whoisserver, args: [_sender, nickname, server_addr, server_name]}, state) do + new_buffer = state.whois_buffers |> put_in([nickname, :server_name], server_name) |> put_in([nickname, :server_address], server_addr) {:noreply, %ClientState{state|whois_buffers: new_buffer}} end - def handle_data(%IrcMessage{cmd: @rpl_whoisoperator, args: [_sender, nickname, _message]}, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_whoisoperator, args: [_sender, nickname, _message]}, state) do {:noreply, %ClientState{state|whois_buffers: put_in(state.whois_buffers, [nickname, :ircop?], true)}} end - def handle_data(%IrcMessage{cmd: @rpl_whoisaccount, args: [_sender, nickname, account_name, _message]}, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_whoisaccount, args: [_sender, nickname, account_name, _message]}, state) do {:noreply, %ClientState{state|whois_buffers: put_in(state.whois_buffers, [nickname, :account_name], account_name)}} end - def handle_data(%IrcMessage{cmd: @rpl_whoissecure, args: [_sender, nickname, _message]}, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_whoissecure, args: [_sender, nickname, _message]}, state) do {:noreply, %ClientState{state|whois_buffers: put_in(state.whois_buffers, [nickname, :tls?], true)}} end - def handle_data(%IrcMessage{cmd: @rpl_whoisidle, args: [_sender, nickname, idling_time, signon_time, _message]}, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_whoisidle, args: [_sender, nickname, idling_time, signon_time, _message]}, state) do + new_buffer = state.whois_buffers |> put_in([nickname, :idling_time], idling_time) |> put_in([nickname, :signon_time], signon_time) {:noreply, %ClientState{state|whois_buffers: new_buffer}} end - def handle_data(%IrcMessage{cmd: @rpl_endofwhois, args: [_sender, nickname, _message]}, state) do - buffer = struct(Irc.Whois, state.whois_buffers[nickname]) + def handle_data(%ExIRC.Message{cmd: @rpl_endofwhois, args: [_sender, nickname, _message]}, state) do + buffer = struct(ExIRC.Whois, state.whois_buffers[nickname]) + send_event {:whois, buffer}, state {:noreply, %ClientState{state|whois_buffers: Map.delete(state.whois_buffers, nickname)}} end - def handle_data(%IrcMessage{cmd: @rpl_notopic, args: [channel]}, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_notopic, args: [channel]}, state) do + if state.debug? do debug "INITIAL TOPIC MSG" debug "1. NO TOPIC SET FOR #{channel}}" @@ -675,7 +684,7 @@ defmodule ExIrc.Client do {:noreply, new_state} end # Called when the topic changes while we're in the channel - def handle_data(%IrcMessage{cmd: "TOPIC", args: [channel, topic]}, state) do + def handle_data(%ExIRC.Message{cmd: "TOPIC", args: [channel, topic]}, state) do if state.debug?, do: debug "TOPIC CHANGED FOR #{channel} TO #{topic}" channels = Channels.set_topic(state.channels, channel, topic) new_state = %{state | channels: channels} @@ -683,7 +692,7 @@ defmodule ExIrc.Client do {:noreply, new_state} end # Called when joining a channel with the list of current users in that channel, or when the NAMES command is sent - def handle_data(%IrcMessage{cmd: @rpl_namereply} = msg, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_namereply} = msg, state) do if state.debug?, do: debug "NAMES LIST RECEIVED" {_nick, channel_type, channel, names} = case msg.args do [nick, channel_type, channel, names] -> {nick, channel_type, channel, names} @@ -699,14 +708,14 @@ defmodule ExIrc.Client do {:noreply, %{state | channels: channels}} end # Called when our nick has succesfully changed - def handle_data(%IrcMessage{cmd: "NICK", nick: nick, args: [new_nick]}, %ClientState{nick: nick} = state) do + def handle_data(%ExIRC.Message{cmd: "NICK", nick: nick, args: [new_nick]}, %ClientState{nick: nick} = state) do if state.debug?, do: debug "NICK CHANGED FROM #{nick} TO #{new_nick}" new_state = %{state | nick: new_nick} send_event {:nick_changed, new_nick}, new_state {:noreply, new_state} end # Called when someone visible to us changes their nick - def handle_data(%IrcMessage{cmd: "NICK", nick: nick, args: [new_nick]}, state) do + def handle_data(%ExIRC.Message{cmd: "NICK", nick: nick, args: [new_nick]}, state) do if state.debug?, do: debug "#{nick} CHANGED THEIR NICK TO #{new_nick}" channels = Channels.user_rename(state.channels, nick, new_nick) new_state = %{state | channels: channels} @@ -714,13 +723,15 @@ defmodule ExIrc.Client do {:noreply, new_state} end # Called upon mode change - def handle_data(%IrcMessage{cmd: "MODE", args: [channel, op, user]}, state) do + def handle_data(%ExIRC.Message{cmd: "MODE", args: [channel, op, user]}, state) do if state.debug?, do: debug "MODE #{channel} #{op} #{user}" send_event {:mode, [channel, op, user]}, state {:noreply, state} end # Called when we leave a channel - def handle_data(%IrcMessage{cmd: "PART", nick: nick} = msg, %ClientState{nick: nick} = state) do + + def handle_data(%ExIRC.Message{cmd: "PART", nick: nick} = msg, %ClientState{nick: nick} = state) do + channel = msg.args |> List.first |> String.trim if state.debug?, do: debug "WE LEFT A CHANNEL: #{channel}" channels = Channels.part(state.channels, channel) @@ -729,7 +740,7 @@ defmodule ExIrc.Client do {:noreply, new_state} end # Called when someone else in our channel leaves - def handle_data(%IrcMessage{cmd: "PART", nick: from, host: host, user: user} = msg, state) do + def handle_data(%ExIRC.Message{cmd: "PART", nick: from, host: host, user: user} = msg, state) do sender = %SenderInfo{nick: from, host: host, user: user} channel = msg.args |> List.first |> String.trim if state.debug?, do: debug "#{from} LEFT A CHANNEL: #{channel}" @@ -738,7 +749,7 @@ defmodule ExIrc.Client do send_event {:parted, channel, sender}, new_state {:noreply, new_state} end - def handle_data(%IrcMessage{cmd: "QUIT", nick: from, host: host, user: user} = msg, state) do + def handle_data(%ExIRC.Message{cmd: "QUIT", nick: from, host: host, user: user} = msg, state) do sender = %SenderInfo{nick: from, host: host, user: user} reason = msg.args |> List.first if state.debug?, do: debug "#{from} QUIT" @@ -748,10 +759,10 @@ defmodule ExIrc.Client do {:noreply, new_state} end # Called when we receive a PING - def handle_data(%IrcMessage{cmd: "PING"} = msg, %ClientState{autoping: true} = state) do + def handle_data(%ExIRC.Message{cmd: "PING"} = msg, %ClientState{autoping: true} = state) do if state.debug?, do: debug "RECEIVED A PING!" case msg do - %IrcMessage{args: [from]} -> + %ExIRC.Message{args: [from]} -> if state.debug?, do: debug("SENT PONG2") Transport.send(state, pong2!(from, msg.server)) _ -> @@ -761,35 +772,39 @@ defmodule ExIrc.Client do {:noreply, state}; end # Called when we are invited to a channel - def handle_data(%IrcMessage{cmd: "INVITE", args: [nick, channel], nick: by, host: host, user: user} = msg, %ClientState{nick: nick} = state) do + def handle_data(%ExIRC.Message{cmd: "INVITE", args: [nick, channel], nick: by, host: host, user: user} = msg, %ClientState{nick: nick} = state) do sender = %SenderInfo{nick: by, host: host, user: user} if state.debug?, do: debug "RECEIVED AN INVITE: #{msg.args |> Enum.join(" ")}" send_event {:invited, sender, channel}, state {:noreply, state} end # Called when we are kicked from a channel - def handle_data(%IrcMessage{cmd: "KICK", args: [channel, nick, reason], nick: by, host: host, user: user} = _msg, %ClientState{nick: nick} = state) do + + def handle_data(%ExIRC.Message{cmd: "KICK", args: [channel, nick, reason], nick: by, host: host, user: user} = _msg, %ClientState{nick: nick} = state) do + sender = %SenderInfo{nick: by, host: host, user: user} if state.debug?, do: debug "WE WERE KICKED FROM #{channel} BY #{by}" send_event {:kicked, sender, channel, reason}, state {:noreply, state} end # Called when someone else was kicked from a channel - def handle_data(%IrcMessage{cmd: "KICK", args: [channel, nick, reason], nick: by, host: host, user: user} = _msg, state) do + + def handle_data(%ExIRC.Message{cmd: "KICK", args: [channel, nick, reason], nick: by, host: host, user: user} = _msg, state) do + sender = %SenderInfo{nick: by, host: host, user: user} if state.debug?, do: debug "#{nick} WAS KICKED FROM #{channel} BY #{by}" send_event {:kicked, nick, sender, channel, reason}, state {:noreply, state} end # Called when someone sends us a message - def handle_data(%IrcMessage{nick: from, cmd: "PRIVMSG", args: [nick, message], host: host, user: user} = _msg, %ClientState{nick: nick} = state) do + def handle_data(%ExIRC.Message{nick: from, cmd: "PRIVMSG", args: [nick, message], host: host, user: user} = _msg, %ClientState{nick: nick} = state) do sender = %SenderInfo{nick: from, host: host, user: user} if state.debug?, do: debug "#{from} SENT US #{message}" send_event {:received, message, sender}, state {:noreply, state} end # Called when someone sends a message to a channel we're in, or a list of users - def handle_data(%IrcMessage{nick: from, cmd: "PRIVMSG", args: [to, message], host: host, user: user} = _msg, %ClientState{nick: nick} = state) do + def handle_data(%ExIRC.Message{nick: from, cmd: "PRIVMSG", args: [to, message], host: host, user: user} = _msg, %ClientState{nick: nick} = state) do sender = %SenderInfo{nick: from, host: host, user: user} if state.debug?, do: debug "#{from} SENT #{message} TO #{to}" send_event {:received, message, sender, to}, state @@ -798,14 +813,16 @@ defmodule ExIrc.Client do {:noreply, state} end # Called when someone uses ACTION, i.e. `/me dies` - def handle_data(%IrcMessage{nick: from, cmd: "ACTION", args: [channel, message], host: host, user: user} = _msg, state) do + def handle_data(%ExIRC.Message{nick: from, cmd: "ACTION", args: [channel, message], host: host, user: user} = _msg, state) do sender = %SenderInfo{nick: from, host: host, user: user} if state.debug?, do: debug "* #{from} #{message} in #{channel}" send_event {:me, message, sender, channel}, state {:noreply, state} end + # Called when a NOTICE is received by the client. - def handle_data(%IrcMessage{nick: from, cmd: "NOTICE", args: [_target, message], host: host, user: user} = _msg, state) do + def handle_data(%ExIRC.Message{nick: from, cmd: "NOTICE", args: [_target, message], host: host, user: user} = _msg, state) do + sender = %SenderInfo{nick: from, host: host, user: user} diff --git a/lib/exirc/commands.ex b/lib/exirc/commands.ex index 0d959c0..c4833d5 100644 --- a/lib/exirc/commands.ex +++ b/lib/exirc/commands.ex @@ -1,4 +1,4 @@ -defmodule Irc.Commands do +defmodule ExIRC.Commands do @moduledoc """ Defines IRC command constants, and methods for generating valid commands to send to an IRC server. """ @@ -6,7 +6,7 @@ defmodule Irc.Commands do defmacro __using__(_) do quote do - import Irc.Commands + import ExIRC.Commands #################### # IRC Numeric Codes diff --git a/lib/exirc/example_handler.ex b/lib/exirc/example_handler.ex index 48774fd..1701729 100644 --- a/lib/exirc/example_handler.ex +++ b/lib/exirc/example_handler.ex @@ -27,10 +27,10 @@ defmodule ExampleHandler do def handle_info(:logged_in, _state) do IO.puts "Logged in!" end - def handle_info(%IrcMessage{nick: from, cmd: "PRIVMSG", args: ["mynick", msg]}, _state) do + def handle_info(%ExIRC.Message{nick: from, cmd: "PRIVMSG", args: ["mynick", msg]}, _state) do IO.puts "Received a private message from \#{from}: \#{msg}" end - def handle_info(%IrcMessage{nick: from, cmd: "PRIVMSG", args: [to, msg]}, _state) do + def handle_info(%ExIRC.Message{nick: from, cmd: "PRIVMSG", args: [to, msg]}, _state) do IO.puts "Received a message in \#{to} from \#{from}: \#{msg}" end """ @@ -110,18 +110,18 @@ defmodule ExampleHandler do debug "* #{from} #{message} in #{channel}" {:noreply, nil} end - # This is an example of how you can manually catch commands if ExIrc.Client doesn't send a specific message for it - def handle_info(%IrcMessage{nick: from, cmd: "PRIVMSG", args: ["testnick", msg]}, _state) do + # This is an example of how you can manually catch commands if ExIRC.Client doesn't send a specific message for it + def handle_info(%ExIRC.Message{nick: from, cmd: "PRIVMSG", args: ["testnick", msg]}, _state) do debug "Received a private message from #{from}: #{msg}" {:noreply, nil} end - def handle_info(%IrcMessage{nick: from, cmd: "PRIVMSG", args: [to, msg]}, _state) do + def handle_info(%ExIRC.Message{nick: from, cmd: "PRIVMSG", args: [to, msg]}, _state) do debug "Received a message in #{to} from #{from}: #{msg}" {:noreply, nil} end # Catch-all for messages you don't care about def handle_info(msg, _state) do - debug "Received IrcMessage:" + debug "Received ExIRC.Message:" IO.inspect msg {:noreply, nil} end diff --git a/lib/exirc/exirc.ex b/lib/exirc/exirc.ex index c36e6e4..41d105a 100644 --- a/lib/exirc/exirc.ex +++ b/lib/exirc/exirc.ex @@ -1,32 +1,32 @@ -defmodule ExIrc do +defmodule ExIRC do @moduledoc """ Supervises IRC client processes Usage: - # Start the supervisor (started automatically when ExIrc is run as an application) - ExIrc.start_link + # Start the supervisor (started automatically when ExIRC is run as an application) + ExIRC.start_link # Start a new IRC client - {:ok, client} = ExIrc.start_client! + {:ok, client} = ExIRC.start_client! # Connect to an IRC server - ExIrc.Client.connect! client, "localhost", 6667 + ExIRC.Client.connect! client, "localhost", 6667 # Logon - ExIrc.Client.logon client, "password", "nick", "user", "name" + ExIRC.Client.logon client, "password", "nick", "user", "name" # Join a channel (password is optional) - ExIrc.Client.join client, "#channel", "password" + ExIRC.Client.join client, "#channel", "password" # Send a message - ExIrc.Client.msg client, :privmsg, "#channel", "Hello world!" + ExIRC.Client.msg client, :privmsg, "#channel", "Hello world!" # Quit (message is optional) - ExIrc.Client.quit client, "message" + ExIRC.Client.quit client, "message" # Stop and close the client connection - ExIrc.Client.stop! client + ExIRC.Client.stop! client """ use Supervisor @@ -37,7 +37,7 @@ defmodule ExIrc do ############## @doc """ - Start the ExIrc supervisor. + Start the ExIRC supervisor. """ @spec start! :: {:ok, pid} | {:error, term} def start! do @@ -45,7 +45,7 @@ defmodule ExIrc do end @doc """ - Start a new ExIrc client under the ExIrc supervisor + Start a new ExIRC client under the ExIRC supervisor """ @spec start_client! :: {:ok, pid} | {:error, term} def start_client! do @@ -54,10 +54,10 @@ defmodule ExIrc do end @doc """ - Start a new ExIrc client + Start a new ExIRC client """ def start_link! do - ExIrc.Client.start!([owner: self()]) + ExIRC.Client.start!([owner: self()]) end ############## @@ -67,7 +67,7 @@ defmodule ExIrc do @spec init(any) :: {:ok, pid} | {:error, term} def init(_) do children = [ - worker(ExIrc.Client, [], restart: :temporary) + worker(ExIRC.Client, [], restart: :temporary) ] supervise children, strategy: :simple_one_for_one end diff --git a/lib/exirc/irc_message.ex b/lib/exirc/irc_message.ex index ad865fc..2ea26e5 100644 --- a/lib/exirc/irc_message.ex +++ b/lib/exirc/irc_message.ex @@ -1,4 +1,4 @@ -defmodule IrcMessage do +defmodule ExIRC.Message do defstruct server: '', nick: '', user: '', diff --git a/lib/exirc/logger.ex b/lib/exirc/logger.ex index 65ae980..9cee4bf 100644 --- a/lib/exirc/logger.ex +++ b/lib/exirc/logger.ex @@ -1,4 +1,4 @@ -defmodule ExIrc.Logger do +defmodule ExIRC.Logger do @moduledoc """ A simple abstraction of :error_logger """ diff --git a/lib/exirc/sender_info.ex b/lib/exirc/sender_info.ex index b468f64..eda901b 100644 --- a/lib/exirc/sender_info.ex +++ b/lib/exirc/sender_info.ex @@ -1,4 +1,4 @@ -defmodule ExIrc.SenderInfo do +defmodule ExIRC.SenderInfo do @moduledoc """ This struct represents information available about the sender of a message. """ diff --git a/lib/exirc/transport.ex b/lib/exirc/transport.ex index 4c9456b..dedd8ce 100644 --- a/lib/exirc/transport.ex +++ b/lib/exirc/transport.ex @@ -1,4 +1,4 @@ -defmodule ExIrc.Client.Transport do
+defmodule ExIRC.Client.Transport do
def connect(%{ssl?: false}, host, port, options) do
:gen_tcp.connect(host, port, options)
end
diff --git a/lib/exirc/utils.ex b/lib/exirc/utils.ex index d79b326..428379d 100644 --- a/lib/exirc/utils.ex +++ b/lib/exirc/utils.ex @@ -1,4 +1,4 @@ -defmodule ExIrc.Utils do +defmodule ExIRC.Utils do ###################### # IRC Message Parsing @@ -10,18 +10,20 @@ defmodule ExIrc.Utils do Example: data = ':irc.example.org 005 nick NETWORK=Freenode PREFIX=(ov)@+ CHANTYPES=#&' - message = ExIrc.Utils.parse data + message = ExIRC.Utils.parse data assert "irc.example.org" = message.server """ - @spec parse(raw_data :: charlist) :: IrcMessage.t + + @spec parse(raw_data :: charlist) :: ExIRC.Message.t + def parse(raw_data) do data = :string.substr(raw_data, 1, length(raw_data)) case data do [?:|_] -> [[?:|from]|rest] = :string.tokens(data, ' ') - get_cmd(rest, parse_from(from, %IrcMessage{ctcp: false})) + get_cmd(rest, parse_from(from, %ExIRC.Message{ctcp: false})) data -> - get_cmd(:string.tokens(data, ' '), %IrcMessage{ctcp: false}) + get_cmd(:string.tokens(data, ' '), %ExIRC.Message{ctcp: false}) end end @@ -102,7 +104,7 @@ defmodule ExIrc.Utils do # This function allows us to handle special case messages which are not RFC # compliant, before passing it to the client. - defp post_process(%IrcMessage{cmd: "332", args: [nick, channel]} = msg) do + defp post_process(%ExIRC.Message{cmd: "332", args: [nick, channel]} = msg) do # Handle malformed RPL_TOPIC messages which contain no topic %{msg | :cmd => "331", :args => [channel, "No topic is set"], :nick => nick} end @@ -118,7 +120,7 @@ defmodule ExIrc.Utils do If an empty list is provided, do nothing, otherwise parse CHANTYPES, NETWORK, and PREFIX parameters for relevant data. """ - @spec isup(parameters :: list(binary), state :: ExIrc.Client.ClientState.t) :: ExIrc.Client.ClientState.t + @spec isup(parameters :: list(binary), state :: ExIRC.Client.ClientState.t) :: ExIRC.Client.ClientState.t def isup([], state), do: state def isup([param | rest], state) do try do @@ -158,7 +160,7 @@ defmodule ExIrc.Utils do iex> local_time = {{2013,12,6},{14,5,0}} {{2013,12,6},{14,5,0}} - iex> ExIrc.Utils.ctcp_time local_time + iex> ExIRC.Utils.ctcp_time local_time "Fri Dec 06 14:05:00 2013" """ @spec ctcp_time(datetime :: {{integer, integer, integer}, {integer, integer, integer}}) :: binary diff --git a/lib/exirc/whois.ex b/lib/exirc/whois.ex index fb14e63..3970214 100644 --- a/lib/exirc/whois.ex +++ b/lib/exirc/whois.ex @@ -1,4 +1,5 @@ -defmodule Irc.Whois do +defmodule ExIRC.Whois do + defstruct [account_name: nil, channels: [], helpop?: false, @@ -1,4 +1,4 @@ -defmodule ExIrc.Mixfile do +defmodule ExIRC.Mixfile do use Mix.Project def project do @@ -14,7 +14,7 @@ defmodule ExIrc.Mixfile do # Configuration for the OTP application def application do - [mod: {ExIrc.App, []}, + [mod: {ExIRC.App, []}, applications: [:ssl, :crypto, :inets]] end diff --git a/test/channels_test.exs b/test/channels_test.exs index a1549ca..b29551b 100644 --- a/test/channels_test.exs +++ b/test/channels_test.exs @@ -1,7 +1,7 @@ -defmodule ExIrc.ChannelsTest do +defmodule ExIRC.ChannelsTest do use ExUnit.Case, async: true - alias ExIrc.Channels, as: Channels + alias ExIRC.Channels, as: Channels test "Joining a channel adds it to the tree of currently joined channels" do channels = Channels.init() |> Channels.join("#testchannel") |> Channels.channels diff --git a/test/client_test.exs b/test/client_test.exs index b7277b6..1788dd3 100644 --- a/test/client_test.exs +++ b/test/client_test.exs @@ -1,9 +1,9 @@ -defmodule ExIrc.ClientTest do +defmodule ExIRC.ClientTest do use ExUnit.Case test "start multiple clients" do - assert {:ok, pid} = ExIrc.start_client! - assert {:ok, pid2} = ExIrc.start_client! + assert {:ok, pid} = ExIRC.start_client! + assert {:ok, pid2} = ExIRC.start_client! assert pid != pid2 end @@ -11,7 +11,7 @@ defmodule ExIrc.ClientTest do test_pid = self() pid = spawn_link(fn -> - assert {:ok, pid} = ExIrc.start_client! + assert {:ok, pid} = ExIRC.start_client! send(test_pid, {:client, pid}) receive do :stop -> :ok diff --git a/test/commands_test.exs b/test/commands_test.exs index e9bdaef..38c2e90 100644 --- a/test/commands_test.exs +++ b/test/commands_test.exs @@ -1,7 +1,7 @@ -defmodule ExIrc.CommandsTest do +defmodule ExIRC.CommandsTest do use ExUnit.Case, async: true - use Irc.Commands + use ExIRC.Commands test "Commands are formatted properly" do expected = <<0o001, "TESTCMD", 0o001, ?\r, ?\n>> @@ -45,4 +45,4 @@ defmodule ExIrc.CommandsTest do expected = <<"INVITE testuser #testchan", ?\r, ?\n>> assert expected == invite!("testuser", "#testchan") |> IO.iodata_to_binary end -end
\ No newline at end of file +end diff --git a/test/utils_test.exs b/test/utils_test.exs index 3beb447..0370a82 100644 --- a/test/utils_test.exs +++ b/test/utils_test.exs @@ -1,12 +1,12 @@ -defmodule ExIrc.UtilsTest do +defmodule ExIRC.UtilsTest do use ExUnit.Case, async: true - use Irc.Commands + use ExIRC.Commands - alias ExIrc.Utils, as: Utils - alias ExIrc.Client.ClientState, as: ClientState + alias ExIRC.Utils, as: Utils + alias ExIRC.Client.ClientState, as: ClientState - doctest ExIrc.Utils + doctest ExIRC.Utils test "Given a local date/time as a tuple, can retrieve get the CTCP formatted time" do local_time = {{2013,12,6},{14,5,0}} # Mimics output of :calendar.local_time() @@ -15,7 +15,7 @@ defmodule ExIrc.UtilsTest do test "Can parse a CTCP command" do message = ':pschoenf NOTICE #testchan :' ++ '#{<<0o001>>}' ++ 'ACTION mind explodes!!' ++ '#{<<0o001>>}' - expected = %IrcMessage{ + expected = %ExIRC.Message{ nick: "pschoenf", cmd: "ACTION", ctcp: true, @@ -27,7 +27,7 @@ defmodule ExIrc.UtilsTest do test "Parse cloaked user" do message = ':foo!foo@unaffiliated/foo PRIVMSG #bar Hiya.' - expected = %IrcMessage{ + expected = %ExIRC.Message{ nick: "foo", cmd: "PRIVMSG", host: "unaffiliated/foo", @@ -41,7 +41,7 @@ defmodule ExIrc.UtilsTest do test "Parse uncloaked (normal) user" do message = ':foo!foo@80.21.56.43 PRIVMSG #bar Hiya.' - expected = %IrcMessage{ + expected = %ExIRC.Message{ nick: "foo", cmd: "PRIVMSG", host: "80.21.56.43", @@ -55,7 +55,7 @@ defmodule ExIrc.UtilsTest do test "Parse INVITE message" do message = ':pschoenf INVITE testuser #awesomechan' - assert %IrcMessage{ + assert %ExIRC.Message{ :nick => "pschoenf", :cmd => "INVITE", :args => ["testuser", "#awesomechan"] @@ -64,7 +64,7 @@ defmodule ExIrc.UtilsTest do test "Parse KICK message" do message = ':pschoenf KICK #testchan lameuser' - assert %IrcMessage{ + assert %ExIRC.Message{ :nick => "pschoenf", :cmd => "KICK", :args => ["#testchan", "lameuser"] @@ -83,7 +83,7 @@ defmodule ExIrc.UtilsTest do end test "Can parse full prefix in messages" do - assert %IrcMessage{ + assert %ExIRC.Message{ nick: "WiZ", user: "jto", host: "tolsun.oulu.fi", @@ -91,26 +91,26 @@ defmodule ExIrc.UtilsTest do end test "Can parse prefix with only hostname in messages" do - assert %IrcMessage{ + assert %ExIRC.Message{ nick: "WiZ", host: "tolsun.oulu.fi", } = Utils.parse(':WiZ!tolsun.oulu.fi NICK Kilroy') end test "Can parse reduced prefix in messages" do - assert %IrcMessage{ + assert %ExIRC.Message{ nick: "Trillian", } = Utils.parse(':Trillian SQUIT cm22.eng.umd.edu :Server out of control') end test "Can parse server-only prefix in messages" do - assert %IrcMessage{ + assert %ExIRC.Message{ server: "ircd.stealth.net" } = Utils.parse(':ircd.stealth.net 302 yournick :syrk=+syrk@millennium.stealth.net') end test "Can parse FULL STOP in username in prefixes" do - assert %IrcMessage{ + assert %ExIRC.Message{ nick: "nick", user: "user.name", host: "irc.example.org" @@ -118,7 +118,7 @@ defmodule ExIrc.UtilsTest do end test "Can parse EXCLAMATION MARK in username in prefixes" do - assert %IrcMessage{ + assert %ExIRC.Message{ nick: "nick", user: "user!name", host: "irc.example.org" @@ -127,7 +127,7 @@ defmodule ExIrc.UtilsTest do test "parse join message" do message = ':pschoenf JOIN #elixir-lang' - assert %IrcMessage{ + assert %ExIRC.Message{ nick: "pschoenf", cmd: "JOIN", args: ["#elixir-lang"] @@ -148,7 +148,7 @@ defmodule ExIrc.UtilsTest do # a good idea when I realized that there's nothing in ExIRc that does anything # with 331 at all - they just fall on the floor, no crashes to be seen (ideally) message = ':irc.tinyspeck.com 332 jadams #elm-playground-news :' - assert %IrcMessage{ + assert %ExIRC.Message{ nick: "jadams", cmd: "331", args: ["#elm-playground-news", "No topic is set"] @@ -161,7 +161,7 @@ defmodule ExIrc.UtilsTest do 46, 49, 55, 46, 48, 46, 49, 32, 80, 82, 73, 86, 77, 83, 71, 32, 35, 98, 97, 114, 32, 58, 195, 169, 195, 161, 195, 167, 195, 173, 195, 179, 195, 182, 13, 10] - assert %IrcMessage{ + assert %ExIRC.Message{ args: ["#bar", "éáçíóö"], cmd: "PRIVMSG", ctcp: false, @@ -178,7 +178,7 @@ defmodule ExIrc.UtilsTest do 46, 49, 55, 46, 48, 46, 49, 32, 80, 82, 73, 86, 77, 83, 71, 32, 35, 98, 97, 114, 32, 58, 196, 164, 195, 169, 108, 197, 130, 195, 184, 32, 236, 176, 168, 13, 10] - assert %IrcMessage{ + assert %ExIRC.Message{ args: ["#bar", "Ĥélłø 차"], cmd: "PRIVMSG", ctcp: false, @@ -195,7 +195,7 @@ defmodule ExIrc.UtilsTest do 46, 49, 55, 46, 48, 46, 49, 32, 80, 82, 73, 86, 77, 83, 71, 32, 35, 98, 97, 114, 32, 58, 233, 233, 233, 13, 10] - assert %IrcMessage{ + assert %ExIRC.Message{ args: ["#bar", "ééé"], cmd: "PRIVMSG", ctcp: false, |