Как правильно организовать автообновление через сеть

Для неординарных вопросов. Если вы опытный программист, попавший в трудную ситуацию, — вам сюда.

Модератор: gaidar

Правила форума
Этот раздел не предназначен для того, чтобы вы адресовали свою проблему профессионалам.
Этот раздел предназначен для профессионалов, которые столкнулись с проблемой и не могут решить ее самостоятельно.
Если вы считаете себя профессионалом, а свою проблему сложной — вам сюда.
Если модератор посчитает, что вы ошиблись, то на первый раз он перенесет ваше сообщение в основной раздел без последствий для автора. Во второй раз тема будет закрыта, а автору будет выписано нарушение. В третий раз автор будет забанен.
uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Как правильно организовать автообновление через сеть

Сообщение uni » 14.07.2011 (Чт) 20:08

Не могу найти алгоритм и структуры для разумного подхода к автообновлению программы на VB6. Точнее говоря, мне нужен механизм, который я хочу протестировать при помощи vb6.

Сам я этот механизм вижу так. У меня есть программа, которая имеет GUID для своего "семейства". Семейство - это, к примеру, версии программы 1.x.x.x, а при переходе на следующую версию программе назначается уже другой GUID. Далее, программа знает URL к месту в сети, с которого идёт обновление. По этому адресу должен находиться файл в формате JSON со структурой, которая хранит информацию об обновлениях программы. Скачиваем этот файл, смотрим совпадения GUID и узнаём текущую версию. Если текущая версия на сайте новее, то скачиваем обновление по указанному адресу в указанном формате. После скачивания запускаем инсталлятор, а программу закрываем. Или наоборот - программу закрываем, а инсталлятор запускаем.

Вот так. Вроде не очень сложно, всё это по частям у меня есть: сайт, программа, работа с JSON (функций для скачивания правда нету). Но мне нужна структура JSON файла для такого случая. Какая может быть оптимальная, но расширяемая структура? Как хранить версию, чтобы легче было сравнивать? Может быть должна быть ещё какая-нить дополнительная информация в структуре JSON-файла? Может быть есть уже готовый класс автообновления, где бы я мог забить все свои данные и просто прицепить его к проекту? Это последнее, конечно, и хотелось бы. Иначе, берусь за велосипед.

П.С. Ах да, этот механизм должен работать и со стороны разработчика. Т.е., используя те же данные, я могу заливать новую версию на сайт. Вот как, и чтобы всё обновлялось, в т.ч. JSON файл.
Россия навсегда!
Сетрификаты

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Re: Как правильно организовать автообновление через сеть

Сообщение alibek » 15.07.2011 (Пт) 9:39

Обоснуй появление темы в этом разделе. Я пока не вижу таких причин,

По существу — не нужно изобретать велосипед, в хороших системах инсталляции эти механизмы реализованы (MSI, InstallShield).
Lasciate ogni speranza, voi ch'entrate.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Re: Как правильно организовать автообновление через сеть

Сообщение uni » 15.07.2011 (Пт) 15:35

alibek писал(а):Обоснуй появление темы в этом разделе. Я пока не вижу таких причин,

По существу — не нужно изобретать велосипед, в хороших системах инсталляции эти механизмы реализованы (MSI, InstallShield).

Существует? И как называется этот механизм? Я пользуюсь сотнями программ и у всех разное, а значит, самописное автообновление. Некоторые код вшивают в программу (Помощь->Проверить обновление), некоторые пользуются дополнениями к программе, запуская в трее специальных мониторов. Сам я пользуюсь и пишу скрипты для Inno Setup и что-то не наблюдал там встроенных систем такого рода. Я бы не сказал, что это плохая системы инсталляции. Всё, что тебе нужно ты пишешь сам.

Уважаемый alibek, судя по посту, Вы не поняли вопроса. Причём вообще тут система инсталляции? Это лишь небольшая часть озвученной проблемы. Когда озвученная проблема будет решена, вот тогда уже дело дойдёт до инсталляции. Сначала нужно скачать то, что нужно инсталлировать и мне хочется, чтобы это делалось автоматически, а не путём присоединения ярлыка к текстовому файлу, содержащёму URL сайта, как Вы видимо подумали (примитив меня не интересует, как Вы заметили). Меня интересует современное решение именно в том русле, как я указал, именно так, как работают все современные программы - проявляют самостоятельность в отслеживании своих версий через сеть, без дополнительных усилий со стороны пользователя. Инсталлятор тут вообще не причём.

Вот о чём я: Как не надо делать автообновления
На хабре народ в теме, буду читать, может найду какие мысли.

