Skip to content

Commit

Permalink
object oriented API
Browse files Browse the repository at this point in the history
  • Loading branch information
link2xt committed Nov 14, 2022
1 parent 4e197e0 commit 0577dfe
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 88 deletions.
4 changes: 3 additions & 1 deletion deltachat-rpc-client/src/deltachat_rpc_client/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from .deltachat import Deltachat, start_rpc_server, new_online_account
from .rpc import Rpc, start_rpc_server, new_online_account
from .deltachat import Deltachat
from .account import Account


async def main():
Expand Down
31 changes: 31 additions & 0 deletions deltachat-rpc-client/src/deltachat_rpc_client/account.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from typing import Optional


class Account:
def __init__(self, rpc, id):
self.id = id
self.rpc = rpc

async def remove(self) -> None:
await self.rpc.remove_account(self.id)

async def start_io(self) -> None:
await self.rpc.start_io(self.id)

async def stop_io(self) -> None:
await self.rpc.stop_io(self.id)

async def get_info(self):
await self.rpc.get_info(self.id)

async def get_file_size(self):
await self.rpc.get_account_file_size(self.id)

async def is_configured(self) -> bool:
await self.rpc.is_configured(self.id)

async def set_config(key: str, value: Optional[str]):
await self.rpc.set_config(self.id, key, value)

async def get_config(key: str) -> Optional[str]:
await self.rpc.get_config(self.id, key)
92 changes: 17 additions & 75 deletions deltachat-rpc-client/src/deltachat_rpc_client/deltachat.py
Original file line number Diff line number Diff line change
@@ -1,83 +1,25 @@
import asyncio
import aiohttp
import json
import logging
import os


class JsonRpcError(Exception):
pass
from .account import Account


class Deltachat:
def __init__(self, process):
self.process = process
self.event_queue = asyncio.Queue()
self.id = 0
self.reader_task = asyncio.create_task(self.reader_loop())

# Map from request ID to `asyncio.Future` returning the response.
self.request_events = {}

async def reader_loop(self):
while True:
line = await self.process.stdout.readline()
response = json.loads(line)
if "id" in response:
fut = self.request_events.pop(response["id"])
fut.set_result(response)
else:
if response["method"] == "event":
# An event notification.
await self.event_queue.put(response["params"]["event"])

async def get_next_event(self):
"""Returns next event."""
return await self.event_queue.get()

def __getattr__(self, attr):
async def method(*args, **kwargs):
self.id += 1
request_id = self.id

params = args
if kwargs:
assert not args
params = kwargs

request = {
"jsonrpc": "2.0",
"method": attr,
"params": params,
"id": self.id,
}
data = (json.dumps(request) + "\n").encode()
self.process.stdin.write(data)
event = asyncio.Event()
loop = asyncio.get_running_loop()
fut = loop.create_future()
self.request_events[request_id] = fut
response = await fut
if "error" in response:
raise JsonRpcError(response["error"])
if "result" in response:
return response["result"]
"""
Delta Chat account manager.
This is the root of the object oriented API.
"""

return method
def __init__(self, rpc):
self.rpc = rpc

async def add_account(self):
account_id = await self.rpc.add_account()
return Account(self.rpc, account_id)

async def start_rpc_server():
proc = await asyncio.create_subprocess_exec(
"deltachat-rpc-server",
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE,
)
deltachat = Deltachat(proc)
return deltachat
async def get_all_accounts(self):
account_ids = await self.rpc.get_all_account_ids()
return [Account(rpc, account_id) for account_id in account_ids]

async def start_io(self) -> None:
await self.rpc.start_io_for_all_accounts()

async def new_online_account():
url = os.getenv("DCC_NEW_TMP_EMAIL")
async with aiohttp.ClientSession() as session:
async with session.post(url) as response:
return json.loads(await response.text())
async def stop_io(self) -> None:
await self.rpc.stop_io_for_all_accounts()
83 changes: 83 additions & 0 deletions deltachat-rpc-client/src/deltachat_rpc_client/rpc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import asyncio
import aiohttp
import json
import logging
import os


