IrcClient::getChannel()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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