Modello per un semplice bot di Telegram per gli scolari delle classi 7-9 utilizzando Powershell

Durante una conversazione con un amico, ho scoperto all'improvviso che nella loro scuola, ai bambini tra l'ottavo e il decimo anno non viene insegnato nulla di programmazione. Solo Word, Excel e basta. Nessun logo, nemmeno Pascal, nemmeno VBA per Excel.

Sono rimasto molto sorpreso, ho aperto Internet e ho iniziato a leggere -
Uno dei compiti della scuola specializzata è quello di promuovere l'educazione di una nuova generazione che risponda alle condizioni della società dell'informazione in termini di livello di sviluppo e di stile di vita.
Questo corso permetterà agli studenti di consolidare nella pratica la conoscenza delle costruzioni di base del linguaggio di programmazione Pascal. (dal programma di alcune scuole superiori del 2017)

Alla fine ho deciso di dedicare un paio d'ore a delineare un esempio di "come creare un semplice bot per gli scolari".

Di seguito è riportato un esempio di come scrivere un altro semplice bot in Powershell e farlo funzionare senza webhook, IP bianco, server dedicati, macchine virtuali distribuite nel cloud e così via, su un normale PC domestico con Windows.

TLDR: Un altro articolo noioso con errori grammaticali e fattuali, niente da leggere, niente umorismo, niente immagini.

Non c'è niente di nuovo nell'articolo, quasi tutto ciò che è stato scritto prima è già stato su Habr, ad esempio negli articoli Istruzioni: come creare bot su Telegram и Bot Telegram per l'amministratore di sistema.
Inoltre, l'articolo è volutamente ridondante per non fare ogni volta riferimento alla letteratura didattica. Non ci sono riferimenti a Gang 4, PowerShell Deep Dives o, ad esempio, ai 5 pilastri dell'AWS Well-Architected Framework nel testo.

Invece di una prefazione, puoi saltare

Sentiti libero di saltareNel 2006, Microsoft ha rilasciato PowerShell 1.0 per quelli che allora erano Windows XP, Vista e 2003 Server. In un certo senso, ha sostituito script come cmdbat, VB, Windows Script Host e JScript.

Anche adesso PowerShell può essere considerato solo come il passo successivo dopo le varianti Logo, invece di Delphi (o qualcosa di più vecchio) che probabilmente è ancora in uso da qualche parte, nonostante la presenza di cicli, classi, funzioni, chiamate MS GUI, Integrazioni Git e così via.

Powershell viene utilizzato relativamente raramente, è possibile incontrarlo solo sotto forma di PowerShell Core, VMware vSphere PowerCLI, Azure PowerShell, MS Exchange, Desired State Configuration, Accesso Web PowerShell e una dozzina di programmi e funzioni raramente utilizzati. Forse avrà una seconda vita con il rilascio di WSL2, ma questo non è certo.

Powershell presenta tre grandi vantaggi:

  1. È relativamente semplice, c'è molta letteratura ed esempi a riguardo, e anche in russo, ad esempio, un articolo su Foreach - dal libro PowerShell in profondità — sulla differenza tra () e {}
  2. Va con l'editore. ISE, incluso in Windows. C'è persino una specie di debugger.
  3. È facile chiamare da lì componenti per la creazione di un'interfaccia grafica.

0. Preparazione.

Abbiamo bisogno di:

  • PC con Windows (io ho Windows 10)
  • Almeno un qualche tipo di accesso a Internet (ad esempio tramite NAT)
  • Per coloro che hanno un accesso limitato a Telegram - installare e configurare Freegate nel browser, in alcuni casi complessi insieme a Symple DNS Crypt
  • Avere un client Telegram funzionante sul tuo telefono
  • Capire le basi: cos'è una variabile, un array, un ciclo.

Articoli aperti e letti - Istruzioni: come creare bot su Telegram и Bot Telegram per l'amministratore di sistema

1. Creiamo un altro bot di prova.

Dal momento che tutti lo sanno già ed è già successo, puoi anche saltarlo.Come affermato nell'articolo sopra - Prima di tutto, un bot per Telegram - Si tratta pur sempre di un'applicazione in esecuzione sul tuo computer che invia richieste all'API del bot di Telegram. Inoltre, l'API è intuitiva: il bot accede a un URL specifico con parametri e Telegram risponde con un oggetto JSON.

