Как стать автором
Обновить

Комментарии 58

все гениальное просто :)
спасибо, возьму на заметку
а что будет, если файл создан, но продолжает, скажем, загружаться?
Хороший вопрос. Я это предусмотрел — в обработчике FileSystemWatcher файл пытается открыться на чтение. Если он еще загружается — получаем эксепшен(виндовая ошибка ERROR_SHARING_VIOLATION). Прога уходить в слип на секунду, после чего пытается еще раз открыть ну и т.д. Если за установленое количество попыток ничего не получилось — оставляем архив в покое, пусть кто-нибудь другой разбирается. Для себя количество попыток я установил до дури(int.MaxValue), вы можете поставить другое значение.

Собственно код вы можете найти в функции WatcherHandler
IOUtils.WrapSharingViolations(() => { using (File.OpenRead(file));}, null, int.MaxValue, 1000);

* This source code was highlighted with Source Code Highlighter.

И в утилитном класс IOUtils, там, правда, немного мутно из-за необходимости отличать ERROR_SHARING_VIOLATION в IOException от остальных ошибок доступа.
Там бы еще неплохо многопоточную обработку вотчера прикрутить, чтобы не подвисало в ожидании закачки, но пока пользователей(а пока пользователь только я=)) все и так устраивает.
А вызовы раз в секунду не слишком грузят компьютер?
И еще: с запароленными архивами проблем нет?
Раз в секунду — нет, не грузят. Один кол OpenFile в раз секунду вы даже на таскменеджере не увидите.

И еще: с запароленными архивами проблем нет?

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

Ну если в архиве лежит папка, то будет в результате папка с подпапкой — имя_архива/имя_подпапки. Так же, как если через контекстное меню распаковать.
Надо еще сделать так, чтобы он удалял архив после распаковки. Т.е. запаковываешь что-нибудь в архив, а оно распаковывает обратно, да еще и архив сносит)) Прекрасное издевательство над пользователями.
Полагаю, запаковывать что-либо нужно в любую другую папку, отличную от тех, что указаны в настройках сервиса. Те папки исключительно для распаковки.
Надо еще сделать так, чтобы он удалял архив после распаковки.

Я думал над этим, но с другой стороны кому-то может понадобиться сохранить архив. Например я скачал архив с исходниками, поковырялся с ними и грохнул папку, а архив остался на всякий случай, если снова к ним вернусь. Думаю, может вынести это опцией, но по умолчанию лучше оставлять — удаление операция опасная ввиду нетранзакционности файловой системы на большинстве десктопов.
Боюсь, что защиты нет. Я думал над этим — можно считать хэш-архива и запрещать повторную распаковку, но в некоторых случаях это будет багом для пользователя. Еще можно проанализировать структуру архива на предмет наличия таких бомб, но это уже совсем другой уровень сложности, может позже, когда будет время и желание покопаться в разных форматах архивов. Ну или отказаться от автораспаковки вложенных архивов.
распаковка во вложенную папку? во вложенных папках архивы не распаковывать?
После распаковки в альтернативный поток добавлять метку о том что файл распакован автоматом и больше не распаковывать
во вложенных папках архивы не распаковывать?


Ну я об этом и написал «Ну или отказаться от автораспаковки вложенных архивов.». Но опять же, в нормальной работе(где мы не скачиваем рекурсивные архивы), это может считаться недостатком.

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


Хм. Так я же и написал про «запрещать повторную распаковку». Это может быть плохой вариант — например, я скачал архив, он распаковался, все хорошо. Прошло полгода, я обо всем забыл, заново качаю архив, но в другую папку(которая тоже мониторится). У меня ничего не распаковалось — я пишу разработчику багу. Можно, конечно, ограничить время жизнь хранения хэша архива — например один час. Но все равно, потенциально проблема есть.
Я слишком поздно понимаю, чем мне знакомо это разноцветье.
Глубина-глубина…
Слишком поздно.
Дип-программа накрывает меня, и увернуться нет сил.
Глубина-глубина…
А полотнище все полыхает, не собираясь гаснуть, как положено честной, законопослушной дип-программе…
Глубина-глубина…
Я ныряю все глубже, я падаю в эту цветную пропасть, в бесконечную череду фальшивых отражений, в цветной лабиринт, в безумие и беспамятство.
На моей машине нет таймера, и никто не придет к моей двери со своим ключом.
Глубина-глубина…
Я не могу выныривать с такой скоростью, с какой затягивает цветной водоворот!
Глубина-глубина...
В ОС основанных на ядре Linux это делается так:
1. Устанавливаем unp и убеждаемся в наличии inotify.
2. Запускаем из необходимых каталогов следующий скрипт (не тестировалось):
while true; do
inotifywait -e modify -e moved_to -e create "`pwd`"
unp *
sleep 10 # Во избежание убивания процессра постоянной попыткой распаковать качающийся файл.
done

