User:Mr.Z-man/SVG/source
From MediaWiki.org
< User:Mr.Z-man | SVG
Source code and brief installation instructions
Contents |
[edit] Notes
[edit] Requirements
- A Unix-based system
- A sufficiently recent version of Inkscape (it must support the --shell command line option)
- Python with python-daemon
- A C compiler
- GLib
[edit] Installation
- Copy the 2 files below onto your server
- Change SOCK_LOCATION in both programs to a different location if desired
- Compile the C client program
- If GLib is installed through a package and gcc is used:
- gcc -o/path/to/compiled/program `pkg-config --cflags --libs glib-2.0` filename.c
- Set up the python program to run automatically (using cron or a similar utility)
- Add the following lines to LocalSettings.php
$wgSVGConverters['inkscape-daemon'] = '/path/to/compiled/program -z -w $width -f $input -e $output'; $wgSVGConverter = 'inkscape-daemon';
[edit] Caveats
- This is highly experimental and not recommended for a production server.
- The Python program does not automatically restart if it crashes for any reason.
[edit] Python server
import SocketServer import subprocess import os import stat import daemon SOCK_LOCATION = '/usr/tmp/ink.sock' def main(): try: server = InkscapeServer(SOCK_LOCATION, InkscapeRequestHandler) server.serve_forever(poll_interval=0.1) finally: os.remove(SOCK_LOCATION) class InkscapeServer(SocketServer.UnixStreamServer): def __init__(self, server_address, RequestHandlerClass): SocketServer.UnixStreamServer.__init__(self, server_address, RequestHandlerClass) self.proc = subprocess.Popen(['inkscape', '--shell'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE, stdin=subprocess.PIPE) readToEnd(self.proc.stdout) # version stuff os.chmod(server_address, stat.S_IRWXO|stat.S_IRWXG|stat.S_IRWXU) # chmod 777 /path/to/socket self.requestcount = 0 class InkscapeRequestHandler(SocketServer.StreamRequestHandler): def handle(self): args = self.rfile.readline() self.server.proc.stdin.write(args) ret = readToEnd(self.server.proc.stdout) self.wfile.write(ret) def finish(self): # Inkscape slowly leaks memory, if it leaks too much it gets /really/ slow self.server.requestcount += 1 if self.server.requestcount > 50 or self.server.proc.returncode is not None: # also check if inksccape crashed self.server.requestcount = 0 self.server.proc.terminate() self.server.proc = subprocess.Popen(['inkscape', '--shell'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE, stdin=subprocess.PIPE) readToEnd(self.server.proc.stdout) # Since Inkscape stays running, we never get an EOF def readToEnd(buf): ret = '' lastchar = '' while True: char = buf.readline(1) if char == '>' and lastchar == '\n': break ret += char lastchar = char return ret if __name__ == "__main__": with daemon.DaemonContext(): main()
[edit] C client
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/un.h> #include <glib.h> #define SOCK_LOCATION "/usr/tmp/ink.sock" int main ( int argc, char * argv[] ) { if (!argv[1]) { printf("No args given\n"); exit(1); } int sock, retval, len; char args[5000]; // These should probably use less-arbitrary numbers char ret[5000]; char *arg; int returncode = 0; int i=1; while(arg = argv[i]) { arg = g_shell_quote(arg); strncat(args, arg, strlen(arg)); strncat(args, " ", 1); i++; } strncat(args, "\n", 1); struct sockaddr_un remote; if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { printf("Socket error\n"); exit(1); } remote.sun_family = AF_UNIX; strcpy(remote.sun_path, SOCK_LOCATION); len = strlen(remote.sun_path) + sizeof(remote.sun_family); if (connect(sock, (struct sockaddr *)&remote, len) == -1) { printf("Unable to connect to socket\n"); exit(1); } if (send(sock, args, strlen(args)+1, 0) == -1) { printf("Error during sending of data\n"); exit(1); } if ( (retval=recv(sock, ret, 5000, 0)) > 0) { ret[retval] = '\0'; printf(ret); } else { if (retval < 0) { printf("Error during receiving of data\n"); } else { printf("Server closed connection\n"); } exit(1); } // If inkscape threw an error, set the returncode to 1. Inkscape errors // follow a fairly standard format: // ** (inkscape:PID): WARNING ** Error message if (strstr(ret, "\n**") != NULL) { returncode = 1; } return returncode; }