commit c347d800ceee829faa92333a86624dd4237f08b1 Author: sigil-03 Date: Fri Dec 26 15:57:25 2025 -0700 initial rough-cut of fetcher code diff --git a/fetcher.py b/fetcher.py new file mode 100755 index 0000000..9c6216b --- /dev/null +++ b/fetcher.py @@ -0,0 +1,295 @@ +#!/bin/python + +import os +import io +import shutil +import argparse +import time +import RNS +# from io import BufferedReader +# import io +# import LXMF + + +# class Fetcher: +# # DEFAULT_PATH = "/page/index.mu" +# DEFAULT_TIMEOUT = 10 +# DEFAULT_CACHE_TIME = 12*60*60 + +# NO_PATH = 0x00 +# PATH_REQUESTED = 0x01 +# ESTABLISHING_LINK = 0x02 +# LINK_TIMEOUT = 0x03 +# LINK_ESTABLISHED = 0x04 +# REQUESTING = 0x05 +# REQUEST_SENT = 0x06 +# REQUEST_FAILED = 0x07 +# REQUEST_TIMEOUT = 0x08 +# RECEIVING_RESPONSE = 0x09 +# DISCONECTED = 0xFE +# DONE = 0xFF + + +# def retrieve_url(self, url, request_data = None): +# self.previous_destination_hash = self.destination_hash +# self.previous_path = self.path + +# destination_hash = None +# path = None + +# components = url.split(":") +# if len(components) == 1: +# if len(components[0]) == (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2: +# try: +# destination_hash = bytes.fromhex(components[0]) +# except Exception as e: +# raise ValueError("Malformed URL") +# # path = Browser.DEFAULT_PATH +# else: +# raise ValueError("Malformed URL") +# elif len(components) == 2: +# if len(components[0]) == (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2: +# try: +# destination_hash = bytes.fromhex(components[0]) +# except Exception as e: +# raise ValueError("Malformed URL") +# path = components[1] +# # if len(path) == 0: +# # path = Browser.DEFAULT_PATH +# else: +# if len(components[0]) == 0: +# if self.destination_hash != None: +# destination_hash = self.destination_hash +# path = components[1] +# if len(path) == 0: +# path = Browser.DEFAULT_PATH +# else: +# raise ValueError("Malformed URL") +# else: +# raise ValueError("Malformed URL") +# else: +# raise ValueError("Malformed URL") + +# if destination_hash != None and path != None: +# if path.startswith("/file/"): +# if destination_hash != self.loopback: +# if destination_hash == self.destination_hash: +# self.download_file(destination_hash, path) +# else: +# RNS.log("Cannot request file download from a node that is not currently connected.", RNS.LOG_ERROR) +# RNS.log("The requested URL was: "+str(url), RNS.LOG_ERROR) +# else: +# self.download_local_file(path) +# else: +# self.set_destination_hash(destination_hash) +# self.set_path(path) +# self.set_request_data(request_data) +# self.load_page() + +# def download_file(self, destination_hash, path): +# if self.link == None or self.link.destination.hash != self.destination_hash: +# if not RNS.Transport.has_path(self.destination_hash): +# self.status = Browser.NO_PATH +# self.update_display() + +# RNS.Transport.request_path(self.destination_hash) +# self.status = Browser.PATH_REQUESTED +# self.update_display() + +# pr_time = time.time()+RNS.Transport.first_hop_timeout(self.destination_hash) +# while not RNS.Transport.has_path(self.destination_hash): +# now = time.time() +# if now > pr_time+self.timeout: +# self.request_timeout() +# return + +# time.sleep(0.25) + +# self.status = Browser.ESTABLISHING_LINK +# self.update_display() + +# identity = RNS.Identity.recall(self.destination_hash) +# destination = RNS.Destination( +# identity, +# RNS.Destination.OUT, +# RNS.Destination.SINGLE, +# self.app_name, +# self.aspects +# ) + +# self.link = RNS.Link(destination, established_callback = self.link_established, closed_callback = self.link_closed) + +# while self.status == Browser.ESTABLISHING_LINK: +# time.sleep(0.1) + +# if self.status != Browser.LINK_ESTABLISHED: +# return + +# self.update_display() + +# if self.link != None and self.link.destination.hash == self.destination_hash: +# # Send the request +# self.status = Browser.REQUESTING +# self.response_progress = 0 +# self.response_speed = None +# self.progress_updated_at = None +# self.previous_progress = 0 +# self.response_size = None +# self.response_transfer_size = None +# self.saved_file_name = None + +# self.update_display() +# receipt = self.link.request( +# path, +# data = None, +# response_callback = self.file_received, +# failed_callback = self.request_failed, +# progress_callback = self.response_progressed +# ) + +# if receipt: +# self.last_request_receipt = receipt +# self.last_request_id = receipt.request_id +# self.status = Browser.REQUEST_SENT +# self.update_display() +# else: +# self.link.teardown() + +# global server link +server_link = None +file = None + +def link_established(link): + global server_link + server_link = link + print("link established") + +def link_closed(): + print("link closed") + +def file_received(request_receipt): + global file + file = True + try: + if type(request_receipt.response) == io.BufferedReader: + if request_receipt.metadata != None: + file_name = os.path.basename(request_receipt.metadata["name"].decode("utf-8")) + file_handle = request_receipt.response + file_destination = "."+"/"+file_name + + counter = 0 + while os.path.isfile(file_destination): + counter += 1 + file_destination = "."+"/"+file_name+"."+str(counter) + + shutil.move(file_handle.name, file_destination) + + else: + file_name = request_receipt.response[0] + file_data = request_receipt.response[1] + file_destination_name = os.path.basename(file_name) + file_destination = "."+"/"+file_destination_name + + counter = 0 + while os.path.isfile(file_destination): + counter += 1 + file_destination = "."+"/"+file_destination_name+"."+str(counter) + + fh = open(file_destination, "wb") + fh.write(file_data) + fh.close() + + # self.saved_file_name = file_destination.replace(self.app.downloads_path+"/", "", 1) + + # self.status = Browser.DONE + # self.response_progress = 0 + # self.response_speed = None + # self.progress_updated_at = None + # self.previous_progress = 0 + + # self.update_display() + except Exception as e: + RNS.log("An error occurred while handling file response. The contained exception was: "+str(e), RNS.LOG_ERROR) + + + print("file received") + +def request_failed(req_receipt): + print("request failed") + # print(str(e)) + +def response_progressed(req_receipt): + # print("response progressed") + return + +parser = argparse.ArgumentParser(description="request a resource from a target node") +parser.add_argument("URL", help="the LXMF URL of the resource to be fetched") + +args = parser.parse_args() +arglist = args.URL.split(":") +dest_hash = arglist[0] +resource_path = arglist[1] +print(dest_hash) +print(resource_path) + + +r = RNS.Reticulum() +RNS.loglevel = RNS.LOG_DEBUG +# router = LXMF.LXMRouter(storagepath="./tmp2") +# router.register_delivery_callback(delivery_callback) +ident = RNS.Identity() + +dest_hash = bytes.fromhex(dest_hash) +dest_ident = RNS.Identity.recall(dest_hash) + +# need these to connect to a nomadnetwork node +app_name = "nomadnetwork" +aspects = "node" + +destination = RNS.Destination( + dest_ident, + RNS.Destination.OUT, + RNS.Destination.SINGLE, + app_name, + aspects + ) + + +# with open(args.GCODE_FILE, "rb") as f: +# contents = f.read() +# content_size = len(contents) + +# Look up the path to the destination. +print("looking up path to destination...") +if not RNS.Transport.has_path(dest_hash): + RNS.Transport.request_path(dest_hash) + while not RNS.Transport.has_path(dest_hash): + time.sleep(0.1) + +# establish link +link = RNS.Link(destination, established_callback = link_established, closed_callback = link_closed) + + +while not server_link: + time.sleep(0.1) + +receipt = link.request( + resource_path, + data = None, + response_callback = file_received, + failed_callback = request_failed, + progress_callback = response_progressed +) + +while not file: + time.sleep(0.1) + +# if receipt: +# last_request_receipt = receipt +# last_request_id = receipt.request_id +# # status = Browser.REQUEST_SENT +# # update_display() +# else: +# link.teardown() + +# print(ident) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8592aec --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +rns +lxmf