Reduce sleep() in CAP library code (#2189)

* 1) Removed most framework sleeps 2) refactored connection code

* pre-commit fixes

* pre-commit

* ignore protobuf files in pre-commit checks

* Fix duplicate actor registration

* refactor change

* Nicer printing of Actors

* 1) Report recv_multipart errors 4) Always send 4 parts

* AutoGen generate_reply expects to wait indefinitely for an answer.  CAP can wait a certain amount and give up.   In order to reconcile the two, AutoGenConnector is set to wait indefinitely.

* pre-commit formatting fixes

* pre-commit format changes

* don't check autogenerated proto py files
This commit is contained in:
Rajan 2024-04-02 03:49:07 -04:00 committed by GitHub
parent c3193f847b
commit db30ec8961
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 245 additions and 89 deletions

View File

@ -52,7 +52,7 @@ exclude = [
# This file needs to be either upgraded or removed and therefore should be # This file needs to be either upgraded or removed and therefore should be
# ignore from type checking for now # ignore from type checking for now
"math_utils\\.py$", "math_utils\\.py$",
"samples\\apps\\cap\\py\\autogencap\\proto\\.*\\.py", "**/cap/py/autogencap/proto/*",
] ]
ignore-init-module-imports = true ignore-init-module-imports = true
unfixable = ["F401"] unfixable = ["F401"]

View File

@ -2,7 +2,7 @@ import zmq
import threading import threading
import traceback import traceback
import time import time
from .DebugLog import Debug, Info from .DebugLog import Debug, Info, Error
from .Config import xpub_url from .Config import xpub_url
@ -11,6 +11,7 @@ class Actor:
self.actor_name: str = agent_name self.actor_name: str = agent_name
self.agent_description: str = description self.agent_description: str = description
self.run = False self.run = False
self._start_event = threading.Event()
def connect_network(self, network): def connect_network(self, network):
Debug(self.actor_name, f"is connecting to {network}") Debug(self.actor_name, f"is connecting to {network}")
@ -25,14 +26,15 @@ class Actor:
return True return True
def _recv_thread(self): def _recv_thread(self):
Debug(self.actor_name, "recv thread started")
self._socket: zmq.Socket = self._context.socket(zmq.SUB)
self._socket.setsockopt(zmq.RCVTIMEO, 500)
self._socket.connect(xpub_url)
str_topic = f"{self.actor_name}"
Debug(self.actor_name, f"subscribe to: {str_topic}")
self._socket.setsockopt_string(zmq.SUBSCRIBE, f"{str_topic}")
try: try:
Debug(self.actor_name, "recv thread started")
self._socket: zmq.Socket = self._context.socket(zmq.SUB)
self._socket.setsockopt(zmq.RCVTIMEO, 500)
self._socket.connect(xpub_url)
str_topic = f"{self.actor_name}"
Debug(self.actor_name, f"subscribe to: {str_topic}")
self._socket.setsockopt_string(zmq.SUBSCRIBE, f"{str_topic}")
self._start_event.set()
while self.run: while self.run:
try: try:
topic, msg_type, sender_topic, msg = self._socket.recv_multipart() topic, msg_type, sender_topic, msg = self._socket.recv_multipart()
@ -41,7 +43,9 @@ class Actor:
sender_topic = sender_topic.decode("utf-8") # Convert bytes to string sender_topic = sender_topic.decode("utf-8") # Convert bytes to string
except zmq.Again: except zmq.Again:
continue # No message received, continue to next iteration continue # No message received, continue to next iteration
except Exception: except Exception as e:
Error(self.actor_name, f"recv thread encountered an error: {e}")
traceback.print_exc()
continue continue
if msg_type == "text": if msg_type == "text":
msg = msg.decode("utf-8") # Convert bytes to string msg = msg.decode("utf-8") # Convert bytes to string
@ -57,6 +61,9 @@ class Actor:
traceback.print_exc() traceback.print_exc()
finally: finally:
self.run = False self.run = False
# In case there was an exception at startup signal
# the main thread.
self._start_event.set()
Debug(self.actor_name, "recv thread ended") Debug(self.actor_name, "recv thread ended")
def start(self, context: zmq.Context): def start(self, context: zmq.Context):
@ -64,7 +71,7 @@ class Actor:
self.run: bool = True self.run: bool = True
self._thread = threading.Thread(target=self._recv_thread) self._thread = threading.Thread(target=self._recv_thread)
self._thread.start() self._thread.start()
time.sleep(0.01) self._start_event.wait()
def disconnect_network(self, network): def disconnect_network(self, network):
Debug(self.actor_name, f"is disconnecting from {network}") Debug(self.actor_name, f"is disconnecting from {network}")

