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

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

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

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

Итак, storacle использует расширяемый механизм для организации сети. Основные характеристики:

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

Простой пример того, как это работает из программы:

Сервер:

const Node = require('storacle').Node;

(async () => {
  try {
    const node = new Node({
      port: 4000,
      hostname: 'localhost'
    });
    await node.init();
  }
  catch(err) {
    console.error(err.stack);
    process.exit(1);
  }
})();

Клиент:

const Client = require('storacle').Client;

(async () => {
  try {
    const client = new  Client({
      address: 'localhost:4000'
    });
    await client.init();
    const hash = await client.storeFile('./my-file');
    const link = await client.getFileLink(hash);    
    await client.removeFile(hash);

  }
  catch(err) {
    console.error(err.stack);
    process.exit(1);
  }
})();

Краткий обзор

Ничего сверхъестественного под капотом нет. Информация о количестве файлов, их общем размере и других моментах хранится в in-memory базе данных и обновляется при удалении и добавлении файлов, поэтому нет необходимости часто обращаться к файловой системе. Исключением является включение сборщика мусора при необходимости обращения файлов, а не ограничение их количества. В этом случае вам придется время от времени проходить через хранилище. А работа с большим количеством файлов (скажем, более миллиона файлов) может привести к значительным нагрузкам. Лучше хранить меньше файлов и запускать больше узлов. Если «очиститель» отключен, такой проблемы нет.

Хранилище файлов состоит из 256 папок и 2-х уровней вложенности. Файлы хранятся в папках второго уровня. Итак, если у нас в каждой папке по 1 млн файлов, то их примерно 62500 штук (1000000/sqrt(256)).

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

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

Кэширование

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

Изоморфизм

Клиент написан на javascript и является изоморфным, его можно использовать прямо из браузера.

Вы можете загрузить файл https://github.com/ortexx/storacle/blob/master/dist/storacle.client.js в виде скрипта и получить доступ к window.ClientStoracle или импортировать через система сборки и т.д.

Отложенные ссылки

Интересной особенностью также является «отложенная ссылка». Это ссылка на файл, которую можно получить синхронно, здесь и сейчас, и файл будет подтянут, когда будет найден в хранилище. Это очень удобно, например, когда нужно показать какие-то изображения на сайте. Просто поместите отложенную ссылку в src и все. Можно придумать массу случаев.

API клиента

  • async Client.prototype.storeFile() — сохранение файла
  • async Client.prototype.getFileLink() — получение прямой ссылки на файл
  • asyncClient.prototype.getFileLinks() — получение списка прямых ссылок на файл со всех узлов, где он существует
  • async Client.prototype.getFileToBuffer() — получение файла в качестве буфера
  • async Client.prototype.getFileToPath() — получение файла в файловой системе
  • async Client.prototype.getFileToBlob() — получение файла в виде блоба (для браузерной версии)
  • async Client.prototype.removeFile() — удаление файла
  • Client.prototype.createRequestedFileLink() — создание отложенной ссылки

Экспорт файлов на другой сервер

Чтобы передать файлы на другой узел, вы можете:

  • Просто скопируйте всю папку хранилища вместе с настройками. (это может не сработать в будущем).
  • Скопируйте только папку с файлами. Но в этом случае вам нужно запустить функцию node.normalizeFilesInfo() один раз, чтобы пересчитать все данные и поместить их в базу данных.
  • Используйте функцию node.exportFiles(), которая запускает копирование файлов.

Основные настройки узла

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

  • storage.dataSize — размер папки с файлами.
  • storage.tempSize — размер временной папки.
  • storage.autoCleanSize — минимальный размер хранилища, который вы хотите сохранить. Если указать этот параметр, самые малоиспользуемые файлы будут удаляться, как только не хватит места.
  • file.maxSize — максимальный размер файла.
  • file.minSize — минимальный размер файла.
  • file.preferredDuplicates — предпочтительное количество дубликатов файлов в сети.
  • file.mimeWhitelist — допустимые типы файлов.
  • file.mimeBlacklist — недопустимые типы файлов.
  • file.extWhitelist — допустимые расширения файлов.
  • file.extBlacklist — недопустимые расширения файлов.
  • file.linkCache — настройки кэширования ссылок.

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

Использование командной строки

Библиотеку можно использовать через командную строку. Вам необходимо установить его глобально: npm i -g storacle. После этого вы можете запускать необходимые действия из каталога проекта, где находится нода.

Например, storacle -a storeFile -f ./file.txt -c ./config.js, чтобы добавить файл. Все действия можно найти в https://github.com/ortexx/storacle/blob/master/bin/actions.js

Зачем вам это нужно

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

Мои контакты: