mirror of
https://github.com/markqvist/lxmf_messageboard.git
synced 2024-10-01 02:25:36 -04:00
commit
adfd531314
@ -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)
|
||||
|
116
messageboard.py
116
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)
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user