massive refactoring to switch from camelCase to snake_case:

historically, Libervia (SàT before) was using camelCase as allowed by PEP8 when using a
pre-PEP8 code, to use the same coding style as in Twisted.

However, snake_case is more readable and it's better to follow PEP8 best practices, so it
has been decided to move on full snake_case. Because Libervia has a huge codebase, this
ended with a ugly mix of camelCase and snake_case.

To fix that, this patch does a big refactoring by renaming every function and method
(including bridge) that are not coming from Twisted or Wokkel, to use fully snake_case.

This is a massive change, and may result in some bugs.
This commit is contained in:
Goffi 2023-04-08 13:54:42 +02:00
commit 6a6f15707a
5 changed files with 9945 additions and 9945 deletions

File diff suppressed because it is too large Load diff

View file

@ -38,7 +38,7 @@ class APAdHocService:
self._c = self.host.plugins["XEP-0050"]
def init(self, client: SatXMPPEntity) -> None:
self._c.addAdHocCommand(
self._c.add_ad_hoc_command(
client,
self.xmpp_jid_node_2_ap_actor,
"Convert XMPP JID/Node to AP actor",
@ -82,7 +82,7 @@ class APAdHocService:
else:
xmpp_jid = jid.JID(command_form["jid"])
xmpp_node = command_form.get("node")
actor = await self.apg.getAPAccountFromJidAndNode(xmpp_jid, xmpp_node)
actor = await self.apg.get_ap_account_from_jid_and_node(xmpp_jid, xmpp_node)
note = (self._c.NOTE.INFO, actor)
status = self._c.STATUS.COMPLETED
payload = None

View file

@ -113,12 +113,12 @@ class APEvents:
"""
if not event_data.get("id"):
event_data["id"] = shortuuid.uuid()
ap_account = await self.apg.getAPAccountFromJidAndNode(
ap_account = await self.apg.get_ap_account_from_jid_and_node(
author_jid,
self._events.namespace
)
url_actor = self.apg.buildAPURL(TYPE_ACTOR, ap_account)
url_item = self.apg.buildAPURL(TYPE_ITEM, ap_account, event_data["id"])
url_actor = self.apg.build_apurl(TYPE_ACTOR, ap_account)
url_item = self.apg.build_apurl(TYPE_ITEM, ap_account, event_data["id"])
ap_object = {
"actor": url_actor,
"attributedTo": url_actor,
@ -246,7 +246,7 @@ class APEvents:
"""
is_activity = self.apg.is_activity(ap_item)
if is_activity:
ap_object = await self.apg.apGetObject(ap_item, "object")
ap_object = await self.apg.ap_get_object(ap_item, "object")
if not ap_object:
log.warning(f'No "object" found in AP item {ap_item!r}')
raise exceptions.DataError
@ -257,7 +257,7 @@ class APEvents:
if "_repeated" in ap_item:
# if the event is repeated, we use the original one ID
repeated_uri = ap_item["_repeated"]["uri"]
parsed_uri = uri.parseXMPPUri(repeated_uri)
parsed_uri = uri.parse_xmpp_uri(repeated_uri)
object_id = parsed_uri["item"]
else:
object_id = ap_object.get("id")
@ -268,10 +268,10 @@ class APEvents:
raise exceptions.DataError("AP Object is not an event")
# author
actor = await self.apg.apGetSenderActor(ap_object)
actor = await self.apg.ap_get_sender_actor(ap_object)
account = await self.apg.getAPAccountFromId(actor)
author_jid = self.apg.getLocalJIDFromAccount(account).full()
account = await self.apg.get_ap_account_from_id(actor)
author_jid = self.apg.get_local_jid_from_account(account).full()
# name, start, end
event_data = {
@ -370,7 +370,7 @@ class APEvents:
# comments
if ap_object.get("commentsEnabled"):
__, comments_node = await self.apg.getCommentsNodes(object_id, None)
__, comments_node = await self.apg.get_comments_nodes(object_id, None)
event_data["comments"] = {
"service": author_jid,
"node": comments_node,

View file

@ -66,7 +66,7 @@ class HTTPAPGServer(web_resource.Resource):
self._seen_digest = deque(maxlen=50)
super().__init__()
def responseCode(
def response_code(
self,
request: "HTTPRequest",
http_code: int,
@ -77,17 +77,17 @@ class HTTPAPGServer(web_resource.Resource):
log.warning(msg)
request.setResponseCode(http_code, None if msg is None else msg.encode())
def _onRequestError(self, failure_: failure.Failure, request: "HTTPRequest") -> None:
def _on_request_error(self, failure_: failure.Failure, request: "HTTPRequest") -> None:
exc = failure_.value
if isinstance(exc, exceptions.NotFound):
self.responseCode(
self.response_code(
request,
http.NOT_FOUND,
str(exc)
)
else:
log.exception(f"Internal error: {failure_.value}")
self.responseCode(
self.response_code(
request,
http.INTERNAL_SERVER_ERROR,
f"internal error: {failure_.value}"
@ -107,7 +107,7 @@ class HTTPAPGServer(web_resource.Resource):
http.BAD_REQUEST, "Bad Request" , "Invalid webfinger resource"
).render(request)
actor_url = self.apg.buildAPURL(TYPE_ACTOR, account)
actor_url = self.apg.build_apurl(TYPE_ACTOR, account)
resp = {
"aliases": [actor_url],
@ -124,7 +124,7 @@ class HTTPAPGServer(web_resource.Resource):
request.write(json.dumps(resp).encode())
request.finish()
async def handleUndoActivity(
async def handle_undo_activity(
self,
request: "HTTPRequest",
data: dict,
@ -136,7 +136,7 @@ class HTTPAPGServer(web_resource.Resource):
) -> None:
if node is None:
node = self.apg._m.namespace
client = await self.apg.getVirtualClient(signing_actor)
client = await self.apg.get_virtual_client(signing_actor)
object_ = data.get("object")
if isinstance(object_, str):
# we check first if it's not a cached object
@ -149,10 +149,10 @@ class HTTPAPGServer(web_resource.Resource):
# because we'll undo the activity, we can remove it from cache
await self.apg.client._ap_storage.remove(ap_cache_key)
else:
objects = await self.apg.apGetList(data, "object")
objects = await self.apg.ap_get_list(data, "object")
for obj in objects:
type_ = obj.get("type")
actor = await self.apg.apGetSenderActor(obj)
actor = await self.apg.ap_get_sender_actor(obj)
if actor != signing_actor:
log.warning(f"ignoring object not attributed to signing actor: {data}")
continue
@ -163,7 +163,7 @@ class HTTPAPGServer(web_resource.Resource):
except KeyError:
log.warning(f'ignoring invalid object, missing "object" key: {data}')
continue
if not self.apg.isLocalURL(target_account):
if not self.apg.is_local_url(target_account):
log.warning(f"ignoring unfollow request to non local actor: {data}")
continue
await self.apg._p.unsubscribe(
@ -175,17 +175,17 @@ class HTTPAPGServer(web_resource.Resource):
elif type_ == "Announce":
# we can use directly the Announce object, as only the "id" field is
# needed
await self.apg.newAPDeleteItem(client, None, node, obj)
await self.apg.new_ap_delete_item(client, None, node, obj)
elif type_ == TYPE_LIKE:
await self.handleAttachmentItem(client, obj, {"noticed": False})
await self.handle_attachment_item(client, obj, {"noticed": False})
elif type_ == TYPE_REACTION:
await self.handleAttachmentItem(client, obj, {
await self.handle_attachment_item(client, obj, {
"reactions": {"operation": "update", "remove": [obj["content"]]}
})
else:
log.warning(f"Unmanaged undo type: {type_!r}")
async def handleFollowActivity(
async def handle_follow_activity(
self,
request: "HTTPRequest",
data: dict,
@ -197,14 +197,14 @@ class HTTPAPGServer(web_resource.Resource):
) -> None:
if node is None:
node = self.apg._m.namespace
client = await self.apg.getVirtualClient(signing_actor)
client = await self.apg.get_virtual_client(signing_actor)
try:
subscription = await self.apg._p.subscribe(
client,
account_jid,
node,
# subscriptions from AP are always public
options=self.apg._pps.setPublicOpt()
options=self.apg._pps.set_public_opt()
)
except pubsub.SubscriptionPending:
log.info(f"subscription to node {node!r} of {account_jid} is pending")
@ -213,15 +213,15 @@ class HTTPAPGServer(web_resource.Resource):
if subscription.state != "subscribed":
# other states should raise an Exception
raise exceptions.InternalError('"subscribed" state was expected')
inbox = await self.apg.getAPInboxFromId(signing_actor, use_shared=False)
actor_id = self.apg.buildAPURL(TYPE_ACTOR, ap_account)
inbox = await self.apg.get_ap_inbox_from_id(signing_actor, use_shared=False)
actor_id = self.apg.build_apurl(TYPE_ACTOR, ap_account)
accept_data = self.apg.create_activity(
"Accept", actor_id, object_=data
)
await self.apg.signAndPost(inbox, actor_id, accept_data)
await self.apg.sign_and_post(inbox, actor_id, accept_data)
await self.apg._c.synchronise(client, account_jid, node, resync=False)
async def handleAcceptActivity(
async def handle_accept_activity(
self,
request: "HTTPRequest",
data: dict,
@ -233,12 +233,12 @@ class HTTPAPGServer(web_resource.Resource):
) -> None:
if node is None:
node = self.apg._m.namespace
client = await self.apg.getVirtualClient(signing_actor)
objects = await self.apg.apGetList(data, "object")
client = await self.apg.get_virtual_client(signing_actor)
objects = await self.apg.ap_get_list(data, "object")
for obj in objects:
type_ = obj.get("type")
if type_ == "Follow":
follow_node = await self.apg.host.memory.storage.getPubsubNode(
follow_node = await self.apg.host.memory.storage.get_pubsub_node(
client, client.jid, node, with_subscriptions=True
)
if follow_node is None:
@ -270,7 +270,7 @@ class HTTPAPGServer(web_resource.Resource):
else:
log.warning(f"Unmanaged accept type: {type_!r}")
async def handleDeleteActivity(
async def handle_delete_activity(
self,
request: "HTTPRequest",
data: dict,
@ -282,12 +282,12 @@ class HTTPAPGServer(web_resource.Resource):
):
if node is None:
node = self.apg._m.namespace
client = await self.apg.getVirtualClient(signing_actor)
objects = await self.apg.apGetList(data, "object")
client = await self.apg.get_virtual_client(signing_actor)
objects = await self.apg.ap_get_list(data, "object")
for obj in objects:
await self.apg.newAPDeleteItem(client, account_jid, node, obj)
await self.apg.new_ap_delete_item(client, account_jid, node, obj)
async def handleNewAPItems(
async def handle_new_ap_items(
self,
request: "HTTPRequest",
data: dict,
@ -298,7 +298,7 @@ class HTTPAPGServer(web_resource.Resource):
):
"""Helper method to handle workflow for new AP items
accept globally the same parameter as for handleCreateActivity
accept globally the same parameter as for handle_create_activity
@param repeated: if True, the item is an item republished from somewhere else
"""
if "_repeated" in data:
@ -307,25 +307,25 @@ class HTTPAPGServer(web_resource.Resource):
f"happen. Ignoring object from {signing_actor}\n{data}"
)
raise exceptions.DataError("unexpected field in item")
client = await self.apg.getVirtualClient(signing_actor)
objects = await self.apg.apGetList(data, "object")
client = await self.apg.get_virtual_client(signing_actor)
objects = await self.apg.ap_get_list(data, "object")
for obj in objects:
if node is None:
if obj.get("type") == TYPE_EVENT:
node = self.apg._events.namespace
else:
node = self.apg._m.namespace
sender = await self.apg.apGetSenderActor(obj)
sender = await self.apg.ap_get_sender_actor(obj)
if repeated:
# we don't check sender when item is repeated, as it should be different
# from post author in this case
sender_jid = await self.apg.getJIDFromId(sender)
repeater_jid = await self.apg.getJIDFromId(signing_actor)
sender_jid = await self.apg.get_jid_from_id(sender)
repeater_jid = await self.apg.get_jid_from_id(signing_actor)
repeated_item_id = obj["id"]
if self.apg.isLocalURL(repeated_item_id):
if self.apg.is_local_url(repeated_item_id):
# the repeated object is from XMPP, we need to parse the URL to find
# the right ID
url_type, url_args = self.apg.parseAPURL(repeated_item_id)
url_type, url_args = self.apg.parse_apurl(repeated_item_id)
if url_type != "item":
raise exceptions.DataError(
"local URI is not an item: {repeated_id}"
@ -339,7 +339,7 @@ class HTTPAPGServer(web_resource.Resource):
"local URI is invalid: {repeated_id}"
)
else:
url_jid, url_node = await self.apg.getJIDAndNode(url_account)
url_jid, url_node = await self.apg.get_jid_and_node(url_account)
if ((url_jid != sender_jid
or url_node and url_node != self.apg._m.namespace)):
raise exceptions.DataError(
@ -352,7 +352,7 @@ class HTTPAPGServer(web_resource.Resource):
obj["_repeated"] = {
"by": repeater_jid.full(),
"at": data.get("published"),
"uri": uri.buildXMPPUri(
"uri": uri.build_xmpp_uri(
"pubsub",
path=sender_jid.full(),
node=self.apg._m.namespace,
@ -369,9 +369,9 @@ class HTTPAPGServer(web_resource.Resource):
)
continue
await self.apg.newAPItem(client, account_jid, node, obj)
await self.apg.new_ap_item(client, account_jid, node, obj)
async def handleCreateActivity(
async def handle_create_activity(
self,
request: "HTTPRequest",
data: dict,
@ -381,9 +381,9 @@ class HTTPAPGServer(web_resource.Resource):
ap_url: str,
signing_actor: str
):
await self.handleNewAPItems(request, data, account_jid, node, signing_actor)
await self.handle_new_ap_items(request, data, account_jid, node, signing_actor)
async def handleUpdateActivity(
async def handle_update_activity(
self,
request: "HTTPRequest",
data: dict,
@ -395,9 +395,9 @@ class HTTPAPGServer(web_resource.Resource):
):
# Update is the same as create: the item ID stays the same, thus the item will be
# overwritten
await self.handleNewAPItems(request, data, account_jid, node, signing_actor)
await self.handle_new_ap_items(request, data, account_jid, node, signing_actor)
async def handleAnnounceActivity(
async def handle_announce_activity(
self,
request: "HTTPRequest",
data: dict,
@ -408,7 +408,7 @@ class HTTPAPGServer(web_resource.Resource):
signing_actor: str
):
# we create a new item
await self.handleNewAPItems(
await self.handle_new_ap_items(
request,
data,
account_jid,
@ -417,7 +417,7 @@ class HTTPAPGServer(web_resource.Resource):
repeated=True
)
async def handleAttachmentItem(
async def handle_attachment_item(
self,
client: SatXMPPEntity,
data: dict,
@ -447,10 +447,10 @@ class HTTPAPGServer(web_resource.Resource):
await client._ap_storage.aset(f"{ST_AP_CACHE}{data['id']}", data)
for target_id in target_ids:
if not self.apg.isLocalURL(target_id):
if not self.apg.is_local_url(target_id):
log.debug(f"ignoring non local target ID: {target_id}")
continue
url_type, url_args = self.apg.parseAPURL(target_id)
url_type, url_args = self.apg.parse_apurl(target_id)
if url_type != TYPE_ITEM:
log.warning(f"unexpected local URL for attachment on item {target_id}")
continue
@ -458,20 +458,20 @@ class HTTPAPGServer(web_resource.Resource):
account, item_id = url_args
except ValueError:
raise ValueError(f"invalid URL: {target_id}")
author_jid, item_node = await self.apg.getJIDAndNode(account)
author_jid, item_node = await self.apg.get_jid_and_node(account)
if item_node is None:
item_node = self.apg._m.namespace
attachment_node = self.apg._pa.getAttachmentNodeName(
attachment_node = self.apg._pa.get_attachment_node_name(
author_jid, item_node, item_id
)
cached_node = await self.apg.host.memory.storage.getPubsubNode(
cached_node = await self.apg.host.memory.storage.get_pubsub_node(
client,
author_jid,
attachment_node,
with_subscriptions=True,
create=True
)
found_items, __ = await self.apg.host.memory.storage.getItems(
found_items, __ = await self.apg.host.memory.storage.get_items(
cached_node, item_ids=[client.jid.userhost()]
)
if not found_items:
@ -487,16 +487,16 @@ class HTTPAPGServer(web_resource.Resource):
None
)
# we reparse the element, as there can be other attachments
attachments_data = self.apg._pa.items2attachmentData(client, [item_elt])
attachments_data = self.apg._pa.items_2_attachment_data(client, [item_elt])
# and we update the cache
await self.apg.host.memory.storage.cachePubsubItems(
await self.apg.host.memory.storage.cache_pubsub_items(
client,
cached_node,
[item_elt],
attachments_data or [{}]
)
if self.apg.isVirtualJID(author_jid):
if self.apg.is_virtual_jid(author_jid):
# the attachment is on t a virtual pubsub service (linking to an AP item),
# we notify all subscribers
for subscription in cached_node.subscriptions:
@ -509,11 +509,11 @@ class HTTPAPGServer(web_resource.Resource):
)
else:
# the attachment is on an XMPP item, we publish it to the attachment node
await self.apg._p.sendItems(
await self.apg._p.send_items(
client, author_jid, attachment_node, [item_elt]
)
async def handleLikeActivity(
async def handle_like_activity(
self,
request: "HTTPRequest",
data: dict,
@ -523,10 +523,10 @@ class HTTPAPGServer(web_resource.Resource):
ap_url: str,
signing_actor: str
) -> None:
client = await self.apg.getVirtualClient(signing_actor)
await self.handleAttachmentItem(client, data, {"noticed": True})
client = await self.apg.get_virtual_client(signing_actor)
await self.handle_attachment_item(client, data, {"noticed": True})
async def handleEmojireactActivity(
async def handle_emojireact_activity(
self,
request: "HTTPRequest",
data: dict,
@ -536,12 +536,12 @@ class HTTPAPGServer(web_resource.Resource):
ap_url: str,
signing_actor: str
) -> None:
client = await self.apg.getVirtualClient(signing_actor)
await self.handleAttachmentItem(client, data, {
client = await self.apg.get_virtual_client(signing_actor)
await self.handle_attachment_item(client, data, {
"reactions": {"operation": "update", "add": [data["content"]]}
})
async def handleJoinActivity(
async def handle_join_activity(
self,
request: "HTTPRequest",
data: dict,
@ -551,10 +551,10 @@ class HTTPAPGServer(web_resource.Resource):
ap_url: str,
signing_actor: str
) -> None:
client = await self.apg.getVirtualClient(signing_actor)
await self.handleAttachmentItem(client, data, {"rsvp": {"attending": "yes"}})
client = await self.apg.get_virtual_client(signing_actor)
await self.handle_attachment_item(client, data, {"rsvp": {"attending": "yes"}})
async def handleLeaveActivity(
async def handle_leave_activity(
self,
request: "HTTPRequest",
data: dict,
@ -564,10 +564,10 @@ class HTTPAPGServer(web_resource.Resource):
ap_url: str,
signing_actor: str
) -> None:
client = await self.apg.getVirtualClient(signing_actor)
await self.handleAttachmentItem(client, data, {"rsvp": {"attending": "no"}})
client = await self.apg.get_virtual_client(signing_actor)
await self.handle_attachment_item(client, data, {"rsvp": {"attending": "no"}})
async def APActorRequest(
async def ap_actor_request(
self,
request: "HTTPRequest",
data: Optional[dict],
@ -577,24 +577,24 @@ class HTTPAPGServer(web_resource.Resource):
ap_url: str,
signing_actor: Optional[str]
) -> dict:
inbox = self.apg.buildAPURL(TYPE_INBOX, ap_account)
shared_inbox = self.apg.buildAPURL(TYPE_SHARED_INBOX)
outbox = self.apg.buildAPURL(TYPE_OUTBOX, ap_account)
followers = self.apg.buildAPURL(TYPE_FOLLOWERS, ap_account)
following = self.apg.buildAPURL(TYPE_FOLLOWING, ap_account)
inbox = self.apg.build_apurl(TYPE_INBOX, ap_account)
shared_inbox = self.apg.build_apurl(TYPE_SHARED_INBOX)
outbox = self.apg.build_apurl(TYPE_OUTBOX, ap_account)
followers = self.apg.build_apurl(TYPE_FOLLOWERS, ap_account)
following = self.apg.build_apurl(TYPE_FOLLOWING, ap_account)
# we have to use AP account as preferredUsername because it is used to retrieve
# actor handle (see https://socialhub.activitypub.rocks/t/how-to-retrieve-user-server-tld-handle-from-actors-url/2196)
preferred_username = ap_account.split("@", 1)[0]
identity_data = await self.apg._i.getIdentity(self.apg.client, account_jid)
identity_data = await self.apg._i.get_identity(self.apg.client, account_jid)
if node and node.startswith(self.apg._events.namespace):
events = outbox
else:
events_account = await self.apg.getAPAccountFromJidAndNode(
events_account = await self.apg.get_ap_account_from_jid_and_node(
account_jid, self.apg._events.namespace
)
events = self.apg.buildAPURL(TYPE_OUTBOX, events_account)
events = self.apg.build_apurl(TYPE_OUTBOX, events_account)
actor_data = {
"@context": [
@ -636,7 +636,7 @@ class HTTPAPGServer(web_resource.Resource):
except KeyError:
log.error(f"incomplete avatar data: {identity_data!r}")
else:
avatar_url = self.apg.buildAPURL("avatar", filename)
avatar_url = self.apg.build_apurl("avatar", filename)
actor_data["icon"] = {
"type": "Image",
"url": avatar_url,
@ -645,14 +645,14 @@ class HTTPAPGServer(web_resource.Resource):
return actor_data
def getCanonicalURL(self, request: "HTTPRequest") -> str:
def get_canonical_url(self, request: "HTTPRequest") -> str:
return parse.urljoin(
f"https://{self.apg.public_url}",
request.path.decode().rstrip("/")
# we unescape "@" for the same reason as in [APActorRequest]
# we unescape "@" for the same reason as in [ap_actor_request]
).replace("%40", "@")
def queryData2RSMRequest(
def query_data_2_rsm_request(
self,
query_data: Dict[str, List[str]]
) -> rsm.RSMRequest:
@ -673,7 +673,7 @@ class HTTPAPGServer(web_resource.Resource):
return rsm.RSMRequest(**kwargs)
raise ValueError(f"Invalid query data: {query_data!r}")
async def APOutboxPageRequest(
async def ap_outbox_page_request(
self,
request: "HTTPRequest",
data: Optional[dict],
@ -690,18 +690,18 @@ class HTTPAPGServer(web_resource.Resource):
url_keys = sorted(set(query_data) & {"page", "index", "before", "after"})
query_data = {k: query_data[k] for k in url_keys}
try:
items, metadata = await self.apg._p.getItems(
items, metadata = await self.apg._p.get_items(
client=self.apg.client,
service=account_jid,
node=node,
rsm_request=self.queryData2RSMRequest(query_data),
rsm_request=self.query_data_2_rsm_request(query_data),
extra = {C.KEY_USE_CACHE: False}
)
except error.StanzaError as e:
log.warning(f"Can't get data from pubsub node {node} at {account_jid}: {e}")
return {}
base_url = self.getCanonicalURL(request)
base_url = self.get_canonical_url(request)
url = f"{base_url}?{parse.urlencode(query_data, True)}"
if node and node.startswith(self.apg._events.namespace):
ordered_items = [
@ -753,7 +753,7 @@ class HTTPAPGServer(web_resource.Resource):
return ret_data
async def APOutboxRequest(
async def ap_outbox_request(
self,
request: "HTTPRequest",
data: Optional[dict],
@ -769,7 +769,7 @@ class HTTPAPGServer(web_resource.Resource):
parsed_url = parse.urlparse(request.uri.decode())
query_data = parse.parse_qs(parsed_url.query)
if query_data:
return await self.APOutboxPageRequest(
return await self.ap_outbox_page_request(
request, data, account_jid, node, ap_account, ap_url, query_data
)
@ -779,7 +779,7 @@ class HTTPAPGServer(web_resource.Resource):
# The current workaround is to do a request as if RSM was available, and actually
# check its availability according to result.
try:
__, metadata = await self.apg._p.getItems(
__, metadata = await self.apg._p.get_items(
client=self.apg.client,
service=account_jid,
node=node,
@ -799,7 +799,7 @@ class HTTPAPGServer(web_resource.Resource):
)
items_count = 20
url = self.getCanonicalURL(request)
url = self.get_canonical_url(request)
url_first_page = f"{url}?{parse.urlencode({'page': 'first'})}"
url_last_page = f"{url}?{parse.urlencode({'page': 'last'})}"
return {
@ -811,7 +811,7 @@ class HTTPAPGServer(web_resource.Resource):
"last": url_last_page,
}
async def APInboxRequest(
async def ap_inbox_request(
self,
request: "HTTPRequest",
data: Optional[dict],
@ -824,26 +824,26 @@ class HTTPAPGServer(web_resource.Resource):
assert data is not None
if signing_actor is None:
raise exceptions.InternalError("signing_actor must be set for inbox requests")
await self.checkSigningActor(data, signing_actor)
await self.check_signing_actor(data, signing_actor)
activity_type = (data.get("type") or "").lower()
if not activity_type in ACTIVITY_TYPES_LOWER:
return self.responseCode(
return self.response_code(
request,
http.UNSUPPORTED_MEDIA_TYPE,
f"request is not an activity, ignoring"
)
if account_jid is None and activity_type not in ACTIVIY_NO_ACCOUNT_ALLOWED:
return self.responseCode(
return self.response_code(
request,
http.UNSUPPORTED_MEDIA_TYPE,
f"{activity_type.title()!r} activity must target an account"
)
try:
method = getattr(self, f"handle{activity_type.title()}Activity")
method = getattr(self, f"handle_{activity_type}_activity")
except AttributeError:
return self.responseCode(
return self.response_code(
request,
http.UNSUPPORTED_MEDIA_TYPE,
f"{activity_type.title()} activity is not yet supported"
@ -853,7 +853,7 @@ class HTTPAPGServer(web_resource.Resource):
request, data, account_jid, node, ap_account, ap_url, signing_actor
)
async def APFollowersRequest(
async def ap_followers_request(
self,
request: "HTTPRequest",
data: Optional[dict],
@ -866,20 +866,20 @@ class HTTPAPGServer(web_resource.Resource):
if node is None:
node = self.apg._m.namespace
client = self.apg.client
subscribers = await self.apg._pps.getPublicNodeSubscriptions(
subscribers = await self.apg._pps.get_public_node_subscriptions(
client, account_jid, node
)
followers = []
for subscriber in subscribers.keys():
if self.apg.isVirtualJID(subscriber):
if self.apg.is_virtual_jid(subscriber):
# the subscriber is an AP user subscribed with this gateway
ap_account = self.apg._e.unescape(subscriber.user)
else:
# regular XMPP user
ap_account = await self.apg.getAPAccountFromJidAndNode(subscriber, node)
ap_account = await self.apg.get_ap_account_from_jid_and_node(subscriber, node)
followers.append(ap_account)
url = self.getCanonicalURL(request)
url = self.get_canonical_url(request)
return {
"@context": ["https://www.w3.org/ns/activitystreams"],
"type": "OrderedCollection",
@ -892,7 +892,7 @@ class HTTPAPGServer(web_resource.Resource):
}
}
async def APFollowingRequest(
async def ap_following_request(
self,
request: "HTTPRequest",
data: Optional[dict],
@ -909,17 +909,17 @@ class HTTPAPGServer(web_resource.Resource):
following = []
for sub_dict in subscriptions:
service = jid.JID(sub_dict["service"])
if self.apg.isVirtualJID(service):
if self.apg.is_virtual_jid(service):
# the subscription is to an AP actor with this gateway
ap_account = self.apg._e.unescape(service.user)
else:
# regular XMPP user
ap_account = await self.apg.getAPAccountFromJidAndNode(
ap_account = await self.apg.get_ap_account_from_jid_and_node(
service, sub_dict["node"]
)
following.append(ap_account)
url = self.getCanonicalURL(request)
url = self.get_canonical_url(request)
return {
"@context": ["https://www.w3.org/ns/activitystreams"],
"type": "OrderedCollection",
@ -953,7 +953,7 @@ class HTTPAPGServer(web_resource.Resource):
to_log.append(f" headers:\n{headers}")
return to_log
async def APRequest(
async def ap_request(
self,
request: "HTTPRequest",
data: Optional[dict] = None,
@ -967,13 +967,13 @@ class HTTPAPGServer(web_resource.Resource):
f"https://{self.apg.public_url}",
path
)
request_type, extra_args = self.apg.parseAPURL(ap_url)
request_type, extra_args = self.apg.parse_apurl(ap_url)
if ((MEDIA_TYPE_AP not in (request.getHeader("accept") or "")
and request_type in self.apg.html_redirect)):
# this is not a AP request, and we have a redirections for it
kw = {}
if extra_args:
kw["jid"], kw["node"] = await self.apg.getJIDAndNode(extra_args[0])
kw["jid"], kw["node"] = await self.apg.get_jid_and_node(extra_args[0])
kw["jid_user"] = kw["jid"].user
if kw["node"] is None:
kw["node"] = self.apg._m.namespace
@ -1007,7 +1007,7 @@ class HTTPAPGServer(web_resource.Resource):
if len(extra_args) == 0:
if request_type != "shared_inbox":
raise exceptions.DataError(f"Invalid request type: {request_type!r}")
ret_data = await self.APInboxRequest(
ret_data = await self.ap_inbox_request(
request, data, None, None, None, ap_url, signing_actor
)
elif request_type == "avatar":
@ -1017,14 +1017,14 @@ class HTTPAPGServer(web_resource.Resource):
avatar_path = self.apg.host.common_cache.getPath(avatar_filename)
return static.File(str(avatar_path)).render(request)
elif request_type == "item":
ret_data = await self.apg.apGetLocalObject(ap_url)
ret_data = await self.apg.ap_get_local_object(ap_url)
if "@context" not in ret_data:
ret_data["@context"] = [NS_AP]
else:
if len(extra_args) > 1:
log.warning(f"unexpected extra arguments: {extra_args!r}")
ap_account = extra_args[0]
account_jid, node = await self.apg.getJIDAndNode(ap_account)
account_jid, node = await self.apg.get_jid_and_node(ap_account)
if request_type not in AP_REQUEST_TYPES.get(
request.method.decode().upper(), []
):
@ -1046,12 +1046,12 @@ class HTTPAPGServer(web_resource.Resource):
log.info("\n".join(to_log))
request.finish()
async def APPostRequest(self, request: "HTTPRequest") -> None:
async def ap_post_request(self, request: "HTTPRequest") -> None:
try:
data = json.load(request.content)
if not isinstance(data, dict):
log.warning(f"JSON data should be an object (uri={request.uri.decode()})")
self.responseCode(
self.response_code(
request,
http.BAD_REQUEST,
f"invalid body, was expecting a JSON object"
@ -1059,7 +1059,7 @@ class HTTPAPGServer(web_resource.Resource):
request.finish()
return
except (json.JSONDecodeError, ValueError) as e:
self.responseCode(
self.response_code(
request,
http.BAD_REQUEST,
f"invalid json in inbox request: {e}"
@ -1081,14 +1081,14 @@ class HTTPAPGServer(web_resource.Resource):
pass
try:
signing_actor = await self.checkSignature(request)
signing_actor = await self.check_signature(request)
except exceptions.EncryptionError as e:
if self.apg.verbose:
to_log = self._get_to_log(request)
to_log.append(f" body: {request.content.read()!r}")
request.content.seek(0)
log.info("\n".join(to_log))
self.responseCode(
self.response_code(
request,
http.FORBIDDEN,
f"invalid signature: {e}"
@ -1096,7 +1096,7 @@ class HTTPAPGServer(web_resource.Resource):
request.finish()
return
except Exception as e:
self.responseCode(
self.response_code(
request,
http.INTERNAL_SERVER_ERROR,
f"Can't check signature: {e}"
@ -1115,27 +1115,27 @@ class HTTPAPGServer(web_resource.Resource):
# default response code, may be changed, e.g. in case of exception
try:
return await self.APRequest(request, data, signing_actor)
return await self.ap_request(request, data, signing_actor)
except Exception as e:
self._onRequestError(failure.Failure(e), request)
self._on_request_error(failure.Failure(e), request)
async def checkSigningActor(self, data: dict, signing_actor: str) -> None:
async def check_signing_actor(self, data: dict, signing_actor: str) -> None:
"""That that signing actor correspond to actor declared in data
@param data: request payload
@param signing_actor: actor ID of the signing entity, as returned by
checkSignature
check_signature
@raise exceptions.NotFound: no actor found in data
@raise exceptions.EncryptionError: signing actor doesn't match actor in data
"""
actor = await self.apg.apGetSenderActor(data)
actor = await self.apg.ap_get_sender_actor(data)
if signing_actor != actor:
raise exceptions.EncryptionError(
f"signing actor ({signing_actor}) doesn't match actor in data ({actor})"
)
async def checkSignature(self, request: "HTTPRequest") -> str:
async def check_signature(self, request: "HTTPRequest") -> str:
"""Check and validate HTTP signature
@return: id of the signing actor
@ -1242,7 +1242,7 @@ class HTTPAPGServer(web_resource.Resource):
raise exceptions.EncryptionError(
"Only SHA-256 algorithm is currently supported for digest"
)
__, computed_digest = self.apg.getDigest(body)
__, computed_digest = self.apg.get_digest(body)
if given_digest != computed_digest:
raise exceptions.EncryptionError(
f"SHA-256 given and computed digest differ:\n"
@ -1275,7 +1275,7 @@ class HTTPAPGServer(web_resource.Resource):
raise exceptions.EncryptionError("Signature has expired")
try:
return await self.apg.checkSignature(
return await self.apg.check_signature(
sign_data["signature"],
key_id,
headers
@ -1287,7 +1287,7 @@ class HTTPAPGServer(web_resource.Resource):
"Using workaround for (request-target) encoding bug in signature, "
"see https://github.com/mastodon/mastodon/issues/18871"
)
return await self.apg.checkSignature(
return await self.apg.check_signature(
sign_data["signature"],
key_id,
headers
@ -1303,8 +1303,8 @@ class HTTPAPGServer(web_resource.Resource):
defer.ensureDeferred(self.webfinger(request))
return server.NOT_DONE_YET
elif path.startswith(self.apg.ap_path):
d = defer.ensureDeferred(self.APRequest(request))
d.addErrback(self._onRequestError, request)
d = defer.ensureDeferred(self.ap_request(request))
d.addErrback(self._on_request_error, request)
return server.NOT_DONE_YET
return web_resource.NoResource().render(request)
@ -1313,7 +1313,7 @@ class HTTPAPGServer(web_resource.Resource):
path = request.path.decode().lstrip("/")
if not path.startswith(self.apg.ap_path):
return web_resource.NoResource().render(request)
defer.ensureDeferred(self.APPostRequest(request))
defer.ensureDeferred(self.ap_post_request(request))
return server.NOT_DONE_YET

View file

@ -34,7 +34,7 @@ from sat.core.log import getLogger
from sat.core.constants import Const as C
from sat.tools import image
from sat.tools.utils import ensure_deferred
from sat.tools.web import downloadFile
from sat.tools.web import download_file
from sat.memory.sqla_mapping import PubsubSub, SubscriptionState
from .constants import (
@ -74,7 +74,7 @@ class APPubsubService(rsm.PubSubService):
"name": "Libervia ActivityPub Gateway",
}
async def getAPActorIdsAndInbox(
async def get_ap_actor_ids_and_inbox(
self,
requestor: jid.JID,
recipient: jid.JID,
@ -92,16 +92,16 @@ class APPubsubService(rsm.PubSubService):
"item-not-found",
text="No user part specified"
)
requestor_actor_id = self.apg.buildAPURL(TYPE_ACTOR, requestor.userhost())
requestor_actor_id = self.apg.build_apurl(TYPE_ACTOR, requestor.userhost())
recipient_account = self.apg._e.unescape(recipient.user)
recipient_actor_id = await self.apg.getAPActorIdFromAccount(recipient_account)
inbox = await self.apg.getAPInboxFromId(recipient_actor_id, use_shared=False)
recipient_actor_id = await self.apg.get_ap_actor_id_from_account(recipient_account)
inbox = await self.apg.get_ap_inbox_from_id(recipient_actor_id, use_shared=False)
return requestor_actor_id, recipient_actor_id, inbox
@ensure_deferred
async def publish(self, requestor, service, nodeIdentifier, items):
if self.apg.local_only and not self.apg.isLocal(requestor):
if self.apg.local_only and not self.apg.is_local(requestor):
raise error.StanzaError(
"forbidden",
"Only local users can publish on this gateway."
@ -118,19 +118,19 @@ class APPubsubService(rsm.PubSubService):
f"{ap_account!r} is not a valid ActivityPub actor account."
)
client = self.apg.client.getVirtualClient(requestor)
if self.apg._pa.isAttachmentNode(nodeIdentifier):
await self.apg.convertAndPostAttachments(
client = self.apg.client.get_virtual_client(requestor)
if self.apg._pa.is_attachment_node(nodeIdentifier):
await self.apg.convert_and_post_attachments(
client, ap_account, service, nodeIdentifier, items, publisher=requestor
)
else:
await self.apg.convertAndPostItems(
await self.apg.convert_and_post_items(
client, ap_account, service, nodeIdentifier, items
)
cached_node = await self.host.memory.storage.getPubsubNode(
cached_node = await self.host.memory.storage.get_pubsub_node(
client, service, nodeIdentifier, with_subscriptions=True, create=True
)
await self.host.memory.storage.cachePubsubItems(
await self.host.memory.storage.cache_pubsub_items(
client,
cached_node,
items
@ -144,27 +144,27 @@ class APPubsubService(rsm.PubSubService):
[(subscription.subscriber, None, items)]
)
async def apFollowing2Elt(self, ap_item: dict) -> domish.Element:
async def ap_following_2_elt(self, ap_item: dict) -> domish.Element:
"""Convert actor ID from following collection to XMPP item"""
actor_id = ap_item["id"]
actor_jid = await self.apg.getJIDFromId(actor_id)
subscription_elt = self.apg._pps.buildSubscriptionElt(
actor_jid = await self.apg.get_jid_from_id(actor_id)
subscription_elt = self.apg._pps.build_subscription_elt(
self.apg._m.namespace, actor_jid
)
item_elt = pubsub.Item(id=actor_id, payload=subscription_elt)
return item_elt
async def apFollower2Elt(self, ap_item: dict) -> domish.Element:
async def ap_follower_2_elt(self, ap_item: dict) -> domish.Element:
"""Convert actor ID from followers collection to XMPP item"""
actor_id = ap_item["id"]
actor_jid = await self.apg.getJIDFromId(actor_id)
subscriber_elt = self.apg._pps.buildSubscriberElt(actor_jid)
actor_jid = await self.apg.get_jid_from_id(actor_id)
subscriber_elt = self.apg._pps.build_subscriber_elt(actor_jid)
item_elt = pubsub.Item(id=actor_id, payload=subscriber_elt)
return item_elt
async def generateVCard(self, ap_account: str) -> domish.Element:
async def generate_v_card(self, ap_account: str) -> domish.Element:
"""Generate vCard4 (XEP-0292) item element from ap_account's metadata"""
actor_data = await self.apg.getAPActorDataFromAccount(ap_account)
actor_data = await self.apg.get_ap_actor_data_from_account(ap_account)
identity_data = {}
summary = actor_data.get("summary")
@ -181,13 +181,13 @@ class APPubsubService(rsm.PubSubService):
value = actor_data.get(field)
if value:
identity_data.setdefault("nicknames", []).append(value)
vcard_elt = self.apg._v.dict2VCard(identity_data)
vcard_elt = self.apg._v.dict_2_v_card(identity_data)
item_elt = domish.Element((pubsub.NS_PUBSUB, "item"))
item_elt.addChild(vcard_elt)
item_elt["id"] = self.apg._p.ID_SINGLETON
return item_elt
async def getAvatarData(
async def get_avatar_data(
self,
client: SatXMPPEntity,
ap_account: str
@ -197,9 +197,9 @@ class APPubsubService(rsm.PubSubService):
``cache_uid``, `path``` and ``media_type`` keys are always files
``base64`` key is only filled if the file was not already in cache
"""
actor_data = await self.apg.getAPActorDataFromAccount(ap_account)
actor_data = await self.apg.get_ap_actor_data_from_account(ap_account)
for icon in await self.apg.apGetList(actor_data, "icon"):
for icon in await self.apg.ap_get_list(actor_data, "icon"):
url = icon.get("url")
if icon["type"] != "Image" or not url:
continue
@ -221,19 +221,19 @@ class APPubsubService(rsm.PubSubService):
if cache_uid is None:
cache = None
else:
cache = self.apg.host.common_cache.getMetadata(cache_uid)
cache = self.apg.host.common_cache.get_metadata(cache_uid)
if cache is None:
with tempfile.TemporaryDirectory() as dir_name:
dest_path = Path(dir_name, filename)
await downloadFile(url, dest_path, max_size=MAX_AVATAR_SIZE)
await download_file(url, dest_path, max_size=MAX_AVATAR_SIZE)
avatar_data = {
"path": dest_path,
"filename": filename,
'media_type': image.guess_type(dest_path),
}
await self.apg._i.cacheAvatar(
await self.apg._i.cache_avatar(
self.apg.IMPORT_NAME,
avatar_data
)
@ -246,7 +246,7 @@ class APPubsubService(rsm.PubSubService):
return avatar_data
async def generateAvatarMetadata(
async def generate_avatar_metadata(
self,
client: SatXMPPEntity,
ap_account: str
@ -256,14 +256,14 @@ class APPubsubService(rsm.PubSubService):
@raise StanzaError("item-not-found"): no avatar is present in actor data (in
``icon`` field)
"""
avatar_data = await self.getAvatarData(client, ap_account)
return self.apg._a.buildItemMetadataElt(avatar_data)
avatar_data = await self.get_avatar_data(client, ap_account)
return self.apg._a.build_item_metadata_elt(avatar_data)
def _blockingB64EncodeAvatar(self, avatar_data: Dict[str, Any]) -> None:
def _blocking_b_6_4_encode_avatar(self, avatar_data: Dict[str, Any]) -> None:
with avatar_data["path"].open("rb") as f:
avatar_data["base64"] = b64encode(f.read()).decode()
async def generateAvatarData(
async def generate_avatar_data(
self,
client: SatXMPPEntity,
ap_account: str,
@ -274,9 +274,9 @@ class APPubsubService(rsm.PubSubService):
@raise StanzaError("item-not-found"): no avatar cached with requested ID
"""
if not itemIdentifiers:
avatar_data = await self.getAvatarData(client, ap_account)
avatar_data = await self.get_avatar_data(client, ap_account)
if "base64" not in avatar_data:
await threads.deferToThread(self._blockingB64EncodeAvatar, avatar_data)
await threads.deferToThread(self._blocking_b_6_4_encode_avatar, avatar_data)
else:
if len(itemIdentifiers) > 1:
# only a single item ID is supported
@ -284,16 +284,16 @@ class APPubsubService(rsm.PubSubService):
item_id = itemIdentifiers[0]
# just to be sure that that we don't have an empty string
assert item_id
cache_data = self.apg.host.common_cache.getMetadata(item_id)
cache_data = self.apg.host.common_cache.get_metadata(item_id)
if cache_data is None:
raise error.StanzaError("item-not-found")
avatar_data = {
"cache_uid": item_id,
"path": cache_data["path"]
}
await threads.deferToThread(self._blockingB64EncodeAvatar, avatar_data)
await threads.deferToThread(self._blocking_b_6_4_encode_avatar, avatar_data)
return self.apg._a.buildItemDataElt(avatar_data)
return self.apg._a.build_item_data_elt(avatar_data)
@ensure_deferred
async def items(
@ -320,31 +320,31 @@ class APPubsubService(rsm.PubSubService):
if node == self.apg._pps.subscriptions_node:
collection_name = "following"
parser = self.apFollowing2Elt
parser = self.ap_following_2_elt
kwargs["only_ids"] = True
use_cache = False
elif node.startswith(self.apg._pps.subscribers_node_prefix):
collection_name = "followers"
parser = self.apFollower2Elt
parser = self.ap_follower_2_elt
kwargs["only_ids"] = True
use_cache = False
elif node == self.apg._v.node:
# vCard4 request
item_elt = await self.generateVCard(ap_account)
item_elt = await self.generate_v_card(ap_account)
return [item_elt], None
elif node == self.apg._a.namespace_metadata:
item_elt = await self.generateAvatarMetadata(self.apg.client, ap_account)
item_elt = await self.generate_avatar_metadata(self.apg.client, ap_account)
return [item_elt], None
elif node == self.apg._a.namespace_data:
item_elt = await self.generateAvatarData(
item_elt = await self.generate_avatar_data(
self.apg.client, ap_account, itemIdentifiers
)
return [item_elt], None
elif self.apg._pa.isAttachmentNode(node):
elif self.apg._pa.is_attachment_node(node):
use_cache = True
# we check cache here because we emit an item-not-found error if the node is
# not in cache, as we are not dealing with real AP items
cached_node = await self.host.memory.storage.getPubsubNode(
cached_node = await self.host.memory.storage.get_pubsub_node(
client, service, node
)
if cached_node is None:
@ -365,14 +365,14 @@ class APPubsubService(rsm.PubSubService):
if use_cache:
if cached_node is None:
cached_node = await self.host.memory.storage.getPubsubNode(
cached_node = await self.host.memory.storage.get_pubsub_node(
client, service, node
)
# TODO: check if node is synchronised
if cached_node is not None:
# the node is cached, we return items from cache
log.debug(f"node {node!r} from {service} is in cache")
pubsub_items, metadata = await self.apg._c.getItemsFromCache(
pubsub_items, metadata = await self.apg._c.get_items_from_cache(
client, cached_node, maxItems, itemIdentifiers, rsm_request=rsm_req
)
try:
@ -384,7 +384,7 @@ class APPubsubService(rsm.PubSubService):
if itemIdentifiers:
items = []
for item_id in itemIdentifiers:
item_data = await self.apg.apGet(item_id)
item_data = await self.apg.ap_get(item_id)
item_elt = await parser(item_data)
items.append(item_elt)
return items, None
@ -419,11 +419,11 @@ class APPubsubService(rsm.PubSubService):
f"No cache found for node {node} at {service} (AP account {ap_account}), "
"using Collection Paging to RSM translation"
)
if self.apg._m.isCommentNode(node):
parent_item = self.apg._m.getParentItem(node)
if self.apg._m.is_comment_node(node):
parent_item = self.apg._m.get_parent_item(node)
try:
parent_data = await self.apg.apGet(parent_item)
collection = await self.apg.apGetObject(
parent_data = await self.apg.ap_get(parent_item)
collection = await self.apg.ap_get_object(
parent_data.get("object", {}),
"replies"
)
@ -433,8 +433,8 @@ class APPubsubService(rsm.PubSubService):
text=e
)
else:
actor_data = await self.apg.getAPActorDataFromAccount(ap_account)
collection = await self.apg.apGetObject(actor_data, collection_name)
actor_data = await self.apg.get_ap_actor_data_from_account(ap_account)
collection = await self.apg.ap_get_object(actor_data, collection_name)
if not collection:
raise error.StanzaError(
"item-not-found",
@ -442,7 +442,7 @@ class APPubsubService(rsm.PubSubService):
)
kwargs["parser"] = parser
return await self.apg.getAPItems(collection, **kwargs)
return await self.apg.get_ap_items(collection, **kwargs)
@ensure_deferred
async def retract(self, requestor, service, nodeIdentifier, itemIdentifiers):
@ -459,11 +459,11 @@ class APPubsubService(rsm.PubSubService):
sub_state = SubscriptionState.PENDING
else:
sub_state = SubscriptionState.SUBSCRIBED
node = await self.host.memory.storage.getPubsubNode(
node = await self.host.memory.storage.get_pubsub_node(
client, service, nodeIdentifier, with_subscriptions=True
)
if node is None:
node = await self.host.memory.storage.setPubsubNode(
node = await self.host.memory.storage.set_pubsub_node(
client,
service,
nodeIdentifier,
@ -510,13 +510,13 @@ class APPubsubService(rsm.PubSubService):
if nodeIdentifier in (self.apg._m.namespace, self.apg._events.namespace):
# if we subscribe to microblog or events node, we follow the corresponding
# account
req_actor_id, recip_actor_id, inbox = await self.getAPActorIdsAndInbox(
req_actor_id, recip_actor_id, inbox = await self.get_ap_actor_ids_and_inbox(
requestor, service
)
data = self.apg.create_activity("Follow", req_actor_id, recip_actor_id)
resp = await self.apg.signAndPost(inbox, req_actor_id, data)
resp = await self.apg.sign_and_post(inbox, req_actor_id, data)
if resp.code >= 300:
text = await resp.text()
raise error.StanzaError("service-unavailable", text=text)
@ -524,7 +524,7 @@ class APPubsubService(rsm.PubSubService):
@ensure_deferred
async def unsubscribe(self, requestor, service, nodeIdentifier, subscriber):
req_actor_id, recip_actor_id, inbox = await self.getAPActorIdsAndInbox(
req_actor_id, recip_actor_id, inbox = await self.get_ap_actor_ids_and_inbox(
requestor, service
)
data = self.apg.create_activity(
@ -537,7 +537,7 @@ class APPubsubService(rsm.PubSubService):
)
)
resp = await self.apg.signAndPost(inbox, req_actor_id, data)
resp = await self.apg.sign_and_post(inbox, req_actor_id, data)
if resp.code >= 300:
text = await resp.text()
raise error.StanzaError("service-unavailable", text=text)