1 /** 2 * Send queue management 3 */ 4 module birchwood.client.sender; 5 6 import core.thread : Thread, dur; 7 8 import std.container.slist : SList; 9 import core.sync.mutex : Mutex; 10 import core.sync.condition : Condition; 11 12 import birchwood.client; 13 14 version(unittest) 15 { 16 import std.stdio : writeln; 17 } 18 19 /** 20 * Manages the send queue 21 */ 22 public final class SenderThread : Thread 23 { 24 /** 25 * The send queue 26 */ 27 private SList!(ubyte[]) sendQueue; 28 29 /** 30 * The send queue's lock 31 */ 32 private Mutex sendQueueLock; 33 34 /** 35 * Condition variable for waking 36 * up send queue reader 37 */ 38 private Condition sendQueueCond; 39 40 /** 41 * The associated IRC client 42 */ 43 private Client client; 44 45 /** 46 * Constructs a new sender thread with the associated 47 * client 48 * 49 * Params: 50 * client = the Client to associate with 51 * Throws: 52 * `SnoozeError` on failure to construct an 53 * `Event` or ensure ourselves 54 */ 55 this(Client client) 56 { 57 super(&sendHandlerFunc); 58 this.client = client; 59 this.sendQueueLock = new Mutex(); 60 this.sendQueueCond = new Condition(this.sendQueueLock); 61 } 62 63 /** 64 * Enqueues the raw message into the send queue 65 * for eventual sending 66 * 67 * Params: 68 * encodedMessage = the message to enqueue 69 */ 70 public void sq(ubyte[] encodedMessage) 71 { 72 /* Lock queue */ 73 sendQueueLock.lock(); 74 75 /* Add to queue */ 76 sendQueue.insertAfter(sendQueue[], encodedMessage); 77 78 /* Wake the sleeping message handler */ 79 sendQueueCond.notify(); 80 81 /* Unlock queue */ 82 sendQueueLock.unlock(); 83 } 84 85 /** 86 * The send queue worker function 87 */ 88 private void sendHandlerFunc() 89 { 90 while(client.isRunning()) 91 { 92 /* TODO: handle normal messages (xCount with fakeLagInBetween) */ 93 94 /* Lock the queue */ 95 sendQueueLock.lock(); 96 97 /* Sleep till woken (new message) */ 98 sendQueueCond.wait(); // TODO: Check SyncError? 99 100 foreach(ubyte[] message; sendQueue[]) 101 { 102 client.socket.send(message); 103 Thread.sleep(dur!("seconds")(client.connInfo.getFakeLag())); 104 } 105 106 /* Empty the send queue */ 107 sendQueue.clear(); 108 109 /* Unlock queue */ 110 sendQueueLock.unlock(); 111 } 112 } 113 114 /** 115 * Stops the send queue manager 116 */ 117 public void end() 118 { 119 /* Lock the queue */ 120 sendQueueLock.lock(); 121 122 /* Wake up sleeping thread (so it can exit) */ 123 sendQueueCond.notify(); 124 125 /* Unlock the queue */ 126 sendQueueLock.unlock(); 127 128 // Wait on the manager thread to end 129 join(); 130 } 131 }