Problemi correlati: se in qualche modo prendi del codice da un oggetto JSON e in qualche modo lo invii per l'esecuzione (non di proposito), il codice verrà eseguito automaticamente.

Il processo di creazione è descritto nei due articoli precedenti, ma lo ripeto: in Telegram, apri i contatti, cerca @botfather, digli /newbot, crea un bot Botfortest12344321, chiamalo Mynext1234bot e ricevi un messaggio con una chiave univoca del formato 1234544311:AbcDefNNNNNNNNNNNN

Prenditi cura della chiave e non regalarla!

È possibile configurare ulteriormente il bot, ad esempio impedendone l'aggiunta ai gruppi, ma nei primi passaggi ciò non è necessario.

Chiediamo a BotFather "/mybot" e modifichiamo le impostazioni se qualcosa non ci piace.

Apriamo di nuovo i contatti, cerchiamo @Botfortest12344321 (bisogna iniziare la ricerca con @), clicchiamo su "start" e scriviamo al bot "/Gloria ai robot". Il segno / è obbligatorio, le virgolette non servono.
Il bot, ovviamente, non risponderà a nulla.

Controlliamo che il bot sia stato creato: apriamolo.

api.telegram.org/bot1234544311:AbcDefNNNNNNNNNNNNNN/getMe
dove 1234544311:AbcDefNNNNNNNNNNNNNN è la chiave ricevuta in precedenza,
e otteniamo una linea come questa
{"ok":true,"result":{""}}

Abbiamo la prima frase segreta (token). Ora dobbiamo scoprire la seconda cifra segreta: l'ID della chat con il bot. Ogni chat, gruppo, ecc. è individuale e ha un proprio numero (a volte con un segno meno, per i gruppi aperti). Per scoprire questo numero, dobbiamo richiedere nel browser (in realtà, non è necessario nel browser, ma per una migliore comprensione puoi iniziare da lì) l'indirizzo (dove 1234544311:NNNNNNNNNN è il tuo token).

https://api.telegram.org/bot1234544311:NNNNNNNNN/getUpdates

e ottenere una risposta come questa

