memcached frontend

Evan Martin martine@danga.com
Thu, 14 Aug 2003 21:27:05 -0700


--=-uEQ7Wtut1OZsnnJ22Htq
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

Ignore that last mail... I hit the wrong button.

Once gzipped data starts showing up more often in the memcache (dear
Whitaker:  please send in your patch), using telnet to diagnose systems
using memcached starts getting even more difficult.

Attached is a GTK2/Perl (http://gtk2-perl.sf.net) client for memcached,
along with a screenshot of it in use.  It has a command history (up/down
arrows) and will automatically use Data::Dumper on references.

-- 
Evan Martin
martine@danga.com
http://neugierig.org

--=-uEQ7Wtut1OZsnnJ22Htq
Content-Disposition: attachment; filename=memcachedclient
Content-Type: text/x-perl; name=memcachedclient; charset=UTF-8
Content-Transfer-Encoding: 7bit

#!/usr/bin/perl
# vim: set ts=4 sw=4 et :

use strict;
use Gtk2;
use MemCachedClient;
use Data::Dumper;

$Data::Dumper::Terse = 1;

my @cmds = ();
my $cmd_cur = -1;

my $mc = new MemCachedClient {
    'servers' => [ "127.0.0.1:11211" ]
};

Gtk2->init;
my $win = Gtk2::Window->new("toplevel");
$win->signal_connect(delete_event => sub { Gtk2->main_quit });
$win->set_border_width(10);

my $vb = Gtk2::VBox->new(0, 5);
my $display = Gtk2::TextView->new;
my $buffer = $display->get_buffer;
$display->set_editable(0);
my $scroll = Gtk2::ScrolledWindow->new;
$scroll->set_policy('automatic', 'automatic');
$scroll->set_shadow_type('in');
$scroll->add($display);
$vb->pack_start($scroll, 1, 1, 0);

$display->modify_font(Gtk2::Pango::FontDescription->from_string("monospace"));
$buffer->create_tag("command", "foreground", "blue");
$buffer->create_tag("data");
$buffer->create_tag("error", "foreground", "red");

my $entry = Gtk2::Entry->new();
$entry->signal_connect(key_press_event => \&entry_keypress);
$entry->signal_connect(activate => \&entry_activate);
$vb->pack_start($entry, 0, 0, 0);

$win->add($vb);

$win->set_title("MemCachedClient");
$win->set_default_size(400, 500);
$win->signal_connect(show => sub { $entry->grab_focus });
$win->show_all;

Gtk2->main;

sub display {
    my ($level, $text) = @_;
    $buffer->insert_with_tags_by_name($buffer->get_end_iter, "$text\n", $level);
}

sub run_command {
    my ($text) = @_;
    
    # if we're rerunning a history command, then
    # we should pull it out of its old spot in the history.
    splice(@cmds, $cmd_cur, 1)
        if $cmd_cur >= 0 and $cmds[$cmd_cur] eq $text;
    # and in any case, add this command to the history.
    unshift(@cmds, $text);
    $cmd_cur = -1;

    display('command', $text);
    if ($text =~ /^get\s+(\S+)$/i) {
        my $str = $mc->get($1);
        if (ref $str) {
            $str = Dumper($str);
            $str =~ s/^        //gm;
        }
        if ($str) {
            display('data', $str);
        } else {
            display('error', "Not found.");
        }
    } elsif ($text =~ /^set\s+(\S+)\s+(.*)$/i) {
        my ($key, $val) = ($1, $2);
        if ($mc->set($key, $val)) {
            display('data', "Ok.");
        } else {
            display('error', "Not found.");
        }
    } elsif ($text =~ /^delete\s+(\S+)$/i) {
        $mc->delete($1);
        display('data', "Ok.");
    } else {
        display('error', "Unknown command '$text'.");
    }
}

sub entry_keypress {
    my ($entry, $ev) = @_;
    if ($ev->keyval == $Gtk2::Gdk::Keysyms{'Up'}) {
        $cmd_cur++ if $cmd_cur < @cmds-1;
        $entry->set_text($cmds[$cmd_cur]) if $cmds[$cmd_cur];
        return 1;
    } elsif ($ev->keyval == $Gtk2::Gdk::Keysyms{'Down'}) {
        $cmd_cur-- if $cmd_cur >= 0;
        if ($cmd_cur >= 0 and $cmds[$cmd_cur]) {
            $entry->set_text($cmds[$cmd_cur]);
        } else {
            $entry->set_text('');
        }
        return 1;
    }
    return 0;
}

sub entry_activate {
    my $text = $entry->get_text;
    if ($text =~ /\w/) {
        run_command($entry->get_text);
        $entry->set_text("");
    }
}


--=-uEQ7Wtut1OZsnnJ22Htq
Content-Disposition: attachment; filename=memcachedclient.png
Content-Type: image/png; name=memcachedclient.png
Content-Transfer-Encoding: base64

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
8X/aY2TBdNJepAAAAABJRU5ErkJggj==

--=-uEQ7Wtut1OZsnnJ22Htq--