Contributions are welcome, preferably via pull request. Check the github issues and project roadmap to see what needs work, but Mara aims to include as much common generic functionality as is practical - so if you write something for your service which you think would be a good addition to contrib, please do send it in.
The easiest way to work on Mara is to fork the project on github, then install it to a virtualenv:
virtualenv mara cd mara source bin/activate pip install -e firstname.lastname@example.org:USERNAME/mara.git#egg=mara[full,dev]
USERNAME with your username).
This will also install all the dependencies you need for development and testing; you'll find the Mara source ready for you to work on in the
src folder of your virtualenv.
It is greatly appreciated when contributions come with unit tests.
To run the tests with debug data:
cd src/mara nosetests -s -vv
To run the tests without debug data:
python setup.py test
To run the tests and generate a coverage report:
The Mara tests are in the
tests folder; there are tests for each of the example services, as well as any fragile areas of the code which make more sense tested away from a server/client arrangement.
Mara is based around services, so start in
Service class is responsible for:
- collecting settings (work actually done by
- starting the server (in
- handling events (event classes are in
- timers (managed by the
- keeping track of its stores (a dict of
Storesubclasses, inheriting from
- starting a restart (in
Service.restart), serialising and deserialising the server and stores (in
Service.deserialise) and restoring the state after a restart (in
Mara does not use threads. When you call
service.run(), the service tells the
service.server to enter its main listen loop. This will run continually until
service.stop() is called as the result of an event (eg the
restart command). The server loops continually, checking all connected sockets for data to read; it uses
select to time this operation out after 100ms (by default), at which point it calls
service.poll(), which in turn runs any due/overdue timers.
select finds that there is a socket with data to read, it will pass it to a
Client instance (from
mara.connection.client). In raw socket mode this will immediately trigger a
Receive event; otherwise the client maintains an input buffer, parses the input for telnet negotiation commands, and when it has received a full line it will trigger a
The angel server (
Angel) and client (
Process) are defined in
mara.angel. When in angel mode, logging is passed up to the angel. The angel script in
bin/mara simply instantiates and runs the
Angel class; the
Process class is instantiated and used in
Lastly, anything which isn't classed as a core feature is defined in
mara.contrib. See the mara.contrib docs for more information.
Planned but not scheduled for a specific version:
More contrib modules:
- Items and inventory
- Combat (health, weapons and armour)
- Improved natural language processing tools
- SSH support
- Support for poll, epoll