def create_gateway(
config: GatewayConfig,
*,
configure: GatewayConfigure | None = None,
client: Any | None = None,
) -> Starlette:
r"""创建一个轻量的 Starlette 飞书网关应用。"""
if not config.service_keys:
raise ValueError("GatewayConfig.service_keys must contain at least one service API key")
if configure is not None and config.encrypt_key is None:
raise ValueError("GatewayConfig.encrypt_key is required when configure is provided")
owns_client = client is None
feishu_client = client or FeishuClient(
config.app_id,
config.app_secret,
region=config.region,
base_url=config.base_url,
accounts_url=config.accounts_url,
)
seen_store = InMemorySeenStore()
routes = create_gateway_routes(config, feishu_client)
dispatcher: EventDispatcher | None = None
if config.encrypt_key is not None:
configured = configure(GatewayContext(feishu_client, seen_store)) if configure is not None else None
dispatcher = configured or EventDispatcher()
routes.extend(
[
create_event_route(
dispatcher,
encrypt_key=config.encrypt_key,
verification_token=config.verification_token,
seen_store=seen_store,
max_age_seconds=config.event_max_age_seconds,
),
create_card_route(
dispatcher,
encrypt_key=config.encrypt_key,
verification_token=config.verification_token,
seen_store=seen_store,
max_age_seconds=config.event_max_age_seconds,
),
]
)
@asynccontextmanager
async def lifespan(app: Starlette) -> AsyncIterator[None]:
app.state.feishu_client = feishu_client
app.state.seen_store = seen_store
app.state.event_dispatcher = dispatcher
try:
yield
finally:
if owns_client:
close = getattr(feishu_client, "aclose", None)
if close is not None:
await close()
return Starlette(routes=routes, lifespan=lifespan)