6
use IO::Socket::INET qw();
9
muse_emacs => '/usr/local/bin/emacs',
10
muse_init => '/stuff/proj/personal-site/ikiwiki/muse-init.el',
11
muse_shared_secret => 'foo',
14
my %MUSE_SERVER = ( host => 'localhost' );
19
# Determine the emacs binary to use
22
die "Unable to find your emacs binary.\n",
23
" Set muse_emacs config to the right value.\n";
25
if ( $config{muse_emacs} ) {
26
( -x $config{muse_emacs} ) ? return $config{muse_emacs} : $err->();
29
my $emacs = `which emacs`;
31
( $emacs ) ? return $emacs : $err->();
35
# Initialize connection to the Muse IPC server
36
sub start_muse_server {
37
my $secret = $config{muse_shared_secret};
38
my $init_port = $config{muse_init_port} || 0;
39
my $ipc_port = $config{muse_ipc_port};
41
# Perform sanity checks
42
$config{muse_init} or die "Error: muse_init config option not defined.\n";
44
# Start initialization server
45
my $pserver = IO::Socket::INET->new(
47
LocalAddr => 'localhost',
48
LocalPort => $init_port,
49
Listen => IO::Socket::INET::SOMAXCONN,
50
) or die "Error: Cannot begin initialization for the Muse IPC server.\n";
51
$pserver->autoflush(1);
52
$init_port = $pserver->sockport();
53
my $select = IO::Select->new($pserver);
56
defined(my $pid = fork()) or die "Error: Unable to fork.\n";
58
$MUSE_SERVER{pid} = $pid;
62
qw( -q --no-site-file -batch -l ), $config{muse_init},
63
qw( --eval ), "(muse-ikiwiki-start-server \"$init_port\"" .
64
( $ipc_port ? " \"$ipc_port\"" : '' ) . ")";
65
die "Error: Unable to exec emacs.\n";
68
my $emacs_port = undef;
72
while ( my @ready = $select->can_read() ) {
73
for my $client (@ready) {
74
if ($client == $pserver) {
75
my $new = $pserver->accept();
80
chomp $line if defined $line;
81
if ( defined $line && $line =~ m/^begin (.+)$/s &&
85
chomp $line if defined $line;
86
if ( defined $line && $line =~ m/^port (.+)$/s ) {
91
Error: Invalid response while initializing Muse IPC server.
96
print $client "nok\n" if $line;
97
$select->remove($client);
104
$MUSE_SERVER{port} = $emacs_port;
111
sub stop_muse_server {
114
if ( $MUSE_SERVER{pid} ) {
115
# Give Muse 3 seconds to stop, presuming that it has already
116
# been sent the "done" command via stop_muse_server.
117
local $SIG{ALRM} = sub {
118
kill 9, $MUSE_SERVER{pid};
123
print $sock "done\n";
125
waitpid($MUSE_SERVER{pid}, 0);
128
delete $MUSE_SERVER{pid};
131
print $sock "done\n";
136
sub kill_muse_server {
139
kill 9, $MUSE_SERVER{pid} if $MUSE_SERVER{pid};
144
my ( $sock, $err_msg ) = @_;
145
$err_msg = "Error: Command did not succeed on Muse IPC server.\n";
149
if ( $line ne 'ok' ) {
151
kill_muse_server $err_msg;
156
my $secret = $config{muse_shared_secret};
157
my $host = $MUSE_SERVER{host};
158
my $port = $MUSE_SERVER{port};
160
or kill_muse_server "Error: No Muse IPC server is active.\n";
162
# Start client connection
163
my $sock = IO::Socket::INET->new(
167
) or kill_muse_server "Error: Cannot connect to the Muse IPC server.\n";
171
print $sock "begin $secret\n";
173
"Error: Could not authenticate to the Muse IPC server.\n";
181
print $sock "name foobar\n";
183
"Error: Could not set name of page on Muse IPC server.\n";
189
print $sock "title quux\n";
191
"Error: Could not set title of page on Muse IPC server.\n";
195
print "Starting Muse server ...\n";
198
print "Got port $MUSE_SERVER{port}.\n";
199
my $sock = ipc_connect();
203
print "Shutting down ...\n";
204
stop_muse_server($sock);
205
print "Done shutting down.\n";