feat: OnlyOffice Standalone integration with S3 direct URLs

 ЧТО СДЕЛАНО:
- Поднят новый standalone OnlyOffice Document Server (порт 8083)
- Настроен Nginx для доступа через office.clientright.ru:9443
- Создан open_file_v3_standalone.php для работы с новым OnlyOffice
- Реализована поддержка прямых S3 URL (bucket публичный)
- Добавлен s3_proxy.php с поддержкой Range requests
- Создан onlyoffice_callback.php для сохранения (базовая версия)
- Файлы успешно открываются и загружаются!

⚠️ TODO (на завтра):
- Доработать onlyoffice_callback.php для сохранения обратно в ОРИГИНАЛЬНЫЙ путь в S3
- Добавить Redis маппинг documentKey → S3 path
- Обновить CRM JS для использования open_file_v3_standalone.php
- Протестировать сохранение файлов
- Удалить тестовые файлы

📊 РЕЗУЛЬТАТ:
- OnlyOffice Standalone РАБОТАЕТ! 
- Файлы открываются напрямую из S3 
- Редактор загружается БЫСТРО 
- Автосохранение настроено  (но нужна доработка callback)
This commit is contained in:
Fedor
2025-11-01 01:02:03 +03:00
parent d7941ac862
commit 269c7ea216
4383 changed files with 282112 additions and 7731 deletions

67
FINAL_STEPS.sh Normal file
View File

@@ -0,0 +1,67 @@
#!/bin/bash
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🚀 ФИНАЛЬНЫЕ ШАГИ - Сохранение и перезапуск"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# 1. Git Commit
echo "📦 Шаг 1: Git Commit..."
cd /var/www/fastuser/data/www/crm.clientright.ru/erv_platform
git add -A
git commit -m "fix: OCR endpoint исправлен /process → /analyze-file
Проблема:
❌ POST http://147.45.146.17:8001/process → 404 Not Found
❌ OCR не работал
❌ Gemini Vision не получал данные
Решение:
✅ Endpoint изменен на /analyze-file (правильный)
✅ Исправлено в 3 местах
✅ Добавлено детальное логирование
Теперь OCR работает!"
git push origin main
echo "✅ Git push выполнен!"
echo ""
# 2. Перезапуск Backend
echo "🔄 Шаг 2: Перезапуск Backend..."
pkill -9 -f "uvicorn app.main"
sleep 2
cd /var/www/fastuser/data/www/crm.clientright.ru/erv_platform/backend
source venv/bin/activate
nohup python -m uvicorn app.main:app --host 0.0.0.0 --port 8100 > ../../erv_platform_backend.log 2>&1 &
sleep 3
echo "✅ Backend перезапущен!"
echo ""
# 3. Проверка
echo "🔍 Шаг 3: Проверка сервисов..."
curl -s http://localhost:8100/health | python3 -m json.tool
echo ""
docker ps | grep frontend
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "✅ ВСЁ ГОТОВО!"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "🌐 Открывай и тестируй:"
echo " http://147.45.146.17:5173"
echo ""
echo "🔍 Смотри логи:"
echo " tail -f /var/www/fastuser/data/www/crm.clientright.ru/erv_platform_backend.log"
echo ""
echo "При загрузке файла увидишь:"
echo " 🔍 Starting OCR for: filename"
echo " 📄 OCR completed: XXX chars"
echo " 🤖 Starting AI analysis"
echo " ✅ AI: policy, confidence: 95%"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

View File

@@ -0,0 +1,222 @@
# ✅ NEXTCLOUD - ИТОГОВОЕ РЕШЕНИЕ МЕДЛЕННОЙ РАБОТЫ
**Дата:** 31 октября 2025
**Проблема:** Медленное открытие файлов для редактирования (25 секунд)
**Решение:** Найдено и применено
---
## 🔍 НАЙДЕННАЯ ПРОБЛЕМА
### **Корневая причина:**
При запросе **одного файла** через PROPFIND, Nextcloud с настройкой `filesystem_check_changes=1`:
1. Проверяет кеш для файла
2. **НЕ находит актуальные данные**
3. Решает обновить кеш
4. **СКАНИРУЕТ ВСЮ РОДИТЕЛЬСКУЮ ПАПКУ** `Documents/Project/`
5. Вызывает `getDirectoryContent()` для S3
6. **Делает LIST запрос к S3 для ~700 подпапок проектов**
7. Каждая подпапка - отдельный HTTP запрос
8. **700 запросов × 30ms latency = 21+ секунда**
### **Почему так происходило:**
```php
// AmazonS3.php line 648
function getDirectoryMetaData($path) {
// Сканирует ВСЮ папку, а не только запрошенный файл!
return $this->getDirectoryContent($path);
}
```
При `filesystem_check_changes=1` Nextcloud хотел убедиться что файл актуален, но вместо проверки одного файла - сканировал всю папку с сотнями проектов!
---
## ✅ РЕШЕНИЕ
### **Отключить filesystem_check для S3 External Storage:**
```bash
docker exec -u www-data nextcloud-fresh php occ files_external:option 1 filesystem_check_changes 0
```
### **Результаты:**
| Показатель | До | После | Улучшение |
|------------|-----|--------|-----------|
| **PROPFIND время** | 24-26 сек | 1.3-1.7 сек | **-94%** 🚀 |
| **Ускорение** | - | - | **x18** |
| **Стабильность** | Скачет | Стабильно | ✅ |
### **Побочные эффекты:**
⚠️ **Новые файлы НЕ видны автоматически**
**Решение:** Периодическое сканирование через cron:
```bash
# Каждые 30 минут - сканируем только новые файлы
*/30 * * * * docker exec -u www-data nextcloud-fresh php occ files:scan --path=/admin/files/crm/crm2/CRM_Active_Files/Documents/Project --shallow
```
---
## 📊 ТЕСТЫ ПРОИЗВОДИТЕЛЬНОСТИ
### Серия из 5 тестов:
```
Тест 1: 1.722s
Тест 2: 1.496s
Тест 3: 1.339s ← лучший
Тест 4: 1.447s
Тест 5: 1.452s
Среднее: 1.49 секунды
```
**Стабильная скорость:** ~1.5 секунды
---
## 🎯 ДОПОЛНИТЕЛЬНЫЕ ОПТИМИЗАЦИИ
### Что уже сделано:
1.**Redis Distributed Cache** - кеш между запросами
2.**PHP Memory 1024MB** - больше памяти
3.**OPcache оптимизирован** - меньше компиляций
4.**MySQL max_connections=300** - больше соединений
5.**Шифрование отключено** - меньше CPU
6.**filesystem_check_changes=0** - без сканирования S3
### CPU/Memory после всех оптимизаций:
```
Nextcloud: 0.05-5% CPU (было 50%)
Memory: 643-746 MB (было 1005 MB)
Deadlocks: минимум (было много)
```
---
## 💡 ДАЛЬНЕЙШИЕ УЛУЧШЕНИЯ (опционально)
### Если нужно ещё быстрее (< 1 секунды):
#### **#1: Nginx Reverse Proxy с кешем метаданных**
```nginx
# Кешировать PROPFIND ответы
location ~ ^/remote.php/dav/files/ {
proxy_cache_path /var/cache/nginx/propfind levels=1:2 keys_zone=PROPFIND:10m;
proxy_cache PROPFIND;
proxy_cache_valid 200 5m;
proxy_cache_methods GET HEAD PROPFIND;
proxy_cache_key "$request_method$request_uri";
proxy_pass http://nextcloud-fresh;
}
```
**Эффект:** Метаданные из Nginx кеша → 0.01-0.05 секунды
---
#### **#2: Прямой WOPI endpoint в CRM (обход Nextcloud для метаданных)**
```php
// Collabora запрашивает метаданные напрямую из CRM
// CRM отдаёт из своей БД (мгновенно!)
// Collabora читает файл через presigned S3 URL
WOPISrc = https://crm.clientright.ru/wopi/files/{recordId}
```
**Эффект:** 0.1-0.2 секунды полное открытие
---
#### **#3: Кеш в CRM Redis**
```php
// Кешировать fileId в CRM Redis
$redis->set("nc_fileid:$recordId", $fileId, 3600);
// При открытии - сразу из кеша
$fileId = $redis->get("nc_fileid:$recordId");
if ($fileId) {
// Сразу открываем без PROPFIND
return "https://office.clientright.ru:8443/apps/richdocuments/index?fileId=$fileId";
}
```
**Эффект:** Без PROPFIND вообще → 0.05-0.1 секунды
---
## 🎯 ИТОГОВЫЕ РЕКОМЕНДАЦИИ
### **ДЛЯ ПРОДАКШЕНА (СЕЙЧАС):**
```bash
# 1. filesystem_check_changes=0 для S3 (УЖЕ ПРИМЕНЕНО)
docker exec -u www-data nextcloud-fresh php occ files_external:option 1 filesystem_check_changes 0
# 2. Cron сканирование каждые 30 минут
crontab -e
*/30 * * * * docker exec -u www-data nextcloud-fresh php occ files:scan --path=/admin/files/crm --shallow > /dev/null 2>&1
# 3. Мониторинг
docker stats nextcloud-fresh --no-stream
```
### **ЕСЛИ НУЖНО ЕЩЁ БЫСТРЕЕ:**
- Nginx cache для PROPFIND (→ 0.05s)
- Кеш fileId в CRM Redis (→ без PROPFIND)
- Прямой WOPI от CRM (→ полный обход Nextcloud для метаданных)
---
## ✅ ТЕКУЩИЙ СТАТУС
### Производительность:
-**Открытие для редактирования:** ~1.5 секунды (было 25с)
-**Просмотр:** ~0.2 секунды (прямые ссылки S3)
-**CPU Nextcloud:** 0.05-5% (было 50%)
-**Стабильность:** отлично
### Настройки:
```php
'memcache.distributed' => '\OC\Memcache\Redis', // ✅
'filesystem_check_changes' => 1, // глобально
```
```json
// External Storage ID 1 (/crm)
{
"filesystem_check_changes": 0, // ✅ ОТКЛЮЧЕНО
"encrypt": false, // ✅ ОТКЛЮЧЕНО
"previews": true
}
```
---
## 🎉 РЕЗУЛЬТАТ
**Редактирование документов теперь открывается в 18 раз быстрее!**
- Было: 25 секунд ❌
- Стало: 1.5 секунды ✅
**Это приемлемая скорость для редактирования!** 🚀
---
**Следующий шаг:** Настроить cron для периодического сканирования новых файлов
**Хочешь настрою cron?** 😊

View File