П.С. Найдённые механизмы:
1. Updater Application Block (.Net, по ссылке пишут, что это устарело).
The Updater Application Block is a .NET Framework component that you can use to detect, download, and apply client application updates deployed in a central location. By using the Updater Application Block, you can keep smart client applications up to date with little or no user intervention. You can also extend the Updater Application Block to use custom classes for downloading files and for performing post-deployment configuration tasks.


Всё оказывается не так просто, как я думал. Если для .Net и можно что-то найти, то для Win32 это сделать будет трудновато, что и видно по старому ПО. На Хабре писали, что в Windows есть некоторый аналог репозитория (как в Ubuntu, к примеру), но им почему-то мало кто пользуется. Если есть репозиторий, то должен быть и API к нему.
Россия навсегда!
Сетрификаты

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Re: Как правильно организовать автообновление через сеть

Сообщение uni » 15.07.2011 (Пт) 17:24

Я нашёл как это называется в Windows. Не удивительно, что эти у нас мало кто пользуется. Это управление заплатками (патчами). Для этого должен быть (видимо) запущен сервис SUS, которые многие товарищи у себя на компах с пиратскими виндами отключают, т.к. не любят, когда комп с сам подрубается к серверу microsoft.

Там целая серия лейблов: Windows Update , Software Update Services (Windows Update Services ) и Systems Management Server Software Updates.

Действительно, стандартные и известные инсталляторы могут делать патчи, но вот их автообновление... это нужно, как минимум, иметь сервер SUS. Хотя я спецификации не читал, но понимаю, что такого рода решения для моей скромной проги - извращение. Вариант с JSON (упрощённый XML) и пассивной страничной в инете мне куда ближе. Почитаю спецификации на эти сервисы от MS, может прийдёт в голову какие данные должны быть, чтобы процесс обновления был как можно "гибче".
Россия навсегда!
Сетрификаты

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Как правильно организовать автообновление через сеть

Сообщение Хакер » 15.07.2011 (Пт) 18:03

В чём вообще вопрос-то?

Когда-то я делал систему обновления для внутреннего софта в одной обширной (филиалы разбросаны географически) компании.

Механизм был такой.
  • Каждая рабочая станция имела уникальный идентификатор.
  • В головном офисе был сервер, к которому подключался агент обновления с каждой раб. станции.
  • На сервере работало серверное приложение, в составе которого была база данных всех рабочий станций, информация о членстве каждой рабочей станции в группе (соответствие многие-ко-мнгогим).
  • Если отбросить все лишние детали системы (обмен документами, нотификациями), администратор мог добавлять в систему обновления. Для каждого обновления администратор указывал целевую аудиторию (все, или определённые группы, или определённые пользователи), файл(ы), куда из разместить на клиентской системе и что дальше с ними выполнить. Каждое обновление имело уникальный идентификатор.
  • На каждой рабочей станции агент обновления хранил у себя список обновлений, которые уже были установлены в процессе обновления. При подключении к серверу он передавал количество уже установленных обновлений и слепок списка всех установленных обновлений. Если количество и слепок, присланные клиентом на сервер не совпадали с теми, которые должны придти от клиента по мнению сервера (сервер регистрирует все запросы на обновления), то тогда инициировалась процедура установлений разногласий, в ходе которой клиент слал на сервер уже не слепок списка идентификаторов обновлений, а сам список, и они вместе с сервером устанавливали, какие обновления на самом деле должны быть дополнительно установлены (то есть по мнению сервера клиент их скачал и установил, но теперь клиент говорит, что не качал, и не устанавливал)
  • Далее, после того, как несоответствия будут устранены, сервер на основе информации от клиента устанавливает, как обновления были добавлены администратором с момента загрузки клиентом последнего обновления. Выбираются, разумеется, только те обновления, которые предназначены данному клиенту (клиент входит в список целевых клиентов, или входит в группу целевых групп). Сервер формирует список идентификаторов обновлений с информацией о каждом (например, о размере файлов), и отправляет его клиенту.
  • Клиент запоминает список, резервирует на диске место под все необходимые файлы и начинает скачивать обновления в порядке их следования, или, если сервер занят, в том порядке, в котором сервер готов их отдать. При этом, предусмотрен механизм докачки при обрыве соединения. Более того, после загрузки, клиент вычисляет md5-хеш и отсылает его на сервер, чтобы сервер подтвердил, что файл скачался без изменений. Дополнительный смысл здесь был в том, что одни из условий было требование, чтобы все закачки клиентами фиксировались на сервере. И клиент не мог подделать журнал скачиваний на сервере, послава что-то вроде «ну окей, я всё скачал». От клиента требовалось прислать корректный md5 в доказательство того, что файл действительно был скачан и при том правильно. Сервер получал доказательство, а клиент получал информацию о том, что файл скачался правильно (или неправильно). Если файл скачался неправильно, клиент и сервер инициировали процедуру поиска битых участков файла. Файл разбивался на фрагменты, для каждого фрагмента подсчитывался хеш, затем сверялись хеши фрагментов между клиентом и серверов. Фрагменты, хеши которых совпали, вычёркивались из списка. Фрагменты, хеши которых не совпали, дробились на субфрагменты и субфрагменты проверялись похожим образом. Корректные субфрагменты вычёркивались, а битые опять же разбивались на части, если только не превышен порог гранулярности. Когда в конце-концов устанавливался список битых фрагментов (дробить их уже не позволял порог фрагментации), клиент повторно скачивал эти битые фрагменты, а потом наступала повторная проверка целостности файла целиком. И если хеши опять не совпали, опять инициировалась проверка на битость. Только уже не с нуля, а проверялись хеши повторно скачанных в последний раз фрагментов.
    И так до тех пор, пока битых регионов не останется.
    После этого клиент либо вызывал необходимые команды (если это требовалось), либо, если требуется заменить файл, которые занят другим процессом, ставил файл в список pending-moves.
  • Клиент сообщал на сервер обо всех этапах процесса загрузки/установки, администратор на сервере могу
    наблюдать/контролировать это.

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

