Andrew A. de Laix 2010-12-07 10:38:06 -08:00
commit ac5a8ca607
5 changed files with 438 additions and 1 deletions

View File

@ -80,6 +80,7 @@
#include "llfeaturemanager.h"
#include "llurlmatch.h"
#include "lltextutil.h"
#include "lllogininstance.h"
#include "llweb.h"
#include "llsecondlifeurls.h"
@ -590,10 +591,14 @@ LLAppViewer::LLAppViewer() :
setupErrorHandling();
sInstance = this;
gLoggedInTime.stop();
LLLoginInstance::instance().setUpdaterService(mUpdater.get());
}
LLAppViewer::~LLAppViewer()
{
LLLoginInstance::instance().setUpdaterService(0);
destroyMainloopTimeout();
// If we got to this destructor somehow, the app didn't hang.

View File

@ -55,12 +55,382 @@
#include "llsecapi.h"
#include "llstartup.h"
#include "llmachineid.h"
#include "llupdaterservice.h"
#include "llevents.h"
#include "llnotificationsutil.h"
#include "llappviewer.h"
#include <boost/scoped_ptr.hpp>
namespace {
class MandatoryUpdateMachine {
public:
MandatoryUpdateMachine(LLLoginInstance & loginInstance, LLUpdaterService & updaterService);
void start(void);
private:
class State;
class CheckingForUpdate;
class Error;
class ReadyToInstall;
class StartingUpdaterService;
class WaitingForDownload;
LLLoginInstance & mLoginInstance;
boost::scoped_ptr<State> mState;
LLUpdaterService & mUpdaterService;
void setCurrentState(State * newState);
};
class MandatoryUpdateMachine::State {
public:
virtual ~State() {}
virtual void enter(void) {}
virtual void exit(void) {}
};
class MandatoryUpdateMachine::CheckingForUpdate:
public MandatoryUpdateMachine::State
{
public:
CheckingForUpdate(MandatoryUpdateMachine & machine);
virtual void enter(void);
virtual void exit(void);
private:
LLTempBoundListener mConnection;
MandatoryUpdateMachine & mMachine;
bool onEvent(LLSD const & event);
};
class MandatoryUpdateMachine::Error:
public MandatoryUpdateMachine::State
{
public:
Error(MandatoryUpdateMachine & machine);
virtual void enter(void);
virtual void exit(void);
void onButtonClicked(const LLSD &, const LLSD &);
private:
MandatoryUpdateMachine & mMachine;
};
class MandatoryUpdateMachine::ReadyToInstall:
public MandatoryUpdateMachine::State
{
public:
ReadyToInstall(MandatoryUpdateMachine & machine);
virtual void enter(void);
virtual void exit(void);
private:
MandatoryUpdateMachine & mMachine;
};
class MandatoryUpdateMachine::StartingUpdaterService:
public MandatoryUpdateMachine::State
{
public:
StartingUpdaterService(MandatoryUpdateMachine & machine);
virtual void enter(void);
virtual void exit(void);
void onButtonClicked(const LLSD & uiform, const LLSD & result);
private:
MandatoryUpdateMachine & mMachine;
};
class MandatoryUpdateMachine::WaitingForDownload:
public MandatoryUpdateMachine::State
{
public:
WaitingForDownload(MandatoryUpdateMachine & machine);
virtual void enter(void);
virtual void exit(void);
private:
LLTempBoundListener mConnection;
MandatoryUpdateMachine & mMachine;
bool onEvent(LLSD const & event);
};
}
static const char * const TOS_REPLY_PUMP = "lllogininstance_tos_callback";
static const char * const TOS_LISTENER_NAME = "lllogininstance_tos";
std::string construct_start_string();
// MandatoryUpdateMachine
//-----------------------------------------------------------------------------
MandatoryUpdateMachine::MandatoryUpdateMachine(LLLoginInstance & loginInstance, LLUpdaterService & updaterService):
mLoginInstance(loginInstance),
mUpdaterService(updaterService)
{
; // No op.
}
void MandatoryUpdateMachine::start(void)
{
llinfos << "starting manditory update machine" << llendl;
if(mUpdaterService.isChecking()) {
switch(mUpdaterService.getState()) {
case LLUpdaterService::UP_TO_DATE:
mUpdaterService.stopChecking();
mUpdaterService.startChecking();
// Fall through.
case LLUpdaterService::INITIAL:
case LLUpdaterService::CHECKING_FOR_UPDATE:
setCurrentState(new CheckingForUpdate(*this));
break;
case LLUpdaterService::DOWNLOADING:
setCurrentState(new WaitingForDownload(*this));
break;
case LLUpdaterService::TERMINAL:
if(LLUpdaterService::updateReadyToInstall()) {
setCurrentState(new ReadyToInstall(*this));
} else {
setCurrentState(new Error(*this));
}
break;
case LLUpdaterService::ERROR:
setCurrentState(new Error(*this));
break;
default:
llassert(!"unpossible case");
break;
}
} else {
setCurrentState(new StartingUpdaterService(*this));
}
}
void MandatoryUpdateMachine::setCurrentState(State * newStatePointer)
{
{
boost::scoped_ptr<State> newState(newStatePointer);
if(mState != 0) mState->exit();
mState.swap(newState);
// Old state will be deleted on exit from this block before the new state
// is entered.
}
if(mState != 0) mState->enter();
}
// MandatoryUpdateMachine::CheckingForUpdate
//-----------------------------------------------------------------------------
MandatoryUpdateMachine::CheckingForUpdate::CheckingForUpdate(MandatoryUpdateMachine & machine):
mMachine(machine)
{
; // No op.
}
void MandatoryUpdateMachine::CheckingForUpdate::enter(void)
{
llinfos << "entering checking for update" << llendl;
mConnection = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()).
listen("MandatoryUpdateMachine::CheckingForUpdate", boost::bind(&MandatoryUpdateMachine::CheckingForUpdate::onEvent, this, _1));
}
void MandatoryUpdateMachine::CheckingForUpdate::exit(void)
{
}
bool MandatoryUpdateMachine::CheckingForUpdate::onEvent(LLSD const & event)
{
if(event["type"].asInteger() == LLUpdaterService::STATE_CHANGE) {
switch(event["state"].asInteger()) {
case LLUpdaterService::DOWNLOADING:
mMachine.setCurrentState(new WaitingForDownload(mMachine));
break;
case LLUpdaterService::UP_TO_DATE:
case LLUpdaterService::TERMINAL:
case LLUpdaterService::ERROR:
mMachine.setCurrentState(new Error(mMachine));
break;
case LLUpdaterService::INSTALLING:
llassert(!"can't possibly be installing");
break;
default:
break;
}
} else {
; // Ignore.
}
return false;
}
// MandatoryUpdateMachine::Error
//-----------------------------------------------------------------------------
MandatoryUpdateMachine::Error::Error(MandatoryUpdateMachine & machine):
mMachine(machine)
{
; // No op.
}
void MandatoryUpdateMachine::Error::enter(void)
{
llinfos << "entering error" << llendl;
LLNotificationsUtil::add("FailedUpdateInstall", LLSD(), LLSD(), boost::bind(&MandatoryUpdateMachine::Error::onButtonClicked, this, _1, _2));
}
void MandatoryUpdateMachine::Error::exit(void)
{
LLAppViewer::instance()->forceQuit();
}
void MandatoryUpdateMachine::Error::onButtonClicked(const LLSD &, const LLSD &)
{
mMachine.setCurrentState(0);
}
// MandatoryUpdateMachine::ReadyToInstall
//-----------------------------------------------------------------------------
MandatoryUpdateMachine::ReadyToInstall::ReadyToInstall(MandatoryUpdateMachine & machine):
mMachine(machine)
{
; // No op.
}
void MandatoryUpdateMachine::ReadyToInstall::enter(void)
{
llinfos << "entering ready to install" << llendl;
// Open update ready dialog.
}
void MandatoryUpdateMachine::ReadyToInstall::exit(void)
{
// Restart viewer.
}
// MandatoryUpdateMachine::StartingUpdaterService
//-----------------------------------------------------------------------------
MandatoryUpdateMachine::StartingUpdaterService::StartingUpdaterService(MandatoryUpdateMachine & machine):
mMachine(machine)
{
; // No op.
}
void MandatoryUpdateMachine::StartingUpdaterService::enter(void)
{
llinfos << "entering start update service" << llendl;
LLNotificationsUtil::add("UpdaterServiceNotRunning", LLSD(), LLSD(), boost::bind(&MandatoryUpdateMachine::StartingUpdaterService::onButtonClicked, this, _1, _2));
}
void MandatoryUpdateMachine::StartingUpdaterService::exit(void)
{
; // No op.
}
void MandatoryUpdateMachine::StartingUpdaterService::onButtonClicked(const LLSD & uiform, const LLSD & result)
{
if(result["OK_okcancelbuttons"].asBoolean()) {
mMachine.mUpdaterService.startChecking(false);
mMachine.setCurrentState(new CheckingForUpdate(mMachine));
} else {
LLAppViewer::instance()->forceQuit();
}
}
// MandatoryUpdateMachine::WaitingForDownload
//-----------------------------------------------------------------------------
MandatoryUpdateMachine::WaitingForDownload::WaitingForDownload(MandatoryUpdateMachine & machine):
mMachine(machine)
{
; // No op.
}
void MandatoryUpdateMachine::WaitingForDownload::enter(void)
{
llinfos << "entering waiting for download" << llendl;
mConnection = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()).
listen("MandatoryUpdateMachine::CheckingForUpdate", boost::bind(&MandatoryUpdateMachine::WaitingForDownload::onEvent, this, _1));
}
void MandatoryUpdateMachine::WaitingForDownload::exit(void)
{
}
bool MandatoryUpdateMachine::WaitingForDownload::onEvent(LLSD const & event)
{
switch(event["type"].asInteger()) {
case LLUpdaterService::DOWNLOAD_COMPLETE:
mMachine.setCurrentState(new ReadyToInstall(mMachine));
break;
case LLUpdaterService::DOWNLOAD_ERROR:
mMachine.setCurrentState(new Error(mMachine));
break;
default:
break;
}
return false;
}
// LLLoginInstance
//-----------------------------------------------------------------------------
LLLoginInstance::LLLoginInstance() :
mLoginModule(new LLLogin()),
mNotifications(NULL),
@ -69,7 +439,8 @@ LLLoginInstance::LLLoginInstance() :
mSkipOptionalUpdate(false),
mAttemptComplete(false),
mTransferRate(0.0f),
mDispatcher("LLLoginInstance", "change")
mDispatcher("LLLoginInstance", "change"),
mUpdaterService(0)
{
mLoginModule->getEventPump().listen("lllogininstance",
boost::bind(&LLLoginInstance::handleLoginEvent, this, _1));
@ -353,6 +724,14 @@ bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)
void LLLoginInstance::updateApp(bool mandatory, const std::string& auth_msg)
{
if(mandatory)
{
gViewerWindow->setShowProgress(false);
MandatoryUpdateMachine * machine = new MandatoryUpdateMachine(*this, *mUpdaterService);
machine->start();
return;
}
// store off config state, as we might quit soon
gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE);
LLUIColorTable::instance().saveUserSettings();

