working v1
This commit is contained in:
commit
5b54f3f636
19 changed files with 403 additions and 0 deletions
BIN
__pycache__/agent.cpython-38.pyc
Normal file
BIN
__pycache__/agent.cpython-38.pyc
Normal file
Binary file not shown.
BIN
__pycache__/mail.cpython-38.pyc
Normal file
BIN
__pycache__/mail.cpython-38.pyc
Normal file
Binary file not shown.
BIN
__pycache__/mailroom.cpython-38.pyc
Normal file
BIN
__pycache__/mailroom.cpython-38.pyc
Normal file
Binary file not shown.
BIN
__pycache__/message.cpython-38.pyc
Normal file
BIN
__pycache__/message.cpython-38.pyc
Normal file
Binary file not shown.
BIN
__pycache__/messenger.cpython-38.pyc
Normal file
BIN
__pycache__/messenger.cpython-38.pyc
Normal file
Binary file not shown.
BIN
__pycache__/schemes.cpython-38.pyc
Normal file
BIN
__pycache__/schemes.cpython-38.pyc
Normal file
Binary file not shown.
BIN
__pycache__/sdk.cpython-38.pyc
Normal file
BIN
__pycache__/sdk.cpython-38.pyc
Normal file
Binary file not shown.
BIN
__pycache__/server.cpython-38.pyc
Normal file
BIN
__pycache__/server.cpython-38.pyc
Normal file
Binary file not shown.
BIN
__pycache__/session.cpython-38.pyc
Normal file
BIN
__pycache__/session.cpython-38.pyc
Normal file
Binary file not shown.
BIN
__pycache__/typs.cpython-38.pyc
Normal file
BIN
__pycache__/typs.cpython-38.pyc
Normal file
Binary file not shown.
98
agent.py
Normal file
98
agent.py
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
import json
|
||||
import asyncio
|
||||
import websockets
|
||||
|
||||
import typs
|
||||
|
||||
|
||||
class Agent:
|
||||
"""Session interface for Crimata Agent
|
||||
|
||||
Receive core functionalities for communicating with Crimata
|
||||
Agent in an OOP way.
|
||||
|
||||
"""
|
||||
def __init__(self, connection):
|
||||
self.connection = connection
|
||||
|
||||
# Submit a request for info, return response.
|
||||
# Must disclose what service it's for.
|
||||
async def fetch(self, entities, service):
|
||||
|
||||
# Assert list.
|
||||
if type(entities) == str:
|
||||
entities = [entities]
|
||||
|
||||
print(f"Fetching {[e for e in entities]} for {service}")
|
||||
|
||||
# Build intent.
|
||||
params = {
|
||||
"service": service,
|
||||
"entities": entities
|
||||
}; intent = typs.Intent("fetch", params)
|
||||
|
||||
# Send intent to agent, wait for response.
|
||||
await self.send_agent_intent(intent)
|
||||
response = await self.recv_agent_intent()
|
||||
|
||||
# Parse response and return entities.
|
||||
entities = response.params.get("found")
|
||||
print(f"Fetch response: {entities}")
|
||||
return entities
|
||||
|
||||
# Text the client something. Also, let agent know
|
||||
# when your service is complete via the complete
|
||||
# attribute.
|
||||
# Must disclose what service it's for.
|
||||
async def notify(self, text, end=False):
|
||||
|
||||
print(f"Notifying: {text} for {self.service}")
|
||||
|
||||
params = {
|
||||
"service": self.service,
|
||||
"text": text,
|
||||
"end": end
|
||||
}
|
||||
|
||||
# Build the intent
|
||||
intent = typs.Intent("notify", params)
|
||||
|
||||
# Send intent to agent.
|
||||
await self.send_agent_intent(intent)
|
||||
|
||||
# Get user info.
|
||||
async def sync(self):
|
||||
|
||||
intent = typs.Intent("sync", params={})
|
||||
|
||||
# Send intent to agent.
|
||||
await self.send_agent_intent(intent)
|
||||
|
||||
# Recv and return profile.
|
||||
intent = await self.recv_agent_intent()
|
||||
profile = intent.params.get("profile")
|
||||
return profile
|
||||
|
||||
async def recv_agent_intent(self):
|
||||
package = await self.connection.recv()
|
||||
intent = self.__decode(package)
|
||||
return intent
|
||||
|
||||
async def send_agent_intent(self, intent):
|
||||
package = self.__encode(intent)
|
||||
await self.connection.send(package)
|
||||
|
||||
def __encode(self, intent: typs.Intent):
|
||||
package = json.dumps(intent.__dict__)
|
||||
return package
|
||||
|
||||
def __decode(self, package) -> typs.Intent:
|
||||
jpackage = json.loads(package)
|
||||
name = jpackage.get("name")
|
||||
params = jpackage.get("params")
|
||||
intent = typs.Intent(name, params)
|
||||
return intent
|
||||
|
||||
|
||||
|
||||
|
||||
42
mail.py
Normal file
42
mail.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# mail.py
|
||||
|
||||
import typs
|
||||
import mailroom
|
||||
|
||||
|
||||
class Mail:
|
||||
"""Session interface for mailroom.
|
||||
|
||||
Two main IO methods. Will translate intents to mail and vice versa.
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
# Receive intent.
|
||||
async def mailbox_recv(self):
|
||||
mail = await mailroom.get_mail(self.crimata_id)
|
||||
intent = self.__decode(mail)
|
||||
return intent
|
||||
|
||||
# Send intent.
|
||||
def mailbox_send(self, intent):
|
||||
mail = self.__encode(intent)
|
||||
mailroom.put_mail(self.crimata_id, mail)
|
||||
|
||||
def __encode(self, intent: typs.Intent) -> typs.Mail:
|
||||
p = intent.params
|
||||
owner = self.crimata_id
|
||||
target = p.get("target")
|
||||
text = p.get("text")
|
||||
mail = typs.Mail(owner, target, text)
|
||||
return mail
|
||||
|
||||
@staticmethod
|
||||
def __decode(mail: typs.Mail) -> typs.Intent:
|
||||
name = "notify"
|
||||
params = {
|
||||
"text": mail.text #dev only
|
||||
}
|
||||
intent = typs.Intent(name, params)
|
||||
return intent
|
||||
|
||||
42
mailroom.py
Normal file
42
mailroom.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# mailroom.py
|
||||
|
||||
import queue
|
||||
import asyncio
|
||||
|
||||
import typs
|
||||
|
||||
# Subcribers (Crimata IDs)
|
||||
subs = []
|
||||
|
||||
# Mailroom (all mailboxes)
|
||||
que = queue.Queue()
|
||||
ref = {}
|
||||
|
||||
# Mailroom functions
|
||||
# ------------------
|
||||
|
||||
# Create mailbox and add to mailroom.
|
||||
def create_mailbox(crimata_id):
|
||||
mailbox = typs.MailBox(name=crimata_id)
|
||||
que.put(mailbox)
|
||||
ref.update({crimata_id: mailbox})
|
||||
subs.append(crimata_id)
|
||||
|
||||
# Get mailbox by Crimata ID.
|
||||
def get_mailbox(crimata_id):
|
||||
if not crimata_id in subs:
|
||||
create_mailbox(crimata_id)
|
||||
mailbox = ref.get(crimata_id)
|
||||
return mailbox
|
||||
|
||||
# Inbox -> receiving mail.
|
||||
async def get_mail(crimata_id):
|
||||
mailbox = get_mailbox(crimata_id)
|
||||
mail = await mailbox.inbox.get()
|
||||
return mail
|
||||
|
||||
# Outbox -> sending mail.
|
||||
def put_mail(crimata_id, mail: typs.Mail):
|
||||
mailbox = get_mailbox(crimata_id)
|
||||
mailbox.outbox.put(mail)
|
||||
|
||||
18
main.py
Normal file
18
main.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# server.py
|
||||
|
||||
import typs
|
||||
import queue
|
||||
import asyncio
|
||||
import websockets
|
||||
|
||||
import server
|
||||
import message
|
||||
|
||||
|
||||
# Run the ws server and the messenger concurrently.
|
||||
async def main():
|
||||
print(f"Crimata Messenger")
|
||||
await asyncio.gather(server.lift(), message.run())
|
||||
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(main())
|
||||
37
message.py
Normal file
37
message.py
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# messenge.py
|
||||
|
||||
import asyncio
|
||||
|
||||
import mailroom
|
||||
|
||||
|
||||
# Independent loop that updates mailboxes.
|
||||
async def messenger():
|
||||
|
||||
print("Running Messenger")
|
||||
|
||||
while True:
|
||||
|
||||
# Yield if no mailboxes.
|
||||
if mailroom.que.empty():
|
||||
await asyncio.sleep(1)
|
||||
continue
|
||||
|
||||
# Grab a mailbox.
|
||||
mailbox = mailroom.que.get()
|
||||
print(f"Handling mailbox: {mailbox.name}.")
|
||||
|
||||
# Handle every message in outbox.
|
||||
while not mailbox.outbox.empty():
|
||||
message = mailbox.outbox.get()
|
||||
|
||||
# Get mailbox of target and put mail there.
|
||||
target_mailbox = mailroom.get_mailbox(message.target)
|
||||
await target_mailbox.inbox.put(message)
|
||||
|
||||
# Put the mailbox back
|
||||
mailroom.que.put(mailbox)
|
||||
await asyncio.sleep(1)
|
||||
|
||||
async def run():
|
||||
await messenger()
|
||||
30
schemes.py
Normal file
30
schemes.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# schemes.py
|
||||
|
||||
|
||||
class Schemes:
|
||||
|
||||
def __init__(self):
|
||||
self.service = None
|
||||
|
||||
async def handle_intent(self, intent):
|
||||
print(f"Handling intent {intent.name}.")
|
||||
|
||||
# Set the service
|
||||
self.service = intent.name
|
||||
|
||||
if intent.name == "init":
|
||||
await self.init(intent)
|
||||
if intent.name == "message":
|
||||
self.message(intent)
|
||||
|
||||
async def init(self, intent):
|
||||
self.crimata_id = intent.params.get("crimata_id")
|
||||
await self.notify("Messaging is live.")
|
||||
|
||||
def message(self, intent):
|
||||
text = intent.params.get("text")
|
||||
target = intent.params.get("target") #crimata_id
|
||||
print(f"Messaging {target}: '{text}'")
|
||||
|
||||
# Uses mail.Mail interface.
|
||||
self.mailbox_send(intent)
|
||||
27
server.py
Normal file
27
server.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# server.py
|
||||
|
||||
import asyncio
|
||||
import websockets
|
||||
|
||||
import session
|
||||
|
||||
HOST = "localhost"
|
||||
PORT = 8764
|
||||
|
||||
|
||||
# Makes instance of a Messenger session for every client that connects.
|
||||
async def launch_session(connection, path):
|
||||
s = session.Session(connection)
|
||||
|
||||
await asyncio.gather(
|
||||
|
||||
s.do_agent_intents(),
|
||||
|
||||
s.deliver_mail()
|
||||
|
||||
)
|
||||
|
||||
# Run run for every new connection.
|
||||
async def lift():
|
||||
print(f"Listening for connections on {HOST}:{PORT}")
|
||||
await websockets.serve(launch_session, HOST, PORT)
|
||||
81
session.py
Normal file
81
session.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# session.py
|
||||
|
||||
import time
|
||||
import asyncio
|
||||
|
||||
import mail
|
||||
import agent
|
||||
import schemes
|
||||
|
||||
|
||||
class Session(schemes.Schemes, agent.Agent, mail.Mail):
|
||||
"""Launch instance for every client connection.
|
||||
|
||||
Will recv messages from client and push them to mailbox.
|
||||
Also, will pull messages from mailbox and send to client.
|
||||
|
||||
"""
|
||||
def __init__(self, connection):
|
||||
agent.Agent.__init__(self, connection)
|
||||
|
||||
self.crimata_id = False
|
||||
|
||||
print("Launched new session")
|
||||
|
||||
# Recv intents run desired endpoint.
|
||||
async def do_agent_intents(self):
|
||||
while True:
|
||||
|
||||
# Recv intent from agent.
|
||||
intent = await self.recv_agent_intent()
|
||||
print(f"Intent: {intent.name}")
|
||||
|
||||
# Call corresponding endpoint.
|
||||
await self.handle_intent(intent)
|
||||
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
# Send mail back to agent.
|
||||
async def deliver_mail(self):
|
||||
while True:
|
||||
|
||||
# Sleep until Crimata ID.
|
||||
if not self.crimata_id:
|
||||
await asyncio.sleep(1)
|
||||
continue
|
||||
|
||||
intent = await self.mailbox_recv()
|
||||
await self.send_agent_intent(intent)
|
||||
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# async def hello(self):
|
||||
|
||||
# intent = await self.recv_agent_intent()
|
||||
|
||||
# response = await self.fetch("crimata_id", service="message")
|
||||
# self.profile = response.get("profile")
|
||||
|
||||
# target = intent.params.get("target")
|
||||
# await self.notify(f"Messenger APP: Received Message Intent",
|
||||
# service="message", complete=True)
|
||||
|
||||
# print("Shutting down in 10s")
|
||||
|
||||
# await asyncio.sleep(10)
|
||||
28
typs.py
Normal file
28
typs.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# typs.py
|
||||
|
||||
import queue
|
||||
import asyncio
|
||||
|
||||
|
||||
class Mail:
|
||||
|
||||
def __init__(self, owner, target, text):
|
||||
self.owner = owner
|
||||
self.target = target
|
||||
self.text = text
|
||||
|
||||
|
||||
class MailBox:
|
||||
|
||||
def __init__(self, name):
|
||||
|
||||
self.name = name # just for logging purposes.
|
||||
self.inbox = asyncio.Queue()
|
||||
self.outbox = queue.Queue()
|
||||
|
||||
|
||||
class Intent:
|
||||
|
||||
def __init__(self, name, params: dict):
|
||||
self.name = name
|
||||
self.params = params
|
||||
Loading…
Reference in a new issue