Сервер был написан на PHP, база данных — MySQL. Протокол передачи — собственный бинарный поверх HTTP. Библиотека взаимодействия с сервером — С++. Пользовательский интерфейс агента обновлеия и администраторской утилиты — VB.

Повторяю: в чём собственно вопрос?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Re: Как правильно организовать автообновление через сеть

Сообщение uni » 15.07.2011 (Пт) 19:02

Спасибо, Хакер. Позновательно. Очень напоминает перевод даташита от Microsoft. У них это всё реализовано и так. Применяя групповые политики можно устанавливать msi удалённо на всех рабочих станциях. Насколько я почитал в рунете, используя стандартный софт и нанятого админа, который в этом шарит, можно одновременно установить хоть 100 обновлений на 100 компов.

У меня вопрос в идеологии. Как писали тут, подходы у Microsoft и других инсталляторов отличаются.
Изображение
(не смог скопировать только нужную чать, там у них картинки)

Так вот, для простых смертных и небольшого по функционалу ПО, вполне достаточно использовать приём автообновления пассивного типа. Когда не нужны администраторы, серверы и дополнительные заморочки. Вот как, к примеру, делает NOD32, обновляя базы. Он скачивает файл update.ver со следующим содержимым:
Код: Выделить всё
[PRODUCT_TYPES]
ESS=ESET Smart Security
[ADVHEUR0]
platform=x86
versionid=1085
type=advheur
group=perseus
date=12.01.2009
file=nod27C8.nup
buildregname=AdvheurBuild
build=1039
level=0
base=268435456
size=438663
category=engine
[ADVHEUR1]
platform=x86
versionid=1098
type=advheur
group=perseus
date=24.09.2009
file=nod767F.nup
buildregname=AdvheurBuild
build=1055
level=1
base=1039
size=111391
category=engine
[ADVHEUR2]
platform=x86
versionid=1099
type=advheur
group=perseus
date=30.10.2009
file=nod0342.nup
buildregname=AdvheurBuild
build=1056
level=2
base=1055
size=12954
category=engine
...

Повторяю: в чём собственно вопрос?

У меня есть софтина, которая представляет из себя небольшую утилитку, которую я время от времени обновляю. Я не хочу привязываться к сервер-клиент технологиям в активном их понимании, т.к. это просто не нужно. Я хочу иметь возможность "пассивного" обновления, когда я выкладываю свой дистрибутив в сети по известному адресу и один раз установленная программа сама иногда считывает некий файл некого формата по этому адресу, чтобы проверить обновление и скачать (предложить) новый дистриб (инсталлятор) по указанному там пути.

Не нужно никаких лишних телодвижений. Вот как NOD32 скачивает свои обновления. Их можно даже зазеркалить локально и технология та же. Никаких серверов и пр. Они для этого придумали свой формат upgrade-файла. Насколько я заметил, так делают все, кто пишет отдельно взятое небольшое приложение.

Вопрос простой: Как, используя описанный выше, пассивный метод со скачкой файла с инструкциями проверять обновления для своей небольшой программы? Вот взять тот же QIP, как он проверяет свои обновления? Мм? Все пишут свой велосипед? Может придумали что-нить универсальное для небольших программ? Написать-то мне не трудно, я даже придумал формат своего upgrade-файла, но я чувствую, что где-то уже должна быть дока по этому вопросу.

Ещё пример: 2GIS. Он имеет свой менеджер, который скачивает MSI для своего обновления. Они написали свой велосипед.

Ещё, мне хотелось бы используя этот же приём заливать обновление на мой сайт, если оно "устарело", т.е. "обновлять" сайт обновлений. Как-то это должно быть всё не сложно и автоматизированно.

