feat(meeting): add meeting channel with follow and join entry points - #18
Conversation
8a2b29f to
8a3c01f
Compare
| """A single-consumer queue that awaits each handler in turn.""" | ||
|
|
||
| def __init__(self, *, on_handler_error: Callable[[BaseException], Any]) -> None: | ||
| self._queue: "asyncio.Queue[Optional[Tuple[List[Callable], Any]]]" = ( |
There was a problem hiding this comment.
Done — the queue is now bounded at MAX_QUEUED_DELIVERIES = 1000 per session.
Two things fell out of deciding which end to drop, so I want to flag them
rather than leave them implicit:
Overflow rejects the newest, not the oldest. Order is the guarantee this
queue exists for — a document swap arrives as magic_share_ended then
magic_share_started — so evicting from the front would split such a pair and
hand the application a queue that still looks complete. Blocking the producer
was not available either: it would park the socket's message handler or the poll
loop, and with one thread that stalls every meeting and the heartbeat with it.
Rejecting at the tail keeps what is queued contiguous, so a gap is a gap at the
end.
Error reports get headroom above the ceiling (REPORT_RESERVE = 32).
Teardown submits here — the end event and any error raised by the departure
call — and those are what explain why a session went away. A ceiling filled with
transcripts must not be able to drop the explanation and keep the noise. The
reserve is bounded too, so a handler that raises on every delivery cannot grow
the queue through the reports about it.
Drops are counted and surface as dropped on get_meeting_event_health(), with
a row in the diagnostics table in docs/meeting-channel.md. A silent drop is
exactly the failure that readout exists to make visible.
Five tests cover it, each verified to fail against the corresponding wrong
implementation: no ceiling, evict-oldest, no report headroom, unbounded
headroom, and drops from retired sessions not reaching the readout.
8a3c01f to
d6b2de7
Compare
What this adds
A meeting channel, so a bot can act on what happens during a meeting —
captions, in-meeting chat, participants joining and leaving, shared documents.
Two entry points, one session type. Moving from one to the other changes the
entry-point line and nothing else.
follow_my_meetingjoin_meetingconnect()send_messageBoth require the meeting's "allow agents to join" setting; joining as the bot
is additionally gated behind an application process.
Two smaller additions came out of the same work:
on_raw_event(event_type, handler)— subscribe to any Feishu event type thechannel does not wrap, and have it take effect on the dispatcher that is
already running.
get_meeting_event_health()— counters for diagnosing silence on this path.An undeclared subscription, a missing permission and a renamed field all look
like "nothing happened", so the counters separate them.
Notes for integrators
follow_my_meetingreads a meeting under a user's own authorization, andthe bot is not visible in the meeting. The
user_open_idyou pass is theidentity the SDK acts as; the SDK receives a string and cannot verify whose it
is.
MeetingChannelConfig.follow_allowlistgates it and defaults to open.meetingInvitedandon_raw_eventdo not pass throughPolicyConfig,SeenCachededup, the processing lock or the loop guard. Both default toopen;
MeetingChannelConfig.invite_allowlistgates the former.dispose()does not leave a meeting, which is what makes reconnects safe. Sodisconnect()leaves the bot in its meetings, and a process that is reallyexiting should
leave()each session first.needs
if event.self_echo: return.docs/meeting-channel.mdcovers ordering, caption settling, session limits andreclamation, and diagnostics.
docs/security.mdgained sections on user accesstokens and on the entry points that sit outside the message policy.
Compatibility
Additive only — nothing existing changed or was removed. Version 1.2.0 → 1.3.0.
New code imports only the standard library, and the package still installs
alongside
lark-oapi.Tests
1308 unit tests pass. 206 of them are new and live in
lark_channel/channel/meeting/tests/, covering event normalization across bothwire shapes the platform uses, dedup and caption settling, seat accounting and
reclamation evidence, credential hygiene (including values reachable through a
raised error's
__traceback__frame locals), event-loop affinity, and theraw-event registry. Two runnable samples are included under
samples/channel/.