@@ -0,0 +1,560 @@
# 🚀 NEXTCLOUD - ЛАЙФХАКИ УСКОРЕНИЯ
## 🎯 ЦЕЛЬ: Работать как Google Drive
---
## 💡 ПРЕДЛОЖЕНИЯ ДЛЯ ОБСУЖДЕНИЯ
### 1⃣ **HTTP/2 Push и Preload** ⚡⚡⚡
**Что:** Предзагрузка ресурсов до того как браузер их запросит
**Реализация в Nginx:**
```nginx
location ~ \.php$ {
# Предзагрузка JS/CSS
add_header Link "</core/css/styles.css>; rel=preload; as=style";
add_header Link "</core/js/main.js>; rel=preload; as=script";
# HTTP/2 Push
http2_push /core/css/styles.css;
http2_push /core/js/main.js;
}
```
**Ожидаемый эффект:** +30-50% скорость загрузки интерфейса
---
### 2⃣ **Separating Data Directory на SSD** 💾⚡⚡⚡
**Что:** Переместить БД Nextcloud на SSD диск (если сейчас на HDD)
**Проверка текущего диска:**
```bash
docker exec nextcloud-db-fresh df -h /var/lib/mysql
lsblk
```
**Если на HDD:**
- Создать volume на SSD
- Перенести `/var/lib/mysql` туда
- **Ускорение:** 5-10x для случайных запросов
---
### 3⃣ **Query Cache для MySQL** 🗄️⚡⚡
**Что:** Кешировать результаты повторяющихся SQL запросов
**НО!** В MariaDB 10.6+ Query Cache УДАЛЁН (deprecated)
**Альтернатива - ProxySQL:**
```bash
docker run -d --name proxysql \
--link nextcloud-db-fresh:mysql \
-p 6033:6033 \
proxysql/proxysql
```
**Настройка:**
- ProxySQL кеширует запросы к БД
- Nextcloud подключается к ProxySQL вместо напрямую к MySQL
- **Ускорение:** 2-3x для повторяющихся запросов
---
### 4⃣ **Preview Pre-generation** 🖼️⚡⚡
**Что:** Генерировать превью заранее в фоне
```bash
# Установка приложения
docker exec -u www-data nextcloud-fresh php occ app:install previewgenerator
# Настройка размеров
docker exec -u www-data nextcloud-fresh php occ config:app:set previewgenerator squareSizes --value="32 256"
docker exec -u www-data nextcloud-fresh php occ config:app:set previewgenerator widthSizes --value="256 384"
docker exec -u www-data nextcloud-fresh php occ config:app:set previewgenerator heightSizes --value="256"
# Первичная генерация (один раз)
docker exec -u www-data nextcloud-fresh php occ preview:generate-all
# Cron каждые 10 минут
*/10 * * * * docker exec -u www-data nextcloud-fresh php occ preview:pre-generate
```
**Эффект:** Превью файлов грузятся мгновенно
---
### 5⃣ **Chunked Upload для больших файлов** 📤⚡⚡
**Что:** Загрузка кусками вместо одного большого файла
```bash
docker exec -u www-data nextcloud-fresh php occ config:app:set files max_chunk_size --value=10485760 # 10MB chunks
```
**Для S3 External Storage:**
```bash
# Multipart upload для файлов > 5GB
docker exec -u www-data nextcloud-fresh php occ config:system:set objectstore.s3.multipart_threshold --value=5368709120 --type=integer
```
**Эффект:** Большие файлы загружаются быстрее и надёжнее
---
### 6⃣ **MySQL InnoDB Optimization** 🗄️⚡⚡⚡
**Что:** Правильные индексы для oc_filecache
**Текущие индексы:**
```sql
-- Проверка
docker exec nextcloud-db-fresh mariadb -u root -proot_password nextcloud -e "SHOW INDEX FROM oc_filecache;" 2>&1 | grep -v insecure
```
**Добавление недостающих:**
```sql
-- Для быстрого поиска по storage+path
CREATE INDEX idx_storage_path_hash ON oc_filecache(storage, path_hash);
-- Для быстрого поиска дочерних файлов
CREATE INDEX idx_parent_name ON oc_filecache(parent, name(191));
-- Для быстрого поиска по mimetype
CREATE INDEX idx_storage_mimetype ON oc_filecache(storage, mimetype);
-- Для сортировки по времени
CREATE INDEX idx_storage_mtime ON oc_filecache(storage, mtime);
```
**Автоматически:**
```bash
docker exec -u www-data nextcloud-fresh php occ db:add-missing-indices
docker exec -u www-data nextcloud-fresh php occ db:convert-filecache-bigint
```
**Эффект:** +50-100% скорость запросов к файлам
---
### 7⃣ **Nginx FastCGI Cache** 🌐⚡⚡⚡
**Что:** Кеш статических ресурсов и некоторых динамических
**Конфигурация Nginx:**
```nginx
# В http блоке
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=NEXTCLOUD:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
server {
location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) {
# FastCGI cache для избранных endpoints
fastcgi_cache NEXTCLOUD;
fastcgi_cache_valid 200 10m;
fastcgi_cache_bypass $http_pragma $http_authorization;
add_header X-Cache-Status $upstream_cache_status;
}
}
```
**Эффект:** Статика грузится мгновенно
---
### 8⃣ **Lazy Loading для больших папок** 📂⚡⚡
**Что:** Не грузить все 24K файлов сразу, а порциями
**В Nextcloud уже есть!** Проверяем настройки:
```bash
# Pagination включена по умолчанию
docker exec -u www-data nextcloud-fresh php occ config:app:get files pagination_limit
# Если нет - ставим
docker exec -u www-data nextcloud-fresh php occ config:app:set files pagination_limit --value=100
```
**Эффект:** Папки открываются быстрее
---
### 9⃣ **S3 Transfer Acceleration** 🌍⚡⚡⚡
**Что:** Использовать CDN endpoints TWC Storage
**Проверяем у провайдера TWC:**
- Есть ли CDN endpoint?
- Есть ли региональные endpoints ближе к серверу?
**Если есть:**
```php
// В config.php Nextcloud для S3
'objectstore' => [
'arguments' => [
'endpoint' => 'https://s3-accelerate.twcstorage.ru', // вместо обычного
]
]
```
**Эффект:** +50-200% скорость доступа к S3
---
### 🔟 **WebDAV Keepalive Connections** 🔗⚡⚡
**Что:** Переиспользовать HTTP соединения вместо создания новых
**В Nginx:**
```nginx
upstream nextcloud {
server nextcloud-fresh:80;
keepalive 32;
}
server {
location / {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://nextcloud;
}
}
```
**Эффект:** Меньше латентности при множественных запросах
---
### 1⃣1⃣ **Collabora Caching** 📝⚡⚡⚡
**Что:** Кеш документов и шрифтов в Collabora
**Проверка docker-compose Collabora:**
```yaml
collabora:
environment:
- DONT_GEN_SSL_CERT=true
- extra_params=--o:ssl.enable=false --o:logging.level=warning --o:net.post_allow=crm\.clientright\.ru
# Добавляем кеширование
- extra_params=--o:admin_console.enable_pam=false --o:net.connection_timeout_secs=30 --o:per_document.idle_timeout_secs=3600
# Добавляем volume для кеша
volumes:
- /var/cache/collabora:/tmp/cache
```
**Создаём кеш папку:**
```bash
mkdir -p /var/cache/collabora
chmod 777 /var/cache/collabora
```
**Эффект:** Документы открываются в 2-3 раза быстрее
---
### 1⃣2⃣ **Browser Service Worker Cache** 🌐⚡⚡
**Что:** Кеш в браузере через Service Workers
**Nextcloud уже использует!** Проверить можно:
- F12 → Application → Service Workers
- Должен быть зарегистрирован
**Если нет - включаем PWA:**
```bash
docker exec -u www-data nextcloud-fresh php occ config:app:set core enable_pwa --value=yes
```
**Эффект:** Интерфейс грузится мгновенно после первого раза
---
### 1⃣3⃣ **Direct S3 Access (bypass Nextcloud)** 🔥⚡⚡⚡
**Что:** Открывать файлы напрямую из S3, минуя Nextcloud WebDAV
**Реализация в CRM:**
```php
// В nextcloud-editor.js
function openFileDirectFromS3(recordId) {
// Получаем s3_key из CRM
fetch(`/crm_extensions/nextcloud_api.php?record=${recordId}`)
.then(r => r.json())
.then(data => {
// Прямая ссылка на S3
const s3Url = `https://s3.twcstorage.ru/${bucket}/${data.s3_key}`;
// Для просмотра - прямо открываем
if (isViewMode) {
window.open(s3Url, '_blank');
}
// Для редактирования - через Nextcloud
if (isEditMode) {
openInCollabora(data.nc_path);
}
});
}
```
**Эффект:**
- Просмотр: мгновенно (прямо из S3)
- Редактирование: через Nextcloud (нужен Collabora)
---
### 1⃣4⃣ **MySQL Connection Pooling** 🔗⚡⚡
**Что:** Пул соединений к БД вместо открытия нового каждый раз
**ProxySQL (рекомендуется):**
```yaml
services:
proxysql:
image: proxysql/proxysql:latest
ports:
- "6033:6033"
volumes:
- ./proxysql.cnf:/etc/proxysql.cnf
```
**Или в самом MySQL:**
```sql
SET GLOBAL max_connections = 500; -- увеличиваем пул
SET GLOBAL thread_cache_size = 100; -- кеш потоков
SET GLOBAL table_open_cache = 4096; -- кеш таблиц
```
**Эффект:** Меньше overhead на создание соединений
---
### 1⃣5⃣ **Отключение Activity Log для CRM папки** 📊⚡⚡
**Что:** Не логировать каждое действие в папке с 24K файлов
```bash
# Отключаем activity для storage ID 4 (crm)
docker exec nextcloud-db-fresh mariadb -u root -proot_password nextcloud -e "
DELETE FROM oc_activity WHERE object_type = 'files' AND object_id IN (
SELECT fileid FROM oc_filecache WHERE storage = 4
);
"
# Настройка в Nextcloud
docker exec -u www-data nextcloud-fresh php occ config:app:set activity enable_activity_tracking --value=no
```
**Эффект:** Меньше записей в БД при каждом открытии файла
---
### 1⃣6⃣ **CDN для статики Nextcloud** 🌍⚡⚡⚡
**Что:** Статические файлы (JS/CSS/иконки) через CDN
**Cloudflare перед Nextcloud:**
```nginx
# В Nginx - доверяем Cloudflare IP
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
# ... остальные Cloudflare IP
real_ip_header CF-Connecting-IP;
```
**В Nextcloud config.php:**
```php
'overwriteprotocol' => 'https',
'trusted_proxies' => ['173.245.48.0/20', '103.21.244.0/22'],
```
**Эффект:**
- Статика грузится из ближайшего PoP
- Меньше нагрузки на сервер
- Быстрее для пользователей
---
### 1⃣7⃣ **Асинхронные операции через Jobs** ⏱️⚡⚡
**Что:** Тяжёлые операции (сканирование, превью) в фоне
```bash
# Cron вместо Ajax/Webcron
docker exec -u www-data nextcloud-fresh php occ background:cron
# В host cron
*/5 * * * * docker exec -u www-data nextcloud-fresh php occ cron:job:run
```
**Важно для нас:**
- Сканирование S3 - в фоне
- Генерация превью - в фоне
- Очистка кеша - в фоне
**Эффект:** UI не тормозит при открытии файлов
---
### 1⃣8⃣ **Partitioning таблицы oc_filecache** 🗂️⚡⚡⚡
**Что:** Разбить огромную таблицу по storage ID
```sql
-- Проверяем размер таблицы
SELECT
table_name AS `Table`,
ROUND(((data_length + index_length) / 1024 / 1024), 2) AS `Size (MB)`
FROM information_schema.TABLES
WHERE table_schema = "nextcloud" AND table_name = "oc_filecache";
-- Если > 100MB - делаем partitioning
ALTER TABLE oc_filecache
PARTITION BY RANGE (storage) (
PARTITION p_storage_1_3 VALUES LESS THAN (4),
PARTITION p_storage_4 VALUES LESS THAN (5), -- CRM папка отдельно!
PARTITION p_storage_other VALUES LESS THAN MAXVALUE
);
```
**Эффект:**
- Запросы к CRM папке НЕ сканируют всю таблицу
- +50-80% скорость для больших таблиц
---
### 1⃣9⃣ **Отдельный WOPI сервер для Collabora** 📝⚡⚡⚡
**Что:** Collabora на отдельном сервере/контейнере
**Сейчас у вас:**
- Nextcloud + Collabora на одном сервере
- Конкурируют за ресурсы
**Оптимально:**
```yaml
# На другом сервере или с лимитами
collabora:
cpus: '2.0'
mem_limit: 2g
mem_reservation: 1g
```
**Эффект:** Nextcloud и Collabora не мешают друг другу
---
### 2⃣0⃣ **Varnish Cache перед Nextcloud** 🚀⚡⚡⚡
**Что:** HTTP кеш для статики и некоторых API
```
Browser → Varnish (6081) → Nginx → Nextcloud
```
**VCL конфигурация:**
```vcl
# Кешируем статику
if (req.url ~ "^/core/.*\.(js|css|png|jpg|svg)$") {
return (hash); # кешируем
}
# НЕ кешируем WebDAV
if (req.url ~ "^/remote.php/dav/") {
return (pass); # не кешируем
}
```
**Эффект:** Статика грузится в 10-100 раз быстрее
---
## 🎯 РЕКОМЕНДОВАННЫЙ ПЛАН
### **БЫСТРЫЕ ПОБЕДЫ (сделать сегодня):**
1.**Добавить индексы в MySQL** (5 минут)
```bash
docker exec -u www-data nextcloud-fresh php occ db:add-missing-indices
```
2. ✅ **Preview Generator** (30 минут первый раз)
```bash
docker exec -u www-data nextcloud-fresh php occ app:install previewgenerator
docker exec -u www-data nextcloud-fresh php occ preview:generate-all &
```
3. ✅ **Отключить Activity для CRM папки** (2 минуты)
```sql
DELETE FROM oc_activity WHERE object_id IN (
SELECT fileid FROM oc_filecache WHERE storage = 4
);
```
4. ✅ **Chunked upload** (1 минута)
```bash
docker exec -u www-data nextcloud-fresh php occ config:app:set files max_chunk_size --value=10485760
```
**Ожидаемое ускорение:** +100-200%
---
### **СРЕДНЯЯ СЛОЖНОСТЬ (на неделе):**
5.**InnoDB Buffer Pool 1GB** - требует изменение docker-compose
6.**Partitioning oc_filecache** - разделение таблицы
7.**HTTP/2 в Nginx** - если ещё не включено
8.**Cron для фоновых задач** - вместо webcron
**Ожидаемое ускорение:** +50-100%
---
### **ПРОДВИНУТОЕ (если нужно ещё быстрее):**
9.**ProxySQL** - пул соединений к MySQL
10.**Varnish Cache** - HTTP кеш перед Nextcloud
11.**Отдельный сервер для Collabora** - разделение нагрузки
12.**CDN (Cloudflare)** - статика через CDN
**Ожидаемое ускорение:** +200-500%
---
### **ЭКСПЕРИМЕНТАЛЬНОЕ:**
13.**Direct S3 access для просмотра** - обход Nextcloud
14.**Nginx caching для WebDAV** - кеш метаданных
15.**S3 Transfer Acceleration** - если TWC поддерживает
---
## 💰 СООТНОШЕНИЕ УСИЛИЙ/РЕЗУЛЬТАТА
| Решение | Сложность | Эффект | Приоритет |
|---------|-----------|--------|-----------|
| **Индексы MySQL** | ⭐ | ⭐⭐⭐ | 🔥🔥🔥 |
| **Preview Generator** | ⭐ | ⭐⭐⭐ | 🔥🔥🔥 |
| **Отключить Activity** | ⭐ | ⭐⭐ | 🔥🔥 |
| **InnoDB Buffer 1GB** | ⭐⭐ | ⭐⭐⭐ | 🔥🔥🔥 |
| **Partitioning** | ⭐⭐⭐ | ⭐⭐⭐ | 🔥🔥 |
| **ProxySQL** | ⭐⭐⭐ | ⭐⭐ | 🔥 |
| **Varnish** | ⭐⭐⭐⭐ | ⭐⭐⭐ | 🔥 |
| **Direct S3** | ⭐⭐ | ⭐⭐⭐⭐ | 🔥🔥 |
---
## 🤔 МОИ РЕКОМЕНДАЦИИ
### **Начни с TOP-4:**
1. **Индексы MySQL** - 5 минут, +50% скорость
2. **Preview Generator** - 30 минут, мгновенные превью
3. **Отключить Activity для CRM** - 2 минуты, меньше записей в БД
4. **InnoDB Buffer 1GB** - 10 минут, +30% скорость БД
**Это даст примерно 2-3x ускорение БЕЗ риска!**
---
### **Потом, если нужно ещё:**
5. **Partitioning oc_filecache** - разделить таблицу (сложнее, но эффективно)
6. **Direct S3 access** - для просмотра файлов (очень быстро!)
---
## 🎯 ВОПРОСЫ ДЛЯ ОБСУЖДЕНИЯ:
1. **Хочешь начать с быстрых побед** (индексы, preview, activity)?
2. **Готов менять docker-compose** для InnoDB Buffer?
3. **Интересует Direct S3 access** для просмотра файлов (обход Nextcloud)?
4. **Рассматриваешь Varnish/ProxySQL** для серьёзного ускорения?
**Что выберем?** 😊

View File

@@ -0,0 +1,249 @@
# 🚀 ОПТИМИЗАЦИЯ NEXTCLOUD - 31 ОКТЯБРЯ 2025
## 🔍 ПРОБЛЕМА
### Симптомы:
- ⏱️ Медленное открытие документов из CRM
- 🔥 Nextcloud CPU: **50.43%** (постоянно)
- ❌ Database Deadlocks при работе с файлами
- 📊 24,000+ файлов в папке crm2
### Найденные проблемы:
#### 1. **Database Deadlocks** ❌
```
SQLSTATE[40001]: Serialization failure: 1213
Deadlock found when trying to get lock; try restarting transaction
```
- Nextcloud постоянно сканирует папку crm2 (24K файлов)
- Обновления таблицы `oc_filecache` создают блокировки
- 404 блокировки (Innodb_row_lock_waits)
#### 2. **Отсутствие Distributed Cache** ❌
- Был только `memcache.local` (APCu)
- Не было `memcache.distributed` (Redis)
- Кеш не переживал перезапуски
#### 3. **Автоматическое сканирование** ❌
- `filesystem_check_changes = 1` (по умолчанию)
- При каждом запросе Nextcloud сканировал все 24K файлов
- Огромная нагрузка на БД
#### 4. **Маленький InnoDB Buffer Pool** ❌
- Всего **128 MB** (должно быть минимум 512MB)
- Не хватает памяти для кеширования запросов
---
## ✅ РЕШЕНИЕ
### 1. Distributed Cache (Redis)
```bash
docker exec -u www-data nextcloud-fresh php occ config:system:set memcache.distributed --value='\OC\Memcache\Redis'
```
**Результат:**
- ✅ Кеш между запросами
- ✅ Меньше обращений к БД
- ✅ Быстрее открытие файлов
### 2. Отключение автосканирования
```bash
docker exec -u www-data nextcloud-fresh php occ config:system:set filesystem_check_changes --value=0 --type=integer
```
**Результат:**
- ✅ Nextcloud НЕ сканирует 24K файлов при каждом запросе
- ✅ Меньше Deadlocks
- ✅ Меньше нагрузки на БД
**Важно:** Файлы будут обновляться через:
- Redis события (`crm:file:events`)
- Ручное сканирование при необходимости
- WebDAV уведомления
### 3. Оптимизация PHP
```bash
# Увеличен memory_limit
echo 'memory_limit=1024M' >> /usr/local/etc/php/conf.d/nextcloud.ini
# Оптимизация OPcache
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.memory_consumption=256
opcache.revalidate_freq=60
```
**Результат:**
- ✅ Больше памяти для PHP скриптов
- ✅ Больше файлов в OPcache
- ✅ Меньше компиляций
### 4. Оптимизация MySQL
```sql
SET GLOBAL max_connections = 300; -- было 151
SET GLOBAL innodb_lock_wait_timeout = 120; -- было 50
```
**Примечание:** `innodb_buffer_pool_size` требует изменения в docker-compose и перезапуск.
---
## 📊 РЕЗУЛЬТАТ
### До оптимизации:
```
CPU: 50.43% ❌
Memory: 1005 MiB
Deadlocks: много
Скорость: медленно
```
### После оптимизации:
```
CPU: 5.29% ✅ (в 10 раз меньше!)
Memory: 645 MiB
Deadlocks: должны уменьшиться
Скорость: быстрее
```
---
## 🎯 ДОПОЛНИТЕЛЬНЫЕ РЕКОМЕНДАЦИИ
### 1. Увеличить InnoDB Buffer Pool (требует перезапуск)
Найти docker-compose файл Nextcloud и добавить:
```yaml
services:
db:
environment:
MYSQL_INNODB_BUFFER_POOL_SIZE: 1073741824 # 1GB
command:
- --innodb-buffer-pool-size=1073741824
- --innodb-log-file-size=268435456 # 256MB
- --innodb-flush-log-at-trx_commit=2
- --innodb-flush-method=O_DIRECT
```
**Ожидаемое ускорение:** +30-50%
### 2. Добавить индексы в oc_filecache
```sql
-- Проверить существующие индексы
SHOW INDEX FROM oc_filecache;
-- Добавить если нужно
CREATE INDEX idx_storage_path ON oc_filecache(storage, path(255));
CREATE INDEX idx_parent_name ON oc_filecache(parent, name(255));
```
**Ожидаемое ускорение:** +20-40%
### 3. Настроить Chunked Upload для больших файлов
```bash
docker exec -u www-data nextcloud-fresh php occ config:app:set files max_chunk_size --value=10485760 # 10MB
```
### 4. Включить Preview Generation в фоне
```bash
docker exec -u www-data nextcloud-fresh php occ config:app:set previewgenerator squareSizes --value="256 512"
docker exec -u www-data nextcloud-fresh php occ config:app:set previewgenerator widthSizes --value="256 512 1024"
docker exec -u www-data nextcloud-fresh php occ config:app:set previewgenerator heightSizes --value="256 512 1024"
```
---
## 📈 МОНИТОРИНГ
### Проверка производительности:
```bash
# CPU/Memory Nextcloud
docker stats nextcloud-fresh --no-stream
# Deadlocks MySQL
docker exec nextcloud-db-fresh mariadb -u root -proot_password -e "SHOW GLOBAL STATUS LIKE 'Innodb_row_lock%';" 2>&1 | grep -v insecure
# Redis статистика
redis-cli -h 127.0.0.1 -p 6380 -a 'Nextcloud_Redis_Pass_2025!' INFO stats 2>&1 | grep -v Warning | head -10
```
### Логи Nextcloud:
```bash
docker logs nextcloud-fresh --tail 50 | grep -i "error\|warning\|deadlock"
```
---
## ✅ ТЕКУЩИЕ НАСТРОЙКИ
### Nextcloud Config:
```php
'memcache.local' => '\OC\Memcache\APCu', // Локальный кеш
'memcache.distributed' => '\OC\Memcache\Redis', // Распределённый кеш ✅ НОВОЕ
'memcache.locking' => '\OC\Memcache\Redis', // Блокировки через Redis
'filesystem_check_changes' => 0, // Автоскан ОТКЛЮЧЕН ✅ НОВОЕ
```
### PHP:
```
memory_limit = 1024M (было 512M)
opcache.memory_consumption = 256
opcache.max_accelerated_files = 20000
opcache.interned_strings_buffer = 16
```
### MySQL:
```
max_connections = 300 (было 151)
innodb_lock_wait_timeout = 120 (было 50)
innodb_buffer_pool_size = 128MB (⚠️ НУЖНО 1GB)
```
---
## 🚀 СЛЕДУЮЩИЕ ШАГИ
### Критично (сделать сегодня):
1. ✅ Distributed cache - **ГОТОВО**
2. ✅ Отключить автоскан - **ГОТОВО**
3. ✅ PHP оптимизация - **ГОТОВО**
4. ⏳ Проверить результат - **тестируем**
### Важно (сделать на неделе):
1. ⬜ Увеличить InnoDB buffer pool до 1GB
2. ⬜ Добавить индексы в oc_filecache
3. ⬜ Настроить chunked upload
4. ⬜ Preview generation в фоне
### Можно (если будет время):
1. ⬜ APCu увеличить (apc.shm_size=128M)
2. ⬜ Отключить ненужные приложения Nextcloud
3. ⬜ Настроить логи на rotation
4. ⬜ Мониторинг производительности
---
## 🎯 ОЖИДАЕМЫЙ РЕЗУЛЬТАТ
**После всех оптимизаций:**
- ⚡ Открытие документов: **в 3-5 раз быстрее**
- 📉 CPU Nextcloud: **< 10%** (было 50%)
- Deadlocks: **минимум** (было много)
- 💾 Меньше нагрузки на БД
---
**Статус:** Критичные оптимизации применены
**CPU до:** 50.43%
**CPU после:** 5.29%
**Ускорение:** **~10x** 🚀
**Дата:** 31 октября 2025, 10:04
**Автор:** Фёдор + AI Assistant

View File

@@ -0,0 +1,190 @@
# 🔍 КАК РАБОТАЕТ WORKFLOW OCR
## ⚠️ **ВАЖНО: Нет ручного запуска!**
**Workflow OCR** работает **ТОЛЬКО через правила автоматизации**!
В нём **НЕТ** кнопки "Submit to OCR" в меню файла.
---
## 🔄 **КАК ЭТО РАБОТАЕТ:**
### **Принцип работы:**
```
1. Создаёшь правило workflow
2. Загружаешь файл в Nextcloud
3. Workflow Engine видит событие
4. Запускает OCR автоматически
5. Результат сохраняется
```
**Это АВТОМАТИЗАЦИЯ, а не ручной инструмент!**
---
## 📝 **КАК СОЗДАТЬ ПРАВИЛО:**
### **Вариант 1: Через интерфейс Nextcloud**
**Шаг 1: Открой настройки Flow**
```
https://office.clientright.ru:8443/settings/admin/workflow
```
**Шаг 2: Добавь правило**
1. Нажми **"Add new workflow"**
2. Выбери условия:
- **When:** File created
- **And:** File MIME type is `application/pdf`
- **And:** Path matches `Documents/Project/*`
3. Выбери действие:
- **Then:** `OCR processing`
4. Нажми **Save**
---
### **Вариант 2: Через команду (автоматически)**
Я могу создать правило автоматически через БД!
Команда создаст правило:
```
Имя: "CRM - Автоматический OCR судебных документов"
Условия:
- Файл создан
- Тип: PDF
- Имя содержит: решение, определение, постановление, договор, иск
Действие:
- OCR с русским + английским
- Создать searchable PDF
```
---
## 🧪 **КАК ПРОТЕСТИРОВАТЬ:**
### **После создания правила:**
1. **Загрузи тестовый PDF** в папку проекта
2. **Дождись 30-60 секунд** (OCR работает в фоне)
3. **Проверь через поиск:**
```
Files → Search (🔍)
Введи слово из документа
```
4. Если находит → **OCR работает!** ✅
---
## 📊 **КАК ПРОВЕРИТЬ ЧТО OCR ВЫПОЛНЕН:**
### **Способ 1: Через теги**
После OCR файл получит тег в Nextcloud (если настроено)
### **Способ 2: Через логи**
```bash
docker exec nextcloud-fresh tail -100 /var/www/html/data/nextcloud.log | grep -i ocr
```
### **Способ 3: Через поиск**
Если файл находится по тексту из него → OCR выполнен!
---
## ⚡ **АЛЬТЕРНАТИВА: Ручной OCR**
### **Если нужен РУЧНОЙ OCR (не автоматический):**
Есть другое приложение: **OCR** (не workflow_ocr!)
**Установка:**
```bash
docker exec -u www-data nextcloud-fresh php occ app:install ocr
```
**В нём есть:**
- Кнопка "OCR" в меню файла
- Ручной запуск для выбранных файлов
- Выбор языка
**НО:** Это старое приложение, может не работать на Nextcloud 31
---
## 🎯 **ЧТО ДЕЛАТЬ СЕЙЧАС:**
### **Вариант А: Я создам правило автоматически**
Создам через команду, займёт 10 секунд:
```sql
INSERT INTO oc_flow_operations ...
```
**Результат:** Все новые PDF в проектах автоматически пройдут OCR
---
### **Вариант Б: Ты создашь сам через интерфейс**
Я покажу пошагово со скриншотами:
```
Settings → Flow → Add rule → ...
```
**Результат:** Ты понимаешь как создавать правила
---
### **Вариант В: Установить приложение для ручного OCR**
```bash
docker exec -u www-data nextcloud-fresh php occ app:install ocr
```
**Результат:** Появится кнопка OCR в меню файла
**⚠️ Внимание:** Может не работать на Nextcloud 31!
---
## 💡 **МОЯ РЕКОМЕНДАЦИЯ:**
**Используй АВТОМАТИЧЕСКИЙ OCR** (Workflow):
- ✅ Настроил один раз → работает всегда
- ✅ Не нужно помнить запускать OCR
- ✅ Все документы обрабатываются одинаково
- ✅ Современный подход
**Ручной OCR** нужен редко (только для старых файлов)
---
## 🚀 **ДАВАЙ СОЗДАМ ПРАВИЛО?**
**Что создать:**
**Правило 1: Судебные документы**
```
PDF с словами: решение, определение, постановление, иск
→ OCR (русский + английский)
```
**Правило 2: Договоры**
```
PDF в папке Contracts
→ OCR (русский + английский)
```
**Правило 3: Все PDF в проектах < 10MB**
```
PDF в Documents/Project/*, размер < 10MB
→ OCR (русский + английский)
```
---
**Какое правило создать?** Или все три сразу? 😊

View File

@@ -0,0 +1,276 @@
# 🔄 WORKFLOW ПРИЛОЖЕНИЯ В NEXTCLOUD
## 1⃣ **Workflow OCR Backend** (workflow_ocr)
### **ЧТО ЭТО:**
Приложение для **автоматического распознавания текста (OCR)** из изображений и PDF файлов.
### **КАК РАБОТАЕТ:**
```
PDF/Изображение загружено →
→ Workflow Engine видит событие →
→ Tesseract OCR обрабатывает →
→ Создаёт текстовый файл с распознанным текстом
```
### **ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ:**
**1. Автоматическое распознавание сканов:**
```
Правило: Если загружен файл *.pdf в папку /Scans
Действие: Распознать текст и создать .txt файл
```
**2. Обработка чеков:**
```
Правило: Если загружена фотография в /Receipts
Действие: OCR → поиск по тексту
```
**3. Юридические документы:**
```
Правило: Если загружен скан решения суда
Действие: Распознать текст → сделать документ searchable
```
### **НАСТРОЙКА:**
**1. Создать правило:**
```
Settings → Flow → Add rule:
- When: File created
- And: Mime type is image/* OR application/pdf
- And: Path matches /Scans/*
- Then: OCR processing
```
**2. Выбрать язык:**
- Russian (rus)
- English (eng)
- Multi (rus+eng)
### **ТЕКУЩИЙ СТАТУС:**
- ✅ Установлено: workflow_ocr 1.31.3
- ✅ Tesseract OCR: 5.5.0 (движок распознавания)
- ❌ Правил НЕТ (не настроено)
**Вывод:** Приложение установлено, но **НЕ ИСПОЛЬЗУЕТСЯ** (нет правил).
---
## 2⃣ **Flow Notifications** (flow_notifications)
### **ЧТО ЭТО:**
Приложение для **отправки уведомлений** на основе событий Workflow.
### **КАК РАБОТАЕТ:**
```
Событие в Nextcloud →
→ Workflow Engine проверяет правила →
→ Flow Notifications отправляет уведомление
```
### **ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ:**
**1. Уведомление при загрузке важного файла:**
```
Правило: Если файл загружен в /Important
Действие: Отправить уведомление "Загружен важный файл"
```
**2. Уведомление о новом контракте:**
```
Правило: Если PDF загружен в /Contracts
Действие: Уведомить юриста
```
**3. Алерт при большом файле:**
```
Правило: Если размер файла > 100MB
Действие: Уведомить администратора
```
### **ТИПЫ УВЕДОМЛЕНИЙ:**
- 🔔 Push-уведомления в браузере
- 📧 Email
- 📱 Nextcloud app (Android/iOS)
- 🔗 Webhook (для интеграций)
### **НАСТРОЙКА:**
**Пример правила:**
```
Settings → Flow → Add rule:
- When: File created
- And: File size > 100000000 (100MB)
- Then: Send notification
- User: admin
- Message: "Large file uploaded: {file}"
```
### **ТЕКУЩИЙ СТАТУС:**
- ✅ Установлено: flow_notifications 2.0.1
- ❌ Правил НЕТ (не настроено)
**Вывод:** Приложение установлено, но **НЕ ИСПОЛЬЗУЕТСЯ**.
---
## 3⃣ **Workflow Engine** (workflowengine)
### **ЧТО ЭТО:**
**Основной движок** для всех workflow - автоматизация действий на основе событий.
### **АРХИТЕКТУРА:**
```
┌─────────────────┐
│ Workflow Engine │
│ (ядро) │
└────────┬─────────┘
┌─────────────────┼─────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ workflow_ocr │ │flow_notifications││workflow_script│
│ (OCR) │ │ (уведомления) │ │ (скрипты) │
└───────────────┘ └───────────────┘ └───────────────┘
```
### **ДОСТУПНЫЕ ДЕЙСТВИЯ:**
**Стандартные:**
- ✅ Отправить уведомление
- ✅ Добавить тег
- ✅ Переместить файл
- ✅ Конвертировать в PDF
- ✅ Запустить скрипт
**С установленными приложениями:**
- ✅ OCR обработка (workflow_ocr)
- ✅ Конвертация PDF (workflow_pdf_converter)
- ✅ Запуск скриптов (workflow_script)
---
## 4⃣ **Другие установленные Workflow приложения:**
### **workflow_pdf_converter**
Конвертация документов в PDF:
- Word → PDF
- Excel → PDF
- Images → PDF
### **workflow_script**
Запуск произвольных скриптов при событиях:
```bash
#!/bin/bash
# Пример: отправка файла по API
curl -X POST https://api.example.com/upload \
-F "file=@$1"
```
---
## 🎯 **ТЕКУЩАЯ СИТУАЦИЯ:**
### **Установлено:**
```
✅ workflowengine: 2.13.0 (ядро)
✅ workflow_ocr: 1.31.3 (OCR)
✅ workflow_pdf_converter: 2.0.0 (PDF конвертер)
✅ workflow_script: 2.0.0 (скрипты)
✅ flow_notifications: 2.0.1 (уведомления)
```
### **Активных правил:** 0 ❌
**Вывод:** Все приложения установлены, но **НЕ НАСТРОЕНЫ** и **НЕ ИСПОЛЬЗУЮТСЯ**.
---
## 💡 **РЕКОМЕНДАЦИИ:**
### **Вариант 1: ИСПОЛЬЗОВАТЬ для автоматизации**
**Полезные сценарии для CRM:**
**1. OCR судебных решений:**
```
Правило: PDF загружен в Documents/Project/*/Судебные решения
Действие: OCR → текст извлечён → можно искать
```
**2. Уведомления о новых документах:**
```
Правило: Файл загружен в Documents/Project/*
Действие: Уведомить ответственного юриста
```
**3. Автоматическая конвертация в PDF:**
```
Правило: Word/Excel загружен
Действие: Конвертировать в PDF
```
### **Вариант 2: ОТКЛЮЧИТЬ если не нужно**
Если не планируете использовать автоматизацию:
```bash
docker exec -u www-data nextcloud-fresh php occ app:disable workflow_ocr
docker exec -u www-data nextcloud-fresh php occ app:disable flow_notifications
docker exec -u www-data nextcloud-fresh php occ app:disable workflow_pdf_converter
docker exec -u www-data nextcloud-fresh php occ app:disable workflow_script
```
**Оставить только ядро:** `workflowengine` (базовая функциональность)
---
## 🔧 **КАК НАСТРОИТЬ (если нужно):**
### **Шаг 1: Открыть настройки Flow**
```
https://office.clientright.ru:8443/settings/admin/workflow
```
### **Шаг 2: Создать правило**
```
1. Add rule
2. Выбрать событие (File created, File updated, etc.)
3. Добавить условия (path, mime type, size)
4. Выбрать действие (OCR, notification, convert)
5. Save
```
### **Шаг 3: Протестировать**
Загрузить тестовый файл → проверить что правило сработало
---
## 📊 **ИСПОЛЬЗУЕМЫЕ РЕСУРСЫ:**
### **Tesseract OCR:**
- Версия: 5.5.0
- Языки: русский, английский (установлены)
- CPU: ~50-100% на файл
- Время: ~10-30 сек на страницу
### **Дисковое пространство:**
OCR создаёт дополнительные текстовые файлы = +10-20% от размера PDF
---
## ⚠️ **ВАЖНО:**
**Если НЕ используете эти функции** → лучше **отключить**:
- Меньше нагрузка на систему
- Меньше ошибок в логах
- Проще поддержка
**Если НУЖНА автоматизация** → настроить правила workflow
---
**Вам нужна автоматизация (OCR, уведомления)?** Или отключить эти приложения? 🤔

520
ai_dialogs_export.txt Normal file
View File

@@ -0,0 +1,520 @@
╔══════════════════════════════════════════════════════════════════════════════╗
║ 📚 ИСТОРИЯ AI ДИАЛОГОВ С КЛИЕНТАМИ ║
║ Дата выгрузки: 29.10.2025 12:01:36 ║
╚══════════════════════════════════════════════════════════════════════════════╝
Всего записей: 29
════════════════════════════════════════════════════════════════════════════════
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📁 ПРОЕКТ: Курманжанова ИП Жгенти Дав<D0B0> (ID: 36937)
👤 КЛИЕНТ: Карина Курманжанова
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┌─ Диалог #1 ─────────────────────────────────────────────────────────────────┐
│ 📅 2025-10-20 11:37:53 │
├──────────────────────────────────────────────────────────────────────────────┤
│ ❓ ВОПРОС: │
│ [document] │
│ │
│ 🤖 ОТВЕТ: │
На основе найденных фрагментов, я могу │
│ рассказать о требованиях к │
│ документам: │
│ │
│ 1. Документы нужно предоставлять в │
│ формате PDF │
│ 2. Если у вас бумажные документы - их │
│ можно сфотографировать, но важно │
│ делать это ровно и четко, захватывая │
│ все страницы │
│ 3. Для подачи в суд документы лучше │
│ собрать в один PDF-файл │
│ 4. При личном участии в суде нужно │
│ иметь с собой: │
│ - распечатанные копии всех документов │
│ - паспорт │
│ - оригиналы документов │
│ │
│ Если вам нужна помощь с конкретными │
│ документами по вашему делу, уточните │
│ пожалуйста ваш вопрос. │
│ │
│ &lt;b&gt;Если у вас остались вопросы &mdash; │
│ мы с радостью ответим!&lt;/b&gt; │
│ Напишите их прямо здесь. │
└──────────────────────────────────────────────────────────────────────────────┘
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📁 ПРОЕКТ: Юдин ИП Николаенков Васили (ID: 87121)
👤 КЛИЕНТ:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📁 ПРОЕКТ: Коробков _Тим_ДТП (ID: 354918)
👤 КЛИЕНТ: Fedor -
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┌─ Диалог #1 ─────────────────────────────────────────────────────────────────┐
│ 📅 2025-10-16 16:39:10 │
├──────────────────────────────────────────────────────────────────────────────┤
│ ❓ ВОПРОС: │
│ да, скажи пожалуйста, какой статус? │
│ │
│ 🤖 ОТВЕТ: │
На данный момент дело инициировано │
│ (находится в начальной стадии │
│ претензионно-исковой работы). Это │
│ значит, что работа по делу начата, но │
│ до суда дело еще не дошло. В системе │
│ есть загруженные документы, включая │
│ претензию, но окончательное решение │
│ по делу пока не принято. │
│ │
│ Отмечу важные моменты: │
│ - Дело активно (не завершено) │
│ - Находится на стадии досудебного │
│ урегулирования │
│ - Плановая дата завершения │
│ установлена на 16.11.2025 │
│ │
│ &lt;b&gt;Если у вас остались вопросы &mdash; │
│ мы с радостью ответим!&lt;/b&gt; │
│ Напишите их прямо здесь. │
└──────────────────────────────────────────────────────────────────────────────┘
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📁 ПРОЕКТ: Казаков УНИВЕРСИТЕТ СИНЕРГ (ID: 370163)
👤 КЛИЕНТ: Антон Казаков
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┌─ Диалог #1 ─────────────────────────────────────────────────────────────────┐
│ 📅 2025-10-10 11:35:19 │
├──────────────────────────────────────────────────────────────────────────────┤
│ ❓ ВОПРОС: │
│ Подробную статью Гайд давай │
│ │
│ 🤖 ОТВЕТ: │
│ Простите, но я не могу составить для │
│ вас подробную статью-гайд или │
│ рекомендации для публикации. Это │
│ выходит за рамки моих полномочий как │
│ юридического помощника по вашему │
│ делу. │
│ │
│ Вместо этого я рекомендую: │
│ │
│ 1. Обратиться к вашему юристу, который │
│ вел дело - он сможет дать │
│ квалифицированную консультацию о том, │
│ как безопасно делиться информацией о
│ деле. │
│ │
│ 2. Любые публикации о деле лучше │
│ предварительно согласовать с вашим │
│ юристом, чтобы избежать возможных │
│ рисков. │
│ │
│ Я могу отвечать на ваши вопросы по │
│ существу дела: о датах заседаний, │
│ суммах, статусе, имеющихся документах. │
Но составление рекомендаций для │
│ публикации - это отдельная │
│ юридическая услуга, которая требует │
│ участия вашего представителя. │
│ │
│ Хотите узнать конкретную информацию │
│ по вашему делу? │
│ │
│ &lt;b&gt;Если у вас остались вопросы &mdash; │
│ мы с радостью ответим!&lt;/b&gt; │
│ Напишите их прямо здесь. │
└──────────────────────────────────────────────────────────────────────────────┘
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📁 ПРОЕКТ: Сатюкова ООО ЭДЭКС (ID: 379166)
👤 КЛИЕНТ: Дария Сатюкова
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┌─ Диалог #1 ─────────────────────────────────────────────────────────────────┐
│ 📅 2025-10-14 20:20:03 │
├──────────────────────────────────────────────────────────────────────────────┤
│ ❓ ВОПРОС: │
│ [photo] │
│ │
│ 🤖 ОТВЕТ: │
│ Я не могу обрабатывать или │
│ анализировать фотографии. Если у вас │
│ есть вопрос по вашему делу, │
│ пожалуйста, задайте его текстом, и я │
│ постараюсь помочь найти нужную │
│ информацию. │
│ │
│ &lt;b&gt;Если у вас остались вопросы &mdash; │
│ мы с радостью ответим!&lt;/b&gt; │
│ Напишите их прямо здесь. │
└──────────────────────────────────────────────────────────────────────────────┘
┌─ Диалог #2 ─────────────────────────────────────────────────────────────────┐
│ 📅 2025-10-14 20:20:53 │
├──────────────────────────────────────────────────────────────────────────────┤
│ ❓ ВОПРОС: │
│ Мне прислали письмо о неявке в суд │
│ │
│ 🤖 ОТВЕТ: │
│ Если вы получили письмо о неявке в суд, │
│ это важное уведомление, которое │
│ требует вашего внимания. Давайте я │
│ уточню детали вашей ситуации: │
│ │
│ 1. Получите письмо и внимательно │
│ ознакомьтесь с его содержанием │
│ 2. Если вы действительно не можете │
│ присутствовать на судебном заседании, │
│ вам нужно уведомить суд о причинах │
│ неявки │
│ 3. Для получения более точной │
│ информации о необходимых действиях в │
│ вашей конкретной ситуации, рекомендую │
│ обратиться к вашему юристу, который │
│ ведет ваше дело │
│ │
│ Также вы можете отслеживать │
│ информацию о деле, позвонив │
│ непосредственно в суд. │
│ │
│ Для того чтобы дать вам более точный │
│ ответ по вашей конкретной ситуации, │
│ мне нужны дополнительные детали. │
│ Пожалуйста, уточните: │
│ - Получили ли вы уже само письмо или │
│ только уведомление о нем? │
│ - От какого суда пришло письмо? │
│ - На какую дату назначено заседание? │
│ │
│ &lt;b&gt;Если у вас остались вопросы &mdash; │
│ мы с радостью ответим!&lt;/b&gt; │
│ Напишите их прямо здесь. │
└──────────────────────────────────────────────────────────────────────────────┘
┌─ Диалог #3 ─────────────────────────────────────────────────────────────────┐
│ 📅 2025-10-14 20:22:36 │
├──────────────────────────────────────────────────────────────────────────────┤
│ ❓ ВОПРОС: │
│ Я уже получила письмо │
│ От Гагаринского районного суда города │
│ Москвы │
На 25.11.2025 │
│ │
│ 🤖 ОТВЕТ: │
│ Если вы не можете присутствовать на │
│ судебном заседании 25.11.2025 в │
│ Гагаринском районном суде города │
│ Москвы, вам необходимо: │
│ │
│ 1. Подать в суд ходатайство об
│ отложении дела или о рассмотрении │
│ дела в ваше отсутствие. Это можно │
│ сделать: │
│ - через сайт суда в электронном виде │
│ - направить почтой │
│ - подать непосредственно в │
│ канцелярию суда │
│ │
│ 2. В ходатайстве нужно: │
│ - указать причины вашей неявки │
│ - приложить подтверждающие │
│ документы (если есть) │
│ - указать, просите ли вы рассмотреть │
│ дело без вашего участия или перенести │
│ заседание │
│ │
│ Для получения более подробной │
│ консультации по вашей конкретной │
│ ситуации рекомендую обратиться к │
│ вашему юристу, который ведет ваше │
│ дело. Он лучше знает обстоятельства и │
│ сможет подсказать оптимальное │
│ решение. │
│ │
│ Также вы можете отслеживать │
│ информацию о движении дела на │
│ официальном сайте суда. │
│ │
│ &lt;b&gt;Если у вас остались вопросы &mdash; │
│ мы с радостью ответим!&lt;/b&gt; │
│ Напишите их прямо здесь. │
└──────────────────────────────────────────────────────────────────────────────┘
┌─ Диалог #4 ─────────────────────────────────────────────────────────────────┐
│ 📅 2025-10-16 16:19:25 │
├──────────────────────────────────────────────────────────────────────────────┤
│ ❓ ВОПРОС: │
│ Я уже получила письмо от Гагаринского │
│ районного суда │
│ │
│ 🤖 ОТВЕТ: │
│ Если вы не можете присутствовать на │
│ судебном заседании... │
└──────────────────────────────────────────────────────────────────────────────┘
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📁 ПРОЕКТ: Гафиев ООО ЭДЭКС (ID: 384256)
👤 КЛИЕНТ: Марсель Гафиев
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┌─ Диалог #1 ─────────────────────────────────────────────────────────────────┐
│ 📅 2025-10-25 17:39:54 │
├──────────────────────────────────────────────────────────────────────────────┤
│ ❓ ВОПРОС: │
│ Здравствуйте! Подготовьте пожалуйста │
│ памятку о дольнейсших действиях, │
│ (исполнении решения, и сроки) │
│ благодарю. │
│ │
│ 🤖 ОТВЕТ: │
На основании имеющейся информации, │
│ вот памятка о дальнейших действиях по │
│ исполнению решения суда: │
│ │
│ 1. Получение исполнительного листа: │
│ - После вступления решения в законную │
│ силу подайте заявление в суд о выдаче │
│ исполнительного листа │
│ - Вы можете получить исполнительный │
│ лист лично в суде или попросить │
│ направить его почтой │
│ - Срок для получения исполнительного │
│ листа - 3 года с момента вступления │
│ решения в законную силу │
│ │
│ 2. Сроки действия исполнительного │
│ листа: │
│ - Исполнительный лист действует 3 года │
с момента его выдачи │
│ - В течение этого срока вы можете │
│ предъявить его к исполнению │
│ │
│ 3. Порядок исполнения: │
│ - После получения исполнительного │
│ листа вы можете: │
│ * Предъявить его в службу судебных │
│ приставов │
│ * Если у вас есть банковские │
│ реквизиты должника, направить │
│ исполнительный лист напрямую в банк │
│ │
│ Если у вас возникнут вопросы по │
│ конкретным действиям или потребуется │
│ дополнительная информация, │
│ обратитесь к вашему юристу, который │
│ сможет дать более детальные │
│ рекомендации с учетом особенностей │
│ вашего дела. │
│ │
│ &lt;b&gt;Если у вас остались вопросы &mdash; │
│ мы с радостью ответим!&lt;/b&gt; │
│ Напишите их прямо здесь. │
└──────────────────────────────────────────────────────────────────────────────┘
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📁 ПРОЕКТ: Лучина ООО ОТКРЫТЫЙ МИР (ID: 392972)
👤 КЛИЕНТ: Галина Лучина
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┌─ Диалог #1 ─────────────────────────────────────────────────────────────────┐
│ 📅 2025-10-22 09:49:48 │
├──────────────────────────────────────────────────────────────────────────────┤
│ ❓ ВОПРОС: │
│ Возврат денежных средств выполнен в │
│ полном объёме │
│ │
│ 🤖 ОТВЕТ: │
│ По имеющимся данным, возвращена │
│ только часть суммы: │
│ - Цена договора составляла 130 960,00 ₽ │
│ - Возвращено 57 456 ₽ (частичный возврат, │
│ выполнен 29.09.2025) │
│ │
│ Таким образом, возврат денежных │
│ средств выполнен не в полном объеме. │
│ Остаток задолженности составляет 73 │
│ 504,00 ₽. │
│ │
│ Дело находится в претензионной │
│ стадии, ожидается ответ на претензию │
│ от ООО &quot;Открытый Мир&quot;. │
│ │
│ &lt;b&gt;Если у вас остались вопросы &mdash; │
│ мы с радостью ответим!&lt;/b&gt; │
│ Напишите их прямо здесь. │
└──────────────────────────────────────────────────────────────────────────────┘
┌─ Диалог #2 ─────────────────────────────────────────────────────────────────┐
│ 📅 2025-10-22 09:51:29 │
├──────────────────────────────────────────────────────────────────────────────┤
│ ❓ ВОПРОС: │
│ Возврат выполнен 18.10 по итогам спора, │
│ открытого банком, картой которого │
│ произведена оплата. │
│ │
│ 🤖 ОТВЕТ: │
В данных нет информации о возврате │
│ денежных средств 18.10 через банк. Для │
│ корректного отражения в деле этой │
│ информации рекомендую: │
│ │
│ 1. Предоставить подтверждающие │
│ документы о возврате (чек, выписка или │
│ уведомление от банка) │
│ 2. После этого информация о полном │
│ возврате будет добавлена в карточку │
│ дела │
│ │
На текущий момент в деле отражен │
│ только частичный возврат 57 456 ₽ от │
│ 29.09.2025. Если у вас есть документы о
│ дополнительном возврате, пожалуйста, │
│ направьте их вашему юристу для │
│ актуализации информации по делу. │
│ │
│ &lt;b&gt;Если у вас остались вопросы &mdash; │
│ мы с радостью ответим!&lt;/b&gt; │
│ Напишите их прямо здесь. │
└──────────────────────────────────────────────────────────────────────────────┘
┌─ Диалог #3 ─────────────────────────────────────────────────────────────────┐
│ 📅 2025-10-22 09:59:28 │
├──────────────────────────────────────────────────────────────────────────────┤
│ ❓ ВОПРОС: │
│ [photo] │
│ │
│ 🤖 ОТВЕТ: │
│ Да, я вижу подтверждение вашей │
│ информации. Действительно, возврат │
│ денежных средств по спору, │
│ инициированному банком, произошел. │
│ Однако для корректного отражения этой │
│ информации в деле нужно: │
│ │
│ 1. Предоставить подтверждающие │
│ документы о возврате (на выбор): │
│ - чек │
│ - выписка │
│ - уведомление от банка │
│ │
│ После предоставления подтверждающих │
│ документов информация о полном │
│ возврате будет добавлена в карточку │
│ дела. │
│ │
На данный момент в деле отражен только │
│ первый частичный возврат в размере 57 │
│ 456 ₽ от 29.09.2025. │
│ │
│ &lt;b&gt;Если у вас остались вопросы &mdash; │
│ мы с радостью ответим!&lt;/b&gt; │
│ Напишите их прямо здесь. │
└──────────────────────────────────────────────────────────────────────────────┘
┌─ Диалог #4 ─────────────────────────────────────────────────────────────────┐
│ 📅 2025-10-22 10:03:46 │
├──────────────────────────────────────────────────────────────────────────────┤
│ ❓ ВОПРОС: │
│ [photo] │
│ │
│ 🤖 ОТВЕТ: │
В деле действительно сейчас учтен │
│ только частичный возврат денежных │
│ средств в размере 54 567 ₽. Чтобы │
│ зафиксировать полный возврат по спору │
│ через банк от 18.10, пожалуйста, │
│ предоставьте любой из подтверждающих │
│ документов: │
│ │
│ - чек, или │
│ - выписку, или │
│ - уведомление от банка │
│ │
│ После получения документа информация │
о полном возврате денежных средств │
│ будет добавлена в материалы дела. │
│ │
│ &lt;b&gt;Если у вас остались вопросы &mdash; │
│ мы с радостью ответим!&lt;/b&gt; │
│ Напишите их прямо здесь. │
└──────────────────────────────────────────────────────────────────────────────┘
┌─ Диалог #5 ─────────────────────────────────────────────────────────────────┐
│ 📅 2025-10-22 10:03:50 │
├──────────────────────────────────────────────────────────────────────────────┤
│ ❓ ВОПРОС: │
│ [photo] │
│ │
│ 🤖 ОТВЕТ: │
│ Я вижу фотоподтверждение возврата │
│ средств. Для корректного отражения │
│ полного возврата в деле необходимо │
│ предоставить один из официальных │
│ подтверждающих документов: │
│ │
│ 1. Чек │
│ 2. Банковскую выписку │
│ 3. Уведомление от банка о возврате │
│ средств │
│ │
│ После получения любого из этих │
│ документов информация о полном │
│ возврате будет добавлена в карточку │
│ дела. │
│ │
На текущий момент в деле отражен │
│ только частичный возврат в размере 57 │
│ 456 ₽. │
│ │
│ &lt;b&gt;Если у вас остались вопросы &mdash; │
│ мы с радостью ответим!&lt;/b&gt; │
│ Напишите их прямо здесь. │
└──────────────────────────────────────────────────────────────────────────────┘
┌─ Диалог #6 ─────────────────────────────────────────────────────────────────┐
│ 📅 2025-10-22 10:04:43 │
├──────────────────────────────────────────────────────────────────────────────┤
│ ❓ ВОПРОС: │
│ Иных документов не имею. │
│ │
│ 🤖 ОТВЕТ: │
│ Для корректного отражения полного │
│ возврата средств в деле, необходимо │
│ предоставить один из следующих │
│ подтверждающих документов: │
│ │
│ 1. Чек │
│ 2. Банковскую выписку │
│ 3. Уведомление от банка о возврате │
│ средств │
│ │
На данный момент в деле учтен только │
│ частичный возврат в размере 57 456 ₽. │
│ │
│ После предоставления любого из │
│ указанных документов, информация о
│ полном возврате будет добавлена в │
│ карточку дела. │
│ │
│ &lt;b&gt;Если у вас остались вопросы &mdash; │
│ мы с радостью ответим!&lt;/b&gt; │
│ Напишите их прямо здесь. │
└──────────────────────────────────────────────────────────────────────────────┘
════════════════════════════════════════════════════════════════════════════════
Конец выгрузки

View File

@@ -0,0 +1,3 @@
S3_ACCESS_KEY=2OMAK5ZNM900TAXM16J7
S3_SECRET_KEY=f4ADllb5VZBAt2HdsyB8WcwVEU7U74MwFCa1DARG
S3_BUCKET=f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c

View File

@@ -0,0 +1,277 @@
# 🏗️ Архитектура системы мониторинга файлов
## 🎯 Общая схема
```
┌─────────────────────────────────────────────────────────────────────────┐
│ ИСТОЧНИКИ ФАЙЛОВ │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ CRM PHP │ │ Nextcloud │ │ S3 Browser │ │ Внешние │ │
│ │ │ │ WebUI │ │ Cyberduck │ │ скрипты │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └─────┬──────┘ │
│ │ │ │ │ │
│ └─────────────────┼─────────────────┼─────────────────┘ │
│ │ │ │
└───────────────────────────┼─────────────────┼───────────────────────────┘
▼ ▼
┌──────────────────────────────────────┐
│ │
│ TWC S3 Storage (Cloud) │
│ f9825c87-18698658-c378-... │
│ │
└────┬─────────────────────────────┬───┘
│ │
│ (mounted via │ (polling)
│ external │
│ storage) │
▼ ▼
┌──────────────────────┐ ┌──────────────────────────┐
│ Nextcloud │ │ n8n S3 Monitor │
│ Docker Container │ │ Workflow │
│ │ │ │
│ Files change → │ │ Every 30s: │
│ notify_storage_ │ │ 1. List S3 files │
│ update (Redis) │ │ 2. Compare with prev │
└──────────┬───────────┘ │ 3. Detect changes │
│ └─────────┬────────────────┘
│ │
▼ ▼
┌──────────────────────┐ ┌─────────────────────────┐
│ redis_bridge.js │ │ │
│ (Node.js) │ │ (n8n internal) │
│ │ │ │
│ 1. Subscribe NC │ │ │
│ Redis │ │ │
│ 2. Parse events │ │ │
│ 3. Enrich data │ │ │
└──────────┬───────────┘ └─────────┬───────────────┘
│ │
│ │
└────────────┬───────────────┘
┌──────────────────────────────┐
│ CRM Redis │
│ 147.45.146.17:6379 │
│ │
│ Channel: │
│ crm:file:events │
└───────────┬──────────────────┘
│ (subscribe)
┌─────────────────┼─────────────────┐
│ │ │
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ n8n │ │ CRM PHP │ │ Другие │
│ Workflows │ │ Listeners │ │ сервисы │
└────────────┘ └────────────┘ └────────────┘
```
---
## 📊 Потоки событий
### Поток 1: Файлы через Nextcloud WebUI
```
User uploads file → Nextcloud → S3 Storage →
→ Nextcloud detects change → notify_storage_update (NC Redis) →
→ redis_bridge.js → crm:file:events (CRM Redis) → Обработчики
```
⏱️ **Задержка:** ~1-2 секунды (реал-тайм)
---
### Поток 2: Файлы напрямую в S3
```
External tool → S3 Storage →
→ n8n S3 Monitor (polling every 30s) → Detects change →
→ crm:file:events (CRM Redis) → Обработчики
```
⏱️ **Задержка:** 0-30 секунд (зависит от интервала polling)
---
## 🔄 Компоненты системы
### 1. **redis_bridge.js** (Node.js, работает на хосте)
- **Задача:** Мост между Nextcloud Redis и CRM Redis
- **Вход:** `notify_storage_update` (Nextcloud Redis, port 6380)
- **Выход:** `crm:file:events` (CRM Redis, port 6379)
- **Статус:** ✅ Работает
- **Запуск:**
```bash
cd /var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage
/usr/bin/nodejs redis_bridge.js &
```
### 2. **n8n S3 Monitor Workflow** (в n8n)
- **Задача:** Мониторинг прямых изменений в S3
- **Метод:** Polling (каждые 30 секунд)
- **Вход:** TWC S3 API (ListObjectsV2)
- **Выход:** `crm:file:events` (CRM Redis)
- **Статус:** ⚙️ Нужно настроить
- **Файл:** `n8n_s3_monitor_workflow.json`
### 3. **CRM Redis** (центральная шина событий)
- **Адрес:** `147.45.146.17:6379`
- **Канал:** `crm:file:events`
- **Формат события:**
```json
{
"type": "file_created|file_modified|file_deleted",
"source": "nextcloud|s3_monitor|crm",
"timestamp": "2025-10-30T12:34:56Z",
"path": "full/path/to/file.txt",
"filename": "file.txt",
"size": 12345,
"file_id": 73460,
"etag": "abc123...",
"operation": "create|update|delete"
}
```
---
## 🎯 Сценарии использования
### Сценарий 1: Обработка ERV файлов
```
1. Загружаешь ERV файл в S3 через S3 Browser
2. n8n S3 Monitor обнаруживает файл (через 0-30с)
3. Событие публикуется в Redis → crm:file:events
4. n8n ERV Processor подхватывает событие
5. Скачивает файл из S3
6. Обрабатывает ERV
7. Загружает в CRM
8. Отправляет уведомление
```
### Сценарий 2: Автоматическая обработка PDF счетов
```
1. Клиент загружает PDF в Nextcloud
2. Nextcloud → notify_storage_update → redis_bridge.js
3. Событие в Redis (реал-тайм, ~1с)
4. n8n Invoice Processor:
- Распознаёт текст (OCR)
- Извлекает данные
- Создаёт счёт в CRM
- Уведомляет бухгалтера
```
### Сценарий 3: Синхронизация с внешней системой
```
1. Внешний скрипт пишет в S3
2. n8n S3 Monitor (через 30с)
3. Redis событие
4. n8n External Sync:
- Проверяет формат файла
- Отправляет в external API
- Логирует в CRM
```
---
## ⚙️ Настройки производительности
### Интервал polling S3 Monitor
| Интервал | Задержка | Нагрузка на API | Рекомендация |
|----------|----------|-----------------|--------------|
| 10 сек | 0-10с | Высокая | Только для критичных файлов |
| 30 сек | 0-30с | Средняя | ✅ **Оптимально** |
| 60 сек | 0-60с | Низкая | Для некритичных файлов |
| 300 сек | 0-5мин | Минимальная | Для архивов |
### Количество файлов
- **< 1000 файлов:** Мониторь весь bucket
- **1000-10000:** Используй `Prefix` для фильтрации папок
- **> 10000:** Создай отдельные workflows для разных папок
---
## 🔧 Мониторинг и логи
### Проверка работы redis_bridge.js
```bash
ps aux | grep redis_bridge.js
tail -f /var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/redis_bridge.log
```
### Проверка событий в Redis
```bash
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
SUBSCRIBE crm:file:events
```
### Проверка n8n workflow
- n8n UI → Workflows → S3 File Monitor → Executions
---
## 🚀 Расширение системы
### Добавление новых источников событий
Любой компонент может публиковать в `crm:file:events`:
**Пример из PHP (CRM):**
```php
$redis = new Redis();
$redis->connect('147.45.146.17', 6379);
$redis->auth('CRM_Redis_Pass_2025_Secure!');
$event = [
'type' => 'file_created',
'source' => 'crm_api',
'timestamp' => date('c'),
'path' => $filePath,
'filename' => basename($filePath),
'size' => filesize($localPath),
'user_id' => $userId
];
$redis->publish('crm:file:events', json_encode($event));
```
**Пример из Python:**
```python
import redis
import json
from datetime import datetime
r = redis.Redis(
host='147.45.146.17',
port=6379,
password='CRM_Redis_Pass_2025_Secure!'
)
event = {
'type': 'file_created',
'source': 'python_script',
'timestamp': datetime.utcnow().isoformat() + 'Z',
'path': file_path,
'filename': os.path.basename(file_path)
}
r.publish('crm:file:events', json.dumps(event))
```
---
## 📝 Итого
✅ **Nextcloud файлы** → реал-тайм через `redis_bridge.js`
✅ **S3 прямые загрузки** → polling через n8n (0-30с задержка)
✅ **CRM файлы** → прямая публикация в Redis
✅ **Единая точка обработки** → Redis канал `crm:file:events`
**Гибкость** → любой сервис может подписаться и обработать
**Всё работает через один канал Redis! 🎉**

View File

@@ -0,0 +1,238 @@
# 🎉 ФИНАЛЬНАЯ СВОДКА - S3 МОНИТОРИНГ
## ✅ ЧТО РАБОТАЕТ:
### 1⃣ **S3 Monitor** (Docker контейнер)
```
Контейнер: s3-monitor
Статус: ✅ Работает
Bucket: f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c
Файлов: 24,523
Интервал: каждые 30 секунд
Автоперезапуск: ✅
```
**Что делает:**
- Каждые 30 секунд сканирует S3 bucket
- Получает **ВСЕ** файлы (24,523 штук через pagination)
- Сравнивает с предыдущим состоянием
- Публикует изменения в Redis
**Команды:**
```bash
docker logs s3-monitor -f # Логи в реальном времени
docker stop s3-monitor # Остановить
docker start s3-monitor # Запустить
docker restart s3-monitor # Перезапустить
```
---
### 2⃣ **Redis Bridge** (Nextcloud → CRM Redis)
```
Процесс: /usr/bin/nodejs redis_bridge.js
Статус: ✅ Работает
Порт NC Redis: 127.0.0.1:6380
Порт CRM Redis: 147.45.146.17:6379
```
**Что делает:**
- Слушает Nextcloud Redis канал `notify_storage_update`
- Фильтрует временные файлы (.part, .lock, cache)
- **Дедупликация** - один file_id = одно событие (в течение 5 сек)
- Публикует в CRM Redis канал `crm:file:events`
**Команды:**
```bash
tail -f redis_bridge.log # Логи
ps aux | grep redis_bridge # Статус
pkill -f redis_bridge.js # Остановить
nohup /usr/bin/nodejs redis_bridge.js > redis_bridge.log 2>&1 & # Запустить
```
---
### 3⃣ **Redis Канал** (централизованная шина событий)
```
Host: 147.45.146.17
Port: 6379
Password: CRM_Redis_Pass_2025_Secure!
Channel: crm:file:events
```
---
## 📊 ФОРМАТ СОБЫТИЙ:
### От S3 Monitor:
```json
{
"type": "file_created",
"source": "s3_monitor",
"timestamp": "2025-10-30T20:49:31.593Z",
"path": "folder/subfolder/file.xlsx",
"filename": "file.xlsx",
"action": "created",
"size": 8224,
"etag": "7004954627252c9d0a7e6417f8325d07",
"last_modified": "2025-10-30T20:49:14.132Z"
}
```
### От Nextcloud (redis_bridge):
```json
{
"type": "file_update",
"source": "nextcloud",
"timestamp": "2025-10-30T20:52:21.236Z",
"storage_id": 4,
"path": "crm2/CRM_Active_Files/file.pdf",
"file_id": 42594,
"filename": "file.pdf",
"operation": "update"
}
```
**Оба публикуются в один канал:** `crm:file:events`
---
## 🎯 КАК ОБРАБАТЫВАТЬ В N8N:
### Шаг 1: Импортируй workflow обработчик
Файл: `n8n_s3_event_processor.json`
### Шаг 2: Настрой Redis Trigger
```
Node: Redis Subscribe
Channel: crm:file:events
Credential: CRM Redis
```
### Шаг 3: Parse JSON (если нужно)
```javascript
// n8n автоматически парсит, но если нужно:
const message = $json.message;
const event = typeof message === 'string' ? JSON.parse(message) : message;
return [{ json: event }];
```
### Шаг 4: Фильтруй по типу
```javascript
// Только новые файлы
$json.type === 'file_created'
// Только XLSX
$json.filename.endsWith('.xlsx')
// Только из определённой папки
$json.path.includes('Documents/')
```
### Шаг 5: Обработай файл
```
Switch по расширению:
├─ .xlsx → Обработка Excel
├─ .pdf → OCR и извлечение данных
├─ .jpg → Обработка изображений
└─ Другие → Логирование
```
---
## 🧪 ПРОВЕРКА СОБЫТИЙ:
### Подпишись на Redis:
```bash
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
SUBSCRIBE crm:file:events
```
### Загрузи файл:
- Через Nextcloud WebUI
- Через S3 Browser
- Через aws-cli
### Увидишь событие:
```
1) "message"
2) "crm:file:events"
3) "{\"type\":\"file_created\",\"filename\":\"test.pdf\",...}"
```
---
## 📋 ИСТОЧНИКИ СОБЫТИЙ:
| Источник | Метод | Задержка | Фильтры |
|----------|-------|----------|---------|
| **Nextcloud WebUI** | Redis Bridge | 1-2 сек | ✅ Дедупликация<br>✅ Фильтр .part<br>✅ Фильтр cache |
| **S3 прямая загрузка** | S3 Monitor | 0-30 сек | Нет |
| **CRM API** | Прямая публикация | 0 сек | Настраивается |
---
## 🔧 ДОПОЛНИТЕЛЬНАЯ ФИЛЬТРАЦИЯ В N8N:
Если всё ещё приходит много событий от Nextcloud, добавь в n8n:
```javascript
// Фильтр: пропускаем дубликаты по filename + timestamp
const cache = $getWorkflowStaticData('node');
cache.recent = cache.recent || [];
const key = `${$json.filename}_${$json.file_id}`;
const now = Date.now();
// Очищаем старые (>10 секунд)
cache.recent = cache.recent.filter(item => (now - item.time) < 10000);
// Проверяем дубликат
if (cache.recent.find(item => item.key === key)) {
return []; // Пропускаем дубликат
}
// Добавляем в кеш
cache.recent.push({ key, time: now });
return [$input.item];
```
---
## 📁 ФАЙЛЫ:
Все в:
```
/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/
```
**Рабочие скрипты:**
-`s3_monitor_docker.js` - S3 мониторинг (запущен в Docker)
-`redis_bridge.js` - Nextcloud→CRM мост (запущен)
-`.env.s3monitor` - credentials для S3
**N8N Workflows для импорта:**
- `n8n_s3_event_processor.json` - обработчик событий (НОВЫЙ!)
- `n8n_nextcloud_activity_monitor.json` - альтернатива через Activity API
- `n8n_s3_monitor_workflow.json` - альтернатива S3 Monitor (если не хочешь Docker)
**Документация:**
- `SETUP_CHECKLIST.md` - чек-лист настройки
- `S3_MONITORING_GUIDE.md` - руководство по S3
- `ARCHITECTURE.md` - схема архитектуры
- `NEXTCLOUD_API_OVERVIEW.md` - обзор Nextcloud API
---
## 🎉 ГОТОВО!
**Система полностью работает:**
- ✅ S3 мониторинг (24,523 файла)
- ✅ Nextcloud мониторинг (с дедупликацией)
- ✅ Redis публикация
- ✅ Автоперезапуск
- ✅ Фильтрация дубликатов
**Теперь импортируй `n8n_s3_event_processor.json` в n8n и начинай обрабатывать файлы!** 🚀

View File

@@ -0,0 +1,377 @@
# 🌐 Nextcloud API - Обзор и возможности
## 📋 Доступные API
### 1. **WebDAV API** ✅ (РАБОТАЕТ)
**Базовый URL:** `https://office.clientright.ru:8443/remote.php/webdav/`
**Аутентификация:** Basic Auth (admin + app password)
**Возможности:**
- ✅ Список файлов и папок (PROPFIND)
- ✅ Загрузка файлов (PUT)
- ✅ Скачивание файлов (GET)
- ✅ Удаление файлов (DELETE)
- ✅ Создание папок (MKCOL)
- ✅ Перемещение/копирование (MOVE/COPY)
- ✅ Получение метаданных (PROPFIND)
**Пример - список файлов:**
```bash
curl -u "admin:APP_PASSWORD" \
-X PROPFIND \
"https://office.clientright.ru:8443/remote.php/webdav/" \
-H "Depth: 1"
```
**Пример - загрузка файла:**
```bash
curl -u "admin:APP_PASSWORD" \
-T /path/to/local/file.txt \
"https://office.clientright.ru:8443/remote.php/webdav/file.txt"
```
**Пример - скачивание файла:**
```bash
curl -u "admin:APP_PASSWORD" \
"https://office.clientright.ru:8443/remote.php/webdav/file.txt" \
-o downloaded.txt
```
---
### 2. **OCS API (Open Collaboration Services)** ✅
**Базовый URL:** `https://office.clientright.ru:8443/ocs/v2.php/`
**Заголовки:** `OCS-APIRequest: true`
**Формат ответа:** JSON (`?format=json`)
#### 2.1 **Capabilities API** (информация о сервере)
```bash
curl -u "admin:APP_PASSWORD" \
"https://office.clientright.ru:8443/ocs/v1.php/cloud/capabilities?format=json" \
-H "OCS-APIRequest: true"
```
**Ответ включает:**
- Версию Nextcloud (31.0.9)
- Доступные возможности
- Лимиты загрузки
- Настройки шаринга
---
#### 2.2 **Activity API** ✅ (СОБЫТИЯ ФАЙЛОВ!)
**URL:** `https://office.clientright.ru:8443/ocs/v2.php/apps/activity/api/v2/activity`
**Параметры:**
- `format=json` - формат ответа
- `limit=N` - количество событий
- `since=TIMESTAMP` - события после определённой даты
**Пример:**
```bash
curl -u "admin:APP_PASSWORD" \
"https://office.clientright.ru:8443/ocs/v2.php/apps/activity/api/v2/activity?format=json&limit=10" \
-H "OCS-APIRequest: true"
```
**Типы событий:**
- `file_created` - файл создан
- `file_changed` - файл изменён
- `file_deleted` - файл удалён
- `file_restored` - файл восстановлен
- `file_shared` - файл расшарен
**Структура события:**
```json
{
"activity_id": 195,
"type": "file_created",
"subject": "Вы создали «experimental_report.xlsx»",
"message": "",
"object_type": "files",
"object_id": 73460,
"object_name": "/experimental_report.xlsx",
"datetime": "2025-10-30T12:53:40+00:00",
"user": "admin"
}
```
**⚠️ Ограничения:**
- Нет real-time уведомлений (только polling)
- События агрегируются (несколько файлов в одном событии)
- Может быть задержка до минуты
---
#### 2.3 **Users API**
**Список пользователей:**
```bash
curl -u "admin:APP_PASSWORD" \
"https://office.clientright.ru:8443/ocs/v1.php/cloud/users?format=json" \
-H "OCS-APIRequest: true"
```
**Информация о пользователе:**
```bash
curl -u "admin:APP_PASSWORD" \
"https://office.clientright.ru:8443/ocs/v1.php/cloud/users/admin?format=json" \
-H "OCS-APIRequest: true"
```
---
#### 2.4 **Sharing API**
**Список расшаренных файлов:**
```bash
curl -u "admin:APP_PASSWORD" \
"https://office.clientright.ru:8443/ocs/v2.php/apps/files_sharing/api/v1/shares?format=json" \
-H "OCS-APIRequest: true"
```
**Создать публичную ссылку:**
```bash
curl -u "admin:APP_PASSWORD" \
-X POST \
-d "path=/file.txt&shareType=3" \
"https://office.clientright.ru:8443/ocs/v2.php/apps/files_sharing/api/v1/shares?format=json" \
-H "OCS-APIRequest: true"
```
---
### 3. **Direct Download URL**
Для файлов можно получить прямую ссылку скачивания:
**Формат:**
```
https://office.clientright.ru:8443/index.php/apps/files/ajax/download.php?dir=/&files=filename.txt
```
Или через WebDAV:
```
https://office.clientright.ru:8443/remote.php/webdav/filename.txt
```
---
## 🎯 Использование для мониторинга файлов
### Вариант 1: Activity API Polling (РЕКОМЕНДУЮ для Nextcloud)
**Создай n8n workflow:**
```
┌─────────────────────────────────────────────┐
│ Schedule (каждые 30 сек) │
└─────────────────┬───────────────────────────┘
┌─────────────────────────────────────────────┐
│ HTTP Request │
│ GET /ocs/v2.php/apps/activity/api/v2/ │
│ activity?format=json&limit=100 │
└─────────────────┬───────────────────────────┘
┌─────────────────────────────────────────────┐
│ Code (JS) │
│ - Фильтруем file_created/changed/deleted │
│ - Сохраняем последний activity_id │
│ - Возвращаем только новые события │
└─────────────────┬───────────────────────────┘
┌─────────────────────────────────────────────┐
│ Redis Publish │
│ Channel: crm:file:events │
└─────────────────────────────────────────────┘
```
**Преимущества:**
- ✅ Официальный API
- ✅ Надёжный
- ✅ Детальная информация о событиях
-Не требует доступа к Redis Nextcloud
**Недостатки:**
- ⚠️ Задержка 30-60 сек (polling)
- ⚠️ События агрегируются
---
### Вариант 2: Redis Bridge (УЖЕ РАБОТАЕТ!)
```
Nextcloud Redis (notify_storage_update) →
→ redis_bridge.js →
→ CRM Redis (crm:file:events)
```
**Преимущества:**
- ✅ Real-time (~1-2 сек)
-Не нагружает Nextcloud API
**Недостатки:**
- ⚠️ Требует доступ к внутреннему Redis
- ⚠️ Меньше метаданных
---
## 📊 Сравнение подходов
| Метод | Задержка | Детали | Сложность | Надёжность |
|-------|----------|--------|-----------|------------|
| **Activity API** | 30-60с | ⭐⭐⭐ | Низкая | ⭐⭐⭐ |
| **Redis Bridge** | 1-2с | ⭐⭐ | Средняя | ⭐⭐⭐ |
| **S3 Monitor** | 0-30с | ⭐⭐ | Низкая | ⭐⭐⭐ |
| **WebDAV Poll** | 60с+ | ⭐ | Низкая | ⭐⭐ |
---
## 🛠️ Примеры кода
### PHP - Получение последних событий
```php
<?php
$username = 'admin';
$password = 'APP_PASSWORD';
$url = 'https://office.clientright.ru:8443/ocs/v2.php/apps/activity/api/v2/activity?format=json&limit=10';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
curl_setopt($ch, CURLOPT_HTTPHEADER, ['OCS-APIRequest: true']);
$response = curl_exec($ch);
$data = json_decode($response, true);
foreach ($data['ocs']['data'] as $activity) {
if (in_array($activity['type'], ['file_created', 'file_changed', 'file_deleted'])) {
echo "Event: {$activity['type']}\n";
echo "File: {$activity['object_name']}\n";
echo "Time: {$activity['datetime']}\n";
echo "---\n";
}
}
?>
```
### Node.js - Activity API Monitor
```javascript
const axios = require('axios');
const Redis = require('ioredis');
const CONFIG = {
nextcloud: {
url: 'https://office.clientright.ru:8443',
username: 'admin',
password: 'APP_PASSWORD'
},
redis: {
host: '147.45.146.17',
port: 6379,
password: 'CRM_Redis_Pass_2025_Secure!'
},
pollInterval: 30000 // 30 секунд
};
const redis = new Redis(CONFIG.redis);
let lastActivityId = 0;
async function checkActivities() {
try {
const response = await axios.get(
`${CONFIG.nextcloud.url}/ocs/v2.php/apps/activity/api/v2/activity`,
{
params: { format: 'json', limit: 100 },
headers: { 'OCS-APIRequest': 'true' },
auth: {
username: CONFIG.nextcloud.username,
password: CONFIG.nextcloud.password
}
}
);
const activities = response.data.ocs.data;
const fileEvents = activities.filter(a =>
['file_created', 'file_changed', 'file_deleted'].includes(a.type) &&
a.activity_id > lastActivityId
);
for (const event of fileEvents.reverse()) {
const payload = {
type: event.type,
source: 'nextcloud_activity',
timestamp: event.datetime,
file_id: event.object_id,
path: event.object_name,
filename: event.object_name.split('/').pop(),
user: event.user
};
await redis.publish('crm:file:events', JSON.stringify(payload));
console.log(`📤 Published: ${event.type} - ${event.object_name}`);
lastActivityId = Math.max(lastActivityId, event.activity_id);
}
} catch (error) {
console.error('❌ Error:', error.message);
}
}
// Запуск
console.log('🚀 Nextcloud Activity Monitor');
setInterval(checkActivities, CONFIG.pollInterval);
checkActivities();
```
---
## 🎯 Рекомендации
### Для твоего use case:
**Комбинируй несколько подходов:**
1. **Nextcloud файлы (WebUI)****Redis Bridge** (real-time, 1-2с)
2. **S3 прямые загрузки****n8n S3 Monitor** (polling, 0-30с)
3. **CRM загрузки****Прямая публикация в Redis** (instant)
**Все события в одном канале:** `crm:file:events`
**Альтернатива (если нужна простота):**
- Используй **только Activity API** через n8n для Nextcloud событий
- Плюс **S3 Monitor** для прямых загрузок в S3
---
## 📚 Полезные ссылки
- [Nextcloud WebDAV Documentation](https://docs.nextcloud.com/server/latest/developer_manual/client_apis/WebDAV/)
- [Nextcloud OCS API](https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/)
- [Activity API](https://github.com/nextcloud/activity/blob/master/docs/endpoint-v2.md)
---
## 🔐 Безопасность
**App Password:** `tGHKS-3cC9m-7Hggb-65Awk-zxWQE`
**Пользователь:** `admin`
⚠️ **Важно:** Используй App Passwords, а не основной пароль!
---
**Готово! Теперь ты знаешь все доступные API Nextcloud! 🎉**

View File

@@ -0,0 +1,169 @@
# 🔑 Nextcloud Redis - Креды и подключение
## 📋 Основная информация
**Контейнер:** `nextcloud-redis`
**IP внутри Docker сети:** `172.24.0.4`
**Порт:** `6379`
**Пароль:** `НЕТ` (не установлен)
---
## 🔌 Варианты подключения
### **ВАРИАНТ 1: Из хоста (если проброшен порт)**
**Если пробросить порт наружу:**
```bash
# Перезапустить контейнер с проброшенным портом:
docker stop nextcloud-redis
docker start -p 6378:6379 nextcloud-redis
```
**Тогда подключаться так:**
```
Host: localhost (или 147.45.146.17)
Port: 6378
Password: (пусто)
```
---
### **ВАРИАНТ 2: Через Docker network IP**
**Из другого контейнера в той же сети:**
```
Host: 172.24.0.4
Port: 6379
Password: (пусто)
```
---
### **ВАРИАНТ 3: Из самого хоста (если в той же сети)**
**Если хост в той же Docker сети:**
```
Host: 172.24.0.4
Port: 6379
Password: (пусто)
```
---
## 📡 Каналы Redis для подписки
### **Главный канал для файловых изменений:**
```
notify_storage_update
```
Этот канал публикует события когда:
- Файл создан/удалён/переименован
- Папка создана/удалена/переименована
### **Другие полезные каналы:**
```
notify_activity # Общая активность
notify_notification # Уведомления пользователей
notify_pre_auth # Пред-аутентификация
```
---
## 🧪 Тест подключения
### **Из командной строки:**
```bash
# Подключиться к Redis через docker exec:
docker exec -it nextcloud-redis redis-cli
# Или если порт проброшен:
redis-cli -h localhost -p 6378
```
**Тест подписки на канал:**
```redis
SUBSCRIBE notify_storage_update
```
---
## 📝 Формат сообщений
Сообщения в канале `notify_storage_update` имеют формат:
```json
{
"type": "notify_storage_update",
"path": "/admin/files/Documents/Projects/Проект_390983/файл_395695.docx",
"user": "admin",
"action": "write" | "delete" | "rename",
"oldPath": "...", // только для rename
"timestamp": "..."
}
```
---
## 🔧 Для n8n подключения
**Настройки в n8n:**
```
Host: 172.24.0.4 (или localhost:6378 если проброшен порт)
Port: 6379 (или 6378 если проброшен)
Password: (оставить пустым)
Database: 0
```
**Триггер:**
- Использовать "Redis Trigger" ноду
- Channel: `notify_storage_update`
---
## 🚀 Для нашего Node.js listener
**Обновить `nextcloud_listener.js`:**
```javascript
const redis = new Redis({
host: '172.24.0.4', // или localhost если проброшен порт
port: 6379, // или 6378 если проброшен
password: '' // пусто
});
redis.subscribe('notify_storage_update');
redis.on('message', (channel, message) => {
const event = JSON.parse(message);
// Обработка события
});
```
---
## ⚠️ ВАЖНО
1. **Безопасность:** Redis БЕЗ пароля доступен только из Docker сети!
2. **Если нужен доступ снаружи:** Обязательно установи пароль!
3. **Мониторинг:** Следи за нагрузкой на Redis при подписке на каналы
---
## 🔐 Рекомендация: Установить пароль
Если планируешь пробрасывать порт наружу:
```bash
docker exec nextcloud-redis redis-cli CONFIG SET requirepass аш_пароль"
```
И добавить в Nextcloud config.php:
```php
'redis' => array (
'atype' => 'redis',
'host' => 'nextcloud-redis',
'port' => 6379,
'password' => аш_пароль',
),
```

View File

@@ -0,0 +1,182 @@
# 🎉 PRODUCTION READY - Мониторинг файлов
## ✅ ЧТО РАБОТАЕТ:
### 1⃣ Nextcloud Activity Monitor
**Скрипт:** `nextcloud_activity_monitor.js`
**Запущен:** ✅ (PID: 2122)
**Лог:** `nextcloud_activity.log`
**Мониторит:**
- Файлы загруженные через Nextcloud WebUI
- Файлы созданные/изменённые в Nextcloud
**Метод:**
- Nextcloud Activity API (polling каждые 30 сек)
- Разбивает агрегированные события на отдельные файлы
- БЕЗ дубликатов!
**Формат события:**
```json
{
"type": "file_created",
"source": "nextcloud_activity",
"timestamp": "2025-10-30T12:53:40+00:00",
"file_id": 73460,
"path": "/experimental_report.xlsx",
"filename": "experimental_report.xlsx",
"user": "admin",
"action": "created"
}
```
**Команды:**
```bash
# Статус
ps aux | grep nextcloud_activity_monitor
# Логи
tail -f nextcloud_activity.log
# Остановить
pkill -f nextcloud_activity_monitor.js
# Запустить
cd /var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage
nohup /usr/bin/nodejs nextcloud_activity_monitor.js > nextcloud_activity.log 2>&1 &
```
---
### 2⃣ S3 Monitor (Docker)
**Контейнер:** `s3-monitor`
**Запущен:** ✅ (Up 40 минут)
**Скрипт:** `s3_monitor_docker.js`
**Мониторит:**
- Файлы загруженные напрямую в S3
- Через S3 Browser, aws-cli, Cyberduck, скрипты
- Любые изменения в bucket
**Метод:**
- S3 ListObjectsV2 API (polling каждые 30 сек)
- Pagination - получает ВСЕ файлы (24,522 файла!)
- Сравнение по ETag
**Bucket:** `f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c`
**Формат события:**
```json
{
"type": "file_created",
"source": "s3_monitor",
"timestamp": "2025-10-30T20:49:31.593Z",
"path": "crm2/CRM_Active_Files/Documents/file.xlsx",
"filename": "file.xlsx",
"size": 8224,
"etag": "7004954627252c9d0a7e6417f8325d07",
"last_modified": "2025-10-30T20:49:14.132Z",
"action": "created"
}
```
**Команды:**
```bash
# Статус
docker ps | grep s3-monitor
# Логи
docker logs s3-monitor -f
# Остановить
docker stop s3-monitor
# Запустить
docker start s3-monitor
# Перезапустить
docker restart s3-monitor
```
---
### 3⃣ Redis Канал (центральная шина)
**Host:** `147.45.146.17`
**Port:** `6379`
**Password:** `CRM_Redis_Pass_2025_Secure!`
**Channel:** `crm:file:events`
**Подписаться:**
```bash
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
SUBSCRIBE crm:file:events
```
---
## 🚫 ЧТО ОСТАНОВЛЕНО:
### ❌ redis_bridge.js
**Причина:** Давал неполные данные, много дубликатов
**Заменён на:** Nextcloud Activity Monitor (даёт чистые данные)
---
## 📊 СРАВНЕНИЕ ДАННЫХ:
| Поле | Nextcloud Activity | S3 Monitor |
|------|-------------------|------------|
| **type** | ✅ file_created/changed/deleted | ✅ file_created/modified/deleted |
| **source** | nextcloud_activity | s3_monitor |
| **filename** | ✅ | ✅ |
| **path** | ✅ (Nextcloud путь) | ✅ (S3 полный путь) |
| **file_id** | ✅ | ❌ |
| **user** | ✅ | ❌ |
| **size** | ❌ | ✅ |
| **etag** | ❌ | ✅ |
| **mime_type** | ❌ | ❌ |
**Дополняют друг друга!** 🎯
---
## 🔧 АВТОЗАПУСК ПРИ ПЕРЕЗАГРУЗКЕ СЕРВЕРА:
### S3 Monitor:
✅ Уже настроен (`--restart unless-stopped`)
### Nextcloud Activity Monitor:
Создам systemd service:
```bash
sudo tee /etc/systemd/system/nextcloud-activity-monitor.service << 'EOF'
[Unit]
Description=Nextcloud Activity Monitor
After=network.target redis.service
[Service]
Type=simple
User=root
WorkingDirectory=/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage
ExecStart=/usr/bin/nodejs nextcloud_activity_monitor.js
Restart=always
RestartSec=10
StandardOutput=append:/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/nextcloud_activity.log
StandardError=append:/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/nextcloud_activity.log
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable nextcloud-activity-monitor
sudo systemctl start nextcloud-activity-monitor
```
---
## 🎯 ГОТОВО!
**Система полностью работает в production режиме!** 🚀
Хочешь чтобы я создал systemd service для автозапуска Nextcloud Activity Monitor? 😊

View File

@@ -0,0 +1,104 @@
# ⚡ Quick Start - Мониторинг файлов
## 🎯 Быстрая проверка системы
```bash
bash START.sh
```
Покажет статус всех компонентов и запустит остановленные.
---
## 📊 Что работает прямо сейчас:
### ✅ Nextcloud Activity Monitor
- **PID:** 2122
- **Лог:** `nextcloud_activity.log`
- **Что делает:** Ловит файлы из Nextcloud WebUI
- **Задержка:** 30 сек
### ✅ S3 Monitor (Docker)
- **Контейнер:** `s3-monitor`
- **Uptime:** 40+ минут
- **Что делает:** Ловит файлы загруженные напрямую в S3
- **Задержка:** 30 сек
- **Файлов:** 24,522
### ✅ Redis канал
- **Адрес:** `147.45.146.17:6379`
- **Канал:** `crm:file:events`
- **Статус:** Оба монитора публикуют события ✅
---
## 🧪 Быстрый тест
### Тест 1: Загрузи файл в Nextcloud
```bash
# В другом терминале подпишись на события
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
SUBSCRIBE crm:file:events
```
Загрузи файл через Nextcloud WebUI → через 30 сек увидишь событие!
### Тест 2: Загрузи файл в S3
```bash
echo "test" > /tmp/test.txt
aws s3 cp /tmp/test.txt \
s3://f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c/test_$(date +%s).txt \
--endpoint-url https://s3.twcstorage.ru
```
Через 0-30 сек увидишь событие!
---
## 🔧 Команды управления
```bash
# Проверка статуса
bash START.sh
# Логи в реальном времени
tail -f nextcloud_activity.log
docker logs s3-monitor -f
# Остановка
pkill -f nextcloud_activity_monitor.js
docker stop s3-monitor
# Запуск
bash START.sh
```
---
## 📚 Документация
- `README.md` - обзор системы
- `PRODUCTION_READY.md` - production конфигурация
- `ARCHITECTURE.md` - архитектура
---
## 🆘 Troubleshooting
**Нет событий?**
1. Проверь статус: `bash START.sh`
2. Проверь логи: `tail -f nextcloud_activity.log`
3. Проверь Redis: подпишись на канал
**Много дубликатов?**
- От Nextcloud: дедупликация включена (1 событие вместо 6)
- От S3: дубликатов нет
**Нужна помощь?**
- Читай `PRODUCTION_READY.md`
- Проверяй логи
---
**Всё готово! 🚀**

View File

@@ -0,0 +1,137 @@
# 🔔 Система мониторинга файлов CRM
Автоматический мониторинг изменений файлов в S3 и Nextcloud с публикацией событий в Redis.
## 🎯 Компоненты системы
### 1. Nextcloud Activity Monitor
**Файл:** `nextcloud_activity_monitor.js`
**Назначение:** Мониторинг файлов загруженных через Nextcloud WebUI
**Метод:** Nextcloud Activity API
**Интервал:** 30 секунд
**Запуск:**
```bash
cd /var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage
nohup /usr/bin/nodejs nextcloud_activity_monitor.js > nextcloud_activity.log 2>&1 &
```
**Управление:**
```bash
ps aux | grep nextcloud_activity_monitor # Статус
tail -f nextcloud_activity.log # Логи
pkill -f nextcloud_activity_monitor.js # Остановить
```
---
### 2. S3 Monitor (Docker)
**Контейнер:** `s3-monitor`
**Назначение:** Мониторинг файлов загруженных напрямую в S3
**Bucket:** `f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c`
**Интервал:** 30 секунд
**Файлов:** ~24,500
**Управление:**
```bash
docker ps | grep s3-monitor # Статус
docker logs s3-monitor -f # Логи
docker stop s3-monitor # Остановить
docker start s3-monitor # Запустить
docker restart s3-monitor # Перезапустить
```
---
### 3. Redis (центральная шина событий)
**Адрес:** `147.45.146.17:6379`
**Канал:** `crm:file:events`
**Password:** `CRM_Redis_Pass_2025_Secure!`
**Подписка:**
```bash
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
SUBSCRIBE crm:file:events
```
---
## 📊 Формат событий
### От Nextcloud Activity Monitor:
```json
{
"type": "file_created",
"source": "nextcloud_activity",
"timestamp": "2025-10-30T12:53:40+00:00",
"file_id": 73460,
"path": "/experimental_report.xlsx",
"filename": "experimental_report.xlsx",
"user": "admin",
"action": "created"
}
```
### От S3 Monitor:
```json
{
"type": "file_created",
"source": "s3_monitor",
"timestamp": "2025-10-30T20:49:31.593Z",
"path": "crm2/CRM_Active_Files/Documents/file.xlsx",
"filename": "file.xlsx",
"size": 8224,
"etag": "7004954627252c9d0a7e6417f8325d07",
"last_modified": "2025-10-30T20:49:14.132Z",
"action": "created"
}
```
---
## 🔧 Credentials
### Nextcloud API:
```
URL: https://office.clientright.ru:8443
User: admin
App Password: tGHKS-3cC9m-7Hggb-65Awk-zxWQE
```
### S3 (TWC Storage):
```
Endpoint: https://s3.twcstorage.ru
Region: ru-1
Access Key: 2OMAK5ZNM900TAXM16J7
Secret Key: f4ADllb5VZBAt2HdsyB8WcwVEU7U74MwFCa1DARG
Bucket: f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c
```
---
## 📚 Дополнительные документы
- `PRODUCTION_READY.md` - полное описание production конфигурации
- `ARCHITECTURE.md` - схема архитектуры системы
- `S3_MONITORING_GUIDE.md` - руководство по S3 мониторингу
- `NEXTCLOUD_API_OVERVIEW.md` - обзор Nextcloud API
- `SETUP_CHECKLIST.md` - чек-лист настройки
---
## 🚀 Для разработчиков
### n8n Workflows (готовые для импорта):
- `n8n_s3_event_processor.json` - обработчик событий из Redis
- `n8n_nextcloud_activity_monitor.json` - альтернатива через n8n
- `n8n_s3_monitor_workflow.json` - альтернатива S3 Monitor через n8n
### Утилиты:
- `get_s3_credentials.sh` - получение S3 credentials
---
**Дата создания:** 30 октября 2025
**Версия:** 1.0
**Статус:** Production Ready ✅

View File

@@ -0,0 +1,248 @@
# 🔍 Руководство по мониторингу S3
## Проблема
Тебе нужно ловить **любые** изменения файлов в S3 bucket, даже если они загружены:
- Вручную через S3 Browser / Cyberduck
- Из внешних скриптов
- Не через CRM или Nextcloud
## ❌ Почему не Event Notifications?
TWC Storage **не поддерживает** S3 Event Notifications официально (не документировано).
## ✅ РЕШЕНИЕ: n8n Workflow с Polling
### Как работает:
```
n8n каждые 30 сек → Список файлов в S3 → Сравнение с предыдущим состоянием →
→ Обнаружены изменения → Публикация в Redis → Твои обработчики
```
---
## 📋 Пошаговая инструкция
### Шаг 1: Импортируй workflow в n8n
1. Открой n8n: https://n8n.clientright.pro
2. Создай новый workflow
3. Нажми **Import from File**
4. Загрузи файл: `n8n_s3_monitor_workflow.json`
### Шаг 2: Настрой S3 Credentials
В n8n создай credentials:
**Тип:** AWS S3
**Имя:** `TWC S3`
**Параметры:**
```
Access Key ID: [твой S3 ключ из Nextcloud]
Secret Access Key: [твой S3 секрет из Nextcloud]
Region: ru-1
Custom Endpoints: ✅ (включить!)
S3 Endpoint: https://s3.twcstorage.ru
Force Path Style: ✅ (включить!)
```
**Как получить ключи:**
```bash
docker exec nextcloud-fresh php occ files_external:list --output=json | jq -r '.[0].configuration | "Key: \(.key)\nSecret: \(.secret)\nBucket: \(.bucket)"'
```
### Шаг 3: Настрой Redis Credentials
**Тип:** Redis
**Имя:** `CRM Redis`
**Параметры:**
```
Host: 147.45.146.17
Port: 6379
Password: CRM_Redis_Pass_2025_Secure!
Database: 0
```
### Шаг 4: Настрой Environment Variables (если нужно)
В n8n Settings → Environment Variables:
```
S3_BUCKET=f9825c87-18698658-c378-4aa7-91cc-0c131bebccda
WEBHOOK_URL=https://твой-эндпоинт.com/webhook (опционально)
```
### Шаг 5: Настрой Bucket и Prefix
В ноде **List S3 Files**:
- `Bucket Name`: укажи свой bucket (или используй `{{$env.S3_BUCKET}}`)
- `Prefix`: укажи папку для мониторинга (например `nextcloud/data/admin/files/`)
- Оставь пустым для мониторинга всего bucket
### Шаг 6: Активируй Workflow
1. Нажми **Active** (включи workflow)
2. Первый запуск создаст начальное состояние файлов
3. Последующие запуски будут сравнивать с предыдущим состоянием
---
## 🧪 Тестирование
### 1. Загрузи тестовый файл в S3
Через S3 Browser, Cyberduck или aws-cli:
```bash
echo "test" > test.txt
aws s3 cp test.txt s3://твой-bucket/test.txt \
--endpoint-url https://s3.twcstorage.ru
```
### 2. Подожди 30 секунд (интервал polling)
### 3. Проверь Redis
```bash
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
SUBSCRIBE crm:file:events
```
Должно прийти:
```json
{
"type": "file_created",
"source": "s3_monitor",
"timestamp": "2025-10-30T12:34:56Z",
"path": "test.txt",
"filename": "test.txt",
"size": 5,
"etag": "\"098f6bcd4621d373cade4e832627b4f6\"",
"last_modified": "2025-10-30T12:34:50Z"
}
```
---
## ⚙️ Настройка интервала
Измени интервал проверки в ноде **"Каждые 30 секунд"**:
- **10 секунд** - почти реал-тайм, но больше нагрузка на S3 API
- **30 секунд** - оптимальный баланс (рекомендуется)
- **60 секунд** - экономия API запросов
**Важно:** TWC может лимитировать количество API запросов!
---
## 📊 Типы событий
Workflow генерирует 3 типа событий:
1. **`file_created`** - новый файл появился в bucket
2. **`file_modified`** - файл изменился (другой ETag)
3. **`file_deleted`** - файл удалён из bucket
---
## 🔄 Обработка событий в других workflows
Создай новый workflow в n8n:
### Trigger: Redis (Subscribe)
```
Host: 147.45.146.17
Port: 6379
Password: CRM_Redis_Pass_2025_Secure!
Channel: crm:file:events
```
### Filter: По типу события
```javascript
// Обрабатываем только создание файлов
return $json.type === 'file_created';
```
### Switch: По расширению файла
```javascript
const ext = $json.filename.split('.').pop().toLowerCase();
switch(ext) {
case 'pdf':
return [0]; // Обработка PDF
case 'jpg':
case 'png':
return [1]; // Обработка изображений
case 'xlsx':
case 'csv':
return [2]; // Обработка таблиц
default:
return [3]; // Остальные файлы
}
```
---
## 🎯 Пример: Автоматическая обработка ERV файлов
```
Redis Subscribe (crm:file:events) →
→ Filter (filename contains "erv") →
→ Download from S3 →
→ Process ERV →
→ Upload to CRM →
→ Notify user
```
---
## 📝 Мониторинг нескольких buckets
Если тебе нужно мониторить несколько buckets:
1. **Вариант 1:** Создай отдельный workflow для каждого bucket
2. **Вариант 2:** Используй Loop в workflow для перебора buckets
---
## 🚨 Важные замечания
1. **State сохраняется в Static Data** - не удаляй workflow без экспорта!
2. **Первый запуск не генерирует события** - только создаёт начальное состояние
3. **ETag используется для определения изменений** - если файл перезаписан с тем же содержимым, событие не сработает
4. **Polling = задержка** - событие придёт через 0-30 секунд после реального изменения
---
## 🔧 Troubleshooting
### Проблема: Не приходят события
- Проверь что workflow **Active** (зелёная галочка)
- Проверь логи workflow (Execute → View executions)
- Проверь credentials (S3 и Redis)
### Проблема: Слишком много событий
- Уменьши область мониторинга через `Prefix`
- Увеличь интервал polling до 60-120 секунд
### Проблема: Пропускаются изменения
- Уменьши интервал до 10-15 секунд
- Проверь что State сохраняется (Static Data)
---
## 📚 Дополнительные материалы
- [n8n AWS S3 Node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.awss3/)
- [n8n Redis Node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.redis/)
- [n8n Code Node](https://docs.n8n.io/code-examples/methods-variables-reference/)
---
## 🎉 Готово!
Теперь у тебя есть полноценный мониторинг S3 bucket в реальном времени!
Все изменения файлов будут автоматически публиковаться в Redis канал `crm:file:events`,
откуда их могут подхватить другие твои системы (CRM, другие n8n workflows, и т.д.)

View File

@@ -0,0 +1,228 @@
# ✅ Чек-лист настройки S3 мониторинга
## 📋 Что нужно сделать
### Шаг 1: Получи S3 Credentials ✅
```bash
cd /var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage
bash get_s3_credentials.sh
```
**Сохрани куда-нибудь:**
- Access Key ID
- Secret Access Key
- Bucket name
- Endpoint: `https://s3.twcstorage.ru`
- Region: `ru-1`
---
### Шаг 2: Импортируй workflow в n8n ⏳
1. Открой https://n8n.clientright.pro
2. Нажми **"+"** → **Import from File**
3. Выбери файл: `/var/www/.../n8n_s3_monitor_workflow.json`
4. Нажми **Import**
---
### Шаг 3: Настрой S3 Credentials в n8n ⏳
1. В n8n иди в **Settings** (⚙️) → **Credentials**
2. Нажми **Add Credential** → выбери **AWS**
3. Заполни:
- **Name:** `TWC S3`
- **Access Key ID:** (из шага 1)
- **Secret Access Key:** (из шага 1)
- **Region:** `ru-1`
4. **Включи** `Custom Endpoints`
5. **S3 Endpoint:** `https://s3.twcstorage.ru`
6. **Включи** `Force Path Style`
7. Нажми **Test** → должно быть ✅
8. **Save**
---
### Шаг 4: Настрой Redis Credentials в n8n ⏳
1. **Add Credential****Redis**
2. Заполни:
- **Name:** `CRM Redis`
- **Host:** `147.45.146.17`
- **Port:** `6379`
- **Password:** `CRM_Redis_Pass_2025_Secure!`
- **Database:** `0`
3. **Test** → ✅
4. **Save**
---
### Шаг 5: Настрой workflow ⏳
1. Открой импортированный workflow **"S3 File Monitor"**
2. Кликни на ноду **"List S3 Files"**
3. В поле **Credential for AWS** выбери `TWC S3`
4. В поле **Bucket Name:**
- Вариант 1: Впиши имя bucket из шага 1
- Вариант 2: Оставь `{{$env.S3_BUCKET}}` и настрой env variable
5. В поле **Prefix** (опционально):
- Оставь пустым для мониторинга всего bucket
- Или укажи папку, например: `nextcloud/data/admin/files/`
6. Кликни на ноду **"Publish to Redis"**
7. Выбери credential: `CRM Redis`
8. **Save** workflow
---
### Шаг 6: Активируй workflow ⏳
1. Переключи тумблер **Active** в ON (вверху справа)
2. Workflow начнёт работать!
**Первый запуск:**
- Создаст начальное состояние файлов
- **НЕ** сгенерирует события (это нормально!)
**Последующие запуски (каждые 30 сек):**
- Будут сравнивать с предыдущим состоянием
- Генерировать события при изменениях
---
### Шаг 7: Протестируй! 🧪
#### Тест 1: Загрузи файл в S3
Через **S3 Browser** или **aws-cli**:
```bash
echo "test content" > /tmp/test-file.txt
aws s3 cp /tmp/test-file.txt s3://ИМЯ-BUCKET/test-file.txt \
--endpoint-url https://s3.twcstorage.ru
```
#### Тест 2: Подожди 30 секунд
⏱️ Время для следующего polling цикла...
#### Тест 3: Проверь Redis
```bash
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
--csv SUBSCRIBE crm:file:events
```
Должно прийти:
```
"subscribe","crm:file:events",1
"message","crm:file:events","{\"type\":\"file_created\",\"source\":\"s3_monitor\",...}"
```
#### Тест 4: Проверь n8n executions
1. В n8n → **S3 File Monitor** workflow
2. Нажми **Executions** (внизу)
3. Посмотри последние запуски
4. Должны быть ✅ зелёные
---
### Шаг 8: Настрой обработчик событий (опционально) ⏳
Создай новый workflow в n8n для обработки событий:
1. **Trigger:** Redis (Subscribe)
- Channel: `crm:file:events`
- Credential: `CRM Redis`
2. **Filter** по типу файла:
```javascript
// Обрабатываем только PDF
return $json.filename.endsWith('.pdf');
```
3. **Твоя логика:**
- Download from S3
- Process
- Upload to CRM
- Notify user
---
## 🔧 Troubleshooting
### ❌ Workflow не запускается
- Проверь что он **Active** (зелёная галочка)
- Проверь Executions → есть ли ошибки?
### ❌ S3 Connection failed
- Проверь credentials (Access Key, Secret)
- Проверь что включен `Force Path Style` ✅
- Проверь endpoint: `https://s3.twcstorage.ru`
### ❌ Redis Connection failed
- Проверь firewall: порт 6379 открыт?
- Проверь пароль: `CRM_Redis_Pass_2025_Secure!`
- Попробуй из терминала:
```bash
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' PING
```
### ❌ События не приходят
- Убедись что файл добавлен **в правильный bucket**
- Убедись что файл **в нужной папке** (если указан Prefix)
- Подожди 30 секунд для polling цикла
- Проверь Static Data в workflow (сохраняется ли состояние?)
### ⚠️ Слишком много событий
- Уменьши область мониторинга через `Prefix`
- Увеличь интервал до 60-120 секунд
---
## 📊 Финальная проверка
После всех шагов у тебя должно быть:
- ✅ S3 credentials сохранены в n8n
- ✅ Redis credentials сохранены в n8n
- ✅ Workflow "S3 File Monitor" импортирован
- ✅ Workflow активирован (Active = ON)
- ✅ Тестовый файл загружен в S3
- ✅ Событие пришло в Redis канал `crm:file:events`
- ✅ Execution в n8n показывает ✅ success
---
## 🎉 Готово!
Теперь **любые** изменения в твоём S3 bucket будут автоматически:
1. Обнаруживаться (каждые 30 сек)
2. Публиковаться в Redis (`crm:file:events`)
3. Доступны для обработки в n8n, CRM, и других сервисах
---
## 📚 Дополнительные файлы
- `S3_MONITORING_GUIDE.md` - полное руководство
- `ARCHITECTURE.md` - схема архитектуры
- `n8n_s3_monitor_workflow.json` - workflow для импорта
- `get_s3_credentials.sh` - скрипт для получения credentials
---
## 🆘 Нужна помощь?
Если что-то не работает:
1. Проверь логи n8n executions
2. Проверь Redis подключение
3. Проверь S3 credentials
4. Перечитай `S3_MONITORING_GUIDE.md`
**Удачи!** 🚀

View File

@@ -0,0 +1,76 @@
#!/bin/bash
#
# Скрипт для запуска/проверки всех компонентов мониторинга файлов
#
echo "🚀 CRM File Monitoring System"
echo "════════════════════════════════════════════════════════════════════════════════"
echo ""
cd /var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage
# Проверка S3 Monitor
echo "1⃣ S3 Monitor (Docker):"
if docker ps | grep -q s3-monitor; then
echo " ✅ Работает"
docker ps --format " Статус: {{.Status}}" | grep s3-monitor
else
echo " ❌ НЕ работает"
echo " Запускаем..."
docker start s3-monitor 2>/dev/null || echo " ⚠️ Контейнер не существует, запустите вручную"
fi
echo ""
# Проверка Nextcloud Activity Monitor
echo "2⃣ Nextcloud Activity Monitor:"
if ps aux | grep -v grep | grep -q nextcloud_activity_monitor.js; then
PID=$(ps aux | grep -v grep | grep nextcloud_activity_monitor.js | awk '{print $2}')
echo " ✅ Работает (PID: $PID)"
else
echo " ❌ НЕ работает"
echo " Запускаем..."
nohup /usr/bin/nodejs nextcloud_activity_monitor.js > nextcloud_activity.log 2>&1 &
sleep 2
echo " ✅ Запущен (PID: $!)"
fi
echo ""
# Проверка Redis
echo "3⃣ Redis подключение:"
if redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' PING 2>&1 | grep -q PONG; then
echo " ✅ Redis доступен"
else
echo " ❌ Redis недоступен"
fi
echo ""
echo "════════════════════════════════════════════════════════════════════════════════"
echo ""
echo "📋 СТАТУС:"
echo ""
echo "Nextcloud Activity Monitor:"
tail -3 nextcloud_activity.log 2>/dev/null | tail -1
echo ""
echo "S3 Monitor:"
docker logs s3-monitor 2>&1 | tail -3 | tail -1
echo ""
echo "════════════════════════════════════════════════════════════════════════════════"
echo ""
echo "📚 Команды:"
echo ""
echo "Логи в реальном времени:"
echo " tail -f nextcloud_activity.log"
echo " docker logs s3-monitor -f"
echo ""
echo "Подписка на события:"
echo " redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' SUBSCRIBE crm:file:events"
echo ""
echo "Документация:"
echo " cat README.md"
echo " cat PRODUCTION_READY.md"
echo ""

View File

@@ -0,0 +1,23 @@
<?php
/**
* ПРОСТОЙ Прокси для скачивания файла из S3
* Просто отдаём публичный URL - S3 сам разберётся
*/
$s3Path = isset($_GET['path']) ? $_GET['path'] : '';
if (empty($s3Path)) {
http_response_code(400);
die('Missing path parameter');
}
// Формируем публичный S3 URL
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$s3Url = 'https://s3.twcstorage.ru/' . $bucket . '/' . $s3Path;
error_log("download_s3_file.php: Redirecting to: $s3Url");
// РЕДИРЕКТИМ на S3 напрямую
header('Location: ' . $s3Url);
exit;
?>

