2023-01-31 17:06:47 -05:00
import RNS
import LXMF
2023-02-03 16:09:28 -05:00
import os , time
from queue import Queue
import RNS . vendor . umsgpack as msgpack
2023-01-31 17:06:47 -05:00
2023-02-03 16:09:28 -05:00
display_name = " NomadNet Message Board "
2023-02-01 05:29:58 -05:00
max_messages = 20
2023-01-31 17:06:47 -05:00
def setup_lxmf ( ) :
if os . path . isfile ( identitypath ) :
identity = RNS . Identity . from_file ( identitypath )
RNS . log ( ' Loaded identity from file ' , RNS . LOG_INFO )
else :
RNS . log ( ' No Primary Identity file found, creating new... ' , RNS . LOG_INFO )
identity = RNS . Identity ( )
identity . to_file ( identitypath )
return identity
def lxmf_delivery ( message ) :
# Do something here with a received message
RNS . log ( " A message was received: " + str ( message . content . decode ( ' utf-8 ' ) ) )
message_content = message . content . decode ( ' utf-8 ' )
source_hash_text = RNS . hexrep ( message . source_hash , delimit = False )
2023-02-03 16:09:28 -05:00
#Create username (just first 5 char of your addr)
username = source_hash_text [ 0 : 5 ]
RNS . log ( ' Username: {} ' . format ( username ) , RNS . LOG_INFO )
time_string = time . strftime ( " % Y- % m- %d % H: % M: % S " , time . localtime ( message . timestamp ) )
new_message = ' {} {} : {} \n ' . format ( time_string , username , message_content )
# Push message to board
# First read message board (if it exists
if os . path . isfile ( boardpath ) :
f = open ( boardpath , " rb " )
message_board = msgpack . unpack ( f )
f . close ( )
2023-01-31 17:06:47 -05:00
else :
2023-02-03 16:09:28 -05:00
message_board = [ ]
2023-01-31 17:06:47 -05:00
2023-02-03 16:09:28 -05:00
#Check we aren't doubling up (this can sometimes happen if there is an error initially and it then gets fixed)
if new_message not in message_board :
# Append our new message to the list
message_board . append ( new_message )
2023-01-31 17:06:47 -05:00
2023-02-03 16:09:28 -05:00
# Prune the message board if needed
while len ( message_board ) > max_messages :
RNS . log ( ' Pruning Message Board ' )
message_board . pop ( 0 )
2023-01-31 17:06:47 -05:00
2023-02-03 16:09:28 -05:00
# Now open the board and write the updated list
f = open ( boardpath , " wb " )
msgpack . pack ( message_board , f )
f . close ( )
2023-01-31 17:06:47 -05:00
2023-02-03 16:09:28 -05:00
# Send reply
message_reply = ' {} _ {} _Your message has been added to the messageboard ' . format ( source_hash_text , time . time ( ) )
q . put ( message_reply )
2023-01-31 17:06:47 -05:00
def announce_now ( lxmf_destination ) :
lxmf_destination . announce ( )
def send_message ( destination_hash , message_content ) :
2023-02-01 05:29:58 -05:00
try :
# Make a binary destination hash from a hexadecimal string
destination_hash = bytes . fromhex ( destination_hash )
2023-01-31 17:06:47 -05:00
2023-02-01 05:29:58 -05:00
except Exception as e :
RNS . log ( " Invalid destination hash " , RNS . LOG_ERROR )
return
2023-01-31 17:06:47 -05:00
2023-02-01 05:29:58 -05:00
# Check that size is correct
if not len ( destination_hash ) == RNS . Reticulum . TRUNCATED_HASHLENGTH / / 8 :
RNS . log ( " Invalid destination hash length " , RNS . LOG_ERROR )
2023-01-31 17:06:47 -05:00
2023-02-01 05:29:58 -05:00
else :
# Length of address was correct, let's try to recall the
# corresponding Identity
destination_identity = RNS . Identity . recall ( destination_hash )
2023-01-31 17:06:47 -05:00
2023-02-01 05:29:58 -05:00
if destination_identity == None :
# No path/identity known, we'll have to abort or request one
RNS . log ( " Could not recall an Identity for the requested address. You have probably never received an announce from it. Try requesting a path from the network first. In fact, let ' s do this now :) " , RNS . LOG_ERROR )
RNS . Transport . request_path ( destination_hash )
RNS . log ( " OK, a path was requested. If the network knows a path, you will receive an announce with the Identity data shortly. " , RNS . LOG_INFO )
2023-01-31 17:06:47 -05:00
2023-02-01 05:29:58 -05:00
else :
# We know the identity for the destination hash, let's
# reconstruct a destination object.
lxmf_destination = RNS . Destination ( destination_identity , RNS . Destination . OUT , RNS . Destination . SINGLE , " lxmf " , " delivery " )
2023-01-31 17:06:47 -05:00
2023-02-01 05:29:58 -05:00
# Create a new message object
lxm = LXMF . LXMessage ( lxmf_destination , local_lxmf_destination , message_content , title = " Reply " , desired_method = LXMF . LXMessage . DIRECT )
2023-01-31 17:06:47 -05:00
2023-02-01 05:29:58 -05:00
# You can optionally tell LXMF to try to send the message
# as a propagated message if a direct link fails
lxm . try_propagation_on_fail = True
2023-01-31 17:06:47 -05:00
2023-02-01 05:29:58 -05:00
# Send it
message_router . handle_outbound ( lxm )
2023-01-31 17:06:47 -05:00
2023-02-01 05:06:14 -05:00
def announce_check ( ) :
2023-02-03 16:09:28 -05:00
if os . path . isfile ( announcepath ) :
f = open ( announcepath , " r " )
announce = int ( f . readline ( ) )
f . close ( )
else :
RNS . log ( ' failed to open announcepath ' , RNS . LOG_DEBUG )
announce = 1
if announce > int ( time . time ( ) ) :
2023-02-01 05:06:14 -05:00
RNS . log ( ' Recent announcement ' , RNS . LOG_DEBUG )
else :
2023-02-03 16:09:28 -05:00
f = open ( announcepath , " w " )
next_announce = int ( time . time ( ) ) + 1800
f . write ( str ( next_announce ) )
f . close ( )
2023-02-01 05:06:14 -05:00
announce_now ( local_lxmf_destination )
RNS . log ( ' Announcement sent, expr set 1800 seconds ' , RNS . LOG_INFO )
2023-01-31 17:06:47 -05:00
2023-02-03 16:09:28 -05:00
#Setup Paths and Config Files
userdir = os . path . expanduser ( " ~ " )
if os . path . isdir ( " /etc/nomadmb " ) and os . path . isfile ( " /etc/nomadmb/config " ) :
configdir = " /etc/nomadmb "
elif os . path . isdir ( userdir + " /.config/nomadmb " ) and os . path . isfile ( userdir + " /.config/nomadmb/config " ) :
configdir = userdir + " /.config/nomadmb "
else :
configdir = userdir + " /.nomadmb "
storagepath = configdir + " /storage "
if not os . path . isdir ( storagepath ) :
os . makedirs ( storagepath )
identitypath = configdir + " /storage/identity "
announcepath = configdir + " /storage/announce "
boardpath = configdir + " /storage/board "
# Message Queue
q = Queue ( maxsize = 5 )
2023-01-31 17:06:47 -05:00
# Start Reticulum and print out all the debug messages
2023-02-01 05:06:14 -05:00
reticulum = RNS . Reticulum ( loglevel = RNS . LOG_VERBOSE )
2023-01-31 17:06:47 -05:00
# Create a Identity.
current_identity = setup_lxmf ( )
# Init the LXMF router
message_router = LXMF . LXMRouter ( identity = current_identity , storagepath = configdir )
# Register a delivery destination (for yourself)
# In this example we use the same Identity as we used
# to instantiate the LXMF router. It could be a different one,
# but it can also just be the same, depending on what you want.
local_lxmf_destination = message_router . register_delivery_identity ( current_identity , display_name = display_name )
# Set a callback for when a message is received
message_router . register_delivery_callback ( lxmf_delivery )
# Announce node properties
RNS . log ( ' LXMF Router ready to receive on: {} ' . format ( RNS . prettyhexrep ( local_lxmf_destination . hash ) ) , RNS . LOG_INFO )
2023-02-01 05:06:14 -05:00
announce_check ( )
2023-01-31 17:06:47 -05:00
while True :
2023-02-03 16:09:28 -05:00
# Work through internal message queue
for i in list ( q . queue ) :
message_id = q . get ( )
split_message = message_id . split ( ' _ ' )
destination_hash = split_message [ 0 ]
message = split_message [ 2 ]
2023-01-31 17:06:47 -05:00
RNS . log ( ' {} {} ' . format ( destination_hash , message ) , RNS . LOG_INFO )
send_message ( destination_hash , message )
2023-02-01 05:06:14 -05:00
# Check whether we need to make another announcement
announce_check ( )
#Sleep
2023-01-31 17:06:47 -05:00
time . sleep ( 10 )