9.2 KiB
type, status, related
| type | status | related | |||||
|---|---|---|---|---|---|---|---|
| reference | current |
|
Unified file client — контракт файловых бэкендов
Что это
Один файловый клиент на все бэкенды (эпик #34). Модель и интерфейсы —
file_core.go. Фасад FileClient — file_facade.go. Бэкенды:
REST, WebDAV, SQL (PostgreSQL/MySQL), Elasticsearch. Правило одно:
код зовёт c.Files() и не знает про транспорт.
Модель
Kind—File(0) илиFolder(1).Entry— бэкенд-независимая строка:ID,ParentID,Title,Kind,Size,MIME,Created,Modified,Updated(сырая строка API),Version,Provider,FilesCount/FoldersCount(папки). Чего бэкенд не даёт — остаётся в нуле.SearchQuery—Text,InContent,FolderID,Extensions,Limit.SearchHit—Entry+Score,Highlight,Path.
Интерфейсы
FileStore — операции с файлами:
type FileStore interface {
Name() string
List(ctx, parentID) ([]Entry, error)
Stat(ctx, id) (Entry, error)
CreateFolder(ctx, parentID, title) (Entry, error)
Upload(ctx, parentID, title, r) (Entry, error)
Download(ctx, id, w) (int64, error)
Move(ctx, ids, parentID) error
Copy(ctx, ids, parentID) error
Rename(ctx, id, title) error
Delete(ctx, ids) error
}
Searcher — поиск (необязательный):
type Searcher interface {
Search(ctx, q SearchQuery) ([]SearchHit, error)
Name() string
}
TextIndex (file_es_text.go) — свой индекс: Put, Delete, Search,
Name. ESTextIndex реализует и Searcher, и TextIndex.
Бэкенды
| бэкенд | провайдер | файл | что умеет |
|---|---|---|---|
| REST | rest |
file_rest.go |
read + write, Documents API |
| WebDAV | dav |
file_dav.go |
read + write, Documents fileops |
| SQL | postgres / mysql |
file_pg.go |
read-only |
| OnlyOffice ES | elasticsearch |
file_es.go |
поиск (имя + контент Office) |
| свой ES-индекс | es-text |
file_es_text.go |
поиск + запись (PDF/сканы) |
- REST:
Statзнает только файлы; папки — черезList. - WebDAV:
Move/Copy/DeleteсперваStat-ят id (папка/файл), потом зовут fileops. - SQL:
List/Stat/Download/Search(по имени). Все write-методы →ErrReadOnly.Downloadидёт в S3/MinIO по layout портала. - OnlyOffice ES: индекс
files_file, контент только для docx/xlsx/pptx. - Свой ES: индекс
oo_docs_text, контент изinternal/docpipe, в т.ч. встроенные PDF-вложения.
Фасад FileClient
c.Files() → *FileClient. Он же реализует FileStore, старый код
компилируется.
Read()— первый зарегистрированный изreadOrder:postgres→mysql→rest→dav.Write()— первый изwriteOrder:rest→dav. SQL не пишет.Search()— первый изsearchOrder:elasticsearch. Нет бэкенда → ошибка (ONLYOFFICE_ES_URL).RegisterStore(name, s)/RegisterSearcher(name, s)— добавить бэкенд.
Fallback:
List/Statидут поreadOrder; переходят к следующему только на transient-ошибке (429/502/503/504). Иначе ошибка финальная.Downloadбез fallback: часть байтов уже вw, второй бэкенд допишет.- Запись (
CreateFolder/Upload/Move/Copy/Rename/Delete) — толькоWrite(), без fallback.
newFileClient сам кладёт rest и dav; ES-поиск — если задан
ONLYOFFICE_ES_URL. SQL-стор регистрирует вызывающий: фасад создаётся на
каждый c.Files(), регистрируй на том же экземпляре.
sql, err := c.SQLFileStore() // открыть из env (ONLYOFFICE_DSN)
if err != nil { /* нет DSN */ }
if closer, ok := sql.(interface{ Close() error }); ok { defer closer.Close() }
f := c.Files()
f.RegisterStore(onlyoffice.ProviderPG, sql) // или sql.Name() == "mysql"
e, _ := f.Stat(ctx, "19423") // e.Provider == "mysql"
entries, _ := f.List(ctx, "676") // пойдёт в SQL
Client.FileStore("pg"|"sql"|"postgres"|"mysql") — одноразовый доступ к
SQL-стору без фасада: открывает из env; при ошибке возвращает заглушку,
которая отдаёт ошибку открытия на каждом вызове (не nil). SQLFileStore()
— тот же открыватель, но с ошибкой. Отвечавший бэкенд видно по
Entry.Provider (mysql / postgres у SQL, rest у REST).
CLI
# поиск: --backend oo (индекс OnlyOffice) | own (свой oo_docs_text)
oo search "Rechnung"
oo search "Mahngebühr" --content
oo search "S1021" --content --backend own --folder 634 --limit 50 --json
# наполнение своего индекса (PDF/сканы, idempotent upsert по file id)
oo index folder 634
oo index folder 634 --recursive --exts pdf,png --limit 100
oo index files 3576 3578
oo index folder 634 --dry-run
oo index флаги: --recursive, --exts (default pdf), --limit,
--workers (3), --lang (deu+eng), --min-chars, --work-dir,
--backend rest|dav, --dry-run, --json.
Библиотека:
idx, _ := onlyoffice.NewESTextIndex(onlyoffice.ESTextConfigFromEnv())
ti := onlyoffice.NewTextIndexer(store, idx) // store = FileStore
res, _ := ti.IndexFolder(ctx, "634", onlyoffice.IndexOptions{Recursive: true})
Env (только имена)
| env | default | кто читает |
|---|---|---|
ONLYOFFICE_ES_URL |
— | ES (оба индекса), обязателен |
ONLYOFFICE_ES_INDEX |
files_file |
индекс OnlyOffice |
ONLYOFFICE_ES_TEXT_INDEX |
oo_docs_text |
свой индекс |
ONLYOFFICE_TENANT |
пусто | фильтр tenantId |
ONLYOFFICE_DSN |
— | SQL DSN (MySQL/PostgreSQL) |
ONLYOFFICE_PG_DRIVER |
auto | postgres / mysql |
ONLYOFFICE_PG_TENANT |
ONLYOFFICE_TENANT |
SQL tenant |
ONLYOFFICE_PG_HOST _PORT _USER _PASSWORD _DBNAME _SSLMODE |
— | DSN по частям |
MINIO_ENDPOINT MINIO_BUCKET MINIO_ACCESS_KEY MINIO_SECRET_KEY |
— | download SQL-стора |
OO_URL OO_USER OO_PASS |
— | CLI-алиасы |
Имена — в .env.example. Секретов в репо нет.
Ограничения
- OnlyOffice ES: контент только Office-форматов. PDF — только по имени. Встроенные вложения PDF сервер не индексирует.
- Свой индекс
oo_docs_text: покрывает PDF/сканы и вложения (pdfdetach), но наполняется вручную (oo index) и идемпотентен. Фильтрfolder— id папки, не путь. Дубли дают несколько строк — дедуп на потребителе. - SQL: read-only.
InContentигнорируется (только имя). Download — через MinIO-схему, не HTTP. - ES: без auth, слушает localhost внутри VM — нужен SSH-туннель (см. elasticsearch.md).
oo indexкачает каждый файл и для сканов гоняет OCR — медленно; отсюда--limitи--exts. Нуженpdfdetach(poppler); без него — только тело PDF.
Как добавить бэкенд
- Файл
file_<name>.go. РеализуйFileStore(Name+ 9 методов). Нужен поиск — добавьSearcher; нужна запись своего индекса —TextIndex. - Добавь const провайдера рядом с
ProviderREST/ProviderDAV. - Зарегистрируй: в
newFileClientили снаружи черезRegisterStore/RegisterSearcher. - Внеси имя в
readOrder/writeOrder/searchOrder. - Есть CLI-команда — добавь значение в
--backend. - Тесты: unit (чистые builders/парсеры, без сети) + интеграционный
(
//go:build integration, skip без кред).
Тесты
go test ./... # unit, без сети
go test -tags=integration ./... # live (креды в .env)
go test ./ -run 'FileStore|Facade|ESText|PG'
См. также
- elasticsearch.md — индекс OnlyOffice и свой
oo_docs_text. - community-server-db.md — SQL-стор и схема БД.