Skip to content

Commit

Permalink
feat: add wrapper class for messages to handle optional metadata betw…
Browse files Browse the repository at this point in the history
…een connections (closes #4)
  • Loading branch information
aitorres committed Sep 10, 2023
1 parent 5b3ce11 commit 61865d4
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 32 deletions.
26 changes: 15 additions & 11 deletions barkr/connections/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import logging
from enum import Enum

from barkr.models.message import Message

logger = logging.getLogger()


Expand Down Expand Up @@ -42,27 +44,29 @@ def __init__(self, name: str, modes: list[ConnectionMode]) -> None:
self.modes: list[ConnectionMode] = modes
self.posted_message_ids: set[str] = set()

def read(self) -> list[str]:
def read(self) -> list[Message]:
"""
Read new messages from this connection
Read and return new messages from this connection
:return: A list of new messages
"""

if ConnectionMode.READ not in self.modes:
return []

statuses: list[tuple[str, str]] = self._fetch()
messages: list[Message] = self._fetch()

messages_to_return: list[str] = []
for status_id, status_message in statuses:
if status_id not in self.posted_message_ids:
messages_to_return.append(status_message)
filtered_messages: list[Message] = []
for message in messages:
if (status_id := message.id) not in self.posted_message_ids:
filtered_messages.append(message)
else:
logger.debug("Status %s already posted, skipping.", status_id)
self.posted_message_ids.remove(status_id)

return messages_to_return
return filtered_messages

def write(self, messages: list[str]) -> None:
def write(self, messages: list[Message]) -> None:
"""
Write messages to this connection
Expand All @@ -75,7 +79,7 @@ def write(self, messages: list[str]) -> None:
posted_ids: list[str] = self._post(messages)
self.posted_message_ids.update(posted_ids)

def _fetch(self) -> list[tuple[str, str]]:
def _fetch(self) -> list[Message]:
"""
Fetch messages from this connection and returns a list of pairs
containing (id, message)
Expand All @@ -85,7 +89,7 @@ def _fetch(self) -> list[tuple[str, str]]:

raise NotImplementedError(f"Fetch not implemented for connection {self.name}")

def _post(self, messages: list[str]) -> list[str]:
def _post(self, messages: list[Message]) -> list[str]:
"""
Post messages to this connection and returns a list of message IDs
Expand Down
18 changes: 13 additions & 5 deletions barkr/connections/mastodon.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from mastodon import Mastodon # type: ignore

from barkr.connections.base import Connection, ConnectionMode
from barkr.models.message import Message

logger = logging.getLogger()

Expand Down Expand Up @@ -68,9 +69,11 @@ def __init__(
self.min_id = ""
logger.debug("Mastodon (%s) initial min_id not set.", self.name)

def _fetch(self) -> list[tuple[str, str]]:
def _fetch(self) -> list[Message]:
"""
Fetch messages from this connection
:return: A list of messages
"""

statuses: list[dict[str, Any]] = self.service.account_statuses(
Expand All @@ -88,20 +91,25 @@ def _fetch(self) -> list[tuple[str, str]]:
else:
logger.debug("No new statuses fetched from Mastodon (%s)", self.name)

return [(status["id"], status["content"]) for status in statuses]
return [
Message(id=status["id"], message=status["content"]) for status in statuses
]

def _post(self, messages: list[str]) -> list[str]:
def _post(self, messages: list[Message]) -> list[str]:
"""
Post messages from a list to the Mastodon instance
:param messages: A list of messages to be posted
:return: A list of message IDs
"""

posted_message_ids: list[str] = []

for message in messages:
posted_message = self.service.status_post(message)
posted_message = self.service.status_post(message.message)
posted_message_ids.append(posted_message["id"])
logger.info("Posted status to Mastodon (%s): %s", self.name, message)
logger.info(
"Posted status to Mastodon (%s): %s", self.name, message.message
)

return posted_message_ids
3 changes: 2 additions & 1 deletion barkr/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from threading import Lock, Thread

from barkr.connections.base import Connection
from barkr.models.message import Message
from barkr.utils import wrap_while_true

logger = logging.getLogger()
Expand Down Expand Up @@ -36,7 +37,7 @@ def __init__(self, connections: list[Connection], retry_interval: int = 15) -> N
"Initializing Barkr instance with %s connection(s)...", len(connections)
)
self.connections: list[Connection] = connections
self.message_queues: dict[str, list[str]] = {
self.message_queues: dict[str, list[Message]] = {
connection.name: [] for connection in connections
}
self.message_queues_lock: Lock = Lock()
Expand Down
Empty file added barkr/models/__init__.py
Empty file.
22 changes: 22 additions & 0 deletions barkr/models/message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""
Module to implement a generic, wrapper model for messages.
A message is a generic object that can be posted to a social media network
OR retrieved from a social media network, with an ID and a message body, as
well as (potentially) other metadata that each connection can decide
whether or not to take into account.
"""

from dataclasses import dataclass


@dataclass(frozen=True)
class Message:
"""
A generic message object with an ID and a message body,
as well as (potentially) other metadata that each connection
can decide whether or not to take into account.
"""

id: str
message: str
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ warn_unused_configs = true

[tool.pylint.FORMAT]
max-line-length=90
good-names="id"

[build-system]
requires = ["poetry-core"]
Expand Down
9 changes: 5 additions & 4 deletions tests/test_connections/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import pytest

from barkr.connections.base import Connection, ConnectionMode
from barkr.models.message import Message


def test_connection() -> None:
Expand All @@ -21,7 +22,7 @@ def test_connection() -> None:
assert connection_1.modes == [ConnectionMode.READ]

# This shouldn't raise any exceptions
connection_1.write(["test message"])
connection_1.write([Message(id="id1", message="test message")])

with pytest.raises(NotImplementedError):
connection_1.read()
Expand All @@ -31,10 +32,10 @@ def test_connection() -> None:
assert connection_2.name == "Write Only"
assert connection_2.modes == [ConnectionMode.WRITE]

assert connection_2.read() == []
assert not connection_2.read()

with pytest.raises(NotImplementedError):
connection_2.write(["test message"])
connection_2.write([Message(id="id1", message="test message")])

# Read/Write connection base
connection_3 = Connection("Read/Write", [ConnectionMode.READ, ConnectionMode.WRITE])
Expand All @@ -45,4 +46,4 @@ def test_connection() -> None:
connection_1.read()

with pytest.raises(NotImplementedError):
connection_2.write(["test message"])
connection_2.write([Message(id="id1", message="test message")])
15 changes: 12 additions & 3 deletions tests/test_connections/test_mastodon.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pytest

from barkr.connections.mastodon import ConnectionMode, MastodonConnection
from barkr.models.message import Message


def test_mastodon_connection(monkeypatch: pytest.MonkeyPatch) -> None:
Expand Down Expand Up @@ -45,7 +46,10 @@ def test_mastodon_connection(monkeypatch: pytest.MonkeyPatch) -> None:

messages = mastodon.read()

assert messages == ["test message 1", "test message 2"]
assert messages == [
Message(id="11223344", message="test message 1"),
Message(id="55667788", message="test message 2"),
]
assert mastodon.min_id == "11223344"

posted_messages: list[str] = []
Expand All @@ -59,7 +63,12 @@ def status_post_mockup(_, message: str) -> dict[str, Any]:
"barkr.connections.mastodon.Mastodon.status_post", status_post_mockup
)

