Intégration externe (cache Peer)¶
Guide complet pour intégrer le cache Stream Fusion dans une application tierce via l'API Peer.
Obtenir une PeerKey¶
Demandez à l'administrateur de l'instance Stream Fusion de créer une PeerKey pour votre application. Vous recevrez :
| Information | Description |
|---|---|
key_id |
UUID identifiant la clé |
secret |
Secret 256-bit hex (affiché une seule fois) |
Conserver le secret
Le secret n'est affiché qu'une seule fois à la création. Stockez-le de manière sécurisée.
Authentifier vos requêtes¶
import hmac, hashlib, json, time, requests
def make_authenticated_request(
url: str,
key_id: str,
secret: str,
payload: dict
) -> dict:
body = json.dumps(payload).encode()
timestamp = int(time.time())
body_hash = hashlib.sha256(body).hexdigest()
message = f"{timestamp}.{body_hash}"
signature = hmac.new(
secret.encode(), message.encode(), hashlib.sha256
).hexdigest()
headers = {
"Content-Type": "application/json",
"X-Peer-Key-Id": key_id,
"X-Peer-Timestamp": str(timestamp),
"X-Peer-Signature": signature,
}
response = requests.post(url, headers=headers, data=body)
return response.json()
#!/bin/bash
KEY_ID="a1b2c3d4-e5f6-7890-abcd-ef1234567890"
SECRET="9f8e7d6c5b4a3918273645a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8901234"
TIMESTAMP=$(date +%s)
BODY='{"query":"matrix","limit":20}'
BODY_HASH=$(echo -n "$BODY" | sha256sum | cut -d' ' -f1)
MESSAGE="${TIMESTAMP}.${BODY_HASH}"
SIGNATURE=$(echo -n "$MESSAGE" | openssl dgst -sha256 -hmac "$SECRET" | cut -d' ' -f2)
curl -X POST https://sf.example.com/api/peer/public/search \
-H "Content-Type: application/json" \
-H "X-Peer-Key-Id: $KEY_ID" \
-H "X-Peer-Timestamp: $TIMESTAMP" \
-H "X-Peer-Signature: $SIGNATURE" \
-d "$BODY"
Déchiffrer les réponses¶
import base64, hashlib, json
from cryptography.fernet import Fernet
def derive_fernet_key(secret: str) -> bytes:
prefix = "sf-peer-cache-v1:"
key_material = prefix + secret
key = hashlib.sha256(key_material.encode()).digest()
return base64.urlsafe_b64encode(key)
def decrypt_payload(secret: str, payload: str) -> dict:
key = derive_fernet_key(secret)
f = Fernet(key)
decrypted = f.decrypt(payload.encode()).decode()
return json.loads(decrypted)
Exemples d'utilisation¶
Recherche publique (Meilisearch)¶
result = make_authenticated_request(
url="https://sf.example.com/api/peer/public/search",
key_id=KEY_ID, secret=SECRET,
payload={"query": "matrix 1080p", "limit": 20}
)
data = decrypt_payload(SECRET, result["payload"])
# data = {"hits": [...], "total_hits": 99}
Recherche privée (PostgreSQL)¶
result = make_authenticated_request(
url="https://sf.example.com/api/peer/private/search",
key_id=KEY_ID, secret=SECRET,
payload={"tmdb_id": 155, "limit": 20}
)
data = decrypt_payload(SECRET, result["payload"])
# data = {"items": [...], "total": 42}
Export paginé (sync)¶
# Première page
result = make_authenticated_request(
url="https://sf.example.com/api/peer/private/export",
key_id=KEY_ID, secret=SECRET,
payload={"limit": 500, "since": last_sync_timestamp}
)
data = decrypt_payload(SECRET, result["payload"])
# data = {"items": [...], "next_cursor": "abc...", "count": 500}
# Page suivante
result = make_authenticated_request(
url="https://sf.example.com/api/peer/private/export",
key_id=KEY_ID, secret=SECRET,
payload={"limit": 500, "cursor": data["next_cursor"]}
)
# Continuer tant que next_cursor n'est pas null
Lookup IMDB¶
result = make_authenticated_request(
url="https://sf.example.com/api/peer/imdb/lookup",
key_id=KEY_ID, secret=SECRET,
payload={"imdb_id": "tt0111161", "limit": 10}
)
data = decrypt_payload(SECRET, result["payload"])
# data = {"results": [{"imdb_id": "tt0111161", "primary_title": "The Shawshank Redemption", ...}]}
Gestion des erreurs¶
| Code | Cause | Action |
|---|---|---|
200 |
Succès | Déchiffrer le payload |
400 |
Requête invalide | Vérifier le corps JSON |
401 |
Auth échouée | Vérifier headers HMAC et timestamp (±60s) |
403 |
Clé inactive/expirée | Contacter l'admin |
429 |
Rate limiting | Attendre et réessayer |
500 |
Erreur serveur | Réessayer plus tard |
Bonnes pratiques¶
- Cachez les résultats localement pour réduire les appels API
- Utilisez
since+cursorpour la sync incrémentale (seul le delta) - Respectez le rate limiting (attendre en cas de
429) - Stockez le secret dans un gestionnaire de secrets, jamais en clair dans le code
- Planifiez une rotation régulière des PeerKeys