From f05044ab68e51ce9c374f6af09284051efcda449 Mon Sep 17 00:00:00 2001 From: Simon Robertshaw Date: Sat, 16 Mar 2013 17:45:18 +0000 Subject: [PATCH] APIRequest, Aync methods for client, Profile edit/viewer (WIP) --- src/client/Client.cpp | 55 +++++++++++----- src/client/Client.h | 5 +- src/client/UserInfo.h | 22 +++++++ src/client/requestbroker/APIRequest.cpp | 77 ++++++++++++++++++++++ src/client/requestbroker/APIRequest.h | 15 +++++ src/client/requestbroker/APIResultParser.h | 16 +++++ src/client/requestbroker/RequestBroker.cpp | 12 ++++ src/client/requestbroker/RequestBroker.h | 4 +- src/game/GameController.cpp | 12 +++- src/options/OptionsController.cpp | 5 ++ src/options/OptionsController.h | 1 + src/options/OptionsModel.cpp | 11 ++++ src/options/OptionsModel.h | 2 + src/options/OptionsView.cpp | 18 ++++- src/options/OptionsView.h | 1 + src/preview/PreviewView.cpp | 2 + src/profile/ProfileActivity.cpp | 68 +++++++++++++++++++ src/profile/ProfileActivity.h | 17 +++++ 18 files changed, 320 insertions(+), 23 deletions(-) create mode 100644 src/client/UserInfo.h create mode 100644 src/client/requestbroker/APIRequest.cpp create mode 100644 src/client/requestbroker/APIRequest.h create mode 100644 src/client/requestbroker/APIResultParser.h create mode 100644 src/profile/ProfileActivity.cpp create mode 100644 src/profile/ProfileActivity.h diff --git a/src/client/Client.cpp b/src/client/Client.cpp index a43c45b64..dcd490340 100644 --- a/src/client/Client.cpp +++ b/src/client/Client.cpp @@ -39,10 +39,13 @@ #include "client/SaveInfo.h" #include "client/SaveFile.h" #include "client/GameSave.h" +#include "client/UserInfo.h" #include "search/Thumbnail.h" #include "preview/Comment.h" #include "ClientListener.h" #include "requestbroker/RequestBroker.h" +#include "requestbroker/APIRequest.h" +#include "requestbroker/APIResultParser.h" #include "cajun/reader.h" #include "cajun/writer.h" @@ -1178,26 +1181,42 @@ std::vector Client::GetSaveData(int saveID, int saveDate) return saveData; } -VideoBuffer * Client::GetAvatar(std::string username) +RequestBroker::Request * Client::GetUserInfoAsync(std::string username) { - lastError = ""; - int dataStatus; - int dataLength = 0; - unsigned char * data; - std::stringstream urlStream; - urlStream << "http://" << STATICSERVER << "/avatars/" << username << ".pti"; + class UserInfoParser: public APIResultParser + { + virtual void * ProcessResponse(unsigned char * data, int dataLength) + { + try + { + std::istringstream dataStream((char*)data); + json::Object objDocument; + json::Reader::Read(objDocument, dataStream); + json::Object tempUser = objDocument["User"]; - data = (unsigned char *)http_simple_get((char *)urlStream.str().c_str(), &dataStatus, &dataLength); - if(data && dataStatus == 200) - { - std::vector responseData(data, data+dataLength); - return format::PTIToVideoBuffer(responseData); - } - else if(data) - { - free(data); - } - return NULL; + json::Number userIDTemp = tempUser["ID"]; + json::String usernameTemp = tempUser["Username"]; + json::String bioTemp = tempUser["Biography"]; + //json::Number ageTemp = tempUser["Age"]; + + return new UserInfo( + userIDTemp.Value(), + 0,//ageTemp.Value(), + usernameTemp.Value(), + bioTemp.Value()); + } + catch (json::Exception &e) + { + return 0; + } + } + virtual void Cleanup(void * objectPtr) + { + delete (UserInfo*)objectPtr; + } + virtual ~UserInfoParser() { } + }; + return new APIRequest("http://" SERVER "/User.json?Name=" + username, new UserInfoParser()); } LoginStatus Client::Login(std::string username, std::string password, User & user) diff --git a/src/client/Client.h b/src/client/Client.h index c824d2821..f00083d8a 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -12,6 +12,8 @@ #include "cajun/elements.h" +#include "requestbroker/RequestBroker.h" + class Thumbnail; class SaveInfo; class SaveFile; @@ -126,7 +128,8 @@ public: RequestStatus AddComment(int saveID, std::string comment); - VideoBuffer * GetAvatar(std::string username); + //Retrieves a "UserInfo" object + RequestBroker::Request * GetUserInfoAsync(std::string username); unsigned char * GetSaveData(int saveID, int saveDate, int & dataLength); std::vector GetSaveData(int saveID, int saveDate); diff --git a/src/client/UserInfo.h b/src/client/UserInfo.h new file mode 100644 index 000000000..edd6659cf --- /dev/null +++ b/src/client/UserInfo.h @@ -0,0 +1,22 @@ +#ifndef USERINFO_H_ +#define USERINFO_H_ + +#include + +class UserInfo +{ +public: + int ID; + int Age; + std::string Username; + std::string Biography; + UserInfo(int id, int age, std::string username, std::string biography): + ID(id), + Age(age), + Username(username), + Biography(biography) + { } +}; + + +#endif /* USER_H_ */ diff --git a/src/client/requestbroker/APIRequest.cpp b/src/client/requestbroker/APIRequest.cpp new file mode 100644 index 000000000..71d683f6d --- /dev/null +++ b/src/client/requestbroker/APIRequest.cpp @@ -0,0 +1,77 @@ +#include +#include +#include +#include "APIRequest.h" +#include "client/HTTP.h" +#include "APIResultParser.h" + +APIRequest::APIRequest(std::string url, APIResultParser * parser, ListenerHandle listener): + RequestBroker::Request(API, listener) +{ + HTTPContext = NULL; + Parser = parser; + URL = url; +} + +RequestBroker::ProcessResponse APIRequest::Process(RequestBroker & rb) +{ + if(HTTPContext) + { + if(http_async_req_status(HTTPContext)) + { + char * data; + int status, data_size; + data = http_async_req_stop(HTTPContext, &status, &data_size); + + if (status == 200 && data) + { + void * resultObject = Parser->ProcessResponse((unsigned char *)data, data_size); + free(data); + + if(resultObject) + { + this->ResultObject = resultObject; + rb.requestComplete(this); + return RequestBroker::Finished; + } + else + { + std::cout << typeid(*this).name() << " Request for " << URL << " could not be parsed" << status << std::endl; + return RequestBroker::Failed; + } + } + else + { +//#ifdef DEBUG + std::cout << typeid(*this).name() << " Request for " << URL << " failed with status " << status << std::endl; +//#endif + if(data) + free(data); + + return RequestBroker::Failed; + } + } + } + else + { + std::cout << typeid(*this).name() << " New Request for " << URL << std::endl; + HTTPContext = http_async_req_start(NULL, (char *)URL.c_str(), NULL, 0, 0); + //RequestTime = time(NULL); + } + return RequestBroker::OK; +} + +APIRequest::~APIRequest() +{ + delete Parser; +} + +void APIRequest::Cleanup() +{ + Request::Cleanup(); + if(ResultObject) + { + Parser->Cleanup(ResultObject); + ResultObject = NULL; + } +} \ No newline at end of file diff --git a/src/client/requestbroker/APIRequest.h b/src/client/requestbroker/APIRequest.h new file mode 100644 index 000000000..2d41eb6e0 --- /dev/null +++ b/src/client/requestbroker/APIRequest.h @@ -0,0 +1,15 @@ +#include "RequestBroker.h" + +class APIResultParser; +class APIRequest: public RequestBroker::Request +{ +public: + APIResultParser * Parser; + std::string URL; + void * HTTPContext; + APIRequest(std::string url, APIResultParser * parser, ListenerHandle listener = ListenerHandle(0, 0)); + virtual RequestBroker::ProcessResponse Process(RequestBroker & rb); + virtual ~APIRequest(); + virtual void Cleanup(); +}; + diff --git a/src/client/requestbroker/APIResultParser.h b/src/client/requestbroker/APIResultParser.h new file mode 100644 index 000000000..40c75125c --- /dev/null +++ b/src/client/requestbroker/APIResultParser.h @@ -0,0 +1,16 @@ +#ifndef APIRESULTPARSER_H +#define APIRESULTPARSER_H + +class APIResultParser +{ +public: + //Process the raw API response into a result object to be returned to the requester + virtual void * ProcessResponse(unsigned char * data, int dataLength) { return 0; } + + //A method to clean up the result of ProcessResponse in the event of a callback failure in APIRequest/RequestBroker + virtual void Cleanup(void * objectPtr) { } + + virtual ~APIResultParser() { } +}; + +#endif \ No newline at end of file diff --git a/src/client/requestbroker/RequestBroker.cpp b/src/client/requestbroker/RequestBroker.cpp index 68427dcff..cfa1294de 100644 --- a/src/client/requestbroker/RequestBroker.cpp +++ b/src/client/requestbroker/RequestBroker.cpp @@ -114,6 +114,18 @@ void RequestBroker::RetrieveAvatar(std::string username, int width, int height, RetrieveImage(urlStream.str(), width, height, tListener); } +void RequestBroker::Start(Request * request, RequestListener * tListener) +{ + ListenerHandle handle = AttachRequestListener(tListener); + + request->Listener = handle; + pthread_mutex_lock(&requestQueueMutex); + requestQueue.push_back(request); + pthread_mutex_unlock(&requestQueueMutex); + + assureRunning(); +} + void RequestBroker::RetrieveImage(std::string imageUrl, int width, int height, RequestListener * tListener) { ListenerHandle handle = AttachRequestListener(tListener); diff --git a/src/client/requestbroker/RequestBroker.h b/src/client/requestbroker/RequestBroker.h index 003ac3779..4c31e89bb 100644 --- a/src/client/requestbroker/RequestBroker.h +++ b/src/client/requestbroker/RequestBroker.h @@ -16,6 +16,7 @@ typedef std::pair ListenerHandle; class RequestBroker: public Singleton { friend class ImageRequest; + friend class APIRequest; friend class ThumbRenderRequest; public: class Request; @@ -55,6 +56,7 @@ public: void RetrieveThumbnail(int saveID, int saveDate, int width, int height, RequestListener * tListener); void RetrieveThumbnail(int saveID, int width, int height, RequestListener * tListener); void RetrieveAvatar(std::string username, int width, int height, RequestListener * tListener); + void Start(Request * request, RequestListener * tLIstener); bool CheckRequestListener(ListenerHandle handle); ListenerHandle AttachRequestListener(RequestListener * tListener); @@ -63,7 +65,7 @@ public: class Request { public: - enum RequestType { ThumbnailRender, Image }; + enum RequestType { ThumbnailRender, Image, API }; RequestType Type; void * ResultObject; ListenerHandle Listener; diff --git a/src/game/GameController.cpp b/src/game/GameController.cpp index 017aa5808..1493b3953 100644 --- a/src/game/GameController.cpp +++ b/src/game/GameController.cpp @@ -17,6 +17,7 @@ #include "GameModelException.h" #include "simulation/Air.h" #include "elementsearch/ElementSearchActivity.h" +#include "profile/ProfileActivity.h" #include "colourpicker/ColourPickerActivity.h" #include "update/UpdateActivity.h" #include "Notification.h" @@ -1067,8 +1068,15 @@ void GameController::OpenLocalBrowse() void GameController::OpenLogin() { - loginWindow = new LoginController(); - ui::Engine::Ref().ShowWindow(loginWindow->GetView()); + if(Client::Ref().GetAuthUser().ID) + { + new ProfileActivity(Client::Ref().GetAuthUser().Username); + } + else + { + loginWindow = new LoginController(); + ui::Engine::Ref().ShowWindow(loginWindow->GetView()); + } } void GameController::OpenElementSearch() diff --git a/src/options/OptionsController.cpp b/src/options/OptionsController.cpp index b789c1fee..17c42f4fd 100644 --- a/src/options/OptionsController.cpp +++ b/src/options/OptionsController.cpp @@ -54,6 +54,11 @@ void OptionsController::SetFullscreen(bool fullscreen) model->SetFullscreen(fullscreen); } +void OptionsController::SetShowAvatars(bool showAvatars) +{ + model->SetShowAvatars(showAvatars); +} + void OptionsController::SetScale(bool scale) { if(scale) diff --git a/src/options/OptionsController.h b/src/options/OptionsController.h index f76459c42..481f9d240 100644 --- a/src/options/OptionsController.h +++ b/src/options/OptionsController.h @@ -27,6 +27,7 @@ public: void SetFullscreen(bool fullscreen); void SetScale(bool scale); void SetFastQuit(bool fastquit); + void SetShowAvatars(bool showAvatars); void Exit(); OptionsView * GetView(); virtual ~OptionsController(); diff --git a/src/options/OptionsModel.cpp b/src/options/OptionsModel.cpp index fbfe2a0dd..8ca2a3074 100644 --- a/src/options/OptionsModel.cpp +++ b/src/options/OptionsModel.cpp @@ -124,6 +124,17 @@ void OptionsModel::SetFastQuit(bool fastquit) notifySettingsChanged(); } +bool OptionsModel::GetShowAvatars() +{ + return Client::Ref().GetPrefBool("ShowAvatars", true); +} + +void OptionsModel::SetShowAvatars(bool state) +{ + Client::Ref().SetPref("ShowAvatars", state); + notifySettingsChanged(); +} + void OptionsModel::notifySettingsChanged() { for(int i = 0; i < observers.size(); i++) diff --git a/src/options/OptionsModel.h b/src/options/OptionsModel.h index b0867c187..1fdf372bf 100644 --- a/src/options/OptionsModel.h +++ b/src/options/OptionsModel.h @@ -23,6 +23,8 @@ public: void SetNewtonianGravity(bool state); bool GetWaterEqualisation(); void SetWaterEqualisation(bool state); + bool GetShowAvatars(); + void SetShowAvatars(bool state); int GetAirMode(); void SetAirMode(int airMode); int GetEdgeMode(); diff --git a/src/options/OptionsView.cpp b/src/options/OptionsView.cpp index 5bbd60856..70aeba576 100644 --- a/src/options/OptionsView.cpp +++ b/src/options/OptionsView.cpp @@ -5,7 +5,7 @@ #include "interface/DropDown.h" OptionsView::OptionsView(): - ui::Window(ui::Point(-1, -1), ui::Point(300, 290)){ + ui::Window(ui::Point(-1, -1), ui::Point(300, 310)){ ui::Label * tempLabel = new ui::Label(ui::Point(4, 5), ui::Point(Size.X-8, 14), "Simulation Options"); tempLabel->SetTextColour(style::Colour::InformationTitle); @@ -176,6 +176,21 @@ OptionsView::OptionsView(): AddComponent(tempLabel); AddComponent(fastquit); + class ShowAvatarsAction: public ui::CheckboxAction + { + OptionsView * v; + public: + ShowAvatarsAction(OptionsView * v_){ v = v_; } + virtual void ActionCallback(ui::Checkbox * sender){ v->c->SetShowAvatars(sender->GetChecked()); } + }; + + showAvatars = new ui::Checkbox(ui::Point(8, 270), ui::Point(Size.X-6, 16), "Show Avatars", ""); + showAvatars->SetActionCallback(new ShowAvatarsAction(this)); + tempLabel = new ui::Label(ui::Point(showAvatars->Position.X+Graphics::textwidth(showAvatars->GetText().c_str())+20, showAvatars->Position.Y), ui::Point(Size.X-28, 16), "\bg- Disable if you have a slow connection"); + tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle; + AddComponent(tempLabel); + AddComponent(showAvatars); + class CloseAction: public ui::ButtonAction { public: @@ -206,6 +221,7 @@ void OptionsView::NotifySettingsChanged(OptionsModel * sender) scale->SetChecked(sender->GetScale()); fullscreen->SetChecked(sender->GetFullscreen()); fastquit->SetChecked(sender->GetFastQuit()); + showAvatars->SetChecked(sender->GetShowAvatars()); } void OptionsView::AttachController(OptionsController * c_) diff --git a/src/options/OptionsView.h b/src/options/OptionsView.h index 8d41ba5db..4ee254faa 100644 --- a/src/options/OptionsView.h +++ b/src/options/OptionsView.h @@ -21,6 +21,7 @@ class OptionsView: public ui::Window { ui::Checkbox * scale; ui::Checkbox * fullscreen; ui::Checkbox * fastquit; + ui::Checkbox * showAvatars; public: OptionsView(); void NotifySettingsChanged(OptionsModel * sender); diff --git a/src/preview/PreviewView.cpp b/src/preview/PreviewView.cpp index d9319f8da..e04295a8f 100644 --- a/src/preview/PreviewView.cpp +++ b/src/preview/PreviewView.cpp @@ -67,6 +67,8 @@ PreviewView::PreviewView(): } }; + showAvatars = Client::Ref().GetPrefBool("ShowAvatars", true); + favButton = new ui::Button(ui::Point(50, Size.Y-19), ui::Point(51, 19), "Fav"); favButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; favButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle; favButton->SetIcon(IconFavourite); diff --git a/src/profile/ProfileActivity.cpp b/src/profile/ProfileActivity.cpp new file mode 100644 index 000000000..1b3a1f87e --- /dev/null +++ b/src/profile/ProfileActivity.cpp @@ -0,0 +1,68 @@ +#include +#include "ProfileActivity.h" +#include "interface/Button.h" +#include "interface/Textbox.h" +#include "interface/Label.h" +#include "interface/Keys.h" +#include "Style.h" +#include "client/Client.h" +#include "client/requestbroker/RequestListener.h" + +ProfileActivity::ProfileActivity(std::string username) : + WindowActivity(ui::Point(-1, -1), ui::Point(236, 302)) +{ + bool editable = Client::Ref().GetAuthUser().ID && Client::Ref().GetAuthUser().Username == username; + + + class CloseAction: public ui::ButtonAction + { + ProfileActivity * a; + public: + CloseAction(ProfileActivity * a) : a(a) { } + void ActionCallback(ui::Button * sender_) + { + a->Exit(); + } + }; + + class SaveAction: public ui::ButtonAction + { + ProfileActivity * a; + public: + SaveAction(ProfileActivity * a) : a(a) { } + void ActionCallback(ui::Button * sender_) + { + } + }; + + ui::Button * closeButton = new ui::Button(ui::Point(0, Size.Y-15), ui::Point((Size.X/2)+1, 15), "Close"); + closeButton->SetActionCallback(new CloseAction(this)); + + if(editable) + { + ui::Button * saveButton = new ui::Button(ui::Point(Size.X/2, Size.Y-15), ui::Point(Size.X/2, 15), "Save"); + saveButton->SetActionCallback(new SaveAction(this)); + AddComponent(saveButton); + } + + AddComponent(closeButton); + + RequestBroker::Ref().Start(Client::Ref().GetUserInfoAsync(username), this); +} + +void ProfileActivity::OnResponseReady(void * userDataPtr) +{ + exit(0); +} + +void ProfileActivity::OnDraw() +{ + Graphics * g = ui::Engine::Ref().g; + g->clearrect(Position.X-2, Position.Y-2, Size.X+3, Size.Y+3); + g->drawrect(Position.X, Position.Y, Size.X, Size.Y, 255, 255, 255, 255); +} + +ProfileActivity::~ProfileActivity() { + RequestBroker::Ref().DetachRequestListener(this); +} + diff --git a/src/profile/ProfileActivity.h b/src/profile/ProfileActivity.h new file mode 100644 index 000000000..a4648e918 --- /dev/null +++ b/src/profile/ProfileActivity.h @@ -0,0 +1,17 @@ +#ifndef PROFILEACTIVITY_H_ +#define PROFILEACTIVITY_H_ + +#include +#include "Activity.h" +#include "client/requestbroker/RequestListener.h" +#include "interface/Window.h" + +class ProfileActivity: public WindowActivity, public RequestListener { +public: + ProfileActivity(std::string username); + virtual ~ProfileActivity(); + virtual void OnResponseReady(void * userDataPtr); + virtual void OnDraw(); +}; + +#endif /* PROFILEACTIVITY_H_ */