{"ok":true,"result":[{"update_id":...,... chiacchierare":{"id":123456789

Abbiamo bisogno esattamente di chat_id.

Verifichiamo di poter scrivere manualmente alla chat: chiamiamo l'indirizzo dal browser

https://api.telegram.org/botваштокен/sendMessage?chat_id=123456789&text="Life is directed motion"

Se ricevi un messaggio da un bot nella tua chat, ok, puoi passare alla fase successiva.

In questo modo (tramite il browser) puoi sempre verificare dove si trovano i problemi: se hai difficoltà a generare il collegamento o se c'è qualcosa nascosto da qualche parte che non funziona.

Cosa devi sapere prima di continuare a leggere

Esistono diversi tipi di chat di gruppo su Telegram (aperte, chiuse). Per queste chat, alcune funzioni (ad esempio, l'ID) sono diverse, il che a volte causa qualche problema.

Supponiamo che sia la fine del 2019 e che persino l'eroe del nostro tempo, il noto Man-Orchestra (amministratore, avvocato, specialista in sicurezza informatica, programmatore e praticamente MVP) Evgeny V. distingua la variabile $i da un array, abbia padroneggiato i cicli e forse nei prossimi due anni padroneggerà Chocolatey e poi anche Elaborazione parallela con PowerShell и ForEach-Object Parallel ci arriverà.

1. Pensiamo a cosa farà il nostro bot

Non avevo idee, quindi ho dovuto pensarci. Avevo già scritto un bot per notebook. Non volevo creare un bot "che invia qualcosa da qualche parte". Per connettersi ad Azure, serve una carta di credito, e dove la trova uno studente? Va notato che non è poi così male: i cloud principali offrono una sorta di periodo di prova gratuito (ma serve comunque un numero di carta di credito, che verrà addebitato, credo di un dollaro. Non ricordo se sia stata restituita in seguito).

Senza l'intelligenza artificiale e l'apprendimento automatico, creare un bot-idiota-versificatore non è così interessante.

Ho deciso di creare un bot che mi ricorderà (o non mi ricorderà) le parole inglesi presenti nel dizionario.
Per evitare di manomettere il database, il dizionario verrà salvato in un file di testo e compilato manualmente.
In questo caso, il compito è mostrare le basi in azione e non realizzare un prodotto almeno parzialmente finito.

2. Provare cosa e come per la prima volta

Creiamo una cartella C:poshtranslate
Per prima cosa, vediamo che tipo di PowerShell abbiamo, avviamo ISE tramite start-run
powershell ise
oppure trova Powershell ISE nei programmi installati.
Dopo l'avvio, si aprirà il solito "qualche tipo di editor"; se non è presente alcun campo di testo, puoi sempre cliccare su "File - crea nuovo".

Diamo un'occhiata alla versione PowerShell: scriviamo nel campo di testo:

get-host 

e premere F5.

Powershell offrirà di salvare - "Lo script che stai per eseguire verrà salvato.", accettiamo e salviamo in C:poshtranslate un file da Powershell con il nome myfirstbotBT100.

Dopo l'avvio, nella finestra di testo inferiore verrà visualizzata una tabella di dati:

Name             : Windows PowerShell ISE Host
Version          : 5.1.(и так далее)

Ho la versione 5.1, quindi è sufficiente. Se hai un vecchio Windows 7/8, va bene, anche se PowerShell deve essere aggiornato alla versione 5, ad esempio, tramite istruzione.

Digitiamo Get-Date nella riga di comando sottostante, premiamo Invio, guardiamo l'ora e andiamo alla cartella radice con il comando
cd
e pulisci lo schermo con il comando cls (no, non è necessario usare rm)

Ora vediamo cosa e come funziona: non scriveremo nemmeno un codice, ma due righe, e cercheremo di capire a cosa servono. Commentiamo la riga con get-host con il simbolo # e aggiungiamo qualcos'altro.

# Пример шаблона бота 
# get-host
<# это пример многострочного комментария #>
$TimeNow = Get-Date
$TimeNow

(La cosa interessante è che l'elenco a discesa per la formattazione del codice su Habr ha due dozzine di opzioni, ma Powershell non c'è. C'è Dos. C'è Perl.)

Ed esegui il codice premendo F5 o ">" dalla GUI.

Otteniamo l'output:

Saturday, December 8, 2019 21:00:50 PM (или что-то типа)

Ora diamo un'occhiata a queste due linee e ad alcuni punti interessanti, così non dovremo tornarci sopra più tardi.

A differenza di Pascal (e non solo), PowerShell cerca di determinare autonomamente quale tipo assegnare a una variabile, maggiori dettagli a riguardo sono scritti nell'articolo Un'introduzione alla digitazione nei linguaggi di programmazione
Pertanto, creando una variabile $TimeNow e assegnandole il valore della data e dell'ora correnti (Get-Date), non dobbiamo preoccuparci troppo del tipo di dati che saranno presenti.

È vero, questa ignoranza potrebbe ferire in seguito, ma questo accadrà più avanti. Più avanti nel testo troverete un esempio.
Vediamo cosa abbiamo ottenuto. Eseguiamolo (dalla riga di comando)

$TimeNow | Get-member

e otteniamo una pagina di testo incomprensibile

Esempio di testo poco chiaro numero 1

PS C:> $TimeNow | Get-member
   TypeName: System.DateTime
Name                 MemberType     Definition                                                                                                                                       
----                 ----------     ----------                                                                                                                                       
Add                  <b>Method         </b>datetime Add(timespan value)  
..
DisplayHint          NoteProperty   DisplayHintType DisplayHint=DateTime                                                                                                             
Date                 <b>Property       </b>datetime Date {get;}                                                                                                                             
Year                 Property       int Year {get;}   
..                                                                                                                               
DateTime             ScriptProperty System.Object DateTime {get=if ((& { Set-StrictMode -Version 1; $this.DisplayHint }) -ieq  "Date")...                                         

Come puoi vedere, una variabile del tipo TypeName: System.DateTime è stata creata con una serie di metodi (nel senso di ciò che possiamo fare con questo oggetto variabile) e proprietà.

Chiamiamo $TimeNow.DayOfYear — otterremo il numero del giorno dell'anno.
Chiamiamo $TimeNow.DayOfYear | Get-Member — otteniamo TypeName: System.Int32 e un gruppo di metodi.
Chiamiamo $TimeNow.ToUniversalTime() — e otteniamo l'ora secondo UTC

Debug

A volte capita di dover eseguire un programma fino a una certa riga e vedere lo stato del programma in quel momento. A questo scopo, ISE dispone della funzione Debug, che consente di attivare o disattivare il punto di interruzione.
Inserisci un punto di interruzione da qualche parte nel mezzo, esegui queste due righe e osserva come appare l'interruzione.

3. Comprendere l'interazione con il bot di Telegram

Naturalmente, esiste ancora più letteratura scritta sull'interazione con il bot, con getpush e così via, ma la questione teorica può essere considerata facoltativamente.

Nel nostro caso è necessario:

  • Impara a inviare qualcosa nella corrispondenza
  • Impara a ottenere qualcosa dalla corrispondenza

3.1 Impariamo a inviare qualcosa alla corrispondenza e a ricevere da essa

Un po' di codice - Parte 3

Write-output "This is part 3"
$MyToken = "1234544311:AbcDefNNNNNNNNNNNNN"
$MyChatID = "123456789"
$MyProxy = "http://1.2.3.4:5678" 

$TimeNow = Get-Date
$TimeNow.ToUniversalTime()
$ScriptDir = Split-Path $script:MyInvocation.MyCommand.Path
$BotVersion = "BT102"

$MyText01 = "Life is directed motion - " + $TimeNow

$URL4SEND = "https://api.telegram.org/bot$MyToken/sendMessage?chat_id=$MyChatID&text=$MyText01"

Invoke-WebRequest -Uri $URL4SEND

e nella Federazione Russa a questo punto riceviamo l'errore Impossibile connettersi al server remoto.

Oppure non lo riceviamo: dipende dall'operatore e se il proxy è configurato e funzionante
Bene, non resta che aggiungere un proxy. Tieni presente che utilizzare un proxy non crittografato o addirittura falso è estremamente pericoloso per la tua salute.

Trovare un proxy funzionante non è poi così difficile: la maggior parte dei proxy http pubblicati funzionano. Credo che il quinto abbia funzionato per me.

Sintassi che utilizza il proxy:

Invoke-WebRequest -Uri $URL4SEND -Proxy $MyProxy

Se hai ricevuto un messaggio nella chat con il bot, allora è tutto a posto e puoi procedere. In caso contrario, continua con il debug.

Puoi vedere in cosa si trasforma la tua stringa $URL4SEND e provare a richiederla nel tuo browser, in questo modo:

$URL4SEND2 = '"'+$URL4SEND+'"'
start chrome $URL4SEND2 

3.2. Abbiamo imparato a scrivere “qualcosa” nella chat, ora proviamo a leggere

Aggiungiamo altre 4 righe e vediamo cosa c'è dentro tramite | get-member

$URLGET = "https://api.telegram.org/bot$MyToken/getUpdates"
$MyMessageGet = Invoke-WebRequest -Uri $URLGET -Method Get -Proxy $MyProxy
Write-Host "Get-Member"
$MyMessageGet | Get-Member

La cosa più interessante ci viene fornita da

Content           Property   string Content {get;}  
ParsedHtml        Property   mshtml.IHTMLDocument2 ParsedHtml {get;}                                    
RawContent        Property   string RawContent {get;set;}

Vediamo cosa contengono:

Write-Host "ParsedHtml"
$MyMessageGet.ParsedHtml # тут интересное
Write-Host "RawContent"
$MyMessageGet.RawContent # и тут интересное, но еще к тому же и читаемое. 
Write-Host "Content"
$MyMessageGet.Content

Se tutto funziona per te, otterrai una lunga fila come questa:

{"ok":true,"result":[{"update_id":12345678,
"message":{"message_id":3,"from":{"id"

Fortunatamente, nell'articolo precedentemente pubblicato Bot Telegram per amministratore di sistema questa riga (sì, secondo $MyMessageGet.RawContent | get-member è System.String), era già stato smantellato.

4. Elaborare ciò che abbiamo ricevuto (sappiamo già come inviare almeno qualcosa)

Come già scritto qui, la cosa più importante è il contenuto. Diamo un'occhiata più da vicino.

Per prima cosa, scriviamo un paio di frasi in più al bot dall'interfaccia web o dal telefono

/message1
/message2
/message3

e diamo un'occhiata nel browser all'indirizzo che è stato formato nella variabile $URLGET.

Vedremo qualcosa del tipo:

{"ok":true,"result":[{"update_id":NNNNNNN,
"message":{"message_id":10, .. "text":"/message1"
"message":{"message_id":11, .. "text":"/message2 
"message":{"message_id":12, .. "text":"/message3 

Di cosa si tratta? Un oggetto complesso composto da array di oggetti, contenente l'identificatore del messaggio end-to-end, l'identificatore della chat, l'identificatore dell'invio e molte altre informazioni.

Tuttavia, non abbiamo bisogno di capire "che tipo di oggetto è questo": parte del lavoro è già stato fatto per noi. Vediamo cosa c'è dentro:

Lettura dei messaggi ricevuti o parte 4

Write-Host "This is part 4" <# конечно эта строка нам не нужна в итоговом тексте, но по ней удобно искать. #> 

$Content4Pars01 = ConvertFrom-Json $MyMessageGet.Content
$Content4Pars01 | Get-Member
$Content4Pars01.result
$Content4Pars01.result[0]
$Content4Pars01.result[0] | Get-Member
$Content4Pars01.result[0].update_id
$Content4Pars01.result[0].message
$Content4Pars01.result[0].message.text
$Content4Pars01.result[1].message.text
$Content4Pars01.result[2].message.text

5. Cosa dovremmo fare adesso?

Salva il file risultante con il nome myfirstbotBT105 o come preferisci, cambia il titolo e commenta tutto il codice già scritto tramite

<#start comment 105 end comment 105#>

Ora dobbiamo decidere dove trovare il dizionario (beh, dove, sul disco in un file) e che aspetto avrà.

Naturalmente, è possibile inserire un enorme dizionario direttamente nel testo dello script, ma non è affatto questo il punto.
Vediamo quindi con cosa PowerShell può funzionare normalmente.
In realtà, a lui non importa con quale file lavorare, mentre a noi importa.
Possiamo scegliere tra: txt (possibile, ma perché), csv, xml.
Possiamo guardare tutti? Guardiamo tutti.
Creiamo una classe MyVocabClassExample1 e una variabile $MyVocabExample1
Noto che la classe è scritta senza $

un po' di codice #5

write-host "This is part 5"
class MyVocabClassExample1 {
    [string]$Original  # слово
    [string]$Transcript
    [string]$Translate
    [string]$Example
    [int]$VocWordID # очень интересный момент. Использование int с его ограничениями может порой приводить к диким последствиям, для примера - недавний случай с SSD HPE. Изначально я не стал добавлять этот элемент, потом все же дописал и закомментировал.
    }

$MyVocabExample1 = [MyVocabClassExample1]::new()
$MyVocabExample1.Original = "Apple"
$MyVocabExample1.Transcript = "[ ˈapəl ]"
$MyVocabExample1.Translate = "Яблоко"
$MyVocabExample1.Example = "An apple is a sweet, edible fruit produced by an apple tree (Malus domestica)"
# $MyVocabExample1.$VocWordID = 1

$MyVocabExample2 = [MyVocabClassExample1]::new()
$MyVocabExample2.Original = "Pear"
$MyVocabExample2.Transcript = "[ pe(ə)r ]"
$MyVocabExample2.Translate = "Груша"
$MyVocabExample2.Example = "The pear (/ˈpɛər/) tree and shrub are a species of genus Pyrus"
# $MyVocabExample1.$VocWordID = 2

Proviamo a scriverlo nei file campione.

Un po' di codice #5.1

Write-Host $ScriptDir # надеюсь $ScriptDir вы не закомментировали 
$MyFilenameExample01 = $ScriptDir + "Example01.txt"
$MyFilenameExample02 = $ScriptDir + "Example02.txt"
Write-Host $MyFilenameExample01
Out-File  -FilePath $MyFilenameExample01 -InputObject $MyVocabExample1

Out-File  -FilePath $MyFilenameExample01 -InputObject -Append $MyVocabExample2
notepad $MyFilenameExample01

— e otteniamo un errore sulla riga Out-File -FilePath $MyFilenameExample01 -InputObject -Append $MyVocabExample2.

Non vuole aggiungere, oh-oh, che peccato.

$MyVocabExample3AsArray = @($MyVocabExample1,$MyVocabExample2)
Out-File  -FilePath $MyFilenameExample02 -InputObject $MyVocabExample3AsArray
notepad $MyFilenameExample02

Vediamo cosa è successo. Un'ottima visualizzazione del testo, ma come si esporta di nuovo? Bisogna inserire dei separatori di testo, come le virgole?

E come risultato, si ottiene un "file con valori separati da virgole (CSV)" FERMA ASPETTA.
#

$MyFilenameExample03 = $ScriptDir + "Example03.csv"
$MyFilenameExample04 = $ScriptDir + "Example04.csv"
Export-Csv  -Path $MyFilenameExample03 -InputObject $MyVocabExample1 
Export-Csv  -Path $MyFilenameExample03 -InputObject $MyVocabExample2 -Append 
Export-Csv  -Path $MyFilenameExample04 -InputObject $MyVocabExample3AsArray 

Come si può facilmente vedere, MS non si è distinta particolarmente per quanto riguarda la logica; per una procedura simile in un caso viene utilizzato -FilePath, nell'altro -Path.

Inoltre, in questo terzo file è scomparsa la lingua russa, nel quarto file è successo qualcosa... beh, è successo qualcosa. #TYPE System.Object[] 00
# “Conteggio”, “Lunghezza”, “LongLength”, “Rank”, “SyncRoot”, “IsReadOnly”, “IsFixedSize”, “IsSynchronized”
#
Riscriviamolo un po':

Export-Csv  -Path $MyFilenameExample03 -InputObject $MyVocabExample1 -Encoding Unicode
Export-Csv  -Path $MyFilenameExample03 -InputObject $MyVocabExample2 -Append -Encoding Unicode
notepad $MyFilenameExample03
notepad $MyFilenameExample04

Sembrava che funzionasse, ma il formato non mi piace ancora.

In particolare, non mi piace il fatto di non poter inserire direttamente le linee di un oggetto in un file.
A proposito, visto che abbiamo iniziato a scrivere su file, forse dovremmo iniziare a tenere un registro di avvio? Abbiamo il tempo come variabile e sappiamo come impostare il nome di un file.

Non c'è ancora nulla da scrivere, ma possiamo pensare a come ruotare al meglio i registri.
Per ora proviamo con XML.

Un po' di xml

$MyFilenameExample05 = $ScriptDir + "Example05.xml"
$MyFilenameExample06 = $ScriptDir + "Example06.xml"
Export-Clixml  -Path $MyFilenameExample05 -InputObject $MyVocabExample1 
Export-Clixml  -Path $MyFilenameExample05 -InputObject $MyVocabExample2 -Append -Encoding Unicode
Export-Clixml  -Path $MyFilenameExample06 -InputObject $MyVocabExample3AsArray
notepad $MyFilenameExample05
notepad $MyFilenameExample06

L'esportazione in XML presenta solo vantaggi: leggibilità, esportazione dell'intero oggetto e nessuna necessità di eseguire uppend.

Proviamo leggere il file xml.

Alcune letture da XML

$MyFilenameExample06 = $ScriptDir + "Example06.xml"
$MyVocabExample4AsArray = Import-Clixml -Path $MyFilenameExample06
# $MyVocabExample4AsArray 
# $MyVocabExample4AsArray[0]
# и немного о совершенно неочевидных нюансах. Powershell время от времени ведет себя не так, как вроде бы как бы стоило бы ожидать бы.
# например у меня эти два вывода отличаются
# Write-Output $MyVocabExample4AsArray 
# write-host $MyVocabExample4AsArray 

Torniamo al nostro compito. Abbiamo scritto e letto il file di test, il formato di archiviazione è chiaro, se necessario, possiamo scrivere un piccolo editor di file separato per aggiungere ed eliminare righe.

Vorrei ricordarvi che il compito era quello di realizzare un piccolo bot educativo.

Il formato del lavoro: invio al bot il comando "esempio", il bot mi invia una parola selezionata casualmente e la sua trascrizione, e dopo 10 secondi invia la traduzione e il commento. Possiamo leggere i comandi, ma dobbiamo ancora imparare a selezionare e controllare automaticamente i proxy e a resettare i contatori dei messaggi.

Rimuoviamo il commento da tutto ciò che era stato precedentemente commentato come non necessario, commentiamo gli esempi con txt e csv che sono diventati non necessari e salviamo il file come versione B106

Oh sì. Inviamo di nuovo qualcosa al bot.

6. Invio da funzioni e altro

Prima di elaborare la ricezione, è necessario creare una funzione per inviare "almeno qualcosa" di diverso da un messaggio di prova.

Naturalmente, nell'esempio avremo una sola spedizione e una sola elaborazione, ma cosa succede se dobbiamo fare la stessa cosa più volte?

È più facile scrivere una funzione. Quindi, abbiamo una variabile di tipo oggetto $MyVocabExample4AsArray, letta da un file, come un array di due elementi.
Andiamo a leggere.

Allo stesso tempo, occupiamoci dell'orologio, ci servirà più avanti (in effetti, in questo esempio, non ci servirà :)

Un po' di codice #6.1

Write-Output "This is Part 6"
$Timezone = (Get-TimeZone)
IF($Timezone.SupportsDaylightSavingTime -eq $True){
    $TimeAdjust =  ($Timezone.BaseUtcOffset.TotalSeconds + 3600) } # приведенное время
    ELSE{$TimeAdjust = ($Timezone.BaseUtcOffset.TotalSeconds) 
    }
    
function MyFirstFunction($SomeExampleForFunction1){
$TimeNow = Get-Date
$TimeNow.ToUniversalTime()
# $MyText02 = $TimeNow + " " + $SomeExampleForFunction1 # и вот тут мы получим ошибку
$MyText02 = $SomeExampleForFunction1 + " " + $TimeNow # а тут не получим, кто догадается почему - тот молодец.

$URL4SendFromFunction = "https://api.telegram.org/bot$MyToken/sendMessage?chat_id=$MyChatID&text=$MyText02"
Invoke-WebRequest -Uri $URL4SendFromFunction -Proxy $MyProxy
}

Come puoi facilmente vedere, la funzione chiama $MyToken e $MyChatID, che erano stati precedentemente codificati.

Non è necessario farlo e se $MyToken è lo stesso per ogni bot, allora $MyChatID cambierà a seconda della chat.

Tuttavia, poiché si tratta di un esempio, per ora lo ignoreremo.

Poiché $MyVocabExample4AsArray non è un array, sebbene gli assomigli molto, allora non puoi semplicemente andare e richiederne la lunghezza.

Ancora una volta dovremo fare ciò che non possiamo fare: atterrare non secondo il codice, prendere e contare.

Un po' di codice #6.2

$MaxRandomExample = 0 
foreach ($Obj in $MyVocabExample4AsArray) {
$MaxRandomExample ++
}
Write-Output $MaxRandomExample
$RandomExample = Get-Random -Minimum 0 -Maximum ($MaxRandomExample)
$TextForExample1 = $MyVocabExample4AsArray[$RandomExample].Original
# MyFirstFunction($TextForExample1)
# или в одну строку
# MyFirstFunction($MyVocabExample4AsArray[Get-Random -Minimum 0 -Maximum ($MaxRandomExample -1)].Example)
# Угадайте сами, какой пример легче читается посторонними людьми.

Random caratteristica interessanteSupponiamo di voler ottenere 0 o 1 (abbiamo solo due elementi nell'array). Impostando i limiti 0..1, otterremo "1"?
no - non lo otterremo, abbiamo un esempio speciale Esempio 2: Ottieni un numero intero casuale tra 0 e 99 Get-Random -Maximum 100
Pertanto, per 0..1 dovremo impostare la dimensione su 0..2, mentre il numero massimo di elementi = 1.

7. Elaborazione dei messaggi in arrivo e lunghezza massima della coda

Dove ci eravamo fermati prima? Abbiamo la variabile $MyMessageGet che abbiamo ricevuto.
e il $Content4Pars01 da esso ottenuto, dal quale ci interessano gli elementi dell'array Content4Pars01.result

$Content4Pars01.result[0].update_id
$Content4Pars01.result[0].message
$Content4Pars01.result[0].message.text

Inviamo al bot /message10, /message11, /message12, /word e di nuovo /word e /hello.
Vediamo cosa abbiamo ottenuto:

$Content4Pars01.result[0].message.text
$Content4Pars01.result[2].message.text

Esamineremo tutto ciò che abbiamo ricevuto e invieremo una risposta se il messaggio era /word
il caso di costrutto, quello che alcuni descrivono come if-elseif, è chiamato in PowerShell tramite interruttoreTuttavia, il codice seguente utilizza la chiave -wildcard, che è completamente inutile e persino dannosa.

Un po' di codice #7.1

Write-Output "This is part 7"
Foreach ($Result in $Content4Pars01.result) # Да, можно сделать быстрее 
 { 
    switch -wildcard ($Result.message.text) 
            {
            "/word" {MyFirstFunction($TextForExample1)}
            }
}

Eseguiamo lo script un paio di volte. Otterremo la stessa parola due volte per ogni tentativo di esecuzione, soprattutto se abbiamo commesso un errore nell'implementazione di random.

Ma aspetta. Non abbiamo inviato di nuovo /word, quindi perché il messaggio viene elaborato di nuovo?

La coda per l'invio di messaggi al bot ha una lunghezza finita (credo 100 o 200 messaggi) e deve essere svuotata manualmente.

Naturalmente, questo è descritto nella documentazione, ma devi leggerla!

In questo caso, abbiamo bisogno del parametro ?chat_id, mentre &timeout, &limit, &parse_mode=HTML e &disable_web_page_preview=true non sono ancora necessari.

Documentazione su l'API di Telegram è qui
Lì è scritto in parole semplici:
Identificatore del primo aggiornamento da restituire. Deve essere maggiore di uno rispetto al più alto tra gli identificatori degli aggiornamenti ricevuti in precedenza. Per impostazione predefinita, gli aggiornamenti iniziano con il più vecchio.
non confermato vengono restituiti gli aggiornamenti. Un aggiornamento è considerato confermato non appena getUpdates viene chiamato con un offset superiore rispetto al suo update_idÈ possibile specificare un offset negativo per recuperare gli aggiornamenti a partire da -offset update dalla fine della coda degli aggiornamenti. Tutti gli aggiornamenti precedenti verranno dimenticati.

Diamo un'occhiata a:

$Content4Pars01.result[0].update_id
$Content4Pars01.result[1].update_id 
$Content4Pars01.result | select -last 1
($Content4Pars01.result | select -last 1).update_id

E lo resettiamo, riscrivendo un po' la funzione. Abbiamo due opzioni: passare l'intero messaggio alla funzione ed elaborarlo interamente al suo interno, oppure passare solo l'ID del messaggio e resettarlo. Ad esempio, la seconda opzione sembra più semplice.

In precedenza, la nostra stringa di query "tutti i messaggi" si presentava così:

$URLGET = "https://api.telegram.org/bot$MyToken/getUpdates"

e sarà simile a questo

$LastMessageId = ($Content4Pars01.result | select -last 1).update_id
$URLGET1 = "https://api.telegram.org/bot$mytoken/getUpdates?offset=$LastMessageId&limit=100" 
$MyMessageGet = Invoke-WebRequest -Uri $URLGET1 -Method Get -Proxy $MyProxy 

Nessuno ti vieta di ricevere prima tutti i messaggi, elaborarli e solo dopo l'elaborazione con successo, richiedere non confermato -> confermato.

Perché ha senso richiedere una conferma al termine dell'elaborazione? È possibile che l'esecuzione fallisca a metà e, mentre per un esempio di chatbot gratuito, perdere un singolo messaggio non è un grosso problema, se si sta elaborando lo stipendio di qualcuno o una transazione con carta, il risultato potrebbe essere peggiore.

Ancora un paio di righe di codice

$LastMessageId = ($Content4Pars01.result | select -last 1).update_id  #ошибку в этом месте предполагается исправить самостоятельно. 
$URLGET1 = "https://api.telegram.org/bot$mytoken/getUpdates?offset=$LastMessageId&limit=100" 
Invoke-WebRequest -Uri $URLGET1 -Method Get -Proxy $MyProxy

8. Invece di una conclusione

Vengono completate e illustrate le funzioni principali: lettura dei messaggi, reimpostazione della coda, lettura da un file e scrittura in un file.

Ci sono solo quattro cose rimaste da fare:

  • inviare la risposta corretta a una richiesta nella chat
  • inviare una risposta a QUALSIASI chat in cui è stato aggiunto il bot
  • esecuzione di codice in un ciclo
  • Avvio di un bot dallo scheduler di Windows.

Tutti questi compiti sono semplici e possono essere facilmente implementati leggendo la documentazione su parametri come
Set-ExecutionPolicy Unrestricted e -ExecutionPolicy Bypass
ciclo della specie

$TimeToSleep = 3 # опрос каждые 3 секунды
$TimeToWork = 10 # минут
$HowManyTimes = $TimeToWork*60/$TimeToSleep # счетчик для цикла
$MainCounter = 0
for ($MainCounter=0; $MainCounter -le $HowManyTimes) {
sleep $TimeToSleep
$MainCounter ++

Grazie a tutti coloro che hanno letto fin qui.

Fonte: habr.com

Aggiungi un commento