diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c418eb..c2538b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,12 @@ # Changelog -## [Unreleased][] - 2021-09-05 +## [Unreleased][] - 2021-09-06 -- Now logs to systemd journal. New dependency - `python3-systemd` +- **Logging**: logs to systemd journal when run from systemd, stderr + otherwise. +- New dependency `python3-systemd` - Fixed dependency order in systemd service +- Added `--verbose` argument ## [v0.3.0][] - 2021-08-19 @@ -22,9 +25,9 @@ ## [v0.1.0][] - 2021-06-19 -Initial version. At first, this was a shell script. Than it was converted -into a single python file that did just what the shell script used to do. -The shell script was not given a version. +Initial python version. At first, this was a shell script. Than it was +converted into a single python file that did just what the shell script +used to do. The shell script was not given a version. [unreleased]: https://git.disroot.org/pranav/naxalnet/compare/v0.3.0...HEAD [v0.3.0]: https://git.disroot.org/pranav/naxalnet/compare/v0.2.0...v0.3.0 diff --git a/naxalnet/__init__.py b/naxalnet/__init__.py index 15a69d5..b20beec 100644 --- a/naxalnet/__init__.py +++ b/naxalnet/__init__.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python3 - +# This file is part of naxalnet. # Copyright (C) 2021 The naxalnet Authors # This program is free software: you can redistribute it and/or modify @@ -36,4 +35,4 @@ See README.md for documentation. # # In case you forgot to change the version, skip the number # and put the next number in the next commit. -__version__ = "0.3.0a2.dev2" +__version__ = "0.3.0a2.dev3" diff --git a/naxalnet/__main__.py b/naxalnet/__main__.py index 70456a6..cde1430 100644 --- a/naxalnet/__main__.py +++ b/naxalnet/__main__.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python3 - +# This file is part of naxalnet. # Copyright (C) 2021 The naxalnet Authors # This program is free software: you can redistribute it and/or modify @@ -15,13 +14,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . + """ If called as python -m naxalnet, this file makes naxalnet run like it was called from the commandline. Try: python -m naxalnet --help """ -from naxalnet.scripts import here_be_dragons +from naxalnet.scripts import main if __name__ == "__main__": - here_be_dragons() + main() diff --git a/naxalnet/config.py b/naxalnet/config.py index 2c72b5f..f541cda 100644 --- a/naxalnet/config.py +++ b/naxalnet/config.py @@ -1,4 +1,18 @@ -#!/usr/bin/env python3 +# This file is part of naxalnet. +# Copyright (C) 2021 The naxalnet Authors + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ config.py diff --git a/naxalnet/daemon.py b/naxalnet/daemon.py new file mode 100644 index 0000000..9d539f5 --- /dev/null +++ b/naxalnet/daemon.py @@ -0,0 +1,59 @@ +# This file is part of naxalnet. +# Copyright (C) 2021 The naxalnet Authors + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +daemon.py +--------- + +The daemon part. This is currently under construction. +""" + +import logging +from naxalnet.iwd import IWD + + +class Daemon: + """implements the daemon part""" + + logger = logging.getLogger(__name__) + + def __init__(self): + iwd = IWD() + self.device_add_call = self.device_remove_call = None + + def on_device_add(self, callback): + """ + run the given callback with no arguments + every time a device is added + """ + self.device_add_call = callback + + def on_device_remove(self, callback): + """ + run the given callback with no arguments + every time a device is removed + """ + self.device_remove_call = callback + + def register_callbacks(self): + """ + register the callbacks with D-Bus + """ + + def start(self): + """ + start the daemon + """ diff --git a/naxalnet/default.py b/naxalnet/default.py index 798e386..74c8076 100644 --- a/naxalnet/default.py +++ b/naxalnet/default.py @@ -1,4 +1,18 @@ -#!/usr/bin/env python3 +# This file is part of naxalnet. +# Copyright (C) 2021 The naxalnet Authors + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ default.py diff --git a/naxalnet/iwd.py b/naxalnet/iwd.py index e85e990..19b87b5 100644 --- a/naxalnet/iwd.py +++ b/naxalnet/iwd.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python3 - +# This file is part of naxalnet. # Copyright (C) 2021 The naxalnet Authors # This program is free software: you can redistribute it and/or modify @@ -15,7 +14,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . - """ iwd.py ------ diff --git a/naxalnet/scripts.py b/naxalnet/scripts.py index 6b7a6d7..99ae572 100644 --- a/naxalnet/scripts.py +++ b/naxalnet/scripts.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python3 - +# This file is part of naxalnet. # Copyright (C) 2021 The naxalnet Authors # This program is free software: you can redistribute it and/or modify @@ -24,7 +23,7 @@ and doing the things this program is supposed to do. This file is named scripts.py because the original developer of this program could not think of a better name that suits this file. If you want to hack naxalnet, this is the right place to start. -When run from the commandline, the function here_be_dragons() is called. +When run from the commandline, the function main() is called. """ import sys @@ -40,93 +39,100 @@ from naxalnet.config import parse_args # from naxalnet.log import logger logger = logging.getLogger(__name__) +args = parse_args() -def copy_files(args): +def copy_files(): """ Copy networkd configs to volatile dir. The D-Bus API does not support creating new interfaces or linking to bridges. So we use config files. See man:systemd.network(5) """ + try: + logger.info("Copying network config files") + dest = Path(args.networkd_runtime_dir) + src = Path(args.networkd_config_dir) - logger.info("Copying network config files") - dest = Path(args.networkd_runtime_dir) - src = Path(args.networkd_config_dir) + # Create the volatile directory if it doesn't exist + dest.mkdir(parents=True, exist_ok=True) - # Create the volatile directory if it doesn't exist - dest.mkdir(parents=True, exist_ok=True) - - # Copy all files in src to dest - for i in src.iterdir(): - copy(i, dest) + # Copy all files in src to dest + for i in src.iterdir(): + copy(i, dest) + except PermissionError as error: + logger.error("Cannot copy file: %s", error) + sys.exit(3) -def setup_devices(args): +def setup_devices(): """ Setup wifi interfaces using iwd This function should be called every time an interface is connected or removed. - args should be what parse_args() returns """ - iwd = IWD() - devices = iwd.get_devices() - adhoc_devices = [] - ap_devices = [] + try: + iwd = IWD() + devices = iwd.get_devices() + adhoc_devices = [] + ap_devices = [] - # Find devices supporting ad-hoc and ap - for i in devices: - # For each device, check if its adapter supports - # ad-hoc or ap. Many adapters will support both, - # so we will prioritise ad-hoc over ap. - device = Device(i) - logger.debug("Found device %s", device.name) - adapter = Adapter(device.adapter) - if adapter.supports_mode("ad-hoc"): - logger.debug("The device %s can be used for ad-hoc", device.name) - adhoc_devices.append(i) - if adapter.supports_mode("ap"): - logger.debug("The device %s can be used for ap", device.name) - ap_devices.append(i) + # Find devices supporting ad-hoc and ap + for i in devices: + # For each device, check if its adapter supports + # ad-hoc or ap. Many adapters will support both, + # so we will prioritise ad-hoc over ap. + device = Device(i) + logger.debug("Found device %s", device.name) + adapter = Adapter(device.adapter) + if adapter.supports_mode("ad-hoc"): + logger.debug("The device %s can be used for ad-hoc", device.name) + adhoc_devices.append(i) + if adapter.supports_mode("ap"): + logger.debug("The device %s can be used for ap", device.name) + ap_devices.append(i) - if len(adhoc_devices) != 0: - # Start ad-hoc on first device supporting ad-hoc - adhoc_device = Device(adhoc_devices.pop()) - # The same device is likely to have ap support too. - # But we can't start ad-hoc and ap on the same interface. - # So we will remove adhoc_device from ap_devices if it exists there - if adhoc_device.name in ap_devices: - ap_devices.remove(adhoc_device.name) - logger.info("Starting mesh on %s", adhoc_device.name) - # Turn on adapter if it is off - # See issue #9 - adhoc_adapter = Adapter(adhoc_device.adapter) - if not adhoc_adapter.is_powered_on(): - logger.debug("Adapter %s is off. Turning on", adhoc_adapter.name) - adhoc_adapter.power_on() - adhoc_device.start_adhoc_open(args.adhoc_name) - # Start Access point if ap_device is not empty, - # ie, we have more devices - if len(ap_devices) != 0: - ap_device = Device(ap_devices.pop()) - logger.info("Starting WiFi Access Point on %s", ap_device.name) - logger.info("Use naxalnet --print-wifi to get password") - # Turn on adapter if it is off - # See issue #9 - ap_adapter = Adapter(ap_device.adapter) - if not ap_adapter.is_powered_on(): - logger.debug("Adapter %s is off. Turning on", ap_adapter.name) - ap_adapter.power_on() - ap_device.start_ap(args.ap_ssid, args.ap_passwd) + if len(adhoc_devices) != 0: + # Start ad-hoc on first device supporting ad-hoc + adhoc_device = Device(adhoc_devices.pop()) + # The same device is likely to have ap support too. + # But we can't start ad-hoc and ap on the same interface. + # So we will remove adhoc_device from ap_devices if it exists there + if adhoc_device.name in ap_devices: + ap_devices.remove(adhoc_device.name) + logger.info("Starting mesh on %s", adhoc_device.name) + # Turn on adapter if it is off + # See issue #9 + adhoc_adapter = Adapter(adhoc_device.adapter) + if not adhoc_adapter.is_powered_on(): + logger.debug("Adapter %s is off. Turning on", adhoc_adapter.name) + adhoc_adapter.power_on() + adhoc_device.start_adhoc_open(args.adhoc_name) + # Start Access point if ap_device is not empty, + # ie, we have more devices + if len(ap_devices) != 0: + ap_device = Device(ap_devices.pop()) + logger.info("Starting WiFi Access Point on %s", ap_device.name) + logger.info("Use naxalnet --print-wifi to get password") + # Turn on adapter if it is off + # See issue #9 + ap_adapter = Adapter(ap_device.adapter) + if not ap_adapter.is_powered_on(): + logger.debug("Adapter %s is off. Turning on", ap_adapter.name) + ap_adapter.power_on() + ap_device.start_ap(args.ap_ssid, args.ap_passwd) + else: + logger.info("Not setting up WiFi AP.") else: - logger.info("Not setting up WiFi AP.") - else: - logger.warning( - "No device found to setup mesh. Make sure a WiFi adapter is connected" - ) + logger.warning( + "No device found to setup mesh. Make sure a WiFi adapter is connected" + ) + except DBusError: + logger.exception("Error while communicating with iwd") + sys.exit(4) -def print_wifi(args): +def print_wifi(): """ Prints the name and password of the adhoc, and ap from the arguments @@ -141,14 +147,19 @@ def print_version(): print(__version__) -def here_be_dragons(): +def main(): """ This is where the magic happens! This function is run every time you execute naxalnet from the commandline """ - args = parse_args() + if args.print_wifi: + print_wifi() + sys.exit(0) + elif args.version: + print_version() + sys.exit(0) # --verbose if args.verbose >= 2: loglevel = logging.DEBUG @@ -164,23 +175,9 @@ def here_be_dragons(): else: logging.basicConfig(level=loglevel) - if args.print_wifi: - print_wifi(args) - sys.exit(0) - elif args.version: - print_version() - sys.exit(0) + copy_files() - try: - copy_files(args) - except PermissionError as error: - logger.error("Cannot copy file: %s", error) - sys.exit(3) + setup_devices() - try: - setup_devices(args) - except DBusError: - logger.exception("Error while communicating with iwd") - sys.exit(4) # naxalnet prints Bye if no errors occured logger.info("Bye") diff --git a/setup.cfg b/setup.cfg index df3c1e4..d06bda0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -27,7 +27,7 @@ install_requires = [options.entry_points] console_scripts = - naxalnet = naxalnet.scripts:here_be_dragons + naxalnet = naxalnet.scripts:main [options.data_files] lib/systemd/system =