--- deliantra/Deliantra-Client/DC/Main.pm 2011/12/31 06:51:29 1.7
+++ deliantra/Deliantra-Client/DC/Main.pm 2012/01/06 05:02:39 1.10
@@ -20,6 +20,7 @@
use common::sense;
use Carp 'verbose';
use Cwd ();
+use Digest::MD5 ();
use EV;
BEGIN { *time = \&EV::time }
@@ -197,7 +198,7 @@
$msg =~ s/\s+$//;
# backtrace as second step, in case it crashes, too
- crash Carp::longmess "$msg\nbacktrace, for client version $DC::VERSION, generated"
+ crash Carp::longmess "$msg\nbacktrace, for client version $DC::VERSION$Urlader::EXE_VER, generated"
if $backtrace;
};
@@ -209,7 +210,7 @@
return unless $CONN;
$CONN->send_exti_msg (clientlog => $msg);
- $CONN->send_exti_msg (clientlog => Carp::longmess "$msg\nbacktrace, for client version $DC::VERSION, generated") if $backtrace;
+ $CONN->send_exti_msg (clientlog => Carp::longmess "$msg\nbacktrace, for client version $DC::VERSION$Urlader::EXE_VER, generated") if $backtrace;
}
#############################################################################
@@ -527,6 +528,195 @@
}
#############################################################################
+# Over-the-air updates
+
+sub ota_update {
+ my ($face, $size, $md5) = @_;
+
+ my $coro = Coro::async_pool {
+ my $override = "$Urlader::EXE_DIR/override";
+
+ $MESSAGE_DIST->add_channel ({
+ id => "ota_update",
+ title => "Update",
+ tooltip => "Software Update Log",
+ });
+
+ $MESSAGE_DIST->message ({ type => "ota_update", markup => "preparing override..." });
+
+ my $fh = Coro::AIO::aio_open "$override.tmp", IO::AIO::O_WRONLY | IO::AIO::O_CREAT | IO::AIO::O_TRUNC, 0777;
+
+ unless ($fh) {
+ $MESSAGE_DIST->message ({ type => "ota_update", markup => (DC::asxml "unable to write software update:\n$Urlader::EXE_DIR/override.tmp:\n$!") });
+ return;
+ }
+
+ $MESSAGE_DIST->message ({ type => "ota_update", markup => "downloading $size bytes..." });
+
+ my $cv = AE::cv;
+ my $error;
+
+ $cv->begin (Coro::rouse_cb);
+ $CONN->ask_face (
+ $face,
+ -1000,
+ sub {
+ $STATUSBOX->add (
+ (sprintf "update download: %d/%d", $size - $_[1], $size),
+ pri => -9, group => "ota_update", timeout => 60, fg => [1, 1, 0, 1]
+ );
+
+ $cv->begin;
+ my $len = length $_[2];
+ IO::AIO::aio_write $fh, $_[1], $len, $_[2], undef, sub {
+ $error ||= $_[0] != $len;
+ $cv->end;
+ };
+ },
+ sub {
+ $cv->end;
+ },
+ );
+
+ Coro::rouse_wait;
+
+ $STATUSBOX->clr_group ("ota_update");
+
+ $error ||= Coro::AIO::aio_fsync $fh;
+ $error ||= Coro::AIO::aio_close $fh;
+
+ if ($error) {
+ $MESSAGE_DIST->message ({ type => "ota_update", markup => "file write error, update aborted." });
+ Coro::AIO::aio_unlink "$override.tmp";
+ return;
+ }
+
+ {
+ $MESSAGE_DIST->message ({ type => "ota_update", markup => "verifying update file..." });
+
+ my $fh = Coro::AIO::aio_open "$override.tmp", IO::AIO::O_RDONLY, 0;
+
+ if ($fh) {
+ $error ||= Coro::AIO::aio_stat "$override.tmp";
+ $error ||= -s _ != $size;
+ $error ||= Coro::AIO::aio_readahead $fh, 0, $size;
+
+ my $f_md5 = new Digest::MD5;
+ $f_md5->addfile ($fh);
+ $f_md5 = $f_md5->hexdigest;
+ $error ||= $md5 ne $f_md5;
+ }
+ }
+
+ if ($error) {
+ $MESSAGE_DIST->message ({ type => "ota_update", markup => "verification failed, update aborted." });
+ Coro::AIO::aio_unlink "$override.tmp";
+ return;
+ }
+
+ $MESSAGE_DIST->message ({ type => "ota_update", markup => "replacing override file..." });
+
+ if (Coro::AIO::aio_rename "$override.tmp", $override) {
+ $MESSAGE_DIST->message ({ type => "ota_update", markup => "unable to replace override file, update aborted." });
+ Coro::AIO::aio_unlink "$override.tmp";
+ }
+
+ $MESSAGE_DIST->message ({ type => "ota_update", markup => "success - update becomes active after restarting." });
+ };
+
+ $CONN->{ota_update} = Guard::guard {
+ $coro->cancel;
+ };
+}
+
+sub ota_update_ask {
+ my ($ok, $face, $ver, $size, $md5, $changes) = @_;
+
+ $CONN->{w}{ota_dialog} = my $dialog = new DC::UI::Toplevel
+ x => "center",
+ y => "center",
+ z => 55,
+ force_w => $::WIDTH * 0.7,
+ force_h => $::HEIGHT * 0.7,
+ title => "Software update available",
+ child => my $vbox = new DC::UI::VBox,
+ ;
+
+ $vbox->add (new DC::UI::Label
+ ellipsise => 0,
+ text => "The server offers a software update, "
+ . "do you want to start downloading this update in the background?",
+ );
+
+ $vbox->add (new DC::UI::FancyFrame
+ expand => 1,
+ label => "Details",
+ child => (new DC::UI::TextScroller
+ expand => 1, fontsize => 0.8, padding_x => 4, padding_y => 4,
+ par => [{
+ markup => "Old revision: $Urlader::EXE_VER\n"
+ . "New revision: $ver\n"
+ . "Download size: $size bytes\n\n"
+ . "Changes:\n\n"
+ . DC::asxml $changes
+ }],
+ ),
+ );
+
+ $vbox->add (my $hbox = new DC::UI::HBox);
+
+ $hbox->add (new DC::UI::Button
+ expand => 1,
+ text => "Not now",
+ on_activate => sub {
+ $dialog->destroy;
+ 0
+ }
+ );
+ $hbox->add (new DC::UI::Button
+ expand => 1,
+ text => "Yes, start downloading",
+ on_activate => sub {
+ $dialog->destroy;
+ ota_update $face, $size, $md5;
+ 0
+ },
+ );
+
+ $dialog->show;
+}
+
+sub ota_update_check {
+ return unless defined $Urlader::EXE_ID;
+
+ ::message { markup => "Checking for software update..." };
+
+ $CONN->send_exti_req (ota_update => $Urlader::URLADER_VERSION, $Urlader::EXE_ID, $Urlader::EXE_VER, sub {
+ my ($ok, $face, $ver, $size, $md5, $changes) = @_;
+
+ if ($ok) {
+ if (defined $ver) {
+ ::message { markup => "Server offers version $ver (we are version $Urlader::EXE_VER)." };
+ &ota_update_ask;
+ } else {
+ ::message { markup => "Server has no newer version." };
+ }
+ } else {
+ ::message { markup => "Server does not support software update." };
+ }
+
+# $self->register_face_handler ($exp_table, sub {
+# my ($face) = @_;
+
+# $self->{exp_table} = $self->{json_coder}->decode (delete $face->{data});
+# $_->() for values %{ $self->{on_exp_update} || {} };
+# });
+
+ ()
+ });
+}
+
+#############################################################################
sub destroy_query_dialog {
(delete $_[0]{query_dialog})->destroy
@@ -776,7 +966,7 @@
c_version => {
client => "deliantra",
- clientver => $DC::VERSION,
+ clientver => "$DC::VERSION$Urlader::EXE_VER",
gl_vendor => DC::OpenGL::gl_vendor,
gl_version => DC::OpenGL::gl_version,
},
@@ -795,6 +985,8 @@
if ($_[0]) {
DC::lowdelay fileno $CONN->{fh};
+ ota_update_check;
+
status "successfully connected to the server";
} else {
undef $CONN;
@@ -1857,7 +2049,7 @@
$table->add_at (1, $row++, new DC::UI::Label align => 0, text => $ENV{URLADER_VERSION}, tooltip => "");
$table->add_at (0, $row , new DC::UI::Label align => 1, text => "Branch (Prebuilt)");
$table->add_at (1, $row++, new DC::UI::Label align => 0, text => $ENV{URLADER_EXE_ID}, tooltip => "");
- $table->add_at (0, $row , new DC::UI::Label align => 1, text => "Version (Prebuilt)");
+ $table->add_at (0, $row , new DC::UI::Label align => 1, text => "Revision (Prebuilt)");
$table->add_at (1, $row++, new DC::UI::Label align => 0, text => $ENV{URLADER_EXE_VER}, tooltip => "");
}
@@ -2281,7 +2473,7 @@
$QUIT_DIALOG = new DC::UI::Toplevel
x => "center",
y => "center",
- z => 50,
+ z => 60,
title => "Really Quit?",
on_key_down => sub {
my ($dialog, $ev) = @_;