irc client fixes

This commit is contained in:
Vadim Lopatin 2016-03-15 15:41:52 +03:00
parent 437391c7de
commit 6d0c8d83b3
3 changed files with 155 additions and 18 deletions

View File

@ -409,6 +409,12 @@
<filesToClean>*.obj;*.cmd;*.build;*.json;*.dep</filesToClean> <filesToClean>*.obj;*.cmd;*.build;*.json;*.dep</filesToClean>
</Config> </Config>
<Folder name="d3d"> <Folder name="d3d">
<Folder name="dminer">
<Folder name="core">
<File path="src\dminer\core\minetypes.d" />
<File path="src\dminer\core\world.d" />
</Folder>
</Folder>
<File path="src\d3d.d" /> <File path="src\d3d.d" />
</Folder> </Folder>
</DProject> </DProject>

View File

@ -2,8 +2,10 @@ module ircclient.net.client;
public import dlangui.core.asyncsocket; public import dlangui.core.asyncsocket;
import dlangui.core.logger; import dlangui.core.logger;
import std.string : empty, format; import dlangui.core.collections;
import std.string : empty, format, startsWith;
import std.conv : to; import std.conv : to;
import std.utf : toUTF32, toUTF8;
interface IRCClientCallback { interface IRCClientCallback {
void onIRCConnect(IRCClient client); void onIRCConnect(IRCClient client);
@ -16,6 +18,10 @@ interface IRCClientCallback {
enum IRCCommand : int { enum IRCCommand : int {
UNKNOWN, UNKNOWN,
CHANNEL_TOPIC = 332,
CHANNEL_TOPIC_SET_BY = 333,
CHANNEL_NAMES_LIST = 353,
CHANNEL_NAMES_LIST_END = 366,
USER = 1000, USER = 1000,
PRIVMSG, // :source PRIVMSG <target> :Message PRIVMSG, // :source PRIVMSG <target> :Message
NOTICE, // :source NOTICE <target> :Message NOTICE, // :source NOTICE <target> :Message
@ -101,6 +107,16 @@ class IRCMessage {
if (params.length > 0) if (params.length > 0)
target = params[0]; target = params[0];
break; break;
case CHANNEL_TOPIC:
case CHANNEL_TOPIC_SET_BY:
case CHANNEL_NAMES_LIST_END:
if (params.length > 1)
target = params[1];
break;
case CHANNEL_NAMES_LIST:
if (params.length > 2 && params[1] == "=")
target = params[2];
break;
default: default:
break; break;
} }
@ -114,6 +130,8 @@ class IRCAddress {
string channel; string channel;
string nick; string nick;
string username; string username;
this() {
}
this(string s) { this(string s) {
full = s; full = s;
string s1 = parseDelimitedParameter(s, '!'); string s1 = parseDelimitedParameter(s, '!');
@ -134,6 +152,75 @@ class IRCAddress {
} }
} }
class IRCUser {
string nick;
int flags;
this(string s) {
nick = s;
}
}
class UserList {
Collection!IRCUser _users;
@property int length() { return _users.length; }
@property IRCUser opIndex(int index) { return _users[index]; }
void fromList(string userList) {
_users.clear();
for(;;) {
string s = parseDelimitedParameter(userList);
if (s.empty)
break;
IRCUser u = new IRCUser(s);
_users.add(u);
}
}
}
class IRCChannel {
string name;
string topic;
string topicSetBy;
long topicSetWhen;
UserList users;
this(string name) {
this.name = name;
users = new UserList();
}
char[] userListBuffer;
void setUserList(string userList) {
users.fromList(userList);
}
@property dstring[] userNames() {
dstring[] res;
for(int i = 0; i < users.length; i++) {
res ~= toUTF32(users[i].nick);
}
return res;
}
void handleMessage(IRCMessage msg) {
switch (msg.commandId) with (IRCCommand) {
case CHANNEL_TOPIC:
topic = msg.message;
break;
case CHANNEL_TOPIC_SET_BY:
topicSetBy = msg.params.length == 3 ? msg.params[1] : null;
break;
case CHANNEL_NAMES_LIST:
if (userListBuffer.length > 0)
userListBuffer ~= " ";
userListBuffer ~= msg.message;
break;
case CHANNEL_NAMES_LIST_END:
setUserList(userListBuffer.dup);
Log.d("user list for " ~ name ~ " : " ~ userListBuffer);
userListBuffer = null;
break;
default:
break;
}
}
}
/// IRC Client connection implementation /// IRC Client connection implementation
class IRCClient : AsyncSocketCallback { class IRCClient : AsyncSocketCallback {
protected: protected:
@ -143,6 +230,7 @@ protected:
string _host; string _host;
ushort _port; ushort _port;
string _nick; string _nick;
IRCChannel[string] _channels;
void onDataReceived(AsyncSocket socket, ubyte[] data) { void onDataReceived(AsyncSocket socket, ubyte[] data) {
_readbuf ~= cast(char[])data; _readbuf ~= cast(char[])data;
// split by lines // split by lines
@ -182,6 +270,16 @@ protected:
case NOTICE: case NOTICE:
_callback.onIRCNotice(this, msg.sourceAddress, msg.target, msg.message); _callback.onIRCNotice(this, msg.sourceAddress, msg.target, msg.message);
break; break;
case CHANNEL_TOPIC:
case CHANNEL_TOPIC_SET_BY:
case CHANNEL_NAMES_LIST:
case CHANNEL_NAMES_LIST_END:
if (msg.target.startsWith("#")) {
auto channel = channelByName(msg.target, true);
channel.handleMessage(msg);
_callback.onIRCMessage(this, msg);
}
break;
default: default:
_callback.onIRCMessage(this, msg); _callback.onIRCMessage(this, msg);
break; break;
@ -206,6 +304,23 @@ public:
if (_socket) if (_socket)
destroy(_socket); destroy(_socket);
} }
IRCChannel removeChannel(string name) {
if (auto p = name in _channels) {
_channels.remove(name);
return *p;
}
return null;
}
IRCChannel channelByName(string name, bool createIfNotExist = false) {
if (auto p = name in _channels) {
return *p;
}
if (!createIfNotExist)
return null;
IRCChannel res = new IRCChannel(name);
_channels[name] = res;
return res;
}
@property string host() { return _host; } @property string host() { return _host; }
@property ushort port() { return _port; } @property ushort port() { return _port; }
@property string hostPort() { return "%s:%d".format(_host, _port); } @property string hostPort() { return "%s:%d".format(_host, _port); }

View File

@ -207,21 +207,32 @@ class IRCFrame : AppFrame, IRCClientCallback {
void onIRCMessage(IRCClient client, IRCMessage message) { void onIRCMessage(IRCClient client, IRCMessage message) {
IRCWindow w = getOrCreateWindowFor(client.hostPort); IRCWindow w = getOrCreateWindowFor(client.hostPort);
if (message.commandId < 1000) { switch (message.commandId) with (IRCCommand) {
// custom server messages case JOIN:
w.addLine(message.message); case PART:
return;
}
if (message.commandId == IRCCommand.JOIN || message.commandId == IRCCommand.PART) {
if (message.sourceAddress && !message.sourceAddress.nick.empty && message.target.startsWith("#")) { if (message.sourceAddress && !message.sourceAddress.nick.empty && message.target.startsWith("#")) {
w = getOrCreateWindowFor(message.target); w = getOrCreateWindowFor(message.target);
if (message.commandId == IRCCommand.JOIN) { if (message.commandId == JOIN) {
w.addLine("* " ~ message.sourceAddress.longName ~ " has joined " ~ message.target); w.addLine("* " ~ message.sourceAddress.longName ~ " has joined " ~ message.target);
} else { } else {
w.addLine("* " ~ message.sourceAddress.longName ~ " has left " ~ message.target ~ (message.message.empty ? "" : ("(Reason: " ~ message.message ~ ")"))); w.addLine("* " ~ message.sourceAddress.longName ~ " has left " ~ message.target ~ (message.message.empty ? "" : ("(Reason: " ~ message.message ~ ")")));
} }
} }
return; return;
case CHANNEL_NAMES_LIST_END:
if (message.target.startsWith("#")) {
w = getOrCreateWindowFor(message.target);
IRCChannel channel = _client.channelByName(message.target);
w.updateUserList(channel);
}
return;
default:
if (message.commandId < 1000) {
// custom server messages
w.addLine(message.message);
return;
}
break;
} }
w.addLine(message.msg); w.addLine(message.msg);
} }
@ -258,7 +269,7 @@ class IRCWindow : VerticalLayout, EditorActionHandler {
_listBox.minWidth = 100; _listBox.minWidth = 100;
_listBox.maxWidth = 200; _listBox.maxWidth = 200;
_listBox.orientation = Orientation.Vertical; _listBox.orientation = Orientation.Vertical;
_listBox.items = ["Nick1"d, "Nick2"d]; //_listBox.items = ["Nick1"d, "Nick2"d];
hlayout.addChild(new ResizerWidget(null, Orientation.Horizontal)); hlayout.addChild(new ResizerWidget(null, Orientation.Horizontal));
hlayout.addChild(_listBox); hlayout.addChild(_listBox);
_kind = IRCWindowKind.Channel; _kind = IRCWindowKind.Channel;
@ -278,6 +289,10 @@ class IRCWindow : VerticalLayout, EditorActionHandler {
if (visible) if (visible)
window.update(); window.update();
} }
void updateUserList(IRCChannel channel) {
_listBox.items = channel.userNames;
window.update();
}
bool onEditorAction(const Action action) { bool onEditorAction(const Action action) {
if (!_editLine.text.empty) { if (!_editLine.text.empty) {
string s = toUTF8(_editLine.text); string s = toUTF8(_editLine.text);
@ -288,8 +303,8 @@ class IRCWindow : VerticalLayout, EditorActionHandler {
string cmd = parseDelimitedParameter(s); string cmd = parseDelimitedParameter(s);
if (cmd == "/quit") { if (cmd == "/quit") {
_client.quit(param); _client.quit(s);
return; return true;
} }
string param = parseDelimitedParameter(s); string param = parseDelimitedParameter(s);
@ -303,6 +318,7 @@ class IRCWindow : VerticalLayout, EditorActionHandler {
_client.privMsg(param, s); _client.privMsg(param, s);
} else { } else {
Log.d("Unknown command: " ~ cmd); Log.d("Unknown command: " ~ cmd);
addLine("Supported commands: /nick /join /part /msg /quit");
} }
} else { } else {
// message // message