FaciLinux

Guide Facili per Linux

scripting

scripting

Telegram URL caching

- Posted in scripting by

Nello sviluppo di un bot di Telegram ho avuto la necessità di caricare le immagini gif animate dei radar meteo dell'ARPAV, che vengono aggiornate con una certa frequenza.

In una prima versione le immagini venivano scaricate in locale e poi caricate su Telegram.

Leggendo la documentazione delle API Telegram del metodo "sendDocument"

File to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data.

volevo velocizzare la risposta del bot alla richiesta del client sfruttando la possibilità di far eseguire ai server Telegram il download dell'immagine.

Il metodo funziona, ma mi sono scontrato con un problema: le immagini non erano aggiornate, ma si riferivano ad anni indietro.

Telegram risulta fare il caching degli URL che vengono inviati e non c'è modo automatico per scatenarne un aggiornamento.
Ciò è dovuto probabilmente alla funzonalità di "Link Preview" (quando viene scritto un URL in una chat Telegram genera una preview) e si ripercuote anche sull'invio di documenti e immagini.
Altri riferimenti a questo comportamento sono documentati qui e qui anche se non ho trovato una documentazione ufficiale.

Per aggirare il problema ho seguito una soluzioneproposta in una delle due discussioni:
generare un URL variabile nel tempo che venga poi rediretto all'URL dell'immagine.

Su un server http (ad es. example.com) viene creato un file rd.php

<?php
header("Location: http://original.url.com/image.jpg");
die();
?>

e una directory /get/ nella quale viene posizionato questo file .htaccess

RewriteEngine on
RewriteRule ^(.*)$ http://example.com/rd.php

In questo modo ogni URL del tipo http://example.com/get/qualsiasicosa
viene riscritto come http://example.com/rd.php
e quindi viene rediretto all'URL http://original.url.com/image.jpg dell'immagine che deve essere caricata.

Poichè qualsiasicosa deve variare nel tempo il candidato ideale è una qualche forma di timestamp.

Questa configurazione è stata fatta utilizzando il servizio di hosting gratuito Altervista.

Dokuwiki è un potente wiki opensource che permette di editare, far versioning di documenti e caricare file e immagini, anch'essi sottoposti a controllo di versione.

Il controllo di versione funziona in modo trasparente se si utilizza l'interfaccia web di dokuwiki, ma supponiamo di avere dei file che vengono generati sul server che ospita la vostra istanza dokuwiki, e supponiamo di volerli rendere disponibili come media all'interno di dokuwiki stesso, con il controllo di versione.

Dokuwiki non offre nessuno strumento nativo per questo tipo di esigenza ma, con un po' di reverse engineering di come funziona il sistema di versioning di dokuwiki è possibile realizzare tale istanza, ovvero copiare localmente un file all'interno della struttura media di dokuwiki, mantenendone il versioning (potendo quindi ripristinare versioni precedenti, qualora lo si rendesse necessario).

Prima di entrare nella modalità operativa occorre spiegare un attimo come funziona dokuwiki e il suo sistema di versioning. Dokuwiki è un sistema che funziona senza database, quindi tutta la logica di funzionamento è presente all'interno di directory e files nella struttura dell'istanza di dokuwiki.

Supponiamo di voler mantenere aggiornato, con controllo di versione, il file logs.zip creato da uno script sul server stesso che monta l'istanza di dokuwiki. Supponiamo di mantenere il file logs.zip all'interno del contenitore generale media.

Se si fa l'upload da interfaccia web del file logs.zip, quello che avviene a livello di filesystem è che il file viene salvato nella directory <path_dokuwiki>/data/media . Se il file viene sostituito da una versione più recente, il media manager compie queste azioni:

  1. Calcola la data di ultima modifica in timestamp unix del file logs.zip originale
  2. Sposta il file logs.zip originale nella directory <path_dokuwiki>/data/media_attic e lo rinomina come logs.<unix_timestamp_ultima_modifica>.zip
  3. Aggiunge al file <path_dokuwiki>/data/media_meta/logs.zip.changes una riga, la cui sintassi viene descritta più avanti, che mantiene le informazioni per il versioning
  4. Copia il nuovo file logs.zip in <path_dokuwiki>/data/media

Volendo fare "l'upload" del file logs.zip dall'interno del server stesso occorre quindi simulare le operazioni svolte dal media manager di dokuwiki.

La sintassi dei file con estensione .changes, che sono responsabili del mantenimento di versione, è la seguente; per ogni nuova versione del file caricata viene aggiunta una riga contenente le seguenti informazioni, separate da tabulazione:

  1. tempo di ultima modifica in unix timestamp del nuovo file
  2. ip di origine
  3. Flag di creazione/modifica
  4. path del file in notazione namespace
  5. utente che ha fatto la modifica
  6. riga "creata" se creazione
  7. dimensione del file in byte

Usando uno script bash è possibile eseguire tutte le operazioni e i calcoli necessari, in particolare:

  1. tempo di ultima modifica in unix timestamp del nuovo file stat -c %Y
  2. ip di origine 127.0.0.1
  3. Flag di creazione/modifica C oppure E
  4. path del file in notazione namespace logs.zip
  5. utente che ha fatto la modifica (il proprio utente dokuwiki va bene)
  6. riga "creata" se creazione
  7. dimensione del file in byte ls -l file| awk '{print $5}'

