diff --git a/plugins/audios/audios/__init__.py b/plugins/audios/audios/__init__.py index 5054b8606c1579a1300f4777b18c9e7aadfd8a26..15b6a64ba0b5ae38cb7e3b6e9c0f6f9f49af0c24 100644 --- a/plugins/audios/audios/__init__.py +++ b/plugins/audios/audios/__init__.py @@ -1 +1 @@ -from .audios_provider import * +from .main import * diff --git a/plugins/audios/audios/audios_provider.py b/plugins/audios/audios/audios_provider.py deleted file mode 100644 index 87a1abe2f4b393606e51e69995c978f2c3343aa1..0000000000000000000000000000000000000000 --- a/plugins/audios/audios/audios_provider.py +++ /dev/null @@ -1,22 +0,0 @@ -def get(word: str, config: dict): - return [[], []], "" - - -def load(): - return - - -def unload(): - return - - -def get_config_description(): - return {} - - -def get_default_config(): - return {} - - -def set_config(new_config: dict) -> dict: - return {} diff --git a/plugins/audios/audios/consts.py b/plugins/audios/audios/consts.py new file mode 100644 index 0000000000000000000000000000000000000000..eb4500a09e10da2e0c30df01cf112fec8c9114ae --- /dev/null +++ b/plugins/audios/audios/consts.py @@ -0,0 +1,5 @@ +import os + +_PLUGIN_LOCATION = os.path.dirname(__file__) +_PLUGIN_NAME = os.path.split(_PLUGIN_LOCATION)[-1] +_HEADERS = {'User-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:77.0) Gecko/20100101 Firefox/77.0'} diff --git a/plugins/audios/audios/language_list.py b/plugins/audios/audios/language_list.py new file mode 100644 index 0000000000000000000000000000000000000000..5d0c7136bf8ac21dda0ba2ff284c767d34b93795 --- /dev/null +++ b/plugins/audios/audios/language_list.py @@ -0,0 +1,102 @@ +from .page_processing import get_forvo_page + +#all the languages forvo supports with their language code used in forvo word pages +languages = [ + "Abaza_abq", "Abkhazian_ab", "Adygean_ady", "Afar_aa", "Afrikaans_af", + "Aghul_agx", "Akan_ak", "Albanian_sq", "Algerian Arabic_arq", "Algonquin_alq", + "Amharic_am", "Ancient Greek_grc", "Arabic_ar", "Aragonese_an", "Arapaho_arp", + "Arbëresh_aae", "Armenian_hy", "Aromanian_rup", "Assamese_as", "Assyrian Neo-Aramaic_aii", + "Asturian_ast", "Avaric_av", "Aymara_ay", "Azerbaijani_az", "Bakhtiari_bqi", + "Balochi_bal", "Bambara_bm", "Bardi_bcj", "Bashkir_ba", "Basque_eu", + "Bavarian_bar", "Belarusian_be", "Bemba_bem", "Bench_bcq", "Bengali_bn", + "Biblical Hebrew_hbo", "Bihari_bh", "Bislama_bi", "Bosnian_bs", "Bouyei_pcc", + "Breton_br", "Bulgarian_bg", "Burmese_my", "Burushaski_bsk", "Buryat_bxr", + "Campidanese_sro", "Cantonese_yue", "Cape Verdean Creole_kea", "Catalan_ca", "Cebuano_ceb", + "Central Atlas Tamazight_tzm", "Central Bikol_bcl", "Chamorro_ch", "Changzhou_plig", "Chechen_ce", + "Cherokee_chr", "Chichewa_ny", "Chuvash_cv", "Coptic_cop", "Cornish_kw", + "Corsican_co", "Cree_cr", "Crimean Tatar_crh", "Croatian_hr", "Czech_cs", + "Dagbani_dag", "Danish_da", "Dari_prs", "Divehi_dv", "Dusun_dtp", + "Dutch_nl", "Dzongkha_dz", "Edo_bin", "Egyptian Arabic_arz", "Emilian_egl", + "English_en", "Erzya_myv", "Esperanto_eo", "Estonian_et", "Etruscan_ett", + "Ewe_ee", "Ewondo_ewo", "Faroese_fo", "Fiji Hindi_hif", "Fijian_fj", + "Finnish_fi", "Flemish_vls", "Franco-Provençal_frp", "French_fr", "Frisian_fy", + "Friulan_fur", "Fulah_ff", "Fuzhou_fzho", "Ga_gaa", "Galician_gl", + "Gan Chinese_gan", "Georgian_ka", "German_de", "Gilaki_glk", "Greek_el", + "Guarani_gn", "Gujarati_gu", "Gulf Arabic_afb", "Gusii_guz", "Haitian Creole_ht", + "Hakka_hak", "Hassaniyya_mey", "Hausa_ha", "Hawaiian_haw", "Hebrew_he", + "Herero_hz", "Hiligaynon_hil", "Hindi_hi", "Hmong_hmn", "Hungarian_hu", + "Icelandic_is", "Igbo_ig", "Iloko_ilo", "Indonesian_ind", "Ingush_inh", + "Interlingua_ia", "Inuktitut_iu", "Irish_ga", "Italian_it", "Iwaidja_ibd", + "Jamaican Patois_jam", "Japanese_ja", "Javanese_jv", "Jeju_jje", "Jiaoliao Mandarin_jliu", + "Jin Chinese_cjy", "Judeo-Spanish_lad", "Kabardian_kbd", "Kabyle_kab", "Kalaallisut_kl", + "Kalenjin_kln", "Kalmyk_xal", "Kannada_kn", "Karachay-Balkar_krc", "Karakalpak_kaa", + "Kashmiri_ks", "Kashubian_csb", "Kazakh_kk", "Khasi_kha", "Khmer_km", + "Kikuyu_ki", "Kimbundu_kmb", "Kinyarwanda_rw", "Kirundi_rn", "Klingon_tlh", + "Komi_kv", "Konkani_gom", "Korean_ko", "Kotava_avk", "Krio_kri", + "Kurdish_ku", "Kurmanji_kmr", "Kutchi_kfr", "Kyrgyz_ky", "Ladin_lld", + "Lakota_lkt", "Lao_lo", "Latgalian_ltg", "Latin_la", "Latvian_lv", + "Laz_lzz", "Lezgian_lez", "Ligurian_lij", "Limburgish_li", "Lingala_ln", + "Lithuanian_lt", "Lombard_lmo", "Louisiana Creole_lou", "Low German_nds", "Lower Yangtze Mandarin_juai", + "Lozi_loz", "Luganda_lg", "Luo_luo", "Lushootseed_lut", "Luxembourgish_lb", + "Macedonian_mk", "Mainfränkisch_vmf", "Malagasy_mg", "Malay_ms", "Malayalam_ml", + "Maltese_mt", "Manchu_mnc", "Mandarin Chinese_zh", "Mansi_mns", "Manx_gv", + "Māori_mi", "Mapudungun_arn", "Marathi_mr", "Mari_chm", "Marshallese_mh", + "Masbateño_msb", "Mauritian Creole_mfe", "Mazandarani_mzn", "Mbe_mfo", "Mennonite Low German_pdt", + "Micmac_mic", "Middle Chinese_ltc", "Middle English_enm", "Min Dong_cdo", "Min Nan_nan", + "Minangkabau_min", "Mingrelian_xmf", "Minjaee Luri_lrc", "Mohawk_moh", "Moksha_mdf", + "Moldovan_mo", "Mongolian_mn", "Moroccan Arabic_ary", "Nahuatl_nah", "Naskapi_nsk", + "Navajo_nv", "Naxi_nxq", "Ndonga_ng", "Neapolitan_nap", "Nepal Bhasa_new", + "Nepali_ne", "Nogai_nog", "North Levantine Arabic_apc", "Northern Sami_sme", "Norwegian_no", + "Norwegian Nynorsk_nn", "Nuosu_ii", "Nǀuu_ngh", "Occitan_oc", "Ojibwa_oj", + "Okinawan_ryu", "Old English_ang", "Old Norse_non", "Old Turkic_otk", "Oriya_or", + "Oromo_om", "Ossetian_os", "Ottoman Turkish_ota", "Palauan_pau", "Palenquero_pln", + "Pali_pi", "Pangasinan_pag", "Papiamento_pap", "Pashto_ps", "Pennsylvania Dutch_pdc", + "Persian_fa", "Picard_pcd", "Piedmontese_pms", "Pitjantjatjara_pjt", "Polish_pl", + "Portuguese_pt", "Pu-Xian Min_cpx", "Pulaar_fuc", "Punjabi_pa", "Quechua_qu", + "Quenya_qya", "Quiatoni Zapotec_zpf", "Rapa Nui_rap", "Reunionese Creole_rcf", "Romagnol_rgn", + "Romani_rom", "Romanian_ro", "Romansh_rm", "Rukiga_cgg", "Russian_ru", + "Rusyn_rue", "Samoan_sm", "Sango_sg", "Sanskrit_sa", "Saraiki_skr", + "Sardinian_sc", "Scots_sco", "Scottish Gaelic_gd", "Seediq_trv", "Serbian_sr", + "Shanghainese_jusi", "Shilha_shi", "Shona_sn", "Siberian Tatar_sty", "Sicilian_scn", + "Silesian_szl", "Silesian German_sli", "Sindhi_sd", "Sinhalese_si", "Slovak_sk", + "Slovenian_sl", "Somali_so", "Soninke_snk", "Sotho_st", "Southwestern Mandarin_xghu", + "Spanish_es", "Sranan Tongo_srn", "Sundanese_su", "Swabian German_swg", "Swahili_sw", + "Swati_ss", "Swedish_sv", "Swiss German_gsw", "Sylheti_syl", "Tagalog_tl", + "Tahitian_ty", "Tajik_tg", "Talossan_tzl", "Talysh_tly", "Tamil_ta", + "Tatar_tt", "Telugu_te", "Thai_th", "Tibetan_bo", "Tigrinya_ti", + "Toisanese Cantonese_tisa", "Tok Pisin_tpi", "Toki Pona_x-tp", "Tondano_tdn", "Tongan_to", + "Tswana_tn", "Tunisian Arabic_aeb", "Turkish_tr", "Turkmen_tk", "Tuvan_tyv", + "Twi_tw", "Ubykh_uby", "Udmurt_udm", "Ukrainian_uk", "Upper Saxon_sxu", + "Upper Sorbian_hsb", "Urdu_ur", "Uyghur_ug", "Uzbek_uz", "Venda_ve", + "Venetian_vec", "Vietnamese_vi", "Volapük_vo", "Võro_vro", "Walloon_wa", + "Welsh_cy", "Wenzhounese_qjio", "Wolof_wo", "Wu Chinese_wuu", "Xhosa_xh", + "Xiang Chinese_hsn", "Yakut_sah", "Yeyi_yey", "Yiddish_yi", "Yoruba_yo", + "Yucatec Maya_yua", "Yupik_esu", "Zazaki_zza", "Zhuang_za", "Zulu_zu", + ] + +def getLanguages(listPage): + #TODO: see line 99 + # takes a forvo language list page and returns all the languages with their code (I think forvo uses ISO 639-2) + langList = [] + languagesUl = listPage.select_one("ul.alphabetically") + for languageLi in languagesUl.findChildren("li", recursive=False): #LOL recursive lookup is true by default. Guess it makes sense, but got me confused (lxml habits die hard) + languageName = languageLi.select_one("a").getText() + languageCode = languageLi.select_one("abbr").getText() + langList.append(languageName + "_" + languageCode) + return langList + + +def updateForvoLanguages(): + # probably never needed, but useful if forvo adds extra languages + languageList = [] + # You can't get all pagination numbers displayed on 1 page, I check page 1 and go up untill the page returns None (404) + pageNumber = 1 + while(True): #TODO: Forvo has a single page with all languages and lang-codes. Use that instead of this + page, error_message = get_forvo_page("https://forvo.com/languages/alphabetically/" + "page-" + str(pageNumber), 1) + if page is None: + break + print("fetching languages from page: " + str(pageNumber)) + languageList.extend(getLanguages(page)) + pageNumber += 1 + print(languageList) + return languageList diff --git a/plugins/audios/audios/main.py b/plugins/audios/audios/main.py new file mode 100644 index 0000000000000000000000000000000000000000..2af92204c0ce35c02dbbf512655406bdc5d3c589 --- /dev/null +++ b/plugins/audios/audios/main.py @@ -0,0 +1,104 @@ +""" +Credits: + https://github.com/Rascalov/Anki-Simple-Forvo-Audio +""" + + +import re + +import requests.utils + +from .consts import _PLUGIN_LOCATION, _PLUGIN_NAME +from .page_processing import get_audio_link, get_forvo_page + +CACHED_RESULT = {} + +REMOVE_SPACES_PATTERN = re.compile(r"\s+", re.MULTILINE) + + +def remove_spaces(string: str) -> str: + return re.sub(REMOVE_SPACES_PATTERN, " ", string.strip()) + + +def get(word: str): + global CACHED_RESULT + + word_with_lang_code = "{} {}".format(word, "en") + + if (audioListLis := CACHED_RESULT.get(word_with_lang_code)) is None: + wordEncoded = requests.utils.requote_uri(word) + forvoPage, error_message = get_forvo_page( + "https://forvo.com/word/" + wordEncoded + ) + if error_message: + return [], error_message + speachSections = forvoPage.select("div#language-container-" + "en") + if not len(speachSections): + return ( + [], + f"[{_PLUGIN_NAME}] Word not found (Language Container does not exist!)", + ) + speachSections = forvoPage.select_one("div#language-container-" + "en") + audioListUl = speachSections.select_one("ul") + if audioListUl is None or not len( + audioListUl.findChildren(recursive=False) + ): + return ( + [], + f"[{_PLUGIN_NAME}] Word not found (Language Container exists, but audio not found)", + ) + # if config["language_code"] == "en": + audioListLis = forvoPage.select("li[class*=en_]") + # else: + # audioListLis = audioListUl.find_all("li") + + if audioListLis: + CACHED_RESULT[word_with_lang_code] = audioListLis + + audio_batch: list[tuple[str, str]] = [] + batch_size = yield + for li in audioListLis: + if (r := li.find("div")) is not None and ( + onclick := r.get("onclick") + ) is not None: + audio_link = get_audio_link(onclick) + by_whom_data = li.find("span", {"class": "info"}) + by_whom_data = ( + remove_spaces(by_whom_data.text) + if by_whom_data is not None + else "" + ) + from_data = li.find("span", {"class": "from"}) + from_data = ( + remove_spaces(from_data.text) if from_data is not None else "" + ) + additional_info = ( + (f"{by_whom_data}\n{from_data}") + if from_data is not None + else "" + ) + audio_batch.append((audio_link, additional_info)) + if len(audio_batch) == batch_size: + batch_size = yield audio_batch, "" + audio_batch = [] + return audio_batch, "" + + +def load(): + return + + +def unload(): + return + + +def get_config_description(): + return {} + + +def get_default_config(): + return {} + + +def set_config(new_config: dict) -> dict: + return {} diff --git a/plugins/audios/audios/page_processing.py b/plugins/audios/audios/page_processing.py new file mode 100644 index 0000000000000000000000000000000000000000..602b55cc3145216b3d189878d6fcc7743e13b6f8 --- /dev/null +++ b/plugins/audios/audios/page_processing.py @@ -0,0 +1,42 @@ +import base64 +from typing import Optional + +import requests +from bs4 import BeautifulSoup + +from .consts import _HEADERS, _PLUGIN_NAME + + +def get_forvo_page(url: str, timeout: int = 1) -> tuple[Optional[BeautifulSoup], str]: + try: + r = requests.get(url, headers=_HEADERS) + r.raise_for_status() + decoded_page_content = r.content.decode('UTF-8') + except requests.RequestException as e: + return None, f"[{_PLUGIN_NAME}] Couldn't get web page! Error: {str(e)}" + except UnicodeDecodeError as e: + return None, f"[{_PLUGIN_NAME}] Couldn't decode page to UTF-8 format! Error: {str(e)}" + + soup = BeautifulSoup(decoded_page_content, "html.parser") + return soup, "" + + +def get_audio_link(onclickFunction) -> str: + #example js play functions from forvo: + #Play(6166435,'OTg4MTIyMC8xMzgvOTg4MTIyMF8xMzhfMzM5MDIxLm1wMw==','OTg4MTIyMC8xMzgvOTg4MTIyMF8xMzhfMzM5MDIxLm9nZw==',false,'by80L280Xzk4ODEyMjBfMTM4XzMzOTAyMS5tcDM=','by80L280Xzk4ODEyMjBfMTM4XzMzOTAyMS5vZ2c=','h');return false; + #Play(6687207,'OTU5NzcxMy8xMzgvOTU5NzcxM18xMzhfNjk2MDEyMi5tcDM=','OTU5NzcxMy8xMzgvOTU5NzcxM18xMzhfNjk2MDEyMi5vZ2c=',false,'','','l');return false; + # All audios have an ogg version as a fallback on the mp3. Ogg is open source and compresses audio to a smaller size than mp3. + # So I grab the ogg base64 string and decode it. + # + # Ogg doesn't work properly with playsound on Windows :( + # Ogg index - 2; MP3 index - 1 + base64audio = onclickFunction.split(',')[1].replace('\'', "") + decodedLink = base64.b64decode(base64audio.encode('ascii')).decode('ascii') + return "https://audio00.forvo.com/mp3/" + decodedLink + + +def get_forvo_audio_link(audioLi) -> str: + #selector = CSSSelector("span") + audioTag = audioLi.select_one("span") + audioLink = get_audio_link(audioTag["onclick"]) + return audioLink \ No newline at end of file diff --git a/plugins/images/images/images_provider.py b/plugins/images/images/images_provider.py index f30187a4ee062d692d4047b3aaa14cb92f27929d..50cd7836470fcbc8c52224f1a2c926571428300e 100644 --- a/plugins/images/images/images_provider.py +++ b/plugins/images/images/images_provider.py @@ -1,5 +1,62 @@ -def get(): - return [], "" +import json +import os +import re + +import bs4 +import requests + +PLUGIN_NAME = os.path.split(os.path.dirname(__file__))[-1] + + +def get(word: str): + link = f"https://www.google.com/search?tbm=isch&q={word}" + user_agent = ( + "Mozilla/5.0 (Windows NT 6.1; Win64; x64) ApplewebKit/537.36 (KHTML, like Gecko) " + "Chrome/70.0.3538.67 Safari/537.36" + ) + headers = {"User-Agent": user_agent} + try: + r = requests.get(link, headers=headers) + r.raise_for_status() + except requests.RequestException: + return [], f"[{PLUGIN_NAME}]: Couldn't get a web page!" + + html = r.text + soup = bs4.BeautifulSoup(r.text, "html.parser") + rg_meta = soup.find_all("div", {"class": "rg_meta"}) + metadata = [json.loads(e.text) for e in rg_meta] + results = [d["ou"] for d in metadata] + + batch_size = yield + if not results: + regex = re.escape("AF_initDataCallback({") + regex += r"[^<]*?data:[^<]*?" + r"(\[[^<]+\])" + + for txt in re.findall(regex, html): + data = json.loads(txt) + + try: + for d in data[31][0][12][2]: + try: + results.append(d[1][3][0]) + if not len(results) % batch_size: + batch_size = yield results, "" + results = [] + except Exception as exception: + pass + except Exception as exception: + try: + for d in data[56][1][0][0][1][0]: + try: + results.append(d[0][0]["444383007"][1][3][0]) + if not len(results) % batch_size: + batch_size = yield results, "" + results = [] + except Exception as exception: + pass + except Exception as exception: + pass + return results, "" def load(): diff --git a/plugins/sentences/sentences/sentences_provider.py b/plugins/sentences/sentences/sentences_provider.py index f2eedee4dca8eda9fd9b113721b91694bdc0b2da..2b1adaed70b44775e6ef9223cb44459d094e8f22 100644 --- a/plugins/sentences/sentences/sentences_provider.py +++ b/plugins/sentences/sentences/sentences_provider.py @@ -1,4 +1,37 @@ -def get(): +import os + +import bs4 +import requests + +FILE_PATH = os.path.split(os.path.dirname(__file__))[-1] + + +def get(word: str): + try: + page = requests.get( + f"https://searchsentences.com/words/{word}-in-a-sentence", + ) + page.raise_for_status() + except requests.RequestException as e: + return [], f"{FILE_PATH} couldn't get a web page: {e}" + + soup = bs4.BeautifulSoup(page.content, "html.parser") + src = soup.find_all("li", {"class": "sentence-row"}) + sentences = [] + for sentence_block in src: + if (sentence := sentence_block.find("span")) is None: + continue + text = sentence.get_text() + if text: + sentences.append(text) + + sentences.sort(key=len) + i = 0 + size = yield + while i < len(sentences): + size = yield sentences[i : i + size], "" + i += size + return [], "" diff --git a/server/lib/network/ResponseGenerators/ResponseGenerators.cpp b/server/lib/network/ResponseGenerators/ResponseGenerators.cpp index 36fc4ddfe4f4a8a9a826af8f7f3954b2d5db90aa..01ec8716fc83fa7291937e179155cdbe2d2b450b 100644 --- a/server/lib/network/ResponseGenerators/ResponseGenerators.cpp +++ b/server/lib/network/ResponseGenerators/ResponseGenerators.cpp @@ -6,6 +6,7 @@ #include "PyExceptionInfo.hpp" #include "SentencesProviderWrapper.hpp" #include "spdlog/common.h" +#include "spdlog/spdlog.h" #include #include @@ -26,10 +27,12 @@ static auto return_error(const std::string &message) -> json { json dst; dst["status"] = 1; dst["message"] = message; + SPDLOG_ERROR(message); return dst; } auto ResponseGenerator::handle(const std::string &request) -> json { + SPDLOG_INFO("Got new request"); json parsed_request; try { parsed_request = json::parse(request); @@ -50,27 +53,39 @@ auto ResponseGenerator::handle(const std::string &request) -> json { } std::string query_type = json_query_type; if (query_type == INIT_QUERY_TYPE) { + SPDLOG_INFO("Started handling `{}` request", INIT_QUERY_TYPE); return handle_init(parsed_request); } if (query_type == GET_DEFAULT_CONFIG_QUERY_TYPE) { + SPDLOG_INFO("Started handling `{}` request", + GET_DEFAULT_CONFIG_QUERY_TYPE); return handle_get_default_config(parsed_request); } if (query_type == GET_CONFIG_SCHEME_QUERY_TYPE) { + SPDLOG_INFO("Started handling `{}` request", + GET_CONFIG_SCHEME_QUERY_TYPE); return handle_get_config_scheme(parsed_request); } if (query_type == SET_CONFIG_QUERY_TYPE) { + SPDLOG_INFO("Started handling `{}` request", SET_CONFIG_QUERY_TYPE); return handle_set_config(parsed_request); } if (query_type == LIST_PLUGINS_QUERY_TYPE) { + SPDLOG_INFO("Started handling `{}` request", LIST_PLUGINS_QUERY_TYPE); return handle_list_plugins(parsed_request); } if (query_type == LOAD_NEW_PLUGINS_QUERY_TYPE) { + SPDLOG_INFO("Started handling `{}` request", + LOAD_NEW_PLUGINS_QUERY_TYPE); return handle_load_new_plugins(parsed_request); } if (query_type == GET_QUERY_TYPE) { + SPDLOG_INFO("Started handling `{}` request", GET_QUERY_TYPE); return handle_get(parsed_request); } if (query_type == GET_DICT_SCHEME_QUERY_TYPE) { + SPDLOG_INFO("Started handling `{}` request", + GET_DICT_SCHEME_QUERY_TYPE); return handle_get_dict_scheme(parsed_request); } return return_error("Unknown query type: "s + query_type); @@ -99,6 +114,9 @@ auto ResponseGenerator::handle_init(const nlohmann::json &request) auto plugin_name = request[PLUGIN_NAME_FIELD].get(); if (plugin_type == DEFINITION_PROVIDER_PLUGIN_TYPE) { + SPDLOG_INFO("Handling {} definitions provider's initialization request", + plugin_name); + auto requested_wrapper_option = plugins_provider_->get_definitions_provider(plugin_name); if (!requested_wrapper_option.has_value()) { @@ -113,14 +131,23 @@ auto ResponseGenerator::handle_init(const nlohmann::json &request) "\" definitions provider's construction:\n" + exception_info.stack_trace()); } + auto wrapper = std::move(std::get(wrapper_variant)); auto unique_wrapper = std::make_unique(std::move(wrapper)); + plugins_bundle_.set_definitions_provider(std::move(unique_wrapper)); + + SPDLOG_INFO("Successfully handled {} definition provider's " + "initialization request", + plugin_name); return R"({"status": 0, "message": ""})"_json; } if (plugin_type == SENTENCES_PROVIDER_PLUGIN_TYPE) { + SPDLOG_INFO("Handling {} sentences provider's initialization request", + plugin_name); + auto requested_wrapper_option = plugins_provider_->get_sentences_provider(plugin_name); if (!requested_wrapper_option.has_value()) { @@ -139,9 +166,16 @@ auto ResponseGenerator::handle_init(const nlohmann::json &request) auto unique_wrapper = std::make_unique(std::move(wrapper)); plugins_bundle_.set_sentences_provider(std::move(unique_wrapper)); + + SPDLOG_INFO("Successfully handled {} sentences provider's " + "initialization request", + plugin_name); return R"({"status": 0, "message": ""})"_json; } if (plugin_type == IMAGES_PROVIDER_PLUGIN_TYPE) { + SPDLOG_INFO("Handling {} images provider's initialization request", + plugin_name); + auto requested_wrapper_option = plugins_provider_->get_images_provider(plugin_name); if (!requested_wrapper_option.has_value()) { @@ -160,9 +194,16 @@ auto ResponseGenerator::handle_init(const nlohmann::json &request) auto unique_wrapper = std::make_unique(std::move(wrapper)); plugins_bundle_.set_images_provider(std::move(unique_wrapper)); + + SPDLOG_INFO("Successfully handled {} images provider's " + "initialization request", + plugin_name); return R"({"status": 0, "message": ""})"_json; } if (plugin_type == AUDIOS_PROVIDER_PLUGIN_TYPE) { + SPDLOG_INFO("Handling {} audios provider's initialization request", + plugin_name); + auto requested_wrapper_option = plugins_provider_->get_audios_provider(plugin_name); if (!requested_wrapper_option.has_value()) { @@ -181,9 +222,16 @@ auto ResponseGenerator::handle_init(const nlohmann::json &request) auto unique_wrapper = std::make_unique(std::move(wrapper)); plugins_bundle_.set_audios_provider(std::move(unique_wrapper)); + + SPDLOG_INFO("Successfully handled {} audios provider's " + "initialization request", + plugin_name); return R"({"status": 0, "message": ""})"_json; } if (plugin_type == FORMAT_PROCESSOR_PLUGIN_TYPE) { + SPDLOG_INFO("Handling {} format processor's initialization request", + plugin_name); + auto requested_wrapper_option = plugins_provider_->get_format_processor(plugin_name); if (!requested_wrapper_option.has_value()) { @@ -202,6 +250,10 @@ auto ResponseGenerator::handle_init(const nlohmann::json &request) auto unique_wrapper = std::make_unique(std::move(wrapper)); plugins_bundle_.set_format_processor(std::move(unique_wrapper)); + + SPDLOG_INFO("Successfully handled {} format processor's " + "initialization request", + plugin_name); return R"({"status": 0, "message": ""})"_json; } return return_error("Unknown plugin_type: " + plugin_type); @@ -209,31 +261,31 @@ auto ResponseGenerator::handle_init(const nlohmann::json &request) auto ResponseGenerator::handle_get_default_config(const nlohmann::json &request) -> nlohmann::json { - spdlog::throw_spdlog_ex("handle_get_default_config() is not implemented"); + SPDLOG_THROW("handle_get_default_config() is not implemented"); return {}; } auto ResponseGenerator::handle_get_config_scheme(const nlohmann::json &request) -> nlohmann::json { - spdlog::throw_spdlog_ex("handle_get_config_scheme() is not implemented"); + SPDLOG_THROW("handle_get_config_scheme() is not implemented"); return {}; } auto ResponseGenerator::handle_set_config(const nlohmann::json &request) -> nlohmann::json { - spdlog::throw_spdlog_ex("handle_set_config() is not implemented"); + SPDLOG_THROW("handle_set_config() is not implemented"); return {}; } auto ResponseGenerator::handle_list_plugins(const nlohmann::json &request) -> nlohmann::json { - spdlog::throw_spdlog_ex("handle_list_plugins() is not implemented"); + SPDLOG_THROW("handle_list_plugins() is not implemented"); return {}; } auto ResponseGenerator::handle_load_new_plugins(const nlohmann::json &request) -> nlohmann::json { - spdlog::throw_spdlog_ex("handle_load_new_plugins() is not implemented"); + SPDLOG_THROW("handle_load_new_plugins() is not implemented"); return {}; } @@ -250,81 +302,16 @@ auto ResponseGenerator::handle_get(const nlohmann::json &request) auto plugin_type = request[PLUGIN_TYPE_FIELD].get(); if (plugin_type == DEFINITION_PROVIDER_PLUGIN_TYPE) { - auto *provider = plugins_bundle_.definitions_provider(); - if (provider == nullptr) { - return return_error("Cannot return anything because definitions " - "provider is not initialized"); - } - - if (!request.contains(WORD_FIELD)) { - return return_error("\""s + WORD_FIELD + - "\" filed was not found in request"); - } - if (!request[WORD_FIELD].is_string()) { - return return_error("\""s + WORD_FIELD + - "\" field is expected to be a string"); - } - auto word = request[WORD_FIELD].get(); - - if (!request.contains(FILTER_QUERY_FIELD)) { - return return_error("\""s + FILTER_QUERY_FIELD + - "\" fieled was not found in request"); - } - if (!request[FILTER_QUERY_FIELD].is_string()) { - return return_error("\""s + FILTER_QUERY_FIELD + - "\" field is expected to be a string"); - } - auto filter_query = request[FILTER_QUERY_FIELD].get(); - - if (!request.contains(BATCH_SIZE_FIELD)) { - return return_error("\""s + BATCH_SIZE_FIELD + - "\" filed was not found in request"); - } - if (!request[BATCH_SIZE_FIELD].is_number()) { - return return_error("\""s + BATCH_SIZE_FIELD + - "\" field is expected to be a number"); - } - auto batch_size = request[BATCH_SIZE_FIELD].get(); - - if (!request.contains(RESTART_FIELD)) { - return return_error("\""s + RESTART_FIELD + - "\" filed was not found in request"); - } - if (!request[RESTART_FIELD].is_boolean()) { - return return_error("\""s + RESTART_FIELD + - "\" field is expected to be a boolean"); - } - auto restart = request[RESTART_FIELD].get(); - - auto result_or_error = - provider->get(word, filter_query, batch_size, restart); - if (std::holds_alternative(result_or_error)) { - auto exception_info = std::get(result_or_error); - return return_error("Exception was thrown during \"" + - provider->name() + "\" definitions request:\n" + - exception_info.stack_trace()); - } - if (std::holds_alternative( - result_or_error)) { - auto result = - std::get(result_or_error); - return result; - } - auto non_python_error_message = std::get(result_or_error); - - auto json_message = R"({"status": 1, "message": ")"s + - non_python_error_message + R"("})"; - return json::parse(json_message); + return handle_get_definitions(request); } if (plugin_type == SENTENCES_PROVIDER_PLUGIN_TYPE) { - return return_error( - "Requests to sentences provider is not implemented"); + return handle_get_sentences(request); } if (plugin_type == IMAGES_PROVIDER_PLUGIN_TYPE) { - return return_error("Requests to images provider is not implemented"); + return handle_get_images(request); } if (plugin_type == AUDIOS_PROVIDER_PLUGIN_TYPE) { - return return_error("Requests to audios provider is not implemented"); + return handle_get_audios(request); } if (plugin_type == FORMAT_PROCESSOR_PLUGIN_TYPE) { return return_error("Requests to format processor is not implemented"); @@ -332,8 +319,258 @@ auto ResponseGenerator::handle_get(const nlohmann::json &request) return return_error("Unknown plugin type: "s + plugin_type); } +auto ResponseGenerator::handle_get_definitions(const nlohmann::json &request) + -> nlohmann::json { + SPDLOG_INFO("Starting handling `get` request for definitions"); + + auto *provider = plugins_bundle_.definitions_provider(); + if (provider == nullptr) { + return return_error("Definitions provider is not initialized"); + } + + if (!request.contains(WORD_FIELD)) { + return return_error("\""s + WORD_FIELD + + "\" filed was not found in request"); + } + if (!request[WORD_FIELD].is_string()) { + return return_error("\""s + WORD_FIELD + + "\" field is expected to be a string"); + } + auto word = request[WORD_FIELD].get(); + + if (!request.contains(FILTER_QUERY_FIELD)) { + return return_error("\""s + FILTER_QUERY_FIELD + + "\" fieled was not found in request"); + } + if (!request[FILTER_QUERY_FIELD].is_string()) { + return return_error("\""s + FILTER_QUERY_FIELD + + "\" field is expected to be a string"); + } + auto filter_query = request[FILTER_QUERY_FIELD].get(); + + if (!request.contains(BATCH_SIZE_FIELD)) { + return return_error("\""s + BATCH_SIZE_FIELD + + "\" filed was not found in request"); + } + if (!request[BATCH_SIZE_FIELD].is_number()) { + return return_error("\""s + BATCH_SIZE_FIELD + + "\" field is expected to be a number"); + } + auto batch_size = request[BATCH_SIZE_FIELD].get(); + + if (!request.contains(RESTART_FIELD)) { + return return_error("\""s + RESTART_FIELD + + "\" filed was not found in request"); + } + if (!request[RESTART_FIELD].is_boolean()) { + return return_error("\""s + RESTART_FIELD + + "\" field is expected to be a boolean"); + } + auto restart = request[RESTART_FIELD].get(); + + auto result_or_error = + provider->get(word, filter_query, batch_size, restart); + if (std::holds_alternative(result_or_error)) { + auto exception_info = std::get(result_or_error); + return return_error("Exception was thrown during \"" + + provider->name() + "\" definitions request:\n" + + exception_info.stack_trace()); + } + if (std::holds_alternative( + result_or_error)) { + auto result = + std::get(result_or_error); + return result; + } + auto non_python_error_message = std::get(result_or_error); + + auto json_message = + R"({"status": 1, "message": ")"s + non_python_error_message + R"("})"; + + SPDLOG_INFO("Successfully handled `get` request for definitions"); + return json::parse(json_message); +} + +auto ResponseGenerator::handle_get_sentences(const nlohmann::json &request) + -> nlohmann::json { + SPDLOG_INFO("Starting handling `get` request for sentences"); + + auto *provider = plugins_bundle_.sentences_provider(); + if (provider == nullptr) { + return return_error("Sentences provider is not initialized"); + } + + if (!request.contains(WORD_FIELD)) { + return return_error("\""s + WORD_FIELD + + "\" filed was not found in request"); + } + if (!request[WORD_FIELD].is_string()) { + return return_error("\""s + WORD_FIELD + + "\" field is expected to be a string"); + } + auto word = request[WORD_FIELD].get(); + + if (!request.contains(BATCH_SIZE_FIELD)) { + return return_error("\""s + BATCH_SIZE_FIELD + + "\" filed was not found in request"); + } + if (!request[BATCH_SIZE_FIELD].is_number()) { + return return_error("\""s + BATCH_SIZE_FIELD + + "\" field is expected to be a number"); + } + auto batch_size = request[BATCH_SIZE_FIELD].get(); + + if (!request.contains(RESTART_FIELD)) { + return return_error("\""s + RESTART_FIELD + + "\" filed was not found in request"); + } + if (!request[RESTART_FIELD].is_boolean()) { + return return_error("\""s + RESTART_FIELD + + "\" field is expected to be a boolean"); + } + auto restart = request[RESTART_FIELD].get(); + + auto result_or_error = provider->get(word, batch_size, restart); + if (std::holds_alternative(result_or_error)) { + auto exception_info = std::get(result_or_error); + return return_error("Exception was thrown during \"" + + provider->name() + "\" sentences request:\n" + + exception_info.stack_trace()); + } + if (std::holds_alternative( + result_or_error)) { + auto result = std::get(result_or_error); + return result; + } + auto non_python_error_message = std::get(result_or_error); + + auto json_message = + R"({"status": 1, "message": ")"s + non_python_error_message + R"("})"; + + SPDLOG_INFO("Successfully handled `get` request for sentences"); + return json::parse(json_message); +} + +auto ResponseGenerator::handle_get_images(const nlohmann::json &request) + -> nlohmann::json { + SPDLOG_INFO("Starting handling `get` request for images"); + + auto *provider = plugins_bundle_.images_provider(); + if (provider == nullptr) { + return return_error("Images provider is not initialized"); + } + + if (!request.contains(WORD_FIELD)) { + return return_error("\""s + WORD_FIELD + + "\" filed was not found in request"); + } + if (!request[WORD_FIELD].is_string()) { + return return_error("\""s + WORD_FIELD + + "\" field is expected to be a string"); + } + auto word = request[WORD_FIELD].get(); + + if (!request.contains(BATCH_SIZE_FIELD)) { + return return_error("\""s + BATCH_SIZE_FIELD + + "\" filed was not found in request"); + } + if (!request[BATCH_SIZE_FIELD].is_number()) { + return return_error("\""s + BATCH_SIZE_FIELD + + "\" field is expected to be a number"); + } + auto batch_size = request[BATCH_SIZE_FIELD].get(); + + if (!request.contains(RESTART_FIELD)) { + return return_error("\""s + RESTART_FIELD + + "\" filed was not found in request"); + } + if (!request[RESTART_FIELD].is_boolean()) { + return return_error("\""s + RESTART_FIELD + + "\" field is expected to be a boolean"); + } + auto restart = request[RESTART_FIELD].get(); + + auto result_or_error = provider->get(word, batch_size, restart); + if (std::holds_alternative(result_or_error)) { + auto exception_info = std::get(result_or_error); + return return_error("Exception was thrown during \"" + + provider->name() + "\" images request:\n" + + exception_info.stack_trace()); + } + if (std::holds_alternative(result_or_error)) { + auto result = std::get(result_or_error); + return result; + } + auto non_python_error_message = std::get(result_or_error); + + auto json_message = + R"({"status": 1, "message": ")"s + non_python_error_message + R"("})"; + + SPDLOG_INFO("Successfully handled `get` request for images"); + return json::parse(json_message); +} + +auto ResponseGenerator::handle_get_audios(const nlohmann::json &request) + -> nlohmann::json { + SPDLOG_INFO("Starting handling `get` request for audios"); + + auto *provider = plugins_bundle_.audios_provider(); + if (provider == nullptr) { + return return_error("Audios provider is not initialized"); + } + + if (!request.contains(WORD_FIELD)) { + return return_error("\""s + WORD_FIELD + + "\" filed was not found in request"); + } + if (!request[WORD_FIELD].is_string()) { + return return_error("\""s + WORD_FIELD + + "\" field is expected to be a string"); + } + auto word = request[WORD_FIELD].get(); + + if (!request.contains(BATCH_SIZE_FIELD)) { + return return_error("\""s + BATCH_SIZE_FIELD + + "\" filed was not found in request"); + } + if (!request[BATCH_SIZE_FIELD].is_number()) { + return return_error("\""s + BATCH_SIZE_FIELD + + "\" field is expected to be a number"); + } + auto batch_size = request[BATCH_SIZE_FIELD].get(); + + if (!request.contains(RESTART_FIELD)) { + return return_error("\""s + RESTART_FIELD + + "\" filed was not found in request"); + } + if (!request[RESTART_FIELD].is_boolean()) { + return return_error("\""s + RESTART_FIELD + + "\" field is expected to be a boolean"); + } + auto restart = request[RESTART_FIELD].get(); + + auto result_or_error = provider->get(word, batch_size, restart); + if (std::holds_alternative(result_or_error)) { + auto exception_info = std::get(result_or_error); + return return_error("Exception was thrown during \"" + + provider->name() + "\" definitions request:\n" + + exception_info.stack_trace()); + } + if (std::holds_alternative(result_or_error)) { + auto result = std::get(result_or_error); + return result; + } + auto non_python_error_message = std::get(result_or_error); + + auto json_message = + R"({"status": 1, "message": ")"s + non_python_error_message + R"("})"; + + SPDLOG_INFO("Successfully handled `get` request for audios"); + return json::parse(json_message); +} + auto ResponseGenerator::handle_get_dict_scheme(const nlohmann::json &request) -> nlohmann::json { - spdlog::throw_spdlog_ex("handle_get_dict_scheme() is not implemented"); + SPDLOG_THROW("handle_get_dict_scheme() is not implemented"); return {}; } diff --git a/server/lib/network/ResponseGenerators/ResponseGenerators.hpp b/server/lib/network/ResponseGenerators/ResponseGenerators.hpp index d17cf6291306b49fc4a50cfb1d6f96ea184d5ded..e9c2ecdb7511df0434ca7c525c29f5f6c3989bb5 100644 --- a/server/lib/network/ResponseGenerators/ResponseGenerators.hpp +++ b/server/lib/network/ResponseGenerators/ResponseGenerators.hpp @@ -5,6 +5,7 @@ #include "PluginsProvider.hpp" #include #include +#include #include class IResponceGenerator { @@ -76,6 +77,13 @@ class ResponseGenerator : public IResponceGenerator { auto handle_get_dict_scheme(const nlohmann::json &request) -> nlohmann::json override; + auto handle_get_definitions(const nlohmann::json &request) + -> nlohmann::json; + + auto handle_get_sentences(const nlohmann::json &request) -> nlohmann::json; + auto handle_get_images(const nlohmann::json &request) -> nlohmann::json; + auto handle_get_audios(const nlohmann::json &request) -> nlohmann::json; + private: PluginsBundle plugins_bundle_; const std::shared_ptr plugins_provider_; diff --git a/server/lib/network/Server/Server.cpp b/server/lib/network/Server/Server.cpp index 30438d3c37e1f41ed6d33801f68ac17d5420512a..93b86211db76db6914e1c85e6133f5ccbb7046f5 100644 --- a/server/lib/network/Server/Server.cpp +++ b/server/lib/network/Server/Server.cpp @@ -26,7 +26,11 @@ PluginServer::PluginServer(std::shared_ptr &&provider, : io_context_(context), acceptor_(io_context_, tcp::endpoint(tcp::v4(), port)), plugins_provider_(std::move(provider)) { + SPDLOG_INFO("Initializing Python interpreter"); Py_Initialize(); + SPDLOG_INFO("Successfully initialized Python interpreter"); + + SPDLOG_INFO("Starting accepting requests"); start_accept(); } diff --git a/server/lib/network/Session/Session.cpp b/server/lib/network/Session/Session.cpp index d773f68068c5014a923e7b9becce1ea4a78894dc..2361119573a17e6830ed7ea2c0e2597596f510e6 100644 --- a/server/lib/network/Session/Session.cpp +++ b/server/lib/network/Session/Session.cpp @@ -13,7 +13,7 @@ Session::Session(boost::asio::ip::tcp::socket socket, } void Session::start() { - spdlog::info("Started new session"); + SPDLOG_INFO("Started new session"); do_read(); } @@ -26,7 +26,7 @@ void Session::do_read() { "\r\n", [this, self](boost::system::error_code error_code, std::size_t length) { if (error_code) { - spdlog::error("Couldn't read from user"); + SPDLOG_ERROR("Couldn't read from user"); return; } @@ -52,7 +52,7 @@ void Session::do_write(std::string response) { boost::asio::buffer(response, response.length()), [this, self](boost::system::error_code ec, std::size_t length) { if (ec) { - spdlog::error("Couldn't respond to user"); + SPDLOG_ERROR("Couldn't respond to user"); } do_read(); }); diff --git a/server/lib/plugins/PluginsLoader/PluginsLoader.hpp b/server/lib/plugins/PluginsLoader/PluginsLoader.hpp index ec2eec64a92baa64ef5a89807ff03b8a7462dc11..ee9476cace89c74b9a00dc74160d471547e8cb5f 100644 --- a/server/lib/plugins/PluginsLoader/PluginsLoader.hpp +++ b/server/lib/plugins/PluginsLoader/PluginsLoader.hpp @@ -44,14 +44,14 @@ class PluginsLoader : public IPluginsLoader { boost::python::object sys = boost::python::import("sys"); sys.attr("path").attr("append")(plugins_dir.c_str()); } catch (const boost::python::error_already_set &) { - spdlog::throw_spdlog_ex("Couldn't import sys module"); + SPDLOG_THROW("Couldn't import sys module"); } std::ranges::for_each( std::filesystem::directory_iterator(plugins_dir), [this](const std::filesystem::path &dir_entry) { using std::string_literals::operator""s; - spdlog::info("Loading plugin from "s + dir_entry.string()); + SPDLOG_INFO("Loading plugin from "s + dir_entry.string()); if (!std::filesystem::is_directory(dir_entry)) { return; @@ -62,35 +62,35 @@ class PluginsLoader : public IPluginsLoader { try { loaded_module = boost::python::import(module_name.c_str()); } catch (const boost::python::error_already_set &) { - spdlog::info("Failed to import module: "s + - module_name.string()); + SPDLOG_INFO("Failed to import module: "s + + module_name.string()); auto error_info = PyExceptionInfo::build(); failed_containers_.emplace(std::move(module_name), std::move(error_info)); return; } - spdlog::info("Successfully imported Python module: "s + - module_name.string()); auto wrapper_or_error = Wrapper::build(module_name.string(), loaded_module); + SPDLOG_INFO("Successfully imported Python module: "s + + module_name.string()); + if (std::holds_alternative(wrapper_or_error)) { auto info = std::get(wrapper_or_error); - spdlog::info("Failed to load plugin from "s + - dir_entry.string()); + SPDLOG_INFO("Failed to load plugin from "s + + dir_entry.string()); failed_containers_.emplace(std::move(module_name), std::move(info)); } else if (std::holds_alternative(wrapper_or_error)) { auto wrapper = std::move(std::get(wrapper_or_error)); - spdlog::info("Successfully loaded plugin from "s + - dir_entry.string()); + SPDLOG_INFO("Successfully loaded plugin from "s + + dir_entry.string()); loaded_containers_.emplace(std::move(module_name), std::move(wrapper)); } else { - spdlog::throw_spdlog_ex( - "Unknown return from a container build"); + SPDLOG_THROW("Unknown return from a container build"); } }); } @@ -98,14 +98,14 @@ class PluginsLoader : public IPluginsLoader { auto get(const std::string &plugin_name) -> std::optional> override { using std::string_literals::operator""s; - spdlog::info(plugin_name + " was requested"); + SPDLOG_INFO(plugin_name + " was requested"); auto res = loaded_containers_.find(plugin_name); if (res == loaded_containers_.end()) { - spdlog::info(plugin_name + " not found"); + SPDLOG_INFO(plugin_name + " not found"); return std::nullopt; } - spdlog::info(plugin_name + " was found"); + SPDLOG_INFO(plugin_name + " was found"); auto found_wrapper = res->second; return found_wrapper; } diff --git a/server/lib/plugins/PluginsProvider/PluginsProvider.cpp b/server/lib/plugins/PluginsProvider/PluginsProvider.cpp index 7e7f2c082f0de3cd73f93bdc9219c8d107fdc132..b2a2f633aafdfe9c5b631212de9f8d91fcad5778 100644 --- a/server/lib/plugins/PluginsProvider/PluginsProvider.cpp +++ b/server/lib/plugins/PluginsProvider/PluginsProvider.cpp @@ -49,5 +49,5 @@ auto PluginsProvider::get_format_processor(const std::string &name) } auto PluginsProvider::load_new_plugins() -> void { - spdlog::throw_spdlog_ex("load_new_plugins() is not implemented"); + SPDLOG_THROW("load_new_plugins() is not implemented"); } diff --git a/server/lib/plugins/PyExceptionInfo/PyExceptionInfo.cpp b/server/lib/plugins/PyExceptionInfo/PyExceptionInfo.cpp index 6078e2c68ee54d8aae578204948ae498804ba673..1b94555a8e0aed0b810c18dc9c0dda13c4505cb3 100644 --- a/server/lib/plugins/PyExceptionInfo/PyExceptionInfo.cpp +++ b/server/lib/plugins/PyExceptionInfo/PyExceptionInfo.cpp @@ -10,6 +10,7 @@ auto PyExceptionInfo::build() -> std::optional { // PyErr_Print обязатетен // https://stackoverflow.com/a/57896281 PyExceptionInfo info; + try { PyErr_Print(); boost::python::object main_namespace = @@ -35,7 +36,7 @@ auto PyExceptionInfo::build() -> std::optional { PyErr_Clear(); } catch (const boost::python::error_already_set &) { - spdlog::error("Couldn't extract python exception info"); + SPDLOG_ERROR("Couldn't extract python exception info"); return std::nullopt; } return info; diff --git a/server/lib/plugins/wrappers/actual/AudiosProviderWrapper/AudiosProviderWrapper.cpp b/server/lib/plugins/wrappers/actual/AudiosProviderWrapper/AudiosProviderWrapper.cpp index 10e55a5e20911a3223185d06903b57d5f06d56c2..cdb3e5ed7f7c781218568b6adcc512f46d269a05 100644 --- a/server/lib/plugins/wrappers/actual/AudiosProviderWrapper/AudiosProviderWrapper.cpp +++ b/server/lib/plugins/wrappers/actual/AudiosProviderWrapper/AudiosProviderWrapper.cpp @@ -61,49 +61,111 @@ auto AudiosProviderWrapper::get(const std::string &word, uint64_t batch_size, bool restart) -> std::variant { - std::vector test; + SPDLOG_INFO( + "[{}] Handling request: word: `{}`, batch_size: `{}`, restart: `{}`", + name(), + word, + batch_size, + restart); + if (restart) { auto found_item = generators_.find(word); if (found_item != generators_.end()) { + + SPDLOG_INFO( + "[{}] Restarting generator for word `{}`", name(), word); + generators_.erase(found_item); + } else { + SPDLOG_WARN("[{}] restart request was given but no generator for " + "word `{}` was found", + name(), + word); } } if (generators_.find(word) == generators_.end()) { + SPDLOG_INFO("[{}] Initializing generator for word `{}`", name(), word); + + boost::python::object generator; try { - boost::python::object test = specifics_.get(word); - generators_[word] = test; - generators_[word]->attr("__next__")(); + generator = specifics_.get(word); + generator.attr("__next__")(); } catch (const boost::python::error_already_set &) { - generators_.erase(generators_.find(word)); return PyExceptionInfo::build().value(); } + generators_[word] = generator; } try { + SPDLOG_INFO("[{}] (Python side) Loading JSON module", name()); + boost::python::object py_json = boost::python::import("json"); boost::python::object py_json_dumps = py_json.attr("dumps"); + SPDLOG_INFO( + "[{}] (Python side) Trying to obtain data batch for word `{}`", + name(), + word); + boost::python::object py_res = - generators_[word]->attr("send")(batch_size); + generators_[word].attr("send")(batch_size); + + SPDLOG_INFO("[{}] (Python side) successfully obtained data batch for " + "word `{}`. Trying to " + "serialize it to JSON", + name(), + word); + boost::python::object py_json_res = py_json_dumps(py_res); + SPDLOG_INFO("[{}] (Python side) successfully serialized data batch for " + "word `{}` to JSON", + name(), + word); + std::string str_res = boost::python::extract(py_json_res); nlohmann::json json_res = nlohmann::json::parse(str_res); try { + SPDLOG_INFO( + "[{}] (Server side) Trying to deserialize JSON data batch " + "for word `{}`", + name(), + word); + auto audio_information = json_res[0].get>(); auto error_message = json_res[1].get(); + + SPDLOG_INFO( + "[{}] (Server side) successfully deserialized JSON data batch " + "for word `{}`", + name(), + word); + return std::make_pair(audio_information, error_message); } catch (const std::exception &error) { return error.what(); } } catch (boost::python::error_already_set &) { + SPDLOG_INFO("[{}] caught Python exception during response construction " + "for word `{}`. Destroying corresponding Python generator", + name(), + word); + + generators_.erase(word); auto py_exc_info = PyExceptionInfo::build().value(); const auto &exception_type = py_exc_info.last_type(); if (exception_type == "") { + SPDLOG_INFO("[{}] caught Python StopIteration exception during " + "response construction " + "for word `{}`. Respoding with empty object", + name(), + word); + return {}; } + return py_exc_info; } std::vector empty(0); diff --git a/server/lib/plugins/wrappers/actual/AudiosProviderWrapper/AudiosProviderWrapper.hpp b/server/lib/plugins/wrappers/actual/AudiosProviderWrapper/AudiosProviderWrapper.hpp index fd82dc3a901d0299dda58b97ae5c5093d4c119e2..94c45b6b15c3b1dfc97ec7afbeb08e55325c954b 100644 --- a/server/lib/plugins/wrappers/actual/AudiosProviderWrapper/AudiosProviderWrapper.hpp +++ b/server/lib/plugins/wrappers/actual/AudiosProviderWrapper/AudiosProviderWrapper.hpp @@ -45,8 +45,7 @@ class AudiosProviderWrapper : public BasePluginWrapper, private: explicit AudiosProviderWrapper(BasePluginWrapper &&base); - std::unordered_map> - generators_; + std::unordered_map generators_; }; static_assert(is_plugin_wrapper); diff --git a/server/lib/plugins/wrappers/actual/DefinitionsProviderWrapper/DefinitionsProviderWrapper.cpp b/server/lib/plugins/wrappers/actual/DefinitionsProviderWrapper/DefinitionsProviderWrapper.cpp index e8122a3876e2a5b3c03aa10331de94957abe8559..37a8438414b44e3c076ddd6e1608cfe59474e82b 100644 --- a/server/lib/plugins/wrappers/actual/DefinitionsProviderWrapper/DefinitionsProviderWrapper.cpp +++ b/server/lib/plugins/wrappers/actual/DefinitionsProviderWrapper/DefinitionsProviderWrapper.cpp @@ -2,6 +2,7 @@ #include "PyExceptionInfo.hpp" #include "pyerrors.h" #include "pythonrun.h" +#include "spdlog/spdlog.h" #include #include #include @@ -35,10 +36,12 @@ DefinitionsProviderWrapper::DefinitionsProviderWrapper( auto DefinitionsProviderWrapper::build(const std::string &name, const boost::python::object &module) -> std::variant { + SPDLOG_INFO("Trying to build " + name + " definition provider"); auto base_or_error = BasePluginWrapper::build(name, module); if (std::holds_alternative(base_or_error)) { return std::get(base_or_error); } + SPDLOG_INFO("Trying to build " + name + " definition provider"); auto base = std::move(std::get(base_or_error)); auto specifics_or_error = DefinitionsProvidersFunctions::build(module); @@ -58,49 +61,115 @@ auto DefinitionsProviderWrapper::get(const std::string &word, uint64_t batch_size, bool restart) -> std:: variant { + SPDLOG_INFO( + "[{}] Handling request: word: `{}`, batch_size: `{}`, restart: `{}`", + name(), + word, + batch_size, + restart); + if (restart) { auto found_item = generators_.find(word); if (found_item != generators_.end()) { + SPDLOG_INFO( + "[{}] Restarting generator for word `{}`", name(), word); + generators_.erase(found_item); + } else { + SPDLOG_WARN("[{}] restart request was given but no generator for " + "word `{}` was found", + name(), + word); } } if (generators_.find(word) == generators_.end()) { + SPDLOG_INFO("[{}] Initializing generator for word `{}`", name(), word); + + boost::python::object generator; try { - boost::python::object test = specifics_.get(word); - generators_[word] = test; - generators_[word]->attr("__next__")(); + generator = specifics_.get(word); + generator.attr("__next__")(); } catch (const boost::python::error_already_set &) { - generators_.erase(generators_.find(word)); return PyExceptionInfo::build().value(); } + generators_[word] = generator; } try { + SPDLOG_INFO("[{}] (Python side) Loading JSON module", name()); + boost::python::object py_json = boost::python::import("json"); boost::python::object py_json_dumps = py_json.attr("dumps"); + SPDLOG_INFO( + "[{}] (Python side) Trying to obtain data batch for word `{}`", + name(), + word); + boost::python::object py_res = - generators_[word]->attr("send")(batch_size); + generators_[word].attr("send")(batch_size); + + SPDLOG_INFO("[{}] (Python side) successfully obtained data batch for " + "word `{}`. Trying to " + "serialize it to JSON", + name(), + word); + boost::python::object py_json_res = py_json_dumps(py_res); + SPDLOG_INFO("[{}] (Python side) successfully serialized data batch for " + "word `{}` to JSON", + name(), + word); + std::string str_res = boost::python::extract(py_json_res); nlohmann::json json_res = nlohmann::json::parse(str_res); try { + SPDLOG_INFO( + "[{}] (Server side) Trying to deserialize JSON data batch " + "for word `{}`", + name(), + word); + auto error_message = json_res[1].get(); auto cards = json_res[0].get>(); - // TODO: ЗДЕСЬ БУДЕТ ФИЛЬТР ПО ЗАПРОСУ + + SPDLOG_INFO( + "[{}] (Server side) successfully deserialized JSON data batch " + "for word `{}`", + name(), + word); + + // TODO(QUERY LANGUAGE): ЗДЕСЬ БУДЕТ ФИЛЬТР ПО ЗАПРОСУ return std::make_pair(cards, error_message); } catch (const std::exception &error) { return error.what(); } } catch (boost::python::error_already_set &) { + SPDLOG_INFO("[{}] caught Python exception during response construction " + "for word `{}`. Destroying corresponding Python generator", + name(), + word); + auto py_exc_info = PyExceptionInfo::build().value(); const auto &exception_type = py_exc_info.last_type(); + generators_.erase(word); if (exception_type == "") { + SPDLOG_INFO("[{}] caught Python StopIteration exception during " + "response construction " + "for word `{}`. Respoding with empty object", + name(), + word); return {}; } + + // SPDLOG_ERROR("[{}] caught Python exception of type: {} during " + // "response construction " + // "for word `{}`. Forwarding exception info to the + // caller", name(), py_exc_info.last_type(), word); + return py_exc_info; } std::vector empty(0); diff --git a/server/lib/plugins/wrappers/actual/DefinitionsProviderWrapper/DefinitionsProviderWrapper.hpp b/server/lib/plugins/wrappers/actual/DefinitionsProviderWrapper/DefinitionsProviderWrapper.hpp index a1d0b2a946420d5fa1446eb907c4708a6a8686c9..98a3195ffefc24325c1917f59b06f2ddc512cb2b 100644 --- a/server/lib/plugins/wrappers/actual/DefinitionsProviderWrapper/DefinitionsProviderWrapper.hpp +++ b/server/lib/plugins/wrappers/actual/DefinitionsProviderWrapper/DefinitionsProviderWrapper.hpp @@ -52,8 +52,7 @@ class DefinitionsProviderWrapper : public IDefinitionsProviderWrapper, private: explicit DefinitionsProviderWrapper(BasePluginWrapper &&base); - std::unordered_map> - generators_; + std::unordered_map generators_; }; static_assert(is_plugin_wrapper); diff --git a/server/lib/plugins/wrappers/actual/ImagesProviderWrapper/ImagesProviderWrapper.cpp b/server/lib/plugins/wrappers/actual/ImagesProviderWrapper/ImagesProviderWrapper.cpp index 88e910538f09bccffc23cf9e52639128fa649efe..d052b16b21cf651b3b4a4c400b13b30a2625a140 100644 --- a/server/lib/plugins/wrappers/actual/ImagesProviderWrapper/ImagesProviderWrapper.cpp +++ b/server/lib/plugins/wrappers/actual/ImagesProviderWrapper/ImagesProviderWrapper.cpp @@ -1,6 +1,8 @@ #include "ImagesProviderWrapper.hpp" +#include "spdlog/spdlog.h" #include #include +#include auto ImagesProviderWrapper::ImagesProvidersFunctions::build( const boost::python::object &module) @@ -43,7 +45,113 @@ auto ImagesProviderWrapper::build(const std::string &name, return wrapper; } -auto ImagesProviderWrapper::get(const std::string &word, uint64_t batch_size) - -> std::variant { - return {}; +auto ImagesProviderWrapper::get(const std::string &word, + uint64_t batch_size, + bool restart) + -> std::variant { + SPDLOG_INFO( + "[{}] Handling request: word: `{}`, batch_size: `{}`, restart: `{}`", + name(), + word, + batch_size, + restart); + + if (restart) { + auto found_item = generators_.find(word); + if (found_item != generators_.end()) { + + SPDLOG_INFO( + "[{}] Restarting generator for word `{}`", name(), word); + + generators_.erase(found_item); + } else { + SPDLOG_WARN("[{}] restart request was given but no generator for " + "word `{}` was found", + name(), + word); + } + } + if (generators_.find(word) == generators_.end()) { + SPDLOG_INFO("[{}] Initializing generator for word `{}`", name(), word); + + boost::python::object generator; + try { + generator = specifics_.get(word); + generator.attr("__next__")(); + } catch (const boost::python::error_already_set &) { + return PyExceptionInfo::build().value(); + } + generators_[word] = generator; + } + try { + SPDLOG_INFO("[{}] (Python side) Loading JSON module", name()); + + boost::python::object py_json = boost::python::import("json"); + boost::python::object py_json_dumps = py_json.attr("dumps"); + + SPDLOG_INFO( + "[{}] (Python side) Trying to obtain data batch for word `{}`", + name(), + word); + + boost::python::object py_res = + generators_[word].attr("send")(batch_size); + + SPDLOG_INFO("[{}] (Python side) successfully obtained data batch for " + "word `{}`. Trying to " + "serialize it to JSON", + name(), + word); + + boost::python::object py_json_res = py_json_dumps(py_res); + + SPDLOG_INFO("[{}] (Python side) successfully serialized data batch for " + "word `{}` to JSON", + name(), + word); + + std::string str_res = boost::python::extract(py_json_res); + nlohmann::json json_res = nlohmann::json::parse(str_res); + + try { + SPDLOG_INFO( + "[{}] (Server side) Trying to deserialize JSON data batch " + "for word `{}`", + name(), + word); + + auto images_urls = json_res[0].get>(); + auto error_message = json_res[1].get(); + + SPDLOG_INFO( + "[{}] (Server side) successfully deserialized JSON data batch " + "for word `{}`", + name(), + word); + return std::make_pair(images_urls, error_message); + } catch (const std::exception &error) { + return error.what(); + } + } catch (boost::python::error_already_set &) { + SPDLOG_INFO("[{}] caught Python exception during response construction " + "for word `{}`. Destroying corresponding Python generator", + name(), + word); + + auto py_exc_info = PyExceptionInfo::build().value(); + const auto &exception_type = py_exc_info.last_type(); + + generators_.erase(word); + if (exception_type == "") { + SPDLOG_INFO("[{}] caught Python StopIteration exception during " + "response construction " + "for word `{}`. Respoding with empty object", + name(), + word); + return {}; + } + return py_exc_info; + } + std::vector empty(0); + return std::make_pair(empty, ""); } diff --git a/server/lib/plugins/wrappers/actual/ImagesProviderWrapper/ImagesProviderWrapper.hpp b/server/lib/plugins/wrappers/actual/ImagesProviderWrapper/ImagesProviderWrapper.hpp index 003340c8bde2e712d9e902c93e645c3b8398104b..2acda47db5824c6e9664dcfe634ebdb06d177ce7 100644 --- a/server/lib/plugins/wrappers/actual/ImagesProviderWrapper/ImagesProviderWrapper.hpp +++ b/server/lib/plugins/wrappers/actual/ImagesProviderWrapper/ImagesProviderWrapper.hpp @@ -25,8 +25,10 @@ class ImagesProviderWrapper : public IImagesProviderWrapper, const boost::python::object &module) -> std::variant; - auto get(const std::string &word, uint64_t batch_size) - -> std::variant override; + auto get(const std::string &word, uint64_t batch_size, bool restart) + -> std::variant override; protected: struct ImagesProvidersFunctions { @@ -40,6 +42,8 @@ class ImagesProviderWrapper : public IImagesProviderWrapper, private: explicit ImagesProviderWrapper(BasePluginWrapper &&base); + + std::unordered_map generators_; }; static_assert(is_plugin_wrapper); diff --git a/server/lib/plugins/wrappers/actual/SentencesProviderWrapper/SentencesProviderWrapper.cpp b/server/lib/plugins/wrappers/actual/SentencesProviderWrapper/SentencesProviderWrapper.cpp index 3b11fdd7b909b85cea8ad258a5765d4d67c26e83..9c9845dec37c3620cb8260c9793600643abf5c7d 100644 --- a/server/lib/plugins/wrappers/actual/SentencesProviderWrapper/SentencesProviderWrapper.cpp +++ b/server/lib/plugins/wrappers/actual/SentencesProviderWrapper/SentencesProviderWrapper.cpp @@ -1,5 +1,6 @@ #include "SentencesProviderWrapper.hpp" #include "BasePluginWrapper.hpp" +#include "spdlog/spdlog.h" #include #include @@ -25,9 +26,115 @@ SentencesProviderWrapper::SentencesProviderWrapper( specifics_(other.specifics_) { } -auto SentencesProviderWrapper::get(const std::string &word, uint64_t batch_size) - -> std::variant { - return {}; +auto SentencesProviderWrapper::get(const std::string &word, + uint64_t batch_size, + bool restart) -> std:: + variant { + SPDLOG_INFO( + "[{}] Handling request: word: `{}`, batch_size: `{}`, restart: `{}`", + name(), + word, + batch_size, + restart); + + if (restart) { + auto found_item = generators_.find(word); + if (found_item != generators_.end()) { + SPDLOG_INFO( + "[{}] Restarting generator for word `{}`", name(), word); + + generators_.erase(found_item); + } else { + SPDLOG_WARN("[{}] restart request was given but no generator for " + "word `{}` was found", + name(), + word); + } + } + if (generators_.find(word) == generators_.end()) { + SPDLOG_INFO("[{}] Initializing generator for word `{}`", name(), word); + + boost::python::object generator; + try { + generator = specifics_.get(word); + generator.attr("__next__")(); + } catch (const boost::python::error_already_set &) { + return PyExceptionInfo::build().value(); + } + generators_[word] = generator; + } + try { + SPDLOG_INFO("[{}] (Python side) Loading JSON module", name()); + + boost::python::object py_json = boost::python::import("json"); + boost::python::object py_json_dumps = py_json.attr("dumps"); + + SPDLOG_INFO( + "[{}] (Python side) Trying to obtain data batch for word `{}`", + name(), + word); + + boost::python::object py_res = + generators_[word].attr("send")(batch_size); + + SPDLOG_INFO("[{}] (Python side) successfully obtained data batch for " + "word `{}`. Trying to " + "serialize it to JSON", + name(), + word); + + boost::python::object py_json_res = py_json_dumps(py_res); + + SPDLOG_INFO("[{}] (Python side) successfully serialized data batch for " + "word `{}` to JSON", + name(), + word); + + std::string str_res = boost::python::extract(py_json_res); + nlohmann::json json_res = nlohmann::json::parse(str_res); + + try { + SPDLOG_INFO( + "[{}] (Server side) Trying to deserialize JSON data batch " + "for word `{}`", + name(), + word); + + auto sentences = json_res[0].get>(); + auto error_message = json_res[1].get(); + + SPDLOG_INFO( + "[{}] (Server side) successfully deserialized JSON data batch " + "for word `{}`", + name(), + word); + + return std::make_pair(sentences, error_message); + } catch (const std::exception &error) { + return error.what(); + } + } catch (boost::python::error_already_set &) { + SPDLOG_INFO("[{}] caught Python exception during response construction " + "for word `{}`. Destroying corresponding Python generator", + name(), + word); + + auto py_exc_info = PyExceptionInfo::build().value(); + const auto &exception_type = py_exc_info.last_type(); + + generators_.erase(word); + if (exception_type == "") { + SPDLOG_INFO("[{}] caught Python StopIteration exception during " + "response construction " + "for word `{}`. Respoding with empty object", + name(), + word); + return {}; + } + return py_exc_info; + } + std::vector empty(0); + return std::make_pair(empty, ""); } auto SentencesProviderWrapper::build(const std::string &name, diff --git a/server/lib/plugins/wrappers/actual/SentencesProviderWrapper/SentencesProviderWrapper.hpp b/server/lib/plugins/wrappers/actual/SentencesProviderWrapper/SentencesProviderWrapper.hpp index bf7f71081ff7bd7443757ef538a8466259a0acc0..0006078b44ae8a81dc6b03de63d4ec0d7e35954c 100644 --- a/server/lib/plugins/wrappers/actual/SentencesProviderWrapper/SentencesProviderWrapper.hpp +++ b/server/lib/plugins/wrappers/actual/SentencesProviderWrapper/SentencesProviderWrapper.hpp @@ -27,8 +27,10 @@ class SentencesProviderWrapper : public BasePluginWrapper, const boost::python::object &module) -> std::variant; - auto get(const std::string &word, uint64_t batch_size) - -> std::variant; + auto get(const std::string &word, uint64_t batch_size, bool restart) + -> std::variant; protected: struct SentencesProvidersFunctions { @@ -42,6 +44,8 @@ class SentencesProviderWrapper : public BasePluginWrapper, private: explicit SentencesProviderWrapper(BasePluginWrapper &&base); + + std::unordered_map generators_; }; static_assert(is_plugin_wrapper); diff --git a/server/lib/plugins/wrappers/interfaces/IAudiosProviderWrapper/IAudiosProviderWrapper.hpp b/server/lib/plugins/wrappers/interfaces/IAudiosProviderWrapper/IAudiosProviderWrapper.hpp index 68fe801c0a95c228a76eba181543eda2d8a83feb..197d78c9fd6d997763f985acc42d0f73f7721055 100644 --- a/server/lib/plugins/wrappers/interfaces/IAudiosProviderWrapper/IAudiosProviderWrapper.hpp +++ b/server/lib/plugins/wrappers/interfaces/IAudiosProviderWrapper/IAudiosProviderWrapper.hpp @@ -18,6 +18,10 @@ inline void from_json(const nlohmann::json &json_arr, AudioInfo &info) { json_arr.at(1).get_to(info.additional_info); } +inline void to_json(nlohmann::json &json_arr, const AudioInfo &info) { + json_arr = {info.audio, info.additional_info}; +} + class IAudiosProviderWrapper : public virtual IPluginWrapper { public: using type = std::pair, std::string>; diff --git a/server/lib/plugins/wrappers/interfaces/IImagesProviderWrapper/IImagesProviderWrapper.hpp b/server/lib/plugins/wrappers/interfaces/IImagesProviderWrapper/IImagesProviderWrapper.hpp index 8ec38f80c65890b5be5fc6340a048270555ec030..289d1e494214b6868cec43566f52b8abf6ff0947 100644 --- a/server/lib/plugins/wrappers/interfaces/IImagesProviderWrapper/IImagesProviderWrapper.hpp +++ b/server/lib/plugins/wrappers/interfaces/IImagesProviderWrapper/IImagesProviderWrapper.hpp @@ -11,8 +11,8 @@ class IImagesProviderWrapper : public virtual IPluginWrapper { public: using type = std::pair, std::string>; - virtual auto get(const std::string &word, uint64_t batch_size) - -> std::variant = 0; + virtual auto get(const std::string &word, uint64_t batch_size, bool restart) + -> std::variant = 0; }; #endif // !I_AUDIOS_PROVIDER_WRAPPER diff --git a/server/lib/plugins/wrappers/interfaces/ISentencesProviderWrapper/ISentencesProviderWrapper.hpp b/server/lib/plugins/wrappers/interfaces/ISentencesProviderWrapper/ISentencesProviderWrapper.hpp index ed6cd27b1be21cf8dceeda66ab933038d9738a2f..642e2a71c2f5dce70bae7a7b7287fdc3d0b7a590 100644 --- a/server/lib/plugins/wrappers/interfaces/ISentencesProviderWrapper/ISentencesProviderWrapper.hpp +++ b/server/lib/plugins/wrappers/interfaces/ISentencesProviderWrapper/ISentencesProviderWrapper.hpp @@ -11,8 +11,10 @@ class ISentencesProviderWrapper : public virtual IPluginWrapper { public: using type = std::pair, std::string>; - virtual auto get(const std::string &word, uint64_t batch_size) - -> std::variant = 0; + virtual auto get(const std::string &word, uint64_t batch_size, bool restart) + -> std::variant = 0; }; #endif // !I_AUDIOS_PROVIDER_WRAPPER diff --git a/server/main.cpp b/server/main.cpp index 65b2d8a2c1c53edcec179e714c5bc8b07c4e9aaa..ff72cdd74c791f24177f428a383c906d04b620df 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -1,3 +1,11 @@ +// https://github.com/gabime/spdlog/issues/1515 +#include "spdlog/common.h" +#define SPDLOG_ACTIVE_LEVEL \ + SPDLOG_LEVEL_TRACE // Must: define SPDLOG_ACTIVE_LEVEL before `#include + // "spdlog/spdlog.h"` +#include "spdlog/sinks/stdout_sinks.h" +#include "spdlog/spdlog.h" + #include "DefinitionsProviderWrapper.hpp" #include "FormatProcessorWrapper.hpp" #include "PluginsProvider.hpp" @@ -8,6 +16,9 @@ #include auto main(int argc, char *argv[]) -> int { + // https://github.com/gabime/spdlog/wiki/3.-Custom-formatting + spdlog::set_pattern("[%H:%M:%S] [%s] line %# %v"); + Py_Initialize(); auto plugins_dirs = PluginTypesLocationsConfig{ .definitions_providers_dir = diff --git a/test_client/sender.cpp b/test_client/sender.cpp index f3d0adfbc390ad8019c1f81e410d5dab6d565be4..18b2981f1545d2484e51bbf3b6483f4a22a95448 100644 --- a/test_client/sender.cpp +++ b/test_client/sender.cpp @@ -12,9 +12,34 @@ #include #include #include +#include +#include using boost::asio::ip::tcp; +void request(tcp::socket &socket, const std::string &json_request) { + boost::array buf = {}; + strncpy(buf.data(), json_request.c_str(), json_request.size()); + + boost::system::error_code error; + + size_t len = + socket.write_some(boost::asio::buffer(buf, strlen(buf.data())), error); + size_t len2 = socket.read_some(boost::asio::buffer(buf), error); + + auto parsed_response = nlohmann::json::parse(buf.data(), buf.data() + len2); + + std::cout << "=======================================" << std::endl; + std::cout << parsed_response.dump(2) << std::endl; + + if (error == boost::asio::error::eof) { + return; + } + if (error) { + throw boost::system::system_error(error); // Some other error. + } +} + int main(int argc, char *argv[]) { try { // if (argc != 2) { @@ -30,83 +55,101 @@ int main(int argc, char *argv[]) { boost::asio::ip::tcp::socket socket(ios); socket.connect(endpoint); - for (auto i = 0; i < 1; ++i) { - { - boost::array buf = { - "{\"query_type\": \"init\", \"plugin_type\": \"word\", " - "\"plugin_name\": \"definitions\"}\r\n"}; - boost::system::error_code error; - - // std::cout.write(buf.data(), 4); - - size_t len = socket.write_some( - boost::asio::buffer(buf, strlen(buf.data())), error); - size_t len2 = socket.read_some(boost::asio::buffer(buf), error); - std::cout.write(buf.data(), strlen(buf.data())) << std::endl; - - if (error == boost::asio::error::eof) - break; // Connection closed cleanly by peer. - else if (error) - throw boost::system::system_error( - error); // Some other error. - } - { - boost::array buf = { - R"( + + // DEFINITIONS + request(socket, + R"( + { + "query_type": "init", + "plugin_name": "definitions", + "plugin_type": "word" + })" + "\r\n"); + request(socket, + R"( { "query_type": "get", "plugin_type": "word", "filter": "", - "word": "definitions", + "word": "go", "batch_size": 5, - "restart": true + "restart": false })" - "\r\n"}; - boost::system::error_code error; - - // std::cout.write(buf.data(), 4); - - size_t len = socket.write_some( - boost::asio::buffer(buf, strlen(buf.data())), error); - size_t len2 = socket.read_some(boost::asio::buffer(buf), error); - std::cout.write(buf.data(), strlen(buf.data())) << std::endl; - - if (error == boost::asio::error::eof) - break; // Connection closed cleanly by peer. - else if (error) - throw boost::system::system_error( - error); // Some other error. - } - { - boost::array buf = { - R"( + "\r\n"); + // SENTENCES + request(socket, + R"( + { + "query_type": "init", + "plugin_name": "sentences", + "plugin_type": "sentences" + })" + "\r\n"); + request(socket, + R"( + { + "query_type": "get", + "plugin_type": "sentences", + "word": "go", + "batch_size": 5, + "restart": false + })" + "\r\n"); + // AUDIOS + request(socket, + R"( + { + "query_type": "init", + "plugin_name": "audios", + "plugin_type": "audios" + })" + "\r\n"); + request(socket, + R"( + { + "query_type": "get", + "plugin_type": "audios", + "word": "go", + "batch_size": 5, + "restart": false + })" + "\r\n"); + // IMAGES + request(socket, + R"( + { + "query_type": "init", + "plugin_name": "images", + "plugin_type": "images" + })" + "\r\n"); + request(socket, + R"( + { + "query_type": "get", + "plugin_type": "images", + "word": "go", + "batch_size": 5, + "restart": false + })" + "\r\n"); + + // DEFINITIONS + request(socket, + R"( { "query_type": "get", "plugin_type": "word", "filter": "", - "word": "definitions", + "word": "go", "batch_size": 5, "restart": false })" - "\r\n"}; - boost::system::error_code error; - - // std::cout.write(buf.data(), 4); - - size_t len = socket.write_some( - boost::asio::buffer(buf, strlen(buf.data())), error); - size_t len2 = socket.read_some(boost::asio::buffer(buf), error); - std::cout.write(buf.data(), strlen(buf.data())) << std::endl; - - if (error == boost::asio::error::eof) - break; // Connection closed cleanly by peer. - else if (error) - throw boost::system::system_error( - error); // Some other error. - } - } + "\r\n"); + } catch (std::exception &e) { std::cerr << e.what() << std::endl; } + return 0; }