View File

@ -5,25 +5,97 @@ import zmq
from zmq.utils.monitor import recv_monitor_message from zmq.utils.monitor import recv_monitor_message
import time import time
import uuid import uuid
from .DebugLog import Debug, Error from .DebugLog import Debug, Error, Info
from .Config import xsub_url, xpub_url, router_url from .Config import xsub_url, xpub_url, router_url
from typing import Any, Dict from typing import Any, Dict
class ActorSender:
def __init__(self, context, topic):
self._context = context
self._topic = topic
self._connect_pub_socket()
def _connect_pub_socket(self):
Debug("ActorSender", f"Connecting pub socket {self._topic}")
self._pub_socket = self._context.socket(zmq.PUB)
monitor = self._pub_socket.get_monitor_socket()
self._pub_socket.setsockopt(zmq.LINGER, 0)
self._pub_socket.connect(xsub_url)
# Monitor handshake on the pub socket
while monitor.poll():
evt: Dict[str, Any] = {}
mon_evt = recv_monitor_message(monitor)
evt.update(mon_evt)
if evt["event"] == zmq.EVENT_MONITOR_STOPPED or evt["event"] == zmq.EVENT_HANDSHAKE_SUCCEEDED:
Debug("ActorSender", "Handshake received (Or Monitor stopped)")
break
self._pub_socket.disable_monitor()
monitor.close()
self._send_recv_router_msg()
def _send_recv_router_msg(self):
# Send a request to the router and wait for a response
req_socket = self._context.socket(zmq.REQ)
req_socket.connect(router_url)
try:
Debug("ActorSender", "Broker Check Request Sent")
req_socket.send_string("Request")
_ = req_socket.recv_string()
Debug("ActorSender", "Broker Check Response Received")
finally:
req_socket.close()
def send_txt_msg(self, msg):
Debug("ActorSender", f"[{self._topic}] send_txt_msg: {msg}")
self._pub_socket.send_multipart(
[self._topic.encode("utf8"), "text".encode("utf8"), "no_resp".encode("utf8"), msg.encode("utf8")]
)
def send_bin_msg(self, msg_type: str, msg):
Debug("ActorSender", f"[{self._topic}] send_bin_msg: {msg_type}")
self._pub_socket.send_multipart(
[self._topic.encode("utf8"), msg_type.encode("utf8"), "no_resp".encode("utf8"), msg]
)
def send_bin_request_msg(self, msg_type: str, msg, resp_topic: str):
Debug("ActorSender", f"[{self._topic}] send_bin_request_msg: {msg_type}")
self._pub_socket.send_multipart(
[self._topic.encode("utf8"), msg_type.encode("utf8"), resp_topic.encode("utf8"), msg]
)
def close(self):
self._pub_socket.close()
class ActorConnector: class ActorConnector:
def __init__(self, context, topic): def __init__(self, context, topic):
self._context = context self._context = context
self._topic = topic
self._connect_sub_socket()
self._sender = ActorSender(context, topic)
time.sleep(0.1) # Wait for the socket to connect
def _connect_sub_socket(self):
self._resp_socket = self._context.socket(zmq.SUB) self._resp_socket = self._context.socket(zmq.SUB)
monitor = self._resp_socket.get_monitor_socket()
self._resp_socket.setsockopt(zmq.LINGER, 0) self._resp_socket.setsockopt(zmq.LINGER, 0)
self._resp_socket.setsockopt(zmq.RCVTIMEO, 250) self._resp_socket.setsockopt(zmq.RCVTIMEO, 250)
self._resp_socket.connect(xpub_url) self._resp_socket.connect(xpub_url)
self._resp_topic = str(uuid.uuid4()) self._resp_topic = str(uuid.uuid4())
Debug("AgentConnector", f"subscribe to: {self._resp_topic}") Debug("ActorConnector", f"subscribe to: {self._resp_topic}")
self._resp_socket.setsockopt_string(zmq.SUBSCRIBE, f"{self._resp_topic}") self._resp_socket.setsockopt_string(zmq.SUBSCRIBE, f"{self._resp_topic}")
self._topic = topic while monitor.poll():
evt: Dict[str, Any] = {}
self._connect_pub_socket() mon_evt = recv_monitor_message(monitor)
evt.update(mon_evt)
Debug("ActorConnector", evt)
if evt["event"] == zmq.EVENT_MONITOR_STOPPED or evt["event"] == zmq.EVENT_HANDSHAKE_SUCCEEDED:
Debug("ActorConnector", "Handshake received (Or Monitor stopped)")
break
self._resp_socket.disable_monitor()
monitor.close()
self._send_recv_router_msg()
def _send_recv_router_msg(self): def _send_recv_router_msg(self):
# Send a request to the router and wait for a response # Send a request to the router and wait for a response
@ -37,48 +109,38 @@ class ActorConnector:
finally: finally:
req_socket.close() req_socket.close()
def _connect_pub_socket(self):
self._pub_socket = self._context.socket(zmq.PUB)
self._pub_socket.setsockopt(zmq.LINGER, 0)
monitor = self._pub_socket.get_monitor_socket()
self._pub_socket.connect(xsub_url)
# Monitor handshake on the pub socket
while monitor.poll():
evt: Dict[str, Any] = {}
mon_evt = recv_monitor_message(monitor)
evt.update(mon_evt)
if evt["event"] == zmq.EVENT_MONITOR_STOPPED or evt["event"] == zmq.EVENT_HANDSHAKE_SUCCEEDED:
Debug("ActorConnector", "Handshake received (Or Monitor stopped)")
break
self._pub_socket.disable_monitor()
monitor.close()
self._send_recv_router_msg()
def send_txt_msg(self, msg): def send_txt_msg(self, msg):
self._pub_socket.send_multipart( self._sender.send_txt_msg(msg)
[self._topic.encode("utf8"), "text".encode("utf8"), self._resp_topic.encode("utf8"), msg.encode("utf8")]
)
def send_bin_msg(self, msg_type: str, msg): def send_bin_msg(self, msg_type: str, msg):
self._pub_socket.send_multipart( self._sender.send_bin_msg(msg_type, msg)
[self._topic.encode("utf8"), msg_type.encode("utf8"), self._resp_topic.encode("utf8"), msg]
)
def binary_request(self, msg_type: str, msg, retry=5): def binary_request(self, msg_type: str, msg, retry=5):
self._pub_socket.send_multipart( original_timeout: int = 0
[self._topic.encode("utf8"), msg_type.encode("utf8"), self._resp_topic.encode("utf8"), msg] if retry == -1:
) original_timeout = self._resp_socket.getsockopt(zmq.RCVTIMEO)
for i in range(retry + 1): self._resp_socket.setsockopt(zmq.RCVTIMEO, 1000)
try:
resp_topic, resp_msg_type, resp_sender_topic, resp = self._resp_socket.recv_multipart() try:
return resp_topic, resp_msg_type, resp_sender_topic, resp self._sender.send_bin_request_msg(msg_type, msg, self._resp_topic)
except zmq.Again: while retry == -1 or retry > 0:
Debug("ActorConnector", f"binary_request: No response received. retry_count={i}, max_retry={retry}") try:
time.sleep(0.01) # Wait a bit before retrying topic, resp_msg_type, _, resp = self._resp_socket.recv_multipart()
continue return topic, resp_msg_type, resp
Error("ActorConnector", "binary_request: No response received. Giving up.") except zmq.Again:
return None, None, None, None Debug(
"ActorConnector", f"{self._topic}: No response received. retry_count={retry}, max_retry={retry}"
)
time.sleep(0.01)
if retry != -1:
retry -= 1
finally:
if retry == -1:
self._resp_socket.setsockopt(zmq.RCVTIMEO, original_timeout)
Error("ActorConnector", f"{self._topic}: No response received. Giving up.")
return None, None, None
def close(self): def close(self):
self._pub_socket.close() self._sender.close()
self._resp_socket.close() self._resp_socket.close()

