mirror of
https://github.com/craigerl/aprsd.git
synced 2026-01-09 01:48:40 -05:00
235 lines
7.5 KiB
ReStructuredText
235 lines
7.5 KiB
ReStructuredText
APRSD Extension Development
|
|
============================
|
|
|
|
APRSD extensions are more comprehensive than plugins and can add new functionality
|
|
to the APRSD daemon beyond simple command plugins. Extensions can include:
|
|
|
|
* New command-line commands
|
|
* Configuration options
|
|
* Background threads
|
|
* Statistics collectors
|
|
* Custom packet processors
|
|
* And more
|
|
|
|
Creating an Extension Project
|
|
-------------------------------
|
|
|
|
The recommended way to create a new APRSD extension project is to use the
|
|
`cookiecutter-aprsd-extension`_ template. This template provides a complete project
|
|
structure with all the necessary files, testing infrastructure, and documentation setup.
|
|
|
|
Installation
|
|
~~~~~~~~~~~~
|
|
|
|
First, install cookiecutter if you haven't already::
|
|
|
|
pip install cookiecutter
|
|
|
|
Creating a New Extension Project
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Run cookiecutter with the APRSD extension template::
|
|
|
|
cookiecutter gh:hemna/cookiecutter-aprsd-extension
|
|
|
|
Cookiecutter will prompt you for several pieces of information:
|
|
|
|
* **extension_name**: The name of your extension (e.g., ``aprsd-my-extension``)
|
|
* **extension_module_name**: The Python module name (e.g., ``aprsd_my_extension``)
|
|
* **author_name**: Your name or organization name
|
|
* **author_email**: Your email address
|
|
* **description**: A brief description of your extension
|
|
* **version**: Initial version (default: ``0.1.0``)
|
|
|
|
Project Structure
|
|
~~~~~~~~~~~~~~~~~
|
|
|
|
The cookiecutter template creates a complete project structure including:
|
|
|
|
* **Test automation** with Tox
|
|
* **Linting** with pre-commit and Flake8
|
|
* **Continuous integration** with GitHub Actions
|
|
* **Documentation** with Sphinx and Read the Docs
|
|
* **Automated uploads** to PyPI and TestPyPI
|
|
* **Automated dependency updates** with Dependabot
|
|
* **Code formatting** with Gray
|
|
* **Testing** with pytest
|
|
* **Code coverage** with Coverage.py
|
|
* **Coverage reporting** with Codecov
|
|
|
|
The generated project follows Python packaging best practices and includes:
|
|
|
|
* Proper ``setup.py`` and ``pyproject.toml`` configuration
|
|
* Entry point registration for APRSD extension discovery (``aprsd.extension``)
|
|
* Configuration entry points for oslo.config (``oslo.config.opts``)
|
|
* Test suite structure
|
|
* Documentation templates
|
|
* CI/CD pipeline configuration
|
|
|
|
Extension Registration
|
|
~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Extensions are registered using Python entry points in your ``pyproject.toml`` or
|
|
``setup.py`` file. The entry point group is ``aprsd.extension``::
|
|
|
|
[project.entry-points."aprsd.extension"]
|
|
"my_extension" = "aprsd_my_extension.extension"
|
|
|
|
Configuration Options
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Extensions can add their own configuration options using oslo.config. Register
|
|
your configuration options using the ``oslo.config.opts`` entry point::
|
|
|
|
[project.entry-points."oslo.config.opts"]
|
|
"aprsd_my_extension.conf" = "aprsd_my_extension.conf.opts:list_opts"
|
|
|
|
Example Extension Structure
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
A typical extension project structure looks like this::
|
|
|
|
aprsd-my-extension/
|
|
├── aprsd_my_extension/
|
|
│ ├── __init__.py
|
|
│ ├── extension.py # Main extension entry point
|
|
│ ├── cmds/ # Command-line commands
|
|
│ │ ├── __init__.py
|
|
│ │ └── show.py
|
|
│ ├── conf/ # Configuration options
|
|
│ │ ├── __init__.py
|
|
│ │ ├── opts.py
|
|
│ │ └── main.py
|
|
│ ├── threads/ # Background threads
|
|
│ │ ├── __init__.py
|
|
│ │ └── MyThread.py
|
|
│ └── stats.py # Statistics collectors
|
|
├── tests/
|
|
├── docs/
|
|
├── pyproject.toml
|
|
├── setup.py
|
|
└── README.md
|
|
|
|
Example Extension: WebChat
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
The `aprsd-webchat-extension`_ is a real-world example of an APRSD extension that
|
|
adds a web-based chat interface to APRSD. Let's examine how it's structured:
|
|
|
|
Entry Point Registration
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
In ``pyproject.toml``, the extension registers itself::
|
|
|
|
[project.entry-points."aprsd.extension"]
|
|
"webchat" = "aprsd_webchat_extension.extension"
|
|
|
|
[project.entry-points."oslo.config.opts"]
|
|
"aprsd_webchat_extension.conf" = "aprsd_webchat_extension.conf.opts:list_opts"
|
|
|
|
Extension Entry Point
|
|
^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
The ``extension.py`` file imports the command module to register it::
|
|
|
|
from aprsd_webchat_extension.cmds import webchat # noqa: F401
|
|
|
|
This import causes the command to be registered with APRSD's CLI system.
|
|
|
|
Command Implementation
|
|
^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
The webchat extension adds a new command ``aprsd webchat`` that starts a Flask-based
|
|
web server. The command is implemented in ``cmds/webchat.py`` and uses Click for
|
|
command-line interface::
|
|
|
|
import click
|
|
from aprsd.main import cli
|
|
|
|
@cli.command()
|
|
@click.option('--host', default='0.0.0.0', help='Host to bind to')
|
|
@click.option('--port', default=8080, help='Port to bind to')
|
|
def webchat(host, port):
|
|
"""Start the webchat interface."""
|
|
# Implementation here
|
|
pass
|
|
|
|
Configuration Options
|
|
^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
The extension adds configuration options through ``conf/opts.py``::
|
|
|
|
from oslo_config import cfg
|
|
|
|
webchat_group = cfg.OptGroup(name='webchat',
|
|
title='WebChat Options')
|
|
|
|
webchat_opts = [
|
|
cfg.StrOpt('host',
|
|
default='0.0.0.0',
|
|
help='WebChat server host'),
|
|
cfg.IntOpt('port',
|
|
default=8080,
|
|
help='WebChat server port'),
|
|
]
|
|
|
|
def list_opts():
|
|
return [
|
|
(webchat_group, webchat_opts),
|
|
]
|
|
|
|
The configuration can then be used in the extension code::
|
|
|
|
from oslo_config import cfg
|
|
|
|
CONF = cfg.CONF
|
|
host = CONF.webchat.host
|
|
port = CONF.webchat.port
|
|
|
|
Project Structure
|
|
^^^^^^^^^^^^^^^^^
|
|
|
|
The webchat extension has the following structure::
|
|
|
|
aprsd-webchat-extension/
|
|
├── aprsd_webchat_extension/
|
|
│ ├── __init__.py
|
|
│ ├── extension.py # Entry point that imports commands
|
|
│ ├── cmds/
|
|
│ │ ├── __init__.py
|
|
│ │ └── webchat.py # Command implementation
|
|
│ ├── conf/
|
|
│ │ ├── __init__.py
|
|
│ │ ├── opts.py # Configuration option definitions
|
|
│ │ └── main.py # Configuration group definitions
|
|
│ ├── web/ # Web assets (HTML, CSS, JS)
|
|
│ │ └── chat/
|
|
│ │ ├── static/
|
|
│ │ └── templates/
|
|
│ └── utils.py # Utility functions
|
|
├── tests/
|
|
├── docs/
|
|
├── pyproject.toml
|
|
└── README.md
|
|
|
|
Usage
|
|
^^^^^
|
|
|
|
Once installed, users can run the webchat command::
|
|
|
|
$ aprsd webchat --loglevel DEBUG
|
|
|
|
This demonstrates how extensions can add new functionality beyond simple plugins,
|
|
including web interfaces, background services, and complex integrations.
|
|
|
|
For more information about the cookiecutter template, visit the
|
|
`cookiecutter-aprsd-extension repository`_.
|
|
|
|
For the complete source code of the webchat extension, see the
|
|
`aprsd-webchat-extension repository`_.
|
|
|
|
.. _cookiecutter-aprsd-extension: https://github.com/hemna/cookiecutter-aprsd-extension
|
|
.. _cookiecutter-aprsd-extension repository: https://github.com/hemna/cookiecutter-aprsd-extension
|
|
.. _aprsd-webchat-extension: https://github.com/hemna/aprsd-webchat-extension
|
|
.. _aprsd-webchat-extension repository: https://github.com/hemna/aprsd-webchat-extension
|