Хакер, если все пишут велосипеды, то не возникает у тебя мысли, что вопрос есть?
Россия навсегда!
Сетрификаты

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Re: Как правильно организовать автообновление через сеть

Сообщение uni » 28.07.2011 (Чт) 18:42

Свой велосипед я сделал и опробовал. Пашет. Если кому это будет интересно, то опишу свою технологию автообновления. Ничего необычного в ней конечно нет. Разве что есть некоторые тонкости, которые специфичны именно для моей программы.

Для начала опишу вкратце алгоритм пассивного автообновления.

В программе есть окно настроек, которое позволяет задавать некоторые параметры автообновления:
- включить/выключить автообновление;
- периодичность автообновления (каждый день, через неделю, через месяц);

Также в программе есть отдельная опция в меню "Помощь\Обновить". Это ручной вызов того же алгоритма автообновления. Используется, если автообновление в настройках выключено.

Далее, при вызове (автоматическом или ручном) функции автообновления программа делает следующее:

1) проверяет наличие доступа к сети (активного Интернет-соединения);
2) если соединение найдено, то скачивается с известного адреса файл "update";
3) при успешном скачивании, файл сохраняется во временном файле временной папки;
4) осуществляется парсинг файла на предмет наличия записи для конкретно нашей программы;
5) если метка программы найдена, то считываются поля версии доступного обновления;
6) делается сравнение, если новая версия больше текущей, то пользователю выпадает окно с вопросом о доступности обновления;
7) при положительном ответе, просим пользователя указать куда сохранить файл обновления;
8 ) скачиваем сам файл по ссылке, указанной в файле "update";
9) удаляем файл "update".

Что же в моём варианте специфичного. А это почти всё.

1. Я использую нестандартный для VB6 формат записи версии в виде: Major.Minor.Revision.Build. Для бейсика он нестандартный, а вот для всего остального мира это не так, поэтому я использую именно этот формат, хотя это требует дополнительного кода для обслуживания (и addin'а vbAdvance).

2. Я использую не совсем обычный опять же для VB6 формат файла "update". Опять же, уточню, что необычен он именно для бейсика, а в современном мире очень даже обычен. Формат таков (UTF-8, кстати):
Код: Выделить всё
[
    {
        "ProgID": "{43CE9E0A-3657-4258-B573-8B18F6AC3B42}",
        "Major": 1,
        "Minor": 4,
        "Revision": 0,
        "Build": 0
        "DownloadLink": "http:\/\/x-uni-x.chat.ru\/cop\/Configurator_1.3.0.160_setup.zip"
    }
]

Это экспериментальный вариант. Цифры тут от балды для проверки. Как Вы возможно узнали, да, это JSON. Простой универсальный формат для обмена данными в современной сети. Для VB6 есть специальный класс, который позволяет работать с этим форматом: VBA JSON project. Нужна библиотека scrrun.dll.
Файл может быть обнаружен тут: update .

Дело в том, что в моей программке этот формат используется, поэтому я использовал его и для "update"-файла. Вы, конечно, можете использовать хоть ini-файлы, хоть даже одну строку, которую потом будете сплитить на части. Дело Ваше, не суть.

3. Для закачки используется местный кирпич "Качалка".

----------------------------------

Теперь чуть детальнее. Как Вы видите, я присвоил своей программе GUID. Его можно получить самостоятельно:
Код: Выделить всё
Public Declare Function CoCreateGuid Lib "ole32.dll" (buffer As Byte) As Long

Public Function getGUID() As String
    Dim buffer(0 To 15) As Byte
    Dim s As String
    Dim ret As Long

    s = String$(128, 0)

    ' получает численный код
    ret = CoCreateGuid(buffer(0))
   
    ' преобразуем его в текст,
    ' используя недокументированную функцию StrPtr
    ret = StringFromGUID2(buffer(0), StrPtr(s), 128)

    getGUID = Left$(s, ret - 1) ' отсекаем "хвост"

End Function

' ...
Debug.Print getGUID
'...

Либо пользоваться стандартными средствами. В Visual Studio есть специальный генератор GUID, которым я не помню даже пользовался или нет. Не суть, смысл сего действа в том, что мой "update" должен быть расширяемым и запись для моего приложения может находиться среди кучи других таких же записей для других программ. Мне хотелось сделать универсальную вещь, т.к. пишу я не только на бейсике, точнее говоря, на бейсике я почти вообще не пишу :) Так, для общего развития. В "update"-файле может находится целый список моих программок и их обновлений. Они будут там через запятую (см. формат JSON).

Прежде чем начать, мы должны проверить наличие соединения. Делаю я это так:
Код: Выделить всё
' Local system uses a modem to connect to the Internet
Public Const INTERNET_CONNECTION_MODEM = 1

