forked from iarv/meshing-around
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 51cd2002af | |||
| b40f41f41c | |||
| 4c33b30f14 | |||
| b7490afb99 | |||
| 8b57ed727c | |||
| fd5d64b9fb | |||
| 00af152c2c | |||
| 31f0abc8c8 |
@@ -259,6 +259,7 @@ lon = -123.0
|
||||
fuzzConfigLocation = True
|
||||
# Fuzz all values in all data
|
||||
fuzzItAll = False
|
||||
|
||||
UseMeteoWxAPI = True
|
||||
|
||||
coastalEnabled = False # NOAA Coastal Data Enable NOAA Coastal Waters Forecasts and Tide
|
||||
|
||||
+7
-2
@@ -29,6 +29,7 @@ def auto_response(message, snr, rssi, hop, pkiStatus, message_from_id, channel_n
|
||||
"ack": lambda: handle_ping(message_from_id, deviceID, message, hop, snr, rssi, isDM, channel_number),
|
||||
"ask:": lambda: handle_llm(message_from_id, channel_number, deviceID, message, publicChannel),
|
||||
"askai": lambda: handle_llm(message_from_id, channel_number, deviceID, message, publicChannel),
|
||||
"bannode": lambda: handle_bbsban(message, message_from_id, isDM),
|
||||
"bbsack": lambda: bbs_sync_posts(message, message_from_id, deviceID),
|
||||
"bbsdelete": lambda: handle_bbsdelete(message, message_from_id),
|
||||
"bbshelp": bbs_help,
|
||||
@@ -402,7 +403,7 @@ def handle_howtall(message, message_from_id, deviceID, isDM):
|
||||
shadow_length = float(message.lower().split("howtall ")[1].split(" ")[0])
|
||||
except:
|
||||
return f"Please provide a shadow length in {measure} example: howtall 5.5"
|
||||
|
||||
|
||||
# get data
|
||||
msg = measureHeight(lat, lon, shadow_length)
|
||||
|
||||
@@ -1536,7 +1537,11 @@ def onReceive(packet, interface):
|
||||
#print (f"calculated hop count: {hop_start} - {hop_limit} = {hop_count}")
|
||||
|
||||
hop = f"{hop_count} hops"
|
||||
|
||||
|
||||
# check with stringSafeChecker if the message is safe
|
||||
if stringSafeCheck(message_string) is False:
|
||||
logger.warning(f"System: Possibly Unsafe Message from {get_name_from_number(message_from_id, 'long', rxNode)}")
|
||||
|
||||
if help_message in message_string or welcome_message in message_string or "CMD?:" in message_string:
|
||||
# ignore help and welcome messages
|
||||
logger.warning(f"Got Own Welcome/Help header. From: {get_name_from_number(message_from_id, 'long', rxNode)}")
|
||||
|
||||
+6
-2
@@ -88,7 +88,11 @@ def bbs_delete_message(messageID = 0, fromNode = 0):
|
||||
else:
|
||||
return "Please specify a message number to delete."
|
||||
|
||||
def bbs_post_message(subject, message, fromNode):
|
||||
def bbs_post_message(subject, message, fromNode, threadID=0, replytoID=0):
|
||||
# post a message to the bbsdb
|
||||
now = today.strftime('%Y-%m-%d %H:%M:%S')
|
||||
thread = threadID
|
||||
replyto = replytoID
|
||||
# post a message to the bbsdb and assign a messageID
|
||||
messageID = len(bbs_messages) + 1
|
||||
|
||||
@@ -106,7 +110,7 @@ def bbs_post_message(subject, message, fromNode):
|
||||
return "Message posted. ID is: " + str(messageID)
|
||||
# validate its not overlength by keeping in chunker limit
|
||||
# append the message to the list
|
||||
bbs_messages.append([messageID, subject, message, fromNode])
|
||||
bbs_messages.append([messageID, subject, message, fromNode, now, thread, replyto])
|
||||
logger.info(f"System: NEW Message Posted, subject: {subject}, message: {message} from {fromNode}")
|
||||
|
||||
# save the bbsdb
|
||||
|
||||
+44
-17
@@ -3,6 +3,8 @@
|
||||
# 2025
|
||||
from modules.log import *
|
||||
import random
|
||||
import time
|
||||
|
||||
# to molly and jake, I miss you both so much.
|
||||
|
||||
if disable_emojis_in_games:
|
||||
@@ -47,6 +49,10 @@ class TicTacToe:
|
||||
ret += self.show_board(id)
|
||||
ret += "Pick 1-9:"
|
||||
return ret
|
||||
|
||||
def rndTeaPrice(self, tea=42):
|
||||
"""Return a random tea between 0 and tea."""
|
||||
return random.uniform(0, tea)
|
||||
|
||||
def show_board(self, id):
|
||||
"""Display compact board with move numbers"""
|
||||
@@ -90,19 +96,30 @@ class TicTacToe:
|
||||
return True
|
||||
|
||||
def bot_move(self, id):
|
||||
"""AI makes a move"""
|
||||
"""AI makes a move: tries to win, block, or pick random"""
|
||||
g = self.game[id]
|
||||
|
||||
# Simple AI: Try to win, block, or pick random
|
||||
move = self.find_winning_move(id, O) # Try to win
|
||||
if move == -1:
|
||||
move = self.find_winning_move(id, X) # Block player
|
||||
if move == -1:
|
||||
move = self.find_random_move(id) # Random move
|
||||
|
||||
board = g["board"]
|
||||
|
||||
# Try to win
|
||||
move = self.find_winning_move(id, O)
|
||||
if move != -1:
|
||||
g["board"][move] = O
|
||||
return move
|
||||
board[move] = O
|
||||
return move
|
||||
|
||||
# Try to block player
|
||||
move = self.find_winning_move(id, X)
|
||||
if move != -1:
|
||||
board[move] = O
|
||||
return move
|
||||
|
||||
# Pick random move
|
||||
move = self.find_random_move(id)
|
||||
if move != -1:
|
||||
board[move] = O
|
||||
return move
|
||||
|
||||
# No moves possible
|
||||
return -1
|
||||
|
||||
def find_winning_move(self, id, player):
|
||||
"""Find a winning move for the given player"""
|
||||
@@ -117,12 +134,22 @@ class TicTacToe:
|
||||
return i
|
||||
board[i] = " "
|
||||
return -1
|
||||
|
||||
def find_random_move(self, id):
|
||||
"""Find a random empty position"""
|
||||
g = self.game[id]
|
||||
empty = [i for i in range(9) if g["board"][i] == " "]
|
||||
return random.choice(empty) if empty else -1
|
||||
|
||||
def find_random_move(self, id: str, tea_price: float = 42.0) -> int:
|
||||
"""Find a random empty position, using time and tea_price for extra randomness."""
|
||||
board = self.game[id]["board"]
|
||||
empty = [i for i, cell in enumerate(board) if cell == " "]
|
||||
current_time = time.time()
|
||||
from_china = self.rndTeaPrice(time.time() % 7) # Correct usage
|
||||
tea_price = from_china
|
||||
tea_price = (42 * 7) - (13 / 2) + (tea_price % 5)
|
||||
if not empty:
|
||||
return -1
|
||||
# Combine time and tea_price for a seed
|
||||
seed = int(current_time * 1000) ^ int(tea_price * 1000)
|
||||
local_random = random.Random(seed)
|
||||
local_random.shuffle(empty)
|
||||
return empty[0]
|
||||
|
||||
def check_winner_on_board(self, board):
|
||||
"""Check winner on given board state"""
|
||||
|
||||
@@ -85,6 +85,10 @@ def llm_query(input, nodeID=0, location_name=None):
|
||||
if input == " " and rawLLMQuery:
|
||||
logger.warning("System: These LLM models lack a traditional system prompt, they can be verbose and not very helpful be advised.")
|
||||
input = meshbotAIinit
|
||||
else:
|
||||
input = input.strip()
|
||||
# classic model for gemma2, deepseek-r1, etc
|
||||
logger.debug(f"System: Using classic LLM model framework, ideally for gemma2, deepseek-r1, etc")
|
||||
|
||||
if not location_name:
|
||||
location_name = "no location provided "
|
||||
|
||||
+124
-10
@@ -14,7 +14,7 @@ import io # for suppressing output on watchdog
|
||||
from modules.log import *
|
||||
|
||||
# Global Variables
|
||||
trap_list = ("cmd","cmd?") # default trap list
|
||||
trap_list = ("cmd","cmd?","bannode",) # base commands
|
||||
help_message = "Bot CMD?:"
|
||||
asyncLoop = asyncio.new_event_loop()
|
||||
games_enabled = False
|
||||
@@ -557,7 +557,7 @@ def get_node_location(nodeID, nodeInt=1, channel=0, round_digits=2):
|
||||
else:
|
||||
return config_position
|
||||
|
||||
def get_closest_nodes(nodeInt=1,returnCount=3):
|
||||
def get_closest_nodes(nodeInt=1,returnCount=3, channel=publicChannel):
|
||||
interface = globals()[f'interface{nodeInt}']
|
||||
node_list = []
|
||||
|
||||
@@ -584,14 +584,22 @@ def get_closest_nodes(nodeInt=1,returnCount=3):
|
||||
|
||||
except Exception as e:
|
||||
pass
|
||||
# else:
|
||||
# # request location data
|
||||
# try:
|
||||
# logger.debug(f"System: Requesting location data for {node['id']}")
|
||||
# interface.sendPosition(destinationId=node['id'], wantResponse=False, channelIndex=publicChannel)
|
||||
# except Exception as e:
|
||||
# logger.error(f"System: Error requesting location data for {node['id']}. Error: {e}")
|
||||
|
||||
else:
|
||||
# request location data
|
||||
reqLocationEnabled = False
|
||||
if reqLocationEnabled:
|
||||
try:
|
||||
logger.debug(f"System: Requesting location data for {node['id']}, lastHeard: {node.get('lastHeard', 'N/A')}")
|
||||
# one idea is to send a ping to the node to request location data for if or when, ask again later
|
||||
interface.sendPosition(destinationId=node['id'], wantResponse=False, channelIndex=channel)
|
||||
# wait a bit
|
||||
time.sleep(3)
|
||||
# send a traceroute request
|
||||
interface.sendTraceRoute(destinationId=node['id'], channelIndex=channel, wantResponse=False)
|
||||
# wait a bit
|
||||
time.sleep(1)
|
||||
except Exception as e:
|
||||
logger.error(f"System: Error requesting location data for {node['id']}. Error: {e}")
|
||||
# sort by distance closest
|
||||
#node_list.sort(key=lambda x: (x['latitude']-latitudeValue)**2 + (x['longitude']-longitudeValue)**2)
|
||||
node_list.sort(key=lambda x: x['distance'])
|
||||
@@ -826,6 +834,112 @@ def messageTrap(msg):
|
||||
return True
|
||||
return False
|
||||
|
||||
def stringSafeCheck(s):
|
||||
# Check if a string is safe to use, no control characters or non-printable characters
|
||||
soFarSoGood = True
|
||||
if not all(c.isprintable() or c.isspace() for c in s):
|
||||
return False
|
||||
if any(ord(c) < 32 and c not in '\n\r\t' for c in s):
|
||||
return False
|
||||
if any(c in s for c in ['\x0b', '\x0c', '\x1b']):
|
||||
return False
|
||||
if len(s) > 1000:
|
||||
return False
|
||||
injection_chars = [';', '|', '../']
|
||||
if any(char in s for char in injection_chars):
|
||||
return False
|
||||
return soFarSoGood
|
||||
|
||||
def save_bbsBanList():
|
||||
# save the bbs_ban_list to file
|
||||
try:
|
||||
with open('data/bbs_ban_list.txt', 'w') as f:
|
||||
for node in bbs_ban_list:
|
||||
f.write(f"{node}\n")
|
||||
logger.debug("System: BBS ban list saved")
|
||||
except Exception as e:
|
||||
logger.error(f"System: Error saving BBS ban list: {e}")
|
||||
|
||||
def load_bbsBanList():
|
||||
global bbs_ban_list
|
||||
# load the bbs_ban_list from file
|
||||
try:
|
||||
with open('data/bbs_ban_list.txt', 'r') as f:
|
||||
bbs_ban_list = [line.strip() for line in f.readlines() if line.strip()]
|
||||
logger.debug("System: BBS ban list loaded")
|
||||
except FileNotFoundError:
|
||||
bbs_ban_list = config['bbs'].get('bbs_ban_list', '').split(',')
|
||||
logger.debug("System: No BBS ban list found, starting with default")
|
||||
except Exception as e:
|
||||
logger.error(f"System: Error loading BBS ban list: {e}")
|
||||
bbs_ban_list = []
|
||||
|
||||
def isNodeAdmin(nodeID):
|
||||
# check if the nodeID is in the bbs_admin_list
|
||||
if bbs_admin_list != ['']:
|
||||
for admin in bbs_admin_list:
|
||||
if str(nodeID) == admin:
|
||||
return True
|
||||
else:
|
||||
return True
|
||||
return False
|
||||
|
||||
def isNodeBanned(nodeID):
|
||||
# check if the nodeID is in the bbs_ban_list
|
||||
for banned in bbs_ban_list:
|
||||
if str(nodeID) == banned:
|
||||
return True
|
||||
return False
|
||||
|
||||
def handle_bbsban(message, message_from_id, isDM):
|
||||
msg = ""
|
||||
if not isDM:
|
||||
return "🤖only available in a Direct Message📵"
|
||||
if not isNodeAdmin(message_from_id):
|
||||
return NO_ALERTS
|
||||
if "?" in message:
|
||||
return "Ban or unban a node from posting to the BBS. Example: bannode add 1234567890 or bannode remove 1234567890"
|
||||
|
||||
parts = message.lower().split()
|
||||
if len(parts) < 2 or parts[0] != "bannode":
|
||||
return "Please specify add, remove, or list. Example: bannode add 1234567890"
|
||||
|
||||
action = parts[1]
|
||||
|
||||
if action == "list":
|
||||
if bbs_ban_list:
|
||||
return "BBS Ban List:\n" + "\n".join(bbs_ban_list)
|
||||
else:
|
||||
return "The BBS ban list is currently empty."
|
||||
|
||||
if len(parts) < 3:
|
||||
return "Please specify add or remove and a node number. Example: bannode add 1234567890"
|
||||
|
||||
node_id = parts[2].strip()
|
||||
if not node_id.isdigit():
|
||||
return "Invalid node number. Please provide a numeric node ID."
|
||||
|
||||
if action == "add":
|
||||
if node_id not in bbs_ban_list:
|
||||
bbs_ban_list.append(node_id)
|
||||
save_bbsBanList()
|
||||
logger.warning(f"System: {message_from_id} added {node_id} to the BBS ban list")
|
||||
msg = f"Node {node_id} added to the BBS ban list"
|
||||
else:
|
||||
msg = f"Node {node_id} is already in the BBS ban list"
|
||||
elif action == "remove":
|
||||
if node_id in bbs_ban_list:
|
||||
bbs_ban_list.remove(node_id)
|
||||
save_bbsBanList()
|
||||
logger.warning(f"System: {message_from_id} removed {node_id} from the BBS ban list")
|
||||
msg = f"Node {node_id} removed from the BBS ban list"
|
||||
else:
|
||||
msg = f"Node {node_id} is not in the BBS ban list"
|
||||
else:
|
||||
msg = "Invalid action. Please use 'add', 'remove', or 'list'."
|
||||
|
||||
return msg
|
||||
|
||||
def handleMultiPing(nodeID=0, deviceID=1):
|
||||
global multiPingList
|
||||
if len(multiPingList) > 1:
|
||||
|
||||
Reference in New Issue
Block a user