gustav/source/Connection.d

480 lines
12 KiB
D

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;
import Channel;
import std.string;
import core.sync.mutex;
import gtk.Notebook;
import std.conv;
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;
private string[] auth;
private string statusText;
/* TODO: Check if we need to protect */
/* TODO: So far usage is in signal handlers (mutex safved) and within te-tl lock for notifications */
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 */
/**
* All joined Channel-s in this Connection
*/
private Notebook notebookSwitcher;
private Channel[] chans; /*TODO: Technically locking by GTK would make this not needed */
private Mutex chansLock;
private Channel focusedChan;
// public void setPrescence(string pres)
// {
// /* The new status */
// string newStatus =
// statusText = "";
// statusText =
// }
this(GUI gui, Address address, string[] auth)
{
super(&worker);
this.gui = gui;
this.address = address;
this.auth = auth;
/* Initialize locks */
initializeLocks();
statusText = "Hey there, I'm using Dnet!";
/* Start the notification atcher */
start();
}
/**
* Initializes all locks (other than GDK)
*/
private void initializeLocks()
{
chansLock = new Mutex();
}
private void worker()
{
/* Create a new Label */
currentChannelLabel = new Label("CHANNEL NAME GOES HERE");
/**
* Setup the tab for this connection
*/
te();
box = getChatPane();
gui.notebook.add(box);
//gui.notebook.setTabReorderable(box, true);
//gui.notebook setChildPacking(box, true, true, 0, GtkPackType.START);
// gui.mainWindow.
gui.notebook.setTabLabelText(box, auth[0]~"@"~address.toString());
gui.notebook.showAll();
tl();
/**
* Connects and logs in
*/
client = new DClient(address);
client.auth(auth[0], auth[1]); /* TODO: DO this without auth (the list in the loop, crahses server) */
/* Set your prescense */
client.setProperty("pres","available");
// te();
// import ProfileWIndow;
// ProfileWindow profile = new ProfileWindow(this, auth[0]);
// tl();
/**
* Notification loop
*
* Awaits notifications and then displays them
*/
while(true)
{
/* Receive a notification */
byte[] notificationData = client.awaitNotification();
writeln(notificationData);
te();
// import std.conv;
// textArea.add(new Label(to!(string)(notificationData)));
// textArea.showAll();
process(notificationData);
//gui.mainWindow.showAll();
// import gtk.InfoBar;
// InfoBar notificationBar = new InfoBar();
// notificationBar.add(new Label("Poes"));
// notificationBar.setMessageType(GtkMessageType.INFO);
// notificationBar
// box.add(notificationBar);
// notificationBar.showAll();
notebookSwitcher.showAll();
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");
writeln(data);
/* Decode is a test for assuming channel message received */
data = data[1..data.length];
/* Decode the [usernameLength, username] */
ubyte usernameLength = data[1];
writeln(usernameLength);
string username = cast(string)data[2..2+usernameLength];
writeln(username);
/* Decode the [channelLength, channel] */
ubyte channelLength = data[2+usernameLength];
writeln(channelLength);
string channel = cast(string)data[2+usernameLength+1..2+usernameLength+1+channelLength];
writeln(channel);
findChannel(channel).receiveMessage(username, cast(string)data[2+usernameLength+1+channelLength..data.length]);
writeln("hdsfhdk");
}
/* 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)
{
/* LeaveInfo: <channel>,<username> */
string[] leaveInfo = split(cast(string)data[2..data.length],",");
writeln("LeaveInfo: ",leaveInfo);
/* Decode the LeaveInfo */
string channel = leaveInfo[0];
string username = leaveInfo[1];
/* Find the channel */
Channel matchedChannel = findChannel(channel);
/* Channel leave */
matchedChannel.channelLeave(username);
}
/* If the notification was join (stype=1) */
else if(subType == 1)
{
/* JoinInfo: <channel>,<username> */
string[] joinInfo = split(cast(string)data[2..data.length],",");
writeln("JoinInfo: ",joinInfo);
/* Decode the JoinInfo */
string channel = joinInfo[0];
string username = joinInfo[1];
/* Find the channel */
Channel matchedChannel = findChannel(channel);
/* Channel join */
matchedChannel.channelJoin(username);
}
/* TODO: Unknown */
else
{
}
}
}
public void joinChannel(string channelName)
{
/* Check if we have joined this channel already */
Channel foundChannel = findChannel(channelName);
/* If we have joined this channel before */
if(foundChannel)
{
/* TODO: Switch to */
writeln("nope time: "~channelName);
}
/* If we haven't joined this channel before */
else
{
/* Join the channel */
client.join(channelName);
/* Create the Channel object */
Channel newChannel = new Channel(client, channelName);
/* Add the channel */
addChannel(newChannel);
/* Set as the `foundChannel` */
foundChannel = newChannel;
/* Get the Widgets container for this channel and add a tab for it */
notebookSwitcher.add(newChannel.getBox());
notebookSwitcher.setTabReorderable(newChannel.getBox(), true);
notebookSwitcher.setTabLabelText(newChannel.getBox(), newChannel.getName());
writeln("hdsjghjsd");
writeln("first time: "~channelName);
/* Get the user's list */
newChannel.populateUsersList();
}
/* Render recursively all children of the container and then the container itself */
box.showAll();
}
private void channelList()
{
te();
channelList_unsafe();
tl();
}
public DClient getClient()
{
return client;
}
/**
* 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));
channels.showAll();
}
}
public Channel findChannel(string channelName)
{
Channel result;
chansLock.lock();
foreach(Channel channel; chans)
{
if(cmp(channel.getName(), channelName) == 0)
{
result = channel;
break;
}
}
import std.stdio;
writeln("\""~channelName~"\"");
chansLock.unlock();
return result;
}
/**
* Adds the given channel to the tarcking list
*
* This adds the Channel object to the list of
* channels joined
*
* TODO: Migrate the gui.d channel join selectChannel
* here
* NOTE: You must manually join it though
*/
public void addChannel(Channel newChannel)
{
/* Add the channel to the `chans` tracking list */
chansLock.lock();
chans ~= newChannel;
chansLock.unlock();
/* Add the channel to the channels list (sidebar) */
writeln("Adding channel "~newChannel.getName());
Label babaBooey = new Label(newChannel.getName()); /* TODO: Fuck Pango, fix here but yeah _ */
babaBooey.setUseMarkup(false);
babaBooey.setText(newChannel.getName());
channels.add(babaBooey);
}
/**
* Called when you select a channel in the sidebar
*
* This moves you to the correct notebook tab for
* that channel
*/
private void viewChannel(ListBox s)
{
/* Get the name of the channel selected */
string channelSelected = (cast(Label)(s.getSelectedRow().getChild())).getText();
/* Check if we have joined this channel already */
Channel foundChannel = findChannel(channelSelected);
writeln(foundChannel is null);
/* Switch to the channel's pane */
notebookSwitcher.setCurrentPage(foundChannel.getBox());
box.showAll();
}
/**
* 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(&viewChannel);
channelBox.add(new Label("Channels"));
channelBox.add(channels);
// /* The user's box */
// Box userBox = new Box(GtkOrientation.VERTICAL, 1);
// /* The user's list */
// users = new ListBox();
// userBox.add(new Label("Users"));
// userBox.add(users);
// /* 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());
// import gtk.TextView;
// TextView f = new TextView();
// textBox.add(f);
notebookSwitcher = new Notebook();
notebookSwitcher.setScrollable(true);
//notebookSwitcher.add(newnew Label("test"));
box.add(channelBox);
box.add(notebookSwitcher);
// box.add(textBox);
//box.packEnd(notebookSwitcher,0,0,0);
// textBox.setChildPacking(scrollTextChats, true, true, 0, GtkPackType.START);
box.setChildPacking(notebookSwitcher, true, true, 0, GtkPackType.START);
return box;
}
private int getPageNum()
{
return gui.notebook.pageNum(box);
}
public void shutdown()
{
/* This is called from gui.d */
int pageNum = getPageNum();
if(pageNum == -1)
{
/* TODO: Error handling */
}
else
{
gui.notebook.removePage(pageNum);
gui.notebook.showAll();
}
}
}