mastodon.write(["test message 3", "test message 4"])
mastodon.write(
[
Message(id="ForeignId1", message="test message 3"),
Message(id="ForeignId2", message="test message 4"),
]
)
assert posted_messages == ["test message 3", "test message 4"]
assert mastodon.posted_message_ids == {"12121212", "23232323"}

Expand All @@ -74,6 +83,6 @@ def status_post_mockup(_, message: str) -> dict[str, Any]:

messages = mastodon.read()

assert messages == ["test message 5"]
assert messages == [Message(id="44554455", message="test message 5")]
assert mastodon.min_id == "12121212"
assert mastodon.posted_message_ids == set()
38 changes: 30 additions & 8 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from barkr.connections.base import Connection, ConnectionMode
from barkr.main import Barkr
from barkr.models.message import Message


class ConnectionMockup(Connection):
Expand All @@ -18,11 +19,14 @@ def __init__(self, name: str, modes: list[ConnectionMode]) -> None:
super().__init__(name, modes)
self.posted_messages: list[str] = []

def _fetch(self) -> list[tuple[str, str]]:
return [("1234", f"{self.name}-TestMsg1"), ("5678", f"{self.name}-TestMsg2")]
def _fetch(self) -> list[Message]:
return [
Message(id=f"{self.name}-Id1", message=f"{self.name}-TestMsg1"),
Message(id=f"{self.name}-Id2", message=f"{self.name}-TestMsg2"),
]

def _post(self, messages: list[str]) -> list[str]:
self.posted_messages += messages
def _post(self, messages: list[Message]) -> list[str]:
self.posted_messages += [m.message for m in messages]
return [f"id-{i}" for i in range(len(messages))]


Expand All @@ -49,8 +53,14 @@ def test_barkr_read_only() -> None:

barkr.read()
assert barkr.message_queues == {
"TestCon1": ["TestCon2-TestMsg1", "TestCon2-TestMsg2"],
"TestCon2": ["TestCon1-TestMsg1", "TestCon1-TestMsg2"],
"TestCon1": [
Message(id="TestCon2-Id1", message="TestCon2-TestMsg1"),
Message(id="TestCon2-Id2", message="TestCon2-TestMsg2"),
],
"TestCon2": [
Message(id="TestCon1-Id1", message="TestCon1-TestMsg1"),
Message(id="TestCon1-Id2", message="TestCon1-TestMsg2"),
],
}
assert test_connection_1.posted_messages == []
assert test_connection_2.posted_messages == []
Expand Down Expand Up @@ -83,7 +93,16 @@ def test_barkr_write_only() -> None:
assert test_connection_2.posted_messages == []

# forcing messages to appear in the queue
barkr.message_queues = {"TestCon1": ["msg1", "msg2"], "TestCon2": ["msg3", "msg4"]}
barkr.message_queues = {
"TestCon1": [
Message(id="Idx", message="msg1"),
Message(id="Idx", message="msg2"),
],
"TestCon2": [
Message(id="Idx", message="msg3"),
Message(id="Idx", message="msg4"),
],
}
barkr.write()
assert barkr.message_queues == {"TestCon1": [], "TestCon2": []}
assert test_connection_1.posted_messages == ["msg1", "msg2"]
Expand All @@ -105,7 +124,10 @@ def test_barkr_read_write() -> None:
barkr.read()
assert barkr.message_queues == {
"TestCon1": [],
"TestCon2": ["TestCon1-TestMsg1", "TestCon1-TestMsg2"],
"TestCon2": [
Message(id="TestCon1-Id1", message="TestCon1-TestMsg1"),
Message(id="TestCon1-Id2", message="TestCon1-TestMsg2"),
],
}
assert test_connection_1.posted_messages == []
assert test_connection_2.posted_messages == []
Expand Down

0 comments on commit 61865d4

Please sign in to comment.