View File

@ -12,6 +12,7 @@ class Broker:
self._xpub: zmq.Socket = None self._xpub: zmq.Socket = None
self._xsub: zmq.Socket = None self._xsub: zmq.Socket = None
self._router: zmq.Socket = None self._router: zmq.Socket = None
self._start_event = threading.Event()
def _init_sockets(self): def _init_sockets(self):
try: try:
@ -44,8 +45,9 @@ class Broker:
self._run = True self._run = True
self._broker_thread: threading.Thread = threading.Thread(target=self.thread_fn) self._broker_thread: threading.Thread = threading.Thread(target=self.thread_fn)
self._broker_thread.start() self._broker_thread.start()
time.sleep(0.01) self._start_event.wait()
return True # this will be false if the thread is not running
return self._run
def stop(self): def stop(self):
if not self._run: if not self._run:
@ -67,6 +69,7 @@ class Broker:
if not self._init_sockets(): if not self._init_sockets():
Debug("BROKER", "Receive thread not started since sockets were not initialized") Debug("BROKER", "Receive thread not started since sockets were not initialized")
self._run = False self._run = False
self._start_event.set()
return return
# Poll sockets for events # Poll sockets for events
@ -76,6 +79,8 @@ class Broker:
self._poller.register(self._router, zmq.POLLIN) self._poller.register(self._router, zmq.POLLIN)
Info("BROKER", "Started. Waiting for events") Info("BROKER", "Started. Waiting for events")
# signal to the main thread that Broker has started
self._start_event.set()
# Receive msgs, forward and process # Receive msgs, forward and process
while self._run: while self._run:
events = dict(self._poller.poll(500)) events = dict(self._poller.poll(500))
@ -131,6 +136,8 @@ def main():
Info("BROKER", "Running.") Info("BROKER", "Running.")
last_time = current_time last_time = current_time
try: try:
# Hang out for a while and print out
# status every now and then
time.sleep(0.5) time.sleep(0.5)
except KeyboardInterrupt: except KeyboardInterrupt:
Info("BROKER", "KeyboardInterrupt. Stopping the broker.") Info("BROKER", "KeyboardInterrupt. Stopping the broker.")

