mirror of
https://github.com/meshcore-dev/meshcore_py.git
synced 2026-06-11 11:56:18 +00:00
Added contact based dest
This commit is contained in:
27
README.md
27
README.md
@@ -26,8 +26,11 @@ async def main():
|
|||||||
|
|
||||||
# Send a message to the first contact
|
# Send a message to the first contact
|
||||||
if contacts:
|
if contacts:
|
||||||
contact_key = next(iter(contacts.items()))[1]['public_key']
|
# Get the first contact
|
||||||
await meshcore.commands.send_msg(bytes.fromhex(contact_key), "Hello from Python!")
|
contact = next(iter(contacts.items()))[1]
|
||||||
|
|
||||||
|
# Pass the contact object directly to send_msg
|
||||||
|
await meshcore.commands.send_msg(contact, "Hello from Python!")
|
||||||
|
|
||||||
await meshcore.disconnect()
|
await meshcore.disconnect()
|
||||||
|
|
||||||
@@ -247,15 +250,31 @@ This logs detailed information about commands sent and events received.
|
|||||||
|
|
||||||
### Sending Messages to Contacts
|
### Sending Messages to Contacts
|
||||||
|
|
||||||
|
Commands that require a destination (`send_msg`, `send_login`, `send_statusreq`, etc.) now accept either:
|
||||||
|
- A string with the hex representation of a public key
|
||||||
|
- A contact object with a "public_key" field
|
||||||
|
- Bytes object (for backward compatibility)
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Get contacts and send to a specific one
|
# Get contacts and send to a specific one
|
||||||
contacts = await meshcore.commands.get_contacts()
|
contacts = await meshcore.commands.get_contacts()
|
||||||
for key, contact in contacts.items():
|
for key, contact in contacts.items():
|
||||||
if contact["adv_name"] == "Alice":
|
if contact["adv_name"] == "Alice":
|
||||||
# Convert the hex key to bytes
|
# Option 1: Pass the contact object directly
|
||||||
|
await meshcore.commands.send_msg(contact, "Hello Alice!")
|
||||||
|
|
||||||
|
# Option 2: Use the public key string
|
||||||
|
await meshcore.commands.send_msg(contact["public_key"], "Hello again Alice!")
|
||||||
|
|
||||||
|
# Option 3 (backward compatible): Convert the hex key to bytes
|
||||||
dst_key = bytes.fromhex(contact["public_key"])
|
dst_key = bytes.fromhex(contact["public_key"])
|
||||||
await meshcore.commands.send_msg(dst_key, "Hello Alice!")
|
await meshcore.commands.send_msg(dst_key, "Hello once more Alice!")
|
||||||
break
|
break
|
||||||
|
|
||||||
|
# You can also directly use a contact found by name
|
||||||
|
contact = meshcore.get_contact_by_name("Bob")
|
||||||
|
if contact:
|
||||||
|
await meshcore.commands.send_msg(contact, "Hello Bob!")
|
||||||
```
|
```
|
||||||
|
|
||||||
### Monitoring Channel Messages
|
### Monitoring Channel Messages
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ async def main():
|
|||||||
# Send the message and get the MSG_SENT event
|
# Send the message and get the MSG_SENT event
|
||||||
print(f"Sending message: '{args.message}'")
|
print(f"Sending message: '{args.message}'")
|
||||||
send_result = await mc.commands.send_msg(
|
send_result = await mc.commands.send_msg(
|
||||||
bytes.fromhex(contact["public_key"])[0:6],
|
contact,
|
||||||
args.message
|
args.message
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ async def main () :
|
|||||||
await mc.commands.get_contacts()
|
await mc.commands.get_contacts()
|
||||||
repeater = mc.get_contact_by_name(REPEATER)
|
repeater = mc.get_contact_by_name(REPEATER)
|
||||||
|
|
||||||
await mc.commands.send_login(bytes.fromhex(repeater["public_key"]), PASSWORD)
|
if repeater is None:
|
||||||
|
print(f"Repeater '{REPEATER}' not found in contacts.")
|
||||||
|
return
|
||||||
|
await mc.commands.send_login(repeater, PASSWORD)
|
||||||
|
|
||||||
print("Login sent ... awaiting")
|
print("Login sent ... awaiting")
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ async def main () :
|
|||||||
await mc.connect()
|
await mc.connect()
|
||||||
|
|
||||||
await mc.ensure_contacts()
|
await mc.ensure_contacts()
|
||||||
await mc.commands.send_msg(bytes.fromhex(mc.get_contact_by_name(DEST)["public_key"])[0:6],MSG)
|
contact = mc.get_contact_by_name(DEST)
|
||||||
|
if contact is None:
|
||||||
|
print(f"Contact '{DEST}' not found in contacts.")
|
||||||
|
return
|
||||||
|
await mc.commands.send_msg(contact ,MSG)
|
||||||
|
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
|
|||||||
@@ -1,11 +1,50 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict, List, Optional, Union
|
||||||
from .events import EventType
|
from .events import EventType
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
# Define types for destination parameters
|
||||||
|
DestinationType = Union[bytes, str, Dict[str, Any]]
|
||||||
|
|
||||||
logger = logging.getLogger("meshcore")
|
logger = logging.getLogger("meshcore")
|
||||||
|
|
||||||
|
def _validate_destination(dst: DestinationType, prefix_length: int = 6) -> bytes:
|
||||||
|
"""
|
||||||
|
Validates and converts a destination to a bytes object.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
dst: The destination, which can be:
|
||||||
|
- str: Hex string representation of a public key
|
||||||
|
- dict: Contact object with a "public_key" field
|
||||||
|
prefix_length: The length of the prefix to use (default: 6 bytes)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bytes: The destination public key as a bytes object
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If dst is invalid or doesn't contain required fields
|
||||||
|
"""
|
||||||
|
if isinstance(dst, bytes):
|
||||||
|
# Already bytes, use directly
|
||||||
|
return dst[:prefix_length]
|
||||||
|
elif isinstance(dst, str):
|
||||||
|
# Hex string, convert to bytes
|
||||||
|
try:
|
||||||
|
return bytes.fromhex(dst)[:prefix_length]
|
||||||
|
except ValueError:
|
||||||
|
raise ValueError(f"Invalid public key hex string: {dst}")
|
||||||
|
elif isinstance(dst, dict):
|
||||||
|
# Contact object, extract public_key
|
||||||
|
if "public_key" not in dst:
|
||||||
|
raise ValueError("Contact object must have a 'public_key' field")
|
||||||
|
try:
|
||||||
|
return bytes.fromhex(dst["public_key"])[:prefix_length]
|
||||||
|
except ValueError:
|
||||||
|
raise ValueError(f"Invalid public_key in contact: {dst['public_key']}")
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Destination must be a public key string or contact object, got: {type(dst)}")
|
||||||
|
|
||||||
class CommandHandler:
|
class CommandHandler:
|
||||||
DEFAULT_TIMEOUT = 5.0
|
DEFAULT_TIMEOUT = 5.0
|
||||||
|
|
||||||
@@ -166,41 +205,44 @@ class CommandHandler:
|
|||||||
logger.debug("Requesting pending messages")
|
logger.debug("Requesting pending messages")
|
||||||
return await self.send(b"\x0A", [EventType.CONTACT_MSG_RECV, EventType.CHANNEL_MSG_RECV, EventType.ERROR], timeout)
|
return await self.send(b"\x0A", [EventType.CONTACT_MSG_RECV, EventType.CHANNEL_MSG_RECV, EventType.ERROR], timeout)
|
||||||
|
|
||||||
async def send_login(self, dst, pwd):
|
async def send_login(self, dst: DestinationType, pwd: str) -> Dict[str, Any]:
|
||||||
logger.debug(f"Sending login request to: {dst.hex() if isinstance(dst, bytes) else dst}")
|
dst_bytes = _validate_destination(dst)
|
||||||
data = b"\x1a" + dst + pwd.encode("ascii")
|
logger.debug(f"Sending login request to: {dst_bytes.hex()}")
|
||||||
|
data = b"\x1a" + dst_bytes + pwd.encode("ascii")
|
||||||
return await self.send(data, [EventType.MSG_SENT, EventType.ERROR])
|
return await self.send(data, [EventType.MSG_SENT, EventType.ERROR])
|
||||||
|
|
||||||
async def send_logout(self, dst):
|
async def send_logout(self, dst: DestinationType) -> Dict[str, Any]:
|
||||||
|
dst_bytes = _validate_destination(dst)
|
||||||
self.login_resp = asyncio.Future()
|
self.login_resp = asyncio.Future()
|
||||||
data = b"\x1d" + dst
|
data = b"\x1d" + dst_bytes
|
||||||
return await self.send(data, [EventType.MSG_SENT, EventType.ERROR])
|
return await self.send(data, [EventType.MSG_SENT, EventType.ERROR])
|
||||||
|
|
||||||
async def send_statusreq(self, dst):
|
async def send_statusreq(self, dst: DestinationType) -> Dict[str, Any]:
|
||||||
logger.debug(f"Sending status request to: {dst.hex() if isinstance(dst, bytes) else dst}")
|
dst_bytes = _validate_destination(dst)
|
||||||
data = b"\x1b" + dst
|
logger.debug(f"Sending status request to: {dst_bytes.hex()}")
|
||||||
|
data = b"\x1b" + dst_bytes
|
||||||
return await self.send(data, [EventType.MSG_SENT, EventType.ERROR])
|
return await self.send(data, [EventType.MSG_SENT, EventType.ERROR])
|
||||||
|
|
||||||
async def send_cmd(self, dst, cmd, timestamp=None):
|
async def send_cmd(self, dst: DestinationType, cmd: str, timestamp: Optional[int] = None) -> Dict[str, Any]:
|
||||||
logger.debug(f"Sending command to {dst.hex() if isinstance(dst, bytes) else dst}: {cmd}")
|
dst_bytes = _validate_destination(dst)
|
||||||
|
logger.debug(f"Sending command to {dst_bytes.hex()}: {cmd}")
|
||||||
|
|
||||||
# Default to current time if timestamp not provided
|
|
||||||
if timestamp is None:
|
if timestamp is None:
|
||||||
import time
|
import time
|
||||||
timestamp = int(time.time()).to_bytes(4, 'little')
|
timestamp = int(time.time())
|
||||||
|
|
||||||
data = b"\x02\x01\x00" + timestamp + dst + cmd.encode("ascii")
|
data = b"\x02\x01\x00" + timestamp.to_bytes(4, 'little') + dst_bytes + cmd.encode("ascii")
|
||||||
return await self.send(data, [EventType.OK, EventType.ERROR])
|
return await self.send(data, [EventType.OK, EventType.ERROR])
|
||||||
|
|
||||||
async def send_msg(self, dst, msg, timestamp=None):
|
async def send_msg(self, dst: DestinationType, msg: str, timestamp: Optional[int] = None) -> Dict[str, Any]:
|
||||||
logger.debug(f"Sending message to {dst.hex() if isinstance(dst, bytes) else dst}: {msg}")
|
dst_bytes = _validate_destination(dst)
|
||||||
|
logger.debug(f"Sending message to {dst_bytes.hex()}: {msg}")
|
||||||
|
|
||||||
# Default to current time if timestamp not provided
|
|
||||||
if timestamp is None:
|
if timestamp is None:
|
||||||
import time
|
import time
|
||||||
timestamp = int(time.time()).to_bytes(4, 'little')
|
timestamp = int(time.time())
|
||||||
|
|
||||||
data = b"\x02\x00\x00" + timestamp + dst + msg.encode("ascii")
|
data = b"\x02\x00\x00" + timestamp.to_bytes(4, 'little') + dst_bytes + msg.encode("ascii")
|
||||||
return await self.send(data, [EventType.MSG_SENT, EventType.ERROR])
|
return await self.send(data, [EventType.MSG_SENT, EventType.ERROR])
|
||||||
|
|
||||||
async def send_chan_msg(self, chan, msg, timestamp=None):
|
async def send_chan_msg(self, chan, msg, timestamp=None):
|
||||||
|
|||||||
Reference in New Issue
Block a user