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";