cardstories part 2: webservice

The webservice implementation of the gameplay was debugged and completed. It is sometimes available and the design of the JQuery client was discussed.

game and handle

The webservice implementation was completed with the handle function to dispatch the incoming requests to the appropriate function implementing it:

    def handle(self, args):
        try:
            action = args['action'][0]
            if action in self.ACTIONS:
                d = getattr(self, action)(args)
                def error(reason):
                    if reason.type is UserWarning:
                        return {'error': reason.getErrorMessage()}
                    else:
                        return reason
                d.addErrback(error)
                return d
            else:
                raise UserWarning('action ' + action + ' is not among the allowed actions ' + ','.join(self.ACTIONS))
        except UserWarning, e:
            return defer.succeed({'error': e.args[0]})

It is surprisingly complex. The idea is that it catches all UserWarning exceptions and send them back to the caller as a JSON object of the form

{'error': 'the error message'}

while the other exceptions are not caught. However, UserWarning exceptions reach the handle function in two different ways:

  • within a deferred object if it happens within a deferred callback, either explicitly or implicitly because a function is decorated with a defer.inlineCallbacks
  • as a regular exception that must be caught

The game function was implemented to return the current state of a game. The information returned depends on the player_id argument. It will reveal the information known to the player and hide the informations from the other players.
Each function exposed by the webservice checks if the required arguments are provided with:

    @staticmethod
    def required(args, method, *keys):

primarily because it helps writing the tests for the handle function. At this stage, the rest of the code is very fragile.

client architecture

The JQuery client architecture has been discussed with Xavier Antoviaque on irc.freenode.net#farsides and the following directions will be followed:

  • the HTML will not be generated by the plugin
  • the metadata will be stored in the DOM instead of in a JavaScript object attached to $.cardstories
  • each game state will be implemented in a different plugin because it has a different behavior and user interface

A few lines were written in this direction and remain to be tested.

binding to nginx

When running the webservice for debug purposes:

root@cardstories:/var/www/cardstories# PYTHONPATH=.:etc/cardstories\
   twistd --nodaemon cardstories --port 4923 --db /tmp/cardstories.sqlite

it was made available from the outside by adding the following proxypass to the nginx running on the development machine:

        location /resource {
                proxy_pass   http://127.0.0.1:4923;
        }

style

A few stylistic improvements were suggested during a conversation on irc.freenode.net#python

  • the files were renamed to be valid python identifiers test_XXX instead of test-XXX
  • the trial command line is not used, python-coverage is used instead because it gives a more readable coverage report
  • the + between multiline strings have been removed in multiple places
  • where relevant generators were used instead of map / lambda

posting on the cardstories blog

An update about the work done yesterday was posted in the project blog. As suggested by Xavier Antoviaque, an update will be posted to keep track of the reports posted on dachary.org.