Differenze tra le versioni di "GOLEM Telegram Bot"

Da GolemWiki.
Jump to navigation Jump to search
(Creata pagina con 'Il bot Telegram del GOLEM è in fase di '''testing''', e per ora il codice sorgente può essere consultato solamente dai nostri soci attraverso l'interfaccia WebDav di ILS opp...')
 
m (aggiornamenti sulla dockerizzazione)
 
(5 versioni intermedie di 2 utenti non mostrate)
Riga 1: Riga 1:
Il bot Telegram del GOLEM è in fase di '''testing''', e per ora il codice sorgente può essere consultato solamente dai nostri soci attraverso l'interfaccia WebDav di ILS oppure su richiesta.
+
Su questa pagina si trovano...
 +
* ''Guida all'uso:'' un breve manuale d'uso del BOT (per gli addetti ai lavori o chi vuol replicarlo)
 +
* ''Creare un BOT:'' un prontuario per creare un nuovo BOT
 +
* ''Documentazione:'' una rapida descrizione del codice del GOLEM BOT
  
== Creare un BOT ==
+
Il BOT del GOLEM provvede ad indirizzare messaggi, foto e video sul [https://web.telegram.org/#/im?p=@golem_empoli canale Telegram dell'associazione], permettendo anche di controllare chi può inviare i messaggi e pianificarne l'invio in momenti successivi.
 +
'''Nota:''' da gennaio 2020, la funzionalità di invio differito è integrata nell'applicazione ufficiale.
 +
 
 +
Il bot è in fase di '''testing''' perenne ed è scritto coi piedi, ma al momento sta correttamente funzionando sul nostro VPS.
 +
 
 +
* Il codice sorgente può essere consultato sul [https://git.golem.linux.it/golem/golem-telegram-bot repository git dedicato].
 +
* Da dicembre 2020 è stato leggermente riadattato per girare in un'immagine Docker, chiedere al syadmin.
 +
 
 +
= Guida d'uso =
 +
Il BOT è raggiungibile col nome [http://t.me/GOLEMpoliBot @GOLEMpoliBot], naturalmente riceve messaggi da chiunque, ma prende in considerazione solo quelli provenienti dagli utenti da noi abilitati.
 +
I restanti utenti saranno indirizzati verso il [http://t.me/golem_empoli canale].
 +
 
 +
La prima volta che viene contattato, il BOT si presenta illustrando funzionalità e comandi.
 +
 
 +
<gallery>
 +
File:Telegram-bot-01.png
 +
</gallery>
 +
 
 +
Scritto un messaggio, viene richiesto se si intende inviarlo immediatamente (OK) o successivamente (Programma).
 +
Nel primo caso si riceverà semplicemente la conferma del corretto invio.
 +
Nel secondo caso vengono mostrati, in due step, i menù per impostare data ed ora di invio.
 +
È possibile interrompere la procedura in qualsiasi momento, tornando nella situazione iniziale.
 +
 
 +
<gallery>
 +
File:Telegram-bot-02.png
 +
File:Telegram-bot-3.png
 +
File:Telegram-bot-4.png
 +
File:Telegram-bot-5.png
 +
</gallery>
 +
 
 +
I messaggi pianificati da qualsiasi utente sono consultabili mediante il comando <code>/list</code>. Allo stato attuale è possibile pianificare anche foto e video, ma non compaiono "graficamente" nella lista.
 +
 
 +
<gallery>
 +
File:Telegram-bot-7.png
 +
</gallery>
 +
 
 +
= Creare un BOT =
 
Aprire una chat col bot [https://telegram.me/botfather BotFather] e creare un nuovo bot seguendo le intuitive istruzioni interattive. Generare anche il ''token''. Il token è un codice casuale, ma univoco una volta creato, che serve agli sviluppatori per accedere al bot.
 
Aprire una chat col bot [https://telegram.me/botfather BotFather] e creare un nuovo bot seguendo le intuitive istruzioni interattive. Generare anche il ''token''. Il token è un codice casuale, ma univoco una volta creato, che serve agli sviluppatori per accedere al bot.
  
Riga 68: Riga 107:
 
A questo punto il nostro programma non deve far altro che leggere il JSON che gli è stato inviato tramite HTTP POST e decidere cosa fare. Il JSON contiene il messaggio e tutti i metadati relativi ad esso (presenza di link, emoticon, allegati come foto, video, ecc...) e per il suo contenuto ci sono varie strutture documentate [https://core.telegram.org/bots/api#making-requests].
 
A questo punto il nostro programma non deve far altro che leggere il JSON che gli è stato inviato tramite HTTP POST e decidere cosa fare. Il JSON contiene il messaggio e tutti i metadati relativi ad esso (presenza di link, emoticon, allegati come foto, video, ecc...) e per il suo contenuto ci sono varie strutture documentate [https://core.telegram.org/bots/api#making-requests].
  
== Cosa fa il nostro bot ==
+
Il BOT inoltra sul canale qualsiasi messaggio, a patto che il mittente sia fra gli utenti autorizzati.
Il nostro bot riceve messaggi da chiunque, ma prende in considerazione solo quelli provenienti dagli utenti che noi abilitiamo (per ragioni che saranno ovvie presto).
+
 
 +
= Documentazione =
 +
Con l'ultima versione di codice il bot si comporta come segue: se è ricevuto del testo puro oppure un'immagine, viene richiesto mediante tastiera inline se si vuole inoltrare il contenuto al nostro canale Telegram, se si vuole programmare l'invio per il futuro oppure se si vuol annullare l'operazione.
 +
Il caso di invio programmato compaiono di seguito un calendario ed una lista di orari che consentono la pianificazione.
 +
 
 +
Il bot accetta anche alcuni comandi, come <code>/help</code> per avere rapide informazioni sul funzionamento e <code>/list</code> per prendere visione dei messaggi pianificati.
 +
 
 +
'''Oss:''' a proposito di questo uso "strano" del bot, abbiamo scelto di scrivere direttamente a lui e non di fargli leggere i comandi all'interno del nostro gruppo sia per snellire il processo di condivisione (basta fare copia-incolla del link di interesse o buttar giù un messaggio e dare l'OK), sia per non intasare il gruppo stesso con inutili chiacchiere col bot.
 +
 
 +
Tempo stimato per la condivisione: 3 secondi. Immediatezza d'uso: 1 Googol (circa 10<sup>100</sup>)
 +
 
 +
Un secondo script viene lanciato ogni ora dal server, controlla se ci sono messaggi pianificati, eventualmente li invia e li rimuove dalla coda.
 +
 
 +
==Più nel dettaglio==
 +
Attenzione: si tratta, allo stato attuale, di appunti sparsi in fase di scrittura
 +
 
 +
La realizzazione di quanto descritto in precedenza si scontra con la seguente difficoltà: ogni volta che l'utente compie un'azione col bot
 +
Ogni volta che un utente invia un messaggio al bot viene chiamato lo script. Ciò rende difficile scrivere un programma che compia azioni "sequenziali".
 +
 
 +
Si è cercato di identificare le possibili situazioni in cui il bot si dovrà trovare (ad esempio: in attesa di un messaggio oppure in attesa di una data) e le possibili operazioni che l'utente può compiere in ciascuno stato con le relative azioni che il bot prenderà (ad esempio: scrivere un comando, cliccare su un pulsante, eccetera). Nel caso del nostro bot ne viene fuori il grafico seguente:
 +
 
 +
[[File:Telegram-Bot-StateMachine.jpg | 600px | center]]
 +
 
 +
Le cosiddette ''callback'' sono particolari "messaggi" che si inviano al bot cliccando sui pulsanti delle tastiere inline (che noi abbiamo utilizzato ampiamente).
  
Il messaggio viene sempre inoltrato al nostro canale su Telegram, indipendentemente dal contenuto.
+
Il problema della perdita delle variabili che si ha fra un messaggio e l'altro è stato risolto mediante <code>Memcached</code>, un demone che permette di salvare o recuperare variabili in uno spazio di memoria condiviso. Si è stabilito che ogni variabile relativa ad un certo utente debba essere salvata nella forma <code>''codice_utente''-''nome_variabile''</code>.
Se il messaggio contiene un URL, allora si suppone che il link sia adatto per la mailing list, e allora viene analizzato, e se punta ad una pagina HTML con un campo ''title'' valido, viene inoltrato sulla nostra mailing list tradizionale.
 
  
'''Oss:''' abbiamo scelto di non mettere un comando per far ciò per snellire il processo di condivisione.
+
Ogni volta che il bot viene sollecitato lo script verifica che tipo di sollecitazione è stata fatta (callback, messaggio...) e si procede all'interpretazione dei dati. Vengono scartate richieste provenienti dagli utenti non autorizzati (che sono indirizzati verso il canale), da gruppi o dal canale stesso.
 +
Dopodiché viene recuperato lo stato in cui il bot si trova (relativo all'utente che ha lanciato la sollecitazione) e il percorso prosegue seguendo la macchina a stati.
  
Infine, un altro script indipendente osserva i cambiamenti sul feed RSS del nostro blog Wordpress, e quando ci sono dei nuovi articoli li inoltra sulla mailing list e sul canale.
+
[[Category:Officina]]
 +
[[Category:Howto]]

Versione attuale delle 13:32, 6 dic 2020

Su questa pagina si trovano...

  • Guida all'uso: un breve manuale d'uso del BOT (per gli addetti ai lavori o chi vuol replicarlo)
  • Creare un BOT: un prontuario per creare un nuovo BOT
  • Documentazione: una rapida descrizione del codice del GOLEM BOT

Il BOT del GOLEM provvede ad indirizzare messaggi, foto e video sul canale Telegram dell'associazione, permettendo anche di controllare chi può inviare i messaggi e pianificarne l'invio in momenti successivi. Nota: da gennaio 2020, la funzionalità di invio differito è integrata nell'applicazione ufficiale.

Il bot è in fase di testing perenne ed è scritto coi piedi, ma al momento sta correttamente funzionando sul nostro VPS.

  • Il codice sorgente può essere consultato sul repository git dedicato.
  • Da dicembre 2020 è stato leggermente riadattato per girare in un'immagine Docker, chiedere al syadmin.

Guida d'uso

Il BOT è raggiungibile col nome @GOLEMpoliBot, naturalmente riceve messaggi da chiunque, ma prende in considerazione solo quelli provenienti dagli utenti da noi abilitati. I restanti utenti saranno indirizzati verso il canale.

La prima volta che viene contattato, il BOT si presenta illustrando funzionalità e comandi.

Scritto un messaggio, viene richiesto se si intende inviarlo immediatamente (OK) o successivamente (Programma). Nel primo caso si riceverà semplicemente la conferma del corretto invio. Nel secondo caso vengono mostrati, in due step, i menù per impostare data ed ora di invio. È possibile interrompere la procedura in qualsiasi momento, tornando nella situazione iniziale.

I messaggi pianificati da qualsiasi utente sono consultabili mediante il comando /list. Allo stato attuale è possibile pianificare anche foto e video, ma non compaiono "graficamente" nella lista.

Creare un BOT

Aprire una chat col bot BotFather e creare un nuovo bot seguendo le intuitive istruzioni interattive. Generare anche il token. Il token è un codice casuale, ma univoco una volta creato, che serve agli sviluppatori per accedere al bot.

È una cosa brutta che assomiglia a questo:

110201543:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw

Contattare il bot tramite token

Costruire un URL tipo questo: https://api.telegram.org/botTOKEN/metodo

  • TOKEN è ovviamente il token che abbiamo generato
  • metodo è l'operazione che vogliamo effettuare

Ne esistono tante [1], noi ne vedremo alcune che ci servono.

getMe

Ottiene informazioni sul bot. Lo usiamo per vedere se i server di Telegram funzionano. Esempio di URL da consultare:

https://api.telegram.org/bot110201543:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw/getMe

Riceveremo in risposta un documento JSON che possiamo facilmente interpretare tramite Python o PHP per estrapolare le varie informazioni attraverso il nostro programma.

Ricevere gli aggiornamenti

Quando qualcuno scrive al bot, il messaggio viene inviato ai server di Telegram, che lo mantengono per un certo periodo (max 24 ore). Per leggerlo tramite il nostro bot (il nostro programma) esistono due modi:

  • query attiva via HTTP (getUpdates): a intervalli regolari, il nostro programma interroga i server di Telegram per sapere se c'è un nuovo messaggio. CONTRO: è grande spreco di risorse; PRO: utile per fare debugging;
  • query passiva via HTTP (WebHook): quando i server di Telegram ricevono un messaggio per il bot, saranno loro a contattare il nostro programma via HTTP; PRO: non spreca risorse CONTRO: necessità di un server web dedicato e debugging più ostico.

Alla fine, la soluzione con query passiva WebHook è decisamente quella più sensata.

Mentre si usa un WebHook non si può usare il getUpdates, e viceversa (ma va?).

WebHook

Per impostare un WebHook bisogna usare il metodo setWebhook, con una cosa del genere:

https://api.telegram.org/bot110201543:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw/setWebhook?url=

Se lasciamo url= vuoto in questo modo, cancelliamo il WebHook e Telegram non contatterà il nostro programma quando il nostro bot riceverà un messaggio. Utile per tornare nella modalità getUpdates e fare debugging.

Altrimenti, dobbiamo specificare l'URL a cui si trova il nostro programma, per esempio:

https://api.telegram.org/bot110201543:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw/setWebhook?url=https://golem.linux.it/directory/bot.php

Ovviamente non è quello, mica siamo così citrulli da scriverlo qui! :-) È meglio usare URL con nomi strani e caratteri casuali, così si evita che qualcuno possa inavvertitamente (o intenzionalmente) usare il nostro programma a sproposito. Siccome ci fa fatica pensare a dei caratteri casuali, facciamoci aiutare da questo comando:

dd if=/dev/urandom bs=1 count=12 | base64

Certificato SSL

Importante: tutte le query devono avvenire attraverso HTTPS (HTTP su SSL). Si può acquistare un certificato (sganciando parecchi euri), si può generare con Let's Encrypt oppure si può generare in locale e autofirmarlo (self-signed). La prima soluzione è la più immediata e costosa, la seconda e la terza sono meno immediate ma sono gratuita (free as in free beer, che non è poi così male).

Generiamo il nostro certificato [2]:

openssl req -newkey rsa:2048 -sha256 -nodes -keyout golem.linux.it.key -x509 -days 720 -out golem.linux.it.pem -subj "/C=IT/ST=Italy/L=Florence/O=GruppoLinuxEmpoli/CN=golem.linux.it"
  • -days 720 imposta la scadenza (nel caso specifico, tra due anni)
  • -keyout golem.linux.it.key specifica il nome del file su cui verrà scritta la nostra chiave privata (da custodire gelosamente)
  • -out golem.linux.it.pem specifica il nome del file su cui verrà scritta la nostra chiave pubblica (che manderemo a Telegram)

E impostiamo il nostro webserver per usarlo come certificato per l'HTTPS. Per esempio, ecco qui come farlo su Apache.

Mandiamo a Telegram la nostra chiave pubblica effettuando una richiesta HTTP di tipo POST invece che GET, con lo stesso URL di prima, e ovviamente allegando il nostro certificato pubblico. Per farlo possiamo usare curl con questo praticissimo comando:

curl -F "url=https://golem.linux.it/directory/bot.php" -F "certificate=@golem.linux.it.pem" https://api.telegram.org/bot110201543:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw/setWebhook

Il comando dovrebbe restituire un messaggio di successo dai server di Telegram.

Come doppio controllo, controlliamo che tutto funzioni davvero provando il metodo getUpdates: deve dare errore perché abbiamo impostato il WebHook.

Programma

Scriviamo il nostro programma (per esempio in PHP) e mettiamolo all'URL appena indicato a Telegram. Mandiamo un messaggio al nostro bot, e notiamo che il nostro script viene contattato (possiamo controllare /var/log/apache2/access.log per vedere se davvero viene chiamato. Si può usare tail -f su quel file per controllarlo in tempo reale)

A questo punto il nostro programma non deve far altro che leggere il JSON che gli è stato inviato tramite HTTP POST e decidere cosa fare. Il JSON contiene il messaggio e tutti i metadati relativi ad esso (presenza di link, emoticon, allegati come foto, video, ecc...) e per il suo contenuto ci sono varie strutture documentate [3].

Il BOT inoltra sul canale qualsiasi messaggio, a patto che il mittente sia fra gli utenti autorizzati.

Documentazione

Con l'ultima versione di codice il bot si comporta come segue: se è ricevuto del testo puro oppure un'immagine, viene richiesto mediante tastiera inline se si vuole inoltrare il contenuto al nostro canale Telegram, se si vuole programmare l'invio per il futuro oppure se si vuol annullare l'operazione. Il caso di invio programmato compaiono di seguito un calendario ed una lista di orari che consentono la pianificazione.

Il bot accetta anche alcuni comandi, come /help per avere rapide informazioni sul funzionamento e /list per prendere visione dei messaggi pianificati.

Oss: a proposito di questo uso "strano" del bot, abbiamo scelto di scrivere direttamente a lui e non di fargli leggere i comandi all'interno del nostro gruppo sia per snellire il processo di condivisione (basta fare copia-incolla del link di interesse o buttar giù un messaggio e dare l'OK), sia per non intasare il gruppo stesso con inutili chiacchiere col bot.

Tempo stimato per la condivisione: 3 secondi. Immediatezza d'uso: 1 Googol (circa 10100)

Un secondo script viene lanciato ogni ora dal server, controlla se ci sono messaggi pianificati, eventualmente li invia e li rimuove dalla coda.

Più nel dettaglio

Attenzione: si tratta, allo stato attuale, di appunti sparsi in fase di scrittura

La realizzazione di quanto descritto in precedenza si scontra con la seguente difficoltà: ogni volta che l'utente compie un'azione col bot Ogni volta che un utente invia un messaggio al bot viene chiamato lo script. Ciò rende difficile scrivere un programma che compia azioni "sequenziali".

Si è cercato di identificare le possibili situazioni in cui il bot si dovrà trovare (ad esempio: in attesa di un messaggio oppure in attesa di una data) e le possibili operazioni che l'utente può compiere in ciascuno stato con le relative azioni che il bot prenderà (ad esempio: scrivere un comando, cliccare su un pulsante, eccetera). Nel caso del nostro bot ne viene fuori il grafico seguente:

Telegram-Bot-StateMachine.jpg

Le cosiddette callback sono particolari "messaggi" che si inviano al bot cliccando sui pulsanti delle tastiere inline (che noi abbiamo utilizzato ampiamente).

Il problema della perdita delle variabili che si ha fra un messaggio e l'altro è stato risolto mediante Memcached, un demone che permette di salvare o recuperare variabili in uno spazio di memoria condiviso. Si è stabilito che ogni variabile relativa ad un certo utente debba essere salvata nella forma codice_utente-nome_variabile.

Ogni volta che il bot viene sollecitato lo script verifica che tipo di sollecitazione è stata fatta (callback, messaggio...) e si procede all'interpretazione dei dati. Vengono scartate richieste provenienti dagli utenti non autorizzati (che sono indirizzati verso il canale), da gruppi o dal canale stesso. Dopodiché viene recuperato lo stato in cui il bot si trova (relativo all'utente che ha lanciato la sollecitazione) e il percorso prosegue seguendo la macchina a stati.