Refactor PageNode class to improve page and file registration logic
- Consolidated page and file scanning methods to return lists of served pages and files. - Improved error handling in file reading operations. - Updated the announce loop to use a more efficient waiting mechanism. - Improved command-line argument handling for log level configuration.
This commit is contained in:
@@ -124,9 +124,10 @@ class PageNode:
|
|||||||
|
|
||||||
def register_pages(self):
|
def register_pages(self):
|
||||||
"""Scan pages directory and register request handlers for all .mu files."""
|
"""Scan pages directory and register request handlers for all .mu files."""
|
||||||
|
pages = self._scan_pages(self.pagespath)
|
||||||
|
|
||||||
with self._lock:
|
with self._lock:
|
||||||
self.servedpages = []
|
self.servedpages = pages
|
||||||
self._scan_pages(self.pagespath)
|
|
||||||
|
|
||||||
pagespath = Path(self.pagespath)
|
pagespath = Path(self.pagespath)
|
||||||
|
|
||||||
@@ -137,7 +138,7 @@ class PageNode:
|
|||||||
allow=RNS.Destination.ALLOW_ALL,
|
allow=RNS.Destination.ALLOW_ALL,
|
||||||
)
|
)
|
||||||
|
|
||||||
for full_path in self.servedpages:
|
for full_path in pages:
|
||||||
rel = full_path[len(str(pagespath)) :]
|
rel = full_path[len(str(pagespath)) :]
|
||||||
if not rel.startswith("/"):
|
if not rel.startswith("/"):
|
||||||
rel = "/" + rel
|
rel = "/" + rel
|
||||||
@@ -150,13 +151,14 @@ class PageNode:
|
|||||||
|
|
||||||
def register_files(self):
|
def register_files(self):
|
||||||
"""Scan files directory and register request handlers for all files."""
|
"""Scan files directory and register request handlers for all files."""
|
||||||
|
files = self._scan_files(self.filespath)
|
||||||
|
|
||||||
with self._lock:
|
with self._lock:
|
||||||
self.servedfiles = []
|
self.servedfiles = files
|
||||||
self._scan_files(self.filespath)
|
|
||||||
|
|
||||||
filespath = Path(self.filespath)
|
filespath = Path(self.filespath)
|
||||||
|
|
||||||
for full_path in self.servedfiles:
|
for full_path in files:
|
||||||
rel = full_path[len(str(filespath)) :]
|
rel = full_path[len(str(filespath)) :]
|
||||||
if not rel.startswith("/"):
|
if not rel.startswith("/"):
|
||||||
rel = "/" + rel
|
rel = "/" + rel
|
||||||
@@ -170,23 +172,31 @@ class PageNode:
|
|||||||
|
|
||||||
def _scan_pages(self, base):
|
def _scan_pages(self, base):
|
||||||
base_path = Path(base)
|
base_path = Path(base)
|
||||||
|
if not base_path.exists():
|
||||||
|
return []
|
||||||
|
served = []
|
||||||
for entry in base_path.iterdir():
|
for entry in base_path.iterdir():
|
||||||
if entry.name.startswith("."):
|
if entry.name.startswith("."):
|
||||||
continue
|
continue
|
||||||
if entry.is_dir():
|
if entry.is_dir():
|
||||||
self._scan_pages(str(entry))
|
served.extend(self._scan_pages(entry))
|
||||||
elif entry.is_file() and not entry.name.endswith(".allowed"):
|
elif entry.is_file() and not entry.name.endswith(".allowed"):
|
||||||
self.servedpages.append(str(entry))
|
served.append(str(entry))
|
||||||
|
return served
|
||||||
|
|
||||||
def _scan_files(self, base):
|
def _scan_files(self, base):
|
||||||
base_path = Path(base)
|
base_path = Path(base)
|
||||||
|
if not base_path.exists():
|
||||||
|
return []
|
||||||
|
served = []
|
||||||
for entry in base_path.iterdir():
|
for entry in base_path.iterdir():
|
||||||
if entry.name.startswith("."):
|
if entry.name.startswith("."):
|
||||||
continue
|
continue
|
||||||
if entry.is_dir():
|
if entry.is_dir():
|
||||||
self._scan_files(str(entry))
|
served.extend(self._scan_files(entry))
|
||||||
elif entry.is_file():
|
elif entry.is_file():
|
||||||
self.servedfiles.append(str(entry))
|
served.append(str(entry))
|
||||||
|
return served
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def serve_default_index(
|
def serve_default_index(
|
||||||
@@ -217,16 +227,21 @@ class PageNode:
|
|||||||
if not str(file_path).startswith(str(pagespath)):
|
if not str(file_path).startswith(str(pagespath)):
|
||||||
return DEFAULT_NOTALLOWED.encode("utf-8")
|
return DEFAULT_NOTALLOWED.encode("utf-8")
|
||||||
try:
|
try:
|
||||||
with file_path.open("rb") as _f:
|
with file_path.open("rb") as file_handle:
|
||||||
first_line = _f.readline()
|
first_line = file_handle.readline()
|
||||||
is_script = first_line.startswith(b"#!")
|
is_script = first_line.startswith(b"#!")
|
||||||
except Exception:
|
if not is_script:
|
||||||
is_script = False
|
file_handle.seek(0)
|
||||||
|
return file_handle.read()
|
||||||
|
except FileNotFoundError:
|
||||||
|
return DEFAULT_NOTALLOWED.encode("utf-8")
|
||||||
|
except OSError as err:
|
||||||
|
RNS.log(f"Error reading page {file_path}: {err}", RNS.LOG_ERROR)
|
||||||
|
return DEFAULT_NOTALLOWED.encode("utf-8")
|
||||||
|
|
||||||
if is_script and os.access(str(file_path), os.X_OK):
|
if is_script and os.access(str(file_path), os.X_OK):
|
||||||
try:
|
try:
|
||||||
env_map = {}
|
env_map = os.environ.copy()
|
||||||
if "PATH" in os.environ:
|
|
||||||
env_map["PATH"] = os.environ["PATH"]
|
|
||||||
if _link_id is not None:
|
if _link_id is not None:
|
||||||
env_map["link_id"] = RNS.hexrep(_link_id, delimit=False)
|
env_map["link_id"] = RNS.hexrep(_link_id, delimit=False)
|
||||||
if remote_identity is not None:
|
if remote_identity is not None:
|
||||||
@@ -249,8 +264,18 @@ class PageNode:
|
|||||||
return result.stdout
|
return result.stdout
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
RNS.log(f"Error executing script page: {e}", RNS.LOG_ERROR)
|
RNS.log(f"Error executing script page: {e}", RNS.LOG_ERROR)
|
||||||
with file_path.open("rb") as f:
|
try:
|
||||||
return f.read()
|
return self._read_file_bytes(file_path)
|
||||||
|
except FileNotFoundError:
|
||||||
|
return DEFAULT_NOTALLOWED.encode("utf-8")
|
||||||
|
except OSError as err:
|
||||||
|
RNS.log(f"Error reading page fallback {file_path}: {err}", RNS.LOG_ERROR)
|
||||||
|
return DEFAULT_NOTALLOWED.encode("utf-8")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _read_file_bytes(file_path):
|
||||||
|
with file_path.open("rb") as file_handle:
|
||||||
|
return file_handle.read()
|
||||||
|
|
||||||
def serve_file(
|
def serve_file(
|
||||||
self,
|
self,
|
||||||
@@ -278,15 +303,33 @@ class PageNode:
|
|||||||
"""Handle new link connections."""
|
"""Handle new link connections."""
|
||||||
|
|
||||||
def _announce_loop(self):
|
def _announce_loop(self):
|
||||||
|
interval_seconds = max(self.announce_interval, 0) * 60
|
||||||
try:
|
try:
|
||||||
while not self._stop_event.is_set():
|
while not self._stop_event.is_set():
|
||||||
if time.time() - self.last_announce > self.announce_interval * 60:
|
now = time.time()
|
||||||
|
if (
|
||||||
|
self.last_announce == 0
|
||||||
|
or now - self.last_announce >= interval_seconds
|
||||||
|
):
|
||||||
|
try:
|
||||||
if self.name:
|
if self.name:
|
||||||
self.destination.announce(app_data=self.name.encode("utf-8"))
|
self.destination.announce(
|
||||||
|
app_data=self.name.encode("utf-8"),
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.destination.announce()
|
self.destination.announce()
|
||||||
self.last_announce = time.time()
|
self.last_announce = time.time()
|
||||||
time.sleep(1)
|
except Exception as announce_error:
|
||||||
|
RNS.log(
|
||||||
|
f"Error during announce: {announce_error}", RNS.LOG_ERROR,
|
||||||
|
)
|
||||||
|
wait_time = max(
|
||||||
|
(self.last_announce + interval_seconds) - time.time()
|
||||||
|
if self.last_announce
|
||||||
|
else 0,
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
self._stop_event.wait(min(wait_time, 60))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
RNS.log(f"Error in announce loop: {e}", RNS.LOG_ERROR)
|
RNS.log(f"Error in announce loop: {e}", RNS.LOG_ERROR)
|
||||||
|
|
||||||
@@ -296,17 +339,37 @@ class PageNode:
|
|||||||
now = time.time()
|
now = time.time()
|
||||||
if (
|
if (
|
||||||
self.page_refresh_interval > 0
|
self.page_refresh_interval > 0
|
||||||
and now - self.last_page_refresh > self.page_refresh_interval
|
and now - self.last_page_refresh >= self.page_refresh_interval
|
||||||
):
|
):
|
||||||
self.register_pages()
|
self.register_pages()
|
||||||
self.last_page_refresh = now
|
self.last_page_refresh = time.time()
|
||||||
if (
|
if (
|
||||||
self.file_refresh_interval > 0
|
self.file_refresh_interval > 0
|
||||||
and now - self.last_file_refresh > self.file_refresh_interval
|
and now - self.last_file_refresh >= self.file_refresh_interval
|
||||||
):
|
):
|
||||||
self.register_files()
|
self.register_files()
|
||||||
self.last_file_refresh = now
|
self.last_file_refresh = time.time()
|
||||||
time.sleep(1)
|
|
||||||
|
wait_candidates = []
|
||||||
|
if self.page_refresh_interval > 0:
|
||||||
|
wait_candidates.append(
|
||||||
|
max(
|
||||||
|
(self.last_page_refresh + self.page_refresh_interval)
|
||||||
|
- time.time(),
|
||||||
|
0.5,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if self.file_refresh_interval > 0:
|
||||||
|
wait_candidates.append(
|
||||||
|
max(
|
||||||
|
(self.last_file_refresh + self.file_refresh_interval)
|
||||||
|
- time.time(),
|
||||||
|
0.5,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
wait_time = min(wait_candidates) if wait_candidates else 1.0
|
||||||
|
self._stop_event.wait(min(wait_time, 60))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
RNS.log(f"Error in refresh loop: {e}", RNS.LOG_ERROR)
|
RNS.log(f"Error in refresh loop: {e}", RNS.LOG_ERROR)
|
||||||
|
|
||||||
@@ -430,19 +493,40 @@ def main():
|
|||||||
files_dir = get_config_value(args.files_dir, str(Path.cwd() / "files"), "files-dir")
|
files_dir = get_config_value(args.files_dir, str(Path.cwd() / "files"), "files-dir")
|
||||||
node_name = get_config_value(args.node_name, None, "node-name")
|
node_name = get_config_value(args.node_name, None, "node-name")
|
||||||
announce_interval = get_config_value(
|
announce_interval = get_config_value(
|
||||||
args.announce_interval, 360, "announce-interval", int,
|
args.announce_interval,
|
||||||
|
360,
|
||||||
|
"announce-interval",
|
||||||
|
int,
|
||||||
)
|
)
|
||||||
identity_dir = get_config_value(
|
identity_dir = get_config_value(
|
||||||
args.identity_dir, str(Path.cwd() / "node-config"), "identity-dir",
|
args.identity_dir,
|
||||||
|
str(Path.cwd() / "node-config"),
|
||||||
|
"identity-dir",
|
||||||
)
|
)
|
||||||
page_refresh_interval = get_config_value(
|
page_refresh_interval = get_config_value(
|
||||||
args.page_refresh_interval, 0, "page-refresh-interval", int,
|
args.page_refresh_interval,
|
||||||
|
0,
|
||||||
|
"page-refresh-interval",
|
||||||
|
int,
|
||||||
)
|
)
|
||||||
file_refresh_interval = get_config_value(
|
file_refresh_interval = get_config_value(
|
||||||
args.file_refresh_interval, 0, "file-refresh-interval", int,
|
args.file_refresh_interval,
|
||||||
|
0,
|
||||||
|
"file-refresh-interval",
|
||||||
|
int,
|
||||||
)
|
)
|
||||||
log_level = get_config_value(args.log_level, "INFO", "log-level")
|
log_level = get_config_value(args.log_level, "INFO", "log-level")
|
||||||
|
|
||||||
|
# Set RNS log level based on command line argument
|
||||||
|
log_level_map = {
|
||||||
|
"CRITICAL": RNS.LOG_CRITICAL,
|
||||||
|
"ERROR": RNS.LOG_ERROR,
|
||||||
|
"WARNING": RNS.LOG_WARNING,
|
||||||
|
"INFO": RNS.LOG_INFO,
|
||||||
|
"DEBUG": RNS.LOG_DEBUG,
|
||||||
|
}
|
||||||
|
RNS.loglevel = log_level_map.get(log_level.upper(), RNS.LOG_INFO)
|
||||||
|
|
||||||
RNS.Reticulum(configpath)
|
RNS.Reticulum(configpath)
|
||||||
Path(identity_dir).mkdir(parents=True, exist_ok=True)
|
Path(identity_dir).mkdir(parents=True, exist_ok=True)
|
||||||
identity_file = Path(identity_dir) / "identity"
|
identity_file = Path(identity_dir) / "identity"
|
||||||
|
|||||||
Reference in New Issue
Block a user