Added link example
This commit is contained in:
		
							parent
							
								
									481d43ad72
								
							
						
					
					
						commit
						a9c4d0e78d
					
				
							
								
								
									
										232
									
								
								Examples/Link.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										232
									
								
								Examples/Link.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,232 @@ | ||||
| ########################################################## | ||||
| # This RNS example demonstrates how to set up a link to  # | ||||
| # a destination, and pass data back and forth over it.   # | ||||
| ########################################################## | ||||
| 
 | ||||
| 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_utilitites" | ||||
| 
 | ||||
| ########################################################## | ||||
| #### 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, "linkexample") | ||||
| 
 | ||||
| 	# We configure a function that will get called every time | ||||
| 	# a new client creates a link to this destination. | ||||
| 	server_destination.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 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.link_closed_callback(client_disconnected) | ||||
| 	link.packet_callback(server_packet_received) | ||||
| 	latest_client_link = link | ||||
| 
 | ||||
| def client_disconnected(link): | ||||
| 	RNS.log("Client disconnected") | ||||
| 
 | ||||
| def server_packet_received(message, packet): | ||||
| 	global latest_client_link | ||||
| 
 | ||||
| 	text = message.decode("utf-8") | ||||
| 	RNS.log("Received data on the link: "+text) | ||||
| 	 | ||||
| 	reply_text = "I got \""+text+"\" from you" | ||||
| 	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 | ||||
| 
 | ||||
| # This initialisation is executed when the users chooses | ||||
| # to run as a client | ||||
| def client(destination_hexhash, configpath): | ||||
| 	# 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) | ||||
| 
 | ||||
| 	# Check if we know a path to the destination | ||||
| 	if not RNS.Transport.hasPath(destination_hash): | ||||
| 		RNS.log("Destination is not yet known. Requesting path and waiting for announce to arrive...") | ||||
| 		RNS.Transport.requestPath(destination_hash) | ||||
| 		while not RNS.Transport.hasPath(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, "linkexample") | ||||
| 
 | ||||
| 	# 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.packet_callback(client_packet_received) | ||||
| 
 | ||||
| 	# We'll also set up functions to inform the | ||||
| 	# user when the link is established or closed | ||||
| 	link.link_established_callback(link_established) | ||||
| 	link.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: | ||||
| 		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") | ||||
| 			RNS.Packet(server_link, data).send() | ||||
| 
 | ||||
| # 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 | ||||
| 	server_link = link | ||||
| 
 | ||||
| 	# Inform the user that the server is | ||||
| 	# connected | ||||
| 	RNS.log("Link established with server, enter some text to send, or \"quit\" to quit") | ||||
| 
 | ||||
| # 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() | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user