(no commit message)
[ikiwiki] / doc / plugins / write / external.mdwn
1 External plugins are standalone, executable programs, that can be written
2 in any language. When ikiwiki starts up, it runs the program, and
3 communicates with it using [XML RPC][xmlrpc]. If you want to [[write]] an
4 external plugin, read on..
5
6 [xmlrpc]: http://www.xmlrpc.com/
7
8 ikiwiki contains one sample external plugin, named `externaldemo`. This is
9 written in perl, but is intended to be an example of how to write an
10 external plugin in your favorite programming language. Wow us at how much
11 easier you can do the same thing in your favorite language. ;-)
12
13 There's now a second external plugin, the [[rst]] plugin, written in
14 python. It uses a `proxy.py`, a helper library for ikiwiki python plugins.
15
16 [[!toc ]]
17
18 ## How external plugins use XML RPC
19
20 While XML RPC is typically used over http, ikiwiki doesn't do that.
21 Instead, the external plugin reads XML RPC data from stdin, and writes it
22 to stdout. To ease parsing, each separate XML RPC request or response must
23 start at the beginning of a line, and end with a newline. When outputting
24 XML RPC to stdout, be _sure_ to flush stdout. Failure to do so will result
25 in deadlock!
26
27 An external plugin should operate in a loop. First, read a command from
28 stdin, using XML RPC. Dispatch the command, and return its result to
29 stdout, also using XML RPC. After reading a command, and before returning
30 the result, the plugin can output XML RPC requests of its own, calling
31 functions in ikiwiki. Note: *Never* make an XML RPC request at any other
32 time. IkiWiki won't be listening for it, and you will deadlock.
33
34 When ikiwiki starts up an external plugin, the first RPC it will make
35 is to call the plugin's `import()` function. That function typically makes
36 an RPC to ikiwiki's `hook()` function, registering a callback.
37
38 An external plugin can use XML RPC to call any of the exported functions
39 documented in the [[plugin_interface_documentation|write]]. It can also
40 actually call any non-exported IkiWiki function, but doing so is a good way
41 to break your plugin when ikiwiki changes. There is currently no versioned
42 interface like there is for perl plugins, but external plugins were first
43 supported in ikiwiki version 2.6.
44
45 ## Accessing data structures
46
47 IkiWiki has a few global data structures such as `%config`, which holds
48 its configuration. External plugins can use the `getvar` and `setvar` RPCs
49 to access any such global hash. To get the "url" configuration value,
50 call `getvar("config", "url")`. To set it, call 
51 `setvar("config", "url", "http://example.com/)`.
52
53 The `%pagestate` is a special hash with a more complex format. To access
54 it, external plugins can use the `getstate` and `setstate` RPCs. To access
55 stored state, call `getstate("page", "id", "key")`, and to store state,
56 call `setstate("page", "id", "key", "value")`.
57
58 To access ikiwiki's ARGV array, call `getargv()`. To change its ARGV, call
59 `setargv(array)`.
60
61 ## Notes on function parameters
62
63 The [[plugin_interface_documentation|write]] talks about functions that take
64 "named parameters". When such a function is called over XML RPC, such named
65 parameters look like a list of keys and values:
66
67         page, foo, destpage, bar, magnify, 1
68
69 If a name is repeated in the list, the later value overrides the earlier
70 one:
71
72         name, Bob, age, 20, name, Sally, gender, female
73
74 In perl, boiling this down to an associative array of named parameters is
75 very easy:
76
77         sub foo {
78                 my %params=@list;
79
80 Other languages might not find it so easy. If not, it might be a good idea
81 to convert these named parameters into something more natural for the
82 language as part of their XML RPC interface.
83
84 ## undef
85
86 XML RPC has a limitation that it does not have a way to pass
87 undef/NULL/None. There is an extension to the protocol that supports this,
88 but it is not yet available in all versions of the [[!cpan XML::RPC]] library
89 used by ikiwiki.
90
91 Until the extension is available, ikiwiki allows undef to be communicated
92 over XML RPC by passing a sentinal value, a hash with a single key "null"
93 with a value of an empty string. External plugins that need to communicate
94 null values to or from ikiwiki will have to translate between undef and
95 the sentinal.
96
97 ## Function injection
98
99 Some parts of ikiwiki are extensible by adding or overriding functions.
100 It's actually possible to do this from an external plugin too. 
101
102 To make your external plugin override the `IkiWiki::formattime` function, for
103 example, make an RPC call to `inject`. Pass it named parameters "name" and
104 "call", where "name" is the name of the function to inject into perl (here
105 "Ikiwiki::formattime" and "call" is the RPC call ikiwiki will make whenever
106 that function is run.
107
108 If the RPC call is memoizable, you can also pass a "memoize" parameter, set
109 to 1.
110
111 ## Limitations of XML RPC
112
113 Since XML RPC can't pass around references to objects, it can't be used
114 with functions that take or return such references. That means you can't
115 100% use XML RPC for `cgi` or `formbuilder` hooks (which are passed CGI and
116 FormBuilder perl objects), or use it to call `template()` (which returns a
117 perl HTML::Template object).
118
119 ## Performance issues
120
121 Since each external plugin is a separate process, when ikiwiki is
122 configured to use lots of external plugins, it will start up slower, and
123 use more resources. One or two should not be a problem though.
124
125 There is some overhead in using XML RPC for function calls. Most plugins
126 should find it to be pretty minimal though. In one benchmark, ikiwiki was
127 able to perform 10000 simple XML RPC calls in 11 seconds -- 900 per second.
128
129 Using external plugins for hooks such as `sanitize` and `format`, which
130 pass around entire pages, and are run for each page rendered, will cause
131 more XML RPC overhead than usual, due to the larger number of calls, and the
132 large quantity of data conversion going on. In contrast, `preprocess` hooks
133 are called generally rarely, and pass around minimal data.
134
135 External plugins should avoid making RPC calls unnecessarily (ie, in a loop).
136 Memoizing the results of appropriate RPC calls is one good way to minimize the
137 number of calls.
138
139 Injecting a replacement for a commonly called ikiwiki function
140 could result in a lot more RPC calls than expected and slow
141 everything down. `pagetitle`, for instance, is called about 100 times
142 per page build. Whenever possible, you should tell ikiwiki to memoize
143 injected functions.
144
145 In general, use common sense, and your external plugin will probably
146 perform ok.