' Local system uses a local area network to connect to the Internet
Public Const INTERNET_CONNECTION_LAN = 2

' Local system uses a proxy server to connect to the Internet
Public Const INTERNET_CONNECTION_PROXY = 4

' Local system's modem is busy with a non-Internet connection
Public Const INTERNET_CONNECTION_MODEM_BUSY = 8

' ***********************************
' *  ФУНКЦИИ ДЛЯ РАБОТЫ С ИНТЕРНЕТ
' *  ~~~~~~~~ ~~~~~~~~~ ~ ~~~~~~~~
' ***********************************
Public Declare Function InternetGetConnectedState _
               Lib "wininet.dll" (ByRef lpdwFlags As Long, _
                                  ByVal dwReserved As Long) As Long

----------------

    ' Проверяем интернет-соединение
    Dim InternetConnected As Boolean
    Dim Result As Boolean
    Dim dwConnectionTypes As Long

    StatusBar.Panels(1).Text = "Проверяю доступ к сети..."
   
    dwConnectionTypes = INTERNET_CONNECTION_MODEM + INTERNET_CONNECTION_LAN + _
            INTERNET_CONNECTION_PROXY
   
    InternetConnected = InternetGetConnectedState(dwConnectionTypes, 0)

    ' TODO: Отображать процесс автообновления в статус строке
    ' Если имеется подключение к Интернет, то проверяем доступность сервера и
    ' файла автообновления
    If InternetConnected = True Then
        '  ...
        '  ...
    End If


Это работает. Уже не помню как и почему, но работает. Портировал с паскаля, когда-то там использовал эту функцию для индикации состояния "Онлайн".

Если соединение есть, то скачиваем файл "update":
Код: Выделить всё
Private Function DoAutoUpdate(UpdateFileLink As String) As Boolean
    '<EhHeader>
    On Error GoTo DoAutoUpdate_Err
    '</EhHeader>

    Dim Result As Boolean
       
    Result = False
   
    ' Создаём временный файл
    Dim szBuffer As String, szTempFileName As String
    Dim MAX_PATH As Long
    Dim length As Integer
   
    MAX_PATH = 255
    szBuffer = Space(255)
   
    ' Получаем путь к временной папке
    length = GetTempPath(MAX_PATH, szBuffer)

    ' Формируем путь к временному файлу
    szTempFileName = Space(255)
    GetTempFileName szBuffer, "cop", 0, szTempFileName
       
    ' Пытаемся скачать файл описания с сервера
    Kachalka.DownloadToFile UpdateFileLink, szTempFileName

...


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

