Code Monkey home page Code Monkey logo

c-core's People

Contributors

anovikov1984 avatar chriskush avatar crimsonred avatar macgritsch avatar marcgeh avatar maxpresman avatar rmadair avatar samiahmedsiddiqui avatar sjaeckel avatar sveljko avatar vveljko avatar walterbrebels avatar

Watchers

 avatar  avatar  avatar

Forkers

petar-saric

c-core's Issues

УРЛ енкодирање канала

Иако у називу канала не може да буде "све и свашта" (https://support.pubnub.com/support/solutions/articles/14000043769-what-are-valid-channel-names-), ипак, могу да "залете" знакови који треба да се УРЛ енкодирају. Постоје два проблема:

  1. Ми и не проверавамо да ли је име канала "ваљано" (у смислу Пубнуб захтева).
  2. Не радимо УРЛ енкодирање, тако да неко име канала које садржи "тужне знакове" може да "упропасти" УРЛ и да због тога трансакција "падне".

У склопу ове бубе, хоћемо да направимо да се канал УРЛ енкодира. Провера ваљаности имена канала није у склопу ове бубе.

Ово није урађено раније зато што је незгодација. УРЛ углавном направимо са једним снпринтф(), а који нема %УРЛс или тако нешто.

Могуће "путање" извођења:

  1. Направити "оно у УРЛ пре канала" путем спринтф, а онда додати канал УРЛ енкодиран, па онда и оно остало (да ли са још једним снпринтф, или "ручно"). Ово би унело много измена у коду, што би значило могућност за много нових буба и направило код који је непрегледнији - тежи за одржавање.
  2. УРЛ енкодирати у помоћни низ знакова, па онда то проследити снпринтф()-у, уместо канала "какав је примљен".

Пошто је назив канала ограничен на 92 знака и пошто УРЛ енкодирање увек прави 3 знака од једног (осим, наравно, за не-АСЦИИ знаке, али, ми их и тако не подржавамо, па нема везе :) ), онда би могли да направимо помоћни локални низ од 297 знакова (1 за НУЛ знак) и да "будемо мирни". Е, сад, за неки микроконтролер попут АВР, који има 2К РАМ-а укупно, то је бесмислено много. Стога, "колики је највећи УРЛ енкодирани канал" постављамо као један од конфигурационих параметара (за пубнуб_цонфиг.х). Ако УРЛ енкодирани назив канал не може да "стане" у толики помоћни низ, пријавимо нову грешку ПНР_УРЛ_ЕНЦОДЕД_ЦХАННЕЛ_ТОО_ЛОНГ, којом пригодом пријавимо, са ПУБНУБ_ЛОГ_ЕРРОР, који је то канал, колики је тренутно ПУБНУБ_МАЏ_УРЛ_ЕНЦОДЕД_ЦХАННЕЛ и, ако знамо, а колики би требало да буде (и како би изгледао УРЛ енкодиран назив канала).

Такође, проверавамо и да ли је ПУБНУБ_МАЏ_УРЛ_ЕНЦОДЕД_ЦХАННЕЛ смислен - можда и не мора да буде већи од 91 знака, али свакако мора да буде већи од 10 и нема смисла да буде већи од 296. Ако је ван тих граница, пријавити грешку у току превођења. Очигледно, за Њиндоњс и ПОСИЏ, ПУБНУБ_МАЏ_УРЛ_ЕНЦОДЕД_ЦХАННЕЛ ће да буде 296.

Узгред буди речено, овако ћемо, "на мала врата", да уведемо бар проверy дужине имена канала, односно бар нешто од провере ваљаности имена канала.

Подршка за секундарни ДНС опслуживач

Тренутно, наш ДНС модул подржава само један ДНС опслуживач ("примарни"), иако је предвиђена спрега за постављање секундарног. Е, па, да ми подржимо секундарни:

  1. Ако примарни није задат, а секундарни јесте, пробати са секундарним
  2. Ако примарни јесте задат а и секундарни јесте задат, онда, ако примарни не одговори, или, ако се у одговору не нађе адреса Пубнуб опслуживача који тражимо (из ма ког разлога), онда пробати секундарни.
  3. Подразумевани секундарни ДНС опслуживач не постоји (примарни је Гуглов 8.8.8.8)

Направити тестове модула за ову сврху. Нема потребе за функционалним тестовима или примерима за корисника. Подршка треба да се дода и у Ц++ "омотачу".

Читање бројача непрочитаних порука

Ово је "потпуно нови" РЕСТ АПИ који пружа Пубнуб. Део је "историје в3 (#36)", само што, уместо да врати садржај порука из историје, враћа бројаче непрочитаних порука за дате канале.

Званично име ове трансакције је messages_count.

Путања за РЕСТ је:

/v3/history/sub-key/{SUBKEY}/channels-with-messages/{CHANNEL(S)}

Са уобичајеним значењима - SUBKEY претплатни кључ и CHANNEL(S) списак канала за које се траже подаци.

Од параметара, сем уобичајених УУИД и "аутх", имамо два само за ове потребе, при чему су искључиви (или један или други):

  • timetoken: од кога се узимају бројачи непрочитаних порука за све канале
  • channelTimetokens: списак (листа), која мора да има исти број чланова као и списак канала и где сваки токен означава од када се читају бројачи непрочитаних порука за дати канал

Није јасно да ли је обавезно да постоји један од њих, личи да је сасвим у реду да нема ниједног (у ком случају се узима, претпостављам, цела историја). Дакле, за почетак, прихватити да могу да буду оба НУЛЛ, али да не могу оба да буду не-НУЛЛ.

Дакле, спрега је отприлике:

