From 40f683f8e11e217c3c27bf6e8606aa7bcb88f908 Mon Sep 17 00:00:00 2001 From: (no author) Date: Thu, 28 Sep 2006 15:13:27 +0000 Subject: This commit was manufactured by cvs2svn to create branch 'debian_sarge_branch'. --- debian/changelog | 29 +++ debian/control | 10 +- debian/rules | 41 ++-- icp.prj | 9 + src/Agent.pm | 589 ++++++++++++++++++++++++++++------------------------ src/IvyIO.pm | 70 +++++-- src/ivycontrolpanel | 200 ++++++++++++------ 7 files changed, 569 insertions(+), 379 deletions(-) create mode 100755 icp.prj diff --git a/debian/changelog b/debian/changelog index b3a89c5..ff0744a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,32 @@ +ivycontrolpanel (2.3) unstable; urgency=low + + * Ajout d'un mécanisme de polling pour détecter les problèmes de + performance. Cette fonctionnalité nécessite Ivy v4.18. + (contribution de JP Imbert) + + -- Daniel Etienne Thu, 28 Sep 2006 15:49:19 +0200 + +ivycontrolpanel (2.2) unstable; urgency=low + + * Optimisation des regexps ivy (correction d'un bug introduit en v2.0) + + -- Daniel Etienne Wed, 19 Apr 2006 11:23:03 +0200 + +ivycontrolpanel (2.1) unstable; urgency=low + + * Ajout de l'option -smallsize: affichage en 640x480. + * Ajout de l'option -position. + + -- Cedirc Mariot Wed, 26 Nov 2003 14:17:18 +0200 + +ivycontrolpanel (2.0) unstable; urgency=low + + * Reconception IHM : le widget Zinc est abandonné au profit de widgets + plus adaptés. + * Reconception graphique + + -- Daniel Etienne Wed, 7 May 2003 17:47:18 +0200 + ivycontrolpanel (1.9) unstable; urgency=low * passage à zinc-perl 3.2.6a1 ou >= 3.2.6h diff --git a/debian/control b/debian/control index c7fbfb9..68f5696 100644 --- a/debian/control +++ b/debian/control @@ -1,16 +1,16 @@ Source: ivycontrolpanel Section: devel Priority: extra -Maintainer: Christophe Mertz -Standards-Version: 2.3.0.0 +Maintainer: Daniel Etienne +Standards-Version: 3.2.1 Package: ivycontrolpanel Architecture: all -Depends: perl5, ivy-perl (>= 4.11b), perl-tk, zinc-perl (= 3.2.6a1) | zinc-perl (>= 3.2.6h) +Depends: perl5, ivy-perl (>= 4.11b), perl-tk, ivylaunch Description: Monitoring of ivy based applications Monitoring of ivy agent (ie ivy based applications). It monitors applications launched on a given ivy port number. - (Specific use for Toccata demos). It allows restarting agents described in a configuration file. - It also offers some simulation start, stop and pause. + It also offers some simulation start, stop and pause (specific + use for Toccata trafic generator) diff --git a/debian/rules b/debian/rules index 0204846..74aba0a 100755 --- a/debian/rules +++ b/debian/rules @@ -6,57 +6,48 @@ package=ivycontrolpanel build: $(checkdir) - pod2man src/$(package) > doc/$(package).1 touch build clean: $(checkdir) -rm -f build + -$(MAKE) clean -rm -f `find . -name "*~"` -rm -rf debian/tmp debian/files* core debian/substvars -binary-indep: checkroot build +binary-indep: checkroot build + $(checkdir) +# There are no architecture-independent files to be uploaded +# generated by this package. If there were any they would be +# made here. + +binary-arch: checkroot build $(checkdir) -rm -rf debian/tmp + install -d debian/tmp install -d debian/tmp/usr/bin - install -d debian/tmp/usr/ install -d debian/tmp/usr/lib/$(package) install -d debian/tmp/usr/share/$(package) - install -d debian/tmp/usr/share/man/man1 - - pod2man src/$(package) > debian/tmp/usr/share/man/man1/$(package).1 - install -m755 src/ivycontrolpanel debian/tmp/usr/bin/$(package) - for f in src/*.pm; do \ - install -m644 $$f debian/tmp/usr/lib/$(package); \ - done - for f in images/*; do \ - install -m644 $$f debian/tmp/usr/share/$(package); \ - done + install -m755 src/$(package) debian/tmp/usr/bin/$(package) + install -m644 src/*.pm debian/tmp/usr/lib/$(package) + install -m644 images/*.bmp debian/tmp/usr/share/$(package) # Must have debmake installed for this to work. Otherwise please copy # /usr/bin/debstd into the debian directory and change debstd to debian/debstd - debstd debian/copyright debian/changelog doc/*.1 doc/ivycontrolpanel.gif - dpkg-gencontrol -isp + pod2man src/$(package) > $(package).1 + debstd + dpkg-gencontrol chown -R root.root debian/tmp chmod -R go=rX debian/tmp dpkg --build debian/tmp .. -binary-arch: checkroot build - $(checkdir) -# There are no architecture-independent files to be uploaded -# generated by this package. If there were any they would be -# made here. - define checkdir test -f debian/rules endef -# Below here is fairly generic really - -binary: binary-indep binary-arch +binary: binary-indep binary-arch checkroot: $(checkdir) test root = "`whoami`" .PHONY: binary binary-arch binary-indep clean checkroot - diff --git a/icp.prj b/icp.prj new file mode 100755 index 0000000..fbc6fe1 --- /dev/null +++ b/icp.prj @@ -0,0 +1,9 @@ +[Project ID] +Signature=UE Proj: v.1 +[Files] +0=E:\Travail\ivycontrolpanel\debian\changelog +1=E:\Travail\ivycontrolpanel\src\Agent.pm +2=E:\Travail\ivycontrolpanel\src\ivycontrolpanel +3=E:\Travail\ivycontrolpanel\src\IvyIO.pm +[Group] +0= diff --git a/src/Agent.pm b/src/Agent.pm index 75cf616..d1a6fc1 100644 --- a/src/Agent.pm +++ b/src/Agent.pm @@ -13,122 +13,138 @@ use strict; # #---------------------------------------------------------------------- my ($x0, $y0, $wmax, $dx, $dy, $cmin, $rmax, @matrix, @hosts, $tempo_id, - $mw, $bg, $fg, $selcolor, $hlbg, $darkbg, $fontspec, @fontspec, - $on_img, $off_img, %instances, @instances, $bus, - $hosts_tl, $selected_host, $preselected_host); + $mw, $bg, $fg, $selcolor, $pbcolor, $hlbg, $darkbg, $fontspec, @fontspec, + $on_img, $off_img, $pb_img, %instances, @instances, $bus, $coef, + $hosts_tl, $selected_host, $preselected_host, $pingThreshold); # configure the class : graphic parameters, geometry and ivy bus sub configure { - shift; - ($mw, $bg, $fg, $selcolor, $hlbg, $darkbg, - $fontspec, $x0, $y0, $wmax, $dy, $cmin, $rmax, $bus) = @_; - @fontspec = @$fontspec if $fontspec; - $off_img = $mw->Bitmap('off', -file => Tk::findINC('led.bmp'), - -foreground => $bg); - $on_img = $mw->Bitmap('on', -file => Tk::findINC('led.bmp'), - -foreground => $selcolor); - &_resetmatrix; - + shift; + ($mw, $bg, $fg, $selcolor, $pbcolor, $hlbg, $darkbg, + $fontspec, $x0, $y0, $wmax, $dy, $cmin, $rmax, $bus, $coef, $pingThreshold) = @_; + @fontspec = @$fontspec if $fontspec; + $off_img = $mw->Bitmap('off', -file => Tk::findINC('led.bmp'), + -foreground => $bg); + $pb_img = $mw->Bitmap('pb', -file => Tk::findINC('led.bmp'), + -foreground => $pbcolor); + $on_img = $mw->Bitmap('on', -file => Tk::findINC('led.bmp'), + -foreground => $selcolor); + &_resetmatrix; + } # end configure # kill an named agent sub kill { - my ($class, $appname) = @_; - IvyIO::kill($appname); + my ($class, $appname) = @_; + IvyIO::kill($appname); } # end kill; # kill all agents sub killall { - my ($class) = @_; - my $nb = 0; - for(@instances) { - if ($_->{status} > 0) { - IvyIO::kill($_->{appname}); - $nb++; - } - } - return $nb; + my ($class) = @_; + my $nb = 0; + for(@instances) { + if ($_->{status} > 0) { + IvyIO::kill($_->{appname}); + $nb++; + } + } + return $nb; } # end killall; # set usable hosts list for executing agents sub hosts { - shift; - @hosts = @_; + shift; + @hosts = @_; } # end hosts # callback called when an agent connects sub connect { - my ($class, $appname, $host) = @_; - if ($instances{$appname}) { - if ($instances{$appname}->{status} == 1) { - $instances{$appname}->addtwin; - } else { - $instances{$appname}->on; - } - } else { - $class->new($appname, $host, undef, undef, 1); - } + my ($class, $appname, $host) = @_; + if ($instances{$appname}) { + if ($instances{$appname}->{status} == 1) { + $instances{$appname}->addtwin; + } else { + $instances{$appname}->on; + } + } else { + $class->new($appname, $host, undef, undef, 1); + } } # end connect # callback called when an agent disconnects sub disconnect { - my ($class, $appname, $host) = @_; - if ($instances{$appname}) { - if ($instances{$appname}->{number} > 1) { - $instances{$appname}->removetwin; - } else { - $instances{$appname}->off; - } - } else { - $class->new($appname, $host, undef, undef, 0); - } + my ($class, $appname, $host) = @_; + if ($instances{$appname}) { + if ($instances{$appname}->{number} > 1) { + $instances{$appname}->removetwin; + } else { + $instances{$appname}->off; + } + } else { + $class->new($appname, $host, undef, undef, 0); + } } # end disconnect +# callback called when a ping/pong is received +sub pingcb { + my ($class, $appname, $host, $pingtime) = @_; + #print "pingtime=$pingtime\n"; + if ($instances{$appname}) { + # if pingtime > $pingThreshold status is changed + if ($pingtime > $pingThreshold) { + $instances{$appname}->pb; + } elsif ($instances{$appname}->{status} == 2) { + $instances{$appname}->nopb; + } + } +} # end pingcb + # class constructor sub new { - my ($class, $appname, $host, $command, $params, $status) = @_; - if ($instances{$appname}) { - $instances{$appname}->addtwin; - return; - } - my $self = {}; - bless $self; - - # set object attributes - $self->{appname} = $appname; - $self->{status} = $status; - $self->{host} = $host; - $self->{command} = $command; - $self->{params} = $params; - $self->{number} = 1; - $self->{led} = undef; - $self->{label} = undef; - - # reset positions before adding new instance - if (@instances >= ($rmax*$cmin)) { - $cmin++; - $class->_updatepositions; - } - # set class variables - $instances{$appname} = $self; - push(@instances, $self); - - # graphical updates - $self->createlabel; - $self->on if $status; - - $class->_alphabeticsort(); - - return $self; + my ($class, $appname, $host, $command, $params, $status) = @_; + if ($instances{$appname}) { + $instances{$appname}->addtwin; + return; + } + my $self = {}; + bless $self; + + # set object attributes + $self->{appname} = $appname; + $self->{status} = $status; + $self->{host} = $host; + $self->{command} = $command; + $self->{params} = $params; + $self->{number} = 1; + $self->{led} = undef; + $self->{label} = undef; + + # reset positions before adding new instance + if (@instances >= ($rmax*$cmin)) { + $cmin++; + $class->_updatepositions; + } + # set class variables + $instances{$appname} = $self; + push(@instances, $self); + + # graphical updates + $self->createlabel; + $self->on if $status; + + $class->_alphabeticsort(); + + return $self; } # end new @@ -142,139 +158,166 @@ sub new { # called when several agent instances are detected sub addtwin { - my $self = shift; - $self->{number}++; - $self->{label}->configure(-text => $self->formatlabel); + my $self = shift; + $self->{number}++; + $self->{label}->configure(-text => $self->formatlabel); } # end addtwin # called when an instance of a not single agent dies sub removetwin { - my $self = shift; - return if $self->{number} == 1; - $self->{number}--; - $self->{label}->configure(-text => $self->formatlabel); + my $self = shift; + return if $self->{number} == 1; + $self->{number}--; + $self->{label}->configure(-text => $self->formatlabel); } # end addtwin # graphical effect when a known agent connects sub on { - my $self = shift; - $self->{status} = 1; - $self->{led}->configure(-image => $on_img); - $self->{label}->raise; - $self->{label}->configure(-highlightthicknes => 2); - $tempo_id = $mw->after(3000, sub { - $self->{label}->configure(highlightthicknes => 0); - }); + my $self = shift; + $self->nopb; + $self->{label}->raise; + $self->{label}->configure(-highlightthicknes => 2); + $tempo_id = $mw->after(2000, sub { + $self->{label}->configure(-highlightthicknes => 0); + }); } # end on # graphical effect when a known agent disconnects sub off { - my $self = shift; - $self->{status} = 0; - $self->{led}->configure(-image => $off_img); + my $self = shift; + $self->{status} = 0; + $self->{led}->configure(-image => $off_img); } # end off +# graphical effect when a know agent has a ping problem (latency) + +sub pb { + my $self = shift; + $self->{status} = 2; + $self->{led}->configure(-image => $pb_img); + my $i = 0; + my $id; + $id = $mw->repeat(100, sub { + if ($i == 4) { + $mw->afterCancel($id); + } elsif ($i % 2 == 0) { + $self->{led}->configure(-image => $on_img); + } else { + $self->{led}->configure(-image => $pb_img); + } + $i++; + }); + +} # end pb + +sub nopb { + my $self = shift; + $self->{status} = 1; + $self->{led}->configure(-image => $on_img); + +} # end pb + # label placement sub setposition { - my $self = shift; - my ($r, $c); - for (my $i=0; $i<@matrix; $i++) { - for (my $j=0; $j<=$#{$matrix[$i]}; $j++) { - unless ($matrix[$i][$j]->[0]) { - ($r, $c) = ($i, $j); - last; - } - } - last if defined $r; - } - $matrix[$r][$c]->[0] = $self; - my ($x, $y) = ($matrix[$r][$c]->[1], $matrix[$r][$c]->[2]); - my $y2 = $y - 5; - $y2 -= 12 if ($self->{label}->cget(-text) =~ /\n/); - - if ($self->{command}) { - $self->{led}->configure(-highlightthickness => 6); - $self->{led}->place(-x => $x+3, -y => $y+3); - } else { - $self->{led}->configure(-highlightthickness => 2); - $self->{led}->place(-x => $x+6, -y => $y+6); - } - $self->{label}->place(-x => $x + 38, -y => $y2); + my $self = shift; + my ($r, $c); + for (my $i=0; $i<@matrix; $i++) { + for (my $j=0; $j<=$#{$matrix[$i]}; $j++) { + unless ($matrix[$i][$j]->[0]) { + ($r, $c) = ($i, $j); + last; + } + } + last if defined $r; + } + $matrix[$r][$c]->[0] = $self; + my ($x, $y) = ($matrix[$r][$c]->[1], $matrix[$r][$c]->[2]); + my $y2 = $y - 5*$coef; + $y2 -= 12*$coef if ($self->{label}->cget(-text) =~ /\n/); + + if ($self->{command}) { + $self->{led}->configure(-highlightthickness => 6*$coef); + $self->{led}->place(-x => $x+3*$coef, -y => $y+3*$coef); + } else { + $self->{led}->configure(-highlightthickness => 2*$coef); + $self->{led}->place(-x => $x+6*$coef, -y => $y+6*$coef); + } + $self->{label}->place(-x => $x + 38, -y => $y2); } # end setposition # label creation sub createlabel { - my ($self) = @_; - $self->{led} = - $mw->Label(-image => $off_img, - -highlightbackground => $hlbg, - -borderwidth => 0, - ); - $self->{label} = - $mw->Label(-text => $self->formatlabel, - -pady => 10, - -justify => 'left', - -relief => 'flat', - -highlightthickness => 0, - -background => $darkbg, - -foreground => $fg, - @fontspec, - ); - $self->{led}->bind('<1>', [\&_cbOnPress, $self]); - $self->{label}->bind('<1>', [\&_cbOnPress, $self]); + my ($self) = @_; + $self->{led} = + $mw->Label(-image => $off_img, + -highlightbackground => $hlbg, + -borderwidth => 0, + ); + $self->{label} = + $mw->Label(-text => $self->formatlabel, + -pady => 10*$coef, + -justify => 'left', + -relief => 'flat', + -highlightthickness => 0, + -background => $darkbg, + -foreground => $fg, + @fontspec, + ); + $self->{led}->bind('<1>', [\&_cbOnPress, $self]); + $self->{label}->bind('<1>', [\&_cbOnPress, $self]); } # end createlabel # label format : affects too long labels and not single agents sub formatlabel { - my ($self) = @_; - my $im_width = 38; - my $dx = $dx - $im_width; - my $appname = $self->{appname}; - # for not single agents - $appname = '['.$self->{number}.'] '.$appname if $self->{number} > 1; - my $width = $mw->fontMeasure($fontspec[1], $appname); - my $appnametext; - # for too long names - while ($width > 2*$dx) { - $appname = substr($appname, 0, -1); - $width = $mw->fontMeasure($fontspec[1], $appname); - } - if ($width > $dx) { - my $hlen = int(length($appname)/2); - my @fields = split(/:/, $appname); - if (@fields > 1) { - my $len = 0; - my $imax = -1; - for (my $i=0; $i<@fields; $i++) { - $len += length($fields[$i]); - if ($len > $hlen) { - $imax = $i - 1; - last; - } - } - if ($imax >= 0) { - $appnametext = join(':', (@fields)[0..$imax])."\n". - join(':', (@fields)[$imax+1..$#fields]); - } - } - $appnametext = substr($appname, 0, $hlen)."\n".substr($appname, $hlen) - unless $appnametext; - } else { - my @fields = split(/:/, $appname); - if (@fields > 1) { - $appnametext = $fields[0].":\n ".join(':', (@fields)[1..$#fields]); - } - } - $appnametext = $appname unless $appnametext; - return $appnametext; + my ($self) = @_; + my $im_width = 38; + my $dx = $dx - $im_width; + my $appname = $self->{appname}; + # for not single agents + $appname = '['.$self->{number}.'] '.$appname if $self->{number} > 1; + my $width = $mw->fontMeasure($fontspec[1], $appname); + my $appnametext; + # for too long names + while ($width > 2*$dx) { + $appname = substr($appname, 0, -1); + $width = $mw->fontMeasure($fontspec[1], $appname); + } + if ($width > $dx) { + my $hlen = int(length($appname)/2); + my @fields = split(/:/, $appname); + if (@fields > 1) { + my $len = 0; + my $imax = -1; + for (my $i=0; $i<@fields; $i++) { + $len += length($fields[$i]); + if ($len > $hlen) { + $imax = $i - 1; + last; + } + } + if ($imax >= 0) { + $appnametext = join(':', (@fields)[0..$imax])."\n". + join(':', (@fields)[$imax+1..$#fields]); + } + } + $appnametext = substr($appname, 0, $hlen)."\n".substr($appname, $hlen) + unless $appnametext; + } else { + my @fields = split(/:/, $appname); + if (@fields > 1) { + $appnametext = $fields[0].":\n ".join(':', (@fields)[1..$#fields]); + } + } + $appnametext = $appname unless $appnametext; + return $appnametext; } # end formatlabel @@ -285,120 +328,120 @@ sub formatlabel { # #---------------------------------------------------------------------- sub _resetmatrix { - $dx = $wmax/$cmin; - for(my $r=0; $r<$rmax; $r++) { - for(my $c=0; $c<$cmin; $c++) { - $matrix[$r][$c] = [undef, $x0 + $c*$dx, $y0 + $r*$dy]; - } - } + $dx = $wmax/$cmin; + for(my $r=0; $r<$rmax; $r++) { + for(my $c=0; $c<$cmin; $c++) { + $matrix[$r][$c] = [undef, $x0 + $c*$dx, $y0 + $r*$dy]; + } + } } # end _resetmatrix sub _updatepositions { - &_resetmatrix; - for (@instances) { - $_->setposition(); - $_->{label}->configure(-text => $_->formatlabel); - } + &_resetmatrix; + for (@instances) { + $_->setposition(); + $_->{label}->configure(-text => $_->formatlabel); + } } # end _updatepositions sub _alphabeticsort { - &_resetmatrix; - for (sort {uc($a->{appname}) cmp uc($b->{appname})} @instances) { - $_->setposition(); - } + &_resetmatrix; + for (sort {uc($a->{appname}) cmp uc($b->{appname})} @instances) { + $_->setposition(); + } } # end _alphabeticsort # callback invoked when user press on label sub _cbOnPress { - shift; - my $self = shift; - $self->{label}->configure(-foreground => $hlbg); - if ($self->{status} == 1) { - IvyIO::kill($self->{appname}); - $mw->after(400, sub {$self->{label}->configure(-foreground => $fg);}); - } elsif ($self->{command}) { - my ($x, $y) = ($self->{label}->rootx, $self->{label}->rooty); - my $host = &_hostsmenu($x, $y, $self->{host}); - $self->{label}->configure(-foreground => $fg); - return unless $host; - FugueConfig::launchAgent($self->{appname}, $host, - $self->{command}, $self->{params}, $bus); - print "$self->{appname} launched\n"; - } else { - $mw->bell; - $mw->after(400, sub {$self->{label}->configure(-foreground => $fg);}); - } + shift; + my $self = shift; + $self->{label}->configure(-foreground => $hlbg); + if ($self->{status} > 0) { + IvyIO::kill($self->{appname}); + $mw->after(400, sub {$self->{label}->configure(-foreground => $fg);}); + } elsif ($self->{command}) { + my ($x, $y) = ($self->{label}->rootx, $self->{label}->rooty); + my $host = &_hostsmenu($x, $y, $self->{host}); + $self->{label}->configure(-foreground => $fg); + return unless $host; + FugueConfig::launchAgent($self->{appname}, $host, + $self->{command}, $self->{params}, $bus); + print "$self->{appname} launched\n"; + } else { + $mw->bell; + $mw->after(400, sub {$self->{label}->configure(-foreground => $fg);}); + } } # end _cbOnPress # create and show hosts menu sub _hostsmenu { - my $x = shift; - my $y = shift; - $x += 50; - - my $preselected_host = shift; - return $preselected_host if @hosts <= 1; - $hosts_tl->destroy if Tk::Exists($hosts_tl); - $hosts_tl = $mw->Toplevel(-background => $darkbg); - $hosts_tl->resizable(0,0); - $hosts_tl->title('ivycontrolpanel'); - my $hosts_fm = $hosts_tl->Frame(-background => $darkbg, - -highlightthickness => 3, - -highlightbackground => $hlbg, - )->pack(-side => 'top', -padx => 0, -pady => 0); - my @lattr = (-padx => 10, - -pady => 10, - -relief => 'flat', - -highlightthickness => 0, - -background => $darkbg, - -foreground => $fg, - -borderwidth => 0, - @fontspec); - my @battr = (@lattr, - -width => 4, -height => 1, - -highlightthickness => 3, - -highlightbackground => $hlbg, - -activebackground => $darkbg, - -activeforeground => $fg, - ); - my @rattr = (@lattr, - -activebackground => $darkbg, - -activeforeground => $fg, - -selectcolor => $selcolor); - - $hosts_fm->Label(@lattr, -text => "restart on :" - )->pack(-side => 'top', -padx => 20, -pady => 20); - for(@hosts) { - $hosts_fm->Radiobutton(@rattr, - -variable => \$preselected_host, - -value => $_, - -text => $_, - )->pack(-side => 'top'); - } - my $fm = $hosts_fm->Frame(-background => $darkbg)->pack(-side => 'bottom'); - $fm->Button(@battr, - -command => sub {$hosts_tl->destroy}, - -text => 'ok')->pack(-side => 'left', -padx => 10, -pady => 20); - $fm->Button(@battr, - -command => sub {$preselected_host = undef; $hosts_tl->destroy}, - -text => 'cancel')->pack(-side => 'left', -padx => 10, -pady => 20); - $hosts_tl->update; - my ($X, $Y) = ($mw->rootx, $mw->rooty); - my ($w, $h) = ($hosts_tl->width, $hosts_tl->height); - my ($W, $H) = ($mw->width, $mw->height); - $x = $X + $W - $w if ($x + $w) > $X + $W; - $y = $Y + $H - $h if ($y + $h) > $Y + $H; - $hosts_tl->geometry('+'.$x.'+'.$y); - $hosts_tl->waitWindow(); - return $preselected_host; + my $x = shift; + my $y = shift; + $x += 50; + + my $preselected_host = shift; + return $preselected_host if @hosts <= 1; + $hosts_tl->destroy if Tk::Exists($hosts_tl); + $hosts_tl = $mw->Toplevel(-background => $darkbg); + $hosts_tl->resizable(0,0); + $hosts_tl->title('ivycontrolpanel'); + my $hosts_fm = $hosts_tl->Frame(-background => $darkbg, + -highlightthickness => 3, + -highlightbackground => $hlbg, + )->pack(-side => 'top', -padx => 0, -pady => 0); + my @lattr = (-padx => 10, + -pady => 10, + -relief => 'flat', + -highlightthickness => 0, + -background => $darkbg, + -foreground => $fg, + -borderwidth => 0, + @fontspec); + my @battr = (@lattr, + -width => 4, -height => 1, + -highlightthickness => 3, + -highlightbackground => $hlbg, + -activebackground => $darkbg, + -activeforeground => $fg, + ); + my @rattr = (@lattr, + -activebackground => $darkbg, + -activeforeground => $fg, + -selectcolor => $selcolor); + + $hosts_fm->Label(@lattr, -text => "restart on :" + )->pack(-side => 'top', -padx => 20, -pady => 20); + for(@hosts) { + $hosts_fm->Radiobutton(@rattr, + -variable => \$preselected_host, + -value => $_, + -text => $_, + )->pack(-side => 'top'); + } + my $fm = $hosts_fm->Frame(-background => $darkbg)->pack(-side => 'bottom'); + $fm->Button(@battr, + -command => sub {$hosts_tl->destroy}, + -text => 'ok')->pack(-side => 'left', -padx => 10, -pady => 20); + $fm->Button(@battr, + -command => sub {$preselected_host = undef; $hosts_tl->destroy}, + -text => 'cancel')->pack(-side => 'left', -padx => 10, -pady => 20); + $hosts_tl->update; + my ($X, $Y) = ($mw->rootx, $mw->rooty); + my ($w, $h) = ($hosts_tl->width, $hosts_tl->height); + my ($W, $H) = ($mw->width, $mw->height); + $x = $X + $W - $w if ($x + $w) > $X + $W; + $y = $Y + $H - $h if ($y + $h) > $Y + $H; + $hosts_tl->geometry('+'.$x.'+'.$y); + $hosts_tl->waitWindow(); + return $preselected_host; } # end hostsmenu diff --git a/src/IvyIO.pm b/src/IvyIO.pm index 8283a02..76dc968 100644 --- a/src/IvyIO.pm +++ b/src/IvyIO.pm @@ -2,19 +2,28 @@ package IvyIO; use strict; use Ivy; +use Carp; +use Tk; my $ivy; +my %appNameByhostAndPort = (); +my %diedApp = (); +my $pingcallback; # init an ivy bus sub init { - my ($appname, $bus, $conncb, $disconncb) = @_; + my ($appname, $bus, $conncb, $disconncb, $pingcb, $mw) = @_; Ivy->init(-loopMode => 'TK', -appName => $appname, -ivyBus => $bus, ); + + $pingcallback = $pingcb; + $ivy = Ivy->new(-statusFunc => sub {&_status($conncb, $disconncb, @_);}); $ivy->start; + $mw->repeat (3000 ,[\&sendPings]) if defined $pingcb; } # end init @@ -27,13 +36,17 @@ sub kill { sub _status { - my ($conncb, $disconncb, $ref_array_present, $ref_array_absent, - $ref_hash_present, $agent, $status, $host) = @_; - if ($status eq "new") { - &$conncb($agent, $host); - } elsif ($status eq "died") { - &$disconncb($agent, $host); - } + my ($conncb, $disconncb, $ref_array_present, $ref_array_absent, + $ref_hash_present, $agent, $status, $host) = @_; + #print "Status : @_\n"; + if ($status eq "new") { + &$conncb($agent, $host); + $appNameByhostAndPort{$host} = $agent; + delete $diedApp{$host}; + } elsif ($status eq "died") { + &$disconncb($agent, $host); + $diedApp{$host} = 1; + } } # end _status @@ -83,7 +96,7 @@ sub bind_for_play_event { my $cb = shift; return unless $cb; return unless $ivy; - $ivy->bindRegexp("ClockStart", [sub { shift; &$cb(); }]); + $ivy->bindRegexp("^ClockStart", [sub { shift; &$cb(); }]); } # end bind_for_play_event @@ -92,7 +105,7 @@ sub bind_for_pause_event { my $cb = shift; return unless $cb; return unless $ivy; - $ivy->bindRegexp("ClockStop", [sub { shift; &$cb(); }]); + $ivy->bindRegexp("^ClockStop", [sub { shift; &$cb(); }]); } # end bind_for_pause_event @@ -103,12 +116,45 @@ sub bind_for_clock_and_rate_event { my $cb = shift; return unless $cb; return unless $ivy; - $ivy->bindRegexp('ClockEvent Time=(\d\d):(\d\d):(\d\d) Rate=(.*) Bs=.*', + $ivy->bindRegexp('^ClockEvent Time=(\d\d):(\d\d):(\d\d) Rate=(.*) Bs=.*', [sub { shift; &$cb(@_); }]); - $ivy->bindRegexp('ClockDatas Time=(\d\d):(\d\d):(\d\d) Rate=(.*) Bs=.*', + $ivy->bindRegexp('^ClockDatas Time=(\d\d):(\d\d):(\d\d) Rate=(.*) Bs=.*', [sub { shift; &$cb(@_); }]); } # end bind_for_clock_event +# execute the callback kill all +sub bind_for_kill_all { + my $cb = shift; + return unless $cb; + return unless $ivy; + $ivy->bindRegexp('^IvyControlPanel KillAll', + [sub { shift; &$cb(); }]); + +} # end bind_for_clock_event + + +# send a ping to agent(s) +sub sendPings () +{ + my $appf; + foreach $appf (keys (%appNameByhostAndPort)) { + next if exists $diedApp{$appf}; + $ivy->ping ($appf, \&receivePongCb); + } +} # end sendPings + + +# received pong, Agent is notified with the ping/pong time value +sub receivePongCb($$) +{ + my ($time, $appf) = @_; # time = ping/pong duration in ms + + #printf ("DBG> :$received: $appf [$time]".$appNameByhostAndPort{$appf}."\n"); + &$pingcallback($appNameByhostAndPort{$appf}, $appf, $time); + +} # end receivePongCb + + 1; diff --git a/src/ivycontrolpanel b/src/ivycontrolpanel index e0214bd..0bbc4d4 100755 --- a/src/ivycontrolpanel +++ b/src/ivycontrolpanel @@ -9,10 +9,12 @@ use strict; use Carp; + # where you may find bitmap files use lib "/usr/share/ivycontrolpanel"; # where you may find the IvyIO and Agent modules use lib "/usr/lib/ivycontrolpanel"; +#use lib "."; # where you may find the FugueConfig module use lib "/usr/lib/ivylaunch"; @@ -42,6 +44,8 @@ use vars qw(%opt); # window size my $width = 1024; my $height = 768; +my $smallsized = 0; +my $coef = 1; # fonts spec my @fontspec34 = (-font => @@ -59,6 +63,8 @@ my $bg = '#5C5655'; my $hlbg = '#7CC452'; my $fg = '#FCFAFC'; my $selcolor = 'yellow'; +my $pbcolor = '#c9b900000000'; +my $pingThreshold = 20; # traffic rate spec my @rate = (-20..-1, -0.5, 0, 0.5, 1..20); @@ -77,6 +83,17 @@ my $settingtime; my $selectedtimelabel; my $ivylaunch_agent; +# ivy version +my $ivy_version = $Ivy::VERSION; +my $ivy_versionstring = "v$ivy_version"; +my $ivy_cvsrevision = 0; +if ($ivy_version =~ s/Revision: (.*)//) { + $ivy_version = $1; + $ivy_cvsrevision = 1; + $ivy_versionstring = "v$ivy_version (cvs revision)"; +} +my $newapi4_18 = 1 if (($ivy_cvsrevision == 1 and $ivy_version ge 1.40) or + ($ivy_cvsrevision == 0 and $ivy_version ge 4.18)); #--------------------------------------------------------------------------------- # @@ -84,26 +101,53 @@ my $ivylaunch_agent; # #--------------------------------------------------------------------------------- -&usage unless Getopt::Long::GetOptions(\%opt, 'b=s', 'nocursor', 'help'); -&usage if $opt{help}; +Getopt::Long::Configure('pass_through'); +&usage unless Getopt::Long::GetOptions(\%opt, 'b=s', 'nocursor', 'help', 'smallsize', + 'position=s','pingthreshold=s'); +&usage(1) if $opt{help}; my ($fuguefile) = @ARGV; + #--------------------------------------------------------------------------------- # -# init ivy +# build the mainwindow # #--------------------------------------------------------------------------------- +if ($opt{smallsize}) +{ + $width = 640; + $height = 480; + $smallsized = 1; + $coef = 0.620; + + @fontspec34 = (-font => + '-b&h-lucida-bold-r-normal-sans-20-140-100-100-p-127-iso8859-1'); + @fontspec20 = (-font => + '-b&h-lucida-bold-r-normal-sans-12-120-75-75-p-79-iso8859-1'); + @fontspec24 = (-font => + '-b&h-lucida-bold-i-normal-sans-15-150-100-100-p-216-iso8859-1'); + @fontspec17 = (-font => + '-adobe-helvetica-medium-r-normal--11-80-100-100-p-60-iso10646-1'); +} + +if ($opt{pingthreshold}) { + $pingThreshold = $opt{pingthreshold}; +} -IvyIO::init("ivycontrolpanel", $opt{b}, \&connected, \&disconnected); +my $mw = MainWindow->new (-bg => 'black'); #--------------------------------------------------------------------------------- # -# build the mainwindow +# init ivy # #--------------------------------------------------------------------------------- -my $mw = MainWindow->new (-bg => 'black'); +if ($newapi4_18) { + IvyIO::init("ivycontrolpanel", $opt{b}, \&connected, \&disconnected, \&pingcb, $mw); +} else { + IvyIO::init("ivycontrolpanel", $opt{b}, \&connected, \&disconnected, undef, $mw); +} if ($opt{nocursor}) { open(CURSOR, ">/tmp/cursor-ivybanner"); @@ -120,27 +164,27 @@ if ($opt{nocursor}) { } else { $mw->configure(-cursor => 'circle'); } -$mw->geometry ($width."x".$height."--0+0"); -$mw->title ('ivycontrolpanel'); +$mw->geometry ($width."x".$height.$opt{position}); +$mw->title ('ivycontrolpanel - Ivy '.$ivy_versionstring); $mw->client ('ivycontrolpanel'); $mw->resizable(0,0); # geometry variables -my $dxleft = 20; -my $dxright = 20; -my $dybot = 90; -my $dytop = 20; -my $ddy = 10; +my $dxleft = 20*$coef; +my $dxright = 20*$coef; +my $dybot = 90*$coef; +my $dytop = 20*$coef; +my $ddy = 10*$coef; my $y; my $x; my $btn_h = $dybot - 3*$ddy; my $btn_w = $btn_h; -my $fm_w = $btn_w + 10; -my $fm_h = $btn_h + 10; +my $fm_w = $btn_w + 10*$coef; +my $fm_h = $btn_h + 10*$coef; # widgets attributes my @frameattr = (-relief => 'flat', - -highlightthickness => 3, + -highlightthickness => 3*$coef, -highlightbackground => $hlbg, -highlightcolor => $hlbg, -height => $height - $dytop - $dybot, @@ -155,7 +199,7 @@ my @labelattr = (-width => 2, -height => 1, my @buttonattr = (@labelattr, -borderwidth => 1, -highlightbackground => $hlbg, - -highlightthickness => 3, + -highlightthickness => 3*$coef, -width => $btn_w, -height => $btn_h, -activebackground => $bg, -activeforeground => $fg); @@ -189,7 +233,7 @@ $fm1->Label(-borderwidth => 0, -text => ' [ Bus ] '.(($opt{b}) ? $opt{b} : 'default').' '. '[ File ] '.(($fuguefile) ? $fuguefile : 'none').' ', @fontspec17, - -foreground => $hlbg)->place(-x => $dxleft+20, -y => $dytop-10); + -foreground => $hlbg)->place(-x => $dxleft+20*$coef, -y => $dytop-10); # build traffic rate frame #--------------------------------------------------------------------------------- @@ -204,19 +248,19 @@ my $btn_prev = $fm1->Button(@buttonattr, -image => $prevbmp, )->place(-x => $x, -y => $y ); -$x += $btn_w + 15; +$x += $btn_w + 15*$coef; my $fm_lab = $fm1->Frame(@frameattr, -width => $fm_w, -height => $fm_h)->place(-x => $x, -y => $y); my $lab_rate = $fm_lab->Label(@labelattr, -anchor => 'center', - -text => 1)->place(-x => 7, -y => 10); + -text => 1)->place(-x => 7*$coef, -y => 10*$coef); -$x += $fm_w + 5; +$x += $fm_w + 5*$coef; my $btn_next = $fm1->Button(@buttonattr, -image => $nextbmp, )->place(-x => $x, -y => $y); -$x += $btn_w + 15; +$x += $btn_w + 15*$coef; &setloopcommand($btn_prev, \&decrease_rate); &setloopcommand($btn_next, \&increase_rate); @@ -231,19 +275,19 @@ $lab_rate->bind('', [sub { # build hour frame #--------------------------------------------------------------------------------- -$x += 90; +$x += 90*$coef; my $xi; # next/prev buttons my $btn_tprev = $fm1->Button(@buttonattr, -image => $prevbmp, - )->place(-x => $x-$fm_w-5, -y => $y + 80); + )->place(-x => $x-$fm_w-5, -y => $y + 80*$coef); my $fm_lab = $fm1->Frame(@frameattr, -width => 3*$fm_w, -height => $fm_h)->place(-x => $x, -y => $y); # separators -$xi = -13 ; +$xi = -13*$coef ; for (my $i=0; $i<2; $i++) { $xi += $fm_w; $fm_lab->Label(@labelattr, @@ -252,28 +296,28 @@ for (my $i=0; $i<2; $i++) { -text => ':')->place(-x => $xi, -y => $ddy); } # hour, minutes, seconds -$xi = 5; +$xi = 5*$coef; my $lab_hour = $fm_lab->Label(@labelattr, -anchor => 'center', -text => '00')->place(-x => $xi, -y => $ddy); $xi += $fm_w; my $lab_min = $fm_lab->Label(@labelattr, -anchor => 'center', - -text => '00')->place(-x => $xi, -y => 10); + -text => '00')->place(-x => $xi, -y => 10*$coef); $xi += $fm_w; my $lab_sec = $fm_lab->Label(@labelattr, -anchor => 'center', - -text => '00')->place(-x => $xi, -y => 10); + -text => '00')->place(-x => $xi, -y => 10*$coef); $lab_hour->bind('<1>', [\&settime, 0]); $lab_min->bind('<1>', [\&settime, 1]); $lab_sec->bind('<1>', [\&settime, 2]); -$x += 3*$fm_w + 10; +$x += 3*$fm_w + 10*$coef; my $btn_tnext = $fm1->Button(@buttonattr, -image => $nextbmp, - )->place(-x => $x-5, -y => $y + 80); + )->place(-x => $x-5, -y => $y + 80*$coef); @@ -289,7 +333,7 @@ IvyIO::bind_for_clock_and_rate_event(sub { # build traffic control frame #--------------------------------------------------------------------------------- -$x += 90; +$x += 90*$coef; my $playbmp = $mw->Bitmap('play', -file => Tk::findINC('play.bmp'), -background => $bg, -foreground => $hlbg); @@ -306,11 +350,11 @@ my $playbtn = $fm1->Button(@buttonattr, -image => $playbmp, )->place(-x => $x, -y => $y); -$x += $btn_w + 20; +$x += $btn_w + 20*$coef; my $pausebtn = $fm1->Button(@buttonattr, -image => $pausebmp, )->place(-x => $x, -y => $y ); -$x += $btn_w + 20; +$x += $btn_w + 20*$coef; $playbtn->configure(-command => \&play); @@ -332,8 +376,9 @@ $fm1->Button(@buttonattr, -image => $quitbmp, -command => \&quitdialogbox, )->place(-x => $x, -y => $y); -$x -= $fm_w + 10; +$x -= $fm_w + 10*$coef; +IvyIO::bind_for_kill_all(\&killandquit); #--------------------------------------------------------------------------------- # @@ -347,16 +392,16 @@ if ($fuguefile) { die "Cant' parse fugue config file $fuguefile\n" unless $code; } -my $x0 = $dxleft + 20; -my $y0 = $dytop + 25; -my $rmax = 10; +my $x0 = $dxleft + 20*$coef; +my $y0 = $dytop + 25*$coef; +my $rmax = 10*$coef; my $cmin = 2; my $wmax = ($width-2*$x0); -my $dy = 64; +my $dy = 64*$coef; my %hosts; -Agent->configure($mw, $bg, $fg, $selcolor, $hlbg, $darkbg, \@fontspec20, - $x0, $y0, $wmax, $dy, $cmin, $rmax, $opt{b}); +Agent->configure($mw, $bg, $fg, $selcolor, $pbcolor, $hlbg, $darkbg, \@fontspec20, + $x0, $y0, $wmax, $dy, $cmin, $rmax, $opt{b}, $coef, $pingThreshold); for (@fugueconfigdata) { next unless $_->[0] eq 'global' or $_->[0] eq 'local'; @@ -381,13 +426,19 @@ MainLoop; #================================================================================= sub usage { - print "Usage : ivycontrolpanel [-help] [-b ivybus] [-nocursor] [fugueconfigfile]\n"; + my $exitflag = shift; + print "Usage : ivycontrolpanel [-help] [-b ivybus] [-nocursor] [-smallsize]\n"; + print " [-pingthreshold threshold] [fugueconfigfile]\n"; print "\n"; print "Options :\n"; print " -b ivybus bus ivy\n"; - print " -nocursor hide mouse cursor\n"; + print " -nocursor hide mouse cursor\n"; + print " -smallsize display the app in 640x480 mode\n"; + print " -pingthreshold ms [def=20] set the ping threshold in ms for detecting\n"; + print " performance problems (requires Ivy >= 4.18)\n"; + print " -position position set the window position\n"; print "\n"; - exit 0; + exit 0 if $exitflag ; } # end usage @@ -395,8 +446,8 @@ sub usage { sub killandquit { Agent->killall; $mw->after(1500, sub { - Agent->kill('ivylaunch') if $ivylaunch_agent > 0; - &quit;}); + Agent->kill('ivylaunch') if $ivylaunch_agent > 0; + &quit;}); } # end killandquit @@ -439,7 +490,7 @@ sub quitdialogbox { $tl->title('ivycontrolpanel'); $tl->resizable(0, 0); my $fm = $tl->Frame(-background => $darkbg, - -highlightthickness => 3, + -highlightthickness => 3*$coef, -highlightbackground => $hlbg, )->pack(-side => 'top', -padx => 0, -pady => 0); my $fm1 = $fm->Frame(-background => $darkbg)->pack(-side => 'bottom'); @@ -455,24 +506,24 @@ sub quitdialogbox { -foreground => $fg, -borderwidth => 1, -highlightbackground => $hlbg, - -highlightthickness => 3, + -highlightthickness => 3*$coef, -height => 2, -activebackground => $bg, -activeforeground => $fg, @fontspec24); my $l = $fm->Label(@labelattr, -text => "kill all agents ?", - )->pack(-side => 'top', -padx => 20, -pady => 20, + )->pack(-side => 'top', -padx => 20*$coef, -pady => 20*$coef, -expand => 1, -fill => 'both'); $fm1->Button(@buttonattr, -text => 'yes', -command => sub { $l->configure(-text => $l->cget(-text)."...\nwait..."); &killandquit; }, - )->pack(-side => 'left', -padx => 20, -pady => 20, + )->pack(-side => 'left', -padx => 20*$coef, -pady => 20*$coef, -expand => 1, -fill => 'both'); $fm1->Button(@buttonattr, -text => 'cancel', -command => sub { $tl->destroy }, - )->pack(-side => 'left', -padx => 20, -pady => 20, + )->pack(-side => 'left', -padx => 20*$coef, -pady => 20*$coef, -expand => 1, -fill => 'both'); # placement at window center $tl->update; @@ -512,6 +563,16 @@ sub disconnected { } # end disconnected +# called when an ivy ping/pong +sub pingcb { + my ($agent, $host, $pingvalue) = @_; + if ($agent eq 'ivylaunch') { + $ivylaunch_agent++; + } elsif ($agent ne 'ivycontrolpanel') { + Agent->pingcb($agent, $host, $pingvalue); + } +} + #--------------------------------------------------------------------------------- # # Functions dedicated to play/pause buttons @@ -655,10 +716,10 @@ sub display_rate { $rate =~ s/\.0+$//; if (length($rate) > 2) { $lab_rate->configure(-width => 3, @fontspec24); - $lab_rate->place(-x => 5, -y => 15); + $lab_rate->place(-x => 5*$coef, -y => 15*$coef); } else { $lab_rate->configure(-width => 2, @fontspec34); - $lab_rate->place(-x => 7, -y => 10); + $lab_rate->place(-x => 7*$coef, -y => 10*$coef); } $lab_rate->configure(-text => $rate); if ($rate == 0 and $isplaying) { @@ -690,8 +751,8 @@ sub settime { if ($selectedtimelabel eq $lab) { $selectedtimelabel = undef; $lab->configure(-background => $bg, -foreground => $fg); - $btn_tprev->place(-y => $y + 80); - $btn_tnext->place(-y => $y + 80); + $btn_tprev->place(-y => $y + 80*$coef); + $btn_tnext->place(-y => $y + 80*$coef); &unsetloopcommand($btn_tprev); &unsetloopcommand($btn_tnext); my $time = $lab_hour->cget(-text).':'.$lab_min->cget(-text).':'. @@ -709,8 +770,8 @@ sub settime { } $lab->configure(-background => $fg, -foreground => $bg); unless (defined $selectedtimelabel) { - $btn_tprev->place(-y => $y - 80); - $btn_tnext->place(-y => $y - 80); + $btn_tprev->place(-y => $y - 80*$coef); + $btn_tnext->place(-y => $y - 80*$coef); } $selectedtimelabel = $lab; &setloopcommand($btn_tprev, sub {&decrease_time($lab, $field)}); @@ -758,24 +819,23 @@ sub display_time { } # end display_time - - =head1 NAME ivycontrolpanel - an interface for controlling ivy agents =head1 SYNOPSIS -ivycontrolpanel [-help] [-b bus] [-nocursor] [fugueconfigfile] +ivycontrolpanel [-help] [-b bus] [-nocursor] [-smallsize] [-position pos] [-pingthreshold ms] [fugueconfigfile] =head1 DESCRIPTION -ivycontrolpanel blabla. - -description des interactions de controle (vitesse, réglage de l'heure, -play/pause, sortie) +ivycontrolpanel displays agents detected on a given ivy bus. For each agent, a led indicates its status. By clicking on an active agent (or its led), you kill it (an ivy die message is sent to it). When ivycontrolpanel is associated with a Fugue configuration file, the agents referenced in this file can be restarted by the same way. These agents are recognizable by their larger led's border. -description du panneau agents. +At bottom of window, two areas are dedicated to a specific agent, the air traffic simulator Rejeu. At bottom left, you can adjust the traffic speed. At bottom center, you have a clock; when you click on one of time fields, two scrolling arrows appears which let you adjust time; validation is done by clicking on the last selected field. Near, play/pause buttons let you start or stop the traffic simulator. Then, at bottom right, the cross button will be used to kill all agents and quit. + +=head1 LISTENED MESSAGE + +listen to the message 'IvyControlPanel KillAll', to kill all the agent (like quit button). =head1 OPTIONS @@ -789,6 +849,18 @@ Specify the ivy bus. Hide mouse cursor (for touchscreen usage). +=item B<-smallsize> + +Set the window size to 640x480 pixels. + +=item B<-position> XOFF+YOFF + +Specify the window position. + +=item B<-pingthreshold> duration in ms + +Set the ping threshold for detecting performance problems. ivycontrolpanel periodically pings agents and compares the ping/pong duration with the given threshold. If duration exceeds it, the agent's led becomes blinking red. Default is 20 ms. Requires Ivy v4.18 or higher. + =back =head1 FILE FORMAT -- cgit v1.1