View File

@ -1,7 +1,7 @@
from autogencap.Constants import Directory_Svc_Topic from autogencap.Constants import Directory_Svc_Topic
from autogencap.Config import xpub_url, xsub_url, router_url from autogencap.Config import xpub_url, xsub_url, router_url
from autogencap.DebugLog import Debug, Info, Error from autogencap.DebugLog import Debug, Info, Error
from autogencap.ActorConnector import ActorConnector from autogencap.ActorConnector import ActorConnector, ActorSender
from autogencap.Actor import Actor from autogencap.Actor import Actor
from autogencap.Broker import Broker from autogencap.Broker import Broker
from autogencap.proto.CAP_pb2 import ( from autogencap.proto.CAP_pb2 import (
@ -12,7 +12,11 @@ from autogencap.proto.CAP_pb2 import (
Ping, Ping,
Pong, Pong,
ActorInfoCollection, ActorInfoCollection,
Error as ErrorMsg,
ErrorCode,
) )
from autogencap.utility import report_error_msg
import zmq import zmq
import threading import threading
import time import time
@ -30,7 +34,7 @@ class DirectoryActor(Actor):
def _process_bin_msg(self, msg: bytes, msg_type: str, topic: str, sender: str) -> bool: def _process_bin_msg(self, msg: bytes, msg_type: str, topic: str, sender: str) -> bool:
if msg_type == ActorRegistration.__name__: if msg_type == ActorRegistration.__name__:
self._actor_registration_msg_handler(topic, msg_type, msg) self._actor_registration_msg_handler(topic, msg_type, msg, sender)
elif msg_type == ActorLookup.__name__: elif msg_type == ActorLookup.__name__:
self._actor_lookup_msg_handler(topic, msg_type, msg, sender) self._actor_lookup_msg_handler(topic, msg_type, msg, sender)
elif msg_type == Ping.__name__: elif msg_type == Ping.__name__:
@ -43,20 +47,26 @@ class DirectoryActor(Actor):
Info("DirectorySvc", f"Ping received: {sender_topic}") Info("DirectorySvc", f"Ping received: {sender_topic}")
pong = Pong() pong = Pong()
serialized_msg = pong.SerializeToString() serialized_msg = pong.SerializeToString()
sender_connection = ActorConnector(self._context, sender_topic) sender_connection = ActorSender(self._context, sender_topic)
sender_connection.send_bin_msg(Pong.__name__, serialized_msg) sender_connection.send_bin_msg(Pong.__name__, serialized_msg)
def _actor_registration_msg_handler(self, topic: str, msg_type: str, msg: bytes): def _actor_registration_msg_handler(self, topic: str, msg_type: str, msg: bytes, sender_topic: str):
actor_reg = ActorRegistration() actor_reg = ActorRegistration()
actor_reg.ParseFromString(msg) actor_reg.ParseFromString(msg)
Info("DirectorySvc", f"Actor registration: {actor_reg.actor_info.name}") Info("DirectorySvc", f"Actor registration: {actor_reg.actor_info.name}")
name = actor_reg.actor_info.name name = actor_reg.actor_info.name
# TODO (Future DirectorySv PR) network_id should be namespace prefixed to support multiple networks # TODO (Future DirectorySv PR) network_id should be namespace prefixed to support multiple networks
actor_reg.actor_info.name + self._network_prefix actor_reg.actor_info.name + self._network_prefix
err = ErrorMsg()
if name in self._registered_actors: if name in self._registered_actors:
Error("DirectorySvc", f"Actor already registered: {name}") Error("DirectorySvc", f"Actor already registered: {name}")
return err.code = ErrorCode.EC_ALREADY_EXISTS
self._registered_actors[name] = actor_reg.actor_info else:
self._registered_actors[name] = actor_reg.actor_info
sender_connection = ActorSender(self._context, sender_topic)
serialized_msg = err.SerializeToString()
sender_connection.send_bin_msg(ErrorMsg.__name__, serialized_msg)
def _actor_lookup_msg_handler(self, topic: str, msg_type: str, msg: bytes, sender_topic: str): def _actor_lookup_msg_handler(self, topic: str, msg_type: str, msg: bytes, sender_topic: str):
actor_lookup = ActorLookup() actor_lookup = ActorLookup()
@ -83,7 +93,7 @@ class DirectoryActor(Actor):
else: else:
Error("DirectorySvc", f"Actor not found: {actor_lookup.actor_info.name}") Error("DirectorySvc", f"Actor not found: {actor_lookup.actor_info.name}")
sender_connection = ActorConnector(self._context, sender_topic) sender_connection = ActorSender(self._context, sender_topic)
serialized_msg = actor_lookup_resp.SerializeToString() serialized_msg = actor_lookup_resp.SerializeToString()
sender_connection.send_bin_msg(ActorLookupResponse.__name__, serialized_msg) sender_connection.send_bin_msg(ActorLookupResponse.__name__, serialized_msg)
@ -98,12 +108,13 @@ class DirectorySvc:
Debug("DirectorySvc", "Pinging existing DirectorySvc") Debug("DirectorySvc", "Pinging existing DirectorySvc")
ping = Ping() ping = Ping()
serialized_msg = ping.SerializeToString() serialized_msg = ping.SerializeToString()
_, _, _, resp = self._directory_connector.binary_request(Ping.__name__, serialized_msg, retry=0) _, _, resp = self._directory_connector.binary_request(Ping.__name__, serialized_msg, retry=0)
if resp is None: if resp is None:
return True return True
return False return False
def start(self): def start(self):
Debug("DirectorySvc", "Starting.")
self._directory_connector = ActorConnector(self._context, Directory_Svc_Topic) self._directory_connector = ActorConnector(self._context, Directory_Svc_Topic)
if self._no_other_directory(): if self._no_other_directory():
self._directory_actor = DirectoryActor(Directory_Svc_Topic, "Directory Service") self._directory_actor = DirectoryActor(Directory_Svc_Topic, "Directory Service")
@ -124,7 +135,8 @@ class DirectorySvc:
actor_reg = ActorRegistration() actor_reg = ActorRegistration()
actor_reg.actor_info.CopyFrom(actor_info) actor_reg.actor_info.CopyFrom(actor_info)
serialized_msg = actor_reg.SerializeToString() serialized_msg = actor_reg.SerializeToString()
self._directory_connector.send_bin_msg(ActorRegistration.__name__, serialized_msg) _, _, resp = self._directory_connector.binary_request(ActorRegistration.__name__, serialized_msg)
report_error_msg(resp, "DirectorySvc")
def register_actor_by_name(self, actor_name: str): def register_actor_by_name(self, actor_name: str):
actor_info = ActorInfo(name=actor_name) actor_info = ActorInfo(name=actor_name)
@ -134,7 +146,7 @@ class DirectorySvc:
actor_info = ActorInfo(name=name_regex) actor_info = ActorInfo(name=name_regex)
actor_lookup = ActorLookup(actor_info=actor_info) actor_lookup = ActorLookup(actor_info=actor_info)
serialized_msg = actor_lookup.SerializeToString() serialized_msg = actor_lookup.SerializeToString()
_, _, _, resp = self._directory_connector.binary_request(ActorLookup.__name__, serialized_msg) _, _, resp = self._directory_connector.binary_request(ActorLookup.__name__, serialized_msg)
actor_lookup_resp = ActorLookupResponse() actor_lookup_resp = ActorLookupResponse()
actor_lookup_resp.ParseFromString(resp) actor_lookup_resp.ParseFromString(resp)
return actor_lookup_resp return actor_lookup_resp
@ -185,6 +197,8 @@ def main():
Info("DirectorySvc", "Running.") Info("DirectorySvc", "Running.")
last_time = current_time last_time = current_time
try: try:
# Hang out for a while and print out
# status every now and then
time.sleep(0.5) time.sleep(0.5)
except KeyboardInterrupt: except KeyboardInterrupt:
Info("DirectorySvc", "KeyboardInterrupt. Stopping the DirectorySvc.") Info("DirectorySvc", "KeyboardInterrupt. Stopping the DirectorySvc.")

View File

@ -33,6 +33,7 @@ class LocalActorNetwork:
if self._directory_svc is None: if self._directory_svc is None:
self._directory_svc = DirectorySvc(self._context) self._directory_svc = DirectorySvc(self._context)
self._directory_svc.start() self._directory_svc.start()
time.sleep(0.25) # Process queued thread events in Broker and Directory
def register(self, actor: Actor): def register(self, actor: Actor):
self._init_runtime() self._init_runtime()

View File

@ -32,7 +32,10 @@ class AutoGenConnector:
""" """
msg = GenReplyReq() msg = GenReplyReq()
serialized_msg = msg.SerializeToString() serialized_msg = msg.SerializeToString()
_, _, _, resp = self._can_channel.binary_request(type(msg).__name__, serialized_msg) # Setting retry to -1 to keep trying until a response is received
# This normal AutoGen behavior but does not handle the case when an AutoGen agent
# is not running. In that case, the connector will keep trying indefinitely.
_, _, resp = self._can_channel.binary_request(type(msg).__name__, serialized_msg, retry=-1)
gen_reply_resp = GenReplyResp() gen_reply_resp = GenReplyResp()
gen_reply_resp.ParseFromString(resp) gen_reply_resp.ParseFromString(resp)
return gen_reply_resp.data return gen_reply_resp.data

View File

@ -33,6 +33,8 @@ class CAPGroupChatManager:
def _wait_for_user_exit(self) -> None: def _wait_for_user_exit(self) -> None:
try: try:
while self.is_running(): while self.is_running():
# Hang out for a while and print out
# status every now and then
time.sleep(0.5) time.sleep(0.5)
except KeyboardInterrupt: except KeyboardInterrupt:
print("Interrupted by user, shutting down.") print("Interrupted by user, shutting down.")

View File

@ -20,7 +20,7 @@ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
_globals = globals() _globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "Autogen_pb2", _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "Autogen_pb2", _globals)
if _descriptor._USE_C_DESCRIPTORS is False: if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None DESCRIPTOR._options = None
_globals["_DATAMAP_DATAENTRY"]._options = None _globals["_DATAMAP_DATAENTRY"]._options = None
_globals["_DATAMAP_DATAENTRY"]._serialized_options = b"8\001" _globals["_DATAMAP_DATAENTRY"]._serialized_options = b"8\001"

