Skip to content

Commit 478d4c4

Browse files
committed
introduce path to node in commands
1 parent a555978 commit 478d4c4

File tree

1 file changed

+155
-114
lines changed

1 file changed

+155
-114
lines changed

src/meshcore_cli/meshcore_cli.py

Lines changed: 155 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/python
2-
"""
2+
"""
33
mccli.py : CLI interface to MeschCore BLE companion app
44
"""
55
import asyncio
@@ -484,8 +484,8 @@ def make_completion_dict(contacts, pending={}, to=None, channels=None):
484484
"neighbors" : None,
485485
"req_acl":None,
486486
"setperm":contact_list,
487-
"gps" : {"on":None,"off":None,"sync":None,"setloc":None,
488-
"advert" : {"none": None, "share": None, "prefs": None},
487+
"gps" : {"on":None,"off":None,"sync":None,"setloc":None,
488+
"advert" : {"none": None, "share": None, "prefs": None},
489489
},
490490
"sensor": {"list": None, "set": {"gps": None}, "get": {"gps": None}},
491491
"get" : {"name" : None,
@@ -681,7 +681,22 @@ def _(event):
681681
pass
682682

683683
# raw meshcli command as on command line
684-
elif line.startswith("$") or line.startswith("/") :
684+
elif line.startswith("/") :
685+
path = line.split(" ", 1)[0]
686+
if path.count("/") == 1:
687+
args = shlex.split(line[1:])
688+
await process_cmds(mc, args)
689+
else:
690+
cmdline = line[1:].split("/",1)[1]
691+
contact_name = path[1:].split("/",1)[0]
692+
tct = mc.get_contact_by_name(contact_name)
693+
if tct is None:
694+
print(f"{contact_name} is not a contact")
695+
else:
696+
if not await process_contact_chat_line(mc, tct, cmdline):
697+
print(f"{cmdline} not found for {contact_name}")
698+
699+
elif line.startswith("$") :
685700
args = shlex.split(line[1:])
686701
await process_cmds(mc, args)
687702

@@ -707,7 +722,7 @@ def _(event):
707722
elif dest == "!" :
708723
nc = process_event_message.last_node
709724
else :
710-
chan = await get_channel_by_name(mc, dest)
725+
chan = await get_channel_by_name(mc, dest)
711726
if chan is None :
712727
print(f"Contact '{dest}' not found in contacts.")
713728
nc = contact
@@ -752,104 +767,8 @@ def _(event):
752767
args = shlex.split(line)
753768
await process_cmds(mc, args)
754769

755-
# commands that take contact as second arg will be sent to recipient
756-
elif contact["type"] > 0 and (line == "sc" or line == "share_contact" or\
757-
line == "ec" or line == "export_contact" or\
758-
line == "uc" or line == "upload_contact" or\
759-
line == "rp" or line == "reset_path" or\
760-
line == "dp" or line == "disc_path" or\
761-
line == "contact_info" or line == "ci" or\
762-
line == "req_status" or line == "rs" or\
763-
line == "req_bstatus" or line == "rbs" or\
764-
line == "req_telemetry" or line == "rt" or\
765-
line == "req_acl" or\
766-
line == "path" or\
767-
line == "logout" ) :
768-
args = [line, contact['adv_name']]
769-
await process_cmds(mc, args)
770-
771-
elif contact["type"] > 0 and line.startswith("set timeout "):
772-
cmds=line.split(" ")
773-
contact["timeout"] = float(cmds[2])
774-
775-
elif contact["type"] > 0 and line == "get timeout":
776-
print(f"timeout: {0 if not 'timeout' in contact else contact['timeout']}")
777-
778-
elif contact["type"] == 4 and\
779-
(line.startswith("get mma ")) or\
780-
contact["type"] > 1 and\
781-
(line.startswith("get telemetry") or line.startswith("get status") or line.startswith("get acl")):
782-
cmds = line.split(" ")
783-
args = [f"req_{cmds[1]}", contact['adv_name']]
784-
if len(cmds) > 2 :
785-
args = args + cmds[2:]
786-
if line.startswith("get mma ") and len(args) < 4:
787-
args.append("0")
788-
await process_cmds(mc, args)
789-
790-
# special treatment for setperm to support contact name as param
791-
elif contact["type"] > 1 and\
792-
(line.startswith("setperm ") or line.startswith("set perm ")):
793-
try:
794-
cmds = shlex.split(line)
795-
off = 1 if line.startswith("set perm") else 0
796-
name = cmds[1 + off]
797-
perm_string = cmds[2 + off]
798-
if (perm_string.startswith("0x")):
799-
perm = int(perm_string,0)
800-
elif (perm_string.startswith("#")):
801-
perm = int(perm_string[1:])
802-
else:
803-
perm = int(perm_string,16)
804-
ct=mc.get_contact_by_name(name)
805-
if ct is None:
806-
ct=mc.get_contact_by_key_prefix(name)
807-
if ct is None:
808-
if name == "self" or mc.self_info["public_key"].startswith(name):
809-
key = mc.self_info["public_key"]
810-
else:
811-
key = name
812-
else:
813-
key=ct["public_key"]
814-
newline=f"setperm {key} {perm}"
815-
await process_cmds(mc, ["cmd", contact["adv_name"], newline])
816-
except IndexError:
817-
print("Wrong number of parameters")
818-
819-
# trace called on a contact
820-
elif contact["type"] > 0 and (
821-
line == "trace" or line == "tr") :
822-
await print_trace_to(mc, contact)
823-
824-
elif contact["type"] > 0 and (
825-
line == "dtrace" or line == "dt") :
826-
await print_disc_trace_to(mc, contact)
827-
828-
# same but for commands with a parameter
829-
elif contact["type"] > 0 and (line.startswith("cmd ") or\
830-
line.startswith("cp ") or line.startswith("change_path ") or\
831-
line.startswith("cf ") or line.startswith("change_flags ") or\
832-
line.startswith("req_binary ") or\
833-
line.startswith("login ")) :
834-
cmds = line.split(" ", 1)
835-
args = [cmds[0], contact['adv_name'], cmds[1]]
836-
await process_cmds(mc, args)
837-
838-
elif contact["type"] == 4 and \
839-
(line.startswith("req_mma ") or line.startswith('rm ')) :
840-
cmds = line.split(" ")
841-
if len(cmds) < 3 :
842-
cmds.append("0")
843-
args = [cmds[0], contact['adv_name'], cmds[1], cmds[2]]
844-
await process_cmds(mc, args)
845-
846-
elif line.startswith(":") : # : will send a command to current recipient
847-
args=["cmd", contact['adv_name'], line[1:]]
848-
await process_cmds(mc, args)
849-
850-
elif line == "reset path" : # reset path for compat with terminal chat
851-
args = ["reset_path", contact['adv_name']]
852-
await process_cmds(mc, args)
770+
elif await process_contact_chat_line(mc, contact, line):
771+
pass
853772

854773
elif line == "list" : # list command from chat displays contacts on a line
855774
it = iter(mc.contacts.items())
@@ -887,6 +806,121 @@ def _(event):
887806
interactive_loop.classic = False
888807
interactive_loop.print_name = True
889808

809+
async def process_contact_chat_line(mc, contact, line):
810+
if contact["type"] == 0:
811+
return False
812+
813+
if line.startswith(":") : # : will send a command to current recipient
814+
args=["cmd", contact['adv_name'], line[1:]]
815+
await process_cmds(mc, args)
816+
return True
817+
818+
if line == "reset path" : # reset path for compat with terminal chat
819+
args = ["reset_path", contact['adv_name']]
820+
await process_cmds(mc, args)
821+
return True
822+
823+
# commands that take contact as second arg will be sent to recipient
824+
if line == "sc" or line == "share_contact" or\
825+
line == "ec" or line == "export_contact" or\
826+
line == "uc" or line == "upload_contact" or\
827+
line == "rp" or line == "reset_path" or\
828+
line == "dp" or line == "disc_path" or\
829+
line == "contact_info" or line == "ci" or\
830+
line == "req_status" or line == "rs" or\
831+
line == "req_bstatus" or line == "rbs" or\
832+
line == "req_telemetry" or line == "rt" or\
833+
line == "req_acl" or\
834+
line == "path" or\
835+
line == "logout" :
836+
args = [line, contact['adv_name']]
837+
await process_cmds(mc, args)
838+
return True
839+
840+
if line.startswith("set timeout "):
841+
cmds=line.split(" ")
842+
contact["timeout"] = float(cmds[2])
843+
return True
844+
845+
if line == "get timeout":
846+
print(f"timeout: {0 if not 'timeout' in contact else contact['timeout']}")
847+
return True
848+
849+
if contact["type"] == 4 and\
850+
(line.startswith("get mma ")) or\
851+
contact["type"] > 1 and\
852+
(line.startswith("get telemetry") or line.startswith("get status") or line.startswith("get acl")):
853+
cmds = line.split(" ")
854+
args = [f"req_{cmds[1]}", contact['adv_name']]
855+
if len(cmds) > 2 :
856+
args = args + cmds[2:]
857+
if line.startswith("get mma ") and len(args) < 4:
858+
args.append("0")
859+
await process_cmds(mc, args)
860+
return True
861+
862+
# special treatment for setperm to support contact name as param
863+
if contact["type"] > 1 and\
864+
(line.startswith("setperm ") or line.startswith("set perm ")):
865+
try:
866+
cmds = shlex.split(line)
867+
off = 1 if line.startswith("set perm") else 0
868+
name = cmds[1 + off]
869+
perm_string = cmds[2 + off]
870+
if (perm_string.startswith("0x")):
871+
perm = int(perm_string,0)
872+
elif (perm_string.startswith("#")):
873+
perm = int(perm_string[1:])
874+
else:
875+
perm = int(perm_string,16)
876+
ct=mc.get_contact_by_name(name)
877+
if ct is None:
878+
ct=mc.get_contact_by_key_prefix(name)
879+
if ct is None:
880+
if name == "self" or mc.self_info["public_key"].startswith(name):
881+
key = mc.self_info["public_key"]
882+
else:
883+
key = name
884+
else:
885+
key=ct["public_key"]
886+
newline=f"setperm {key} {perm}"
887+
await process_cmds(mc, ["cmd", contact["adv_name"], newline])
888+
except IndexError:
889+
print("Wrong number of parameters")
890+
return True
891+
892+
# trace called on a contact
893+
if line == "trace" or line == "tr" :
894+
await print_trace_to(mc, contact)
895+
return True
896+
897+
if line == "dtrace" or line == "dt" :
898+
await print_disc_trace_to(mc, contact)
899+
return True
900+
901+
# same but for commands with a parameter
902+
if line.startswith("cmd ") or\
903+
line.startswith("cp ") or line.startswith("change_path ") or\
904+
line.startswith("cf ") or line.startswith("change_flags ") or\
905+
line.startswith("req_binary ") or\
906+
line.startswith("login ") :
907+
cmds = line.split(" ", 1)
908+
args = [cmds[0], contact['adv_name'], cmds[1]]
909+
await process_cmds(mc, args)
910+
return True
911+
912+
if contact["type"] == 4 and \
913+
(line.startswith("req_mma ") or line.startswith('rm ')) :
914+
cmds = line.split(" ")
915+
if len(cmds) < 3 :
916+
cmds.append("0")
917+
args = [cmds[0], contact['adv_name'], cmds[1], cmds[2]]
918+
await process_cmds(mc, args)
919+
return True
920+
921+
return False
922+
923+
890924
async def send_cmd (mc, contact, cmd) :
891925
res = await mc.commands.send_cmd(contact, cmd)
892926
if not res is None and not res.type == EventType.ERROR:
@@ -910,7 +944,7 @@ async def send_chan_msg(mc, nb, msg):
910944
sent["text"] = msg
911945
sent["txt_type"] = 0
912946
sent["name"] = mc.self_info['name']
913-
await log_message(mc, sent)
947+
await log_message(mc, sent)
914948
return res
915949

916950
async def send_msg (mc, contact, msg) :
@@ -1021,7 +1055,7 @@ async def get_contacts (mc, anim=False, lastomod=0, timeout=5) :
10211055
done, pending = await asyncio.wait(
10221056
futures, timeout=timeout, return_when=asyncio.FIRST_COMPLETED
10231057
)
1024-
1058+
10251059
# Check if any future completed successfully
10261060
if len(done) == 0:
10271061
logger.debug("Timeout while getting contacts")
@@ -1041,7 +1075,7 @@ async def get_contacts (mc, anim=False, lastomod=0, timeout=5) :
10411075
if anim:
10421076
if event.type == EventType.CONTACTS:
10431077
print ((len(event.payload)-contact_nb)*"." + " Done")
1044-
else :
1078+
else :
10451079
print(" Error")
10461080
for future in pending:
10471081
future.cancel()
@@ -1703,7 +1737,7 @@ async def next_cmd(mc, cmds, json_output=False):
17031737
res = await set_channel(mc, cmds[1], cmds[2])
17041738
elif len(cmds[3]) != 32:
17051739
res = None
1706-
else:
1740+
else:
17071741
res = await set_channel(mc, cmds[1], cmds[2], bytes.fromhex(cmds[3]))
17081742
if res is None:
17091743
print("Error setting channel")
@@ -1723,8 +1757,8 @@ async def next_cmd(mc, cmds, json_output=False):
17231757
case "msg" | "m" | "{" : # sends to a contact from name
17241758
argnum = 2
17251759
dest = None
1726-
1727-
if len(cmds[1]) == 12: # possibly an hex prefix
1760+
1761+
if len(cmds[1]) == 12: # possibly an hex prefix
17281762
try:
17291763
dest = bytes.fromhex(cmds[1])
17301764
except ValueError:
@@ -1801,11 +1835,18 @@ async def next_cmd(mc, cmds, json_output=False):
18011835

18021836
case "trace" | "tr":
18031837
argnum = 1
1804-
res = await mc.commands.send_trace(path=cmds[1])
1838+
path = cmds[1]
1839+
plen = int(len(path)/2)
1840+
if plen > 1 and path.count(",") == 0:
1841+
path = cmds[1][0:2]
1842+
for i in range(1, plen):
1843+
path = path + "," + cmds[1][2*i:2*i+2]
1844+
1845+
res = await mc.commands.send_trace(path=path)
18051846
if res and res.type != EventType.ERROR:
18061847
tag= int.from_bytes(res.payload['expected_ack'], byteorder="little")
18071848
timeout = res.payload["suggested_timeout"] / 1000 * 1.2
1808-
ev = await mc.wait_for_event(EventType.TRACE_DATA,
1849+
ev = await mc.wait_for_event(EventType.TRACE_DATA,
18091850
attribute_filters={"tag": tag},
18101851
timeout=timeout)
18111852
if ev is None:
@@ -1939,7 +1980,7 @@ async def next_cmd(mc, cmds, json_output=False):
19391980
print("Timeout waiting telemetry")
19401981
else :
19411982
print(json.dumps(res.payload, indent=4))
1942-
1983+
19431984
case "disc_path" | "dp" :
19441985
argnum = 1
19451986
await mc.ensure_contacts()
@@ -2609,7 +2650,7 @@ async def main(argv):
26092650
if not d.name is None and d.name.startswith("MeshCore-"):
26102651
print(f" {d.address} {d.name}")
26112652
except BleakError:
2612-
print(" No BLE HW")
2653+
print(" No BLE HW")
26132654
print("\nSerial ports:")
26142655
ports = serial.tools.list_ports.comports()
26152656
for port, desc, hwid in sorted(ports):
@@ -2650,7 +2691,7 @@ async def main(argv):
26502691
else:
26512692
logger.error("Invalid choice")
26522693
return
2653-
2694+
26542695
if (debug==True):
26552696
logger.setLevel(logging.DEBUG)
26562697
elif (json_output) :

0 commit comments

Comments
 (0)