Skip to content

Commit

Permalink
misc doc updates
Browse files Browse the repository at this point in the history
* simplify cross-reference links in design doc
* add docstrings to most class attrs/constants
* revise sphinx config
  • Loading branch information
snarfed committed Jan 31, 2025
1 parent 60d594b commit 8043d47
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 150 deletions.
11 changes: 11 additions & 0 deletions activitypub.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,26 +95,37 @@ class ActivityPub(User, Protocol):
Key id is AP/AS2 actor id URL. (*Not* fediverse/WebFinger @-@ handle!)
"""
ABBREV = 'ap'
''
PHRASE = 'the fediverse'
''
LOGO_HTML = '<img src="/static/fediverse_logo.svg">'
''
CONTENT_TYPE = as2.CONTENT_TYPE_LD_PROFILE
''
REQUIRES_AVATAR = True
''
REQUIRES_NAME = False
''
DEFAULT_ENABLED_PROTOCOLS = ('web',)
''
SUPPORTED_AS1_TYPES = (
tuple(as1.ACTOR_TYPES)
+ tuple(as1.POST_TYPES)
+ tuple(as1.CRUD_VERBS)
+ tuple(as1.VERBS_WITH_OBJECT)
+ ('audio', 'bookmark', 'image', 'video')
)
''
SUPPORTED_AS2_TYPES = tuple(
as2.OBJECT_TYPE_TO_TYPE.get(t) or as2.VERB_TO_TYPE.get(t)
for t in SUPPORTED_AS1_TYPES)
''
SUPPORTS_DMS = True
''

@property
def REQUIRES_OLD_ACCOUNT(self):
''
return util.domain_from_link(self.key.id()) not in OLD_ACCOUNT_EXEMPT_DOMAINS

def _pre_put_hook(self):
Expand Down
27 changes: 21 additions & 6 deletions atproto.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ def chat_client(*, repo, method, **kwargs):
Args:
repo (arroba.repo.Repo): ATProto user
method (str): XRPC method NSID, eg ``chat.bsky.convo.sendMessage``
kwargs: passed through to the :class:`lexrpc.Client` constructor
kwargs: passed through to the :class:`lexrpc.client.Client` constructor
Returns:
lexrpc.Client:
lexrpc.client.Client:
"""
token = service_jwt(host=os.environ['CHAT_HOST'],
aud=os.environ['CHAT_DID'],
Expand Down Expand Up @@ -207,8 +207,11 @@ class Cursor(StringIdModel):
re-subscribe to this event stream, we should send ``cursor + 1``.
"""
cursor = ndb.IntegerProperty()
''
created = ndb.DateTimeProperty(auto_now_add=True)
''
updated = ndb.DateTimeProperty(auto_now=True)
''


class ATProto(User, Protocol):
Expand All @@ -218,18 +221,27 @@ class ATProto(User, Protocol):
https://atproto.com/specs/did
"""
ABBREV = 'bsky'
''
PHRASE = 'Bluesky'
''
LOGO_HTML = '<img src="/oauth_dropins_static/bluesky.svg">'
# note that PDS hostname is atproto.brid.gy here, not bsky.brid.gy. Bluesky
# team currently has our hostname as atproto.brid.gy in their federation
# test. also note that PDS URL shouldn't include trailing slash.
# https://atproto.com/specs/did#did-documents
''
PDS_URL = f'https://atproto{common.SUPERDOMAIN}'
"""Note that PDS hostname is atproto.brid.gy here, not bsky.brid.gy. Bluesky
team currently has our hostname as atproto.brid.gy in their federation
test. also note that PDS URL shouldn't include trailing slash.
https://atproto.com/specs/did#did-documents
"""
CONTENT_TYPE = 'application/json'
''
HAS_COPIES = True
''
REQUIRES_AVATAR = True
''
REQUIRES_NAME = False
''
DEFAULT_ENABLED_PROTOCOLS = ('web',)
''
SUPPORTED_AS1_TYPES = frozenset(
tuple(as1.ACTOR_TYPES)
+ tuple(as1.POST_TYPES)
Expand All @@ -239,10 +251,13 @@ class ATProto(User, Protocol):
# TODO: add back once we handle them better
# https://github.com/snarfed/bridgy-fed/issues/1669
)
''
SUPPORTED_RECORD_TYPES = frozenset(
type for type in itertools.chain(*FROM_AS1_TYPES.values())
if '#' not in type)
''
SUPPORTS_DMS = True
''

def _pre_put_hook(self):
"""Validate id, require did:plc or non-blocklisted did:web."""
Expand Down
6 changes: 6 additions & 0 deletions docs/_static/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
color:#fcfcfc;
}