View File

@ -3,6 +3,19 @@ syntax = "proto3";
// Get protoc here https://github.com/protocolbuffers/protobuf/releases // Get protoc here https://github.com/protocolbuffers/protobuf/releases
// .\protoc --python_out=. --pyi_out=. CAP.proto // .\protoc --python_out=. --pyi_out=. CAP.proto
enum ErrorCode {
option allow_alias = true;
EC_OK = 0;
EC_NOT_FOUND = 1;
EC_ALREADY_EXISTS = 2;
EC_MAX = 2; // IMPORTANT: Update this if you add more error codes
}
message Error {
ErrorCode code = 1;
optional string message = 2;
}
message ActorInfo { message ActorInfo {
string name = 1; string name = 1;
optional string namespace = 2; optional string namespace = 2;

View File

@ -14,26 +14,32 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
b'\n\tCAP.proto"i\n\tActorInfo\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x16\n\tnamespace\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\x0c\n\n_namespaceB\x0e\n\x0c_description"3\n\x11\x41\x63torRegistration\x12\x1e\n\nactor_info\x18\x01 \x01(\x0b\x32\n.ActorInfo"A\n\x0b\x41\x63torLookup\x12#\n\nactor_info\x18\x01 \x01(\x0b\x32\n.ActorInfoH\x00\x88\x01\x01\x42\r\n\x0b_actor_info"4\n\x13\x41\x63torInfoCollection\x12\x1d\n\tinfo_coll\x18\x01 \x03(\x0b\x32\n.ActorInfo"X\n\x13\x41\x63torLookupResponse\x12\r\n\x05\x66ound\x18\x01 \x01(\x08\x12(\n\x05\x61\x63tor\x18\x02 \x01(\x0b\x32\x14.ActorInfoCollectionH\x00\x88\x01\x01\x42\x08\n\x06_actor"\x06\n\x04Ping"\x06\n\x04Pongb\x06proto3' b'\n\tCAP.proto"C\n\x05\x45rror\x12\x18\n\x04\x63ode\x18\x01 \x01(\x0e\x32\n.ErrorCode\x12\x14\n\x07message\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\n\n\x08_message"i\n\tActorInfo\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x16\n\tnamespace\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\x0c\n\n_namespaceB\x0e\n\x0c_description"3\n\x11\x41\x63torRegistration\x12\x1e\n\nactor_info\x18\x01 \x01(\x0b\x32\n.ActorInfo"A\n\x0b\x41\x63torLookup\x12#\n\nactor_info\x18\x01 \x01(\x0b\x32\n.ActorInfoH\x00\x88\x01\x01\x42\r\n\x0b_actor_info"4\n\x13\x41\x63torInfoCollection\x12\x1d\n\tinfo_coll\x18\x01 \x03(\x0b\x32\n.ActorInfo"X\n\x13\x41\x63torLookupResponse\x12\r\n\x05\x66ound\x18\x01 \x01(\x08\x12(\n\x05\x61\x63tor\x18\x02 \x01(\x0b\x32\x14.ActorInfoCollectionH\x00\x88\x01\x01\x42\x08\n\x06_actor"\x06\n\x04Ping"\x06\n\x04Pong*O\n\tErrorCode\x12\t\n\x05\x45\x43_OK\x10\x00\x12\x10\n\x0c\x45\x43_NOT_FOUND\x10\x01\x12\x15\n\x11\x45\x43_ALREADY_EXISTS\x10\x02\x12\n\n\x06\x45\x43_MAX\x10\x02\x1a\x02\x10\x01\x62\x06proto3'
) )
_globals = globals() _globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "CAP_pb2", _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "CAP_pb2", _globals)
if _descriptor._USE_C_DESCRIPTORS is False: if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None DESCRIPTOR._options = None
_globals["_ACTORINFO"]._serialized_start = 13 _globals["_ERRORCODE"]._options = None
_globals["_ACTORINFO"]._serialized_end = 118 _globals["_ERRORCODE"]._serialized_options = b"\020\001"
_globals["_ACTORREGISTRATION"]._serialized_start = 120 _globals["_ERRORCODE"]._serialized_start = 469
_globals["_ACTORREGISTRATION"]._serialized_end = 171 _globals["_ERRORCODE"]._serialized_end = 548
_globals["_ACTORLOOKUP"]._serialized_start = 173 _globals["_ERROR"]._serialized_start = 13
_globals["_ACTORLOOKUP"]._serialized_end = 238 _globals["_ERROR"]._serialized_end = 80
_globals["_ACTORINFOCOLLECTION"]._serialized_start = 240 _globals["_ACTORINFO"]._serialized_start = 82
_globals["_ACTORINFOCOLLECTION"]._serialized_end = 292 _globals["_ACTORINFO"]._serialized_end = 187
_globals["_ACTORLOOKUPRESPONSE"]._serialized_start = 294 _globals["_ACTORREGISTRATION"]._serialized_start = 189
_globals["_ACTORLOOKUPRESPONSE"]._serialized_end = 382 _globals["_ACTORREGISTRATION"]._serialized_end = 240
_globals["_PING"]._serialized_start = 384 _globals["_ACTORLOOKUP"]._serialized_start = 242
_globals["_PING"]._serialized_end = 390 _globals["_ACTORLOOKUP"]._serialized_end = 307
_globals["_PONG"]._serialized_start = 392 _globals["_ACTORINFOCOLLECTION"]._serialized_start = 309
_globals["_PONG"]._serialized_end = 398 _globals["_ACTORINFOCOLLECTION"]._serialized_end = 361
_globals["_ACTORLOOKUPRESPONSE"]._serialized_start = 363
_globals["_ACTORLOOKUPRESPONSE"]._serialized_end = 451
_globals["_PING"]._serialized_start = 453
_globals["_PING"]._serialized_end = 459
_globals["_PONG"]._serialized_start = 461
_globals["_PONG"]._serialized_end = 467
# @@protoc_insertion_point(module_scope) # @@protoc_insertion_point(module_scope)

