Passed
Push — master ( 98d018...57883c )
by Jeroen
01:33
created

IrcClient::sendMessage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Jerodev\PhpIrcClient;
4
5
use Exception;
6
use Jerodev\PhpIrcClient\Helpers\EventHandlerCollection;
7
use Jerodev\PhpIrcClient\Messages\IrcMessage;
8
9
class IrcClient
10
{
11
    /** @var IrcChannel[] */
12
    private $channels;
13
14
    /** @var IrcConnection */
15
    private $connection;
16
17
    /** @var bool */
18
    private $isAuthenticated;
19
20
    /** @var EventHandlerCollection */
21
    private $messageEventHandlers;
22
23
    /** @var IrcUser|null */
24
    private $user;
25
26
    /**
27
     *  Create a new IrcClient instance.
28
     *
29
     *  @param string $server The server address to connect to including the port: `address:port`.
30
     *  @param null|string $username The username to use on the server. Can be set in more detail using `setUser()`.
31
     *  @param null|string|string[] $channels The channels to join on connect.
32
     */
33
    public function __construct(string $server, $username = null, $channels = null)
34
    {
35
        $this->connection = new IrcConnection($server);
36
37
        $this->user = $username === null ? null : new IrcUser($username);
38
        $this->channels = [];
39
        $this->messageEventHandlers = new EventHandlerCollection();
40
41
        if (!empty($channels)) {
42
            if (is_string($channels)) {
43
                $channels = [$channels];
44
            }
45
46
            foreach ($channels as $channel) {
47
                $this->channels[$channel] = new IrcChannel($channel);
48
            }
49
        }
50
    }
51
52
    /**
53
     *  Set the user credentials for the connections.
54
     *  When a connection is already open, this function can be used to change the nickname of the client.
55
     *
56
     *  @param IrcUser|string $user The user information.
57
     */
58
    public function setUser($user): void
59
    {
60
        if (is_string($user)) {
61
            $user = new IrcUser($user);
62
        }
63
64
        if ($this->connection->isConnected() && $this->user->nickname !== $user->nickname) {
65
            $this->send("NICK :$user->nickname");
66
        }
67
68
        $this->user = $user;
69
    }
70
71
    /**
72
     *  Connect to the irc server and start listening for messages.
73
     *
74
     *  @throws Exception if no user information is provided before connecting.
75
     */
76
    public function connect(): void
77
    {
78
        if (!$this->user) {
79
            throw new Exception('A nickname must be set before connecting to an irc server.');
80
        }
81
82
        if ($this->connection->isConnected()) {
83
            return;
84
        }
85
86
        $this->isAuthenticated = false;
87
        $this->connection->onData(function ($msg) {
88
            $this->handleIrcMessage($msg);
89
        });
90
        $this->connection->open();
91
    }
92
93
    /**
94
     *  Close the current connection, if any.
95
     */
96
    public function disconnect(): void
97
    {
98
        $this->connection->close();
99
    }
100
101
    /**
102
     *  Send a raw command string to the irc server.
103
     *
104
     *  @param string $command The full command string to send.
105
     */
106
    public function send(string $command): void
107
    {
108
        $this->connection->write($command);
109
    }
110
111
    /**
112
     *  Send a message to a channel or user.
113
     *  To send to a channel, make sure the `$target` starts with a `#`.
114
     *
115
     *  @param string $target The channel or user to message.
116
     *  @param string $message The message to send.
117
     */
118
    public function say(string $target, string $message): void
119
    {
120
        $this->send("PRIVMSG $target :$message");
121
    }
122
123
    /**
124
     *  Join an irc channel.
125
     *
126
     *  @param string $channel The name of the channel to join.
127
     */
128
    public function join(string $channel): void
129
    {
130
        $channel = $this->channelName($channel);
131
        $this->send("JOIN $channel");
132
        $this->getChannel($channel);
133
    }
134
135
    /**
136
     *  Part from an irc channel.
137
     *
138
     *  @param string $channel The name of the channel to leave.
139
     */
140
    public function part(string $channel): void
141
    {
142
        $channel = $this->channelName($channel);
143
144
        if (array_key_exists($channel, $this->channels)) {
145
            $this->send("PART $channel");
146
        }
147
    }
148
149
    /**
150
     *  Grab channel information by its name.
151
     *  This function makes sure the channel exists on this client first.
152
     *
153
     *  @param string $channel The name of this channel.
154
     *
155
     *  @return IrcChannel
156
     */
157
    public function getChannel(string $channel): IrcChannel
158
    {
159
        $channel = $this->channelName($channel);
160
161
        if (($this->channels[$channel] ?? null) === null) {
162
            $this->channels[$channel] = new IrcChannel($channel);
163
        }
164
165
        return $this->channels[$channel];
166
    }
167
168
    /**
169
     *  Return a list of all channels.
170
     *
171
     *  @return IrcChannel[]
172
     */
173
    public function getChannels(): array
174
    {
175
        return $this->channels;
176
    }
177
178
    /**
179
     *  Take actions required for received irc messages and invoke the correct event handlers.
180
     *
181
     *  @param IrcMessage $message The message object for the received line.
182
     */
183
    private function handleIrcMessage(IrcMessage $message): void
184
    {
185
        $message->handle($this);
186
187
        if (!$this->isAuthenticated && $this->user) {
188
            $this->send("USER {$this->user->nickname} * * :{$this->user->nickname}");
189
            $this->send("NICK {$this->user->nickname}");
190
            $this->isAuthenticated = true;
191
        }
192
193
        //$this->messageEventHandlers->invoke($message->command, [$message]);
194
    }
195
196
    /**
197
     *  Make sure all channel names have the same format.
198
     *
199
     *  @param string $channel The name of the channel to format.
200
     *
201
     *  @return string The formatted name.
202
     */
203
    private function channelName(string $channel): string
204
    {
205
        if ($channel[0] !== '#') {
206
            $channel = "#$channel";
207
        }
208
209
        return $channel;
210
    }
211
}
212