2020-10-17 11:54:07 +00:00
|
|
|
module Connection;
|
|
|
|
|
|
|
|
import core.thread;
|
|
|
|
import gui;
|
|
|
|
import gdk.Threads : te = threadsEnter, tl = threadsLeave;
|
|
|
|
import gtk.Box;
|
|
|
|
import std.stdio;
|
|
|
|
import libdnet.dclient;
|
|
|
|
import std.socket;
|
|
|
|
import gtk.ListBox;
|
|
|
|
import gtk.Label;
|
|
|
|
|
2020-10-17 19:05:21 +00:00
|
|
|
import Channel;
|
2020-10-18 09:49:04 +00:00
|
|
|
import std.string;
|
2020-10-17 19:05:21 +00:00
|
|
|
|
2020-10-18 10:06:05 +00:00
|
|
|
import core.sync.mutex;
|
|
|
|
|
2020-10-18 10:12:03 +00:00
|
|
|
import gtk.Notebook;
|
|
|
|
|
2020-10-17 11:54:07 +00:00
|
|
|
public final class Connection : Thread
|
|
|
|
{
|
|
|
|
private GUI gui;
|
|
|
|
private Box box;
|
|
|
|
private ListBox channels;
|
|
|
|
private ListBox users;
|
|
|
|
private ListBox textArea;
|
|
|
|
|
|
|
|
private DClient client;
|
|
|
|
private Address address;
|
2020-10-17 13:58:09 +00:00
|
|
|
private string[] auth;
|
2020-10-19 12:06:14 +00:00
|
|
|
private string statusText;
|
2020-10-17 11:54:07 +00:00
|
|
|
|
2020-10-17 12:26:17 +00:00
|
|
|
/* TODO: Check if we need to protect */
|
|
|
|
/* TODO: So far usage is in signal handlers (mutex safved) and within te-tl lock for notifications */
|
2020-10-17 18:26:23 +00:00
|
|
|
private string currentChannel; /* TODO: Used to track what notificaitons come throug */
|
|
|
|
private Label currentChannelLabel; /* TODO: Using getChild would be nicer, but yeah, this is for the title */
|
2020-10-17 12:26:17 +00:00
|
|
|
|
2020-10-17 19:05:21 +00:00
|
|
|
/**
|
|
|
|
* All joined Channel-s in this Connection
|
|
|
|
*/
|
2020-10-18 10:12:03 +00:00
|
|
|
private Notebook notebookSwitcher;
|
2020-10-18 10:06:05 +00:00
|
|
|
private Channel[] chans; /*TODO: Technically locking by GTK would make this not needed */
|
|
|
|
private Mutex chansLock;
|
|
|
|
private Channel focusedChan;
|
2020-10-17 19:05:21 +00:00
|
|
|
|
2020-10-19 12:06:14 +00:00
|
|
|
|
|
|
|
// public void setPrescence(string pres)
|
|
|
|
// {
|
|
|
|
// /* The new status */
|
|
|
|
// string newStatus =
|
|
|
|
// statusText = "";
|
|
|
|
// statusText =
|
|
|
|
// }
|
|
|
|
|
2020-10-17 13:58:09 +00:00
|
|
|
this(GUI gui, Address address, string[] auth)
|
2020-10-17 11:54:07 +00:00
|
|
|
{
|
|
|
|
super(&worker);
|
|
|
|
this.gui = gui;
|
|
|
|
this.address = address;
|
2020-10-17 13:58:09 +00:00
|
|
|
this.auth = auth;
|
2020-10-18 10:06:05 +00:00
|
|
|
|
|
|
|
/* Initialize locks */
|
|
|
|
initializeLocks();
|
|
|
|
|
2020-10-19 12:06:14 +00:00
|
|
|
statusText = "Hey there, I'm using Dnet!";
|
|
|
|
|
2020-10-18 10:06:05 +00:00
|
|
|
/* Start the notification atcher */
|
2020-10-17 11:54:07 +00:00
|
|
|
start();
|
|
|
|
}
|
|
|
|
|
2020-10-18 10:06:05 +00:00
|
|
|
/**
|
|
|
|
* Initializes all locks (other than GDK)
|
|
|
|
*/
|
|
|
|
private void initializeLocks()
|
|
|
|
{
|
|
|
|
chansLock = new Mutex();
|
|
|
|
}
|
|
|
|
|
2020-10-17 11:54:07 +00:00
|
|
|
private void worker()
|
|
|
|
{
|
2020-10-17 18:26:23 +00:00
|
|
|
/* Create a new Label */
|
|
|
|
currentChannelLabel = new Label("CHANNEL NAME GOES HERE");
|
|
|
|
|
2020-10-17 12:32:26 +00:00
|
|
|
/**
|
|
|
|
* Setup the tab for this connection
|
|
|
|
*/
|
2020-10-17 11:54:07 +00:00
|
|
|
te();
|
|
|
|
box = getChatPane();
|
|
|
|
gui.notebook.add(box);
|
2020-10-19 12:57:16 +00:00
|
|
|
gui.notebook.setTabReorderable(box, true);
|
2020-10-17 18:26:23 +00:00
|
|
|
//gui.notebook setChildPacking(box, true, true, 0, GtkPackType.START);
|
|
|
|
// gui.mainWindow.
|
2020-10-17 13:58:09 +00:00
|
|
|
gui.notebook.setTabLabelText(box, auth[0]~"@"~address.toString());
|
2020-10-17 12:29:41 +00:00
|
|
|
gui.notebook.showAll();
|
2020-10-17 11:54:07 +00:00
|
|
|
tl();
|
|
|
|
|
2020-10-17 12:32:26 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Connects and logs in
|
|
|
|
*/
|
2020-10-17 11:54:07 +00:00
|
|
|
client = new DClient(address);
|
2020-10-17 13:58:09 +00:00
|
|
|
client.auth(auth[0], auth[1]); /* TODO: DO this without auth (the list in the loop, crahses server) */
|
2020-10-17 11:54:07 +00:00
|
|
|
|
2020-10-17 12:32:26 +00:00
|
|
|
/* Display all channels */
|
2020-10-17 11:54:07 +00:00
|
|
|
channelList();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Notification loop
|
|
|
|
*
|
|
|
|
* Awaits notifications and then displays them
|
|
|
|
*/
|
|
|
|
while(true)
|
|
|
|
{
|
|
|
|
/* Receive a notification */
|
|
|
|
byte[] notificationData = client.awaitNotification();
|
|
|
|
writeln(notificationData);
|
|
|
|
|
|
|
|
te();
|
2020-10-18 10:12:03 +00:00
|
|
|
// import std.conv;
|
|
|
|
// textArea.add(new Label(to!(string)(notificationData)));
|
|
|
|
// textArea.showAll();
|
2020-10-19 12:57:16 +00:00
|
|
|
|
2020-10-17 11:54:07 +00:00
|
|
|
|
|
|
|
process(notificationData);
|
2020-10-17 12:10:04 +00:00
|
|
|
//gui.mainWindow.showAll();
|
2020-10-17 11:54:07 +00:00
|
|
|
|
2020-10-18 11:43:23 +00:00
|
|
|
notebookSwitcher.showAll();
|
2020-10-19 11:44:58 +00:00
|
|
|
|
2020-10-18 11:43:23 +00:00
|
|
|
|
2020-10-17 11:54:07 +00:00
|
|
|
tl();
|
|
|
|
|
|
|
|
//Thread.sleep(dur!("seconds")(2));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Processes an incoming notification
|
|
|
|
* accordingly
|
|
|
|
*/
|
|
|
|
private void process(byte[] data)
|
|
|
|
{
|
|
|
|
/* TODO: Implement me */
|
|
|
|
|
|
|
|
/* TODO: Check notification type */
|
|
|
|
ubyte notificationType = data[0];
|
|
|
|
|
|
|
|
/* For normal message (to channel or user) */
|
|
|
|
if(notificationType == 0)
|
|
|
|
{
|
|
|
|
/* TODO: Decode using tristanable */
|
|
|
|
writeln("new message");
|
|
|
|
}
|
|
|
|
/* Channel notification (ntype=1) */
|
|
|
|
else if(notificationType == 1)
|
|
|
|
{
|
|
|
|
/* Get the sub-type */
|
|
|
|
ubyte subType = data[1];
|
|
|
|
|
|
|
|
/* If the notification was leave (stype=0) */
|
|
|
|
if(subType == 0)
|
|
|
|
{
|
2020-10-18 11:27:47 +00:00
|
|
|
/* LeaveInfo: <channel>,<username> */
|
|
|
|
string[] leaveInfo = split(cast(string)data[2..data.length],",");
|
2020-10-18 11:43:23 +00:00
|
|
|
writeln("LeaveInfo: ",leaveInfo);
|
|
|
|
|
2020-10-18 11:44:42 +00:00
|
|
|
/* Decode the LeaveInfo */
|
2020-10-18 11:43:23 +00:00
|
|
|
string channel = leaveInfo[0];
|
|
|
|
string username = leaveInfo[1];
|
|
|
|
|
|
|
|
/* Find the channel */
|
|
|
|
Channel matchedChannel = findChannel(channel);
|
|
|
|
|
2020-10-18 12:26:50 +00:00
|
|
|
/* Channel leave */
|
|
|
|
matchedChannel.channelLeave(username);
|
2020-10-17 11:54:07 +00:00
|
|
|
}
|
|
|
|
/* If the notification was join (stype=1) */
|
|
|
|
else if(subType == 1)
|
|
|
|
{
|
2020-10-18 11:27:47 +00:00
|
|
|
/* JoinInfo: <channel>,<username> */
|
|
|
|
string[] joinInfo = split(cast(string)data[2..data.length],",");
|
2020-10-18 11:43:23 +00:00
|
|
|
writeln("JoinInfo: ",joinInfo);
|
|
|
|
|
2020-10-18 11:44:42 +00:00
|
|
|
/* Decode the JoinInfo */
|
2020-10-18 11:43:23 +00:00
|
|
|
string channel = joinInfo[0];
|
|
|
|
string username = joinInfo[1];
|
|
|
|
|
|
|
|
/* Find the channel */
|
|
|
|
Channel matchedChannel = findChannel(channel);
|
|
|
|
|
2020-10-18 12:26:50 +00:00
|
|
|
/* Channel join */
|
|
|
|
matchedChannel.channelJoin(username);
|
2020-10-17 11:54:07 +00:00
|
|
|
}
|
|
|
|
/* TODO: Unknown */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void channelList()
|
|
|
|
{
|
|
|
|
te();
|
|
|
|
channelList_unsafe();
|
|
|
|
tl();
|
|
|
|
}
|
|
|
|
|
2020-10-18 19:41:22 +00:00
|
|
|
public DClient getClient()
|
|
|
|
{
|
|
|
|
return client;
|
|
|
|
}
|
|
|
|
|
2020-10-17 11:54:07 +00:00
|
|
|
/**
|
|
|
|
* Lists all channels and displays them
|
|
|
|
*
|
|
|
|
* Only to be aclled when locked (i.e. by the event
|
|
|
|
* loop signal dispatch or when we lock it
|
|
|
|
* i.e. `channelList`)
|
|
|
|
*/
|
|
|
|
private void channelList_unsafe()
|
|
|
|
{
|
|
|
|
string[] channelList = client.list();
|
|
|
|
|
|
|
|
foreach(string channel; channelList)
|
|
|
|
{
|
|
|
|
channels.add(new Label(channel));
|
2020-10-17 12:10:04 +00:00
|
|
|
channels.showAll();
|
2020-10-17 11:54:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-18 10:06:05 +00:00
|
|
|
private Channel findChannel(string channelName)
|
2020-10-18 09:49:04 +00:00
|
|
|
{
|
2020-10-18 10:06:05 +00:00
|
|
|
Channel result;
|
|
|
|
|
|
|
|
chansLock.lock();
|
2020-10-18 09:49:04 +00:00
|
|
|
|
|
|
|
foreach(Channel channel; chans)
|
|
|
|
{
|
2020-10-18 10:21:23 +00:00
|
|
|
if(cmp(channel.getName(), channelName) == 0)
|
2020-10-18 09:49:04 +00:00
|
|
|
{
|
2020-10-18 10:06:05 +00:00
|
|
|
result = channel;
|
2020-10-18 09:49:04 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-18 10:06:05 +00:00
|
|
|
chansLock.unlock();
|
2020-10-18 09:49:04 +00:00
|
|
|
|
|
|
|
return result;
|
2020-10-18 10:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void addChannel(Channel newChannel)
|
|
|
|
{
|
|
|
|
chansLock.lock();
|
2020-10-18 09:49:04 +00:00
|
|
|
|
2020-10-18 10:06:05 +00:00
|
|
|
chans ~= newChannel;
|
|
|
|
|
|
|
|
chansLock.unlock();
|
2020-10-18 09:49:04 +00:00
|
|
|
}
|
|
|
|
|
2020-10-17 11:54:07 +00:00
|
|
|
private void selectChannel(ListBox s)
|
|
|
|
{
|
2020-10-17 12:06:38 +00:00
|
|
|
/* Get the name of the channel selected */
|
|
|
|
string channelSelected = (cast(Label)(s.getSelectedRow().getChild())).getText();
|
|
|
|
|
2020-10-18 09:49:04 +00:00
|
|
|
/* Check if we have joined this channel already */
|
2020-10-18 10:06:05 +00:00
|
|
|
Channel foundChannel = findChannel(channelSelected);
|
2020-10-18 09:49:04 +00:00
|
|
|
|
2020-10-18 10:06:05 +00:00
|
|
|
/* If we have joined this channel before */
|
|
|
|
if(foundChannel)
|
|
|
|
{
|
|
|
|
/* TODO: Switch to */
|
2020-10-18 10:21:23 +00:00
|
|
|
writeln("nope time: "~channelSelected);
|
2020-10-18 10:24:30 +00:00
|
|
|
|
|
|
|
|
2020-10-18 10:06:05 +00:00
|
|
|
}
|
|
|
|
/* If we haven't joined this channel before */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Join the channel */
|
|
|
|
client.join(channelSelected);
|
2020-10-17 12:06:38 +00:00
|
|
|
|
2020-10-18 10:06:05 +00:00
|
|
|
/* Create the Channel object */
|
2020-10-18 10:34:06 +00:00
|
|
|
Channel newChannel = new Channel(client, channelSelected);
|
2020-10-17 12:26:17 +00:00
|
|
|
|
2020-10-18 10:06:05 +00:00
|
|
|
/* Add the channel */
|
|
|
|
addChannel(newChannel);
|
2020-10-17 12:06:38 +00:00
|
|
|
|
2020-10-18 10:06:05 +00:00
|
|
|
/* Set as the `foundChannel` */
|
|
|
|
foundChannel = newChannel;
|
2020-10-18 10:16:48 +00:00
|
|
|
|
|
|
|
/* Get the Widgets container for this channel and add a tab for it */
|
|
|
|
notebookSwitcher.add(newChannel.getBox());
|
2020-10-18 10:34:06 +00:00
|
|
|
notebookSwitcher.setTabLabelText(newChannel.getBox(), newChannel.getName());
|
2020-10-18 10:16:48 +00:00
|
|
|
|
|
|
|
writeln("hdsjghjsd");
|
2020-10-18 10:21:23 +00:00
|
|
|
|
|
|
|
writeln("first time: "~channelSelected);
|
2020-10-18 10:34:06 +00:00
|
|
|
|
|
|
|
/* Get the user's list */
|
|
|
|
newChannel.populateUsersList();
|
2020-10-17 12:06:38 +00:00
|
|
|
}
|
2020-10-17 17:32:31 +00:00
|
|
|
|
2020-10-18 10:24:30 +00:00
|
|
|
/* Switch to the channel's pane */
|
|
|
|
notebookSwitcher.setCurrentPage(foundChannel.getBox());
|
|
|
|
|
2020-10-18 10:21:23 +00:00
|
|
|
box.showAll();
|
|
|
|
// notebookSwitcher.showAll();
|
2020-10-18 10:16:48 +00:00
|
|
|
|
2020-10-18 10:06:05 +00:00
|
|
|
/* TODO: Now add the widget */
|
|
|
|
|
|
|
|
// /* Set this as the currently selected channel */
|
|
|
|
// currentChannel = channelSelected;
|
|
|
|
// currentChannelLabel.setText(currentChannel);
|
|
|
|
// // currentChannelLabel.show();
|
|
|
|
// // box.show();
|
|
|
|
|
|
|
|
// /* Fetch a list of members */
|
|
|
|
// string[] members = client.getMembers(channelSelected);
|
|
|
|
|
|
|
|
// /* Display the members */
|
|
|
|
// users.removeAll();
|
|
|
|
// foreach(string member; members)
|
|
|
|
// {
|
|
|
|
// users.add(new Label(member));
|
|
|
|
// users.showAll();
|
|
|
|
// }
|
|
|
|
|
|
|
|
// /* Clear the text area */
|
|
|
|
// textArea.removeAll();
|
|
|
|
// textArea.showAll();
|
2020-10-17 11:54:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a message box
|
|
|
|
*
|
|
|
|
* A message box consists of two labels
|
|
|
|
* one being the name of the person who sent
|
|
|
|
* the message and the next being the message
|
|
|
|
* itself
|
|
|
|
*/
|
|
|
|
private Box createMessageBox()
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
private Box getChatPane()
|
|
|
|
{
|
|
|
|
/* The main page of the tab */
|
|
|
|
Box box = new Box(GtkOrientation.HORIZONTAL, 1);
|
|
|
|
|
|
|
|
/* The channels box */
|
|
|
|
Box channelBox = new Box(GtkOrientation.VERTICAL, 1);
|
|
|
|
|
|
|
|
/* The channel's list */
|
|
|
|
channels = new ListBox();
|
|
|
|
channels.addOnSelectedRowsChanged(&selectChannel);
|
|
|
|
|
|
|
|
channelBox.add(new Label("Channels"));
|
|
|
|
channelBox.add(channels);
|
|
|
|
|
2020-10-18 10:06:05 +00:00
|
|
|
// /* The user's box */
|
|
|
|
// Box userBox = new Box(GtkOrientation.VERTICAL, 1);
|
2020-10-17 11:54:07 +00:00
|
|
|
|
2020-10-18 10:06:05 +00:00
|
|
|
// /* The user's list */
|
|
|
|
// users = new ListBox();
|
2020-10-17 11:54:07 +00:00
|
|
|
|
2020-10-18 10:06:05 +00:00
|
|
|
// userBox.add(new Label("Users"));
|
|
|
|
// userBox.add(users);
|
2020-10-17 11:54:07 +00:00
|
|
|
|
2020-10-18 10:06:05 +00:00
|
|
|
// /* The text box */
|
|
|
|
// Box textBox = new Box(GtkOrientation.VERTICAL, 1);
|
|
|
|
// textBox.add(currentChannelLabel);
|
|
|
|
// textArea = new ListBox();
|
|
|
|
// import gtk.ScrolledWindow;
|
|
|
|
|
|
|
|
// ScrolledWindow scrollTextChats = new ScrolledWindow(textArea);
|
|
|
|
// textBox.add(scrollTextChats);
|
|
|
|
// import gtk.TextView;
|
|
|
|
// textBox.add(new TextView());
|
2020-10-17 19:05:21 +00:00
|
|
|
|
2020-10-17 11:54:07 +00:00
|
|
|
|
2020-10-17 18:33:18 +00:00
|
|
|
// import gtk.TextView;
|
|
|
|
// TextView f = new TextView();
|
|
|
|
// textBox.add(f);
|
2020-10-18 10:12:03 +00:00
|
|
|
|
|
|
|
notebookSwitcher = new Notebook();
|
2020-10-18 20:47:51 +00:00
|
|
|
notebookSwitcher.setScrollable(true);
|
2020-10-18 10:16:48 +00:00
|
|
|
//notebookSwitcher.add(newnew Label("test"));
|
2020-10-17 11:54:07 +00:00
|
|
|
|
|
|
|
box.add(channelBox);
|
2020-10-18 10:12:03 +00:00
|
|
|
box.add(notebookSwitcher);
|
2020-10-18 10:06:05 +00:00
|
|
|
// box.add(textBox);
|
2020-10-18 10:12:03 +00:00
|
|
|
//box.packEnd(notebookSwitcher,0,0,0);
|
2020-10-17 13:58:09 +00:00
|
|
|
|
2020-10-18 10:06:05 +00:00
|
|
|
// textBox.setChildPacking(scrollTextChats, true, true, 0, GtkPackType.START);
|
2020-10-18 10:12:03 +00:00
|
|
|
box.setChildPacking(notebookSwitcher, true, true, 0, GtkPackType.START);
|
2020-10-17 13:58:09 +00:00
|
|
|
|
|
|
|
|
2020-10-17 11:54:07 +00:00
|
|
|
|
|
|
|
return box;
|
|
|
|
}
|
|
|
|
|
2020-10-17 12:26:17 +00:00
|
|
|
private int getPageNum()
|
|
|
|
{
|
|
|
|
return gui.notebook.pageNum(box);
|
|
|
|
}
|
|
|
|
|
2020-10-17 11:54:07 +00:00
|
|
|
public void shutdown()
|
|
|
|
{
|
|
|
|
/* This is called from gui.d */
|
2020-10-17 12:26:17 +00:00
|
|
|
int pageNum = getPageNum();
|
2020-10-17 11:54:07 +00:00
|
|
|
|
|
|
|
if(pageNum == -1)
|
|
|
|
{
|
|
|
|
/* TODO: Error handling */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gui.notebook.removePage(pageNum);
|
2020-10-17 12:28:54 +00:00
|
|
|
gui.notebook.showAll();
|
2020-10-17 11:54:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|