2 # Demo external plugin. Kinda pointless, since it's a perl script, but
3 # useful for testing or as an hint of how to write an external plugin in
8 print STDERR "externaldemo plugin running as pid $$\n";
17 # Used to build up RPC calls as they're read from stdin.
21 # Read stdin, a line at a time, until a whole RPC call is accumulated.
22 # Parse to XML::RPC object and return.
26 # Kinda hackish approach to parse a single XML RPC out of the
27 # accumulated input. Perl's RPC::XML library doesn't
28 # provide a better way to do it. Relies on calls always ending
29 # with a newline, which ikiwiki's protocol requires be true.
30 if ($accum =~ /^\s*(<\?xml\s.*?<\/(?:methodCall|methodResponse)>)\n(.*)/s) {
33 # Now parse the XML RPC.
34 my $r = RPC::XML::Parser->new->parse($1);
36 die "error: XML RPC parse failure $r";
46 # Handle an incoming XML RPC command.
51 if ($r->isa("RPC::XML::request")) {
53 my @args=map { $_->value } @{$r->args};
54 # Dispatch the requested function. This could be
55 # done with a switch statement on the name, or
56 # whatever. I'll use eval to call the function with
58 my $ret = eval $name.'(@args)';
61 # Now send the repsonse from the function back,
62 # followed by a newline.
63 my $resp=RPC::XML::response->new($ret);
64 $resp->serialize(\*STDOUT);
66 # stdout needs to be flushed here. If it isn't,
67 # things will deadlock. Perl flushes it
68 # automatically when $| is set.
71 elsif ($r->isa("RPC::XML::response")) {
72 die "protocol error; got a response when expecting a request";
77 # Make an XML RPC call and return the result.
81 my $req=RPC::XML::request->new($command, @params);
82 $req->serialize(\*STDOUT);
84 # stdout needs to be flushed here to prevent deadlock. Perl does it
85 # automatically when $| is set.
88 if ($r->isa("RPC::XML::response")) {
89 return $r->value->value;
92 die "protocol error; got a request when expecting a response";
96 # Now on with the actual plugin. Let's do a simple preprocessor plugin.
99 # The import function will be called by ikiwiki when the plugin is
100 # loaded. When it's imported, it needs to hook into the preprocessor
102 rpc_call("hook", type => "preprocess", id => "externaldemo", call => "preprocess");
104 # Here's an exmaple of how to access values in %IkiWiki::config.
105 print STDERR "url is set to: ".
106 rpc_call("getvar", "config", "url")."\n";
108 # Here's an example of how to inject an arbitrary function into
109 # ikiwiki, replacing a core function.
110 # Note use of automatic memoization.
111 rpc_call("inject", name => "IkiWiki::formattime",
112 call => "formattime", memoize => 1);
114 print STDERR "externaldemo plugin successfully imported\n";
118 # This function will be called when ikiwiki wants to preprocess
122 # Let's use IkiWiki's pagetitle function to turn the page name into
124 my $title=rpc_call("pagetitle", $params{page});
126 return "externaldemo plugin preprocessing on $title!";
130 print STDERR "externaldemo plugin's formattime called via RPC";
131 return scalar "formatted time: ".localtime(shift);
134 # Now all that's left to do is loop and handle each incoming RPC request.
135 while (rpc_handle()) { print STDERR "externaldemo plugin handled RPC request\n" }