В других *nix inotify заменяется на имеющееся средство, либо на кроссплатформенную обёртку FAM.
Плюс сервиса в автозагрузке и подъеме системой в случае падения. Ну и к сессии пользователя они не привязаны. Я конечно еще тот знаток никсов, но мне казалось, что если проводить аналогию, это должен быть демон, прописанный в /etc/rc.local и кроновская таска, которая будем за ним следить, поднимая когда он упадет, разве нет? Ну и с точке зрения использования, мне было бы удобнее прописать пути в одном конфиге, чем запускать скрипт из нескольких папок.

Опять же, возможно я не прав, но разве эта команда — unp * — не будет каждый раз, когда мы скачаем новый архив, перераспаковывать заново все уже существующие архивы в папке?
«Плюс сервиса в автозагрузке и подъеме системой в случае падения.»
Что-то я не замечал за windows-сервисами подобного. Обычно если он лег, то он лег, и система его не перезапускает.
Вроде как на 2k3 была такая фича.
Я же говорю — не тестировалось. :)

Возможно надо делать так:
files="*.{zip,rar,tar*, и т.д.}
unp $files
rm $files # или mv $files unpacked/

> если проводить аналогию

Зачем делать сложно если ту же задачу можно решить просто? Да, я понимаю что автру возможно захотелось поупражняться в написании служб на C#.
По поводу простоты — там в проекте лежит и консольное приложение — запускай и все. А если начать вешать доп. требования — автозапуск, настройка из одного места, параллельная распаковка, защита от рекурсивных архивов — то решение сразу усложнится и возможно написать его на том же питоне/C#/Lisp/ваш_любимый_язык_программирования и оформить демоном будет проще.
Я тут еще подумал
inotifywait -e modify -e moved_to -e create "`pwd`"
Вот эта штука будет реагировать на создание/изменению любых файлов, что не очень хорошо: я создал текстовый файл — у меня пошли распаковываться все архивы в папке. А еще в скрипте вложенные архивы не обрабатываются.
Вообще замечательная вещь, как правило во время закачки архвам присваивается временное расширение типа *.!ut так что использование его не так страшно, но все таки хотелось бы защиты от ошибок.
Будет ли данный сервис дорабатываться? Хотелось бы еще опцию автоудаления (если ее нет).
Удачи автору в начинании :)
Будет ли данный сервис дорабатываться?
Будет, если это будет кому-то нужно.
Хотелось бы еще опцию автоудаления (если ее нет).
Сейчас залил новую версию и исходники по мотивам(ссылка в статье):
  1. Добавлена опция автоудаления. По умолчанию автоудаление отключено.
    [Options]
    Autodelete = yes
  2. Сделана многопоточная обработка — если скачалось много архивов, они начинают распаковывать параллельно.
  3. Сделана простая защита от рекурсивных архивов — если архив распакован, повторная распаковка может быть запущена только через 10 минут.
По-хорошему бы батник копировал файлы куда надо еще… а то я вижу что он сейчас только устанавливает сервис из текущей папки
А куда надо? Я могу и инсталлятор сделать, если нужно.
Прогресс бар бы все таки не помешал, или хоть какоето оповещение: Началась распаковка, Успешно распакован, Ошибка, и т.д.

Мне кажется это лишним. Программа должна работать незаметно для пользователя. Я скачал архив — пошел в папку — посмотрел содержимое. А так, что-то всплывает, мигает, рассказывает о своих ошибках и успехах, забирает фокус — мне такие программы не очень нравятся.
И да, еще, [WinRar] это както не правильно :) Заменить бы на [Архиватор] и в том же разделе указывать параметры было бы неплохо

Ну это можно =) Изначально параметры не стал выносить, т.к. хотелось сделать конфиг простым.
Ну хотя бы ведение лога опять же опционально, вместо оповещения…
И в том архиве что поставляется хорошо бы указать все возможные параметры с комментариями. Не нашел где указать Extentions в Options?
И почемуто с 7zip не работает на Win 7 x64
Extentions указывается так

[Extentions]
rar,zip,7z


Но вы правы, перенесу в Options.
И в том архиве что поставляется хорошо бы указать все возможные параметры с комментариями.
ok
И почемуто с 7zip не работает на Win 7 x64
Ну наверно потому, что параметры командной строки не подходят. Секция называлась [WinRar] не спроста — я, ибо ленивый, дал возможность только указать место, где лежит winrar.

Все замечания завтра постараюсь поправить.
Uninstall.bat еще приложите для ленивых, перед обновлением же удалять нужно :)
Не нужно. Можно просто остановить и заменить exe файл. После чего запустить сервис снова.
а, ну да, или так…
Прогресс бар бы все таки не помешал, или хоть какоето оповещение: Началась распаковка, Успешно распакован, Ошибка, и т.д.
И да, еще, [WinRar] это както не правильно :) Заменить бы на [Архиватор] и в том же разделе указывать параметры было бы неплохо
«кстати, кто-нибудь может мне ответить, почему я могу создавать/удалять сервисы только через командную строку?»
Никто не может вам ответить, потому что это неправда. В .net есть специальный компонент для этого, который автоматически создается в проекте при создании проекта сервиса. И в msdn про это написано.
В .net есть специальный компонент для этого, который автоматически создается в проекте при создании проекта сервиса