View File

@@ -0,0 +1,40 @@
<?php
/**
* Быстрая индексация одного файла в Nextcloud
*/
header('Content-Type: application/json');
$input = json_decode(file_get_contents('php://input'), true);
$path = $input['path'] ?? '';
if (empty($path)) {
echo json_encode(['success' => false, 'error' => 'Missing path']);
exit;
}
// Формируем Nextcloud путь
$ncPath = '/admin/files/crm/' . $path;
// Запускаем сканирование
$command = "docker exec -u www-data nextcloud-fresh php occ files:scan --path=" . escapeshellarg($ncPath) . " 2>&1";
exec($command, $output, $returnCode);
if ($returnCode === 0) {
echo json_encode([
'success' => true,
'message' => 'File indexed successfully',
'output' => implode("\n", $output)
]);
} else {
echo json_encode([
'success' => false,
'error' => 'Indexing failed',
'output' => implode("\n", $output)
]);
}
?>

View File

@@ -0,0 +1,103 @@
<?php
/**
* OnlyOffice Callback для сохранения файлов в S3
*/
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/shared/EnvLoader.php';
require_once '/var/www/fastuser/data/www/crm.clientright.ru/vendor/autoload.php';
EnvLoader::load('/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/.env');
error_reporting(E_ALL);
ini_set('display_errors', 0);
// Логируем все запросы
$input = file_get_contents('php://input');
$data = json_decode($input, true);
error_log("=== ONLYOFFICE CALLBACK ===");
error_log("Method: " . $_SERVER['REQUEST_METHOD']);
error_log("Body: " . $input);
// OnlyOffice отправляет POST с JSON данными
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($data)) {
$status = $data['status'] ?? 0;
$key = $data['key'] ?? 'unknown';
error_log("Callback Status: $status, Key: $key");
// Status 2 = файл сохранён, нужно скачать и загрузить в S3
if ($status == 2 && isset($data['url'])) {
$downloadUrl = $data['url'];
error_log("File saved! Download URL: " . $downloadUrl);
try {
// Скачиваем изменённый файл от OnlyOffice
$fileContent = file_get_contents($downloadUrl);
if ($fileContent === false) {
error_log("Failed to download file from OnlyOffice");
http_response_code(500);
echo json_encode(['error' => 1]);
exit;
}
error_log("Downloaded file: " . strlen($fileContent) . " bytes");
// Извлекаем путь к файлу из documentKey
// В $key хранится md5($s3Path . '_' . $version)
// Нам нужен оригинальный путь, который мы должны хранить отдельно
// ВРЕМЕННО: Сохраняем в отдельную папку в S3 для отладки
// TODO: Нужно связать documentKey с оригинальным путём файла
// Инициализируем S3 клиент
$s3Client = new Aws\S3\S3Client([
'version' => 'latest',
'region' => 'ru-1',
'endpoint' => 'https://s3.twcstorage.ru',
'use_path_style_endpoint' => true,
'credentials' => [
'key' => EnvLoader::getRequired('S3_ACCESS_KEY'),
'secret' => EnvLoader::getRequired('S3_SECRET_KEY')
],
'suppress_php_deprecation_warning' => true
]);
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
// ВРЕМЕННОЕ РЕШЕНИЕ: Сохраняем в папку /onlyoffice_saved/
$savedPath = 'onlyoffice_saved/' . $key . '_' . date('Y-m-d_H-i-s') . '.docx';
$result = $s3Client->putObject([
'Bucket' => $bucket,
'Key' => $savedPath,
'Body' => $fileContent,
'ContentType' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
]);
error_log("File saved to S3: " . $savedPath);
error_log("S3 Response: " . json_encode($result->toArray()));
http_response_code(200);
echo json_encode(['error' => 0]);
exit;
} catch (Exception $e) {
error_log("Error saving file to S3: " . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 1, 'message' => $e->getMessage()]);
exit;
}
}
// Другие статусы (1 = открыт, 4 = закрыт и т.д.)
http_response_code(200);
echo json_encode(['error' => 0]);
exit;
}
// Для всех остальных запросов - 200 OK
http_response_code(200);
echo json_encode(['error' => 0]);
?>

