Разбор алгоритма (из документации ЖЖ) скачивания веб-клиентом всех постов журнала

Mar 12, 2023 06:55

Ранее в этой серии постов:
...
29. PowerShell и ЖЖ: функция «getevents», скачивание постов (интерфейс «flat»), ч.1
30. PowerShell и ЖЖ: функция «getevents», скачивание постов (интерфейс «flat»), ч.2
31. PowerShell и ЖЖ: функция «getevents», скачивание постов (интерфейс «flat»), ч.3

Алгоритм скачивания всех постов журнала веб-клиентом описан в документации ЖЖ («Живого Журнала») на английском языке по следующей ссылке.

На английском он написан потому (если кто не в курсе), что ЖЖ изначально был создан американцем Брэдом Фицпатриком в 1999 году. Код ЖЖ изначально был открытым, документацию сначала писал сам Фицпатрик, а потом ее много раз дополняли другие разработчики. Бо́льшая часть разработчиков была англоговорящей, поэтому естественно, что документация писалась на английском языке.

После продажи в конце 2007 года ЖЖ российской компании «SUP» (она же «SUP Media» и «SUP Fabrik») по факту разработка интерфейсов общения с ЖЖ из сторонних веб-клиентов остановилась, документация не была переведена на русский язык. Вскоре после того, как компания «SUP Media» в 2013 году вошла в группу компаний «Rambler&Co», код ЖЖ закрыли. Поэтому стороннему наблюдателю неизвестно, что там происходит с кодом сейчас. Спасибо, что оставили доступной старую документацию и набор функций старых интерфейсов.

В само́й старой документации, кстати, есть ошибки, которые не исправлялись годами. Я опишу некоторые из них ниже. Кое-что из документации, касающееся скачивания содержимого журнала, я уже излагал в одном из предыдущих постов.

Алгоритм скачивания всех постов журнала изложен в документации на псевдокоде, цитата:

send client request “syncitems” with the
“lastsync” variable not specified
get list of items back from request, save items into list for processing later
while size_of_list < sync_total {
find most recent time in list
call “syncitems” again, but set “lastsync” to most recent time
push result items onto lost
}
iterate through list and remove items that do not start with “L-” (L means “log” which is a journal entry)
create hash of journal itemids with data { downloaded => 0, time => whatever sync_X_time was }
while (any item in hash has downloaded == 0) {
find the oldest “time” in this hash for items that have downloaded == 0
…decrement this time by one second.
mark this item as downloaded (so we don't use the same time twice and loop forever)
send client request “getevents” with selecttype set to syncitems, lastsync set to oldest time minus 1 second
mark each item you get back as downloaded in your hash
put the entries you got into storage somewhere.
}

Это описание алгоритма было предложено разработчиком Марком Смитом в сообществе ЖЖ lj_clients в 2004 году. В то время Марк работал в компании, поддерживающей ЖЖ (насколько я понимаю, тогда это была собственная компания Брэда Фицпатрика «Danga Interactive», которую он продал компании «Six Apart» в январе 2005 года). Я написал Марку письмо на электронную почту, но он не ответил (вот его учетная запись на «Гитхабе»).

Как видно из блока кода выше, содержимое поста Марка в сообществе lj_clients было практически один в один скопировано в документацию. Кроме имеющихся ошибок в псевдокоде при переносе алгоритма в документацию добавились новые косяки. Например, первые два предложения в псевдокоде (я пометил их красным цветом в блоке кода выше) - это на самом деле одно предложение (этот недочет отсутствует в оригинальном посте Марка). С другой стороны, описка - слово «lost» (я пометил его красным цветом в блоке кода выше) - пришла в документацию из оригинального поста. Думаю, тут должно быть слово «list» («список» по-русски). Я изначально надолго завис на этой опечатке, дошло далеко не сразу, что это опечатка.

Перевод псевдокода на русский язык

Мне было интересно перевести этот псевдокод на русский язык. При этом, несмотря на то, что я полностью понимаю, что написано в этом алгоритме и как это реализовать, я не понимаю, почему некоторые моменты сделаны именно так, как показано в блоке кода выше. Именно поэтому я пытался связаться с Марком, чтобы разобраться в этом коде с ним. Но связаться пока не получилось.

В итоге я решил переводить этот псевдокод на русский язык не дословно. Я изложу этот алгоритм так, как его вижу я. Но базовый алгоритм, естественно, останется примерно таким же, как в блоке кода выше.

отправить запрос на запуск функции «syncitems» без входного параметра «lastsync»
получить из ответа список записей об обновлениях журнала и число «sync_total»
while (размер_списка < sync_total) {
найти новейшее время в списке
отправить запрос на запуск «syncitems» с «lastsync», равным новейшему времени
добавить записи об обновлениях журнала из ответа в список
}
оставить в списке только записи об обновлениях журнала, касающиеся постов
(идентификаторы таких записей начинаются на букву «L»)
добавить к списку записей об обновлениях колонку «downloaded» со значением 0
(в итоге в списке каждая запись содержит поля «itemid», «time», «downloaded»)
while (в списке есть записи с полем «downloaded», равным 0) {
отправить запрос на запуск функции «getevents» с «selecttype», равным «syncitems»
(в первой итерации - без «lastsync», далее для «lastsync» вычисляем время)
получить из ответа посты и сохранить их в какое-либо хранилище (на диске и т.п.)
пометить в списке полученные посты (в поле «downloaded» присвоить 1)
найти в списке новейшее время у полученных постов (для «lastsync»)
}

Как видно из блока кода выше, я внес изменения во второй цикл. В предыдущем посте я описал, как пробовал на практике оба способа - описанный в документации (нахождение старейшего времени в записях об обновлении журнала, касающихся еще не загруженных постов) и альтернативный (нахождение новейшего времени в записях об обновлении журнала, касающихся уже загруженных постов). Оба способа работают, но альтернативный мне нравится больше, потому что не нужно вычитать 1 секунду из значения времени, то есть получается на одно действие меньше.

Кроме того, альтернативный способ во втором цикле - это тот же способ, который используется в первом цикле. Непонятно, почему автор оригинального псевдокода использует в первом и во втором циклах разные способы. Я думаю, правильнее будет работать по одному и тому же принципу.

Еще я не понял пассаж насчет возможности бесконечного цикла, а также зачем в связи с этим нужно помечать в списке записей об обновлениях журнала как загруженный еще не загруженный пост. Вот этот момент очень хотелось бы обсудить с автором псевдокода.

Часть псевдокода до первого цикла можно включить в первый цикл, а сам этот цикл изменить с вида «while-do» (с предусловием) на «do-while» (с постусловием), что я и сделал в своем варианте реализации этого алгоритма на языке «PowerShell», о чем постараюсь рассказать подробнее в следующих постах.

Инструмент, Образование, Сайтостроение, Программирование, История, Английский язык, ЖЖ

Previous post Next post
Up