enum pubnub_res pubnub_message_counts(
    pubnub_t* pbp, char const* channel, 
    char const* timetoken, 
    char const* channel_timetokens);

Ова функција врши следеће провере:

  1. да ли је тиметокен ваљан: ради "универзалности", само проверити да ли је ниска таква да не мора да се УРЛ енкодира (односно, грешка је ако мора)
  2. да ли је channel_timetokens ваљан: слично као тиметокен
  3. да ли је број "чланова" цханнел и channel_timetokens исти (односно, да ли је број зареза у ове две ниске исти)

Да не би претрпавали ПНР...., уводимо (само) ПНР_ИНВАЛИД_ПАРАМЕТЕРС и онда посебан енум пубнуб_параметер_еррор, где ћемо да трпамо нове симболе по потреби (за ову функцију, три комада).

Опционо, можемо да проверимо и

  • да ли су имена канала ваљана
  • да ли су токени довољно дугачки (пре свега да нису празни, али можемо да ставимо и неку разумну границу од, рецимо, 4 знака - како год да променимо начин записа токена, тешко да ће бити мање од 4 знака)

Одговор је мање-више уобичајени ЈСОН објекат:

{"status":200, "error": false, "error_message": "", "channels": {"some":1,"other":5}}

Очигледно, нас занима да ли је у питању грешка (да ли је кључ еррор == труе) - ако јесте, ваља пријавити нови ПНР_ЕРРОР_ОН_СЕРВЕР, и омогућити кориснику да прочита еррор_мессаге. Овај исти ПНР_ЕРРОР_ОН_СЕРВЕР ћемо да злоупотребљавамо за све случајеве када нам стиже овакав мање-више уобичајени ЈСОН објекат - сем за "ченел реџистри", пошто исти већ има посебан код грешке.

Ако грешке нема, треба омогућити кориснику да прочита колико има канала у одговору и да прочита протумачен одговор, који треба да стоји у низу следећих слогова:

struct pubnub_chan_msg_count {
    pubnub_chamebl_t channel;
    size_t message_count;
};

Спрега је отприлике оваква:

/** овог можемо да "пустимо да ради" за било који одговор - ако је ЈСОН објекат */
int pubnub_get_error_message(pubnub_t* ctx, pubnub_chamebl_t* o_msg);

/** ако није исправна порука/одговор, вратиће -1, иначе број  чланова ЈСОН
      објекта `channels` */
int pubnub_get_chan_msg_counts_size(pubnub_t* ctx);

/** на улазу, `io_count` је број заузетих "бројача по каналу" (димензија низа
      `chan_msg_counters`, на излазу, број "уписаних"  у тај низ (колико их стварно
      има у одговору). Уколико их има више него што је заузето ("не могу да стану"),
      то не сматрамо грешком, али, можемо да пријавимо у лог (ниво "дебуг").
      Број Отписаних не враћамо, сви знамо да је 4 (Прле, Тихи, Јоца и Мрки).
 */
int pubnub_get_chan_msg_counts(
    pubnub_t* ctx, 
    size_t* io_count, 
    struct pubnub_chan_msg_count* chan_msg_counters);

Није јасно да ли ће за канале на којима нема "непрочитаних" порука бити враћено 0, или их просто неће бити у објекту, нити да ли ће редослед у одговору бити као у упиту, па је ова спрега "уопштена". За оне којима одговара, имамо и следећу једноставнију спрегу:

/** Димензија `о_цоунт` је број канала из `цханнел` 
      (практично, 1 + број зареза у `цханнел` ) и то мора да заузме позивалац.
      Редослед у `о_цоунт` је као у `цханнел`, иако у одговору можда и
      није тако, а ако канала нема у одговору, уписује се "нешто мање од 0". 
      Ако канала има у одговору, а нема у `цханнел`, то не сматрамо за
      грешку, али, можемо да забележимо у лог (ниво "дебуг").
  */
int pubnub_get_message_counts(pubnub_t* ctx, char const*channel, int* o_count);

