V Bostonu probíhá konference Red Hat Summit 2025. Vybrané přednášky lze sledovat na YouTube. Dění lze sledovat na síti 𝕏 (#RHSummit).
Společnost Red Hat oficiálně oznámila vydání Red Hat Enterprise Linuxu 10. Vedle nových vlastností přináší také aktualizaci ovladačů a předběžné ukázky budoucích technologií. Podrobnosti v poznámkách k vydání.
Tuto sobotu 24. května se koná historicky první komunitní den projektu Home Assistant. Zváni jsou všichni příznivci, nadšenci a uživatelé tohoto projektu. Pro účast je potřebná registrace. Odkazy na akce v Praze a v Bratislavě.
Troy Hunt představil Have I Been Pwned 2.0, tj. nový vylepšený web služby, kde si uživatelé mohou zkontrolovat, zda se jejich hesla a osobní údaje neobjevili v únicích dat a případně se nechat na další úniky upozorňovat.
Microsoft představil open source textový editor Edit bežící v terminálu. Zdrojové kódy jsou k dispozici na GitHubu pod licencí MIT.
V Seattlu a také online probíhá konference Microsoft Build 2025. Microsoft představuje své novinky. Windows Subsystem for Linux je nově open source. Zdrojové kódy jsou k dispozici na GitHubu pod licencí MIT.
Z příspěvku Turris Sentinel – co přinesl rok 2024 na blogu CZ.NIC: "Za poslední rok (únor 2024 – únor 2025) jsme zachytili 8,3 miliardy incidentů a to z 232 zemí a z jejich závislých území. Tyto útoky přišly od 6,2 milionu útočníků (respektive unikátních adres). SMTP minipot je stále nejlákavější pastí, zhruba 79 % útoků bylo směřováno na tento minipot, 16 % útoků směřovalo na minipot Telnet, 3 % útoků směřovaly na minipot HTTP a 2 % na minipot FTP. Dále jsme zaznamenali 3,2 milionu unikátních hesel a 318 tisíc unikátních loginů, které útočníci zkoušeli."
Byla vydána (Mastodon, 𝕏) nová verze 3.0.4 svobodné aplikace pro úpravu a vytváření rastrové grafiky GIMP (GNU Image Manipulation Program). Přehled novinek v oznámení o vydání a v souboru NEWS na GitLabu. Nový GIMP je již k dispozici také na Flathubu.
Byla vydána nová stabilní verze 7.4 webového prohlížeče Vivaldi (Wikipedie). Postavena je na Chromiu 136. Přehled novinek i s náhledy v příspěvku na blogu.
Spolek vpsFree.cz vydal statistiky týkající se distribucí nasazených na serverech členů. V dlouhodobém pohledu je zřejmé, že většina uživatelů z původního CentOS přechází na Rocky Linux. Pozoruhodný je také nárůst obliby distribuce NixOS, která dnes zaujímá třetí místo po Debianu a Ubuntu.
Kterak propojit C++ a Web v praktické aplikaci.
Ve firmě Hobrasoft vyvíjíme distribuovaný CRM systém Deko the CRM. Různých CRM systémů jsou na světě mraky, takže přijít s něčím novým je obtížné. Za výhodu našeho CRM považujeme nezávislost na připojení k internetu. Databáze CouchDB, na které je aplikace postavená, dovolí uživatelům pracovat offline a přitom nejsou nijak omezení ve sdílení dat. Deko je určené jak pro Windows, tak pro Linux.
Jedním z úkolů, před které nás potřeby aplikace postavily, byly tiskové sestavy. Celá aplikace je napsaná v C++ a Qt, takže se nabízela možnost použít C++ i pro tvorbu sestav. Ale tvořit něco v C++ je nepružné i pro nás a představa, že by si mohl uživatel sám vytvořit sdílenou knihovnu se sestavou je čirá utopie. Jak z takové situace ven?
Můj první nápad byl vlastní tabulkový kalkulátor vestavěný v aplikaci. Uživatelé jsou na tabulky zvyklí, nemuselo by jim to činit potíže. Malý průzkum bojem ale ukázal, že potíže by mohl činit tabulkový kalkulátor nám - naprogramovat něco použitelného je pracné.
Druhý nápad bylo použít HTML. Něco vzdáleně podobného už jsme měli hotové:
http://weko.hobrasoft.cz/timesheet/default/288KFTU
Ale to je napsané v PHP a potřebuje to celý ten veliký cirkus spojený s webovými aplikacemi - http server, php interpreter a napojení na databázi (u každého uživatele jiné).
Naštěstí k provádění nějakého programu ve webovém prohlížeči není potřeba PHP, webové prohlížeče už léta dokáží zpracovávat JavaScript a knihoven pro manipulaci HTML stránek je spousta. Spousta je i programátorů - na rozdíl od C++ dnes HTML a Javascript zvládá velké množství lidí.
Takže stačí už jen napsat a připojit k aplikaci webový prohlížeč. V Qt je situace jednoduchá: stačí přilinkovat webkit.
Sestavy obvykle čerpají své podklady z nějaké databáze. Databázi je proto nutné zpřístupnit i do webového prohlížeče. Prohlížeče získávají data dvojím způsobem: pomocí url, například:
nebo přes JavaScript, každý prohlížeč ve speciálním objektu document zpřístupňuje zobrazovanou html stránku:
var html = document.documentElement.outerHTML;
V aplikaci Deko jsme databázi zpřístupnili podobně. Jednak přes speciální url:
deko:///id-dokumentu-v-databazi
nebo přes objekt JavaScriptu:
var dokument = deko.get('id-dokumentu-v-databazi');
Vestavěný webkit se k tomu dá donutit poměrně snadno.
Třída WebView obsahuje webovou stránku, u níž musíme přepsat třídu QNetworkAccessManager, aby rozuměla i našemu schematu deko, zajistí to pár řádků kódu:
QNetworkAccessManager *om = f_view->page()->networkAccessManager(); REPORT_access_manager *nm = new REPORT_access_manager(om, this); f_view->page()->setNetworkAccessManager(nm);
Původní QNetworkAccessManager je nahrazený naším vlastním. Nedělá nic jiného, než že ověří url schema a pokud je schéma deko, vytvoří vlastní odpověď, jinak zavolá standardní proceduru:
class REPORT_access_manager : public QNetworkAccessManager { Q_OBJECT public: REPORT_access_manager(QNetworkAccessManager *, QObject *); QNetworkReply *createRequest( QNetworkAccessManager::Operation, const QNetworkRequest&, QIODevice*); }; REPORT_access_manager::REPORT_access_manager( QNetworkAccessManager *manager, QObject *parent) : QNetworkAccessManager(parent) { setCache (manager->cache()); setCookieJar (manager->cookieJar()); setProxy (manager->proxy()); setProxyFactory (manager->proxyFactory()); } QNetworkReply *REPORT_access_manager::createRequest( QNetworkAccessManager::Operation operation, const QNetworkRequest &request, QIODevice *device) { if (request.url().scheme() != "deko") { return QNetworkAccessManager::createRequest(operation, request, device); } if (operation != GetOperation) { return QNetworkAccessManager::createRequest(operation, request, device); } return new REPORT_reply (request.url()); }
Vrácená odpověď je mírně rozšířená třída QNetworkReply
class REPORT_reply : public QNetworkReply { Q_OBJECT public: REPORT_reply(const QUrl&); void abort() {} ; qint64 bytesAvailable() const; bool isSequential() const { return true; } protected: qint64 readData(char *data, qint64 maxSize); private: QByteArray content; qint64 offset; }; REPORT_reply::REPORT_reply(const QUrl& url) { offset = 0; open(ReadOnly | Unbuffered); // REQUEST je naše třída pro přístup do databáze, vrací obvykle JSON řetězec // Při vaší vlastní implementaci sem doplňte vlastní přístup do databáze REQUEST rq; rq.setBinary(true); rq.get(url.path().toUtf8()); content = rq.data(); setHeader(QNetworkRequest::ContentTypeHeader, rq.contentType().toString()); setHeader(QNetworkRequest::ContentLengthHeader, QVariant(content.size())); QTimer::singleShot(0, this, SIGNAL(metaDataChanged())); QTimer::singleShot(0, this, SIGNAL(readyRead())); QTimer::singleShot(0, this, SIGNAL(finished())); } qint64 REPORT_reply::bytesAvailable() const { qint64 bc = content.size() - offset; return bc; } qint64 REPORT_reply::readData(char *data, qint64 maxSize) { if (offset < content.size()) { qint64 number = qMin(maxSize, content.size() - offset); memcpy(data, content.constData() + offset, number); offset += number; return number; } else { return -1; } }
K webové stránce zobrazené ve webkitu lze snadno připojit libovolný QObject:
QWebFrame *frame = f_view->page()->mainFrame(); frame->addToJavaScriptWindowObject("deko", m_report_script);
Pod jménem deko bude objekt m_report_script přístupný ve webové stránce pomocí JavaScriptu.
U tohoto objektu uvedu pouze deklaraci, samotný kód už není tak důležitý:
class REPORT_SCRIPT : public QObject { Q_OBJECT public: REPORT_SCRIPT(QObject *parent); Q_INVOKABLE QString id(); Q_INVOKABLE QVariant get(const QString& id); Q_INVOKABLE QVariant document(const QString& id); Q_INVOKABLE QVariant linksToMe(const QString& id); Q_INVOKABLE QVariant linksFromMe(const QString& id); Q_INVOKABLE QString hash(const QString& text); Q_INVOKABLE void begin() { emit jobBegin(); } Q_INVOKABLE void end() { emit jobEnd(); } Q_INVOKABLE QString userid(); signals: void jobBegin(); void jobEnd(); };
Makrem Q_INVOKABLE deklaruji metodu jako přístupnou z JavaScriptu. Zajímavé je předávání výsledné hodnoty (podobně lze předávat i parametry). Vrací-li metoda QVariant, použije se v JavaScriptu taková hodnota jako objekt. V C++ vypadá vytvoření takového objektu například takto:
QVariantMap data; data["_id"] = "id-meho-objektu"; data["name"] = "Jmeno objektu"; QVariantList list; list << "abcd" << "1234"; data["list"] = list; return data;
V Javascriptu se interpretuje stejně, jako by se interpretoval tento JSON literár:
{ "_id": "id-meho-objektu", "name": "Jmeno objektu", "list": [ "abcd", "1234"] }
V Javascriptu je použití snadné:
var x = deko.metoda(); var id = x._id; var name = x.name; for (var i=0; i<x.list.length; i++) { // Udělej něco neco( deko.list[i] ); }
Nakonec několik ukázek: Vestavěná google mapa, hotová sestava a kus zdrojového tvaru sestavy. S webkitem dostanete i luxusní debugger - ten je vidět na posledním obrázku.
Tiskni
Sdílej:
QNetworkAccessManager
a ReportAccessManager
, nebo ještě lépe Report::NetworkAccessManager
.
CamelCase
... jdu blejt...
Díky za zápisek. Taky se chystám pustit do jednoho projektu s Qt(WebKitem), tak mě potěšilo, že tam jsou tyhle věci celkem jednoduché.
Ta VELKÁ písmena a podtržítka v názvech tříd se mi taky nelíbí, ale nevím, jaké jsou konvence v okolním kódu, tak to nechci hodnotit.
Mám ale jednu věcnou připomínku k návrhu: jak funguje třída REQUEST
(„…je naše třída pro přístup do databáze“)? To je nějaký singleton? Kde vezme spojení do databáze nebo jiné zdroje? IMHO by bylo lepší, aby je dostávala jako parametr z toho kontextu, ve kterém je používána, ne že si je někde obstará sama.
...proxy objekt...To mě zajímá. Nevyznám se příliš ve webových technologiích, nevím, co si pod tím představit. Jinak vlastní protokol používám právě proto, že nepředpokládám použití jinde, než v rámci aplikace. Navíc v režimu, kdy předem nevím, jak připojení k databázi vypadá a kdy jednu sestavu může používat více lidí s naprosto odlišným připojením k databázi.
/hello/world
namísto http://example.org/hello/world
či deko:/hello/world
. Pak je můžeš vzít jak jsou a poslat po HTTP do běžného prohlížeče.
No a aby fungovalo připojení k databázi, tak místo deko objektu, který máš teď, tam dáš proxy objekt, což je v Javascriptu implementovaný obyčejný objekt přeposílající volání metod na server a vracející obdržené odpovědi. Na serveru pak bude za nějakým HTTP API schovaný skutečný deko objekt, který udělá všechnu dřinu. Pokud proxy i originál budou mít stejné API, můžeš bezezměn zveřejnit tiskové sestavy na webu i v aplikaci a navíc to bude skoro bez práce (stačí udělat jen ten proxy objekt a aplikaci spustit jako démona bez GUI).
Pointa je v tom, aby jsi si teď nezadělal na problémy v budoucnu, kdy s tím budeš chtít něco dělat a budeš mít spoustu hotových sestav.
QWebView::setUrl("deko:/hello/world/");
by mělo stačit.
QWebView::setHtml( html, QUrl("deko:///hello/world") );
Html se bere z externího editoru