Agency Docs
QBESX

Agency-Pad Хранилище Медиа

Теперь с AgencyOS27: бесплатное обновление для всех, у кого уже есть планшет.

v27.1.1Платно7 Страницы

Где хранятся фото, видео и голосовые сообщения

Каждое фото, видеоклип, запись экрана и голосовое сообщение из Agency Pad сохраняется самим скриптом, начиная с версии 27.1.1. Место хранения выбираете Вы:

ХранилищеНастройкаПодходит для
Локальное (по умолчанию)Не требуется. Работает сразу после установки.Любых серверов. Файлы остаются на Вашем сервере, в Вашей базе данных.
Cloudflare R2Около 10 минут, один раз. Бесплатно до 10 ГБ.Серверов с большим объёмом видео или очень большим числом игроков.

Fivemanage и Discord больше не используются как хранилище. Вебхуки Discord по-прежнему доступны для логов.

Локальное хранилище (по умолчанию)

Ничего настраивать не нужно. При первом запуске скрипт создаёт в Вашей базе данных две таблицы (agency_media и agency_media_parts) и хранит файлы в них. Нужен только oxmysql, который скрипту в любом случае необходим.

Что это значит для Вас:

  • Никакого аккаунта, API-ключа и дополнительного ресурса. Ничего не работает за пределами Вашего сервера.
  • Обновления безопасны. Файлы лежат в базе данных, а не в папке ресурса, поэтому замена папки при обновлении сохраняет все фото.
  • Резервные копии базы данных включают медиафайлы. База вырастает примерно на треть больше, чем сами файлы. Одно фото занимает около 150 КБ.
  • Agency Phone и Agency Pad используют общее хранилище. Фото, сделанное в одном из них, появляется и в другом, включая фото, синхронизированные с Agency Cloud.
  • Приложение Agency Companion тоже показывает их на iOS, Android и в веб-версии. Для этого также ничего настраивать не нужно.

Скорость

Файлы передаются через само соединение FiveM, не блокируя игру. FiveM ограничивает скорость, с которой игрок может отправлять данные на сервер (около 165 КБ в секунду), поэтому:

ЧтоСохранение занимает около
Фото1 секунды
Голосовое сообщениеменее 1 секунды
Видеоклип на 15 секунд20 секунд (камера показывает прогресс в процентах)

Показ файла другим игрокам происходит быстро, целый клип приходит за несколько секунд. Если на Вашем сервере записывается много видео, Cloudflare R2 сохраняет клипы почти мгновенно.

Настройки в config.lua

AgencyPadConfig.MediaStorage = {
    Provider = 'local',                -- 'local' или 'cloudflare'

    MaxFileMegabytes = 10,             -- самый большой отдельный файл (клипы, записи)
    TransferKilobytesPerSecond = 1000, -- 'local': с какой скоростью файлы отправляются игрокам

    Local = {
        RetentionDays = 30,            -- удалять файлы старше этого срока (0 = хранить вечно)
        MaxStorageGigabytes = 10,      -- удалять самые старые файлы сверх этого объёма (0 = без лимита)
    },
}
ПараметрЧто делает
RetentionDaysФайлы старше этого срока автоматически удаляются раз в час. Удалённое фото отображается в галерее небольшой заглушкой. Укажите 0, чтобы хранить всё.
MaxStorageGigabytesКогда все файлы вместе превышают этот объём, сначала удаляются самые старые. Укажите 0, чтобы снять ограничение.
MaxFileMegabytesФайлы большего размера отклоняются. Также ограничивает видеоклипы и записи экрана.
TransferKilobytesPerSecondСкорость на одного игрока при отправке файлов игрокам. У игры всегда приоритет.

Cloudflare R2, шаг за шагом

Cloudflare R2 бесплатен до 10 ГБ хранилища, 1 миллиона загрузок и 10 миллионов скачиваний в месяц, а скачивания не стоят ничего никогда. При включении R2 Cloudflare запрашивает способ оплаты, даже для бесплатного тарифа. Вы платите только в том случае, если превысите бесплатные лимиты.

1. Включите R2

  1. Войдите на dash.cloudflare.com (достаточно бесплатного аккаунта).
  2. В меню слева откройте Storage & databases, затем R2 Object Storage.
  3. Добавьте подписку R2. В обзоре к оплате сейчас указано $0.00. Примите условия и нажмите Activate.

2. Создайте бакет

  1. Нажмите Create bucket.
  2. Задайте имя, например myserver-media. Позже имя изменить нельзя.
  3. Оставьте расположение Automatic, а класс хранения Standard.
  4. Нажмите Create bucket.

3. Сделайте файлы доступными для просмотра

  1. Откройте свой бакет и перейдите в Settings.
  2. В разделе Public Development URL нажмите Enable, введите allow и подтвердите.
  3. Скопируйте появившийся адрес, он выглядит как https://pub-1a2b3c….r2.dev. Это Ваш PublicUrl.

Cloudflare ограничивает адрес r2.dev для очень загруженных серверов. Если у Вас есть собственный домен в Cloudflare, Вы можете добавить его в разделе Custom Domains там же и использовать этот адрес как PublicUrl.