Ово све додати у модул адванцед_хистору (као и #36). Очигледно, шта се прво прави, оно ће да "направи" овај модул, а остали ће да се убаце у (тада) већ постојећи.

За Ц++, спрега је једноставнија (а богатија):

futres message_counts(std::string channel, std::string timetoken);
futres message_counts(std::vector<std::string> channel, std::string timetoken);
futres message_counts(std::string channel, std::vector<std::string> channel_timetokens);
futres message_counts(std::vector<std::string> channel, std::vector<std::string> channel_timetokens);
futres message_counts(std::vector<std::pair<std::string, std::string>> channel_timetokens);
std::map<std::string, size_t> get_channel_message_counts();

За Љт, слично:

pubnub_res message_counts(QString channel, QString timetoken);
pubnub_res message_counts(QStringList channel, QString timetoken);
pubnub_res message_counts(QString channel, QString channel_timetoken);
pubnub_res message_counts(QString channel, QStringList channel_timetoken);
pubnub_res message_counts(QStringList channel, QStringList channel_timetoken);
QMap<QString, size_t> get_channel_message_counts();

Ово је нова врста транскације: "PBTT_MESSAGE_COUNTS".

Треба нам тест модула који покрива бар 90% редова кода.

Што се функционалног теста тиче, ово засад не постоји уопште, па нема шта да се проба, па га тренутно не правимо. По потреби ће бити додато касније.

Додати нови "пубнуб_адванцед_хистору_сампле", који за ову намену има пример попут: претплатити се на неколико канала, покупити токене, онда објавити нешто на њима (на једном једну поруку, на другом две, на трећем пет... а на неком ниједну), онда "прочитати" бројаче непрочитаних порука и уверити се да су исправни. Додати за Ц, Ц++ и Љт - у исти ће се трпати све "в3 историје".

Условно превођење retry_after_close

Тренутно се ретру_афтер_цлосе увек преводи, иако се користи само ако имамо ХТТП посредника или ако користимо ТЛС/ССЛ. Оба су #дефине, тако да могу да се искључе, па треба да се ретру_афтер_цлосе такође може да искључи.

Управо, чини се најсимпатичне направити нешто попут:

#define PUBNUB_NEED_RETRY_AFTER_CLOSE (PUBNUB_USE_PROXY || PUBNUB_USE_TLS)

и онда сав ретру_афтер_цлосе код ставити "под" #иф ПУБНУБ_НЕЕД_РЕТРУ_АФТЕР_ЦЛОСЕ

Тест модула за ДНС

Треба направити тест модула за ДНС, са нагласком на декодирање, где је управо била једна буба (и отклоњена). Треба истестирати 100% редова и грана (требало би да је могуће). Треба направити један тест изричито за бубу која је отклоњена.

Пошто ДНС модул користи сокете "непосредно", што може да буде напорно, издвојити функције за кодирање и декодирање у (нови) засебан модул, па их користити из постојећег. Онда тест направити за тај нови модул, а овај који користи сокете оставити "нетестиран" (до даљњег).

Нови модул ставити у /либ, пошто неће имати везе са сокетима. Постојећи пбпал_аднс_соцкетс оставити у /либ/соцкетс.

"Покрити" следеће бубе у постојећем коду:

  1. Декодирање: Показивачи (у оквиру имена/лабеле/етикете) који "праве круг" - најједноставније пример, показивач на "самог себе", рецимо, на померају 24 стоје два октета: Ц0 18. Ово треба пријавити као грешку.
  2. Декодирање: Име које "не стаје" у поруку, рецимо, стоји да има још 10 знакова, а до краја поруке су само два: 0А 44 56.
  3. Декодирање: Проверити у спецификацији, али, личи да највиша два бита почетка "парчета" лабеле морају да буду 00 или 11, па две преостале комбинације треба пријавити као грешку
  4. Декодирање: Запис који "тврди" да јесте ИП (в4) адреса, али исто тако тврди да дужина записа није 4 - тренутни код овде ефективно прекине анализу поруке (а имао је идеју да прескочи), а требало би, у складу са остатком кода, пријавити грешку.
  5. Декодирање: ДНС порука која нема ЉР код = 1 ("одговор"). Тренутни код занемарује ЉР, па може да стигне и 0 ("питање/захтев") - а што треба пријавити као грешку.
  6. Декодирање: ДНС порука која нема РЦОДЕ = 0 ("без грешке"). Тренутни код занемарује РЦОДЕ, па може да стигне и неки други, који у ствари означава грешку, односно, тренутни код анализира садржај поруке за коју друга страна сама каже да је не треба анализирати. У ПУБНУБ_ЛОГ_ЕРРОР() треба исписати који је РЦОДЕ примљен (у сврхе дебубовања), али, довољан је само број, не треба "тумачити" о којој грешки се ради.
  7. Декодирање: показивач нема смисла да показује у ДНС заглавље, тамо сигурно нема лабеле. Тренутно код то "мирно прихвата", а треба пријавити грешку.
  8. Декодирање: порука која је толико кратка да није примљено цело ДНС заглавње. Тренутни код ће да је чита, а треба пријавити грешку.
  9. Декодирање: порука у којој неко питање или запис не стаје у поруку, иако лабела стаје. Рецимо, на крају поруке имамо лабелу - показивач, а после ње још два октета, међутим, у "пуном" питању, после лабеле треба да буде још четири октета. На пример: Ц0 30 00 01 (фале 00 01). Слично може да се појави у декодирању записа, где било фиксни део, било "варијабилни" (после поља дужине), може да "не стане до краја поруке". Тренутни код "мирно" чита дати број питања и одговора, рачунајући да је све у реду, али било који од ових проблема треба пријавити као грешку.
  10. Кодирање: две тачке заредом, попут "нешто..друго". Ово треба пријавити као грешку.
  11. Кодирање: празна ниска или се завршава тачком - треба пријавити грешку.

Наравно, истестирати и све остале нерегуларне ситуације (показивач ван граница поруке, енкодирање толико дугачке адресе ("хоста") да не може да стане у задати бафер и слично) које тренутно нису бубе, као и неки број регуларних сценарија - показивачи "унапред и уназад", дужине на границама опсега, показивачи "усред" лабеле, односно на неко парче лабеле, а не целу...

Требало би да може да се постигне 100% покривености редова кода и врло висока покривеност грана (близу 100%).

Додати Љт функционални тест на Аппвејору

Након што се дода прављење Љт на Аппвејору (в. #20), треба додати и да се пуштају функционални тестови.

Исти су, лако је могуће, мало зарђали, па би их требало и "освежити", највероватније.

Распаковање ГЗИПа у току пријема

Тренутно, ми примимо цело тело ХТТП одговора, па онда распакујемо ГЗИП (ако је тело било ГЗИП-овано). То значи да имамо потребу за помоћним складиштем у које се ставља распакован садржај.

Међутим, ГЗИП је могуће распаковати "како стиже" и чувати тело (само) распаковано. У том случају нам помоћно складиште не би било потребно - односно, бар ми верујемо да је тако. То треба проверити, па, ако је заиста тако, онда и променити начин рада у том смислу. У случају да нам можда ипак треба неко помоћно складишете, али може да буде мало, онда треба размислити да ли се то исплати.

Наиме, шта ако стигне само један октет? То није довољно да се "схвати" да ли тај октет треба да се распакује или не. Треба сигурно "бар још мало" да би се "попунио цео блок". У том смислу, ми би "злоупотребили" хттп_буф да буде то "складиште блока", односно, не би смо "бацали" блок док "не добијемо нешто на излазу распаковања ГЗИП-а". Наравно, распаковани садржај би био у хттп_реплу. Начелно, то звучи да би требало да може да ради, али, треба проверити у пракси.

Заменити цлоцк() са тиме() у свим примерима

цлоцк() мери "колико је процесор времена потрошио", а не "колико је стварног времена прошло", а ми у свим примерима у ствари хоћемо да измеримо колико је стварног времена прошло. Посебно, на Њиндоњсу цлоцк(), из историјских разлога (сагласност са ДОС-ом), враћа стварно време. Тако да, чак и да ипак одлучимо да не желимо да исписујемо стварно време, већ управо "процесорско", цлоцк() није функција која је примењива.

Користити диффтиме() за рачун разлике два тиме(), ради преносивости.

Ово је списак појављиваља цлоцк() у овом тренутку (прављен у цоре/самплес директоријуму):

./console/pnc_ops_callback.c:72:    clock_t start = clock();
./console/pnc_ops_callback.c:75:        time_passed_in_seconds=(clock() - start)/CLOCKS_PER_SEC;
./publish_callback_subloop_sample.c:104:    clock_t  start = clock();
./publish_callback_subloop_sample.c:107:        time_passed_in_seconds = (clock() - start) / CLOCKS_PER_SEC;
./publish_queue_callback_subloop.c:115:    clock_t  start = clock();
./publish_queue_callback_subloop.c:118:        time_passed_in_miliseconds = (clock() - start) / (CLOCKS_PER_SEC / 1000);
./pubnub_callback_sample.c:166:    clock_t  start = clock();
./pubnub_callback_sample.c:169:        time_passed_in_seconds = (clock() - start) / CLOCKS_PER_SEC;
./pubnub_callback_sample.c:251:    clk = clock();
./pubnub_callback_sample.c:259:    clk = clock() - clk;
./pubnub_callback_sample.c:286:    clk = clock();
./pubnub_callback_sample.c:294:    clk = clock() - clk;
./pubnub_callback_subloop_sample.c:26:    clock_t  start = clock();
./pubnub_callback_subloop_sample.c:29:        time_passed_in_seconds = (clock() - start) / CLOCKS_PER_SEC;
./pubnub_crypto_sync_sample.c:76:    clk = clock();
./pubnub_crypto_sync_sample.c:84:    clk = clock() - clk;
./pubnub_crypto_sync_sample.c:100:    clk = clock();
./pubnub_crypto_sync_sample.c:108:    clk = clock() - clk;
./subscribe_publish_callback_sample.c:40:        time_passed_in_seconds = (clock() - start) / CLOCKS_PER_SEC;
./subscribe_publish_from_callback.c:49:        time_passed_in_seconds = (clock() - start) / CLOCKS_PER_SEC;

Ажурирати пубнуб_цанцел() у свим примерима

Примери користе "клот" пубнуб_цанцел(), односно, не гледају шта враћа. Треба увек проверити шта враћа, па, ако враћа ПН_ЦАНЦЕЛ_СТАРТЕД, онда чекати исход, иначе, не, обустава трансакције је већ завршена. Ово пре свега у едукативне сврхе за наше врле кориснике.

У датом тренутку, ово је списак употреба пубнуб_цанцел() у примерима.

./cancel_subscribe_sync_sample.c:84:            pubnub_cancel(pbp);
./cancel_subscribe_sync_sample.c:96:    pubnub_cancel(pbp);
./console/pnc_ops_callback.c:84:    pubnub_cancel(pb);
./console/pnc_ops_sync.c:19:    pubnub_cancel(p);
./publish_callback_subloop_sample.c:117:    pubnub_cancel(pb);
./publish_queue_callback_subloop.c:128:    pubnub_cancel(pb);
./pubnub_callback_sample.c:176:    pubnub_cancel(p);
./pubnub_callback_subloop_sample.c:80:    pubnub_cancel(pbp);
./pubnub_crypto_sync_sample.c:40:    pubnub_cancel(p);
./pubnub_sync_publish_retry.c:13:    pubnub_cancel(p);
./pubnub_sync_subloop_sample.c:13:    pubnub_cancel(p);
./subscribe_publish_callback_sample.c:47:    pubnub_cancel(p);
./subscribe_publish_from_callback.c:55:    pubnub_cancel(p);

ГЗИП-овање при слању

Ако шаљемо ("објављујемо") поруку путем ПОСТ, онда можемо да извршимо ГЗИП-овање поруке (односно тела ХТТП захтева).

Пошто порука не може да буде већа од 32 килобајта, онда је сасвим прихватљиво да целу поруку запакујемо у помоћни низ у Пубнуб контексту (који је под неким #ифдеф ПУБНУБ_УСЕ_ГЗИП_ЦОМПРЕССИОН) и "преусмеримо" поруку за слање у телу ХТТП ПОСТ захтева на тај низ (уместо изворне поруке коју је проследио корисник).

Корисник треба да може да зада да ли хоће да се порука компримује или не. То изведемо тако што ће подразумевано бити да хоће уколико је компресија омогућена. Па, ако баш неће, може да искључи.

Засад нећемо да се бавимо подешавањима за "ниво компресије", већина њих је и тако подесива само у време превођења са "миниз" библиотеком коју би овде користили. По потреби, можемо да их додамо накнадно.

Такође, ако ГЗИП-овање није дало добре резултате, односно није смањило дужину поруке за бар 10% (при чему тих "10%" треба да буду параметар попут ПУБНУБ_МИНИМАЛ_АЦЦЕПТАБЛЕ_ЦОМПРЕССИОН_РАТИО), онда ћемо ипак да пошаљемо изворну поруку. Исто важи и ако буде било какве грешке при компримовању.

Петља за претплату в2

Постојећи модул за "преплату у петљи" треба "унапредити" да може да врши и "преплату в2 у петљи". Дакле, да омогући да се примају поруке у "в2 формату", са свим параметрима који се добијају и код "обичне/једнократне" в2 претплате. Наравно, и за синхрону и за колбек спрегу.

Ако се испостави да је одвећ незграпно унапређавати постојећи модул (додавањем параметара и/или нових функција, попут фетцх_в2), алтернатива је да се направи нови модул за ове намене (клонирањем постојећег).

Звучи логично да за ово може да се направи тест модула без много муке, али, треба пробати. Ако се испостави да је напорно, онда може и да се прескочи, јер се ради о једноставном "омотач" модулу.

Постојеће примере за корисника треба унапредити да "показују" и в1 и в2 претплату.

Ово треба направити и за Ц и за Ц++.

Мутекси за Пубнуб контекст

Иако смо тежили да то минимизујемо, ипак, пубнуб::цонтеџт има нешто чланова који могу да се мењају у току рада. Ако се то ради из различитих нити, долази до "трке података".

Ово би решавали на следећи начин:

  1. за ууид, треба преправити да Ц чува копију, уместо показивача. Наиме, УУИД се често користи, па није "расипнички" да се чува копија, а свакако ће да олакша употребу. Копија се чува као низ, дужине (таман) довољне да сачува стандардну текстуалну представу XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX - 36 знакова (+1 за НУЛ знак).
  2. то значи да Ц++ више не би чувао копију УУИД-а.
  3. ако корисник зада УУИД који је дужи од максималног, понашати се како је уобичајено у Ц-у: "дигнути АССЕРТ" па ископирати колико може.
  4. за "објаву путем ПОСТ" и припадајућу копију поруке у Ц++, просто искористити мутекс да се иста заштити. То би био "монитор" мутекс за пубнуб::цонтеџт. Обратити пажњу, овај мутекс мора да се "ухвати" на почетку, односно, мора да "обухвати" проверу "да ли је трансакција тренутно у току" и позив Ц-а. То, наравно, не спречава неког "трећег" да нас "претекне" и, након што ми проверимо, започне трансакцију над Ц контекстом из неке друге нити, па наша објава "пропадне иако смо већ проверили да ли је трансакција у току". То није проблем, јер у том случају наша трансакција не успева и Ц неће променити свој "показивач на поруку", па то што смо "ископирали поруку без потребе" нема друге последице сем "промашене инвестиције".
  5. За аутх, пошто се исти ретко користи, Ц не би ишта мењали. Ц++ треба да: користи (горепоменути) монитор и да провери да ли "може да се покрене нова трансакција", што, у ствари значи "НЕ(да ли је трансакција у току)". Дакле, ако трансакција није у току (може да се покрене), онда заменити и "у Ц-у" и нашу копију. Слично као малопре, монитор мора да чува "целу функцију" и опет може да се деси да неко "трећи" промени аутх независно од нас и да онда "нико не зна који ће аутх стварно да се пошаље", али, неће бити "трке података", већ простог логичког проблема који корисник може сам да реши. Ако је трансакција у току, просто дићи изузетак. Да, "много јако", али, аутх се јако ретко користи, па је мањи проблем кориснику да то "покрије".

За мутекс користити наш врли мутекс.

Ово одрадити на одговарајући начин и на Љт. Наравно, Љт има свој мутекс.

Не ради објава путем ПОСТ за криптован садржај

Када смо направили #7 , нисмо "покрили случај" да објављени садржај може да буде криптован. Тренутни код закриптовани садржај држи у локалном низу функције (на стеку), што је у реду за објаву путем ГЕТ, јер се садржај одмах УРЛ енкодира. Али, када се ради објава путем ПОСТ, онда се показивач само забележи и касније шаљу октети са дотичне адресе. Како је то показивач на неки "бивши" стек, онда се тад касније чита неко ђубре.

Просто треба закриптовани садржај чувати у Пубнуб контексту уместо на стеку и неће бити проблема. Ради једноставности чувати у статички заузетом низу октета, димензије максималне дужине Пубнуб поруке.

Подршка за ДНС ИПв6

Тренутно, ако нам ДНС опслуживач одговори са ИПв6 адресом, ми то не обрађујемо. Прихватамо само ИПв4 адресе. Такође, ДНС опслуживач можемо да задамо само путем ИПв4 адресе. Е, па, да ми подржимо и ИПв6 адресе:

  1. Треба увести тип за ИПв6 адресу
  2. Треба га искористити при обради ДНС одговора и, ако се ради о ИПв6 адреси, запамтити и касније користити при успостави ТЦП/ИП везе.
  3. Треба омогућити да се примарни и секундарни ДНС опслуживач задају ИПв6 адресом. То је независно, један може да буде ИПв4 а други ИПв6, а могу и оба да буду иста.
  4. Подразумевани ДНС опслуживач је и даље ИПв4 8.8.8.8

Треба направити тестове модула за ову сврху. Функционални тестови и примери за корисника нису потребни. Подршка треба да постоји и у Ц++ омотачу.

Идентификација платформе

Тренутно је наша индикација платформе (коју шаљемо у ХТТП заглављу https://github.com/sveljko/c-core/blob/master/core/pubnub_netcore.c#L46) помало ограничена. Треба да буде 1-на-1 са оним што се види у званичној документацији, односно, да се означи да ли је Ц или Ц++ (уз то да ли је Њиндоњс или ПОСИЏ). Наравно, Љт остаје "прича за себе".

Е, сад, како препознати да ли је Ц или Ц++? Па, могли би да пробамо на основу тога да ли се преводи као Ц или Ц++, али, сасвим је могуће да неко преведе Ц модул (рецимо, пубнуб_версион_њиндоњс.ц) као Ц у Ц++ програму. Наравно, ми не радимо тако, али, идеја је да отежамо кориснику да нас превари.

Дакле, засебан модул за Ц++ - пубнуб_версион_њиндоњс.цпп (и слично за ПОСИЏ).

Препознавање Посредника који ништа не слуша

Ако пошаљемо захтев на Посредник (енг. Proxy), па онда исти врати 407, па ми онда пошаљемо податке за нашег корисника, онда Посредник треба да одговори или са 200 (слободно настави, не дај се прекидати) или 403 (одбиј од казана).

Међутим, пијани Посредник који ништа не слуша и не чује, може да просто поново пошаље 407, на шта онда ми поново шаљемо податке и тако, лепо, уђемо у једно врзино коло, док неко не падне у несвест. У нашем случају, после неког времена истекне ВК и "дигнемо" ПНР_ТИМЕОУТ.

РФЦ надлежан за ова посла каже да се ми понашамо прихватљиво, али, да би било башка лепо ем фино да ми препознамо да је Посредник глуваћ и да онда о томе обавестимо корисника (и престанемо да причамо за глуваћом, јер од тога вајде нема).

Према томе, идеја је да видимо шта нам Посредник шаље у Proxy-Authenticate реду заглавља први пут у току трансакције. Ако, пре него што се трансакција заврши, видимо да поново шаље исти такав ред (заглавља), баталимо ствар и "дигнемо" ПНР_АУТХЕНТИЦАТИОН_ФАИЛЕД (или тако неки, коначно име можемо да изаберемо у току извођења).

Обратити пажњу на:

  1. ХТТП основна "аутентикација" је проста, само један корак. Али, друге могу имати више корака. У сваком кораку може да се деси да Глуваћ поново пита, па дакле то треба препознати у ма ком кораку да се десило.
  2. Слично, за ХТТП основну, лако је просто запамтити садржај првог 407. Међутим, за ХТТП "дигест" или НТЛМ, треба пажљиво видети који параметри се мењају, иако Глуваћ ваздан изнова пита једно те исто. Сходно томе, памтити само оне који се не мењају.
  3. Обратити пажњу да ХТТП заглавље може да има више од једног реда. То смо нешто већ буџили, али, треба проверити.

Пошто количина података коју треба запамтити за сврхе препознавања Глуваћа није јасно одредива, онда оставити да је ово подесив параметар, али, ипак, статички заузет. Ако се испостави да је ово корисник погрешно подесио, односно, да има више него што може да се запамти, просто то пријавити (ПУБНУБ_ЛОГ_ЊАРНИНГ) и наставити "као да смо запамтили све што треба". Очигледно, некад ово може да препозна Глуваћа и када исто нема. Ништа страшно, зато и имамо пријављено упозорење. Подразумевану вредност "открити" у току тестирања.

Не треба нам нова опција, ово увек радимо ако је подршка за Посредника укључена.

Треба нам тест модула - и требало би да је умерено лако да се направи.

Ово треба тестирати и "уживо". Ако имамо Посредника кога можемо овако да "наместимо", добро јест. Иначе, можемо да направимо прости "симулатор", који како год му се обратиш на неки ТЦП отвор (енг. port), а он мирне душе одговори са једним-те-истим (или, у случају ХТТП дигест или НТЛМ, сличним) одговором. Дакле, ништа не гледа шта му се шаље, само, како види нову везу на отвор који слуша, а он истог тренутка само пошаље припремљени одговор.

Додати прављење Љт на Аппвејору

Прављење Љт "омотача" на Травису није препоручиво, јер Љт није инсталиран на његовој виртуелној машини / Докеру, па би требало да се инсталира при сваком превођењу, што предуго траје.

Али, Аппвејор има Љт (и то прилично свеж, 5.11) на својој виртуелној машини, тако да би требало да ово није велики проблем да се дода.

Асинхрони ДНС: Обрада ТТЛ за ИП адресе

Када примимо одговор на наш ДНС упит, за сваку адресу би требало да добијемо и "ТТЛ" (енг. Time To Live), који означава "још колико времена је ова адреса ваљана за задато одредиште". Ово треба запамтити (као и тренутак у коме је то запамћено) и, када следећи пут будемо хтели да извршимо ДНС упит, прво проверимо да ли имамо неку адресу која је још увек ваљана. Ако имамо, онда је просто искористимо и не правимо ДНС упит.
Ако немамо, онда извршавамо упит "као раније".

Ако корисник промени адресу Пубнуб-а (pubnub_set_origin()), онда све податке о ДНС (укључујући и ТТЛ) треба "заборавити", тако да следећи пут сигурно радимо ДНС, шта год ("некад") писало у ДНС одговору и ТТЛ-овима.

Кад смо већ ту, имамо и бубу од раније коју можемо да средимо сада. Ако корисник мења адресу, за следећу трансакцију не би требало да користимо "ХТТП Кип-Алајв". Управо, требало би да кренемо у ДНС упит са том новом адресом.

Очигледно, оба претходна става важе само ако је адреса заиста промењена. Ако је корисник позвао pubnub_set_origin() са истом адресом, онда то просто треба занемарити.

Никакве измене у Ц++ (или Љт) нису потребне.

Не треба нам нова препроцесорска константа. Подразумевамо да ако неко хоће да користи више адреса, користиће ТТЛ (и обратно, ако неће да користи више адреса, не гледамо ТТЛ).

Треба нам тест модула, али нема измена у функционалним тестовима.

Ово може да се испита "уживо" путем "фолирантског" ДНС опслуживача, који ће да враћа ТТЛ-ове "како ми волимо". Али, можемо и да направимо "специјални тест", који ће да има приступ запамћеним ТТЛ подацима, па, након што направи прву трансакцију и види када нека адреса истиче, прави нове трансакције пре него што истекне и након што истекне, при чему још види да ли је у та два случаја било ДНС упита или не. Прецизније, морао би да види када најкасније истичу адресе "све заједно" (односно МАЏ(ТТЛ)). Овај тест онда можемо да пуштамо и на Травису (ако хоћемо),

Сређивање Ц++ функционалних тестова (ажурирање са Ц тестовима)

Имају следеће проблеме и ствари које треба урадити (практично, усаглашавање са изменама у Ц тестовима):

  • Не умеју да обраде да приме ПНР_ОК "одмах", тј., да не приме ПНР_СТАРТЕД пре ПНР_ОК
  • Ако приме "аццоунт љуота еџцеедед", треба да прогласе тест "неодређеним"
  • За све тестове који користе канал групе, треба да "препознају" да ли се извршавају на Травис "пул рекуест" (за ПОСИЏ) односно АппВеуор пул рекуест (за Њиндоњс) и да их прогласе "неодређеним" (без да ишта и почну да тестирају)

Објава путем ПОСТ

Тренутно објаве радимо увек путем ХТТП ГЕТ, где садржај објаве УРЛ енкодирамо. Као и сваки ХТТП ГЕТ, ни овај нема тело.

Међутим, могуће је објављивати и путем ХТТП ПОСТ, у ком случају се садржај објаве ставља у тело (и не мора да се УРЛ енкодира). Наравно, у заглављу треба:

Content-Type: application/json

Спецификација каже да треба да постоји и заглавље:

Location: /publish/myPubKey/mySubKey/ch1/0

У Location, myPubKey и mySubKey су кључеви који се користе (за Пубнуб контекс "преко" кога се објављује) а ch1 је канал на коме се објављује.

Ипак, ми га засада не правимо. Ако буде требало, додаћемо га накнадно.

Постоји неколико "тема за размишљање" у смислу извођења:

  1. Да ли омогућавамо кориснику да у истом програму може "овако или онако"? пубнуб_публисх() свакако остаје "као и досад", али, може да се унапреди пубнуб_публисх_еџ() или да се дода пубнуб_публисх_виа_пост().
  2. Алтернатива је да постоји #дефине ПУБНУБ_ПУБЛИСХ_ВИА_ПОСТ, који ако је дефинисан, онда се увек користи ПОСТ, а ако није, онда се увек користи ГЕТ.
  3. Ако "може и овако и онако", онда је питање да ли су "ПУБЛИСХ ГЕТ" и "ПУБЛИСХ ПОСТ" различите трансакције, или се ради о истој трансакцији а негде у "заставицама" (флагс) ми памтимо да ли треба да се користи ГЕТ или ПОСТ.
  4. Такође, да ли неким #дефине може да се укључи/искључи један од ова два начина? Односно, да корисник има могућност да "укључи" могућност или ХТТП ГЕТ или ХТТП ПОСТ или "ХТТП ГЕТ и ХТТП ПОСТ".

У сваком случају, објаву коју корисник задаје памтимо путем показивача. Дакле, не копирамо је. Односно, понашамо се слично као за УУИД. То значи да је на кориснику да обезбеди да је показивач ваљан док ми не пошаљемо дату објаву.

Треба видети како ће ствари тачно да изгледају у извођењу, али, чини се да:

  • неће бити много новог кода за ове потребе, тако да још #дефине нису много корисни, а већ их имамо превише - дакле, личи да је "може и овако и онако" добар избор - наравно, ако се испостави да ће бити доста новог кода, треба размислити
  • у сличном смислу, збох потребе за "чувањем ваљаности" код ПОСТ, лепо је да корисник има могућност да, ако неће да се тиме бави, може просто да користи ГЕТ (без потребе да све преводи испочетка)
  • са становишта корисника, ружно је да "публисх_виа_пост" буде посебна трансакција. Објава је објава. Посебно што је одговор Пубнуб мреже исти, независно од тога да ли је објава послата путем ГЕТ или ПОСТ
  • пубнуб_публисх_еџ() треба обогатити са параметром "ГЕТ или ПОСТ". Чини се да увођење нове публисх_виа_пост() није стварно потребно нити много корисно. Корисник може, ако му се тако свиђа, да направи своју помоћну функцију истог смисла.

Треба ажуриурати и Ц++ омотач да подржава објаву путем ПОСТ.

РЕСТ АПИ: бриши историју

РЕСТ адреса (УРЛ путања) за брисање је:

/v3/history/sub-key/<sub-key>/channel/<channels>

УРЛ параметри (опциони) су:

  • start (број)
  • end (број)

Иако то заиста јесу бројеви, то су веома велики бројеви, јер се, заправо, ради о временским ознакама (токен). Са наше стране, примаћемо их као ниске и проверавамо их у смислу да је грешка ако мора да се УРЛ енкодирају.

Одговор у случају успеха:

{
    "status": 200,
    "error": false,
    "error_message": "",
}

У случају неуспеха, error ће бити "тачно".

Додати у нови модул "пубнуб_апи_адванцед_хистору`.

Треба нам тест модула и прост функционални тест ако ово ради на демо каналу (објави нешто на неком каналу, покупи историју, обриши нешто, поново покупи историју и увери се да је стварно обрисано (само) оно што треба). Дакле, ако увидимо да ово не ради на демо каналу, онда не треба писати функционални тест.

Прост пример за корисника додати у пубнуб_адванцед_хистору_сампле.

Треба нам подршка у Ц++ омотачу и Љт.

РЕСТ АПИ: вишеканална историја

ПубНуб ово зове batch history. Омогућава читање историје више канала одједном, с тим што се чита највише 25 порука по каналу (и највише 500 порука укупно). РЕСТ адреса (УРЛ путања) је:

v3/history/sub-key/{sub_key}/channel/{channels}?stringtoken,max,reverse,start,end,include_token,auth,uuid

УРИ параметри (који су другачији од "једноканалне" историје):

  • max (опциони, број) - ограничење од 25/500 ми нећемо да обрађујемо, нека се ПубНуб буни ако хоће

Формат одговора је најбоље илустровати примером (тражили смо историју за канале hello_world и my_channel, са max=2:

{"status": 200, "error": false, "error_message": "", "channels": {
    "my_channel":[
        {"message":{"analog":[1761,2515,79,141]},"timetoken":"15459071993688741"}, 
        {"message":{"text":"hey"},"timetoken":"15459501962959096"}
    ], "hello_world":[
        {"message":"Hello World","timetoken":"15459501871338395"},
        {"message":"Hello World","timetoken":"15459501871721426"}
    ]}
}

Засад, не правимо икакву помоћну функцију за обраду овог одговора.

Пошто има много параметара, и већина су опциони, направити спрегу као у пубнуб_еџ.х, али ставити у модул пубнуб_адванцед_хистору.

Треба нам тест модула и прост функционални тест ако ово ради на демо каналу (на неколико канала објавити неколико порука, онда покупити толику порука и уверити се да је све како треба). Дакле, ако увидимо да ово не ради на демо каналу, онда не треба писати функционални тест.

Пример додати у адванцед_хистору_сампле.

Треба нам подршка у Ц++ омотачу, као и у Љт.

Ц++ петља претплата в2

"Под" #13 правимо само "једнократну" претплату В2 за Ц++. Овде правимо "омотач" петља претплате. Треба га направити "клонирањем" постојеће петље претплате за Ц++ (за "в1" претплату).

За ово нам не треба тест модула.

Примере за корисника за петља претплату треба обогатити да показују и в1 и в2 петља претплате.

Ово се не односи на (нема смисла за) Љт.

Покушај поново мисшу! (другом адресом из ДНС одговора)

Када ДНС опслуживач одговори на ДНС упит, може да понуди више ИП адреса као резултат претраге. Тренутно, ми ћемо да искористимо само једну и, ако то не успе, одустајемо.

Уместо тога, ако постоји више адреса, треба их пробати све, једну по једну, док нека не успе - или се све потроше (или, наравно, истекне ВК).

Ово је мало "напорније" за ССЛ/ТЛС, јер тада треба пробати следећу адресу било да не успе само ТЦП/ИП повезивање, било да не успе успостава ТЛС сесије. То је једини критеријум - не занима нас да ли касније трансакција није успела и зашто. Само да ли је успостава ТЦП/ИП везе (и ТЛС сесије) успела или не.

Број ИП адреса које памтимо треба да буде константа која може да се "намешта" у пубнуб_цонфиг.х. Подразумевана вредност треба да буде 2, јер тренутно Пубнуб-ов ДНС враћа увек тачно 2 одговора.

У смислу #34 , овде треба равноправно разматрати ИПв4 и ИПв6. Дакле, пробати и једне и друге и то оним редом којим су прочитане (без егзибиција попут "прво све ИПв4, па онда ИПв6").

За ово нам треба тест модула, а "чист" функционални тест није могуће извести (треба некако да обезбедимо да успостава везе не успе), али је могуће направити "помоћни" ДНС опслуживач који враћа такве "безвезе адресе" - то би био тривијални програмчић који не гледа шта га се пита, већ само враћа или један те исти одговор или садржај чита из датотеке.

Aжурирати "синхроне" примере да трансакција може "одмах" да успе

Традиционално, почетак трансакције није могао да врати ПНР_ОК. Данас то не може само у "колбек" спрези, али у сихнроној, може. Ово је само донекле обрађено у примерима, а тамо где јесте, обрађено је на ружан начин. У ствари је просто, увек треба само проверити да ли почетак трансакције враћа ПНР_СТАРТЕД и, ако јесте, позвати пубнуб_ањаит(), иначе већ имамо исход трансакције.

pnru = pubnub_publish(pb, channel, "\"SXTAGOD\"");
if (PNR_STARTED == pnru) {
    pnru = pubnub_await(pb);
}
if (PNR_OK == pnru) {
    /// obradi uspeh
}
else {
    /// obradi neuspeh
}

Ц++ Подршка за претплату В2

В2 претплата је направљена за Ц, али, треба је додати у Ц++ (укључујући и Љт).

Као и у Ц-у, треба је моделирати слично као "проширену претплату".

Треба дефинисати класу која носи параметре В2 поруке. У истој, "поља која су ниске" нека буду стд::стринг, ради веће преносивости. То јесте мало споро, јер значи да ће све то бити копирано, али, за нешто од тога ће можда да проради "оптимизација за мале ниске", док је стд::стринг_виењ подржан тек од најновијих преводилаца, па стога није много преносив (а има и проблеме са животним веком).

Наравно, и за Љт, нека то буде стд::стринг а не ЉСтринг. Запамтити да је ЉСтринг само за спрегу са самим Љт, а наши корисници треба да виде "православни" стд::стринг. Наравно, зарад лакоће употребе, можемо да имао параметре који су ЉСтринг, али, увек чувамо стд::стринг и увек подразумевано радимо са истим, док је ЉСтринг само "алтернатива".

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.