اجرای کلاینت API
این مثال یک دیتابیس خالی AuthenticationServer را از طریق APIServer محلی در دسترس
میگذارد و وضعیت آن را میخواند. برنامهٔ نمونه فقط از کتابخانهٔ استاندارد Python
استفاده میکند و در مسیر
tunnels/APIServer/examples/api_client.py
در checkout سورس WaterWall قرار دارد.
ماژولهای tunnels/APIServer/client/ww_api.py و ww_api_cli.py بین این مثال و
CLI مدیریت مشترک است. هنگام کپی مثال عمومی،
دایرکتوریهای examples/ و client/ را کنار یکدیگر نگه دارید. برای مدیریت
روزمرهٔ حساب، CLI بدون نیاز به ساخت دستی فایل JSON درخواست، فرمانهای آماده دارد.
مثال عمومی بایتهای نتیجهٔ decodeشده را بدون تغییر در stdout مینویسد؛ transport
و پشتیبانی CLI به schema حساب وابسته نیستند.
زنجیره TcpListener -> APIServer است. gateway از API ثبتشدهٔ
AuthenticationServer که جداگانه پیکربندی شده استفاده میکند؛ node دیتابیس، node
بعدی این زنجیره نیست. این مثال به AuthenticationClient یا listener پروتکل
تولیدکننده نیاز ندارد.
ساخت پیکربندی محلی
از ریشهٔ مخزن WaterWall شروع کنید. دایرکتوری تازهای بسازید تا دیتابیس موجودی جایگزین نشود:
export WATERWALL_REPO="$(pwd)"
umask 077
mkdir api-demo
cd api-demo
پیکربندی و یک token تصادفی مستقل برای اپراتور بسازید:
python3 - <<'PY'
import json
from pathlib import Path
import secrets
token = secrets.token_hex(32)
Path("monitor-token").write_text(token + "\n", encoding="ascii")
Path("users.json").write_text('{"users":[]}\n', encoding="utf-8")
core = {"misc": {"workers": 1, "try-enabling-bbr": False}, "configs": ["config.json"]}
config = {
"name": "central",
"nodes": [
{"name": "auth-db", "type": "AuthenticationServer", "settings": {
"db-path": "users.json", "file-save-rate-ms": 60000,
"auth-clients": [{"name": "reserved-producer", "secret": secrets.token_hex(32)}]
}},
{"name": "api-listener", "type": "TcpListener", "settings": {
"address": "127.0.0.1", "port": 9080
}, "next": "management-api"},
{"name": "management-api", "type": "APIServer", "settings": {
"clients": [{"name": "monitor", "token": token, "allow": [{
"config": "central", "node": "auth-db",
"operations": ["status", "get-user", "list-users"]
}]}]
}}
]
}
for filename, value in (("core.json", core), ("config.json", config)):
Path(filename).write_text(json.dumps(value, indent=2) + "\n", encoding="utf-8")
PY
تنظیم auth-clients در AuthenticationServer باید غیرخالی باشد. تولیدکنندهٔ
رزروشدهٔ بالا هیچ مجوز و listener شبکهای ندارد. secret آن از token اپراتور API
جداست و نمیتواند درخواست API را احراز هویت کند.
WaterWall را از همین دایرکتوری، با فایل اجرایی نصبشده یا build موجود Linux، اجرا کنید:
"$WATERWALL_REPO/build/linux/Release/Waterwall" --config:core.json
مسیرهای core.json و db-path نسبت به دایرکتوری کاری فرایند هستند. برای محلهای
دیگر فایل اجرایی و پیکربندی، راهنمای راهاندازی
را ببینید. listener فقط محلی است؛ APIServer درخواست را احراز هویت میکند اما
transport را رمزنگاری نمیکند.
خواندن وضعیت سرور
در ترمینال دیگری وارد api-demo شوید و WATERWALL_REPO را روی مسیر مطلق checkout
خود تنظیم کنید. سپس اجرا کنید:
python3 "$WATERWALL_REPO/tunnels/APIServer/examples/api_client.py" \
--host 127.0.0.1 --port 9080 \
--client monitor --token-file monitor-token \
--config central --node auth-db --operation status
کلاینت بهصورت پیشفرض {} را بهعنوان بدنهٔ node میفرستد، یک پاسخ frameشدهٔ کامل
میخواند و بدنهٔ decodeشدهٔ نتیجهٔ node را روی stdout مینویسد. دیتابیس خالی مقدار
user_count: "0" میدهد. نتیجهٔ کامل در
مرجع AuthenticationServer
تعریف شده است؛ مقدارهایی مانند شمارندهها و revisionها رشتهٔ دهدهی هستند.
اعتبارنامهها از نتیجههای عمومی حذف شدهاند.
selector از نام منطقی پیکربندی یعنی central استفاده میکند، نه نام فایل
config.json. حذف --config فقط وقتی مجاز است که نام node میان تمام configهای
بارشده یکتا باشد. selector کامل، هدف را صریح نگه میدارد.
تأمین token و بدنهٔ درخواست
token از فایل یا متغیر محیطی خوانده میشود. برای حالت محیطی:
export WATERWALL_API_TOKEN="$(cat monitor-token)"
python3 "$WATERWALL_REPO/tunnels/APIServer/examples/api_client.py" \
--client monitor --token-env WATERWALL_API_TOKEN \
--config central --node auth-db --operation status
host و port پیشفرض 127.0.0.1:9080 هستند. محتوای token هرگز آرگومان خط فرمان
نیست. --body-file بایتهای درخواست node را تأمین میکند؛ با
--body-encoding utf8 پیشفرض، این بایتها باید UTF-8 بدون NUL باشند. برای
operation ثبتشدهای که بایت دلخواه میپذیرد، از --body-encoding base64 استفاده
کنید؛ خود کلاینت فایل را میخواند و base64 میکند. با --content-type نوع محتوای
ثبتشدهٔ operation را مشخص کنید؛ پیشفرض application/json است.
کلاینت frame پاسخ و ID همبستگی را بررسی میکند و دقیقاً یک بار تلاش میکند. خواندن یا نوشتن را خودکار تکرار نمیکند. برای ویرایش مشروط و تغییر رمز، در صورت نیاز راهنمای conflict یا نتیجهٔ نامعلوم را چاپ میکند. ID بیرونی درخواست فقط پاسخ را به درخواست مرتبط میکند و مانع اجرای دوبارهٔ operation نمیشود.
خطاهای busy و shutting_down در gateway یعنی handler فراخوانی نشده است؛ برای ساخت، ویرایش و تغییر رمز نیز
رد قطعیاند و retry خودکار ندارند. خطای بازگشتی node نتیجهٔ جداگانهٔ operation است. پاسخ گمشده یا خراب، timeout
و خطای سقف پاسخ پس از ارسال همچنان نتیجهٔ نامعلوم دارند. هر خواندن socket حداکثر 64 KiB درخواست میکند و تمام
chunkها در سقف frame پذیرفتهشده از همان deadline اصلی monotonic استفاده میکنند؛ short read مهلت را تمدید نمیکند.
ادامه را در CLI مدیریت، workflowهای سطح wire حسابهای احراز هویت یا transportهای HTTP و UDP قابل اعتماد بخوانید. راهنمای پروتکل API قالب frame، envelope و خطاها را برای نوشتن کلاینت دیگر توضیح میدهد؛ تنظیمات gateway و سقف منابع در مرجع APIServer قرار دارند.