Merge pull request #2 from chengtripp/micro

Micro
This commit is contained in:
chengtripp 2023-02-06 21:36:21 +00:00 committed by GitHub
commit adfd531314
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 109 additions and 52 deletions

View File

@ -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 `<d16df67bff870a8eaa2af6957c5a2d7d>` and the message board peer `<ad713cd3fedf36cc190f0cb89c4be1ff>`
![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)

View File

@ -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)

View File

@ -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 <ad713cd3fedf36cc190f0cb89c4be1ff>, 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()