Skip to content

Contact

Runnable example

python/examples/contact_browse.py — list contacts with presence → search the cloud for users → fetch one contact by id (read-only; add / accept / remove are intentionally omitted because they mutate the real cloud contact list).

resoio.contact.ContactClient

ContactClient(socket_path: str | None = None)

Bases: _BaseClient[ContactStub]

Async client for the Resonite IO Contact service over a UDS.

Use as an async context manager so the gRPC channel closes deterministically.

Source code in src/resoio/_client.py
def __init__(self, socket_path: str | None = None) -> None:
    # Defer resolution to __aenter__ so env vars patched between
    # construction and connection are honoured, and so resolution
    # errors surface at the connect site.
    self._explicit_path: str | None = socket_path
    self._channel: Channel | None = None
    self._stub: TStub | None = None
    self._resolved_path: str | None = None

list_contacts async

list_contacts(
    *,
    search: str = "",
    filter: ContactFilter = ContactFilter.ALL,
    include_hidden: bool = False,
) -> ListContactsResponse

List contacts with presence (search / filter applied mod-side).

By default this hides the same contacts the in-game dash Contacts tab hides (ignored / blocked); pass include_hidden=True to return every contact regardless.

Source code in src/resoio/contact.py
async def list_contacts(
    self,
    *,
    search: str = "",
    filter: ContactFilter = ContactFilter.ALL,
    include_hidden: bool = False,
) -> ListContactsResponse:
    """List contacts with presence (search / filter applied mod-side).

    By default this hides the same contacts the in-game dash Contacts
    tab hides (ignored / blocked); pass ``include_hidden=True`` to
    return every contact regardless.
    """
    stub = self._require_stub()
    request = ListContactsRequest(
        search=search,
        filter=_CONTACT_FILTER_TO_WIRE[filter],
        include_hidden=include_hidden,
    )
    return await stub.list_contacts(request)

get_contact async

get_contact(user_id: str) -> GetContactResponse

Fetch a single contact by user_id (found=false if absent).

Source code in src/resoio/contact.py
async def get_contact(self, user_id: str) -> GetContactResponse:
    """Fetch a single contact by ``user_id`` (``found=false`` if
    absent)."""
    stub = self._require_stub()
    return await stub.get_contact(GetContactRequest(user_id=user_id))

search_users async

search_users(query: str, *, exact_match: bool = False) -> SearchUsersResponse

Search the cloud for users (no side effects; precedes add).

exact_match restricts to an exact username match.

Source code in src/resoio/contact.py
async def search_users(
    self,
    query: str,
    *,
    exact_match: bool = False,
) -> SearchUsersResponse:
    """Search the cloud for users (no side effects; precedes ``add``).

    ``exact_match`` restricts to an exact username match.
    """
    stub = self._require_stub()
    request = SearchUsersRequest(query=query, exact_match=exact_match)
    return await stub.search_users(request)

add_contact async

add_contact(user_id: str, *, username: str = '') -> AddContactResponse

Add a user as a contact (username resolved mod-side if empty).

Source code in src/resoio/contact.py
async def add_contact(
    self,
    user_id: str,
    *,
    username: str = "",
) -> AddContactResponse:
    """Add a user as a contact (``username`` resolved mod-side if
    empty)."""
    stub = self._require_stub()
    request = AddContactRequest(user_id=user_id, username=username)
    return await stub.add_contact(request)

accept_request async

accept_request(user_id: str) -> AcceptRequestResponse

Accept an incoming contact request from user_id.

Source code in src/resoio/contact.py
async def accept_request(self, user_id: str) -> AcceptRequestResponse:
    """Accept an incoming contact request from ``user_id``."""
    stub = self._require_stub()
    return await stub.accept_request(AcceptRequestRequest(user_id=user_id))

remove_contact async

remove_contact(user_id: str) -> None

Remove a contact / reject a request from user_id.

Source code in src/resoio/contact.py
async def remove_contact(self, user_id: str) -> None:
    """Remove a contact / reject a request from ``user_id``."""
    stub = self._require_stub()
    await stub.remove_contact(RemoveContactRequest(user_id=user_id))

resoio.contact.ContactInfo dataclass

