Serving Static Files in Drivers#
AFL-automation drivers can serve static files (HTML, CSS, JavaScript, images, etc.) through the API server’s web interface. This is useful for providing custom web interfaces, documentation, or any files that need to be accessible via HTTP.
How It Works#
When you define static directories in your driver class, the API server automatically creates HTTP routes to serve files from those directories. Files are served under the /static/ URL path.
Basic Usage#
To serve static files from your driver, define a class-level static_dirs dictionary that maps URL subpaths to filesystem directories:
from AFL.automation.APIServer.Driver import Driver
import pathlib
class MyDriver(Driver):
# Map URL subpaths to filesystem directories
static_dirs = {
'docs': '/path/to/my/documentation',
'assets': '/path/to/web/assets',
'data': pathlib.Path(__file__).parent / 'static_data'
}
def __init__(self, name="MyDriver"):
super().__init__(name)
# static_dirs are automatically collected and configured
With this configuration:
Files in /path/to/my/documentation/ are served at http://server:port/static/docs/filename
Files in /path/to/web/assets/ are served at http://server:port/static/assets/filename
Files in static_data/ directory are served at http://server:port/static/data/filename
Inheritance#
Static directories are inherited from parent classes and combined using the Method Resolution Order (MRO). This allows for modular composition of static assets:
class BaseDriver(Driver):
static_dirs = {
'common': '/shared/assets',
'docs': '/base/documentation'
}
class SpecializedDriver(BaseDriver):
static_dirs = {
'custom': '/specialized/assets',
'docs': '/specialized/documentation' # Overrides base docs
}
# SpecializedDriver will serve:
# /static/common/ -> /shared/assets
# /static/custom/ -> /specialized/assets
# /static/docs/ -> /specialized/documentation (overridden)
Example: Custom Web Interface#
Here’s a complete example of a driver that serves a custom web interface:
import pathlib
from AFL.automation.APIServer.Driver import Driver
class DataVisualizationDriver(Driver):
# Serve web interface files
static_dirs = {
'viewer': pathlib.Path(__file__).parent / 'web_interface',
'plots': pathlib.Path(__file__).parent / 'generated_plots'
}
def __init__(self, name="DataViz"):
super().__init__(name)
@queued(render_hint='html')
def view_dashboard(self):
"""Return HTML that loads the custom web interface"""
return '''
<iframe src="/static/viewer/dashboard.html"
width="100%" height="600px">
</iframe>
'''
Directory Structure#
For the above example, your directory structure might look like:
my_driver/
├── driver.py # Your driver class
├── web_interface/ # static_dirs['viewer']
│ ├── dashboard.html
│ ├── style.css
│ ├── app.js
│ └── lib/
│ └── charts.js
└── generated_plots/ # static_dirs['plots']
├── plot1.png
└── plot2.svg
Files would be accessible at:
http://server:port/static/viewer/dashboard.html
http://server:port/static/viewer/style.css
http://server:port/static/viewer/lib/charts.js
http://server:port/static/plots/plot1.png
Security Considerations#
Only files within the specified directories are served
Directory traversal attacks (e.g., ../../../etc/passwd) are prevented by Flask’s send_from_directory function
Consider the sensitivity of files you’re serving - they’ll be publicly accessible if the server is accessible
Use appropriate file permissions on the directories you’re serving
Best Practices#
Use relative paths: Use pathlib.Path(__file__).parent to make paths relative to your driver file
Organize logically: Group related files under meaningful subpath names
Version control: Include static assets in your driver’s version control
Documentation: Document what static endpoints your driver provides
Testing: Test that your static files are served correctly after server startup
Troubleshooting#
Files not being served
Verify the directory exists and contains files
Check file permissions are readable by the server process
Confirm the static_dirs dictionary is defined at the class level
Check server logs for any error messages
Wrong files being served
Check for inheritance conflicts if using multiple driver classes
Verify the correct directory paths in static_dirs
Remember that child classes override parent class mappings for the same subpath