diff --git a/docs/manual/_sources/examples.rst.txt b/docs/manual/_sources/examples.rst.txt
index 037ddbe..84018b9 100644
--- a/docs/manual/_sources/examples.rst.txt
+++ b/docs/manual/_sources/examples.rst.txt
@@ -68,6 +68,18 @@ destination, and passing traffic back and forth over the link.
This example can also be found at `
This example can also be found at https://github.com/markqvist/Reticulum/blob/master/Examples/Link.py.
+The Identify example explores identifying an intiator of a link, once +the link has been established.
+##########################################################
+# This RNS example demonstrates how to set up a link to #
+# a destination, and identify the initiator to it's peer #
+##########################################################
+
+import os
+import sys
+import time
+import argparse
+import RNS
+
+# Let's define an app name. We'll use this for all
+# destinations we create. Since this echo example
+# is part of a range of example utilities, we'll put
+# them all within the app namespace "example_utilities"
+APP_NAME = "example_utilities"
+
+##########################################################
+#### Server Part #########################################
+##########################################################
+
+# A reference to the latest client link that connected
+latest_client_link = None
+
+# This initialisation is executed when the users chooses
+# to run as a server
+def server(configpath):
+ # We must first initialise Reticulum
+ reticulum = RNS.Reticulum(configpath)
+
+ # Randomly create a new identity for our link example
+ server_identity = RNS.Identity()
+
+ # We create a destination that clients can connect to. We
+ # want clients to create links to this destination, so we
+ # need to create a "single" destination type.
+ server_destination = RNS.Destination(
+ server_identity,
+ RNS.Destination.IN,
+ RNS.Destination.SINGLE,
+ APP_NAME,
+ "identifyexample"
+ )
+
+ # We configure a function that will get called every time
+ # a new client creates a link to this destination.
+ server_destination.set_link_established_callback(client_connected)
+
+ # Everything's ready!
+ # Let's Wait for client requests or user input
+ server_loop(server_destination)
+
+def server_loop(destination):
+ # Let the user know that everything is ready
+ RNS.log(
+ "Link identification example "+
+ RNS.prettyhexrep(destination.hash)+
+ " running, waiting for a connection."
+ )
+
+ RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)")
+
+ # We enter a loop that runs until the users exits.
+ # If the user hits enter, we will announce our server
+ # destination on the network, which will let clients
+ # know how to create messages directed towards it.
+ while True:
+ entered = input()
+ destination.announce()
+ RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash))
+
+# When a client establishes a link to our server
+# destination, this function will be called with
+# a reference to the link.
+def client_connected(link):
+ global latest_client_link
+
+ RNS.log("Client connected")
+ link.set_link_closed_callback(client_disconnected)
+ link.set_packet_callback(server_packet_received)
+ link.set_remote_identified_callback(remote_identified)
+ latest_client_link = link
+
+def client_disconnected(link):
+ RNS.log("Client disconnected")
+
+def remote_identified(identity):
+ RNS.log("Remote identified as: "+str(identity))
+
+def server_packet_received(message, packet):
+ global latest_client_link
+
+ # Get the originating identity for display
+ remote_peer = "unidentified peer"
+ if packet.link.get_remote_identity() != None:
+ remote_peer = str(packet.link.get_remote_identity())
+
+ # When data is received over any active link,
+ # it will all be directed to the last client
+ # that connected.
+ text = message.decode("utf-8")
+
+ RNS.log("Received data from "+remote_peer+": "+text)
+
+ reply_text = "I received \""+text+"\" over the link from "+remote_peer
+ reply_data = reply_text.encode("utf-8")
+ RNS.Packet(latest_client_link, reply_data).send()
+
+
+##########################################################
+#### Client Part #########################################
+##########################################################
+
+# A reference to the server link
+server_link = None
+
+# A reference to the client identity
+client_identity = None
+
+# This initialisation is executed when the users chooses
+# to run as a client
+def client(destination_hexhash, configpath):
+ global client_identity
+ # We need a binary representation of the destination
+ # hash that was entered on the command line
+ try:
+ if len(destination_hexhash) != 20:
+ raise ValueError("Destination length is invalid, must be 20 hexadecimal characters (10 bytes)")
+ destination_hash = bytes.fromhex(destination_hexhash)
+ except:
+ RNS.log("Invalid destination entered. Check your input!\n")
+ exit()
+
+ # We must first initialise Reticulum
+ reticulum = RNS.Reticulum(configpath)
+
+ # Create a new client identity
+ client_identity = RNS.Identity()
+ RNS.log(
+ "Client created new identity "+
+ str(client_identity)
+ )
+
+ # Check if we know a path to the destination
+ if not RNS.Transport.has_path(destination_hash):
+ RNS.log("Destination is not yet known. Requesting path and waiting for announce to arrive...")
+ RNS.Transport.request_path(destination_hash)
+ while not RNS.Transport.has_path(destination_hash):
+ time.sleep(0.1)
+
+ # Recall the server identity
+ server_identity = RNS.Identity.recall(destination_hash)
+
+ # Inform the user that we'll begin connecting
+ RNS.log("Establishing link with server...")
+
+ # When the server identity is known, we set
+ # up a destination
+ server_destination = RNS.Destination(
+ server_identity,
+ RNS.Destination.OUT,
+ RNS.Destination.SINGLE,
+ APP_NAME,
+ "identifyexample"
+ )
+
+ # And create a link
+ link = RNS.Link(server_destination)
+
+ # We set a callback that will get executed
+ # every time a packet is received over the
+ # link
+ link.set_packet_callback(client_packet_received)
+
+ # We'll also set up functions to inform the
+ # user when the link is established or closed
+ link.set_link_established_callback(link_established)
+ link.set_link_closed_callback(link_closed)
+
+ # Everything is set up, so let's enter a loop
+ # for the user to interact with the example
+ client_loop()
+
+def client_loop():
+ global server_link
+
+ # Wait for the link to become active
+ while not server_link:
+ time.sleep(0.1)
+
+ should_quit = False
+ while not should_quit:
+ try:
+ print("> ", end=" ")
+ text = input()
+
+ # Check if we should quit the example
+ if text == "quit" or text == "q" or text == "exit":
+ should_quit = True
+ server_link.teardown()
+
+ # If not, send the entered text over the link
+ if text != "":
+ data = text.encode("utf-8")
+ if len(data) <= RNS.Link.MDU:
+ RNS.Packet(server_link, data).send()
+ else:
+ RNS.log(
+ "Cannot send this packet, the data size of "+
+ str(len(data))+" bytes exceeds the link packet MDU of "+
+ str(RNS.Link.MDU)+" bytes",
+ RNS.LOG_ERROR
+ )
+
+ except Exception as e:
+ RNS.log("Error while sending data over the link: "+str(e))
+ should_quit = True
+ server_link.teardown()
+
+# This function is called when a link
+# has been established with the server
+def link_established(link):
+ # We store a reference to the link
+ # instance for later use
+ global server_link, client_identity
+ server_link = link
+
+ # Inform the user that the server is
+ # connected
+ RNS.log("Link established with server, identifying to remote peer...")
+
+ link.identify(client_identity)
+
+# When a link is closed, we'll inform the
+# user, and exit the program
+def link_closed(link):
+ if link.teardown_reason == RNS.Link.TIMEOUT:
+ RNS.log("The link timed out, exiting now")
+ elif link.teardown_reason == RNS.Link.DESTINATION_CLOSED:
+ RNS.log("The link was closed by the server, exiting now")
+ else:
+ RNS.log("Link closed, exiting now")
+
+ RNS.Reticulum.exit_handler()
+ time.sleep(1.5)
+ os._exit(0)
+
+# When a packet is received over the link, we
+# simply print out the data.
+def client_packet_received(message, packet):
+ text = message.decode("utf-8")
+ RNS.log("Received data on the link: "+text)
+ print("> ", end=" ")
+ sys.stdout.flush()
+
+
+##########################################################
+#### Program Startup #####################################
+##########################################################
+
+# This part of the program runs at startup,
+# and parses input of from the user, and then
+# starts up the desired program mode.
+if __name__ == "__main__":
+ try:
+ parser = argparse.ArgumentParser(description="Simple link example")
+
+ parser.add_argument(
+ "-s",
+ "--server",
+ action="store_true",
+ help="wait for incoming link requests from clients"
+ )
+
+ parser.add_argument(
+ "--config",
+ action="store",
+ default=None,
+ help="path to alternative Reticulum config directory",
+ type=str
+ )
+
+ parser.add_argument(
+ "destination",
+ nargs="?",
+ default=None,
+ help="hexadecimal hash of the server destination",
+ type=str
+ )
+
+ args = parser.parse_args()
+
+ if args.config:
+ configarg = args.config
+ else:
+ configarg = None
+
+ if args.server:
+ server(configarg)
+ else:
+ if (args.destination == None):
+ print("")
+ parser.print_help()
+ print("")
+ else:
+ client(args.destination, configarg)
+
+ except KeyboardInterrupt:
+ print("")
+ exit()
+
This example can also be found at https://github.com/markqvist/Reticulum/blob/master/Examples/Identify.py.
+The Filetransfer example implements a basic file-server program that @@ -1667,6 +1985,7 @@ interface to efficiently pass files of any size over a Reticulum Broadcast
@@ -292,10 +296,12 @@ |
|