ContactInfo(
    user_id: str = betterproto2.field(1, betterproto2.TYPE_STRING),
    username: str = betterproto2.field(2, betterproto2.TYPE_STRING),
    alternate_usernames: list[str] = betterproto2.field(
        3, betterproto2.TYPE_STRING, repeated=True
    ),
    status: ContactStatus = betterproto2.field(
        4, betterproto2.TYPE_ENUM, default_factory=(lambda: ContactStatus(0))
    ),
    is_accepted: bool = betterproto2.field(5, betterproto2.TYPE_BOOL),
    is_contact_request: bool = betterproto2.field(6, betterproto2.TYPE_BOOL),
    online_status: OnlineStatus = betterproto2.field(
        7, betterproto2.TYPE_ENUM, default_factory=(lambda: OnlineStatus(0))
    ),
    current_session_name: str = betterproto2.field(8, betterproto2.TYPE_STRING),
    current_session_access_level: str = betterproto2.field(9, betterproto2.TYPE_STRING),
    is_hidden: bool = betterproto2.field(10, betterproto2.TYPE_BOOL),
)

Bases: Message

連絡先 1 件 (presence 付き)。service 名 Contact と衝突しないよう ContactInfo

is_contact_request class-attribute instance-attribute

is_contact_request: bool = field(6, TYPE_BOOL)

受信中のフレンドリクエスト (Contact.IsContactRequest)。

current_session_name class-attribute instance-attribute

current_session_name: str = field(8, TYPE_STRING)

現在参加中セッション名 (presence)。不明なら空。

current_session_access_level class-attribute instance-attribute

current_session_access_level: str = field(9, TYPE_STRING)

現在参加中セッションの公開レベル名 (例 "Private" / "Anyone")。不明なら空。

is_hidden class-attribute instance-attribute

is_hidden: bool = field(10, TYPE_BOOL)

dash の Contacts タブが非表示にする連絡先 (None / Ignored / Blocked 等、 engine の Contact.ShouldBeHidden)。ListContacts は既定でこれらを除外する。

resoio.contact.UserSearchResult dataclass

UserSearchResult(
    user_id: str = betterproto2.field(1, betterproto2.TYPE_STRING),
    username: str = betterproto2.field(2, betterproto2.TYPE_STRING),
    is_verified: bool = betterproto2.field(3, betterproto2.TYPE_BOOL),
)

Bases: Message

ユーザー検索結果 1 件 (連絡先化される前のユーザー)。

resoio.contact.ContactFilter

Bases: Enum

Contact-list filter for :meth:ContactClient.list_contacts.

ALL = no filter (aliases the wire UNSPECIFIED head).

resoio.contact.ContactStatus

Bases: Enum

連絡先のステータス (engine ContactManager の ContactStatus を +1 シフトで写す)。 0=UNSPECIFIED は proto3 の必須スロットで、engine の None..Accepted が 1..6 に並ぶ。

resoio.contact.OnlineStatus

Bases: Enum

連絡先の presence (engine OnlineStatus を +1 シフトで写す)。

resoio.contact.ListContactsResponse dataclass

ListContactsResponse(
    contacts: list[ContactInfo] = betterproto2.field(
        1, betterproto2.TYPE_MESSAGE, repeated=True
    ),
    contact_count: int = betterproto2.field(2, betterproto2.TYPE_INT32),
    request_count: int = betterproto2.field(3, betterproto2.TYPE_INT32),
    list_loaded: bool = betterproto2.field(4, betterproto2.TYPE_BOOL),
)

Bases: Message

contact_count class-attribute instance-attribute

contact_count: int = field(2, TYPE_INT32)

ContactManager のカウント (filter / search 適用前の総数)。

list_loaded class-attribute instance-attribute

list_loaded: bool = field(4, TYPE_BOOL)

連絡先リストが cloud から同期済みか。

resoio.contact.GetContactResponse dataclass

GetContactResponse(
    contact: ContactInfo | None = betterproto2.field(
        1, betterproto2.TYPE_MESSAGE, optional=True
    ),
    found: bool = betterproto2.field(2, betterproto2.TYPE_BOOL),
)

Bases: Message

found class-attribute instance-attribute

found: bool = field(2, TYPE_BOOL)

user_id が連絡先キャッシュに無ければ false (contact は既定値)。

resoio.contact.SearchUsersResponse dataclass

SearchUsersResponse(
    results: list[UserSearchResult] = betterproto2.field(
        1, betterproto2.TYPE_MESSAGE, repeated=True
    ),
)

Bases: Message

resoio.contact.AddContactResponse dataclass

AddContactResponse(
    contact: ContactInfo | None = betterproto2.field(
        1, betterproto2.TYPE_MESSAGE, optional=True
    ),
)

Bases: Message

resoio.contact.AcceptRequestResponse dataclass

AcceptRequestResponse(
    contact: ContactInfo | None = betterproto2.field(
        1, betterproto2.TYPE_MESSAGE, optional=True
    ),
)

Bases: Message