Файл закачали, теперь будем его парсить. Тут уж у кого как будет. Всё зависит от содержимого. У меня это выглядит так (черновой, но рабочий вариант):
Код: Выделить всё
    ' Обрабатываем скачанный файл
    Dim I As Integer
    Dim CurrMajor As Integer, CurrMinor As Integer, CurrRevision As Integer, CurrBuild As Integer
    Dim Major As Integer, Minor As Integer, Revision As Integer, Build As Integer
    Dim sInputJson As String
    Dim Version As String
    Dim DownloadLink As String
    Dim VerArr() As String
    Dim p As Object
   
    ' Версия программы
    Dim strFile As String
    Dim udtFileInfo As FILEINFO
   
    strFile = String(255, 0)
    GetModuleFileName 0, strFile, 255
   
    If DesignMode Then szTempFileName = "D:\Projects\vbasic\Projects\Configurator\update"
   
    ' Считываем файл и декодируем его
    sInputJson = FromUTF8(LoadFromJSONFile(szTempFileName))

    ' Производим разбор данных из файла
    Set p = JSON.parse(sInputJson)

    Debug.Print "p.Count = " & CStr(p.Count)
   
    ' Ищем запись, имеющую необходимый GUID в поле ProgID
    For I = 1 To p.Count
   
        If (ProgramGUID = p.Item(I).Item("ProgID")) Then
       
            ' Считываем информацию о версии
            Major = p.Item(I).Item("Major")
            Minor = p.Item(I).Item("Minor")
            Revision = p.Item(I).Item("Revision")
            Build = p.Item(I).Item("Build")
            DownloadLink = p.Item(I).Item("DownloadLink")
           
            Debug.Print "Major = " & CStr(Major)
            Debug.Print "Minor = " & CStr(Minor)
            Debug.Print "Revision = " & CStr(Revision)
            Debug.Print "Build = " & CStr(Build)
            Debug.Print "DownloadLink = " & DownloadLink
           
            ' Узнаём свою текущую версию
            If GetFileVersionInformation(strFile, udtFileInfo) = eNoVersion Then
               
                CurrMajor = Major
                CurrMinor = Minor
                CurrRevision = Revision
                CurrBuild = Build
           
            Else
               
                VerArr = Split(udtFileInfo.FileVersion, ".")
               
                ' Косвенно проверяем формат своей версии
                If (UBound(VerArr) = 3) Then
               
                    CurrMajor = CInt(VerArr(0))
                    CurrMinor = CInt(VerArr(1))
                    CurrRevision = CInt(VerArr(2))
                    CurrBuild = CInt(VerArr(3))
                   
                Else
               
                    CurrMajor = Major
                    CurrMinor = Minor
                    CurrRevision = Revision
                    CurrBuild = Build
               
                End If
               
            End If
           
            Dim NeedUpdate As Boolean
           
            NeedUpdate = False
           
            ' Если текущая версия устарела, то выводим сообщение об этом
            If CurrMajor >= Major Then
               
                If CurrMinor >= Minor Then
                   
                    If CurrRevision >= Revision Then
                       
                        If CurrBuild >= Build Then
                           
                        Else
                           
                            NeedUpdate = True
                           
                        End If
                   
                    Else
                       
                        NeedUpdate = True
                       
                    End If
                   
                Else
                   
                    NeedUpdate = True
                   
                End If
           
            Else
           
                NeedUpdate = True
               
            End If
           
            ' Спрашиваем и качаем дистрибутив
            If NeedUpdate = True Then
           
                Dim vbRes As Integer
               
                vbRes = MsgBox("Доступно обновление:" & _
                    vbCrLf & vbCrLf & _
                    "Новая версия: " & CStr(Major) & "." & CStr(Minor) & "." & CStr(Revision) & "." & CStr(Build) & vbCrLf & _
                    "Текущая версия: " & CStr(CurrMajor) & "." & CStr(CurrMinor) & "." & CStr(CurrRevision) & "." & CStr(CurrBuild) & _
                    vbCrLf & "Загрузить обновление?", _
                    vbYesNo + vbQuestion, APP_NAME)
               
                Select Case vbRes
               
                    Case vbYes
                   
                        Dim FileName As String
                   
                        SaveFileDialog.FileName = MiscExtractPathName(DownloadLink, False, "/")
                        SaveFileDialog.DialogTitle = "Сохранить файл..."
                        SaveFileDialog.DefaultExt = ""
                        SaveFileDialog.Filter = "Все файлы (*.*)|*.*"
                        SaveFileDialog.FilterIndex = 1
                        SaveFileDialog.MaxFileSize = 32767
                        SaveFileDialog.InitDir = CurrentDir
                        SaveFileDialog.CancelError = True
                       
                        SaveFileDialog.ShowSave
                   
                        FileName = SaveFileDialog.FileName
                       
                        If FileName <> "" Then
                                           
                            ' Пытаемся скачать файл
                            Kachalka.DownloadToFile DownloadLink, FileName
                   
                        End If
                       
                    Case vbNo
                   
               
                End Select
               
            End If
           
            Result = True
       
        End If
       
    Next
   
    ' Удаляем временный файл
    If DoesFileExist(szTempFileName) Then DeleteFile szTempFileName
       
    Set p = Nothing
       
    DoAutoUpdate = Result



Парсим, сверяем GUID, считываем поля, узнаём собственные поля версии, проверяем корректность формата версии, сравниваем версии, спрашиваем пользователя о дальнейшем действии, спрашиваем место куда сохранить, скачиваем.

Вот собственно и всё, что я хотел знать. За кадром я оставил многие функции. Когда отлажу свой вариант автообновления, то, наверное, выложу свой "кирпич", который бы моделировал это дело. Хотелось бы, конечно, освоить запуск скачанного файла. Также у меня использован нехороший вариант скачивания в главном потоке, но эти мелочи каждый может доделать сам, используя тему про "качалку".

У меня также остались мысли по доработке формата файла "upgrade". Дело в том, что хранить версию можно по-разному и не плохо было бы иметь поле типа версии и обрабатывать остальные поля в зависимости от типа (бывает в версии включают дату). Если делать свой класс, то обработку сравнения особых случаев можно отдавать пользователю, но это на будущее.

П.С. Я забыл сказать, что у меня на форме есть специальный таймер, с помощью которого я запускаю автообновление. Не знаю как у других, у меня пробуется скачка каждый час, если включено автообновление и выбрана периодичность - каждый день. Для других периодичностей технология другя - мы запоминаем дату попытки и при каждом запуске приложения проверяем разницу между текущей и сохранённой датами. Превысили период - запускаем таймер. И так по кругу. Хотя до сравнения дат я ещё не дошёл.
Россия навсегда!
Сетрификаты

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Re: Как правильно организовать автообновление через сеть

Сообщение alibek » 29.07.2011 (Пт) 8:39