Un ipotetico script in bash, quindi, conterrebbe le seguenti righe:

fileupd="<path>/logs.zip"
lastmod=$(stat -c %Y $fileupd)
fileupdsize=$(ls -l $fileupd| awk '{print $5}'
echo "$lastmod    127.0.0.1    E    logs.zip    mydoku-user        $fileupdsize >> <path_dokuwiki>/data/media_meta/logs.zip

Nello stesso script dovrebbe comparire anche la linea relativa allo spostamento e alla rinomina della vecchia versione del file logs.zip all'interno della directory <path_dokuwiki>/data/media_attic:

mv <path_dokuwiki>/media/logs.zip <path_dokuwiki>/media_attic/logs.$(stat -c %Y <path_dokuwiki>/media/logs.zip).zip

Infine, resta da copiare il nuovo file logs.zip all'interno della directory media e sistemarne i permessi perché sia leggibile all'utente che esegue l'istanza web (per Debian/Ubuntu, ad esempio, è l'utente www-data

mv $fileupd <path_dokuwiki>/media/
chown www-data:www-data <path_dokuwiki>/media/logs.zip

Per rendere il tutto automatico è possibile sfruttare naturalmente cron/anacron, così da far eseguire lo script senza necessità di interazione.

Teamviewer© è un software per il controllo remoto di una postazione; viene distribuito per tutti i maggiori sistemi operativi, Linux incluso. Se avete installato il software completo, pacchettizzato in formato deb o rpm, viene anche aggiunto un canale ai vostri repository per l'aggiornamento del software, ma soprattutto viene aggiunto un demone, teamviewerd, che parte all'avvio del computer e resta in attesa di connessioni. Il demone è necessario anche se usiamo la nostra postazione per controllarne un'altra, ma ha naturalmente la doppia funzione; quando si installa Teamviewer anche la nostra macchina diventa potenzialmente controllabile da remoto. Certo, è necessario avere l'accoppiata di codice id e password, ma se non vi piace l'idea di avere un demone sempre in ascolto per una connessione remota sulla vostra postazione, ecco come fare per avviare Teamviewer, demone incluso, solo quando è strettamente necessario.

Innanzitutto occorre creare uno script wrapper, semplicemente uno script bash che si occupa di:

  • Avviare il demone (chiedendo delle credenziali amministrative)
  • Avviare l'interfaccia di Teamviewer
  • Alla chiusura di Teamviewer fermare il demone

Prendete lo script bash che trovate qui sotto e salvatelo come teamviewer-wrapper all'interno di una directory compresa nel vostro PATH di ricerca degli eseguibili (generalmente $HOME/bin può essere una buona scelta se siete gli unici utilizzatori del pc):

#!/bin/bash
#A wrapper for teamviewer
#Runs teamviewer daemon only when needed

#Set teamviewer path
teamv_path="/opt/teamviewer/tv_bin/"

#check path existence
if [ ! -d $teamv_path ]; then
    zenity --error --text "Errore.\nIl percorso $teamv_path non esiste."
    exit 1
else
    pid_daemon=$(pidof teamviewerd)
    if [ ! $pid_daemon == '' ]; then
        zenity --warning --text "Attenzione, il demone di teamviewer era già in esecuzione.\nPer disabilitarne l'avvio automatico usa il comando\n\nsudo systemctl disable teamviewerd\n\nda terminale."
    else
        pkexec /opt/teamviewer/tv_bin/teamviewerd -d
        pid_daemon=$(pidof teamviewerd)
    fi
    if [ $pid_daemon -gt 1 ]; then
        /opt/teamviewer/tv_bin/TeamViewer
        pkexec kill -9 $pid_daemon
        pid_daemon=$(pidof teamviewerd)
        if [ ! $pid_daemon == '' ]; then
            zenity --warning --text "Attenzione, il demone di teamviewer sembra ancora in esecuzione"
        fi
    fi
fi

A questo punto rendiamo lo script eseguibile; apriamo una finestra di terminale e digitiamo:

chmod +x $HOME/bin/teamviewer-wrapper

Ora occorre fermare e disabilitare il demone teamviewerd, i comandi da eseguire da terminale sono:

sudo systemctl disable teamviewerd
sudo systemctl stop teamviewerd

Ora potete lanciare il comando teamviewer-wrapper dal terminale; se volete integrarlo nel menu del vostro desktop, potete copiare il contenuto riportato qui sotto all'interno della directory $HOME/.local/share/applications, salvando il file con il nome com.teamviewer.TeamViewer.desktop

#!/usr/bin/env xdg-open
[Desktop Entry]
Version=1.0
Encoding=UTF-8
Type=Application
Categories=Network;

Name=TeamViewer 13
Comment=Remote control and meeting solution.
Exec=env teamviewer-wrapper

Icon=TeamViewer
Terminal=false

Aggiornamento di Teamviewer

Ogni volta che il pacchetto Teamviewer viene aggiornato, il demone teamviewerd viene riabilitato e fatto partire in modo silente, quindi dopo l'aggiornamento occorre ricordarsi di dare questi due comandi, per fermare e disabilitare nuovamente l'avvio al boot del demone:

sudo systemctl disable teamviewerd
sudo systemctl stop teamviewerd