View File

@ -34,6 +34,7 @@
class LLLogin;
class LLEventStream;
class LLNotificationsInterface;
class LLUpdaterService;
// This class hosts the login module and is used to
// negotiate user authentication attempts.
@ -75,6 +76,7 @@ public:
typedef boost::function<void()> UpdaterLauncherCallback;
void setUpdaterLauncher(const UpdaterLauncherCallback& ulc) { mUpdaterLauncher = ulc; }
void setUpdaterService(LLUpdaterService * updaterService) { mUpdaterService = updaterService; }
private:
void constructAuthParams(LLPointer<LLCredential> user_credentials);
void updateApp(bool mandatory, const std::string& message);
@ -104,6 +106,7 @@ private:
int mLastExecEvent;
UpdaterLauncherCallback mUpdaterLauncher;
LLEventDispatcher mDispatcher;
LLUpdaterService * mUpdaterService;
};
#endif

View File

@ -2888,6 +2888,18 @@ http://secondlife.com/download.
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="UpdaterServiceNotRunning"
type="alertmodal">
An update is required to log in. May we start the background
updater service to fetch and install the update?
<usetemplate
name="okcancelbuttons"
notext="Quit"
yestext="Start"/>
</notification>
<notification
icon="notifytip.tga"
name="DownloadBackgroundTip"