1. Использовать для парсинга JSON скриптовый движок Windows — это overkill.
2. Слишком много воды про GUID. Я так и не понял, есть там что-то сверх того, что GUID обеспечивает уникальный идентификатор для однозначной идентификации своего предмета интереса. Если ничего сверх этого нет, то и генерировать его в коде незачем.
3. "Прежде чем начать, мы должны проверить наличие соединения." — глупо. Не нужно проверять "наличие подключения к интернету", нужно просто начать процедуру обновления и отслеживать ошибки.
4. update-файл как раз вполне логично было бы считывать в память, а не во временный файл.
5. Действия автообновления должны различаться в случае обновлений мажорной и минорных версий. Во-всяком случае должна быть такая опция.
6. Если уж на то пошло, то можно также учесть, что теоретически CInt(VerArr(0)) может сгенерировать ошибку (т.к. номера версий в VERSIONINFO беззнаковые).
7. "Лестничный марш" из If...EndIf при проверки версий лишний. Если уж ты запрашиваешь VERSIONINFO, то и сравнивай мембер FILEVERSION, как число, одно сравнение лучше, чем четыре.
Lasciate ogni speranza, voi ch'entrate.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Re: Как правильно организовать автообновление через сеть

Сообщение uni » 29.07.2011 (Пт) 12:46

Спасибо за рекомендации по сути. Будем исправлять.

По поводу отслеживания ошибки подключения. Я не овладел ещё азами использования Качалки, чтобы перенести всю заботу по этому поводу на неё. Поэтому ещё до её использования сразу обхожу такой вариант развития событий.

Может быть тут есть у кого-нить обработка ошибок? На случаи: нет соединения, не найден файл, обрыв соединения и т.д., если ещё есть что-нить.

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

По поводу VERSIONINFO. Я использую чужую функцию и не переделал её для получения чисел. Она в таком виде как я её взял выдаёт сборку в виде строки. Потому я и делю всё обратно на части. Сильно не вдавался в её код, но походу она читает ресурсы при помощи VerQueryValue() и в строковый буфер возвращает скомпонованный вариант версии. Чтобы получать числа, нужно переписывать всё это дело.

1. Использовать для парсинга JSON скриптовый движок Windows — это overkill.

Ну не писать же мне свой парсер. Пошукав в инете я нашёл только такой вариант. Хоть он, конечно, не идеален, но работает. У меня импорт/экспорт идёт в этом формате для файлов программы. До XML'я я уж решил не добираться, т.к. структура JSON'а вполне подходит для моего применения. Если есть ещё какие-нибудь общедоступные современные "хранители" содержимого проектов, а-ля XML, то мне интересно было бы узнать как с ними работать на VB6. Вообще же, программка изначально была небольшой тулзой, но с расширением функциональности решил когда-то перейти на VB.Net, чтобы не мучится. Привязка к бейсику идёт от заказчика, который кроме бейсика ничего не учил. Так бы я конечно на C# наваял или на Java. Там хоть мучений с отладкой и IDE нет, но свои сложности тоже имеются.
Россия навсегда!
Сетрификаты

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Как правильно организовать автообновление через сеть

Сообщение Хакер » 29.07.2011 (Пт) 13:54

uni писал(а):Ну не писать же мне свой парсер. Пошукав в инете я нашёл только такой вариант. Хоть он, конечно, не идеален, но работает.

Философия мусорщика.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Re: Как правильно организовать автообновление через сеть

Сообщение uni » 30.07.2011 (Сб) 14:27

Хакер, твоё мнение по ЭТОМУ вопросу мне не интересно. Объясняю по-рабочекрестьянски. Если мне нужно будет специально для проекта написать парсер, то я его напишу.

Вот пример моего парсера: Parser.java (utf8)
Этот парсер является частью программы, которая уже год проработала в "боевом" круглосуточном режиме.

Что касается моей компетенции по теретической части:
Удостоверение №45368 по программе "Разработка компиляторов"

Так что, Хакер, твоё мнение тут неуместно с моей точки зрения. Как я уже говорил: надо - напишу, надо - пройду курс самообучения, надо будет :) найду способ добыть знания. А не надо - возьму и буду использовать чужое, если оно с моей точки зрения в данный момент подходит лучше.

Мне, кстати, для одного моего проектика как-то предлагали JSON формат, но он мне не подошёл, поэтому я и написал свой парсер и придумал свою грамматику. Эт я тебе по хорошему отвечаю :)
Россия навсегда!
Сетрификаты

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Как правильно организовать автообновление через сеть

Сообщение Хакер » 30.07.2011 (Сб) 14:31

Почему люди в такой ситуации бросаются доказывать, что они способны (able) написать упомянутое — ума не приложу. Наверное какие-то комплексы.

Оспаривалась не твоя способность или неспособность написать что-то, а твоя философия, твой способ выбирать между «написать» и «найти готовое».

uni писал(а):Удостоверение №45368 по программе "Разработка компиляторов"

