đ©âđ« Tutoriels#
Dans cette page, nous essayons dâexpliquer comment rĂ©aliser un certain nombre dâactions avec notre librairie Python. IdĂ©alement, il vaut mieux la suivre Ă©tape par Ă©tape afin de suivre le cheminement, mais si vous vous sentez Ă lâaise, vous pouvez essayer dâaccĂ©der directement Ă la section qui vous intĂ©resse.
Les bases#
OlvidClient#
Pour interagir avec le daemon, il vous faudra systĂ©matiquement crĂ©er une instance de la classe OlvidClient. Il peut sâagir de la classe dâorigine ou dâune classe enfant.
Cette classe va automatiquement rĂ©cupĂ©rer une clĂ© client en utilisant lâenvironnement ou un fichier .env. (cf. Configuration)
Grùce à ce client, on pourra notamment exécuter des commandes et mettre en place des listeners de notifications.
Voici Ă quoi ressemble un fichier main.py de base contenant la crĂ©ation dâun client Olvid et lâexĂ©cution dâune commande (afficher lâidentitĂ© courante).
Cette structure est Ă utiliser dans chacun des exemples de code de cette page, il suffit de remplacer le contenu de la fonction main par le code de votre choix.
import asyncio
from olvid import OlvidClient, datatypes
async def main():
client = OlvidClient()
# code to replace
print(await client.identity_get())
asyncio.set_event_loop(asyncio.new_event_loop())
asyncio.get_event_loop().run_until_complete(main())
Commande#
Toutes les méthodes gRPC de commandes exposées par le daemon sont facilement accessibles grùce à des méthodes de la classe OlvidClient.
Par exemple, pour envoyer un message (mĂ©thode MessageSend en gRPC), on utilisera la mĂ©thode message_send de notre instance dâOlvidClient.
Dans le cas oĂč nous connaissons lâidentifiant de la discussion dans laquelle poster, cela donnerait :
from olvid import OlvidClient
client = OlvidClient()
client.message_send(discussion_id=1, body="Use Olvid !")
Notification#
La classe OlvidClient implémente également des méthodes qui permettent de facilement écouter les notifications émises par le daemon.
Ces mĂ©thodes commencent toutes par le prĂ©fixe on_ et doivent ĂȘtre redĂ©finies dans une classe fille dâOlvidClient.
Par exemple, pour afficher dans le terminal quand un message est reçu et lorsquâune rĂ©action est ajoutĂ©e, on peut faire :
import asyncio
from olvid import OlvidClient, datatypes
class Bot(OlvidClient):
async def on_message_received(self, message: datatypes.Message):
print(f"Message received: {message.body}")
async def on_message_reaction_added(self, message: datatypes.Message, reaction: datatypes.MessageReaction):
print(f"Reaction added: {reaction.reaction}")
async def main():
bot = Bot()
await bot.run_forever()
asyncio.set_event_loop(asyncio.new_event_loop())
asyncio.get_event_loop().run_until_complete(main())
Bonnes pratiques#
Invitations#
Pour rendre plus facile la mise en relation avec un bot, il est possible dâactiver lâacceptation automatique des invitations. Il suffit de modifier la configuration du daemon Ă lâaide la mĂ©thode enable_auto_invitation dâun client Olvid.
Note
Lâacceptation automatique des invitations ne peut accepter que les prĂ©sentations, les invitations de groupe et les invitations Ă une discussion personnelle. Il ne peut pas aller au bout des invitations directes avec Ă©change de SAS code.
Voici un programme qui lance un bot aprĂšs avoir configurĂ© lâacceptation automatique des invitations.
import asyncio
from olvid import OlvidClient, datatypes
class Bot(OlvidClient):
async def on_message_received(self, message: datatypes.Message):
print(f"Message received: {message.body}")
async def main():
bot = Bot()
await bot.enable_auto_invitation(accept_all=True)
await bot.run_forever()
asyncio.set_event_loop(asyncio.new_event_loop())
asyncio.get_event_loop().run_until_complete(main())
Nettoyage des messages#
Pour des raisons de performances et de confidentialitĂ© nous vous conseillons dâactiver le nettoyage automatique des messages.
Il est possible de limiter le nombre de messages conservĂ©s globalement ou par discussion (global_count et discussion_count) et/ou de dĂ©finir lâĂąge maximal dâun message (existence_duration).
Nous vous conseillons aussi dâactiver la suppression des messages dans les discussions fermĂ©es.
from olvid import OlvidClient
async def main():
client = OlvidClient()
# keep messages up to 7 days,
# with a maximum of 100 messages and 20 messages per discussions,
# and deletes messages when a discussion is locked
await client.set_message_retention_policy(global_count=100, discussion_count=20,
existence_duration=60*60*24*7, clean_locked_discussions=True)
Docker#
Une fois votre programme prĂȘt Ă ĂȘtre dĂ©ployĂ© nous vous conseillons dâutiliser notre image docker python-runner pour lâexĂ©cuter. Elle est configurĂ©e pour installer les dĂ©pendances de votre projet et exĂ©cuter votre programme.
Veillez simplement Ă ce que votre projet respecte lâarborescence suivante. Vous pouvez ajouter autant de fichiers que nĂ©cessaire, tant que votre programme se lance Ă partir dâun fichier main.py.
| app
| | main.py
| | requirements.txt
Il vous suffit ensuite dâajouter un service Ă votre fichier docker-compose.yaml.
bot:
image: olvid/bot-python-runner:{{docker_version}}
# pass client key to use in environment
environment:
- OLVID_CLIENT_KEY= # TODO set value
# mount your bot code as a volume
volumes:
- ./app:/app
depends_on:
- daemon
Et enfin de lancer votre bot.
# start bot
docker compose up -d bot
# show bot logs
docker compose logs -f bot
Divers#
Envoyer un message éphémÚre#
Les points dâentrĂ©e API messageSend et messageSendWithAttachments permettent de spĂ©cifier lâĂ©phĂ©mĂ©ralitĂ© du message Ă envoyer.
On utilisera pour cela lâobjet olvid.datatypes.MessageEphemerality.
Voici un exemple en python. Il est possible de spécifier les paramÚtres read_once, visibility_duration et existence_duration de maniÚre indépendante.
Les durĂ©es dâexistence et de visibilitĂ© sont en secondes.
import asyncio
from olvid import datatypes, OlvidClient
async def main():
client = OlvidClient()
async for discussion in client.discussion_list():
await client.message_send(
discussion_id=discussion.id,
body="Self-destruct message",
ephemerality=datatypes.MessageEphemerality(
visibility_duration=10,
existence_duration=60,
read_once=True
)
)
asyncio.run(main())
Utilisation avancée#
Listener#
Pour une implĂ©mentation plus fine de lâĂ©coute des notifications, il est possible dâutiliser la notion de Listener. Un listener est une souscription dâune fonction callback Ă un type de notification. Cette fonction sera appelĂ©e Ă chaque fois quâune notification de ce type est reçue.
Chaque type de notification a sa propre classe dans le module olvid.listeners.
Dans cet exemple, la mĂ©thode reply_to_message sera appelĂ©e Ă chaque fois quâun message arrive.
import asyncio
from olvid import OlvidClient, datatypes, listeners
async def reply_to_message(message: datatypes.Message):
await message.reply(f"Reply to: {message.body}")
async def main():
client = OlvidClient()
listener = listeners.MessageReceivedListener(handler=reply_to_message)
client.add_listener(listener)
await client.run_forever()
asyncio.set_event_loop(asyncio.new_event_loop())
asyncio.get_event_loop().run_until_complete(main())
Listener: expiration#
Par dĂ©faut, un listener Ă©coute les notifications pour toujours, mais il est possible dâutiliser lâargument count pour nâĂ©couter quâun certain nombre de notifications.
Dans ce cas, lorsque que count notifications ont Ă©tĂ© traitĂ©es, le listener est arrĂȘtĂ©.
Dans cet exemple, on rĂ©pond au prochain message reçu puis le programme sâarrĂȘte.
import asyncio
from olvid import OlvidClient, datatypes, listeners
async def reply_to_message(message: datatypes.Message):
await message.reply(f"Reply to: {message.body}")
async def main():
client = OlvidClient()
# added count parameter set to 1
listener = listeners.MessageReceivedListener(handler=reply_to_message, count=1)
client.add_listener(listener)
# wait_for_listeners_end: returns when all listeners are finished
await client.wait_for_listeners_end()
print("Program end")
asyncio.set_event_loop(asyncio.new_event_loop())
asyncio.get_event_loop().run_until_complete(main())
Listener : filtrage#
Les listeners permettent Ă©galement de filtrer les notifications Ă traiter. Pour cela, on peut ajouter une ou plusieurs fonctions de filtrage Ă notre listener. Les diffĂ©rentes formes de filtrage dĂ©pendent du type de notification et sont dĂ©fini dans les messages du type MessageReceivedNotificationSubscription (cf description protobuf de lâAPI du daemon).
Par exemple, on peut vouloir traiter uniquement les messages envoyés par un certain contact.
import asyncio
from olvid import OlvidClient, datatypes, listeners
CONTACT_ID: int = 1
async def reply_to_message(message: datatypes.Message):
await message.reply(f"Reply to: {message.body}")
async def main():
client = OlvidClient()
# only notifications matching check_sender_id will be handled
listener = listeners.MessageReceivedListener(handler=reply_to_message, filter=datatypes.MessageFilter(sender_contact_id=CONTACT_ID))
client.add_listener(listener)
await client.wait_for_listeners_end()
asyncio.set_event_loop(asyncio.new_event_loop())
asyncio.get_event_loop().run_until_complete(main())
Il est tout Ă fait possible de combiner le filtrage et lâexpiration.
Ici, on lâutilise pour effectuer une action et quitter le programme quand le message que lâon vient dâenvoyer arrive sur le tĂ©lĂ©phone de son destinataire.
import asyncio
from olvid import OlvidClient, datatypes, listeners
DISCUSSION_ID: int = 1
async def main():
client = OlvidClient()
# send a message
message = await client.message_send(discussion_id=DISCUSSION_ID, body="Hello there !")
# add a listener to do something when message had been delivered, then program will exit
listener = listeners.MessageDeliveredListener(
handler=lambda m: print("Message delivered"),
message_ids=[message.id],
count=1
)
client.add_listener(listener)
await client.wait_for_listeners_end()
print("Program end")
asyncio.set_event_loop(asyncio.new_event_loop())
asyncio.get_event_loop().run_until_complete(main())