diff --git a/meshchatx/meshchat.py b/meshchatx/meshchat.py index 01c54b4..40648ab 100644 --- a/meshchatx/meshchat.py +++ b/meshchatx/meshchat.py @@ -556,6 +556,152 @@ class ReticulumMeshChat: raise RuntimeError("Database not initialized") return self.database.restore_database(backup_path) + def _ensure_reticulum_config(self): + """Ensures that a valid Reticulum config file exists at the expected location. + If the config is missing or invalid, it creates a sane default one. + """ + config_dir = self.reticulum_config_dir or RNS.Reticulum.configpath + config_file = os.path.join(config_dir, "config") + + should_recreate = False + + if not os.path.exists(config_file): + should_recreate = True + print( + f"Reticulum config file not found at {config_file}, creating a default one...", + ) + else: + try: + with open(config_file) as f: + content = f.read() + if "[reticulum]" not in content or "[interfaces]" not in content: + print( + f"Reticulum config file at {config_file} is invalid (missing essential sections), recreating...", + ) + should_recreate = True + except Exception as e: + print( + f"Failed to read Reticulum config at {config_file} ({e}), recreating...", + ) + should_recreate = True + + if should_recreate: + try: + if not os.path.exists(config_dir): + os.makedirs(config_dir, exist_ok=True) + + default_config = """# This is the default Reticulum config file. +# You should probably edit it to include any additional, +# interfaces and settings you might need. + +# Only the most basic options are included in this default +# configuration. To see a more verbose, and much longer, +# configuration example, you can run the command: +# rnsd --exampleconfig + + +[reticulum] + + # If you enable Transport, your system will route traffic + # for other peers, pass announces and serve path requests. + # This should only be done for systems that are suited to + # act as transport nodes, ie. if they are stationary and + # always-on. This directive is optional and can be removed + # for brevity. + + enable_transport = False + + + # By default, the first program to launch the Reticulum + # Network Stack will create a shared instance, that other + # programs can communicate with. Only the shared instance + # opens all the configured interfaces directly, and other + # local programs communicate with the shared instance over + # a local socket. This is completely transparent to the + # user, and should generally be turned on. This directive + # is optional and can be removed for brevity. + + share_instance = Yes + + + # If you want to run multiple *different* shared instances + # on the same system, you will need to specify different + # instance names for each. On platforms supporting domain + # sockets, this can be done with the instance_name option: + + instance_name = default + discover_interfaces = True + autoconnect_discovered_interfaces = 3 + required_discovery_value = 16 + +# Some platforms don't support domain sockets, and if that +# is the case, you can isolate different instances by +# specifying a unique set of ports for each: + +# shared_instance_port = 37428 +# instance_control_port = 37429 + + +# If you want to explicitly use TCP for shared instance +# communication, instead of domain sockets, this is also +# possible, by using the following option: + +# shared_instance_type = tcp + + +# You can configure Reticulum to panic and forcibly close +# if an unrecoverable interface error occurs, such as the +# hardware device for an interface disappearing. This is +# an optional directive, and can be left out for brevity. +# This behaviour is disabled by default. + +# panic_on_interface_error = No + + +[logging] + # Valid log levels are 0 through 7: + # 0: Log only critical information + # 1: Log errors and lower log levels + # 2: Log warnings and lower log levels + # 3: Log notices and lower log levels + # 4: Log info and lower (this is the default) + # 5: Verbose logging + # 6: Debug logging + # 7: Extreme logging + + loglevel = 4 + + +# The interfaces section defines the physical and virtual +# interfaces Reticulum will use to communicate on. This +# section will contain examples for a variety of interface +# types. You can modify these or use them as a basis for +# your own config, or simply remove the unused ones. + +[interfaces] + + # This interface enables communication with other + # link-local Reticulum nodes over UDP. It does not + # need any functional IP infrastructure like routers + # or DHCP servers, but will require that at least link- + # local IPv6 is enabled in your operating system, which + # should be enabled by default in almost any OS. See + # the Reticulum Manual for more configuration options. + + [[Default Interface]] + type = AutoInterface + enabled = false + name = Default Interface + selected_interface_mode = 1 +""" + with open(config_file, "w") as f: + f.write(default_config) + print(f"Default Reticulum config created at {config_file}") + except Exception as e: + print( + f"Failed to create default Reticulum config at {config_file}: {e}", + ) + def setup_identity(self, identity: RNS.Identity): identity_hash = identity.hash.hex() @@ -574,6 +720,7 @@ class ReticulumMeshChat: # Initialize Reticulum if not already done if not hasattr(self, "reticulum"): + self._ensure_reticulum_config() self.reticulum = RNS.Reticulum(self.reticulum_config_dir) # Create new context