View File

@ -1,4 +1,5 @@
from google.protobuf.internal import containers as _containers from google.protobuf.internal import containers as _containers
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message from google.protobuf import message as _message
from typing import ( from typing import (
@ -11,6 +12,26 @@ from typing import (
DESCRIPTOR: _descriptor.FileDescriptor DESCRIPTOR: _descriptor.FileDescriptor
class ErrorCode(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
EC_OK: _ClassVar[ErrorCode]
EC_NOT_FOUND: _ClassVar[ErrorCode]
EC_ALREADY_EXISTS: _ClassVar[ErrorCode]
EC_MAX: _ClassVar[ErrorCode]
EC_OK: ErrorCode
EC_NOT_FOUND: ErrorCode
EC_ALREADY_EXISTS: ErrorCode
EC_MAX: ErrorCode
class Error(_message.Message):
__slots__ = ("code", "message")
CODE_FIELD_NUMBER: _ClassVar[int]
MESSAGE_FIELD_NUMBER: _ClassVar[int]
code: ErrorCode
message: str
def __init__(self, code: _Optional[_Union[ErrorCode, str]] = ..., message: _Optional[str] = ...) -> None: ...
class ActorInfo(_message.Message): class ActorInfo(_message.Message):
__slots__ = ("name", "namespace", "description") __slots__ = ("name", "namespace", "description")
NAME_FIELD_NUMBER: _ClassVar[int] NAME_FIELD_NUMBER: _ClassVar[int]

View File

@ -0,0 +1,10 @@
from autogencap.DebugLog import Error
from autogencap.proto.CAP_pb2 import Error as ErrorMsg, ErrorCode
def report_error_msg(msg: ErrorMsg, src: str):
if msg is not None:
err = ErrorMsg()
err.ParseFromString(msg)
if err.code != ErrorCode.EC_OK:
Error(src, f"Error response: code[{err.code}] msg[{err.message}]")

View File

@ -23,6 +23,8 @@ def cap_ag_pair_demo():
# Wait for the pair to finish # Wait for the pair to finish
try: try:
while pair.running(): while pair.running():
# Hang out for a while and print out
# status every now and then
time.sleep(0.5) time.sleep(0.5)
except KeyboardInterrupt: except KeyboardInterrupt:
print("Interrupted by user, shutting down.") print("Interrupted by user, shutting down.")

View File

@ -1,6 +1,7 @@
import time import time
from AppAgents import GreeterAgent from AppAgents import GreeterAgent
from autogencap.LocalActorNetwork import LocalActorNetwork from autogencap.LocalActorNetwork import LocalActorNetwork
from autogencap.DebugLog import Error
def simple_actor_demo(): def simple_actor_demo():
@ -17,8 +18,11 @@ def simple_actor_demo():
network.connect() network.connect()
# Get a channel to the actor # Get a channel to the actor
greeter_link = network.lookup_actor("Greeter") greeter_link = network.lookup_actor("Greeter")
# Send a message to the actor if greeter_link:
greeter_link.send_txt_msg("Hello World!") # Send a message to the actor
# Cleanup greeter_link.send_txt_msg("Hello World!")
greeter_link.close() # Cleanup
greeter_link.close()
else:
Error("simple_actor_demo", "Could not find Greeter")
network.disconnect() network.disconnect()

View File

@ -3,6 +3,7 @@ from typing import List
from AppAgents import GreeterAgent, FidelityAgent from AppAgents import GreeterAgent, FidelityAgent
from autogencap.LocalActorNetwork import LocalActorNetwork from autogencap.LocalActorNetwork import LocalActorNetwork
from autogencap.proto.CAP_pb2 import ActorInfo from autogencap.proto.CAP_pb2 import ActorInfo
from autogencap.DebugLog import Info
def list_agents(): def list_agents():
@ -22,8 +23,11 @@ def list_agents():
# Get a list of actors # Get a list of actors
actor_infos: List[ActorInfo] = network.lookup_actor_info(name_regex=".*") actor_infos: List[ActorInfo] = network.lookup_actor_info(name_regex=".*")
# Print out all actors found # Print out all actors found
Info("list_agents", f"{len(actor_infos)} actors found:")
for actor_info in actor_infos: for actor_info in actor_infos:
print(f"Name: {actor_info.name}, Namespace: {actor_info.namespace}, Description: {actor_info.description}") Info(
time.sleep(1) "list_agents",
f"Name: {actor_info.name}, Namespace: {actor_info.namespace}, Description: {actor_info.description}",
)
# Cleanup # Cleanup
network.disconnect() network.disconnect()