From 29d5ae626df9fa0946952a78e9f1e8869ef66ae6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Sat, 26 Feb 2011 20:36:33 +0100
Subject: Some more cleanups.


diff --git a/Sluift/linit.c b/Sluift/linit.c
index 0114c12..14299b3 100644
--- a/Sluift/linit.c
+++ b/Sluift/linit.c
@@ -25,6 +25,8 @@ static const char tprint[] =
 	"            tostring (key), tostring(value)))\n"
 	"      end\n"
 	"    end\n"
+	"  elseif type(tt) == \"nil\" then\n"
+	"    io.write(\"nil\\n\")\n"
 	"  else\n"
 	"    io.write(tt .. \"\\n\")\n"
 	"  end\n"
diff --git a/Sluift/sluift.cpp b/Sluift/sluift.cpp
index 086fb2a..fd7b695 100644
--- a/Sluift/sluift.cpp
+++ b/Sluift/sluift.cpp
@@ -18,6 +18,8 @@ extern "C" {
 #include <Swiften/JID/JID.h>
 #include <Swiften/EventLoop/SimpleEventLoop.h>
 #include <Swiften/Network/BoostNetworkFactories.h>
+#include <Swiften/Network/TimerFactory.h>
+#include <Swiften/Network/Timer.h>
 #include <Swiften/Base/sleep.h>
 #include <Swiften/Elements/SoftwareVersion.h>
 #include <Swiften/Queries/Requests/GetSoftwareVersionRequest.h>
@@ -40,6 +42,39 @@ bool debug = false;
 SimpleEventLoop eventLoop;
 BoostNetworkFactories networkFactories(&eventLoop);
 
+class Watchdog {
+	public:
+		Watchdog(int timeout) : timedOut(false) {
+			if (timeout > 0) {
+				timer = networkFactories.getTimerFactory()->createTimer(timeout);
+				timer->start();
+				timer->onTick.connect(boost::bind(&Watchdog::handleTimerTick, this));
+			}
+			else if (timeout == 0) {
+				timedOut = true;
+			}
+		}
+
+		~Watchdog() {
+			if (timer) {
+				timer->stop();
+			}
+		}
+
+		bool getTimedOut() const {
+			return timedOut;
+		}
+	
+	private:
+		void handleTimerTick() {
+			timedOut = true;
+		}
+	
+	private:
+		Timer::ref timer;
+		bool timedOut;
+};
+
 class SluiftException {
 	public:
 		SluiftException(const std::string& reason) : reason(reason) {
@@ -83,7 +118,7 @@ class SluiftClient {
 
 		void waitConnected() {
 			while (client->isActive() && !client->isAvailable()) {
-				processEvents();
+				eventLoop.runUntilEvents();
 			}
 		}
 
@@ -105,7 +140,7 @@ class SluiftClient {
 		void disconnect() {
 			client->disconnect();
 			while (client->isActive()) {
-				processEvents();
+				eventLoop.runUntilEvents();
 			}
 		}
 
@@ -120,35 +155,36 @@ class SluiftClient {
 			error.reset();
 			request->send();
 			while (!softwareVersion && !error) {
-				processEvents();
+				eventLoop.runUntilEvents();
 			}
 			return softwareVersion;
 		}
 
-		Stanza::ref getNextEvent() {
-			if (client->isActive() && !pendingEvents.empty()) {
+		Stanza::ref getNextEvent(int timeout) {
+			eventLoop.runOnce();
+			if (!pendingEvents.empty()) {
 				Stanza::ref event = pendingEvents.front();
 				pendingEvents.pop_front();
 				return event;
 			}
-			while (client->isActive() && pendingEvents.empty()) {
-				processEvents();
+			Watchdog watchdog(timeout);
+			while (!watchdog.getTimedOut() && pendingEvents.empty()) {
+				eventLoop.runUntilEvents();
+			}
+			if (watchdog.getTimedOut()) {
+				return Stanza::ref();
 			}
-			if (client->isActive()) {
-				assert(!pendingEvents.empty());
+			else {
 				Stanza::ref event = pendingEvents.front();
 				pendingEvents.pop_front();
 				return event;
 			}
-			else {
-				return Stanza::ref();
-			}
 		}
 
 		std::vector<XMPPRosterItem> getRoster() {
 			client->requestRoster();
 			while (!rosterReceived) {
-				processEvents();
+				eventLoop.runUntilEvents();
 			}
 			return client->getRoster()->getItems();
 		}
@@ -162,10 +198,6 @@ class SluiftClient {
 			rosterReceived = true;
 		}
 
-		void processEvents() {
-			eventLoop.runUntilEvents();
-		}
-
 		void handleSoftwareVersionResponse(boost::shared_ptr<SoftwareVersion> version, ErrorPayload::ref error) {
 			if (error) {
 				this->error = error;
@@ -224,11 +256,6 @@ class SluiftClient {
 		std::deque<Stanza::ref> pendingEvents;
 };
 
-#define CHECK_CLIENT_CONNECTED(client, L) \
-	if (!(*client)->isConnected()) { \
-		lua_pushnil(L); \
-	} 
-
 /*******************************************************************************
  * Client functions.
  ******************************************************************************/
@@ -331,17 +358,6 @@ static int sluift_client_get_roster(lua_State *L) {
 
 			lua_setfield(L, -2, item.getJID().toString().c_str());
 		}
-		/*boost::optional<SoftwareVersion> version = client->getSoftwareVersion(jid);
-		if (version) {
-		lua_pushstring(L, version->getName().c_str());
-			lua_pushstring(L, version->getName().c_str());
-			lua_setfield(L, -2, "name");
-			lua_pushstring(L, version->getVersion().c_str());
-			lua_setfield(L, -2, "version");
-			lua_pushstring(L, version->getOS().c_str());
-			lua_setfield(L, -2, "os");
-		}
-		*/
 		return 1;
 	}
 	catch (const SluiftException& e) {
@@ -395,23 +411,25 @@ static int sluift_client_set_options(lua_State* L) {
 	return 0;
 }
 
-static int sluift_client_for_event (lua_State *L) {
+static int sluift_client_for_event(lua_State *L) {
 	try {
 		SluiftClient* client = getClient(L);
 		luaL_checktype(L, 2, LUA_TFUNCTION);
+		int timeout = -1;
+		if (lua_type(L, 3) != LUA_TNONE) {
+			timeout = lua_tonumber(L, 3);
+		}
+
 		while (true) {
-			Stanza::ref event = client->getNextEvent();
+			Stanza::ref event = client->getNextEvent(timeout);
 			if (!event) {
-				// We got disconnected
+				// We got a timeout
 				lua_pushnil(L);
-				lua_pushliteral(L, "disconnected");
-				return 2;
+				return 1;
 			}
 			else {
-				// Push the function on the stack
+				// Push the function and event on the stack
 				lua_pushvalue(L, 2);
-
-				bool emitEvent = false;
 				if (Message::ref message = boost::dynamic_pointer_cast<Message>(event)) {
 					lua_createtable(L, 0, 3);
 					lua_pushliteral(L, "message");
@@ -420,7 +438,6 @@ static int sluift_client_for_event (lua_State *L) {
 					lua_setfield(L, -2, "from");
 					lua_pushstring(L, message->getBody().c_str());
 					lua_setfield(L, -2, "body");
-					emitEvent = true;
 				}
 				else if (Presence::ref presence = boost::dynamic_pointer_cast<Presence>(event)) {
 					lua_createtable(L, 0, 3);
@@ -430,24 +447,17 @@ static int sluift_client_for_event (lua_State *L) {
 					lua_setfield(L, -2, "from");
 					lua_pushstring(L, presence->getStatus().c_str());
 					lua_setfield(L, -2, "status");
-					emitEvent = true;
 				}
 				else {
 					assert(false);
+					lua_pushnil(L);
 				}
-				if (emitEvent) {
-					int oldTop = lua_gettop(L) - 2;
-					lua_call(L, 1, LUA_MULTRET);
-					int returnValues = lua_gettop(L) - oldTop;
-					if (returnValues > 0) {
-						lua_remove(L, -1 - returnValues);
-						return returnValues;
-					}
-				}
-				else {
-					// Remove the function from the stack again, since
-					// we're not calling the function
-					lua_pop(L, 1);
+				int oldTop = lua_gettop(L) - 2;
+				lua_call(L, 1, LUA_MULTRET);
+				int returnValues = lua_gettop(L) - oldTop;
+				if (returnValues > 0) {
+					lua_remove(L, -1 - returnValues);
+					return returnValues;
 				}
 			}
 		}
diff --git a/Swiften/EventLoop/SimpleEventLoop.cpp b/Swiften/EventLoop/SimpleEventLoop.cpp
index 2d71544..b77639c 100644
--- a/Swiften/EventLoop/SimpleEventLoop.cpp
+++ b/Swiften/EventLoop/SimpleEventLoop.cpp
@@ -44,6 +44,17 @@ void SimpleEventLoop::doRun(bool breakAfterEvents) {
 	}
 }
 
+void SimpleEventLoop::runOnce() {
+	std::vector<Event> events;
+	{
+		boost::unique_lock<boost::mutex> lock(eventsMutex_);
+		events.swap(events_);
+	}
+	foreach(const Event& event, events) {
+		handleEvent(event);
+	}
+}
+
 void SimpleEventLoop::stop() {
 	postEvent(boost::bind(&SimpleEventLoop::doStop, this));
 }
diff --git a/Swiften/EventLoop/SimpleEventLoop.h b/Swiften/EventLoop/SimpleEventLoop.h
index bdffa3d..6fb3f53 100644
--- a/Swiften/EventLoop/SimpleEventLoop.h
+++ b/Swiften/EventLoop/SimpleEventLoop.h
@@ -27,6 +27,8 @@ namespace Swift {
 				doRun(true);
 			}
 
+			void runOnce();
+
 			void stop();
 
 			virtual void post(const Event& event);
diff --git a/Swiften/QA/ScriptedTests/SendMessage.lua b/Swiften/QA/ScriptedTests/SendMessage.lua
index a3f1917..8c54d00 100644
--- a/Swiften/QA/ScriptedTests/SendMessage.lua
+++ b/Swiften/QA/ScriptedTests/SendMessage.lua
@@ -33,12 +33,12 @@ received_message = client2:for_event(function(event)
 		if event["type"] == "message" and event["from"] == client1_jid then
 			return event["body"]
 		end
-	end)
+	end, 10000)
 assert(received_message == "Hello")
 
 print "Retrieving the roster"
 roster = client1:get_roster()
-table.foreach(roster, print)
+tprint(roster)
 
 client1:disconnect()
 client2:disconnect()
-- 
cgit v0.10.2-6-g49f6