Лол. Как сам факт запощщивания сюда этой ссылки, так и контент.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Re: Как правильно организовать автообновление через сеть

Сообщение uni » 30.07.2011 (Сб) 14:42

Хакер писал(а):Почему люди в такой ситуации бросаются доказывать, что они способны (able) написать упомянутое — ума не приложу. Наверное какие-то комплексы.


Потому что говном кидаться каждый дурак может, а чтобы приличным человеком остаться, приходится не кидаться говном в ответ. Так вот. Мои ссылки содержат продуктив:
- ИНТУИТ - кто не знает, пройдёт дальше и может наткнуться на интересные видео-лекции по разным сторонам программирования в том числе;
- Парсер - пример простого парсера на Java - именно с него я делал пример для местного моего калькулятора, который, как я видел, куда лучше всех Ваших тут поделок и твоей в том числе. Это пример полного парсера, тот что я портировал на бейсик является усечённой версией, т.к. не поддерживает работу с векторами и массивами.

Оспаривалась не твоя способность или неспособность написать что-то, а твоя философия, твой способ выбирать между «написать» и «найти готовое».

П.С. Для человека, который способен преодолеть стереотип англоязычности (это я про себя), посыл звучит странно. Я сторонник "философии", которая объясняет наше (отечественное, российское) отставание англоязычностью доступных ресурсов. Все те, у кого английский язык не является государственным, вынуждены тратить несколько лет своей биологической жизни на то, чтобы овладеть английским. Те же, к кого он государственный тратят ЭТО ЖЕ САМОЕ время на что-то иное. Т.о. по закону больших чисел мы никогда не догоним англоязычное сообщество в IT сфере просто потому, что начальные условия в этой задачке НЕ РАВНЫ.
Поэтому я писал свой парсер на РУССКОМ языке. Для человка с ярлыком "мусорщик" это явно странновато. Или у тебя и на этот случай есть свой ярлык? И всякие остальные?
Россия навсегда!
Сетрификаты

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Re: Как правильно организовать автообновление через сеть

Сообщение Viper » 31.07.2011 (Вс) 8:32

uni, есть мнение: не переходить на личности и не разводить оффтоп.
Весь мир матрица, а мы в нем потоки байтов!

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Re: Как правильно организовать автообновление через сеть

Сообщение uni » 04.07.2012 (Ср) 16:49

На основе пассивного метода автообновления я написал Сервер Обновлений с поддержкой активного метода с ведением статистики.
Исходник проекта всегда можно посмотреть тут: https://mysvn.ru/schoolbell/updserv/ (клиенты svn могут посмотреть любую версию и ревизию).
Руководство будет дописано там же в файле: https://mysvn.ru/schoolbell/updserv/help/updserv.chm

Протокол обмена информацией такой:
1. Программа посылает по известному адресу UTF8 посылку в формате JSON такого вида:
Код: Выделить всё
{"ProgID":"{E6A32F50-03B3-49ae-9C9B-ED435284D4A0}"}

где GUID - это идентификатор сервера. Этот GUID используется также как и версия протокола обмена.
Назначение посылки - сделать запрос на выдачу информации об обновлениях.

2. Сервер, приняв запрос, посылает ответ в том же формате (см. картинку), где указана информация о наличии обновлений ПО. В данном случае на сервере один дистрибутив.

Как это выглядит можно посмотреть на прикрепленной картинке, либо установив тестовый дистрибутив. Только после установки в этой версии нужно ручками скопировать report_empty.mdb в report.mdb, чтобы статистика работала правильно. Я этого ещё не дописал.

В общем, это для тех, кому интересно как бы могла выглядеть процедура автообновления на практике для своих небольших программ. Остальное см. в коде. Написано всё на VB6, но всё то же можно сделать и на любом другом языке или даже страничке php.

Примечания:
1. Кнопочки редактирования записей о программах пока не работают. Эта информация берётся из файла, который я приложил к посту. Его лучше положить к папку установки. Этот файл я пока ручками заполняю, а потом загружаю в программу.
2. Файл с базой report.mdb должен быть также внутри папки с программой. Пустая база входит в дистрибутив, можно просто скопировать.
3. Мой комп включен не всегда, поэтому доступ к дистрибутиву будет также не всегда, в отличие от репозитория с исходным кодом.
4. Кстати, программа клиент, которая работает по этому протоколу также доступна по ссылке на картинке. Там есть Журнал в меню и можно посмотреть как выглядит всё это со стороны клиента.
Вложения
Answer.PNG
Ответ сервера обновлений
ServUpdate_Screen.png
Главное окно
update.zip
Пример файла обновлений
(411 байт) Скачиваний: 356
Россия навсегда!
Сетрификаты


Вернуться в Раздел для Профессионалов

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 6

    TopList