.rst-content code.literal,
.rst-content tt.literal {
/* overrides theme */
color: darkgreen;
}

.rst-content code, .rst-content tt, code {
border: none;
padding: 0;
Expand Down
10 changes: 8 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,13 @@
autodoc_default_options = {
'show-inheritance': True,
'members': True,
'special-members': True,
'private-members': '_convert, _handle',
'no-undoc-members': True,
'no-special-members': True,
'no-imported-members': True,
'member-order': 'bysource',
}
autodoc_inherit_docstrings = False

# Napoleon settings
# http://www.sphinx-doc.org/en/stable/ext/napoleon.html
Expand Down Expand Up @@ -129,7 +134,8 @@

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
add_module_names = False
python_use_unqualified_type_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
Expand Down
58 changes: 29 additions & 29 deletions docs/source/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,16 @@ Google Cloud is priced competitively with the other hyperscalers and major cloud

Bridgy Fed runs on Google Cloud and stores data in [Google Cloud Datastore](https://cloud.google.com/datastore/). (Ok, technically Firestore in Datastore mode.) It's a NoSQL database, but you can think of it more or less like a relational database, just bigger and dumber.

We use [ndb](https://googleapis.dev/python/python-ndb/latest/) our ORM. It's a venerable, conventional ORM for Google Cloud Datastore. Every table is defined by a Python class that ultimately derives from [`ndb.Model`](https://googleapis.dev/python/python-ndb/latest/model.html), with properties (columns) defined via [type-specific ndb `Property` classes](https://googleapis.dev/python/python-ndb/latest/model.html). Queries are programmatic, not SQL.
We use [ndb](https://googleapis.dev/python/python-ndb/latest/) as our ORM. It's a venerable, conventional ORM for Datastore. Every table is defined by a Python class that ultimately derives from [`ndb.Model`](https://googleapis.dev/python/python-ndb/latest/model.html), with properties (columns) defined via [type-specific ndb `Property` classes](https://googleapis.dev/python/python-ndb/latest/model.html). Queries are programmatic, not SQL.

Common models in Bridgy Fed are defined in [`models`](models). Each protocol has its own separate source file where its user model class is defined, eg [`Web`](web.Web) is in [`web`](web).
Common models in Bridgy Fed are defined in [](models). Each protocol has its own separate source file where its user model class is defined, eg [](Web) is in [](web).


## Users

Bridgy Fed has two core sets of tables ("kinds"): _users_ and _objects_. For users, each protocol has its own table, eg [`Web`](web.Web), [`ActivityPub`](activitypub.ActivityPub), and [`ATProto`](atproto.ATProto). Every user who interacts with Bridgy Fed gets a row ("entity") in the corresponding table. Many users in these tables have opted into Bridgy Fed and enabled the bridge, but not all.
Bridgy Fed has two core sets of tables ("kinds"): _users_ and _objects_. For users, each protocol has its own table, eg [](Web), [](ActivityPub), and [](ATProto). Every user who interacts with Bridgy Fed gets a row ("entity") in the corresponding table. Many users in these tables have opted into Bridgy Fed and enabled the bridge, but not all.

Each of these user classes derive from a common base class, [`User`](models.User), which defines common logic for handling users across protocols.
Each of these user classes derive from a common base class, [](User), which defines common logic for handling users across protocols.

The primary key for these user tables is the user's unique id in their native protocol, eg domain for web, actor id for ActivityPub, and DID for AT Protocol. Here are some examples:

Expand All @@ -96,22 +96,22 @@ The primary key for these user tables is the user's unique id in their native pr

## Objects

The [`Object`](models.Object) table stores all content and data. Every post, reply, like, repost, follow, block, etc is an [`Object`](models.Object). User profiles are too; they're attached to users via [`User.obj`](models.User.obj).
The [](Object) table stores all content and data. Every post, reply, like, repost, follow, block, etc is an [](Object). User profiles are too; they're attached to users via [](User.obj).

The primary key for [`Object`](models.Object)s is the object id in its native protocol. For web and ActivityPub, this is a URL; for AT Protocol, it's an [`at://` URI](https://atproto.com/specs/at-uri-scheme). Here are some examples:
The primary key for [](Object)s is the object id in its native protocol. For web and ActivityPub, this is a URL; for AT Protocol, it's an [`at://` URI](https://atproto.com/specs/at-uri-scheme). Here are some examples:

* Web: `https://snarfed.org/2023-06-30_policing-misinformation` (post)
* ActivityPub: `https://mastodon.social/00150396-47fc-42c8-7271-d187a8346d42` (follow)
* AT Protocol: `at://did:plc:3ljmtyyjqcjee2kpewgsifvb/app.bsky.feed.like/3kq6zqoa4hv2a` (like)

Note that user ids and profile ids are the same in some protocols, but not all. They're the same in ActivityPub, eg `https://indieweb.social/users/snarfed`, but in web and AT Protocol, they're different. Web user ids are domains, but web profile ids are home page URLs, eg `snarfed.org` vs `https://snarfed.org/`. Likewise, AT Protocol user ids are DIDs, but profile ids are `at://` URIs, eg `at://did:plc:3ljmtyyjqcjee2kpewgsifvb/app.bsky.actor.profile/self`. [More on translating ids here.](https://fed.brid.gy/docs#translate)

Data is stored in protocol-specific properties on [`Object`](models.Object) - `as2`, `bsky`, `mf2`, etc - and converted on demand to ActivityStreams 1, Bridgy Fed's (and granary's) common data format, via the `as1` computed property. We also sometimes modify the protocol's original data and store the result in the `our_as1` property, which overrides the protocol-specific properties.
Data is stored in protocol-specific properties on [](Object) - `as2`, `bsky`, `mf2`, etc - and converted on demand to ActivityStreams 1, Bridgy Fed's (and granary's) common data format, via the `as1` computed property. We also sometimes modify the protocol's original data and store the result in the `our_as1` property, which overrides the protocol-specific properties.


## Other

The one other notable table is [`Follower`](models.Follower), which stores following relationships across protocols. It just stores two foreign keys, `from_` and `to`, to the corresponding users in the datastore.
The one other notable table is [](Follower), which stores following relationships across protocols. It just stores two foreign keys, `from_` and `to`, to the corresponding users in the datastore.

arroba also stores AT Protocol repo data in the datastore in tables with the `Atp` prefix, eg `AtpRepo`, `AtpBlock`, `AtpRemoteBlob`, etc.

Expand All @@ -120,42 +120,42 @@ arroba also stores AT Protocol repo data in the datastore in tables with the `At

## `Protocol`

So far, we've discussed the [`User`](models.User) and [`Object`](models.Object) classes, defined in [`models`](models), and the per-protocol user classes defined in [`web`](web), [`activitypub`](activitypub), and [`atproto`](atproto). The one other key class is [`Protocol`](protocol.Protocol), defined in [`protocol`](protocol). This class implements all of our generic logic for [interpreting, routing, and delivering activities across protocols](https://fed.brid.gy/docs#router). `Protocol` has no state or instance-level methods, only `@staticmethod`s and `@classmethod`s. The per-protocol user classes `Web`, `ActivityPub`, and `ATProto` all derive from `User` _and_ `Protocol`.
So far, we've discussed the [](User) and [](Object) classes, defined in [](models), and the per-protocol user classes defined in [](web), [](activitypub), and [](atproto). The one other key class is [](Protocol), defined in [](protocol). This class implements all of our generic logic for [interpreting, routing, and delivering activities across protocols](https://fed.brid.gy/docs#router). `Protocol` has no state or instance-level methods, only `@staticmethod`s and `@classmethod`s. The per-protocol user classes `Web`, `ActivityPub`, and `ATProto` all derive from `User` _and_ `Protocol`.

[`Protocol`](protocol.Protocol) has a lot of code. Its most important methods are:
[](Protocol) has a lot of code. Its most important methods are:

* [`receive`](protocol.Protocol.receive): handles an incoming [`Object`](models.Object) that has been received ([more details](https://fed.brid.gy/docs#router))
* [`load`](protocol.Protocol.load): loads an [`Object`](models.Object), either from the datastore or remotely via this protocol if necessary
* [`targets`](protocol.Protocol.targets): determines all targets (eg servers) that we should send a given [`Object`](models.Object) to
* [`deliver`](protocol.Protocol.deliver): sends an [`Object`](models.Object) to all targets that should receive it
* [`convert`](protocol.Protocol.convert): converts an [`Object`](models.Object) to this protocol's data format
* [`translate_ids`](protocol.Protocol.translate_ids): [maps all object and actor ids](https://fed.brid.gy/docs#translate) in an [`Object`](models.Object) to this protocol's id format
* [](Protocol.receive): handles an incoming [](Object) that has been received ([more details](https://fed.brid.gy/docs#router))
* [](Protocol.load): loads an [](Object), either from the datastore or remotely via this protocol if necessary
* [](Protocol.targets): determines all targets (eg servers) that we should send a given [](Object) to
* [](Protocol.deliver): sends an [](Object) to all targets that should receive it
* [](Protocol.convert): converts an [](Object) to this protocol's data format
* [](Protocol.translate_ids): [maps all object and actor ids](https://fed.brid.gy/docs#translate) in an [](Object) to this protocol's id format

Some of these methods run on the source (incoming) protocol; some run on the destination (outgoing) protocol. These are generally class methods, and the traditional `cls` arg is named either `from_cls` or `to_cls` to indicate whether the incoming or outgoing protocol class should run them.

[`Protocol`](protocol.Protocol) has a few abstract methods that subclasses must implement. The most important ones are:
[](Protocol) has a few abstract methods that subclasses must implement. The most important ones are:

* [`fetch`](protocol.Protocol.fetch): fetches an [`Object`](models.Object) via this protocol
* [`send`](protocol.Protocol.send): sends an outgoing [`Object`](models.Object) over this protocol to a single destination server
* `_convert`: converts an [`Object`](models.Object) to this protocol's data format (just the protocol-specific part; called by [`convert`](protocol.Protocol.convert))
* [](Protocol.fetch): fetches an [](Object) via this protocol
* [](Protocol.send): sends an outgoing [](Object) over this protocol to a single destination server
* [](Protocol._convert): converts an [](Object) to this protocol's data format (just the protocol-specific part; called by [](Protocol.convert))


## Other modules

Here are the rest of the relevant modules:

* [`ids`](ids): converts user ids, object ids, and handles between protocols ([more details](https://fed.brid.gy/docs#translate))
* [`convert`](convert), [`redirect`](redirect): serve the `/convert/...` and `/r/...` endpoints, which convert and/or redirect object between protocol data formats. Primarily used by protocols that have at least some pull architecturally, eg web and ActivityPub.
* [`dms`](dms): handles [incoming DM commands](https://fed.brid.gy/docs#dm-commands), sends [outgoing DMs](https://fed.brid.gy/docs#dms)
* [`follow`](follow): implements the web follow UI on [fed.brid.gy](https://fed.brid.gy/); not widely used
* [`pages`](pages): serves the web UI on [fed.brid.gy](https://fed.brid.gy/), along with a few other miscellaneous endpoints like [nodeinfo](https://nodeinfo.diaspora.software/)
* [`common`](common), [`memcache`](memcache): miscellaneous utilities, constants, etc
* [](ids): converts user ids, object ids, and handles between protocols ([more details](https://fed.brid.gy/docs#translate))
* [](convert), [](redirect): serve the `/convert/...` and `/r/...` endpoints, which convert and/or redirect object between protocol data formats. Primarily used by protocols that have at least some pull architecturally, eg web and ActivityPub.
* [](dms): handles [incoming DM commands](https://fed.brid.gy/docs#dm-commands), sends [outgoing DMs](https://fed.brid.gy/docs#dms)
* [](follow): implements the web follow UI on [fed.brid.gy](https://fed.brid.gy/); not widely used
* [](pages): serves the web UI on [fed.brid.gy](https://fed.brid.gy/), along with a few other miscellaneous endpoints like [nodeinfo](https://nodeinfo.diaspora.software/)
* [](common), [](memcache): miscellaneous utilities, constants, etc

...along with the protocol implementations:

* [`activitypub`](activitypub), [`atproto`](atproto), [`web`](web): main implementations of each protocol in the [`ActivityPub`](activitypub.ActivityPub), [`ATProto`](atproto.ATProto), and [`Web`](web.Web) classes
* [`webfinger`](webfinger): webfinger implementation, both server and client side, for fediverse interop
* [`atproto_firehose`](atproto_firehose): [AT Protocol firehose](https://docs.bsky.app/docs/advanced-guides/firehose) subscriber. Receives every Bluesky event from the relay, extracts the ones we need to handle, and enqueues `receive` tasks for them.
* [](activitypub), [](atproto), [](web): main implementations of each protocol in the [](ActivityPub), [](ATProto), and [](Web) classes
* [](webfinger): webfinger implementation, both server and client side, for fediverse interop
* [](atproto_firehose): [AT Protocol firehose](https://docs.bsky.app/docs/advanced-guides/firehose) subscriber. Receives every Bluesky event from the relay, extracts the ones we need to handle, and enqueues `receive` tasks for them.

...and a few other modules for Flask apps and other config:

Expand Down
15 changes: 0 additions & 15 deletions docs/source/modules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,74 +8,59 @@ Reference documentation.
activitypub
-----------
.. automodule:: activitypub
:exclude-members: __eq__, __getnewargs__, __getstate__, __hash__, __new__, __repr__, __str__, __weakref__

atproto
-------
.. automodule:: atproto
:exclude-members: __eq__, __getnewargs__, __getstate__, __hash__, __new__, __repr__, __str__, __weakref__

atproto_firehose
----------------
.. automodule:: atproto_firehose
:exclude-members: __eq__, __getnewargs__, __getstate__, __hash__, __new__, __repr__, __str__, __weakref__

common
------
.. automodule:: common
:exclude-members: __eq__, __getnewargs__, __getstate__, __hash__, __new__, __repr__, __str__, __weakref__

convert
-------
.. automodule:: convert
:exclude-members: __eq__, __getnewargs__, __getstate__, __hash__, __new__, __repr__, __str__, __weakref__

dms
------
.. automodule:: dms
:exclude-members: __eq__, __getnewargs__, __getstate__, __hash__, __new__, __repr__, __str__, __weakref__

follow
------
.. automodule:: follow
:exclude-members: __eq__, __getnewargs__, __getstate__, __hash__, __new__, __repr__, __str__, __weakref__

ids
------
.. automodule:: ids
:exclude-members: __eq__, __getnewargs__, __getstate__, __hash__, __new__, __repr__, __str__, __weakref__

memcache
--------
.. automodule:: memcache
:exclude-members: __eq__, __getnewargs__, __getstate__, __hash__, __new__, __repr__, __str__, __weakref__

models
------
.. automodule:: models
:exclude-members: __eq__, __getnewargs__, __getstate__, __hash__, __new__, __repr__, __str__, __weakref__

pages
-----
.. automodule:: pages
:exclude-members: __eq__, __getnewargs__, __getstate__, __hash__, __new__, __repr__, __str__, __weakref__

protocol
--------
.. automodule:: protocol
:exclude-members: __eq__, __getnewargs__, __getstate__, __hash__, __new__, __repr__, __str__, __weakref__

redirect
--------
.. automodule:: redirect
:exclude-members: __eq__, __getnewargs__, __getstate__, __hash__, __new__, __repr__, __str__, __weakref__

web
---
.. automodule:: web
:exclude-members: __eq__, __getnewargs__, __getstate__, __hash__, __new__, __repr__, __str__, __weakref__

webfinger
---------
.. automodule:: webfinger
:exclude-members: __eq__, __getnewargs__, __getstate__, __hash__, __new__, __repr__, __str__, __weakref__
Loading

0 comments on commit 8043d47

Please sign in to comment.