Вы не правильно поняли вопрос. Я спрашиваю почему в консоли services.msc я не могу создать или удалить сервис, хотя могу сделать это через командную строку.
Потому что незачем, если коротко. Установить сервис — задача того, кто его поставляет.
Надеюсь, что уловил суть вопроса. Возможно, нужно только дописать класс инсталлера. Если хотите создать установшик — вот руководство: wladm.narod.ru/C_Sharp/services.html

Кратко: в проект дописать класс инсталлера
using System.ComponentModel;
using System.Configuration.Install;
using System.ServiceProcess;

namespace AE.Service
{
  [RunInstaller(true)]
  public partial class ExtractorServiceInstaller : Installer
  {
    public ExtractorServiceInstaller()
    {
      var serviceProcessInstaller =
        new ServiceProcessInstaller
        {
          Account = ServiceAccount.LocalSystem,
          Username = null,
          Password = null
        };
      var serviceInstaller =
        new ServiceInstaller
        {
          ServiceName = "My Windows Service",
          DisplayName = "My New C# Windows Service",
          StartType = ServiceStartMode.Automatic
        };

      Installers.AddRange(new Installer[] { serviceProcessInstaller, serviceInstaller });
    }
  }
}


* This source code was highlighted with Source Code Highlighter.

добавить к решению проект типа Setup Project, контекстное->View->Custom Actions; для Install и Uninstall через их контекстное меню выполняем пункт Add Custom Action и указываем System Folder, проследить, чтобы свойство Installer Class у этих Custom Action было выставлено в True.
Да нет, я знаю как сделать установщик. Батник я сделал потому что:

1) Так было проще
2) Хотел показать(может кто не знает), как пользоваться sc.

А вопрос был про то, как мне уже существующие сервисы, как админу, удалить с компа.

Потому что незачем, если коротко. Установить сервис — задача того, кто его поставляет.

Ну во-первых раз у меня возник этот вопрос, значит case есть. Во-вторых, если «задача того, кто его поставляет», чего же тогда в sc у меня есть возможность снести или добавить любой сервис, который мне не нравится? По сути я говорю об отсутствии UI к команде sc(вернее к тому API, который она дергает).
Ну так через установщик можно и удалить.
Ну это же разные вещи. Я говорю про то, что в консоли у меня больше возможностей управления системой, чем в UI и это на мой взгляд не правильно в рамках windows-way, а вы говорите про установщик.
«Ну во-первых раз у меня возник этот вопрос, значит case есть.»
«Ну во-первых раз у меня возник этот вопрос, значит case есть.»
Вот для него и есть sc.

«По сути я говорю об отсутствии UI к команде sc(вернее к тому API, который она дергает). „
Не на всякую чисто административную (и редко используемую) команду есть UI. Это, в среднем, нормально (да, даже в Windows).

Типовое поведение: поставить сервис через инсталлятор, снести через деинсталлятор. Если по типовому сценарию не прошло — тогда есть sc.
Не на всякую чисто административную (и редко используемую) команду есть UI. Это, в среднем, нормально (да, даже в Windows).
Я считаю это вопрос концептуальной целостности. Через services.msc я могу остановить сервис, я могу изменить ему права, я могу сделать так, чтобы он никогда больше не запустился. Вроде как центральная точка управления службами. Но для удаления я должен пользоваться деинсталятором(который мне снесет весь пакет продукта, а не только сервис) либо лезть в командную строку.
«Вроде как центральная точка управления службами. „
Установленными.

“Но для удаления я должен пользоваться деинсталятором(который мне снесет весь пакет продукта, а не только сервис)»
Да, именно так. Потому что только деинсталлятор знает, что будет, если вы снесете только сервис, а все остальное оставите.
Будет все тоже самое, как если бы я его просто остановил навсегда или убил из таскменеджера. Нет?
Не совсем. Его все еще можно достать через сервис-менеджер.
Выслал пример вам личкой
А как решена проблема setup.exe и других подобных имен файлов, часто встречающихся в архивах?
Простите, о какой проблеме идет речь?
Наверное речь идет о том, что в папке распаковки может оказаться два архива, в которых могут лежать файлы с одинаковым именем и расширением, но реально содержащих разные данные.
Ну и при автоматической распаковке файл из одного архива будет затерт файлом из другого.
Ну распаковка идет в папку с именем архива. Так что такая ситуация возникает только если и архивы у нас называются одинаково.
Хм. А зачем понадобились ini-файлы в 2011 году? Чем стандартный App.config не устроил? :)
На мой взгляд ini читается человеком проще, чем xml.
Когда же обновление? :)
Я сейчас немножко уехал в отпуск, а до этого сдавал дела. Постараюсь около 20-го обновить.
Главное чтобы не забросили проект! :)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации