Moduł parser jest oparty na skryptowym języku T-Script, którego głównym zadaniem jest generowanie plików tekstowych. Może być używany do przetwarzania szablonów z danymi pobieranymi z różnych źródeł np. baz SQL lub plików tekstowych. W naszym przypadku treść skryptu (szablon) jest przechowywany w bazie danych, dlatego istnieje możliwość jego edycji poprzez LMS-UI. W przyszłości moduł parser może zastąpić większość modułów demona.
Przed kompilacją modułu upewnij się, że posiadasz w systemie pakiety bison (co najmniej w wersji 1.875) oraz flex.
Parser posiada następujące opcje:
script
Zawartość skryptu (szablonu). Domyślnie: pusta.
Przykład: script = '{var=1}zmienna var={var}'
file
Lokalizacja pliku wynikowego. Domyślnie: pusta
Przykład: file = /tmp/parser.out
command
Polecenie powłoki do wykonania po kompilacji skryptu. Domyślnie: pusta
Przykład: command = "sh /tmp/parser.out"
Składnia języka T-Script jest podobna do składni innych popularnych języków takich jak C czy JavaScript, ale dokonano pewnych zmian mających na celu ułatwienie tworzenia szablonów. Wszystkie podane polecenia powinny być zapisywane wewnątrz klamer { }. Dane poza klamrami zostaną zapisane do pliku wyjściowego (lub jeśli go nie zdefiniowano, pominięte). Wielkość liter ma znaczenie.
Wyrażenia:
Ciąg znaków.
"jakiś ciąg znaków"
Liczba.
1234
Wartość zmiannej "var".
var
N-ty element tablicy "var".
var[n]
Podzmienna "n" zmiennej "var".
var.n
Wartość wyrażenia w nawiasach.
( <wyrażenie> )
Zwraca 1 gdy wyrażenie nie jest prawdą, w przeciwnym wypadku 0.
! <wyrażenie>
Zwraca 1 gdy wartość wyrażenie1 jest identyczna z wartością wyrażenie2 lub 0 gdy są różne.
<wyrażenie1> == <wyrażenie2>
Zwraca 1 gdy wyrażenia są różne lub 0 gdy są takie same.
<wyrażenie1> != <wyrażenie2>
Zwraca 1 gdy wyrażenie1 jest mniejsze od wartości wyrażenia wyrażenie2.
<wyrażenie1> < <wyrażenie2>
Zwraca 1 gdy wartość wyrażenie1 jest większa od wartości wyrażenie2.
<wyrażenie1> > <wyrażenie2>
Zwraca 1 gdy jedno z wyrażeń jest prawdą.
<wyrażenie1> || <wyrażenie2>
Zwraca 1 gdy wyrażenie1 i wyrażenie2 są prawdziwe.
<wyrażenie1> && <wyrażenie2>
Gdy oba wyrażenia są liczbami zwraca wynik operacji arytmetycznej. W innym przypadku traktuje wyrażenia jako ciągi znaków i dokonuje ich połączenia.
<wyrażenie1> + <wyrażenie2>
Zwraca wynik operacji arytmetycznej na dwóch wyrażeniach.
<wyrażenie1> - <wyrażenie2> <wyrażenie1> * <wyrażenie2> <wyrażenie1> / <wyrażenie2> <wyrażenie1> % <wyrażenie2>
Zwraca 1 gdy wyrażenie pasuje do wzorca po prawej stronie, w przeciwnym wypadku zwraca 0.
<wyrażenie> =~ <wzorzec>
Komentarze:
Komentarz w stylu języka C.
{/* to jest komentarz - może być wieloliniowy */}
Podstawowe polecenia:
Przypisanie wartości wyrażenia do podanej zmiennej.
{<nazwa_zmiennej> = <wyrażenie>}
Wykonanie polecenia tylko wtedy gry wyrażenie jest prawdą. Druga forma wykonuje polecenie1 gdy wyrażenie jest prawdą lub polecenie2 gdy jest fałszem.
{if ( <wyrażenie> )} <polecenia> {/if} {if ( <wyrażenie> )} <polecenie1> {else} <polecenie2> {/if}
Tekst między blokami jest traktowany jako polecenia dlatego następujący przykład jest prawidłowy:
Jakiś tekst {if (a==1)} a równe jest 1 {else} a nie jest równe 1 {/if}Można wstawić backslash (\) pomiędzy poleceniem a końcem wiersza aby pozbyć się znaku końca linii i zachować normalny (bez załamania linii w tym miejscu) przepływ tekstu. Na przykład:
Jakiś tekst {if (a==1)}\ a równa się 1 {else}\ a nie równa się 1 {/if}\
Wykonanie polecenie1 jako polecenia inicjalizującego pętlę. Następnie wykonywane jest polecenie i polecenie2, dopóki wyrażenie jest prawdziwe.
{for ( <polecenie1> ; <wyrażenie> ; <polecenie2> )} <polecenia> {/for}
Przekierowanie wyjścia do pliku. Dane zostaną dopisane do pliku.
{file <nazwa_pliku>} <polecenia> {/file}
Podstawowe funkcje:
Zamiana wartości liczbowej na ciąg znaków.
{string(<zmienna>)}
Zamiana ciągu znaków na liczbę. Dla tablic zwraca ilość elementów w tablicy.
{number(<zmienna>)}
Rozszerzenia to dodatki do biblioteki tscript. Są to funkcje i stałe, które można używać w skryptach. Poniżej przedstawiono rozszerzenia udostępnione w lmsd.
![]() | Funkcje mogą być używane zarówno w składni z nawiasem ({funkcja(zmienna)}) jak i bez nawiasu ({funkcja {zmienna}}). |
Wykonywanie poleceń powłoki umożliwia funkcja exec(). Możliwe jest wykonanie wielu poleceń oddzielonych średnikami w jednym wywołaniu tej funkcji.
Wykonywanie poleceń powłoki.
{exec <polecenie>}
'String' zawiera podstawowe funkcje do operowania na ciągach znaków.
Usunięcie "białych" znaków z początku i końca ciągu znaków.
{trim <ciąg_znaków>}
Rozszerzenie SQL udostępnia podstawowe funkcje związane z obsługą bazy danych. Pozwala na wykonywanie poleceń SQL.
Polecenia SQL
{SELECT <dalszy_ciąg_zapytania>} {INSERT <dalszy_ciąg_zapytania>} {DELETE <dalszy_ciąg_zapytania>} {UPDATE <dalszy_ciąg_zapytania>} {CREATE <dalszy_ciąg_zapytania>} {DROP <dalszy_ciąg_zapytania>}
Liczba wierszy, których dotyczy zapytanie.
{rows(<zapytanie_sql>)}
Zabezpieczenie znaków specjalnych w celu użycia w zapytaniu SQL. W szczególności chodzi o apostrofy i backslashe. Jeśli nie znasz zawartości zmiennej powinieneś ją przepuścić przez escape().
{escape(<zmienna>)}
Rozszerzenie ściśle związane z LMS-em. Umożliwia tworzenie skryptów bez znajomości struktury bazy danych. Zawiera predefiniowane stałe, które zawierają dane z bazy. Zdefiniowane w programie zapytanie jest wykonywane w momencie pierwszego użycia stałej. Nazwy stałych należy pisać dużymi literami. Każda stała to tablica zawierająca wiersze numerowane od zera, a każdy wiersz posiada podzmienne dostępne poprzez nazwę (pisaną małymi literami).
CUSTOMERS - lista klientów:
id - ID klienta |
lastname - nazwa/nazwisko klienta |
name - imię klienta |
status - status |
address - adres klienta |
zip - kod pocztowy |
city - miasto |
email - adres e-mail |
phone1, phone2, phone3 - telefony |
ten - NIP |
ssn - PESEL |
info - informacje o kliencie |
message - treść ostrzeżenia |
warning - status ostrzeżenia (suma statusów wszystkich komputerów klienta) |
access - status dostępności (suma statusów wszystkich komputerów klienta) |
balance - bilans klienta |
NODES - lista komputerów (i adresów urządzeń sieciowych):
id - ID komputera |
owner - nazwa/nazwisko i imię klienta |
ownerid - ID klienta ('0' w przypadku urządzeń) |
name - nazwa komputera (adresu urządzenia) |
access - status: włączony/wyłączony (1/0) |
warning - status ostrzeżeń: włączone/wyłączone (1/0) |
netdev - ID urządzenia, do którego jest podłączony |
lastonline - czas ostatniej aktywności |
info - dodatkowe informacje |
message - treść ostrzeżenia |
mac - adres MAC |
passwd - hasło |
ip - adres IP |
ip_pub - publiczny adres IP |
linktype - typ połączenia (0-kabel, 1-radio) |
NETWORKS - lista sieci:
id - ID sieci |
name - nazwa sieci |
address - adres IP |
mask - maska (xxx.xxx.xxx.xxx) |
prefix - liczba jedynek w masce |
size - rozmiar sieci (ilość adresów) |
interface - nazwa interfejsu |
gateway - adres bramy |
dns - adres pierwszego serwera DNS |
dns2 - adres drugiego serwera DNS |
wins - adres WINS |
domain - nazwa domenowa |
dhcpstart - początek zakresu DHCP |
dhcpend - koniec zakresu DHCP |
W tym rozszerzeniu zawarte są funkcje (nazwy pisane małymi literami) przeznaczone do operowania na adresach IP i maskach.
Zamiana maski sieciowej w formacie xxx.xxx.xxx.xxx na liczbę (bitów).
mask2prefix(<maska>)
Zamiana adresu IP w formacie 4-oktetowym na liczbę.
ip2long(<adres>)
Zamiana adresu IP podanego jako liczba na format xxx.xxx.xxx.xxx.
long2ip(<adres>)
Obliczenie adresu broadcast dla podanego adresu IP oraz maski (format maski dowolny).
broadcast(<adres/maska>)
Zacznijmy od bardzo prostego skryptu, który tworzy plik /etc/hosts z listą adresów i nazw komputerów (oraz urządzeń).
Przykład 6-1. Parser: Tworzenie pliku /etc/hosts
{result = SELECT name, inet_ntoa(ipaddr) AS ip FROM nodes}\ 127.0.0.1 localhost {for (r=0; r<number(result); r++)}\ {result[r].name}\t{result[r].ip} {/for}\
Utworzenie listy dłużników jest bardzo proste, zwłaszcza gdy zastosujemy jedną z predefiniowanych stałych.
Przykład 6-2. Parser: Lista dłużników
{for (r=0; r<number(CUSTOMERS); r++)}\ {if (CUSTOMERS[r].balance < 0)}\ {CUSTOMERS[r].lastname} {CUSTOMERS[r].name}\t{CUSTOMERS[r].balance} {/if} {/for}\
Kolejny trochę dłuższy przykład, w którym wykorzystujemy głównie 'exec'. Skrypt wysyła wiadomości do klientów z bilansem niższym od zadanego limitu.
Przykład 6-3. Parser: Zamiennik modułu notify
{limit = 0} {month = exec date +%B} {year = exec date +%Y} {customers = SELECT customers.id AS id, email, pin, name, lastname, SUM((type * -2 +7) * cash.value) AS balance FROM customers LEFT JOIN cash ON customers.id = cash.customerid AND (cash.type = 3 OR cash.type = 4) WHERE deleted = 0 AND email!='' GROUP BY customers.id, name, lastname, email, pin HAVING SUM((type * -2 +7) * cash.value) < {limit}} {for(i=0; i<number(customers); i++)} {exec echo "UWAGA: Niniejsza wiadomość została wygenerowana automatycznie. Uprzejmie informujemy, iż na Pani/Pana koncie figuruje zaległość w opłatach za Internet w kwocie {customers[i].balance*-1} zł. Jeżeli należność za bieżący miesiąc, to jest {trim(month)} {trim(year)}, została już uregulowana prosimy zignorować tę wiadomość. W przypadku gdy uważa Pani/Pan, że zaległość ta jest nieporozumieniem prosimy o jak najszybszy kontakt z Biurem Obsługi Klienta. Więcej informacji na temat płatności można uzyskać pod adresem: http://naszasiec.pl/mojekonto/ W celu uregulowania należności prosimy o kontakt: Nasz Siec ASK - Biuro Obsługi Klienta Gwidon Mniejważny telefon: 0-606031337 e-mail: gwidonm@naszasiec.pl PS. Poniżej załączamy ostatnie 10 operacji na Państwa koncie. --------------+--------------+----------------------------- Data | Kwota | Komentarz --------------+--------------+-----------------------------" > /tmp/mail} {last10 = SELECT comment, time, CASE WHEN type=4 THEN value*-1 ELSE value END AS value FROM cash WHERE customerid = {customers[i].id} ORDER BY time DESC LIMIT 10} {for(j=0; j<number(last10); j++)} {exec echo "{last10[j].time}|\t{last10[j].value}|\t{last10[j].comment}" >> /tmp/mail} {/for} {exec mail -s "Powiadomienie o zaleglosciach" -r lms@domain.tld {customers[i].email} < /tmp/mail} {/for}
Poprzedni | Spis treści | Następny |
Moduły | Początek rozdziału | Dla dociekliwych |