View File

@ -184,6 +184,40 @@ void LLUIColorTable::saveUserSettings(void)const {}
const std::string &LLVersionInfo::getChannelAndVersion() { return VIEWERLOGIN_VERSION_CHANNEL; }
const std::string &LLVersionInfo::getChannel() { return VIEWERLOGIN_CHANNEL; }
//-----------------------------------------------------------------------------
#include "../llappviewer.h"
void LLAppViewer::forceQuit(void) {}
LLAppViewer * LLAppViewer::sInstance = 0;
//-----------------------------------------------------------------------------
#include "llnotificationsutil.h"
LLNotificationPtr LLNotificationsUtil::add(const std::string& name,
const LLSD& substitutions,
const LLSD& payload,
boost::function<void (const LLSD&, const LLSD&)> functor) { return LLNotificationPtr((LLNotification*)0); }
//-----------------------------------------------------------------------------
#include "llupdaterservice.h"
std::string const & LLUpdaterService::pumpName(void)
{
static std::string wakka = "wakka wakka wakka";
return wakka;
}
bool LLUpdaterService::updateReadyToInstall(void) { return false; }
void LLUpdaterService::initialize(const std::string& protocol_version,
const std::string& url,
const std::string& path,
const std::string& channel,
const std::string& version) {}
void LLUpdaterService::setCheckPeriod(unsigned int seconds) {}
void LLUpdaterService::startChecking(bool install_if_ready) {}
void LLUpdaterService::stopChecking() {}
bool LLUpdaterService::isChecking() { return false; }
LLUpdaterService::eUpdaterState LLUpdaterService::getState() { return INITIAL; }
//-----------------------------------------------------------------------------
#include "llnotifications.h"
#include "llfloaterreg.h"
@ -435,6 +469,8 @@ namespace tut
template<> template<>
void lllogininstance_object::test<3>()
{
skip();
set_test_name("Test Mandatory Update User Accepts");
// Part 1 - Mandatory Update, with User accepts response.
@ -462,6 +498,8 @@ namespace tut
template<> template<>
void lllogininstance_object::test<4>()
{
skip();
set_test_name("Test Mandatory Update User Decline");
// Test connect with update needed.