npm package: @sempasha/gzippo
Description: Сканирует исходную директорию, каждый файл в этой директории будет сжат с помощью GZip и сохранён в другую директорию
Latest version: 0.0.1

gzippo
---

Сканирует исходную директорию, каждый файл в этой директории будет сжат с помощью GZip и сохранён в другую директорию.

# Как работает

В работе утилиты можно выделить две стадии:

  1. Сканирование директории;
  2. Сжатие файлов.

Во время сканирования директории составляется список задач на сжатие файлов, задачи записываются в БД PostgreSQL.
После завершения сканирования выполнение задач на сжатие файлов. Один процесс единовременно может выполнять лишь одну
задачу на сжатие файлов. Результат выполнения каждой задачи регистриурется в БД.

Чтобы сжимать одновременно несколько файлов можно запустить несколько процессов в одинаковым набором параметров. Стоит
отметить, что сканирование директории при запуске нескольких процессов будет выполняться только одним из них,
остальные будут ждать результатов сканирования и начнут обрабатывать задачи на сжатие файлов сразу после завершения
сканирования.

## Саканирование директории

  1. Выполняется проверка - было ли выполнено сканирование директории ранее (проверяется существование списка задач
     в БД). Если список задач уже существует и не требуется повторное сканирование директории (см. параметр
     `--rebuild`), то сканирование считается выполненным;
  1. В БД регистрируется список задач и эта запись блокируется от чтения и записи;
  1. Выполняется сканирование директории, для каждого найденного файла в БД добавляется задача на сжатие файла.
     В задаче указывается, какой файл надо прочитать и куда положить результат;
  1. После того, как сканирование завершено и все задачи на сжатие файлов зарегистрированы блокировка со списка задач
     снимается. Сканирование считается выполненным.

**Важно!**
В директории с исходными файлами могут встречаться ссылки на другие директории.
Чтобы избежать рекурсивного сканирования мы пропускаем:

  1. Ссылки на директории, которые содержат внутри себя директорию с исходными файлами;
  1. Ссылки на директории, которые сами содержатся внутри директории с исходными файлами.

## Сжатие файла

  1. Получение задачи на сжатие файла - будет выбрана любая из невыплненных задач. Задачи, которые выполняются в
     другом процессе (записи этих задач заблокированы), не участвуют в выборе. Если не найдено ни одной задачи,
     то процесс завершает работу;
  1. Запись в базе данных соответствующая задаче блокируется от чтения и записи;
  1. Проверяется наличие директории, куда надо сохранить конечный файл. Если директории нет,
     то предпринимается попытка создать её;
  1. Исходный файл открывается на чтение, выполняется его сжатие с записью в конечный файл,
     расположенный в другой директории;
  1. Результат выполнения задачи регистрируется в БД, блокировка с записи снимается;
  1. Если по ходу выполнения задачи происходит ошибка (нет исходного файла, нет прав на его чтение, возникли проблемы с
     созданием целевой директории или с записью в конечный файл), ошибка выполнения задачи так же регистрируется в БД
     и блокировка снимается с записи.

# Установка

## Docker Compose

```
curl -o docker-compose.yml https://raw.githubusercontent.com/sempasha/gzippo/master/docker-compose.yml
docker-compose pull
```

## NPM

Глоабальная установка

```
npm install -g @sempasha/gzippo
```

На Linux, при глобальноу установке от root могут позникнуть проблемы при установке модуля
[dtrace-provider](https://www.npmjs.com/package/dtrace-provider), возникает ошибка
`Error: EACCES: permission denied, mkdir '/usr/lib/node_modules/@sempasha/gzippo/node_modules/dtrace-provider/build'`.
В этом случае можно применить [грязный костыль](https://stackoverflow.com/a/52146502/1075298).

```
sudo npm install -g --unsafe-perm=true @sempasha/gzippo
```

# Использование

## Docker Compose

Содайте .env файл в котором укажите из какой директории нужно взять файлы для сжатия и
в какую директорию их надо положить:

```
echo 'GZIPPO_SOURCE=/source' > .env
echo 'GZIPPO_DESTINATION=/destination' >> .env
```

Можно запускать сервис

```
docker-compose up -d 
```

Чтобы запустить несколько инстансов сервиса gzippo (например, 3):

```
docker-compose up -d --scale gzippo=3 
```

## CLI

```
gzippo [options] [source] <destination>
```

Например, сжать все файлы в текущей директории и поместить сжатые файлы в директорию `/destination/path`:

```
gzippo /destination/dir
```

Или

```
gzippo . /destination/dir
```

Можно сжать файлы в любой директории на хосте:

```
gzippo /source/dir /destination/dir
```

**Важно!**
Директория, в которую необходимо сохранить файлы не должна располагаться внутри директории с исходными файлами.

## Параметры запуска

Все параметры могут быть заданы, как с помощью параметров команды (`[OPTIONS]`), так и с помощью переменных окружения.
Переменные окружения имеют приоритет ниже, чем параметры команды.

Использование параметра `--param-name`:
```
gzippo --param-name value /destination/dir
```

Использование переменной окружения `GZIPPO_PARAM_NAME` вместо параметра `--param-name`:
```
env GZIPPO_PARAM_NAME=value gzippo /destination/dir
```

Если одновременно указать и параметр и переменную окружения, то переменная окружения будет иметь более низкий приоритет:
```
env GZIPPO_PARAM_NAME=value1 gzippo --param-name value2 /destination/dir
```
В этом примере параметр будет иметь значение `value2`

### Хост

Параметр: `--hostname`

Переменная оркужения: `GZIPPO_HOSTNAME`

Значение по умолчанию: Название хоста

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

### PostgreSQL URL

Параметр: `--pg-url`

Переменная оркужения: `GZIPPO_PG_URL`

Значение по умолчанию: `postgresql://postgres:postgres@localhost:5432/postgres`

Адрес для подключения к PostgreSQL.

### Повторное сканирование

Параметр: `--rebuild`

Переменная оркужения: `GZIPPO_REBUILD`

Значение по умолчанию: (нет)

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

# Запуск тестов

```
git clone git@github.com:sempasha/gzippo.git
cd gzippo
docker-compose -f docker-test.yml pull
docker-compose -f docker-test.yml run gzippo 
```

# Разработка

```
git clone git@github.com:sempasha/gzippo.git
cd gzippo
docker-compose -f docker-dev.yml pull
docker-compose -f docker-dev.yml run gzippo bash 
```

# TODO

  1. Добавить тесты для СLI интерфейса (параметры, запуск нескольких процессов и т.д.);
  1. Добавить опцию определяющую владельца созданных директорий и файлов, а так же права на доступ к ним.
     Так же можно сохранять исходного владельца и права (при возможности).
     При запуске в контейнере эта проблема так же актуальна (если dockerd запускает контейнеры от root);
  1. Можно добавить параметр для определения уровня сжатия;
  1. Запуск нескольких процессов с флагом `--rebuild` приводит к тому,
     что все эти процессы будут перестраивать список задач.
     Можно придумать какой-то критерий,
     который позволит производить обновление списка задач при его выполнении,
     Например, время, прошедшее с последнего обновления;
  1. Обновление списка задач можно производить таким образом,
     чтобы не выполнять уже выполненные задачи повторно.
     Но в этом случае скорее всего придется считать контрольные суммы или хэши у файлов;
  1. Для контроля над потоками сжатия проще использовать очереди (RabbitMQ), нежели блокировки в БД.