summaryrefslogtreecommitdiff
path: root/src/client/requestbroker/RequestBroker.cpp
diff options
context:
space:
mode:
authorSimon Robertshaw <simon@hardwired.org.uk>2013-03-14 11:30:24 (GMT)
committer Simon Robertshaw <simon@hardwired.org.uk>2013-03-14 11:30:24 (GMT)
commit9479b7f3300658156c467980c28d3436a728bc0c (patch)
tree631a10f9fe9628d1250109f6b9c643d008591d39 /src/client/requestbroker/RequestBroker.cpp
parent7a055a9d90ea3464bbdc314df423e2aa768ce2be (diff)
downloadpowder-9479b7f3300658156c467980c28d3436a728bc0c.zip
powder-9479b7f3300658156c467980c28d3436a728bc0c.tar.gz
Move requestbroker into new folder, make request process function a method of Request
Diffstat (limited to 'src/client/requestbroker/RequestBroker.cpp')
-rw-r--r--src/client/requestbroker/RequestBroker.cpp300
1 files changed, 300 insertions, 0 deletions
diff --git a/src/client/requestbroker/RequestBroker.cpp b/src/client/requestbroker/RequestBroker.cpp
new file mode 100644
index 0000000..62e5fd7
--- /dev/null
+++ b/src/client/requestbroker/RequestBroker.cpp
@@ -0,0 +1,300 @@
+#include <algorithm>
+#include <iostream>
+#include <typeinfo>
+#include <sstream>
+#include <time.h>
+#include "RequestBroker.h"
+#include "RequestListener.h"
+#include "ThumbRenderRequest.h"
+#include "ImageRequest.h"
+#include "client/Client.h"
+#include "client/GameSave.h"
+
+//Asynchronous Thumbnail render & request processing
+
+RequestBroker::RequestBroker()
+{
+ thumbnailQueueRunning = false;
+
+ //listenersMutex = PTHREAD_MUTEX_INITIALIZER;
+ pthread_mutex_init (&listenersMutex, NULL);
+
+
+ pthread_mutex_init (&runningMutex, NULL);
+
+
+ pthread_mutex_init (&requestQueueMutex, NULL);
+
+
+ pthread_mutex_init (&completeQueueMutex, NULL);
+}
+
+RequestBroker::~RequestBroker()
+{
+ for(std::deque<std::pair<std::string, VideoBuffer*> >::iterator iter = imageCache.begin(), end = imageCache.end(); iter != end; ++iter)
+ {
+ delete (*iter).second;
+ }
+}
+
+void RequestBroker::assureRunning()
+{
+ pthread_mutex_lock(&runningMutex);
+ bool running = thumbnailQueueRunning;
+ thumbnailQueueRunning = true;
+ pthread_mutex_unlock(&runningMutex);
+
+ if(!running)
+ {
+#ifdef DEBUG
+ std::cout << typeid(*this).name() << " Starting background thread for new " << __FUNCTION__ << " request" << std::endl;
+#endif
+ pthread_create(&thumbnailQueueThread, 0, &RequestBroker::thumbnailQueueProcessHelper, this);
+ }
+}
+
+void RequestBroker::Shutdown()
+{
+ pthread_mutex_lock(&runningMutex);
+ if(thumbnailQueueRunning)
+ {
+ thumbnailQueueRunning = false;
+ pthread_mutex_unlock(&runningMutex);
+ pthread_join(thumbnailQueueThread, NULL);
+ }
+ else
+ pthread_mutex_unlock(&runningMutex);
+
+ std::vector<Request*>::iterator req = activeRequests.begin();
+ while(req != activeRequests.end())
+ {
+ (*req)->Cleanup();
+ delete (*req);
+ req++;
+ }
+}
+
+void RequestBroker::RenderThumbnail(GameSave * gameSave, int width, int height, RequestListener * tListener)
+{
+ RenderThumbnail(gameSave, true, true, width, height, tListener);
+}
+
+void RequestBroker::RenderThumbnail(GameSave * gameSave, bool decorations, bool fire, int width, int height, RequestListener * tListener)
+{
+ ListenerHandle handle = AttachRequestListener(tListener);
+
+ ThumbRenderRequest * r = new ThumbRenderRequest(new GameSave(*gameSave), decorations, fire, width, height, handle);
+
+ pthread_mutex_lock(&requestQueueMutex);
+ requestQueue.push_back(r);
+ pthread_mutex_unlock(&requestQueueMutex);
+
+ assureRunning();
+}
+
+void RequestBroker::RetrieveThumbnail(int saveID, int saveDate, int width, int height, RequestListener * tListener)
+{
+ std::stringstream urlStream;
+ urlStream << "http://" << STATICSERVER << "/" << saveID;
+ if(saveDate)
+ {
+ urlStream << "_" << saveDate;
+ }
+ urlStream << "_small.pti";
+
+ RetrieveImage(urlStream.str(), width, height, tListener);
+}
+
+void RequestBroker::RetrieveAvatar(std::string username, int width, int height, RequestListener * tListener)
+{
+ std::stringstream urlStream;
+ urlStream << "http://" << STATICSERVER << "/avatars/" << username << ".pti";
+
+ RetrieveImage(urlStream.str(), width, height, tListener);
+}
+
+void RequestBroker::RetrieveImage(std::string imageUrl, int width, int height, RequestListener * tListener)
+{
+ ListenerHandle handle = AttachRequestListener(tListener);
+
+ ImageRequest * r = new ImageRequest(imageUrl, width, height, handle);
+
+ pthread_mutex_lock(&requestQueueMutex);
+ requestQueue.push_back(r);
+ pthread_mutex_unlock(&requestQueueMutex);
+
+ assureRunning();
+}
+
+void * RequestBroker::thumbnailQueueProcessHelper(void * ref)
+{
+ ((RequestBroker*)ref)->thumbnailQueueProcessTH();
+ return NULL;
+}
+
+void RequestBroker::FlushThumbQueue()
+{
+ pthread_mutex_lock(&completeQueueMutex);
+ while(completeQueue.size())
+ {
+ if(CheckRequestListener(completeQueue.front()->Listener))
+ {
+ std::cout << typeid(*this).name() << " Calling listener: " << completeQueue.front()->Listener.second << std::endl;
+ std::cout.flush();
+ completeQueue.front()->Listener.second->OnResponseReady(completeQueue.front()->ResultObject);
+ }
+ else
+ {
+#ifdef DEBUG
+ std::cout << typeid(*this).name() << " Listener lost, discarding request" << std::endl;
+#endif
+ completeQueue.front()->Cleanup();
+ }
+ delete completeQueue.front();
+ completeQueue.pop();
+ }
+ pthread_mutex_unlock(&completeQueueMutex);
+}
+
+void RequestBroker::thumbnailQueueProcessTH()
+{
+ time_t lastAction = time(NULL);
+ pthread_mutex_lock(&runningMutex);
+ thumbnailQueueRunning = true;
+ pthread_mutex_unlock(&runningMutex);
+ while(true)
+ {
+ //Shutdown after 2 seconds of idle
+ if(time(NULL) - lastAction > 2)
+ {
+#ifdef DEBUG
+ std::cout << typeid(*this).name() << " Idle shutdown" << std::endl;
+#endif
+ break;
+ }
+
+
+ pthread_mutex_lock(&runningMutex);
+ bool running = thumbnailQueueRunning;
+ pthread_mutex_unlock(&runningMutex);
+ if(!running)
+ {
+#ifdef DEBUG
+ std::cout << typeid(*this).name() << " Requested shutdown" << std::endl;
+#endif
+ break;
+ }
+
+ if(activeRequests.size())
+ {
+ std::vector<Request*>::iterator req = activeRequests.begin();
+ while(req != activeRequests.end())
+ {
+ ProcessResponse resultStatus = OK;
+ Request * r = *req;
+ resultStatus = r->Process(*this);
+ if(resultStatus == Duplicate || resultStatus == Failed || resultStatus == Finished)
+ {
+ req = activeRequests.erase(req);
+ }
+ else
+ {
+ req++;
+ }
+ }
+ lastAction = time(NULL);
+ }
+
+ //Move any items from the request queue to the processing queue
+ pthread_mutex_lock(&requestQueueMutex);
+ std::vector<Request*>::iterator newReq = requestQueue.begin();
+ while(newReq != requestQueue.end())
+ {
+ if(activeRequests.size() > 5)
+ {
+ break;
+ }
+ else
+ {
+ activeRequests.push_back(*newReq);
+ newReq = requestQueue.erase(newReq);
+ }
+ }
+ pthread_mutex_unlock(&requestQueueMutex);
+ }
+ pthread_mutex_lock(&runningMutex);
+ thumbnailQueueRunning = false;
+ pthread_mutex_unlock(&runningMutex);
+}
+
+void RequestBroker::requestComplete(Request * completedRequest)
+{
+ pthread_mutex_lock(&completeQueueMutex);
+ completeQueue.push(completedRequest);
+ pthread_mutex_unlock(&completeQueueMutex);
+}
+
+
+void RequestBroker::RetrieveThumbnail(int saveID, int width, int height, RequestListener * tListener)
+{
+ RetrieveThumbnail(saveID, 0, width, height, tListener);
+}
+
+bool RequestBroker::CheckRequestListener(ListenerHandle handle)
+{
+ pthread_mutex_lock(&listenersMutex);
+ int count = std::count(validListeners.begin(), validListeners.end(), handle);
+ pthread_mutex_unlock(&listenersMutex);
+
+ return count;
+}
+
+ListenerHandle RequestBroker::AttachRequestListener(RequestListener * tListener)
+{
+ ListenerHandle handle = ListenerHandle(tListener->ListenerRand, tListener);
+ pthread_mutex_lock(&listenersMutex);
+ validListeners.push_back(handle);
+ pthread_mutex_unlock(&listenersMutex);
+ return handle;
+}
+
+void RequestBroker::DetachRequestListener(RequestListener * tListener)
+{
+ pthread_mutex_lock(&listenersMutex);
+
+ std::vector<ListenerHandle>::iterator iter = validListeners.begin();
+ while (iter != validListeners.end())
+ {
+ if(*iter == ListenerHandle(tListener->ListenerRand, tListener))
+ iter = validListeners.erase(iter);
+ else
+ ++iter;
+ }
+
+ pthread_mutex_unlock(&listenersMutex);
+}
+
+RequestBroker::Request::Request(RequestType type, ListenerHandle listener)
+{
+ Type = type;
+ Listener = listener;
+ ResultObject = NULL;
+}
+RequestBroker::Request::~Request()
+{
+ std::vector<Request*>::iterator iter = Children.begin();
+ while(iter != Children.end())
+ {
+ delete (*iter);
+ iter++;
+ }
+}
+void RequestBroker::Request::Cleanup()
+{
+ std::vector<Request*>::iterator iter = Children.begin();
+ while(iter != Children.end())
+ {
+ (*iter)->Cleanup();
+ iter++;
+ }
+} \ No newline at end of file