Stage 1 of update process completed

This commit is contained in:
Simon Robertshaw 2012-06-21 15:49:32 +01:00
parent 8fc3325b1c
commit 550f6e28e0
14 changed files with 456 additions and 59 deletions

View File

@ -11,8 +11,8 @@
namespace style {
ui::Colour Colour::InformationTitle = ui::Colour(140, 140, 255);
ui::Colour Colour::WarningTitle = ui::Colour(255, 255, 50);
ui::Colour Colour::ErrorTitle = ui::Colour(255, 20, 20);
ui::Colour Colour::WarningTitle = ui::Colour(255, 216, 32);
ui::Colour Colour::ErrorTitle = ui::Colour(255, 64, 32);
ui::Colour Colour::ConfirmButton = ui::Colour(255, 255, 50);

187
src/Update.cpp Normal file
View File

@ -0,0 +1,187 @@
#include <stdio.h>
#include <stdlib.h>
#ifndef WIN32
#include <sys/param.h>
#endif
#if !defined(MACOSX) && !defined(BSD)
#include <malloc.h>
#endif
#include <string.h>
#ifdef WIN32
#include <windows.h>
#else
#include <unistd.h>
#include <sys/stat.h>
#endif
#ifdef MACOSX
#include <mach-o/dyld.h>
#include <errno.h>
#endif
#include <Update.h>
#include <Misc.h>
/*char *exe_name(void)
{
#if defined WIN32
char *name= (char *)malloc(64);
DWORD max=64, res;
while ((res = GetModuleFileName(NULL, name, max)) >= max)
{
#elif defined MACOSX
char *fn=malloc(64),*name=malloc(PATH_MAX);
uint32_t max=64, res;
if (_NSGetExecutablePath(fn, &max) != 0)
{
fn = realloc(fn, max);
_NSGetExecutablePath(fn, &max);
}
if (realpath(fn, name) == NULL)
{
free(fn);
free(name);
return NULL;
}
res = 1;
#else
char fn[64], *name=malloc(64);
size_t max=64, res;
sprintf(fn, "/proc/self/exe");
memset(name, 0, max);
while ((res = readlink(fn, name, max)) >= max-1)
{
#endif
#ifndef MACOSX
max *= 2;
name = (char*)realloc(name, max);
memset(name, 0, max);
}
#endif
if (res <= 0)
{
free(name);
return NULL;
}
return name;
}*/
int update_start(char *data, int len)
{
char *self=exe_name(), *temp;
#ifdef WIN32
char *p;
#endif
FILE *f;
int res = 1;
if (!self)
return 1;
#ifdef WIN32
temp = (char*)malloc(strlen(self)+12);
strcpy(temp, self);
p = temp + strlen(temp) - 4;
if (_stricmp(p, ".exe"))
p += 4;
strcpy(p, "_update.exe");
if (!MoveFile(self, temp))
goto fail;
f = fopen(self, "wb");
if (!f)
goto fail;
if (fwrite(data, 1, len, f) != len)
{
fclose(f);
DeleteFile(self);
goto fail;
}
fclose(f);
if ((int)ShellExecute(NULL, "open", self, NULL, NULL, SW_SHOWNORMAL) <= 32)
{
DeleteFile(self);
goto fail;
}
return 0;
#else
temp = malloc(strlen(self)+8);
strcpy(temp, self);
strcat(temp, "-update");
f = fopen(temp, "w");
if (!f)
goto fail;
if (fwrite(data, 1, len, f) != len)
{
fclose(f);
unlink(temp);
goto fail;
}
fclose(f);
if (chmod(temp, 0755))
{
unlink(temp);
goto fail;
}
if (rename(temp, self))
{
unlink(temp);
goto fail;
}
execl(self, "powder-update", NULL);
#endif
fail:
free(temp);
free(self);
return res;
}
int update_finish(void)
{
#ifdef WIN32
char *temp, *self=exe_name(), *p;
int timeout = 60, err;
temp = (char*)malloc(strlen(self)+12);
strcpy(temp, self);
p = temp + strlen(temp) - 4;
if (_stricmp(p, ".exe"))
p += 4;
strcpy(p, "_update.exe");
while (!DeleteFile(temp))
{
err = GetLastError();
if (err == ERROR_FILE_NOT_FOUND)
{
// just as well, then
free(temp);
return 0;
}
Sleep(500);
timeout--;
if (timeout <= 0)
{
free(temp);
return 1;
}
}
free(temp);
#endif
return 0;
}
void update_cleanup(void)
{
#ifdef WIN32
update_finish();
#endif
}

16
src/Update.h Normal file
View File

@ -0,0 +1,16 @@
/*
* Update.h
*
* Created on: Jun 21, 2012
* Author: Simon
*/
#ifndef UPDATE_H_
#define UPDATE_H_
//char *exe_name(void);
int update_start(char *data, int len);
int update_finish(void);
void update_cleanup(void);
#endif /* UPDATE_H_ */

View File

@ -6,6 +6,7 @@
*/
#include "ConfirmPrompt.h"
#include "Style.h"
#include "interface/Textblock.h"
#include "interface/Button.h"
@ -15,7 +16,7 @@ ConfirmPrompt::ConfirmPrompt(std::string title, std::string message, ConfirmDial
{
int width, height;
ui::Label * titleLabel = new ui::Label(ui::Point(4, 5), ui::Point(Size.X-8, 15), title);
titleLabel->SetTextColour(ui::Colour(220, 220, 50));
titleLabel->SetTextColour(style::Colour::WarningTitle);
titleLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
titleLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(titleLabel);
@ -55,7 +56,7 @@ ConfirmPrompt::ConfirmPrompt(std::string title, std::string message, ConfirmDial
ui::Button * okayButton = new ui::Button(ui::Point(Size.X-76, Size.Y-16), ui::Point(76, 16), "Continue");
okayButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
okayButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
okayButton->Appearance.TextInactive = ui::Colour(220, 220, 50);
okayButton->Appearance.TextInactive = style::Colour::WarningTitle;
okayButton->SetActionCallback(new CloseAction(this, ResultOkay));
AddComponent(okayButton);

View File

@ -5,6 +5,7 @@
* Author: Simon
*/
#include "Style.h"
#include "ErrorMessage.h"
#include "interface/Button.h"
#include "interface/Label.h"
@ -13,7 +14,7 @@ ErrorMessage::ErrorMessage(std::string title, std::string message):
ui::Window(ui::Point(-1, -1), ui::Point(200, 75))
{
ui::Label * titleLabel = new ui::Label(ui::Point(4, 5), ui::Point(Size.X-8, 16), title);
titleLabel->SetTextColour(ui::Colour(200, 100, 50));
titleLabel->SetTextColour(style::Colour::ErrorTitle);
titleLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
titleLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(titleLabel);

View File

@ -13,6 +13,7 @@
#include "dialogues/ConfirmPrompt.h"
#include "GameModelException.h"
#include "simulation/Air.h"
#include "update/UpdateActivity.h"
#include "Notification.h"
using namespace std;
@ -675,5 +676,6 @@ void GameController::RemoveNotification(Notification * notification)
void GameController::RunUpdater()
{
Exit();
new UpdateActivity();
}

View File

@ -20,6 +20,7 @@ SaveRenderer::SaveRenderer(){
Thumbnail * SaveRenderer::Render(GameSave * save)
{
int width, height;
Thumbnail * tempThumb;
#ifdef OGLR
width = save->blockWidth*CELL;
height = save->blockHeight*CELL;
@ -27,7 +28,7 @@ Thumbnail * SaveRenderer::Render(GameSave * save)
VideoBuffer buffer(width, height);
buffer.BlendCharacter((width/2)-3, (height/2)-5, 'x', 255, 255, 255, 255);
Thumbnail * tempThumb = new Thumbnail(0, 0, buffer.Buffer, ui::Point(width, height));
tempThumb = new Thumbnail(0, 0, buffer.Buffer, ui::Point(width, height));
return tempThumb;
#else

View File

@ -10,7 +10,7 @@
#include "Task.h"
#include "TaskListener.h"
void Task::SetTaskListener(TaskListener * listener)
void Task::AddTaskListener(TaskListener * listener)
{
this->listener = listener;
}
@ -37,6 +37,11 @@ std::string Task::GetStatus()
return status;
}
std::string Task::GetError()
{
return error;
}
bool Task::GetDone()
{
return done;
@ -44,38 +49,50 @@ bool Task::GetDone()
void Task::Poll()
{
int newProgress;
bool newDone = false;
std::string newStatus;
pthread_mutex_lock(&taskMutex);
newProgress = thProgress;
newDone = thDone;
newStatus = std::string(thStatus);
pthread_mutex_unlock(&taskMutex);
if(newProgress!=progress) {
progress = newProgress;
if(listener)
listener->NotifyProgress(this);
}
if(newStatus!=status) {
status = std::string(newStatus);
if(listener)
listener->NotifyStatus(this);
}
if(done)
if(!done)
{
pthread_join(doWorkThread, NULL);
pthread_mutex_destroy(&taskMutex);
after();
}
int newProgress;
bool newDone = false;
std::string newStatus;
std::string newError;
pthread_mutex_lock(&taskMutex);
newProgress = thProgress;
newDone = thDone;
newStatus = std::string(thStatus);
newError = std::string(thError);
pthread_mutex_unlock(&taskMutex);
if(newDone!=done)
{
done = newDone;
if(listener)
listener->NotifyDone(this);
if(newProgress!=progress) {
progress = newProgress;
if(listener)
listener->NotifyProgress(this);
}
if(newError!=error) {
error = std::string(newError);
if(listener)
listener->NotifyError(this);
}
if(newStatus!=status) {
status = std::string(newStatus);
if(listener)
listener->NotifyStatus(this);
}
if(done)
{
pthread_join(doWorkThread, NULL);
pthread_mutex_destroy(&taskMutex);
after();
}
if(newDone!=done)
{
done = newDone;
if(listener)
listener->NotifyDone(this);
}
}
}
@ -131,3 +148,10 @@ void Task::notifyDone()
thDone = true;
pthread_mutex_unlock(&taskMutex);
}
void Task::notifyError(std::string error)
{
pthread_mutex_lock(&taskMutex);
thError = std::string(error);
pthread_mutex_unlock(&taskMutex);
}

View File

@ -15,10 +15,11 @@
class TaskListener;
class Task {
public:
void SetTaskListener(TaskListener * listener);
void AddTaskListener(TaskListener * listener);
void Start();
int GetProgress();
bool GetDone();
std::string GetError();
std::string GetStatus();
void Poll();
Task() {}
@ -27,10 +28,12 @@ protected:
int progress;
bool done;
std::string status;
std::string error;
int thProgress;
bool thDone;
std::string thStatus;
std::string thError;
TaskListener * listener;
pthread_t doWorkThread;
@ -43,9 +46,10 @@ protected:
virtual void doWork();
static void * doWork_helper(void * ref);
void notifyProgress(int progress);
void notifyStatus(std::string status);
void notifyDone();
virtual void notifyProgress(int progress);
virtual void notifyError(std::string error);
virtual void notifyStatus(std::string status);
virtual void notifyDone();
};
#endif /* TASK_H_ */

View File

@ -12,6 +12,7 @@ class Task;
class TaskListener {
public:
virtual void NotifyDone(Task * task) {}
virtual void NotifyError(Task * task) {}
virtual void NotifyProgress(Task * task) {}
virtual void NotifyStatus(Task * task) {}
virtual ~TaskListener() {}

View File

@ -5,28 +5,37 @@
* Author: Simon
*/
#include <sstream>
#include "interface/Label.h"
#include "TaskWindow.h"
#include "dialogues/ErrorMessage.h"
#include "Style.h"
#include "Task.h"
TaskWindow::TaskWindow(std::string title_, Task * task_, bool closeOnDone):
task(task_),
title(title_),
ui::Window(ui::Point(-1, -1), ui::Point(300, 200)),
ui::Window(ui::Point(-1, -1), ui::Point(240, 60)),
progress(0),
done(false),
closeOnDone(closeOnDone)
closeOnDone(closeOnDone),
progressStatus("0%")
{
ui::Label * tempLabel = new ui::Label(ui::Point(3, 3), ui::Point(Size.X-6, 16), title);
ui::Label * tempLabel = new ui::Label(ui::Point(4, 5), ui::Point(Size.X-8, 15), title);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
tempLabel->SetTextColour(style::Colour::WarningTitle);
AddComponent(tempLabel);
statusLabel = new ui::Label(ui::Point(3, 19), ui::Point(Size.X-6, 16), "");
statusLabel = new ui::Label(ui::Point(4, 23), ui::Point(Size.X-8, 15), "");
statusLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
statusLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(statusLabel);
ui::Engine::Ref().ShowWindow(this);
task->SetTaskListener(this);
task->AddTaskListener(this);
task->Start();
}
@ -35,6 +44,11 @@ void TaskWindow::NotifyStatus(Task * task)
statusLabel->SetText(task->GetStatus());
}
void TaskWindow::NotifyError(Task * task)
{
new ErrorMessage("Error", task->GetError());
}
void TaskWindow::NotifyDone(Task * task)
{
if(closeOnDone)
@ -53,6 +67,16 @@ void TaskWindow::Exit()
void TaskWindow::NotifyProgress(Task * task)
{
progress = task->GetProgress();
std::stringstream pStream;
if(progress>-1)
{
pStream << progress << "%";
}
else
{
pStream << "Please wait...";
}
progressStatus = pStream.str();
}
void TaskWindow::OnTick(float dt)
@ -69,26 +93,32 @@ void TaskWindow::OnDraw()
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);
g->drawrect(Position.X + 20, Position.Y + 36, Size.X-40, 24, 255, 255, 255, 255);
g->draw_line(Position.X, Position.Y + Size.Y-17, Position.X + Size.X - 1, Position.Y + Size.Y-17, 255, 255, 255, 255);
ui::Colour progressBarColour = style::Colour::WarningTitle;
if(progress!=-1)
{
float size = float(Size.X-40)*(float(progress)/100.0f); // TIL...
g->fillrect(Position.X + 20, Position.Y + 36, size, 24, 255, 255, 255, 255);
float size = float(Size.X-4)*(float(progress)/100.0f); // TIL...
g->fillrect(Position.X + 2, Position.Y + Size.Y-15, size, 13, progressBarColour.Red, progressBarColour.Green, progressBarColour.Blue, 255);
} else {
int size = 40, rsize = 0;
float position = float(Size.X-40)*(intermediatePos/100.0f);
if(position + size > Size.X-40)
float position = float(Size.X-4)*(intermediatePos/100.0f);
if(position + size - 1 > Size.X-4)
{
size = (Size.X-40)-position;
size = (Size.X-4)-position+1;
rsize = 40-size;
}
g->fillrect(Position.X + 20 + position, Position.Y + 36, size, 24, 255, 255, 255, 255);
g->fillrect(Position.X + 2 + position, Position.Y + Size.Y-15, size, 13, progressBarColour.Red, progressBarColour.Green, progressBarColour.Blue, 255);
if(rsize)
{
g->fillrect(Position.X + 20, Position.Y + 36, rsize, 24, 255, 255, 255, 255);
g->fillrect(Position.X + 2, Position.Y + Size.Y-15, rsize, 13, progressBarColour.Red, progressBarColour.Green, progressBarColour.Blue, 255);
}
}
if(progress<50)
g->drawtext(Position.X + ((Size.X-Graphics::textwidth(progressStatus.c_str()))/2), Position.Y + Size.Y-13, progressStatus, 255, 255, 255, 255);
else
g->drawtext(Position.X + ((Size.X-Graphics::textwidth(progressStatus.c_str()))/2), Position.Y + Size.Y-13, progressStatus, 0, 0, 0, 255);
}
TaskWindow::~TaskWindow() {

View File

@ -22,11 +22,13 @@ class TaskWindow: public ui::Window, public TaskListener {
bool done;
bool closeOnDone;
ui::Label * statusLabel;
std::string progressStatus;
public:
TaskWindow(std::string title_, Task * task_, bool closeOnDone = true);
virtual void NotifyStatus(Task * task);
virtual void NotifyDone(Task * task);
virtual void NotifyProgress(Task * task);
virtual void NotifyError(Task * task);
virtual void OnTick(float dt);
virtual void OnDraw();
virtual void Exit();

View File

@ -5,21 +5,148 @@
* Author: Simon
*/
#include <bzlib.h>
#include <sstream>
#include "interface/Engine.h"
#include "UpdateActivity.h"
#include "tasks/Task.h"
#include "client/HTTP.h"
#include "Update.h"
class UpdateDownloadTask : public Task
{
UpdateDownloadTask() {};
/*virtual void doWork()
public:
UpdateDownloadTask(std::string updateName, UpdateActivity * a) : updateName(updateName), a(a) {};
private:
UpdateActivity * a;
std::string updateName;
virtual void notifyDone()
{
while(1)
}*/
a->NotifyDone(this);
}
virtual void doWork()
{
std::stringstream errorStream;
void * request = http_async_req_start(NULL, (char*)updateName.c_str(), NULL, 0, 0);
notifyStatus("Downloading update");
notifyProgress(-1);
while(!http_async_req_status(request))
{
int total, done;
http_async_get_length(request, &total, &done);
notifyProgress((float(done)/float(total))*100.0f);
}
char * data;
int dataLength, status;
data = http_async_req_stop(request, &status, &dataLength);
if (status!=200)
{
if (data)
free(data);
errorStream << "Server responded with Status " << status;
notifyError("Could not download update");
return;
}
if (!data)
{
errorStream << "Server responded with nothing";
notifyError("Server did not return any data");
return;
}
notifyStatus("Unpacking update");
notifyProgress(-1);
int uncompressedLength;
if(dataLength<16)
{
errorStream << "Unsufficient data, got " << dataLength << " bytes";
goto corrupt;
}
if (data[0]!=0x42 || data[1]!=0x75 || data[2]!=0x54 || data[3]!=0x54)
{
errorStream << "Invalid update format";
goto corrupt;
}
uncompressedLength = (unsigned char)data[4];
uncompressedLength |= ((unsigned char)data[5])<<8;
uncompressedLength |= ((unsigned char)data[6])<<16;
uncompressedLength |= ((unsigned char)data[7])<<24;
char * res;
res = (char *)malloc(uncompressedLength);
if (!res)
{
errorStream << "Unable to allocate " << uncompressedLength << " bytes of memory for decompression";
goto corrupt;
}
int dstate;
dstate = BZ2_bzBuffToBuffDecompress((char *)res, (unsigned *)&uncompressedLength, (char *)(data+8), dataLength-8, 0, 0);
if (dstate)
{
errorStream << "Unable to decompress update: " << dstate;
free(res);
goto corrupt;
}
free(data);
notifyStatus("Applying update");
notifyProgress(-1);
if (update_start(res, uncompressedLength))
{
update_cleanup();
notifyError("Update failed - try downloading a new version.");
}
return;
corrupt:
notifyError("Downloaded update is corrupted\n" + errorStream.str());
free(data);
return;
}
};
UpdateActivity::UpdateActivity() {
// TODO Auto-generated constructor stub
char my_uri[] = "http://" SERVER "/Update.api?Action=Download&Architecture="
#if defined WIN32
"Windows32"
#elif defined LIN32
"Linux32"
#elif defined LIN64
"Linux64"
#elif defined MACOSX
"MacOSX"
#else
"Unknown"
#endif
"&InstructionSet="
#if defined X86_SSE3
"SSE3"
#elif defined X86_SSE2
"SSE2"
#elif defined X86_SSE
"SSE"
#else
"SSE"
#endif
;
updateDownloadTask = new UpdateDownloadTask(my_uri, this);
updateWindow = new TaskWindow("Downloading update...", updateDownloadTask, true);
}
void UpdateActivity::NotifyDone(Task * sender)
{
updateWindow->Exit();
ui::Engine::Ref().Exit();
delete this;
}
UpdateActivity::~UpdateActivity() {

View File

@ -17,6 +17,7 @@ class UpdateActivity {
public:
UpdateActivity();
virtual ~UpdateActivity();
virtual void NotifyDone(Task * sender);
};
#endif /* UPDATEACTIVITY_H_ */