RFC for QGIS Server Python Plugins

Alessandro Pasotti (a.pasotti@itopen.it)

Goals

Not goals

Possible applications

Implementations

Two possibilities:

  1. 404 handler - Simplest, hack-ish but unobtrusive and FAST! and KISS and DRY and [place your favourite pattern here!]
  2. Observer - Full-featured but with a minimal overhead and will require an heavy refactoring of the existing request handling code

Standard flow

images/qgis-server-stdflow.png

404 handler

images/qgis-server-404flow.png

404 pros & cons

Pros

  • unobtrusive: just three lines of codes added to main loop
  • CGI-style plugins
  • Minimal overhead when FCGI starts
  • 0 (zero) overhead on core SERVICES: FAST!
  • re-use current Python Plugins loading mechanism
  • proof-of-concept simplest implementation done

Cons

  • no way to manipulate request and response generated from core services

Observer overview

Observer pattern: plugins will register themselves and listen to signals. Plugins will receive the request/response objects and they will be able to manipulate them:

Observer flowchart

images/qgis-server-signals-slots.png

Observer pros & cons

Pros

  • Provides all the possibilities to manipulate the request and response and extend QGIS Server

Cons

  • requires heavy refactoring of request handler --> request/repsponse handler
  • could introduce some (probably tiny) overhead even if there aren't any plugins installed/enabled

404 PoC Implementation Details

Example query string:

http://localhost/cgi-bin/qgis_mapserv.fcgi?SERVICE=HELLO&REQUEST=SayHello

404 PoC metadata

Python methods (static!) are invoked and their output is captured and passed on to FCGI

Plugins exposed SERVICE and REQUEST methods are listed in Plugin's metadata:

Example metadata:

service=HELLO
methods=GetCapabilities,GetOutput,RemoteConsole,SayHello

404 PoC methods

When all checks are done the plugin runs by calling the method in the REQUEST, the method receives:

The plugin (static) method has access to global python environment and can run arbitrary python commands, it can optionally return a content type string (the server defaults to text/plain).

The plugin CGI-style output is captured diverting stdout and stderr to a custom buffer which becomes the server response.

404 PoC example method

@staticmethod
def SayHello(project_path, parameters):
    """Just say something"""
    print "HelloServer"
    return 'text/plain'

Example response:

200 OK
Connection: close
Date: Thu, 04 Sep 2014 09:56:36 GMT
Server: Apache/2.4.7 (Ubuntu)
Vary: Accept-Encoding
Content-Length: 12
Content-Type: text/plain
Client-Date: Thu, 04 Sep 2014 09:56:36 GMT
Client-Peer: 127.0.0.1:80
Client-Response-Num: 1

HelloServer

Observer refactoring

images/qgis-server-refactoring.png

Observer current loop

The current main loop:

Observer refactoring

The new main loop:

Server iFace

Not sure about what should be exposed:

To GUI or not to GUI?

Should we use the same system for desktop and server plugins?

What is the (mostly) unique selling point of QGIS Server ?

GUI-based configuration of the map and the services!

A Server plugin can have (not must) a desktop interface aimed to configure itself

One-click install and deployment

Example(s)

An example plugin is available:

https://github.com/elpaso/qgis-helloserver

A running implementation of the sever plugins basic functionalities is available here:

https://github.com/elpaso/QGIS/tree/serverplugins

Local test:

http://qwc/cgi-bin/qgis_mapserv.cgi?SERVICE=HELLO&request=GetCapabilities http://qwc/cgi-bin/qgis_mapserv.cgi?SERVICE=HELLO&request=SayHello http://qwc/cgi-bin/qgis_mapserv.cgi?SERVICE=HELLO&request=RemoteConsole http://qwc/cgi-bin/qgis_mapserv.cgi?SERVICE=WPS&request=GetCapabilities

Restrictions

If the plugin has a Desktop interface it cannot usually access to user's QSettings, this means that plugins options have to be stored somewhere else in order to be accessible by the server side.