4. Разрешите загрузку из игры

  1. Оставаясь в Settings, найдите CORS Policy и нажмите Add.
  2. Удалите всё в текстовом поле, вставьте следующее и нажмите Save:
[
  {
    "AllowedOrigins": ["https://cfx-nui-agency-phone", "https://cfx-nui-agency-pad"],
    "AllowedMethods": ["PUT", "GET"],
    "AllowedHeaders": ["*"],
    "MaxAgeSeconds": 3600
  }
]

Без этого шага игра не сможет загружать файлы, и фото не будут сохраняться. Если Вы переименовали папку ресурса, укажите имя своей папки после cfx-nui-.

5. Создайте ключ

  1. Вернитесь в R2 Object Storage и нажмите Manage API tokens.
  2. Нажмите Create API token (подойдёт токен аккаунта).
  3. Разрешения: Object Read & Write.
  4. В выборе бакета укажите только Ваш бакет.
  5. Нажмите Create. Cloudflare показывает Access Key ID и Secret Access Key только один раз, скопируйте оба прямо сейчас.
  6. Account ID показан в обзоре R2, а также это первая часть S3-адреса (https://<Account ID>.r2.cloudflarestorage.com).

6. Введите данные в скрипт

Ключи вносятся в config_server.lua. Этот файл читает только сервер, игрокам он никогда не отправляется. Не вносите ключи в config.lua: этот файл отправляется каждому игроку.

-- config_server.lua
AgencyPadServerConfig.Cloudflare = {
    AccountId       = 'your account id',
    Bucket          = 'myserver-media',
    AccessKeyId     = 'your access key id',
    SecretAccessKey = 'your secret access key',
    PublicUrl       = 'https://pub-1a2b3c....r2.dev',
}

Затем укажите провайдера в config.lua и перезапустите ресурс:

AgencyPadConfig.MediaStorage = {
    Provider = 'cloudflare',
    ...
}

Теперь консоль сервера показывает Media: storage: Cloudflare R2, bucket myserver-media. Если чего-то не хватает, консоль сообщит, чего именно, а скрипт продолжит сохранять файлы локально, пока проблема не будет устранена, так что камера никогда не перестаёт работать.

Используете Agency Phone и Agency Pad вместе? Оба могут работать с одним и тем же бакетом и одним и тем же ключом, каждый хранит свои файлы в собственной папке.

Проверьте, что всё работает

Выполните это в консоли сервера (или от имени администратора в игре), указав ID игрока, который находится онлайн:

padmediatest 1

Agency Pad игрока сохраняет небольшое тестовое изображение, загружает его обратно так же, как это сделал бы любой другой игрок, показывает его и воспроизводит короткое голосовое сообщение. Консоль отвечает:

Media test passed for player 1 in 1361 ms: upload ok, download ok, shown as picture ok, app markup and backgrounds ok, voice message plays ok

Добавьте big, чтобы дополнительно проверить видеоклип размером 6 МБ: padmediatest 1 big.

Проблемы и решения

Что Вы видитеРешение
could not create the media tables в консолиoxmysql не запущен или не может подключиться к базе данных. Запустите oxmysql до agency-pad.
Provider is 'cloudflare', but config_server.lua is missing ...Одно из пяти значений пусто, или PublicUrl не начинается с https://. Проверьте шаг 6.
Фото не сохраняются, ошибка Cloudflare HTTP 403У ключа нет права записи в этот бакет, или имя бакета указано неверно. Проверьте шаг 5.
Фото не сохраняются, ошибка Failed to fetch при работе с CloudflareПолитика CORS из шага 4 отсутствует или в ней указано другое имя ресурса.
Сохранённые фото не отображаются при работе с CloudflarePublic Development URL из шага 3 выключен, или PublicUrl указывает на другой бакет.
Видео сохраняется долгоЭто нормально для локального хранилища, см. раздел «Скорость» выше. Для мгновенного сохранения клипов используйте Cloudflare R2.
Старые фото пропалиИх удалил параметр RetentionDays. Увеличьте значение или укажите 0.

Переход с Fivemanage или Discord

Переносить ничего не нужно. Ранее сохранённые фото сохраняют свои старые ссылки и остаются видимыми, пока соответствующий сервис продолжает их отдавать. Всё новое попадает в выбранное Вами хранилище. Старые параметры MediaStorageProvider, FiveManageApiUrl, FiveManageApiKey и ScreenshotWebhook игнорируются, и их можно удалить из конфигурации.

Безопасность

  • Загружать файлы могут только игроки, подключённые к Вашему серверу. Каждая загрузка предварительно объявляется и проверяется по типу и размеру.
  • Содержимое проверяется по первым байтам. Веб-страницу или скрипт невозможно сохранить под видом фото.
  • Имена файлов представляют собой 128-битные случайные значения, их нельзя угадать или получить списком.
  • Загрузки и скачивания ограничены на каждого игрока.
  • В случае Cloudflare каждая загрузка получает собственную ссылку, действительную 5 минут, ровно для одного файла одного типа и одного размера. Секретный ключ никогда не покидает Ваш сервер.

После этой страницы всё ещё не получается? Дальше подключается наша поддержка.