class JsonRpcError(Exception):
pass


class Rpc:
def __init__(self, process):
self.process = process
self.event_queue = asyncio.Queue()
self.id = 0
self.reader_task = asyncio.create_task(self.reader_loop())

# Map from request ID to `asyncio.Future` returning the response.
self.request_events = {}

async def reader_loop(self):
while True:
line = await self.process.stdout.readline()
response = json.loads(line)
if "id" in response:
fut = self.request_events.pop(response["id"])
fut.set_result(response)
else:
if response["method"] == "event":
# An event notification.
await self.event_queue.put(response["params"]["event"])

async def get_next_event(self):
"""Returns next event."""
return await self.event_queue.get()

def __getattr__(self, attr):
async def method(*args, **kwargs):
self.id += 1
request_id = self.id

params = args
if kwargs:
assert not args
params = kwargs

request = {
"jsonrpc": "2.0",
"method": attr,
"params": params,
"id": self.id,
}
data = (json.dumps(request) + "\n").encode()
self.process.stdin.write(data)
event = asyncio.Event()
loop = asyncio.get_running_loop()
fut = loop.create_future()
self.request_events[request_id] = fut
response = await fut
if "error" in response:
raise JsonRpcError(response["error"])
if "result" in response:
return response["result"]

return method


async def start_rpc_server():
proc = await asyncio.create_subprocess_exec(
"deltachat-rpc-server",
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE,
)
rpc = Rpc(proc)
return rpc


async def new_online_account():
url = os.getenv("DCC_NEW_TMP_EMAIL")
async with aiohttp.ClientSession() as session:
async with session.post(url) as response:
return json.loads(await response.text())
34 changes: 22 additions & 12 deletions deltachat-rpc-client/tests/test_something.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,45 @@
import pytest_asyncio

import deltachat_rpc_client
from deltachat_rpc_client import Deltachat


@pytest_asyncio.fixture
async def rpc_server():
async def rpc():
return await deltachat_rpc_client.start_rpc_server()


@pytest.mark.asyncio
async def test_system_info(rpc_server):
system_info = await rpc_server.get_system_info()
async def test_system_info(rpc):
system_info = await rpc.get_system_info()
assert "arch" in system_info
assert "deltachat_core_version" in system_info


@pytest.mark.asyncio
async def test_email_address_validity(rpc_server):
async def test_email_address_validity(rpc):
valid_addresses = [
"email@example.com",
"36aa165ae3406424e0c61af17700f397cad3fe8ab83d682d0bddf3338a5dd52e@yggmail@yggmail",
]
invalid_addresses = ["email@", "example.com", "emai221"]

for addr in valid_addresses:
assert await rpc_server.check_email_validity(addr)
assert await rpc.check_email_validity(addr)
for addr in invalid_addresses:
assert not await rpc_server.check_email_validity(addr)
assert not await rpc.check_email_validity(addr)

@pytest.mark.asyncio
async def test_online_account(rpc_server):
async def test_online_account(rpc):
account_json = await deltachat_rpc_client.new_online_account()

account_id = await rpc_server.add_account()
await rpc_server.set_config(account_id, "addr", account_json["email"])
await rpc_server.set_config(account_id, "mail_pw", account_json["password"])
account_id = await rpc.add_account()
await rpc.set_config(account_id, "addr", account_json["email"])
await rpc.set_config(account_id, "mail_pw", account_json["password"])

await rpc_server.configure(account_id)
await rpc.configure(account_id)
while True:
event = await rpc_server.get_next_event()
event = await rpc.get_next_event()
if event["type"] == "ConfigureProgress":
# Progress 0 indicates error.
assert event["progress"] != 0
Expand All @@ -50,3 +51,12 @@ async def test_online_account(rpc_server):
else:
print(event)
print("Successful configuration")


@pytest.mark.asyncio
async def test_online_account(rpc):
deltachat = Deltachat(rpc)
account = await deltachat.add_account()
assert not await account.is_configured()
info = await account.get_info()
print(info)

0 comments on commit 0577dfe

Please sign in to comment.