Twisted Documentation: Using Application

# Using Application

## Motivation

What happens when you want to write a Twisted application? Well, if you come into Twisted thinking of it as a library, you may decide a useful way is to write a Python script. This Python script would probably take the following actions:

- Install the reactor you want (or skip this step if you want the default reactor).
- Perform initialization options -- open data files, start `reactor.callLater` loops, etc.
- Call `reactor.run()`
- Perform deinitalization options

There are two problems with this methodology. It has a lot of boiler-plate code, and it introduces an inflexibility into the design. The usual way to solve this kind of problem is to write configuration files, and it is no different in Twisted.

At this point, the standard thing to do would be to write a long, tedious and subtly wrong manual describing the configuration language. Rest assured, like every other project, Twisted has those. But the language is secondary, and will be described later -- more important are the configuration objects.

## Services, Persistence and Security, Oh My!

It is possible to think of any configuration language as a specially designed language to build a configuration object, which is then queried and acted upon by the program runtime. In Twisted, this is literally true internally -- and the master configuration object is `twisted.application.service.Application`. However, there is virtually nothing you can do with this object directly. This object is `Componentized` -- it has different, orthogonal, aspects. Access to this aspects is done by using interfaces. Interfaces, for our purposes, are just callables which return different aspects of the `Application`. Unlike other frameworks, like `Qt` or `wxWindows`, in Twisted you do not derive from `Application` -- you use methods to register your objects with it.

There are four interfaces supported, three of which are defined in `twisted.application.service`:

- `IService`
- `IServiceCollection`
- `IProcess`
- `twisted.persisted.sob.IPersistable`

Constructing an application is done by calling it with a single argument -- its name. The name influences some things, among them the default file it will persist to (which is why it is mandatory).

    from twisted.application import service
    from twisted.persisted import sob
    application = service.Application("myapplication")
    s = service.IService(application)
    sc = service.IServiceCollection(application)
    proc = service.IProcess(application)
    per = sob.IPersistable(application)

## Services

There are two interfaces relevant to services -- `IService` and `IServiceCollection`. `IService` represents a state-aware container. That means the service is ready to be notified of application start-ups and shutdowns. Services can be named or unnamed. `IServiceCollection` holds other services. It is possible to get named services from it by name. All services can be gotten from it via either indexing or iteration.

Services can have a parent. Parents are set using `setServiceParent`. Services are detached from their parent with `disownServiceParent`. The parent must always be something that complies with the `IServiceCollection` interface.

Most services will inherit from `Service`. This class will set an attribute `running` to a true value in `startService` and to a false value in `stopService`. This attribute will always be false in just-unpersisted `Service`s, without regards to its value at the time the `Service` was persisted.

`MultiService` implements both `IService` and `IServiceCollection`. It is used to keep the services in a hierarchy.

It is, of course, possible to write one's own services, but Twisted comes out of the box with several services which are useful in writing network applications. These are found in `twisted.application.internet`, including `TCPServer`, `TCPClient`, and `TimerService`.

To each `reactor.listenFoo` method corresponds a service named `FooServer`. The arguments to its constructor are the same as the arguments to the method. It calls the method on application start-up, and stops listening on application shut-down.

To each `reactor.connectFoo` methods corresponds a service named `FooClient`. The arguments to its constructor are the same as the arguments to the method. It calls the method on application start-up. It might, or might not, stop the connection on application shut-down. (This limitation will be removed at some point, and guaranteed disconnection will be implemented.)

The last service in `twisted.application.internet` is `TimerService`. The constructor takes a period, a callable and optionally arguments and keyword arguments. The service, when it is running, will make sure the callable will be called every time the period elapses.

## String Ports

In Twisted, a `ServerFactory` does not care what kind of virtual reliable circuit it listens too -- SSL, UNIX domain sockets, TCP sockets or something else. However, the APIs for constructing the various `*Server` classes are different. When it is necessary for a less sophisticated user to direct construction of such a class, the `twisted.application.strports` module comes in handy. It contains a function `service` which accepts a description and a factory, and returns a service. The description is a string in a mini-language designed to specify ports. Full specifications are in the module docstrings.

## Configuration

At some point, the objects for the configuration actually have to be constructed. The easiest and simplest way to do it is to use Python as the configuration mini-language. This format is called `TAC` and traditionally files with this format have the extension `.tac`.

TAC files need to be valid Python files, which construct a variable named `application`. This variable will be the configuration object. The full power of Python is available, of course.

Here's an example:

    # Import modules
    from twisted.application import service, internet
    from twisted.protocols import wire
    from twisted.internet import protocol

    # Construct the application
    application = service.Application("echo")

    # Get the IServiceCollection interface
    myService = service.IServiceCollection(application)

    # Create the protocol factory
    myFactory = protocol.ServerFactory()
    myFactory.protocol = wire.Echo

    # Create the (sole) server
    # Normally, the echo protocol lives on port 7, but since that
    # is a privileged port, for this example we'll use port 7001
    myServer = internet.TCPServer(7001, myFactory)

    # Tie the service to the application
    myServer.setServiceParent(myService)

Note that `setServiceParent` will, in fact, automatically cast its argument to `IServiceCollection`. So, more succinctly, the above code can be written:

    from twisted.application import service, internet
    from twisted.protocols import wire
    from twisted.internet import protocol
    application = service.Application("echo")
    myFactory = protocol.ServerFactory()
    myFactory.protocol = wire.Echo
    internet.TCPServer(7001, myFactory).setServiceParent(application)

TAC files are run with `twistd -y` or `twistd --python`. The `twistd` manpage has more information, but a common way to run is `twistd -noy echo.tac`. This tells `twistd` to not daemonize and not to try and save application on shutdown.

Index

Version: 1.3.0