View File

@@ -0,0 +1,121 @@
<?php
/**
* OnlyOffice Callback v2 с сохранением в оригинальный файл S3
*/
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/shared/EnvLoader.php';
require_once '/var/www/fastuser/data/www/crm.clientright.ru/vendor/autoload.php';
EnvLoader::load('/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/.env');
error_reporting(E_ALL);
ini_set('display_errors', 0);
$input = file_get_contents('php://input');
$data = json_decode($input, true);
error_log("=== ONLYOFFICE CALLBACK V2 ===");
error_log("Body: " . $input);
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($data)) {
$status = $data['status'] ?? 0;
$key = $data['key'] ?? 'unknown';
error_log("Status: $status, Key: $key");
// Status 2 = файл сохранён, нужно скачать и загрузить в S3
if ($status == 2 && isset($data['url'])) {
$downloadUrl = $data['url'];
error_log("File saved! Downloading from: " . $downloadUrl);
try {
// Подключаемся к Redis чтобы узнать оригинальный путь
$redis = new Predis\Client([
'scheme' => 'tcp',
'host' => EnvLoader::getRequired('REDIS_HOST'),
'port' => (int)EnvLoader::getRequired('REDIS_PORT'),
'password' => EnvLoader::getRequired('REDIS_PASSWORD')
]);
// Получаем маппинг
$mapping = $redis->get("crm:onlyoffice:key:$key");
if (!$mapping) {
error_log("ERROR: No mapping found for key $key");
// Сохраняем в резервную папку
$s3Path = 'onlyoffice_saved/' . $key . '_' . date('Y-m-d_H-i-s') . '.docx';
} else {
$mappingData = json_decode($mapping, true);
$s3Path = $mappingData['s3_path'];
error_log("Found mapping: $key$s3Path");
}
// Скачиваем файл от OnlyOffice
$fileContent = file_get_contents($downloadUrl);
if ($fileContent === false) {
throw new Exception("Failed to download file from OnlyOffice");
}
error_log("Downloaded: " . strlen($fileContent) . " bytes");
// Инициализируем S3 клиент
$s3Client = new Aws\S3\S3Client([
'version' => 'latest',
'region' => 'ru-1',
'endpoint' => 'https://s3.twcstorage.ru',
'use_path_style_endpoint' => true,
'credentials' => [
'key' => EnvLoader::getRequired('S3_ACCESS_KEY'),
'secret' => EnvLoader::getRequired('S3_SECRET_KEY')
],
'suppress_php_deprecation_warning' => true
]);
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
// Загружаем в S3 (ПЕРЕЗАПИСЫВАЕМ оригинальный файл!)
$result = $s3Client->putObject([
'Bucket' => $bucket,
'Key' => $s3Path,
'Body' => $fileContent,
'ContentType' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'Metadata' => [
'saved_by' => 'onlyoffice',
'saved_at' => date('Y-m-d H:i:s')
]
]);
error_log("✅ File saved to S3: $s3Path");
// Публикуем событие в Redis
$redis->publish('crm:file:events', json_encode([
'type' => 'file_modified',
'source' => 'onlyoffice',
'timestamp' => date('c'),
'path' => $s3Path,
'size' => strlen($fileContent),
'action' => 'updated_via_onlyoffice'
]));
http_response_code(200);
echo json_encode(['error' => 0]);
exit;
} catch (Exception $e) {
error_log("ERROR: " . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 1, 'message' => $e->getMessage()]);
exit;
}
}
// Другие статусы
http_response_code(200);
echo json_encode(['error' => 0]);
exit;
}
http_response_code(200);
echo json_encode(['error' => 0]);
?>

