APIRequest, Aync methods for client, Profile edit/viewer (WIP)

This commit is contained in:
Simon Robertshaw 2013-03-16 17:45:18 +00:00
parent d383d6d7e5
commit f05044ab68
18 changed files with 320 additions and 23 deletions

View File

@ -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<unsigned char> 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<char> 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)

View File

@ -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<unsigned char> GetSaveData(int saveID, int saveDate);

22
src/client/UserInfo.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef USERINFO_H_
#define USERINFO_H_
#include <string>
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_ */

View File

@ -0,0 +1,77 @@
#include <iostream>
#include <typeinfo>
#include <cstdlib>
#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;
}
}

View File

@ -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();
};

View File

@ -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

View File

@ -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);

View File

@ -16,6 +16,7 @@ typedef std::pair<int, RequestListener*> ListenerHandle;
class RequestBroker: public Singleton<RequestBroker>
{
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;

View File

@ -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()

View File

@ -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)

View File

@ -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();

View File

@ -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++)

View File

@ -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();

View File

@ -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_)

View File

@ -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);

View File

@ -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);

View File

@ -0,0 +1,68 @@
#include <algorithm>
#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);
}

View File

@ -0,0 +1,17 @@
#ifndef PROFILEACTIVITY_H_
#define PROFILEACTIVITY_H_
#include <string>
#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_ */