From f30399f04f00334b29173817eeb2c6f04190e48d Mon Sep 17 00:00:00 2001 From: chengtripp <124098378+chengtripp@users.noreply.github.com> Date: Fri, 3 Feb 2023 21:06:52 +0000 Subject: [PATCH 1/3] removed redis dependency, now uses umsgpack --- pages/message_board.mu | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/pages/message_board.mu b/pages/message_board.mu index 47d1da2..a79fc04 100644 --- a/pages/message_board.mu +++ b/pages/message_board.mu @@ -1,21 +1,41 @@ #!/bin/python3 import time -import redis -r = redis.Redis(db=2, decode_responses=True) +import os +import RNS.vendor.umsgpack as msgpack -print('`!`F222`Bddd`cSolarExpress Message Board') +message_board_peer = 'b4812e4f193420b1763f8f5fa31fbc29' +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) + +boardpath = configdir+"/storage/board" + +print('`!`F222`Bddd`cNomadNet Message Board') print('-') print('`a`b`f') print("") -print("To add a message to the board just converse with the SolarExpress Message Board at , peers are assigned a unique username") -print("Built with Python and Redis") +print("To add a message to the board just converse with the NomadNet Message Board at `[lxmf@{}]".format(message_board_peer)) time_string = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())) print("Last Updated: {}".format(time_string)) print("") print('>Messages') print(" Date Time Username Message") -for i in range(0, r.llen('message_board_general')): - message_content = r.lindex('message_board_general', i) - print("`a{}".format(message_content)) +f = open(boardpath, "rb") +board_contents = msgpack.unpack(f) +board_contents.reverse() + +for content in board_contents: + print("`a{}".format(content.rstrip())) print("") + +f.close() From 3ae39e811b81000c1faeaf6269e321251cf98559 Mon Sep 17 00:00:00 2001 From: chengtripp <124098378+chengtripp@users.noreply.github.com> Date: Fri, 3 Feb 2023 21:09:28 +0000 Subject: [PATCH 2/3] Removed dependencies, use internal queues, tidy up * Removed need for redis, instead uses umsgpack and flat files similar to reticulum and nomad net * Uses internal queue for the message queue * Announcements are tracked in file rather than redis * Uses its own config folder `nomadmb`, code inspired by NomadNet --- messageboard.py | 116 ++++++++++++++++++++++++++++++------------------ 1 file changed, 74 insertions(+), 42 deletions(-) diff --git a/messageboard.py b/messageboard.py index 2bd0a14..9fc981f 100644 --- a/messageboard.py +++ b/messageboard.py @@ -1,18 +1,12 @@ import RNS import LXMF -import os -import redis -import shortuuid -import time +import os, time +from queue import Queue +import RNS.vendor.umsgpack as msgpack -display_name = "SolarExpress Message Board" -configdir = os.getcwd() -identitypath = configdir+"/storage/identity" -redis_db = 2 +display_name = "NomadNet Message Board" max_messages = 20 -r = redis.Redis(db=redis_db, decode_responses=True) - def setup_lxmf(): if os.path.isfile(identitypath): identity = RNS.Identity.from_file(identitypath) @@ -29,29 +23,43 @@ def lxmf_delivery(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) - if r.exists(source_hash_text): - uuid_user = r.get(source_hash_text) - else: - RNS.log('Generate new username', RNS.LOG_INFO) - uuid_user = shortuuid.ShortUUID().random(length=12) - r.set(source_hash_text, uuid_user) + #Create username (just first 5 char of your addr) + username = source_hash_text[0:5] - message_id = '{}_{}'.format(source_hash_text, time.time()) - r.set(message_id, 'Hi, your unique username is {}, this is linked to your nomad address'.format(uuid_user)) - r.lpush('message_queue', message_id) - - RNS.log('UUID: {}'.format(uuid_user), RNS.LOG_INFO) + RNS.log('Username: {}'.format(username), RNS.LOG_INFO) time_string = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(message.timestamp)) - new_message = '{} {}: {}'.format(time_string, uuid_user, message_content) - r.lpush('message_board_general', new_message) + new_message = '{} {}: {}\n'.format(time_string, username, message_content) - message_id = '{}_{}'.format(source_hash_text, time.time()) - r.set(message_id, 'Your message has been added to the messageboard') - r.lpush('message_queue', message_id) + # 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() + else: + message_board = [] + + #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) + + # Prune the message board if needed + while len(message_board) > max_messages: + RNS.log('Pruning Message Board') + message_board.pop(0) + + # Now open the board and write the updated list + f = open(boardpath, "wb") + msgpack.pack(message_board, f) + f.close() + + # Send reply + message_reply = '{}_{}_Your message has been added to the messageboard'.format(source_hash_text, time.time()) + q.put(message_reply) def announce_now(lxmf_destination): lxmf_destination.announce() @@ -96,17 +104,44 @@ def send_message(destination_hash, message_content): message_router.handle_outbound(lxm) def announce_check(): - if r.exists('announce'): + 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()): RNS.log('Recent announcement', RNS.LOG_DEBUG) else: - r.set('announce', 1) - r.expire('announce', 1800) + f = open(announcepath, "w") + next_announce = int(time.time()) + 1800 + f.write(str(next_announce)) + f.close() announce_now(local_lxmf_destination) RNS.log('Announcement sent, expr set 1800 seconds', RNS.LOG_INFO) -def prune_messageboard(max_messages): - RNS.log('Pruning message board', RNS.LOG_DEBUG) - r.ltrim('message_board_general', 0, max_messages -1) +#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) # Start Reticulum and print out all the debug messages reticulum = RNS.Reticulum(loglevel=RNS.LOG_VERBOSE) @@ -133,20 +168,17 @@ announce_check() while True: - # Work through redis message queue - for i in range(0, r.llen('message_queue')): - message_id = r.lpop('message_queue') - message = r.get(message_id) - r.delete(message_id) - destination_hash = message_id.split('_')[0] + # 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] RNS.log('{} {}'.format(destination_hash, message), RNS.LOG_INFO) send_message(destination_hash, message) # Check whether we need to make another announcement announce_check() - # Keep the message board trim - prune_messageboard(max_messages) - #Sleep time.sleep(10) From cf9b8275098e322807c2e95f65b52a4d3b18c3c0 Mon Sep 17 00:00:00 2001 From: chengtripp <124098378+chengtripp@users.noreply.github.com> Date: Fri, 3 Feb 2023 21:18:03 +0000 Subject: [PATCH 3/3] Update README.md --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 34756f4..1df31ac 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,19 @@ Simple message board that can be hosted on a NomadNet node, messages can be posted by 'conversing' with a unique peer, all messages are then forwarded to the message board. ## How Do I Use It? -A user can submit messages to the message board by initiating a chat with the message board peer, they are assigned a unique username (generated randomly using the shortuuid library) and their messages are added directly to the message board. The message board can be viewed on a page hosted by a NomadNet node. +A user can submit messages to the message board by initiating a chat with the message board peer, they are assigned a username (based on the first 5 characters of their address) and their messages are added directly to the message board. The message board can be viewed on a page hosted by a NomadNet node. An example message board can be found on the reticulum testnet hosted on the SolarExpress Node `` and the message board peer `` ![Screenshot](docs/images/messageboard.png) ## How Does It Work? -The message board page itself is hosted on a NomadNet node, you can place the message_board.mu into the pages directory. You can then run the message_board.py script which provides the peer that the users can send messages to. The two parts are joined together with a redis database in the background. +The message board page itself is hosted on a NomadNet node, you can place the message_board.mu into the pages directory. You can then run the message_board.py script which provides the peer that the users can send messages to. The two parts are joined together using umsgpack and a flat file system similar to NomadNet and Reticulum and runs in the background. + +## How Do I Set It Up? +* Turn on node hosting in NomadNet +* Put the `message_board.mu` file into `pages` directory in the config file for `NomadNet`. Edit the file to customise from the default page. +* Run the `message_board.py` script (`python3 message_board.py` either in a `screen` or as a system service), this script uses `NomadNet` and `RNS` libraries and has no additional libraries that need to be installed. Take a note of the message boards address, it is printed on starting the board, you can then place this address in `message_board.mu` file to make it easier for users to interact the board. ## Credits * The send and receive functions in message_board.py are based on examples posted on the Reticulum Matrix channel by [Mark](https://github.com/markqvist)