View File

@@ -1,110 +1,237 @@
<?php <?php
/** /**
* Простой редирект на файл в Nextcloud БЕЗ CSRF проверок * ФИНАЛ: OnlyOffice + Pre-signed S3 URL
* Использует FilePathManager для новой структуры файлов * Теперь с CORS и правильными настройками!
*/ */
// Включаем отображение ошибок require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/shared/EnvLoader.php';
EnvLoader::load('/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/.env');
error_reporting(E_ALL); error_reporting(E_ALL);
ini_set('display_errors', 1); ini_set('display_errors', 1);
// Подключаем конфигурацию и FilePathManager
require_once '/var/www/fastuser/data/www/crm.clientright.ru/config.inc.php';
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/FilePathManager.php';
// Получаем параметры
$fileName = isset($_GET['fileName']) ? $_GET['fileName'] : ''; $fileName = isset($_GET['fileName']) ? $_GET['fileName'] : '';
$recordId = isset($_GET['recordId']) ? $_GET['recordId'] : '';
// Если fileName содержит полный URL S3, извлекаем путь к файлу if (empty($fileName)) {
$ncPath = ''; die("❌ fileName не указан");
}
// Извлекаем S3 путь
$s3Path = '';
if (strpos($fileName, 'http') === 0) { if (strpos($fileName, 'http') === 0) {
// Декодируем URL
$fileName = urldecode($fileName); $fileName = urldecode($fileName);
// Извлекаем путь после bucket ID
// Формат: https://s3.twcstorage.ru/BUCKET_ID/crm2/CRM_Active_Files/...
$bucketId = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c'; $bucketId = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$pos = strpos($fileName, $bucketId . '/'); $pos = strpos($fileName, $bucketId . '/');
if ($pos !== false) { if ($pos !== false) {
$s3Path = substr($fileName, $pos + strlen($bucketId) + 1); $s3Path = substr($fileName, $pos + strlen($bucketId) + 1);
// Nextcloud путь = /crm/ + s3_path
$ncPath = '/crm/' . $s3Path;
} }
} }
if (empty($ncPath)) { if (empty($s3Path)) {
die(" Ошибка: Не удалось извлечь путь из URL: $fileName"); die("Не удалось извлечь путь из URL");
} }
// Настройки Nextcloud // Извлекаем расширение файла
$nextcloudUrl = 'https://office.clientright.ru:8443'; $ext = strtolower(pathinfo($s3Path, PATHINFO_EXTENSION));
$username = 'admin';
$password = 'office';
// Вспомогательная функция: кодирование пути по сегментам (WebDAV) // ПРЯМОЙ S3 URL (bucket публичный, CORS настроен!)
$encodePath = function(array $segments) { $bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
return implode('/', array_map('rawurlencode', $segments)); $s3Url = 'https://s3.twcstorage.ru/' . $bucket . '/' . $s3Path;
};
// Получаем fileId через WebDAV PROPFIND // Генерируем версию и ключ документа
$fileId = null; $version = time();
$propfindUrl = $nextcloudUrl . '/remote.php/dav/files/' . $username . $ncPath; // СЛУЧАЙНЫЙ ключ при каждом запросе, чтобы OnlyOffice не использовал кеш!
$documentKey = md5($s3Path . '_' . $version);
error_log("Nextcloud Editor: PROPFIND -> {$propfindUrl}"); // ПРЯМОЙ S3 URL (bucket публичный, поэтому pre-signed URL не нужен!)
// Bucket поддерживает Range requests и CORS из коробки
$fileUrl = $s3Url;
// XML запрос для получения fileid // ОТЛАДКА: Логируем все параметры
$xmlRequest = '<?xml version="1.0"?> error_log("=== OPEN FILE DEBUG ===");
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns"> error_log("S3 Path: " . $s3Path);
<d:prop> error_log("File URL: " . $fileUrl);
<oc:fileid/> error_log("File extension: " . $ext);
</d:prop> error_log("Document Key (unique): " . $documentKey);
</d:propfind>'; error_log("Version: " . $version);
$ch = curl_init(); $fileBasename = basename($s3Path);
curl_setopt($ch, CURLOPT_URL, $propfindUrl); $fileType = getFileType($ext);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $officeFormats = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'];
curl_setopt($ch, CURLOPT_USERPWD, $username . ':' . $password);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PROPFIND');
curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlRequest);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Depth: 0',
'Content-Type: application/xml'
]);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
if ($response === false) { if (!in_array($ext, $officeFormats)) {
error_log("Nextcloud Editor: Ошибка cURL: " . $curlError); header('Location: ' . $s3Url);
} else {
error_log("Nextcloud Editor: HTTP код: {$httpCode}");
if ($httpCode === 207 && preg_match('/<oc:fileid>(\d+)<\/oc:fileid>/', $response, $matches)) {
$fileId = (int)$matches[1];
error_log("Nextcloud Editor: Получен fileId: {$fileId}");
} else {
error_log("Nextcloud Editor: Файл не найден по пути: {$ncPath} (HTTP {$httpCode})");
}
}
if (!$fileId) {
$errorMsg = "❌ Ошибка: Не удалось получить fileId для файла {$fileName}";
error_log("Nextcloud Editor ERROR: " . $errorMsg);
die($errorMsg);
}
// Формируем URL для Nextcloud
// РАБОЧИЙ ФОРМАТ - редирект на файл с автооткрытием редактора!
$redirectUrl = $nextcloudUrl . '/apps/files/files/' . $fileId . '?dir=/&editing=true&openfile=true';
// Логирование
error_log("Nextcloud Editor: Redirect to $redirectUrl for file (ID: $fileId)");
// Делаем редирект
header('Location: ' . $redirectUrl);
exit; exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title><?php echo htmlspecialchars($fileBasename); ?></title>
<script src="https://office.clientright.ru:9443/web-apps/apps/api/documents/api.js?v=<?php echo time(); ?>"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body {
width: 100%;
height: 100%;
overflow: hidden;
margin: 0;
padding: 0;
}
#editor {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="editor"></div>
<script>
// Отладка в консоль
console.log('📁 Файл:', <?php echo json_encode($fileBasename); ?>);
console.log('🔗 S3 URL:', <?php echo json_encode($fileUrl); ?>);
console.log('🔑 Document Key (unique):', <?php echo json_encode($documentKey); ?>);
console.log('✅ Standalone OnlyOffice (9443) + Direct S3 URL!');
new DocsAPI.DocEditor("editor", {
"documentType": "<?php echo $fileType; ?>",
"document": {
"fileType": "<?php echo $ext; ?>",
"key": "<?php echo $documentKey; ?>",
"title": <?php echo json_encode($fileBasename); ?>,
"url": <?php echo json_encode($fileUrl); ?>,
"permissions": {
"comment": true,
"download": true,
"edit": true,
"print": true,
"review": true
}
},
"editorConfig": {
"mode": "edit",
"lang": "ru",
"callbackUrl": "https://crm.clientright.ru/crm_extensions/file_storage/api/onlyoffice_callback.php",
"user": {
"id": "user_<?php echo $recordId ?? 'guest'; ?>",
"name": "CRM User"
},
"customization": {
"autosave": true,
"chat": false,
"comments": true,
"compactHeader": false,
"compactToolbar": false,
"help": true,
"hideRightMenu": false,
"logo": {
"image": "https://crm.clientright.ru/layouts/v7/skins/images/logo.png",
"imageEmbedded": "https://crm.clientright.ru/layouts/v7/skins/images/logo.png"
},
"zoom": 100
}
},
"height": "100%",
"width": "100%",
"type": "desktop",
"events": {
"onReady": function() {
console.log('✅ Editor ready!');
},
"onDocumentReady": function() {
console.log('✅ Document loaded!');
},
"onError": function(event) {
console.error('❌ OnlyOffice Error FULL:', JSON.stringify(event, null, 2));
console.error('Event data:', event.data);
console.error('Error code:', event.data.errorCode);
console.error('Error description:', event.data.errorDescription);
// Тестируем доступность URL из браузера
console.log('🧪 Testing S3 URL from browser...');
fetch(<?php echo json_encode($fileUrl); ?>, { method: 'HEAD' })
.then(response => {
console.log('✅ Browser can access S3:', response.status);
})
.catch(error => {
console.error('❌ Browser CANNOT access S3:', error);
});
alert('Ошибка загрузки документа:\n\n' +
'Code: ' + event.data.errorCode + '\n' +
'Description: ' + event.data.errorDescription + '\n\n' +
'Используется Pre-signed URL из S3\n\n' +
'Смотри консоль браузера (F12) для деталей!');
},
"onWarning": function(event) {
console.warn('⚠️ OnlyOffice Warning:', event);
}
}
});
</script>
</body>
</html>
<?php
function getFileType($ext) {
if (in_array($ext, ['doc', 'docx'])) return 'word';
if (in_array($ext, ['xls', 'xlsx'])) return 'cell';
if (in_array($ext, ['ppt', 'pptx'])) return 'slide';
return 'word';
}
function generatePresignedUrl($s3Key, $expirationSeconds) {
try {
require_once '/var/www/fastuser/data/www/crm.clientright.ru/vendor/autoload.php';
$s3Client = new Aws\S3\S3Client([
'version' => 'latest',
'region' => 'ru-1',
'endpoint' => 'https://s3.twcstorage.ru',
'use_path_style_endpoint' => true,
'credentials' => [
'key' => EnvLoader::getRequired('S3_ACCESS_KEY'),
'secret' => EnvLoader::getRequired('S3_SECRET_KEY')
],
'suppress_php_deprecation_warning' => true
]);
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
// КЛЮЧ: Минимальные параметры = правильная подпись!
$cmd = $s3Client->getCommand('GetObject', [
'Bucket' => $bucket,
'Key' => $s3Key
]);
$request = $s3Client->createPresignedRequest($cmd, "+{$expirationSeconds} seconds");
return (string)$request->getUri();
} catch (Exception $e) {
error_log("Pre-signed URL error: " . $e->getMessage());
return null;
}
}
function getContentType($filename) {
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$types = [
'doc' => 'application/msword',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'xls' => 'application/vnd.ms-excel',
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'ppt' => 'application/vnd.ms-powerpoint',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
];
return $types[$ext] ?? 'application/octet-stream';
}
?> ?>

View File

@@ -0,0 +1,58 @@
<?php
/**
* Открытие файлов через Collabora (вместо OnlyOffice)
* Collabora работает через Nextcloud WebDAV
*/
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/shared/EnvLoader.php';
EnvLoader::load('/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/.env');
error_reporting(E_ALL);
ini_set('display_errors', 1);
$fileName = isset($_GET['fileName']) ? $_GET['fileName'] : '';
$recordId = isset($_GET['recordId']) ? $_GET['recordId'] : '';
if (empty($fileName)) {
die("❌ fileName не указан");
}
// Извлекаем S3 путь
$s3Path = '';
if (strpos($fileName, 'http') === 0) {
$fileName = urldecode($fileName);
$bucketId = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$pos = strpos($fileName, $bucketId . '/');
if ($pos !== false) {
$s3Path = substr($fileName, $pos + strlen($bucketId) + 1);
}
}
if (empty($s3Path)) {
die("Не удалось извлечь путь из URL");
}
// Nextcloud path (убираем 'crm2/')
$ncPath = str_replace('crm2/', '', $s3Path);
$fileBasename = basename($ncPath);
// Nextcloud URL
$nextcloudUrl = 'https://office.clientright.ru:8443';
$webdavPath = '/crm/crm2/' . $ncPath;
// Открываем напрямую в Nextcloud Files - Collabora откроется автоматически!
$dirPath = dirname($webdavPath);
$redirectUrl = $nextcloudUrl . '/apps/files/?dir=' . urlencode($dirPath) . '&openfile=' . urlencode($fileBasename);
error_log("=== COLLABORA OPEN ===");
error_log("S3 Path: " . $s3Path);
error_log("NC WebDAV Path: " . $webdavPath);
error_log("Redirect URL: " . $redirectUrl);
// Редиректим в Nextcloud
header('Location: ' . $redirectUrl);
exit;
?>

View File

@@ -0,0 +1,169 @@
<?php
/**
* OnlyOffice Standalone + S3 Direct URL
* С сохранением обратно в S3
*/
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/shared/EnvLoader.php';
require_once '/var/www/fastuser/data/www/crm.clientright.ru/vendor/autoload.php';
EnvLoader::load('/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/.env');
error_reporting(E_ALL);
ini_set('display_errors', 1);
$fileName = isset($_GET['fileName']) ? $_GET['fileName'] : '';
$recordId = isset($_GET['recordId']) ? $_GET['recordId'] : 'unknown';
if (empty($fileName)) {
die("❌ fileName не указан");
}
// Извлекаем S3 путь
$s3Path = '';
if (strpos($fileName, 'http') === 0) {
$fileName = urldecode($fileName);
$bucketId = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$pos = strpos($fileName, $bucketId . '/');
if ($pos !== false) {
$s3Path = substr($fileName, $pos + strlen($bucketId) + 1);
}
}
if (empty($s3Path)) {
die("Не удалось извлечь путь из URL");
}
// Извлекаем расширение файла
$ext = strtolower(pathinfo($s3Path, PATHINFO_EXTENSION));
// ПРЯМОЙ S3 URL (bucket публичный)
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$s3Url = 'https://s3.twcstorage.ru/' . $bucket . '/' . $s3Path;
// Генерируем уникальный ключ документа
$version = time();
$documentKey = md5($s3Path . '_' . $version);
// ВАЖНО: Сохраняем маппинг documentKey → S3 путь в Redis
try {
$redis = new Predis\Client([
'scheme' => 'tcp',
'host' => EnvLoader::getRequired('REDIS_HOST'),
'port' => (int)EnvLoader::getRequired('REDIS_PORT'),
'password' => EnvLoader::getRequired('REDIS_PASSWORD')
]);
// Сохраняем на 24 часа (TTL = срок действия документа)
$redis->setex("crm:onlyoffice:key:$documentKey", 86400, json_encode([
's3_path' => $s3Path,
'record_id' => $recordId,
'created_at' => time()
]));
error_log("Redis: Saved mapping for key $documentKey$s3Path");
} catch (Exception $e) {
error_log("Redis error: " . $e->getMessage());
}
$fileBasename = basename($s3Path);
$fileType = getFileType($ext);
$officeFormats = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'];
if (!in_array($ext, $officeFormats)) {
header('Location: ' . $s3Url);
exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title><?php echo htmlspecialchars($fileBasename); ?></title>
<script src="https://office.clientright.ru:9443/web-apps/apps/api/documents/api.js?v=<?php echo time(); ?>"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body {
width: 100%;
height: 100%;
overflow: hidden;
}
#editor {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="editor"></div>
<script>
console.log('📁 Файл:', <?php echo json_encode($fileBasename); ?>);
console.log('🔗 S3 URL:', <?php echo json_encode($s3Url); ?>);
console.log('🔑 Document Key:', <?php echo json_encode($documentKey); ?>);
console.log('✅ Standalone OnlyOffice + Redis mapping!');
new DocsAPI.DocEditor("editor", {
"documentType": "<?php echo $fileType; ?>",
"document": {
"fileType": "<?php echo $ext; ?>",
"key": "<?php echo $documentKey; ?>",
"title": <?php echo json_encode($fileBasename); ?>,
"url": <?php echo json_encode($s3Url); ?>,
"permissions": {
"comment": true,
"download": true,
"edit": true,
"print": true,
"review": true
}
},
"editorConfig": {
"mode": "edit",
"lang": "ru",
"callbackUrl": "https://crm.clientright.ru/crm_extensions/file_storage/api/onlyoffice_callback_v2.php",
"user": {
"id": "user_<?php echo $recordId; ?>",
"name": "CRM User"
},
"customization": {
"autosave": true,
"compactHeader": false,
"compactToolbar": false
}
},
"height": "100%",
"width": "100%",
"type": "desktop",
"events": {
"onReady": function() {
console.log('✅ Editor ready!');
},
"onDocumentReady": function() {
console.log('✅ Document loaded!');
},
"onError": function(event) {
console.error('❌ Error:', event.data);
alert('Ошибка: ' + event.data.errorDescription);
}
}
});
</script>
</body>
</html>
<?php
function getFileType($ext) {
if (in_array($ext, ['doc', 'docx'])) return 'word';
if (in_array($ext, ['xls', 'xlsx'])) return 'cell';
if (in_array($ext, ['ppt', 'pptx'])) return 'slide';
return 'word';
}
?>

View File

@@ -0,0 +1,121 @@
<?php
/**
* S3 Proxy для OnlyOffice
* Проксирует запросы к S3, чтобы OnlyOffice мог загружать файлы
*/
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/shared/EnvLoader.php';
EnvLoader::load('/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/.env');
error_reporting(E_ALL);
ini_set('display_errors', 0);
$path = isset($_GET['path']) ? $_GET['path'] : '';
if (empty($path)) {
http_response_code(400);
die('Path parameter is required');
}
// CORS preflight
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, HEAD, OPTIONS');
header('Access-Control-Allow-Headers: *');
header('Access-Control-Max-Age: 3600');
http_response_code(200);
exit;
}
// Для HEAD запросов - только headers, без body
$isHeadRequest = ($_SERVER['REQUEST_METHOD'] === 'HEAD');
// Формируем URL к S3
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$s3Url = 'https://s3.twcstorage.ru/' . $bucket . '/' . $path;
// Проверяем Range header (для OnlyOffice partial requests)
$rangeHeader = isset($_SERVER['HTTP_RANGE']) ? $_SERVER['HTTP_RANGE'] : '';
error_log("S3 Proxy: Request from: " . ($_SERVER['REMOTE_ADDR'] ?? 'unknown'));
error_log("S3 Proxy: Downloading: " . $s3Url);
if ($rangeHeader) {
error_log("S3 Proxy: Range request: " . $rangeHeader);
}
// СНАЧАЛА скачиваем в буфер
$ch = curl_init($s3Url);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // ← ВАЖНО: В БУФЕР!
curl_setopt($ch, CURLOPT_HEADER, true); // ← Получаем headers
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 120);
// Для HEAD запросов - только headers
if ($isHeadRequest) {
curl_setopt($ch, CURLOPT_NOBODY, true);
}
// Если есть Range header - передаём его в S3!
if ($rangeHeader) {
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Range: ' . $rangeHeader]);
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$error = curl_error($ch);
curl_close($ch);
// Проверяем ПРЕЖДЕ чем отправлять что-либо
// 200 = полный файл, 206 = частичный (Range request)
if ($response === false || ($httpCode !== 200 && $httpCode !== 206)) {
error_log("S3 Proxy ERROR: HTTP $httpCode, cURL error: $error");
header('Access-Control-Allow-Origin: *');
http_response_code($httpCode ?: 500);
die('Failed to fetch file from S3');
}
// Разделяем headers и body
$headersText = substr($response, 0, $headerSize);
$body = $isHeadRequest ? '' : substr($response, $headerSize); // Для HEAD body пустой
// Парсим headers
$headers = explode("\r\n", $headersText);
foreach ($headers as $header) {
if (strpos($header, ':') !== false) {
list($name, $value) = explode(':', $header, 2);
$name = strtolower(trim($name));
$value = trim($value);
// Пробрасываем нужные headers
if (in_array($name, ['content-type', 'content-length', 'content-range', 'accept-ranges', 'etag', 'last-modified'])) {
header($name . ': ' . $value);
}
}
}
// CORS headers
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, HEAD, OPTIONS');
header('Access-Control-Allow-Headers: *');
header('Access-Control-Expose-Headers: Content-Range, Accept-Ranges');
// Устанавливаем правильный HTTP код (206 для partial content)
if ($httpCode === 206) {
http_response_code(206);
} else {
http_response_code(200);
}
// Отправляем body только для GET запросов (не для HEAD)
if (!$isHeadRequest) {
echo $body;
error_log("S3 Proxy: Success! Sent " . strlen($body) . " bytes");
} else {
error_log("S3 Proxy: HEAD request completed");
}
?>

View File

@@ -0,0 +1,31 @@
version: '3.8'
services:
onlyoffice-standalone:
image: onlyoffice/documentserver:latest
container_name: onlyoffice-standalone
restart: unless-stopped
ports:
- "127.0.0.1:8083:80" # Новый порт (8081 и 8082 заняты)
environment:
- JWT_ENABLED=false
- JWT_SECRET=
- WOPI_ENABLED=false
volumes:
- onlyoffice-standalone-data:/var/www/onlyoffice/Data
- onlyoffice-standalone-logs:/var/log/onlyoffice
- onlyoffice-standalone-fonts:/usr/share/fonts/truetype/custom
- onlyoffice-standalone-forgotten:/var/lib/onlyoffice/documentserver/App_Data/cache/files/forgotten
networks:
- crm-network
volumes:
onlyoffice-standalone-data:
onlyoffice-standalone-logs:
onlyoffice-standalone-fonts:
onlyoffice-standalone-forgotten:
networks:
crm-network:
name: crm-network

View File

@@ -0,0 +1,48 @@
#!/bin/bash
echo "🔑 S3 Credentials для n8n"
echo "════════════════════════════════════════════════════════════════════════════════"
echo ""
# Получаем credentials из Nextcloud
docker exec nextcloud-fresh php occ files_external:list --output=json 2>/dev/null | jq -r '
.[0].configuration |
"📦 Bucket: \(.bucket)
🔑 Access Key: \(.key)
🔐 Secret Key: \(.secret)
🌐 Endpoint: \(.hostname)
🗺️ Region: \(.region)
════════════════════════════════════════════════════════════════════════════════
📋 Для n8n AWS S3 Credentials:
────────────────────────────────────────────────────────────────────────────────
Access Key ID: \(.key)
Secret Access Key: \(.secret)
Region: \(.region)
Custom Endpoints: ✅ ВКЛЮЧИТЬ
S3 Endpoint: https://\(.hostname)
Force Path Style: ✅ ВКЛЮЧИТЬ
────────────────────────────────────────────────────────────────────────────────
📋 Для n8n Environment Variables:
────────────────────────────────────────────────────────────────────────────────
S3_BUCKET=\(.bucket)
S3_ENDPOINT=https://\(.hostname)
S3_REGION=\(.region)
────────────────────────────────────────────────────────────────────────────────
"
'
echo ""
echo "📋 Redis Credentials для n8n:"
echo "────────────────────────────────────────────────────────────────────────────────"
echo "Host: 147.45.146.17"
echo "Port: 6379"
echo "Password: CRM_Redis_Pass_2025_Secure!"
echo "Database: 0"
echo "────────────────────────────────────────────────────────────────────────────────"
echo ""
echo "✅ Готово! Скопируй эти данные в n8n"

View File

@@ -0,0 +1,166 @@
<?php
/**
* Простая миграция одного проекта в новую структуру
* Использование: php migrate_single_project.php PROJECT_ID
*/
require_once(__DIR__ . '/../../config.inc.php');
require_once(__DIR__ . '/../../include/database/PearDatabase.php');
$adb = PearDatabase::getInstance();
// Получаем ID проекта
$projectId = isset($argv[1]) ? (int)$argv[1] : null;
if (!$projectId) {
echo "❌ Укажите ID проекта!\n";
echo "Использование: php migrate_single_project.php PROJECT_ID\n";
exit(1);
}
echo "🔄 МИГРАЦИЯ ПРОЕКТА $projectId\n";
echo "==========================================\n\n";
// Получаем информацию о проекте
$result = $adb->pquery("SELECT p.projectname FROM vtiger_project p WHERE p.projectid = ?", [$projectId]);
if ($adb->num_rows($result) == 0) {
echo "❌ Проект не найден!\n";
exit(1);
}
$projectName = $adb->query_result($result, 0, 'projectname');
echo "📁 Проект: $projectName\n\n";
// Функция очистки имени файла
function sanitizeName($name) {
// Транслитерация
$translitMap = [
'А' => 'A', 'Б' => 'B', 'В' => 'V', 'Г' => 'G', 'Д' => 'D',
'Е' => 'E', 'Ё' => 'E', 'Ж' => 'Zh', 'З' => 'Z', 'И' => 'I',
'Й' => 'Y', 'К' => 'K', 'Л' => 'L', 'М' => 'M', 'Н' => 'N',
'О' => 'O', 'П' => 'P', 'Р' => 'R', 'С' => 'S', 'Т' => 'T',
'У' => 'U', 'Ф' => 'F', 'Х' => 'H', 'Ц' => 'Ts', 'Ч' => 'Ch',
'Ш' => 'Sh', 'Щ' => 'Sch', 'Ъ' => '', 'Ы' => 'Y', 'Ь' => '',
'Э' => 'E', 'Ю' => 'Yu', 'Я' => 'Ya',
'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd',
'е' => 'e', 'ё' => 'e', 'ж' => 'zh', 'з' => 'z', 'и' => 'i',
'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n',
'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't',
'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'ts', 'ч' => 'ch',
'ш' => 'sh', 'щ' => 'sch', 'ъ' => '', 'ы' => 'y', 'ь' => '',
'э' => 'e', 'ю' => 'yu', 'я' => 'ya'
];
$name = strtr($name, $translitMap);
$name = preg_replace('/[^a-zA-Z0-9_\-]/', '_', $name);
$name = preg_replace('/_+/', '_', $name);
$name = trim($name, '_');
if (strlen($name) > 100) {
$name = substr($name, 0, 100);
}
return $name;
}
$sanitizedName = sanitizeName($projectName);
$newFolder = "Documents/Project/{$sanitizedName}_{$projectId}";
echo "📁 Новая папка: $newFolder\n\n";
// Получаем все документы проекта
$result = $adb->pquery(
"SELECT n.notesid, n.title, n.filename, n.s3_key, n.filelocationtype
FROM vtiger_notes n
JOIN vtiger_senotesrel snr ON snr.notesid = n.notesid
JOIN vtiger_crmentity e ON e.crmid = n.notesid
WHERE snr.crmid = ? AND e.deleted = 0 AND n.filelocationtype = 'E'
ORDER BY n.notesid",
[$projectId]
);
$total = $adb->num_rows($result);
echo "📊 Найдено документов: $total\n\n";
if ($total == 0) {
echo "✅ Нет документов для миграции\n";
exit(0);
}
$migrated = 0;
$errors = 0;
while ($doc = $adb->fetch_array($result)) {
$notesid = $doc['notesid'];
$title = $doc['title'];
$oldS3Key = $doc['s3_key'];
echo "[$migrated/$total] Документ: $title (ID: $notesid)\n";
echo " Старый s3_key: $oldS3Key\n";
// Извлекаем имя файла и расширение
$oldFilename = basename($oldS3Key);
$pathInfo = pathinfo($oldFilename);
$extension = isset($pathInfo['extension']) ? '.' . $pathInfo['extension'] : '';
// Новое имя файла: file_docID_название.ext
$newFilename = "file_{$notesid}_{$pathInfo['filename']}{$extension}";
// Новый путь в S3
$newS3Key = "{$newFolder}/{$newFilename}";
$newNcPath = "/crm/crm2/CRM_Active_Files/{$newFolder}/{$newFilename}";
// Новый URL
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$newUrl = "https://s3.twcstorage.ru/{$bucket}/crm2/CRM_Active_Files/{$newS3Key}";
echo " Новый s3_key: $newS3Key\n";
echo " Новый nc_path: $newNcPath\n";
// Копируем файл в S3 (используем aws s3 cp)
$oldKey = "crm2/CRM_Active_Files/" . $oldS3Key;
$newKey = "crm2/CRM_Active_Files/" . $newS3Key;
$copyCmd = "aws s3 cp " .
"s3://{$bucket}/{$oldKey} " .
"s3://{$bucket}/{$newKey} " .
"--endpoint-url https://s3.twcstorage.ru " .
"--region ru-1 2>&1";
echo " Копирование в S3...\n";
exec($copyCmd, $output, $returnCode);
if ($returnCode !== 0) {
echo " ❌ ОШИБКА копирования: " . implode("\n", $output) . "\n";
$errors++;
continue;
}
echo " ✅ Скопировано в S3\n";
// Обновляем БД
$updateResult = $adb->pquery(
"UPDATE vtiger_notes
SET s3_key = ?, nc_path = ?, filename = ?
WHERE notesid = ?",
[$newS3Key, $newNcPath, $newUrl, $notesid]
);
if ($updateResult) {
echo " ✅ БД обновлена\n";
$migrated++;
} else {
echo " ❌ ОШИБКА обновления БД\n";
$errors++;
}
echo "\n";
}
echo "==========================================\n";
echo "✅ МИГРАЦИЯ ЗАВЕРШЕНА!\n";
echo "Обработано: $total\n";
echo "Мигрировано: $migrated\n";
echo "Ошибок: $errors\n";

View File

@@ -0,0 +1,170 @@
{
"name": "Nextcloud Activity Monitor",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "seconds",
"secondsInterval": 30
}
]
}
},
"id": "schedule",
"name": "Каждые 30 секунд",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [250, 300]
},
{
"parameters": {
"url": "https://office.clientright.ru:8443/ocs/v2.php/apps/activity/api/v2/activity",
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "format",
"value": "json"
},
{
"name": "limit",
"value": "100"
}
]
},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "OCS-APIRequest",
"value": "true"
}
]
},
"options": {}
},
"id": "http-request",
"name": "Get Nextcloud Activities",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [450, 300],
"credentials": {
"httpBasicAuth": {
"id": "3",
"name": "Nextcloud Admin"
}
}
},
{
"parameters": {
"jsCode": "// Получаем последний обработанный activity_id из Static Data\nconst staticData = getWorkflowStaticData('node');\nlet lastProcessedId = staticData.lastActivityId || 0;\n\nconst activities = $input.item.json.ocs.data;\nconst fileEvents = [];\n\n// Типы событий которые нас интересуют\nconst relevantTypes = ['file_created', 'file_changed', 'file_deleted', 'file_restored'];\n\n// Фильтруем и обрабатываем события\nfor (const activity of activities) {\n // Пропускаем уже обработанные\n if (activity.activity_id <= lastProcessedId) {\n continue;\n }\n \n // Только файловые события\n if (!relevantTypes.includes(activity.type)) {\n continue;\n }\n \n // РАЗБИВАЕМ агрегированные события!\n // Если есть objects - создаём событие для каждого файла\n if (activity.objects && typeof activity.objects === 'object') {\n const fileIds = Object.keys(activity.objects);\n \n for (const fileId of fileIds) {\n const filePath = activity.objects[fileId];\n \n fileEvents.push({\n json: {\n type: activity.type,\n source: 'nextcloud_activity',\n timestamp: activity.datetime,\n file_id: parseInt(fileId),\n path: filePath,\n filename: filePath ? filePath.split('/').pop() : null,\n user: activity.user,\n activity_id: activity.activity_id,\n action: activity.type.replace('file_', '')\n }\n });\n }\n } else {\n // Одиночное событие\n fileEvents.push({\n json: {\n type: activity.type,\n source: 'nextcloud_activity',\n timestamp: activity.datetime,\n file_id: activity.object_id,\n path: activity.object_name,\n filename: activity.object_name ? activity.object_name.split('/').pop() : null,\n user: activity.user,\n activity_id: activity.activity_id,\n action: activity.type.replace('file_', '')\n }\n });\n }\n \n // Обновляем последний ID\n if (activity.activity_id > lastProcessedId) {\n lastProcessedId = activity.activity_id;\n }\n}\n\n// Сохраняем последний обработанный ID\nstaticData.lastActivityId = lastProcessedId;\n\n// Если новых событий нет - возвращаем пустой массив\nif (fileEvents.length === 0) {\n return [];\n}\n\nreturn fileEvents;"
},
"id": "process-activities",
"name": "Process & Filter Events",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [650, 300]
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "={{$json.filename}}",
"operation": "isNotEmpty"
}
]
}
},
"id": "filter",
"name": "Есть новые события?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [850, 300]
},
{
"parameters": {
"operation": "publish",
"channel": "crm:file:events",
"value": "={{JSON.stringify($json)}}",
"keyType": "automatic"
},
"id": "redis-publish",
"name": "Publish to Redis",
"type": "n8n-nodes-base.redis",
"typeVersion": 1,
"position": [1050, 200],
"credentials": {
"redis": {
"id": "2",
"name": "CRM Redis"
}
}
},
{
"parameters": {
"content": "=📢 Nextcloud Event:\n**Type:** {{$json.type}}\n**File:** {{$json.filename}}\n**Path:** {{$json.path}}\n**User:** {{$json.user}}\n**Time:** {{$json.timestamp}}",
"options": {}
},
"id": "logger",
"name": "Log Event (optional)",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [1050, 400]
}
],
"connections": {
"schedule": {
"main": [
[
{
"node": "http-request",
"type": "main",
"index": 0
}
]
]
},
"http-request": {
"main": [
[
{
"node": "process-activities",
"type": "main",
"index": 0
}
]
]
},
"process-activities": {
"main": [
[
{
"node": "filter",
"type": "main",
"index": 0
}
]
]
},
"filter": {
"main": [
[
{
"node": "redis-publish",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}

View File

@@ -0,0 +1,174 @@
{
"name": "S3 Event Processor",
"nodes": [
{
"parameters": {
"operation": "subscribe",
"channel": "crm:file:events"
},
"id": "redis-subscribe",
"name": "Redis Subscribe",
"type": "n8n-nodes-base.redis",
"typeVersion": 1,
"position": [250, 300],
"credentials": {
"redis": {
"id": "CRM_REDIS_ID",
"name": "CRM Redis"
}
}
},
{
"parameters": {
"jsCode": "// Парсим JSON из Redis message\nconst items = [];\n\nfor (const item of $input.all()) {\n const message = item.json.message;\n \n // Если message это строка - парсим\n let parsedMessage = message;\n if (typeof message === 'string') {\n parsedMessage = JSON.parse(message);\n }\n \n items.push({\n json: parsedMessage\n });\n}\n\nreturn items;"
},
"id": "parse-json",
"name": "Parse Message",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [450, 300]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true
},
"conditions": [
{
"id": "c1",
"leftValue": "={{ $json.type }}",
"rightValue": "file_created",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
}
},
"id": "filter-created",
"name": "Только новые файлы",
"type": "n8n-nodes-base.switch",
"typeVersion": 3,
"position": [650, 300]
},
{
"parameters": {
"conditions": {
"options": {},
"conditions": [
{
"id": "c1",
"leftValue": "={{ $json.filename }}",
"rightValue": ".xlsx",
"operator": {
"type": "string",
"operation": "endsWith"
}
}
],
"combinator": "or"
}
},
"id": "filter-xlsx",
"name": "Только XLSX",
"type": "n8n-nodes-base.switch",
"typeVersion": 3,
"position": [850, 200]
},
{
"parameters": {
"conditions": {
"options": {},
"conditions": [
{
"id": "c1",
"leftValue": "={{ $json.filename }}",
"rightValue": ".pdf",
"operator": {
"type": "string",
"operation": "endsWith"
}
}
],
"combinator": "or"
}
},
"id": "filter-pdf",
"name": "Только PDF",
"type": "n8n-nodes-base.switch",
"typeVersion": 3,
"position": [850, 400]
},
{
"parameters": {
"content": "=📊 **XLSX файл обнаружен!**\n\n**Имя:** {{ $json.filename }}\n**Путь:** {{ $json.path }}\n**Размер:** {{ $json.size }} bytes\n**Время:** {{ $json.timestamp }}\n\n---\n\nЗдесь можно:\n- Скачать файл из S3\n- Обработать данные\n- Загрузить в CRM\n- Отправить уведомление",
"height": 312,
"width": 389
},
"id": "process-xlsx",
"name": "Обработка XLSX",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [1050, 80]
},
{
"parameters": {
"content": "=📄 **PDF файл обнаружен!**\n\n**Имя:** {{ $json.filename }}\n**Путь:** {{ $json.path }}\n**Размер:** {{ $json.size }} bytes\n**Время:** {{ $json.timestamp }}\n\n---\n\nЗдесь можно:\n- Скачать PDF из S3\n- OCR распознавание\n- Извлечь данные\n- Создать документ в CRM",
"height": 312,
"width": 389
},
"id": "process-pdf",
"name": "Обработка PDF",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [1050, 320]
}
],
"connections": {
"redis-subscribe": {
"main": [
[
{
"node": "parse-json",
"type": "main",
"index": 0
}
]
]
},
"parse-json": {
"main": [
[
{
"node": "filter-created",
"type": "main",
"index": 0
}
]
]
},
"filter-created": {
"main": [
[
{
"node": "filter-xlsx",
"type": "main",
"index": 0
},
{
"node": "filter-pdf",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}

View File

@@ -0,0 +1,179 @@
{
"name": "S3 File Monitor",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "seconds",
"secondsInterval": 30
}
]
}
},
"id": "schedule",
"name": "Каждые 30 секунд",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [250, 300]
},
{
"parameters": {
"operation": "getAll",
"bucketName": "={{$env.S3_BUCKET}}",
"returnAll": true,
"options": {
"prefix": ""
}
},
"id": "s3-list",
"name": "List S3 Files",
"type": "n8n-nodes-base.awsS3",
"typeVersion": 1,
"position": [450, 300],
"credentials": {
"aws": {
"id": "1",
"name": "TWC S3"
}
}
},
{
"parameters": {
"functionCode": "// Храним состояние файлов в Static Data\nconst currentState = $node[\"s3-list\"].json;\nconst previousState = $getWorkflowStaticData('node') || {};\nconst events = [];\n\n// Проверяем новые и изменённые файлы\nfor (const file of currentState) {\n const key = file.Key;\n const etag = file.ETag;\n \n if (!previousState[key]) {\n // Новый файл\n events.push({\n type: 'file_created',\n source: 's3_monitor',\n timestamp: new Date().toISOString(),\n path: key,\n filename: key.split('/').pop(),\n size: file.Size,\n etag: etag,\n last_modified: file.LastModified\n });\n } else if (previousState[key].ETag !== etag) {\n // Файл изменён\n events.push({\n type: 'file_modified',\n source: 's3_monitor',\n timestamp: new Date().toISOString(),\n path: key,\n filename: key.split('/').pop(),\n size: file.Size,\n etag: etag,\n last_modified: file.LastModified\n });\n }\n \n previousState[key] = { ETag: etag, Size: file.Size };\n}\n\n// Проверяем удалённые файлы\nconst currentKeys = currentState.map(f => f.Key);\nfor (const key in previousState) {\n if (!currentKeys.includes(key)) {\n events.push({\n type: 'file_deleted',\n source: 's3_monitor',\n timestamp: new Date().toISOString(),\n path: key,\n filename: key.split('/').pop()\n });\n delete previousState[key];\n }\n}\n\n// Сохраняем новое состояние\n$setWorkflowStaticData(previousState);\n\nreturn events.map(event => ({ json: event }));"
},
"id": "detect-changes",
"name": "Detect Changes",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [650, 300]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "c1",
"leftValue": "={{ $json.type }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "notEmpty"
}
}
],
"combinator": "and"
}
},
"id": "filter",
"name": "Есть изменения?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [850, 300]
},
{
"parameters": {
"operation": "publish",
"channel": "crm:file:events",
"value": "={{JSON.stringify($json)}}",
"keyType": "automatic",
"expire": false,
"expireAfter": 86400
},
"id": "redis-publish",
"name": "Publish to Redis",
"type": "n8n-nodes-base.redis",
"typeVersion": 1,
"position": [1050, 200],
"credentials": {
"redis": {
"id": "2",
"name": "CRM Redis"
}
}
},
{
"parameters": {
"url": "={{$env.WEBHOOK_URL}}",
"options": {
"bodyContentType": "json"
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "event",
"value": "={{$json}}"
}
]
}
},
"id": "webhook",
"name": "Send Webhook (опционально)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [1050, 400]
}
],
"connections": {
"schedule": {
"main": [
[
{
"node": "s3-list",
"type": "main",
"index": 0
}
]
]
},
"s3-list": {
"main": [
[
{
"node": "detect-changes",
"type": "main",
"index": 0
}
]
]
},
"detect-changes": {
"main": [
[
{
"node": "filter",
"type": "main",
"index": 0
}
]
]
},
"filter": {
"main": [
[
{
"node": "redis-publish",
"type": "main",
"index": 0
},
{
"node": "webhook",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}

View File

@@ -0,0 +1,249 @@
#!/usr/bin/env node
/**
* Nextcloud Activity Monitor
* Мониторит события файлов через Activity API и публикует в Redis
*/
const https = require('https');
const Redis = require('ioredis');
const CONFIG = {
nextcloud: {
host: 'office.clientright.ru',
port: 8443,
username: 'admin',
password: 'tGHKS-3cC9m-7Hggb-65Awk-zxWQE',
auth: Buffer.from('admin:tGHKS-3cC9m-7Hggb-65Awk-zxWQE').toString('base64')
},
redis: {
host: '147.45.146.17',
port: 6379,
password: 'CRM_Redis_Pass_2025_Secure!'
},
pollInterval: 30000, // 30 секунд
stateKey: 'crm:nextcloud:activity:state'
};
const redis = new Redis({
host: CONFIG.redis.host,
port: CONFIG.redis.port,
password: CONFIG.redis.password
});
// Хранилище последнего обработанного activity_id
let lastActivityId = 0;
// Загрузка состояния из Redis
async function loadState() {
try {
const data = await redis.get(CONFIG.stateKey);
if (data) {
const state = JSON.parse(data);
lastActivityId = state.lastActivityId || 0;
console.log(`📥 Последний обработанный activity_id: ${lastActivityId}`);
} else {
console.log('📥 Состояние пустое (первый запуск)');
}
} catch (err) {
console.error('⚠️ Ошибка загрузки состояния:', err.message);
}
}
// Сохранение состояния в Redis
async function saveState() {
try {
await redis.set(CONFIG.stateKey, JSON.stringify({ lastActivityId }));
} catch (err) {
console.error('⚠️ Ошибка сохранения состояния:', err.message);
}
}
// Получение активностей из Nextcloud API
function getActivities(limit = 100) {
return new Promise((resolve, reject) => {
const options = {
hostname: CONFIG.nextcloud.host,
port: CONFIG.nextcloud.port,
path: `/ocs/v2.php/apps/activity/api/v2/activity?format=json&limit=${limit}`,
method: 'GET',
headers: {
'Authorization': `Basic ${CONFIG.nextcloud.auth}`,
'OCS-APIRequest': 'true'
},
rejectUnauthorized: false
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const json = JSON.parse(data);
resolve(json.ocs.data || []);
} catch (err) {
reject(new Error('Ошибка парсинга JSON: ' + err.message));
}
});
});
req.on('error', (err) => {
reject(err);
});
req.setTimeout(10000, () => {
req.destroy();
reject(new Error('Timeout'));
});
req.end();
});
}
// Публикация события в Redis
async function publishEvent(event) {
console.log(`\n 📢 ${event.type.toUpperCase()}: ${event.filename}`);
console.log(` 🆔 file_id: ${event.file_id}`);
console.log(` 👤 user: ${event.user}`);
try {
await redis.publish('crm:file:events', JSON.stringify(event));
console.log(` ✅ Опубликовано в Redis`);
} catch (err) {
console.error(` ❌ Ошибка публикации:`, err.message);
}
}
// Сканирование новых активностей
async function scanActivities() {
try {
console.log(`\n🔍 Проверка новых событий... (${new Date().toISOString()})`);
const activities = await getActivities(100);
const relevantTypes = ['file_created', 'file_changed', 'file_deleted', 'file_restored'];
let newEvents = 0;
let totalFiles = 0;
// Обрабатываем активности (от новых к старым)
for (const activity of activities) {
// Пропускаем уже обработанные
if (activity.activity_id <= lastActivityId) {
continue;
}
// Только файловые события
if (!relevantTypes.includes(activity.type)) {
continue;
}
newEvents++;
// РАЗБИВАЕМ агрегированные события на отдельные файлы!
if (activity.objects && typeof activity.objects === 'object') {
// Множественное событие - разбиваем
const fileIds = Object.keys(activity.objects);
totalFiles += fileIds.length;
console.log(` 📦 Агрегированное событие: ${fileIds.length} файлов`);
for (const fileId of fileIds) {
const filePath = activity.objects[fileId];
const event = {
type: activity.type,
source: 'nextcloud_activity',
timestamp: activity.datetime,
file_id: parseInt(fileId),
path: filePath,
filename: filePath ? filePath.split('/').pop().replace(/^\//, '') : null,
user: activity.user,
activity_id: activity.activity_id,
action: activity.type.replace('file_', '')
};
await publishEvent(event);
}
} else {
// Одиночное событие
totalFiles++;
const event = {
type: activity.type,
source: 'nextcloud_activity',
timestamp: activity.datetime,
file_id: activity.object_id,
path: activity.object_name,
filename: activity.object_name ? activity.object_name.split('/').pop().replace(/^\//, '') : null,
user: activity.user,
activity_id: activity.activity_id,
action: activity.type.replace('file_', '')
};
await publishEvent(event);
}
// Обновляем последний ID
if (activity.activity_id > lastActivityId) {
lastActivityId = activity.activity_id;
}
}
// Сохраняем состояние
await saveState();
console.log(`\n✅ Сканирование завершено:`);
console.log(` 📊 Новых активностей: ${newEvents}`);
console.log(` 📁 Файлов обработано: ${totalFiles}`);
console.log(` 🆔 Последний activity_id: ${lastActivityId}`);
} catch (err) {
console.error('❌ Ошибка сканирования:', err.message);
}
}
// Запуск
async function start() {
console.log('🚀 Nextcloud Activity Monitor');
console.log('════════════════════════════════════════════════════════════════════════════════');
console.log(`📡 Nextcloud: ${CONFIG.nextcloud.host}:${CONFIG.nextcloud.port}`);
console.log(`📡 Redis: ${CONFIG.redis.host}:${CONFIG.redis.port}`);
console.log(`🔄 Интервал: ${CONFIG.pollInterval / 1000}с`);
console.log('════════════════════════════════════════════════════════════════════════════════\n');
await loadState();
console.log('👂 Начинаем мониторинг...\n');
// Первое сканирование
await scanActivities();
// Периодическое сканирование
setInterval(scanActivities, CONFIG.pollInterval);
}
// Запуск при подключении к Redis
redis.on('connect', () => {
console.log('✅ Подключились к Redis\n');
start();
});
redis.on('error', (err) => {
console.error('❌ Redis ошибка:', err.message);
});
process.on('SIGINT', () => {
console.log('\n\n⛔ Остановка мониторинга...');
redis.disconnect();
process.exit(0);
});
process.on('SIGTERM', () => {
console.log('\n\n⛔ Получен сигнал SIGTERM, останавливаемся...');
redis.disconnect();
process.exit(0);
});

View File

@@ -0,0 +1,123 @@
#!/usr/bin/env node
/**
* Nextcloud Cache Updater
*
* Подписывается на Redis канал crm:file:events
* При новом файле - обновляет кеш Nextcloud для этого файла
* БЕЗ полного сканирования всей папки!
*/
const Redis = require('ioredis');
const { exec } = require('child_process');
const util = require('util');
const execPromise = util.promisify(exec);
const CONFIG = {
redis: {
host: '147.45.146.17',
port: 6379,
password: 'CRM_Redis_Pass_2025_Secure!'
},
channel: 'crm:file:events',
nextcloudContainer: 'nextcloud-fresh'
};
const redis = new Redis(CONFIG.redis);
console.log('🔄 Nextcloud Cache Updater');
console.log('==========================================');
console.log(`📡 Подписка на: ${CONFIG.channel}`);
console.log(`🐳 Nextcloud: ${CONFIG.nextcloudContainer}`);
console.log('');
// Подписка на канал
redis.subscribe(CONFIG.channel, (err, count) => {
if (err) {
console.error('❌ Ошибка подписки:', err);
process.exit(1);
}
console.log(`✅ Подписка активна (${count} каналов)`);
console.log('⏳ Ожидание событий...\n');
});
// Обработка событий
redis.on('message', async (channel, message) => {
try {
const event = JSON.parse(message);
// Логируем событие
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] 📥 Событие:`);
console.log(` Type: ${event.type}`);
console.log(` Source: ${event.source}`);
console.log(` Path: ${event.path || event.filename}`);
// Обрабатываем только создание/изменение файлов
if (!['file_created', 'file_modified', 'file_update'].includes(event.type)) {
console.log(` ⏭️ Пропуск (не файловое событие)\n`);
return;
}
// Извлекаем путь файла
let filePath = event.path || event.filename;
// Для событий из S3 Monitor - путь уже правильный
// Для событий из Nextcloud - может быть без префикса
// Формируем путь для Nextcloud
let ncPath = filePath;
if (!ncPath.startsWith('/')) {
ncPath = '/admin/files/crm/' + ncPath;
}
console.log(` 🔄 Обновление кеша Nextcloud...`);
console.log(` Путь: ${ncPath}`);
// Обновляем кеш только для этого файла
const command = `docker exec -u www-data ${CONFIG.nextcloudContainer} php occ files:scan --path="${ncPath}" 2>&1`;
try {
const { stdout, stderr } = await execPromise(command);
if (stderr && !stderr.includes('Starting scan')) {
console.log(` ⚠️ Предупреждение: ${stderr}`);
}
console.log(` ✅ Кеш обновлён`);
// Дополнительно очищаем statcache для этой папки
const dirname = ncPath.substring(0, ncPath.lastIndexOf('/'));
const clearCommand = `docker exec -u www-data ${CONFIG.nextcloudContainer} php occ files:scan --path="${dirname}" --shallow 2>&1`;
await execPromise(clearCommand);
console.log(` ✅ Родительская папка обновлена\n`);
} catch (execError) {
console.error(` ❌ Ошибка обновления: ${execError.message}\n`);
}
} catch (error) {
console.error(`❌ Ошибка обработки события:`, error.message);
console.error(` Сообщение:`, message.substring(0, 200));
console.log('');
}
});
// Обработка ошибок
redis.on('error', (err) => {
console.error('❌ Redis ошибка:', err);
});
// Graceful shutdown
process.on('SIGINT', () => {
console.log('\n\n🛑 Остановка...');
redis.disconnect();
process.exit(0);
});
process.on('SIGTERM', () => {
console.log('\n\n🛑 Остановка...');
redis.disconnect();
process.exit(0);
});

View File

@@ -0,0 +1,130 @@
#!/usr/bin/env node
/**
* Nextcloud FileID Indexer
*
* Индексирует fileId из Nextcloud БД в Redis для быстрого доступа
* Структура: crm:nc:fileid:{path} => fileId
*/
const mysql = require('mysql2/promise');
const Redis = require('ioredis');
const CONFIG = {
nextcloud_db: {
host: '192.168.128.3',
user: 'nextcloud',
password: 'nextcloud_password',
database: 'nextcloud'
},
redis: {
host: '147.45.146.17',
port: 6379,
password: 'CRM_Redis_Pass_2025_Secure!'
},
// Индексируем только файлы из этих папок
pathPrefixes: [
'files/crm/crm2/',
'files/crm/erv_app/'
],
indexInterval: 60000 // Обновляем индекс каждую минуту
};
const redis = new Redis(CONFIG.redis);
let connection = null;
async function connectDB() {
try {
connection = await mysql.createConnection(CONFIG.nextcloud_db);
console.log('✅ Подключились к БД Nextcloud');
} catch (err) {
console.error('❌ Ошибка подключения к БД:', err.message);
process.exit(1);
}
}
async function indexFiles() {
try {
console.log(`\n🔍 Индексация файлов... (${new Date().toISOString()})`);
let totalIndexed = 0;
for (const prefix of CONFIG.pathPrefixes) {
// Получаем все файлы из этой папки
const [rows] = await connection.execute(
'SELECT fileid, path, name, size, mtime FROM oc_filecache WHERE path LIKE ? AND mimetype != 2',
[prefix + '%']
);
console.log(` 📁 ${prefix}: найдено ${rows.length} файлов`);
// Индексируем в Redis
const pipeline = redis.pipeline();
for (const row of rows) {
const key = `crm:nc:fileid:${row.path}`;
const value = JSON.stringify({
fileId: row.fileid,
name: row.name,
size: row.size,
mtime: row.mtime
});
// Храним 24 часа (обновляется каждую минуту)
pipeline.setex(key, 86400, value);
totalIndexed++;
}
await pipeline.exec();
}
console.log(`✅ Проиндексировано: ${totalIndexed} файлов`);
} catch (err) {
console.error('❌ Ошибка индексации:', err.message);
console.error(err.stack);
}
}
async function start() {
console.log('🚀 Nextcloud FileID Indexer');
console.log('════════════════════════════════════════════════════════════════════════════════');
console.log(`🗄️ Nextcloud DB: ${CONFIG.nextcloud_db.host}/${CONFIG.nextcloud_db.database}`);
console.log(`📡 Redis: ${CONFIG.redis.host}:${CONFIG.redis.port}`);
console.log(`🔄 Интервал: ${CONFIG.indexInterval / 1000}с`);
console.log('════════════════════════════════════════════════════════════════════════════════\n');
await connectDB();
console.log('👂 Начинаем индексацию...\n');
// Первая индексация
await indexFiles();
// Периодическая индексация
setInterval(indexFiles, CONFIG.indexInterval);
}
// Запуск
redis.on('connect', () => {
console.log('✅ Подключились к Redis\n');
start();
});
redis.on('error', (err) => {
console.error('❌ Redis ошибка:', err.message);
});
process.on('SIGINT', async () => {
console.log('\n\n⛔ Остановка индексатора...');
if (connection) await connection.end();
redis.disconnect();
process.exit(0);
});
process.on('SIGTERM', async () => {
console.log('\n\n⛔ Остановка индексатора...');
if (connection) await connection.end();
redis.disconnect();
process.exit(0);
});

1
crm_extensions/file_storage/node_modules/.bin/fxparser generated vendored Symbolic link
View File

@@ -0,0 +1 @@
../fast-xml-parser/src/cli/cli.js

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,100 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.2.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v5.1.0...v5.2.0) (2023-10-16)
### Features
- support ESM artifacts in all packages ([#752](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/752)) ([e930ffb](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/e930ffba5cfef66dd242049e7d514ced232c1e3b))
# [5.1.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v5.0.0...v5.1.0) (2023-09-22)
### Bug Fixes
- Update tsc to 2.x ([#735](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/735)) ([782e0de](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/782e0de9f5fef41f694130580a69d940894b6b8c))
### Features
- Use @smithy/util-utf8 ([#730](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/730)) ([00fb851](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/00fb851ca3559d5a1f370f9256814de1210826b8)), closes [#699](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/699)
# [5.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v4.0.1...v5.0.0) (2023-07-13)
**Note:** Version bump only for package @aws-crypto/crc32
# [4.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v3.0.0...v4.0.0) (2023-02-20)
**Note:** Version bump only for package @aws-crypto/crc32
# [3.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.2...v3.0.0) (2023-01-12)
- feat!: replace Hash implementations with Checksum interface (#492) ([da43dc0](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/da43dc0fdf669d9ebb5bfb1b1f7c79e46c4aaae1)), closes [#492](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/492)
### BREAKING CHANGES
- All classes that implemented `Hash` now implement `Checksum`.
## [2.0.2](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.1...v2.0.2) (2022-09-07)
### Bug Fixes
- **#337:** update @aws-sdk/types ([#373](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/373)) ([b26a811](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/b26a811a392f5209c7ec7e57251500d4d78f97ff)), closes [#337](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/337)
## [2.0.1](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.0...v2.0.1) (2021-12-09)
**Note:** Version bump only for package @aws-crypto/crc32
# [2.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.2...v2.0.0) (2021-10-25)
**Note:** Version bump only for package @aws-crypto/crc32
## [1.2.2](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.1...v1.2.2) (2021-10-12)
### Bug Fixes
- **crc32c:** ie11 does not support Array.from ([#221](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/221)) ([5f49547](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/5f495472ab8988cf203e0f2a70a51f7e1fcd7e60))
## [1.2.1](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.0...v1.2.1) (2021-09-17)
**Note:** Version bump only for package @aws-crypto/crc32
# [1.2.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.1.1...v1.2.0) (2021-09-17)
### Features
- Add AwsCrc32 Hash ([f5d7e81](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/f5d7e815fcbe0f8da1edb855fea3bd33eb1edc15))
# [1.1.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/@aws-crypto/crc32@1.0.0...@aws-crypto/crc32@1.1.0) (2021-08-11)
### Features
- Create CRC-32C implementation ([#201](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/201)) ([e43c7ec](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/e43c7ecd30d6499fa696f5839ecc30502a34b8b6))
# [1.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/@aws-crypto/crc32@1.0.0-alpha.0...@aws-crypto/crc32@1.0.0) (2020-10-22)
**Note:** Version bump only for package @aws-crypto/crc32
# [1.0.0-alpha.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/@aws-crypto/crc32@0.1.0-preview.4...@aws-crypto/crc32@1.0.0-alpha.0) (2020-02-07)
**Note:** Version bump only for package @aws-crypto/crc32
# [0.1.0-preview.4](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/@aws-crypto/crc32@0.1.0-preview.2...@aws-crypto/crc32@0.1.0-preview.4) (2020-01-16)
### Bug Fixes
- Changed package.json files to point to the right Git repo ([#9](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/9)) ([028245d](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/028245d72e642ca98d82226afb300eb154503c4a)), closes [#8](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/8)
- lerna version maintains package-lock ([#14](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/14)) ([2ef29e1](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/2ef29e13779703a5c9b32e93d18918fcb33b7272)), closes [#13](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/13)
# [0.1.0-preview.3](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/@aws-crypto/crc32@0.1.0-preview.2...@aws-crypto/crc32@0.1.0-preview.3) (2019-11-15)
### Bug Fixes
- Changed package.json files to point to the right Git repo ([#9](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/9)) ([028245d](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/028245d72e642ca98d82226afb300eb154503c4a)), closes [#8](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/8)
- lerna version maintains package-lock ([#14](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/14)) ([2ef29e1](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/2ef29e13779703a5c9b32e93d18918fcb33b7272)), closes [#13](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/13)
# [0.1.0-preview.2](https://github.com/aws/aws-javascript-crypto-helpers/compare/@aws-crypto/crc32@0.1.0-preview.1...@aws-crypto/crc32@0.1.0-preview.2) (2019-10-30)
### Bug Fixes
- remove /src/ from .npmignore (for sourcemaps) ([#5](https://github.com/aws/aws-javascript-crypto-helpers/issues/5)) ([ec52056](https://github.com/aws/aws-javascript-crypto-helpers/commit/ec52056))

View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,16 @@
# @aws-crypto/crc32
Pure JS implementation of CRC32 https://en.wikipedia.org/wiki/Cyclic_redundancy_check
## Usage
```
import { Crc32 } from '@aws-crypto/crc32';
const crc32Digest = (new Crc32).update(buffer).digest()
```
## Test
`npm test`

View File

@@ -0,0 +1,7 @@
import { SourceData, Checksum } from "@aws-sdk/types";
export declare class AwsCrc32 implements Checksum {
private crc32;
update(toHash: SourceData): void;
digest(): Promise<Uint8Array>;
reset(): void;
}

View File

@@ -0,0 +1,31 @@
"use strict";
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
Object.defineProperty(exports, "__esModule", { value: true });
exports.AwsCrc32 = void 0;
var tslib_1 = require("tslib");
var util_1 = require("@aws-crypto/util");
var index_1 = require("./index");
var AwsCrc32 = /** @class */ (function () {
function AwsCrc32() {
this.crc32 = new index_1.Crc32();
}
AwsCrc32.prototype.update = function (toHash) {
if ((0, util_1.isEmptyData)(toHash))
return;
this.crc32.update((0, util_1.convertToBuffer)(toHash));
};
AwsCrc32.prototype.digest = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
return [2 /*return*/, (0, util_1.numToUint8)(this.crc32.digest())];
});
});
};
AwsCrc32.prototype.reset = function () {
this.crc32 = new index_1.Crc32();
};
return AwsCrc32;
}());
exports.AwsCrc32 = AwsCrc32;
//# sourceMappingURL=aws_crc32.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"aws_crc32.js","sourceRoot":"","sources":["../../src/aws_crc32.ts"],"names":[],"mappings":";AAAA,oEAAoE;AACpE,sCAAsC;;;;AAGtC,yCAA4E;AAC5E,iCAAgC;AAEhC;IAAA;QACU,UAAK,GAAG,IAAI,aAAK,EAAE,CAAC;IAe9B,CAAC;IAbC,yBAAM,GAAN,UAAO,MAAkB;QACvB,IAAI,IAAA,kBAAW,EAAC,MAAM,CAAC;YAAE,OAAO;QAEhC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAA,sBAAe,EAAC,MAAM,CAAC,CAAC,CAAC;IAC7C,CAAC;IAEK,yBAAM,GAAZ;;;gBACE,sBAAO,IAAA,iBAAU,EAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAC;;;KACxC;IAED,wBAAK,GAAL;QACE,IAAI,CAAC,KAAK,GAAG,IAAI,aAAK,EAAE,CAAC;IAC3B,CAAC;IACH,eAAC;AAAD,CAAC,AAhBD,IAgBC;AAhBY,4BAAQ"}

View File

@@ -0,0 +1,7 @@
export declare function crc32(data: Uint8Array): number;
export declare class Crc32 {
private checksum;
update(data: Uint8Array): this;
digest(): number;
}
export { AwsCrc32 } from "./aws_crc32";

View File

@@ -0,0 +1,108 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AwsCrc32 = exports.Crc32 = exports.crc32 = void 0;
var tslib_1 = require("tslib");
var util_1 = require("@aws-crypto/util");
function crc32(data) {
return new Crc32().update(data).digest();
}
exports.crc32 = crc32;
var Crc32 = /** @class */ (function () {
function Crc32() {
this.checksum = 0xffffffff;
}
Crc32.prototype.update = function (data) {
var e_1, _a;
try {
for (var data_1 = tslib_1.__values(data), data_1_1 = data_1.next(); !data_1_1.done; data_1_1 = data_1.next()) {
var byte = data_1_1.value;
this.checksum =
(this.checksum >>> 8) ^ lookupTable[(this.checksum ^ byte) & 0xff];
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (data_1_1 && !data_1_1.done && (_a = data_1.return)) _a.call(data_1);
}
finally { if (e_1) throw e_1.error; }
}
return this;
};
Crc32.prototype.digest = function () {
return (this.checksum ^ 0xffffffff) >>> 0;
};
return Crc32;
}());
exports.Crc32 = Crc32;
// prettier-ignore
var a_lookUpTable = [
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
];
var lookupTable = (0, util_1.uint32ArrayFrom)(a_lookUpTable);
var aws_crc32_1 = require("./aws_crc32");
Object.defineProperty(exports, "AwsCrc32", { enumerable: true, get: function () { return aws_crc32_1.AwsCrc32; } });
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;AAAA,yCAAiD;AAEjD,SAAgB,KAAK,CAAC,IAAgB;IACpC,OAAO,IAAI,KAAK,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;AAC3C,CAAC;AAFD,sBAEC;AAED;IAAA;QACU,aAAQ,GAAG,UAAU,CAAC;IAchC,CAAC;IAZC,sBAAM,GAAN,UAAO,IAAgB;;;YACrB,KAAmB,IAAA,SAAA,iBAAA,IAAI,CAAA,0BAAA,4CAAE;gBAApB,IAAM,IAAI,iBAAA;gBACb,IAAI,CAAC,QAAQ;oBACX,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;aACtE;;;;;;;;;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,sBAAM,GAAN;QACE,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IACH,YAAC;AAAD,CAAC,AAfD,IAeC;AAfY,sBAAK;AAiBlB,kBAAkB;AAClB,IAAM,aAAa,GAAG;IACpB,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;CAC/C,CAAC;AACF,IAAM,WAAW,GAAgB,IAAA,sBAAe,EAAC,aAAa,CAAC,CAAA;AAC/D,yCAAuC;AAA9B,qGAAA,QAAQ,OAAA"}

View File

@@ -0,0 +1,7 @@
import { SourceData, Checksum } from "@aws-sdk/types";
export declare class AwsCrc32 implements Checksum {
private crc32;
update(toHash: SourceData): void;
digest(): Promise<Uint8Array>;
reset(): void;
}

View File

@@ -0,0 +1,28 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { __awaiter, __generator } from "tslib";
import { convertToBuffer, isEmptyData, numToUint8 } from "@aws-crypto/util";
import { Crc32 } from "./index";
var AwsCrc32 = /** @class */ (function () {
function AwsCrc32() {
this.crc32 = new Crc32();
}
AwsCrc32.prototype.update = function (toHash) {
if (isEmptyData(toHash))
return;
this.crc32.update(convertToBuffer(toHash));
};
AwsCrc32.prototype.digest = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, numToUint8(this.crc32.digest())];
});
});
};
AwsCrc32.prototype.reset = function () {
this.crc32 = new Crc32();
};
return AwsCrc32;
}());
export { AwsCrc32 };
//# sourceMappingURL=aws_crc32.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"aws_crc32.js","sourceRoot":"","sources":["../../src/aws_crc32.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,sCAAsC;;AAGtC,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC;IAAA;QACU,UAAK,GAAG,IAAI,KAAK,EAAE,CAAC;IAe9B,CAAC;IAbC,yBAAM,GAAN,UAAO,MAAkB;QACvB,IAAI,WAAW,CAAC,MAAM,CAAC;YAAE,OAAO;QAEhC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7C,CAAC;IAEK,yBAAM,GAAZ;;;gBACE,sBAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAC;;;KACxC;IAED,wBAAK,GAAL;QACE,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;IAC3B,CAAC;IACH,eAAC;AAAD,CAAC,AAhBD,IAgBC"}

View File

@@ -0,0 +1,7 @@
export declare function crc32(data: Uint8Array): number;
export declare class Crc32 {
private checksum;
update(data: Uint8Array): this;
digest(): number;
}
export { AwsCrc32 } from "./aws_crc32";

View File

@@ -0,0 +1,103 @@
import { __values } from "tslib";
import { uint32ArrayFrom } from "@aws-crypto/util";
export function crc32(data) {
return new Crc32().update(data).digest();
}
var Crc32 = /** @class */ (function () {
function Crc32() {
this.checksum = 0xffffffff;
}
Crc32.prototype.update = function (data) {
var e_1, _a;
try {
for (var data_1 = __values(data), data_1_1 = data_1.next(); !data_1_1.done; data_1_1 = data_1.next()) {
var byte = data_1_1.value;
this.checksum =
(this.checksum >>> 8) ^ lookupTable[(this.checksum ^ byte) & 0xff];
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (data_1_1 && !data_1_1.done && (_a = data_1.return)) _a.call(data_1);
}
finally { if (e_1) throw e_1.error; }
}
return this;
};
Crc32.prototype.digest = function () {
return (this.checksum ^ 0xffffffff) >>> 0;
};
return Crc32;
}());
export { Crc32 };
// prettier-ignore
var a_lookUpTable = [
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
];
var lookupTable = uint32ArrayFrom(a_lookUpTable);
export { AwsCrc32 } from "./aws_crc32";
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEjD,MAAM,UAAU,KAAK,CAAC,IAAgB;IACpC,OAAO,IAAI,KAAK,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;AAC3C,CAAC;AAED;IAAA;QACU,aAAQ,GAAG,UAAU,CAAC;IAchC,CAAC;IAZC,sBAAM,GAAN,UAAO,IAAgB;;;YACrB,KAAmB,IAAA,SAAA,SAAA,IAAI,CAAA,0BAAA,4CAAE;gBAApB,IAAM,IAAI,iBAAA;gBACb,IAAI,CAAC,QAAQ;oBACX,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;aACtE;;;;;;;;;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,sBAAM,GAAN;QACE,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IACH,YAAC;AAAD,CAAC,AAfD,IAeC;;AAED,kBAAkB;AAClB,IAAM,aAAa,GAAG;IACpB,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;CAC/C,CAAC;AACF,IAAM,WAAW,GAAgB,eAAe,CAAC,aAAa,CAAC,CAAA;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}

View File

@@ -0,0 +1,32 @@
{
"name": "@aws-crypto/crc32",
"version": "5.2.0",
"scripts": {
"prepublishOnly": "tsc -p tsconfig.json && tsc -p tsconfig.module.json",
"pretest": "tsc -p tsconfig.test.json",
"test": "mocha --require ts-node/register test/**/*test.ts"
},
"main": "./build/main/index.js",
"module": "./build/module/index.js",
"types": "./build/main/index.d.ts",
"repository": {
"type": "git",
"url": "git@github.com:aws/aws-sdk-js-crypto-helpers.git"
},
"author": {
"name": "AWS Crypto Tools Team",
"email": "aws-cryptools@amazon.com",
"url": "https://docs.aws.amazon.com/aws-crypto-tools/index.html?id=docs_gateway#lang/en_us"
},
"homepage": "https://github.com/aws/aws-sdk-js-crypto-helpers/tree/master/packages/crc32",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/util": "^5.2.0",
"@aws-sdk/types": "^3.222.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
},
"gitHead": "c11b171b35ec5c093364f0e0d8dc4ab1af68e748"
}

View File

@@ -0,0 +1,24 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { SourceData, Checksum } from "@aws-sdk/types";
import { convertToBuffer, isEmptyData, numToUint8 } from "@aws-crypto/util";
import { Crc32 } from "./index";
export class AwsCrc32 implements Checksum {
private crc32 = new Crc32();
update(toHash: SourceData) {
if (isEmptyData(toHash)) return;
this.crc32.update(convertToBuffer(toHash));
}
async digest(): Promise<Uint8Array> {
return numToUint8(this.crc32.digest());
}
reset(): void {
this.crc32 = new Crc32();
}
}

View File

@@ -0,0 +1,92 @@
import {uint32ArrayFrom} from "@aws-crypto/util";
export function crc32(data: Uint8Array): number {
return new Crc32().update(data).digest();
}
export class Crc32 {
private checksum = 0xffffffff;
update(data: Uint8Array): this {
for (const byte of data) {
this.checksum =
(this.checksum >>> 8) ^ lookupTable[(this.checksum ^ byte) & 0xff];
}
return this;
}
digest(): number {
return (this.checksum ^ 0xffffffff) >>> 0;
}
}
// prettier-ignore
const a_lookUpTable = [
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
];
const lookupTable: Uint32Array = uint32ArrayFrom(a_lookUpTable)
export { AwsCrc32 } from "./aws_crc32";

View File

@@ -0,0 +1,9 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./build/main",
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules/**"]
}

View File

@@ -0,0 +1,7 @@
{
"extends": "./tsconfig",
"compilerOptions": {
"outDir": "build/module",
"module": "esnext",
}
}

View File

@@ -0,0 +1,76 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.2.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v5.1.0...v5.2.0) (2023-10-16)
### Features
- support ESM artifacts in all packages ([#752](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/752)) ([e930ffb](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/e930ffba5cfef66dd242049e7d514ced232c1e3b))
# [5.1.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v5.0.0...v5.1.0) (2023-09-22)
### Bug Fixes
- Update tsc to 2.x ([#735](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/735)) ([782e0de](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/782e0de9f5fef41f694130580a69d940894b6b8c))
### Features
- Use @smithy/util-utf8 ([#730](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/730)) ([00fb851](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/00fb851ca3559d5a1f370f9256814de1210826b8)), closes [#699](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/699)
# [5.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v4.0.1...v5.0.0) (2023-07-13)
**Note:** Version bump only for package @aws-crypto/crc32c
# [4.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v3.0.0...v4.0.0) (2023-02-20)
**Note:** Version bump only for package @aws-crypto/crc32c
# [3.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.2...v3.0.0) (2023-01-12)
- feat!: replace Hash implementations with Checksum interface (#492) ([da43dc0](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/da43dc0fdf669d9ebb5bfb1b1f7c79e46c4aaae1)), closes [#492](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/492)
### BREAKING CHANGES
- All classes that implemented `Hash` now implement `Checksum`.
## [2.0.2](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.1...v2.0.2) (2022-09-07)
### Bug Fixes
- **#337:** update @aws-sdk/types ([#373](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/373)) ([b26a811](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/b26a811a392f5209c7ec7e57251500d4d78f97ff)), closes [#337](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/337)
## [2.0.1](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.0...v2.0.1) (2021-12-09)
**Note:** Version bump only for package @aws-crypto/crc32c
# [2.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.2...v2.0.0) (2021-10-25)
**Note:** Version bump only for package @aws-crypto/crc32c
## [1.2.2](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.1...v1.2.2) (2021-10-12)
### Bug Fixes
- **crc32c:** ie11 does not support Array.from ([#221](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/221)) ([5f49547](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/5f495472ab8988cf203e0f2a70a51f7e1fcd7e60))
## [1.2.1](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.0...v1.2.1) (2021-09-17)
**Note:** Version bump only for package @aws-crypto/crc32c
# [1.2.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.1.1...v1.2.0) (2021-09-17)
### Features
- Add AwsCrc32C Hash ([4840c83](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/4840c83bdd7c461dded777ebc45a8f99258ba21c))
## [0.2.1](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/@aws-crypto/crc32c@0.2.0...@aws-crypto/crc32c@0.2.1) (2021-08-24)
**Note:** Version bump only for package @aws-crypto/crc32c
# 0.2.0 (2021-08-11)
### Features
- Create CRC-32C implementation ([#201](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/201)) ([e43c7ec](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/e43c7ecd30d6499fa696f5839ecc30502a34b8b6))

View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,16 @@
# @aws-crypto/crc32c
Pure JS implementation of CRC32-C https://en.wikipedia.org/wiki/Cyclic_redundancy_check
## Usage
```
import { Crc32c } from '@aws-crypto/crc32c';
const crc32Digest = (new Crc32c).update(buffer).digest()
```
## Test
`npm test`

View File

@@ -0,0 +1,7 @@
import { Checksum, SourceData } from "@aws-sdk/types";
export declare class AwsCrc32c implements Checksum {
private crc32c;
update(toHash: SourceData): void;
digest(): Promise<Uint8Array>;
reset(): void;
}

View File

@@ -0,0 +1,31 @@
"use strict";
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
Object.defineProperty(exports, "__esModule", { value: true });
exports.AwsCrc32c = void 0;
var tslib_1 = require("tslib");
var util_1 = require("@aws-crypto/util");
var index_1 = require("./index");
var AwsCrc32c = /** @class */ (function () {
function AwsCrc32c() {
this.crc32c = new index_1.Crc32c();
}
AwsCrc32c.prototype.update = function (toHash) {
if ((0, util_1.isEmptyData)(toHash))
return;
this.crc32c.update((0, util_1.convertToBuffer)(toHash));
};
AwsCrc32c.prototype.digest = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
return [2 /*return*/, (0, util_1.numToUint8)(this.crc32c.digest())];
});
});
};
AwsCrc32c.prototype.reset = function () {
this.crc32c = new index_1.Crc32c();
};
return AwsCrc32c;
}());
exports.AwsCrc32c = AwsCrc32c;
//# sourceMappingURL=aws_crc32c.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"aws_crc32c.js","sourceRoot":"","sources":["../../src/aws_crc32c.ts"],"names":[],"mappings":";AAAA,oEAAoE;AACpE,sCAAsC;;;;AAGtC,yCAA4E;AAC5E,iCAAiC;AAEjC;IAAA;QACU,WAAM,GAAG,IAAI,cAAM,EAAE,CAAC;IAehC,CAAC;IAbC,0BAAM,GAAN,UAAO,MAAkB;QACvB,IAAI,IAAA,kBAAW,EAAC,MAAM,CAAC;YAAE,OAAO;QAEhC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAA,sBAAe,EAAC,MAAM,CAAC,CAAC,CAAC;IAC9C,CAAC;IAEK,0BAAM,GAAZ;;;gBACE,sBAAO,IAAA,iBAAU,EAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAC;;;KACzC;IAED,yBAAK,GAAL;QACE,IAAI,CAAC,MAAM,GAAG,IAAI,cAAM,EAAE,CAAC;IAC7B,CAAC;IACH,gBAAC;AAAD,CAAC,AAhBD,IAgBC;AAhBY,8BAAS"}

View File

@@ -0,0 +1,7 @@
export declare function crc32c(data: Uint8Array): number;
export declare class Crc32c {
private checksum;
update(data: Uint8Array): this;
digest(): number;
}
export { AwsCrc32c } from "./aws_crc32c";

View File

@@ -0,0 +1,78 @@
"use strict";
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
Object.defineProperty(exports, "__esModule", { value: true });
exports.AwsCrc32c = exports.Crc32c = exports.crc32c = void 0;
var tslib_1 = require("tslib");
var util_1 = require("@aws-crypto/util");
function crc32c(data) {
return new Crc32c().update(data).digest();
}
exports.crc32c = crc32c;
var Crc32c = /** @class */ (function () {
function Crc32c() {
this.checksum = 0xffffffff;
}
Crc32c.prototype.update = function (data) {
var e_1, _a;
try {
for (var data_1 = tslib_1.__values(data), data_1_1 = data_1.next(); !data_1_1.done; data_1_1 = data_1.next()) {
var byte = data_1_1.value;
this.checksum =
(this.checksum >>> 8) ^ lookupTable[(this.checksum ^ byte) & 0xff];
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (data_1_1 && !data_1_1.done && (_a = data_1.return)) _a.call(data_1);
}
finally { if (e_1) throw e_1.error; }
}
return this;
};
Crc32c.prototype.digest = function () {
return (this.checksum ^ 0xffffffff) >>> 0;
};
return Crc32c;
}());
exports.Crc32c = Crc32c;
// prettier-ignore
var a_lookupTable = [
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
];
var lookupTable = (0, util_1.uint32ArrayFrom)(a_lookupTable);
var aws_crc32c_1 = require("./aws_crc32c");
Object.defineProperty(exports, "AwsCrc32c", { enumerable: true, get: function () { return aws_crc32c_1.AwsCrc32c; } });
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA,oEAAoE;AACpE,sCAAsC;;;;AAEtC,yCAAiD;AAEjD,SAAgB,MAAM,CAAC,IAAgB;IACrC,OAAO,IAAI,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;AAC5C,CAAC;AAFD,wBAEC;AAED;IAAA;QACU,aAAQ,GAAG,UAAU,CAAC;IAchC,CAAC;IAZC,uBAAM,GAAN,UAAO,IAAgB;;;YACrB,KAAmB,IAAA,SAAA,iBAAA,IAAI,CAAA,0BAAA,4CAAE;gBAApB,IAAM,IAAI,iBAAA;gBACb,IAAI,CAAC,QAAQ;oBACX,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;aACtE;;;;;;;;;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,uBAAM,GAAN;QACE,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IACH,aAAC;AAAD,CAAC,AAfD,IAeC;AAfY,wBAAM;AAiBnB,kBAAkB;AAClB,IAAM,aAAa,GAAG;IACpB,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;CAC/F,CAAC;AAEF,IAAM,WAAW,GAAgB,IAAA,sBAAe,EAAC,aAAa,CAAC,CAAA;AAC/D,2CAAyC;AAAhC,uGAAA,SAAS,OAAA"}

View File

@@ -0,0 +1,7 @@
import { Checksum, SourceData } from "@aws-sdk/types";
export declare class AwsCrc32c implements Checksum {
private crc32c;
update(toHash: SourceData): void;
digest(): Promise<Uint8Array>;
reset(): void;
}

View File

@@ -0,0 +1,28 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { __awaiter, __generator } from "tslib";
import { convertToBuffer, isEmptyData, numToUint8 } from "@aws-crypto/util";
import { Crc32c } from "./index";
var AwsCrc32c = /** @class */ (function () {
function AwsCrc32c() {
this.crc32c = new Crc32c();
}
AwsCrc32c.prototype.update = function (toHash) {
if (isEmptyData(toHash))
return;
this.crc32c.update(convertToBuffer(toHash));
};
AwsCrc32c.prototype.digest = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, numToUint8(this.crc32c.digest())];
});
});
};
AwsCrc32c.prototype.reset = function () {
this.crc32c = new Crc32c();
};
return AwsCrc32c;
}());
export { AwsCrc32c };
//# sourceMappingURL=aws_crc32c.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"aws_crc32c.js","sourceRoot":"","sources":["../../src/aws_crc32c.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,sCAAsC;;AAGtC,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC;IAAA;QACU,WAAM,GAAG,IAAI,MAAM,EAAE,CAAC;IAehC,CAAC;IAbC,0BAAM,GAAN,UAAO,MAAkB;QACvB,IAAI,WAAW,CAAC,MAAM,CAAC;YAAE,OAAO;QAEhC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9C,CAAC;IAEK,0BAAM,GAAZ;;;gBACE,sBAAO,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAC;;;KACzC;IAED,yBAAK,GAAL;QACE,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;IAC7B,CAAC;IACH,gBAAC;AAAD,CAAC,AAhBD,IAgBC"}

View File

@@ -0,0 +1,7 @@
export declare function crc32c(data: Uint8Array): number;
export declare class Crc32c {
private checksum;
update(data: Uint8Array): this;
digest(): number;
}
export { AwsCrc32c } from "./aws_crc32c";

View File

@@ -0,0 +1,73 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { __values } from "tslib";
import { uint32ArrayFrom } from "@aws-crypto/util";
export function crc32c(data) {
return new Crc32c().update(data).digest();
}
var Crc32c = /** @class */ (function () {
function Crc32c() {
this.checksum = 0xffffffff;
}
Crc32c.prototype.update = function (data) {
var e_1, _a;
try {
for (var data_1 = __values(data), data_1_1 = data_1.next(); !data_1_1.done; data_1_1 = data_1.next()) {
var byte = data_1_1.value;
this.checksum =
(this.checksum >>> 8) ^ lookupTable[(this.checksum ^ byte) & 0xff];
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (data_1_1 && !data_1_1.done && (_a = data_1.return)) _a.call(data_1);
}
finally { if (e_1) throw e_1.error; }
}
return this;
};
Crc32c.prototype.digest = function () {
return (this.checksum ^ 0xffffffff) >>> 0;
};
return Crc32c;
}());
export { Crc32c };
// prettier-ignore
var a_lookupTable = [
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
];
var lookupTable = uint32ArrayFrom(a_lookupTable);
export { AwsCrc32c } from "./aws_crc32c";
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,sCAAsC;;AAEtC,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEjD,MAAM,UAAU,MAAM,CAAC,IAAgB;IACrC,OAAO,IAAI,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;AAC5C,CAAC;AAED;IAAA;QACU,aAAQ,GAAG,UAAU,CAAC;IAchC,CAAC;IAZC,uBAAM,GAAN,UAAO,IAAgB;;;YACrB,KAAmB,IAAA,SAAA,SAAA,IAAI,CAAA,0BAAA,4CAAE;gBAApB,IAAM,IAAI,iBAAA;gBACb,IAAI,CAAC,QAAQ;oBACX,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;aACtE;;;;;;;;;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,uBAAM,GAAN;QACE,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IACH,aAAC;AAAD,CAAC,AAfD,IAeC;;AAED,kBAAkB;AAClB,IAAM,aAAa,GAAG;IACpB,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;CAC/F,CAAC;AAEF,IAAM,WAAW,GAAgB,eAAe,CAAC,aAAa,CAAC,CAAA;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC"}

View File

@@ -0,0 +1,32 @@
{
"name": "@aws-crypto/crc32c",
"version": "5.2.0",
"scripts": {
"prepublishOnly": "tsc -p tsconfig.json && tsc -p tsconfig.module.json",
"pretest": "tsc -p tsconfig.test.json",
"test": "mocha --require ts-node/register test/**/*test.ts"
},
"main": "./build/main/index.js",
"module": "./build/module/index.js",
"types": "./build/main/index.d.ts",
"repository": {
"type": "git",
"url": "git@github.com:aws/aws-sdk-js-crypto-helpers.git"
},
"author": {
"name": "AWS Crypto Tools Team",
"email": "aws-cryptools@amazon.com",
"url": "https://docs.aws.amazon.com/aws-crypto-tools/index.html?id=docs_gateway#lang/en_us"
},
"homepage": "https://github.com/aws/aws-sdk-js-crypto-helpers/tree/master/packages/crc32c",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/util": "^5.2.0",
"@aws-sdk/types": "^3.222.0",
"tslib": "^2.6.2"
},
"publishConfig": {
"access": "public"
},
"gitHead": "c11b171b35ec5c093364f0e0d8dc4ab1af68e748"
}

View File

@@ -0,0 +1,24 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { Checksum, SourceData } from "@aws-sdk/types";
import { convertToBuffer, isEmptyData, numToUint8 } from "@aws-crypto/util";
import { Crc32c } from "./index";
export class AwsCrc32c implements Checksum {
private crc32c = new Crc32c();
update(toHash: SourceData) {
if (isEmptyData(toHash)) return;
this.crc32c.update(convertToBuffer(toHash));
}
async digest(): Promise<Uint8Array> {
return numToUint8(this.crc32c.digest());
}
reset(): void {
this.crc32c = new Crc32c();
}
}

View File

@@ -0,0 +1,64 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import {uint32ArrayFrom} from "@aws-crypto/util";
export function crc32c(data: Uint8Array): number {
return new Crc32c().update(data).digest();
}
export class Crc32c {
private checksum = 0xffffffff;
update(data: Uint8Array): this {
for (const byte of data) {
this.checksum =
(this.checksum >>> 8) ^ lookupTable[(this.checksum ^ byte) & 0xff];
}
return this;
}
digest(): number {
return (this.checksum ^ 0xffffffff) >>> 0;
}
}
// prettier-ignore
const a_lookupTable = [
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
];
const lookupTable: Uint32Array = uint32ArrayFrom(a_lookupTable)
export { AwsCrc32c } from "./aws_crc32c";

View File

@@ -0,0 +1,9 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./build/main",
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules/**"]
}

View File

@@ -0,0 +1,7 @@
{
"extends": "./tsconfig",
"compilerOptions": {
"outDir": "build/module",
"module": "esnext",
}
}

View File

@@ -0,0 +1,62 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.2.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v5.1.0...v5.2.0) (2023-10-16)
### Features
- support ESM artifacts in all packages ([#752](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/752)) ([e930ffb](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/e930ffba5cfef66dd242049e7d514ced232c1e3b))
# [5.1.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v5.0.0...v5.1.0) (2023-09-22)
### Bug Fixes
- Update tsc to 2.x ([#735](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/735)) ([782e0de](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/782e0de9f5fef41f694130580a69d940894b6b8c))
### Features
- Use @smithy/util-utf8 ([#730](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/730)) ([00fb851](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/00fb851ca3559d5a1f370f9256814de1210826b8)), closes [#699](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/699)
# [5.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v4.0.1...v5.0.0) (2023-07-13)
- feat!: drop support for IE 11 (#629) ([6c49fb6](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/6c49fb6c1b1f18bbff02dbd77a37a21bdb40c959)), closes [#629](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/629)
### BREAKING CHANGES
- Remove support for IE11
Co-authored-by: texastony <5892063+texastony@users.noreply.github.com>
# [4.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v3.0.0...v4.0.0) (2023-02-20)
**Note:** Version bump only for package @aws-crypto/sha1-browser
# [3.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.2...v3.0.0) (2023-01-12)
- feat!: replace Hash implementations with Checksum interface (#492) ([da43dc0](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/da43dc0fdf669d9ebb5bfb1b1f7c79e46c4aaae1)), closes [#492](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/492)
### BREAKING CHANGES
- All classes that implemented `Hash` now implement `Checksum`.
## [2.0.2](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.1...v2.0.2) (2022-09-07)
### Bug Fixes
- **#337:** update @aws-sdk/types ([#373](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/373)) ([b26a811](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/b26a811a392f5209c7ec7e57251500d4d78f97ff)), closes [#337](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/337)
# [2.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.2...v2.0.0) (2021-10-25)
**Note:** Version bump only for package @aws-crypto/sha1-browser
# [1.2.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.1.1...v1.2.0) (2021-09-17)
### Bug Fixes
- Adding ie11-detection dependency to sha1-browser ([#213](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/213)) ([138750d](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/138750d96385b8cc479b6f54c500ee1b5380648c))
### Features
- Add SHA1 ([#208](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/208)) ([45c50ff](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/45c50ffa3acc9e3bf4039ab59a0102e4d40455ec))

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,21 @@
# @aws-crypto/sha1-browser
SHA1 wrapper for browsers that prefers `window.crypto.subtle`.
SHA1 is **NOT** a cryptographically secure algorithm.
It should _only_ be used for non cryptographic functions like checksums.
## Usage
```
import {Sha1} from '@aws-crypto/sha1-browser'
const hash = new Sha1();
hash.update('some data');
const result = await hash.digest();
```
## Test
`npm test`

View File

@@ -0,0 +1,10 @@
export declare const SHA_1_HASH: {
name: "SHA-1";
};
export declare const SHA_1_HMAC_ALGO: {
name: "HMAC";
hash: {
name: "SHA-1";
};
};
export declare const EMPTY_DATA_SHA_1: Uint8Array;

View File

@@ -0,0 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EMPTY_DATA_SHA_1 = exports.SHA_1_HMAC_ALGO = exports.SHA_1_HASH = void 0;
exports.SHA_1_HASH = { name: "SHA-1" };
exports.SHA_1_HMAC_ALGO = {
name: "HMAC",
hash: exports.SHA_1_HASH,
};
exports.EMPTY_DATA_SHA_1 = new Uint8Array([
218,
57,
163,
238,
94,
107,
75,
13,
50,
85,
191,
239,
149,
96,
24,
144,
175,
216,
7,
9,
]);
//# sourceMappingURL=constants.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,UAAU,GAAsB,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAElD,QAAA,eAAe,GAA8C;IACxE,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,kBAAU;CACjB,CAAC;AAEW,QAAA,gBAAgB,GAAG,IAAI,UAAU,CAAC;IAC7C,GAAG;IACH,EAAE;IACF,GAAG;IACH,GAAG;IACH,EAAE;IACF,GAAG;IACH,EAAE;IACF,EAAE;IACF,EAAE;IACF,EAAE;IACF,GAAG;IACH,GAAG;IACH,GAAG;IACH,EAAE;IACF,EAAE;IACF,GAAG;IACH,GAAG;IACH,GAAG;IACH,CAAC;IACD,CAAC;CACF,CAAC,CAAC"}

View File

@@ -0,0 +1,8 @@
import { Checksum, SourceData } from "@aws-sdk/types";
export declare class Sha1 implements Checksum {
private hash;
constructor(secret?: SourceData);
update(data: SourceData, encoding?: "utf8" | "ascii" | "latin1"): void;
digest(): Promise<Uint8Array>;
reset(): void;
}

View File

@@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Sha1 = void 0;
var webCryptoSha1_1 = require("./webCryptoSha1");
var supports_web_crypto_1 = require("@aws-crypto/supports-web-crypto");
var util_locate_window_1 = require("@aws-sdk/util-locate-window");
var util_1 = require("@aws-crypto/util");
var Sha1 = /** @class */ (function () {
function Sha1(secret) {
if ((0, supports_web_crypto_1.supportsWebCrypto)((0, util_locate_window_1.locateWindow)())) {
this.hash = new webCryptoSha1_1.Sha1(secret);
}
else {
throw new Error("SHA1 not supported");
}
}
Sha1.prototype.update = function (data, encoding) {
this.hash.update((0, util_1.convertToBuffer)(data));
};
Sha1.prototype.digest = function () {
return this.hash.digest();
};
Sha1.prototype.reset = function () {
this.hash.reset();
};
return Sha1;
}());
exports.Sha1 = Sha1;
//# sourceMappingURL=crossPlatformSha1.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"crossPlatformSha1.js","sourceRoot":"","sources":["../../src/crossPlatformSha1.ts"],"names":[],"mappings":";;;AAAA,iDAAwD;AAExD,uEAAoE;AACpE,kEAA2D;AAC3D,yCAAmD;AAEnD;IAGE,cAAY,MAAmB;QAC7B,IAAI,IAAA,uCAAiB,EAAC,IAAA,iCAAY,GAAE,CAAC,EAAE;YACrC,IAAI,CAAC,IAAI,GAAG,IAAI,oBAAa,CAAC,MAAM,CAAC,CAAC;SACvC;aAAM;YACL,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;SACvC;IACH,CAAC;IAED,qBAAM,GAAN,UAAO,IAAgB,EAAE,QAAsC;QAC7D,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAA,sBAAe,EAAC,IAAI,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,qBAAM,GAAN;QACE,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IAC5B,CAAC;IAED,oBAAK,GAAL;QACE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;IACH,WAAC;AAAD,CAAC,AAtBD,IAsBC;AAtBY,oBAAI"}

View File

@@ -0,0 +1,2 @@
export * from "./crossPlatformSha1";
export { Sha1 as WebCryptoSha1 } from "./webCryptoSha1";

View File

@@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebCryptoSha1 = void 0;
var tslib_1 = require("tslib");
tslib_1.__exportStar(require("./crossPlatformSha1"), exports);
var webCryptoSha1_1 = require("./webCryptoSha1");
Object.defineProperty(exports, "WebCryptoSha1", { enumerable: true, get: function () { return webCryptoSha1_1.Sha1; } });
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;AAAA,8DAAoC;AACpC,iDAAwD;AAA/C,8GAAA,IAAI,OAAiB"}

View File

@@ -0,0 +1,2 @@
import { SourceData } from "@aws-sdk/types";
export declare function isEmptyData(data: SourceData): boolean;

View File

@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isEmptyData = void 0;
function isEmptyData(data) {
if (typeof data === "string") {
return data.length === 0;
}
return data.byteLength === 0;
}
exports.isEmptyData = isEmptyData;
//# sourceMappingURL=isEmptyData.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"isEmptyData.js","sourceRoot":"","sources":["../../src/isEmptyData.ts"],"names":[],"mappings":";;;AAEA,SAAgB,WAAW,CAAC,IAAgB;IAC1C,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;QAC5B,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC;KAC1B;IAED,OAAO,IAAI,CAAC,UAAU,KAAK,CAAC,CAAC;AAC/B,CAAC;AAND,kCAMC"}

View File

@@ -0,0 +1,9 @@
import { Checksum, SourceData } from "@aws-sdk/types";
export declare class Sha1 implements Checksum {
private readonly key;
private toHash;
constructor(secret?: SourceData);
update(data: SourceData): void;
digest(): Promise<Uint8Array>;
reset(): void;
}

View File

@@ -0,0 +1,61 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Sha1 = void 0;
var util_utf8_1 = require("@smithy/util-utf8");
var isEmptyData_1 = require("./isEmptyData");
var constants_1 = require("./constants");
var util_locate_window_1 = require("@aws-sdk/util-locate-window");
var Sha1 = /** @class */ (function () {
function Sha1(secret) {
this.toHash = new Uint8Array(0);
if (secret !== void 0) {
this.key = new Promise(function (resolve, reject) {
(0, util_locate_window_1.locateWindow)()
.crypto.subtle.importKey("raw", convertToBuffer(secret), constants_1.SHA_1_HMAC_ALGO, false, ["sign"])
.then(resolve, reject);
});
this.key.catch(function () { });
}
}
Sha1.prototype.update = function (data) {
if ((0, isEmptyData_1.isEmptyData)(data)) {
return;
}
var update = convertToBuffer(data);
var typedArray = new Uint8Array(this.toHash.byteLength + update.byteLength);
typedArray.set(this.toHash, 0);
typedArray.set(update, this.toHash.byteLength);
this.toHash = typedArray;
};
Sha1.prototype.digest = function () {
var _this = this;
if (this.key) {
return this.key.then(function (key) {
return (0, util_locate_window_1.locateWindow)()
.crypto.subtle.sign(constants_1.SHA_1_HMAC_ALGO, key, _this.toHash)
.then(function (data) { return new Uint8Array(data); });
});
}
if ((0, isEmptyData_1.isEmptyData)(this.toHash)) {
return Promise.resolve(constants_1.EMPTY_DATA_SHA_1);
}
return Promise.resolve()
.then(function () { return (0, util_locate_window_1.locateWindow)().crypto.subtle.digest(constants_1.SHA_1_HASH, _this.toHash); })
.then(function (data) { return Promise.resolve(new Uint8Array(data)); });
};
Sha1.prototype.reset = function () {
this.toHash = new Uint8Array(0);
};
return Sha1;
}());
exports.Sha1 = Sha1;
function convertToBuffer(data) {
if (typeof data === "string") {
return (0, util_utf8_1.fromUtf8)(data);
}
if (ArrayBuffer.isView(data)) {
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength / Uint8Array.BYTES_PER_ELEMENT);
}
return new Uint8Array(data);
}
//# sourceMappingURL=webCryptoSha1.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"webCryptoSha1.js","sourceRoot":"","sources":["../../src/webCryptoSha1.ts"],"names":[],"mappings":";;;AACA,+CAA6C;AAC7C,6CAA4C;AAC5C,yCAA4E;AAC5E,kEAA2D;AAE3D;IAIE,cAAY,MAAmB;QAFvB,WAAM,GAAe,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;QAG7C,IAAI,MAAM,KAAK,KAAK,CAAC,EAAE;YACrB,IAAI,CAAC,GAAG,GAAG,IAAI,OAAO,CAAC,UAAC,OAAO,EAAE,MAAM;gBACrC,IAAA,iCAAY,GAAE;qBACX,MAAM,CAAC,MAAM,CAAC,SAAS,CACtB,KAAK,EACL,eAAe,CAAC,MAAM,CAAC,EACvB,2BAAe,EACf,KAAK,EACL,CAAC,MAAM,CAAC,CACT;qBACA,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC3B,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,cAAO,CAAC,CAAC,CAAC;SAC1B;IACH,CAAC;IAED,qBAAM,GAAN,UAAO,IAAgB;QACrB,IAAI,IAAA,yBAAW,EAAC,IAAI,CAAC,EAAE;YACrB,OAAO;SACR;QAED,IAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QACrC,IAAM,UAAU,GAAG,IAAI,UAAU,CAC/B,IAAI,CAAC,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAC3C,CAAC;QACF,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC/B,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC;IAC3B,CAAC;IAED,qBAAM,GAAN;QAAA,iBAgBC;QAfC,IAAI,IAAI,CAAC,GAAG,EAAE;YACZ,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAC,GAAG;gBACvB,OAAA,IAAA,iCAAY,GAAE;qBACX,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,2BAAe,EAAE,GAAG,EAAE,KAAI,CAAC,MAAM,CAAC;qBACrD,IAAI,CAAC,UAAC,IAAI,IAAK,OAAA,IAAI,UAAU,CAAC,IAAI,CAAC,EAApB,CAAoB,CAAC;YAFvC,CAEuC,CACxC,CAAC;SACH;QAED,IAAI,IAAA,yBAAW,EAAC,IAAI,CAAC,MAAM,CAAC,EAAE;YAC5B,OAAO,OAAO,CAAC,OAAO,CAAC,4BAAgB,CAAC,CAAC;SAC1C;QAED,OAAO,OAAO,CAAC,OAAO,EAAE;aACrB,IAAI,CAAC,cAAM,OAAA,IAAA,iCAAY,GAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,sBAAU,EAAE,KAAI,CAAC,MAAM,CAAC,EAA5D,CAA4D,CAAC;aACxE,IAAI,CAAC,UAAC,IAAI,IAAK,OAAA,OAAO,CAAC,OAAO,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,EAArC,CAAqC,CAAC,CAAC;IAC3D,CAAC;IAED,oBAAK,GAAL;QACE,IAAI,CAAC,MAAM,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACH,WAAC;AAAD,CAAC,AAxDD,IAwDC;AAxDY,oBAAI;AA0DjB,SAAS,eAAe,CAAC,IAAgB;IACvC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;QAC5B,OAAO,IAAA,oBAAQ,EAAC,IAAI,CAAC,CAAC;KACvB;IAED,IAAI,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;QAC5B,OAAO,IAAI,UAAU,CACnB,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC,iBAAiB,CAC/C,CAAC;KACH;IAED,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC"}

View File

@@ -0,0 +1,10 @@
export declare const SHA_1_HASH: {
name: "SHA-1";
};
export declare const SHA_1_HMAC_ALGO: {
name: "HMAC";
hash: {
name: "SHA-1";
};
};
export declare const EMPTY_DATA_SHA_1: Uint8Array;

View File

@@ -0,0 +1,28 @@
export var SHA_1_HASH = { name: "SHA-1" };
export var SHA_1_HMAC_ALGO = {
name: "HMAC",
hash: SHA_1_HASH,
};
export var EMPTY_DATA_SHA_1 = new Uint8Array([
218,
57,
163,
238,
94,
107,
75,
13,
50,
85,
191,
239,
149,
96,
24,
144,
175,
216,
7,
9,
]);
//# sourceMappingURL=constants.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,IAAM,UAAU,GAAsB,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAE/D,MAAM,CAAC,IAAM,eAAe,GAA8C;IACxE,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,UAAU;CACjB,CAAC;AAEF,MAAM,CAAC,IAAM,gBAAgB,GAAG,IAAI,UAAU,CAAC;IAC7C,GAAG;IACH,EAAE;IACF,GAAG;IACH,GAAG;IACH,EAAE;IACF,GAAG;IACH,EAAE;IACF,EAAE;IACF,EAAE;IACF,EAAE;IACF,GAAG;IACH,GAAG;IACH,GAAG;IACH,EAAE;IACF,EAAE;IACF,GAAG;IACH,GAAG;IACH,GAAG;IACH,CAAC;IACD,CAAC;CACF,CAAC,CAAC"}

View File

@@ -0,0 +1,8 @@
import { Checksum, SourceData } from "@aws-sdk/types";
export declare class Sha1 implements Checksum {
private hash;
constructor(secret?: SourceData);
update(data: SourceData, encoding?: "utf8" | "ascii" | "latin1"): void;
digest(): Promise<Uint8Array>;
reset(): void;
}

View File

@@ -0,0 +1,26 @@
import { Sha1 as WebCryptoSha1 } from "./webCryptoSha1";
import { supportsWebCrypto } from "@aws-crypto/supports-web-crypto";
import { locateWindow } from "@aws-sdk/util-locate-window";
import { convertToBuffer } from "@aws-crypto/util";
var Sha1 = /** @class */ (function () {
function Sha1(secret) {
if (supportsWebCrypto(locateWindow())) {
this.hash = new WebCryptoSha1(secret);
}
else {
throw new Error("SHA1 not supported");
}
}
Sha1.prototype.update = function (data, encoding) {
this.hash.update(convertToBuffer(data));
};
Sha1.prototype.digest = function () {
return this.hash.digest();
};
Sha1.prototype.reset = function () {
this.hash.reset();
};
return Sha1;
}());
export { Sha1 };
//# sourceMappingURL=crossPlatformSha1.js.map

Some files were not shown because too many files have changed in this diff Show More