- ARCHITECTURE.md: high-level view of FakeFs abstraction, sync flow, state - DEVELOPMENT.md: mise setup + npm commands + local install - CONTRIBUTING.md: workflow, English commit conventions, upstream PR cherry-pick
72 lines
3.1 KiB
Markdown
72 lines
3.1 KiB
Markdown
# Arquitetura
|
|
|
|
Plugin Obsidian (TypeScript) que sincroniza vaults com serviços de armazenamento remoto (WebDAV, S3, Dropbox, OneDrive, etc).
|
|
|
|
## Estrutura
|
|
|
|
```
|
|
src/ código público (MIT)
|
|
├── main.ts entry point, estende Plugin do Obsidian (~2k linhas)
|
|
├── settings.ts UI de settings (~3k linhas)
|
|
├── fsAll.ts abstração FakeFs — interface comum dos backends
|
|
├── fsGetter.ts roteamento backend → instância (switch por tipo)
|
|
├── fs<Backend>.ts implementações: S3, WebDAV, Dropbox, OneDrive, Webdis, Local, Encrypt
|
|
├── localdb.ts IndexedDB via LocalForage — state local
|
|
├── configPersist.ts serialização da config no disco do plugin
|
|
├── i18n.ts Mustache + moment, idiomas em src/langs/
|
|
└── ...
|
|
|
|
pro/ código tier pago (PolyForm Strict License)
|
|
├── src/
|
|
│ ├── sync.ts motor de sincronização (~2k linhas, doActualSync + dispatchDecision)
|
|
│ ├── fs<Backend>.ts GoogleDrive, Box, pCloud, YandexDisk, Koofr, Azure, OnedriveFull
|
|
│ └── ...
|
|
└── tests/
|
|
|
|
tests/ testes Mocha (estrutura básica, sem cobertura do core)
|
|
docs/ documentação
|
|
.github/workflows/ CI
|
|
```
|
|
|
|
## Abstração FakeFs
|
|
|
|
Todo backend implementa a classe abstrata `FakeFs` (`src/fsAll.ts`):
|
|
|
|
```typescript
|
|
abstract class FakeFs {
|
|
walk() / walkPartial() / stat() / mkdir() / writeFile()
|
|
readFile() / rename() / rm()
|
|
checkConnect() / getUserDisplayName() / revokeAuth() / allowEmptyFile()
|
|
}
|
|
```
|
|
|
|
`fsGetter.ts` faz o roteamento via switch — ao adicionar backend novo, registrar nele.
|
|
|
|
## Fluxo de sincronização
|
|
|
|
1. `main.ts` dispara sync (manual, auto-sync, evento de save)
|
|
2. `pro/src/sync.ts:doActualSync()` carrega árvore local + remota
|
|
3. Diff 3-way usando snapshot anterior (`prevSyncRecordsTbl` em IndexedDB)
|
|
4. `dispatchDecision()` aplica decisão por entry (copy, merge, delete, skip)
|
|
5. Conflitos: 3-way merge via `node-diff3` (apenas Markdown < 1MB, tier pro)
|
|
6. Erros agregados em `AggregateError`; falha até 3x antes de abortar
|
|
|
|
## State
|
|
|
|
LocalForage (IndexedDB) com 8 tabelas em `src/localdb.ts`:
|
|
|
|
- `prevSyncRecordsTbl` — snapshot da última sync
|
|
- `fileContentHistoryTbl` — histórico de conteúdo (smart conflict)
|
|
- `syncPlansTbl` — log das operações planejadas
|
|
- `versionTbl`, `loggerOutputTbl`, `profilerResultsTbl` — metadados
|
|
|
|
Config persiste via API do Obsidian em `<vault>/.obsidian/plugins/remotely-save/data.json`,
|
|
com obfuscação base64 reverse (decorativa, não criptográfica).
|
|
|
|
## Pontos de atenção
|
|
|
|
- **mtime no WebDAV**: padrão WebDAV não define mtime — Nextcloud expõe via header custom (`OC-LastModified`). Inconsistência pode causar falsa detecção de modificação.
|
|
- **OAuth2 duplicado**: cada backend implementa fluxo próprio (~100-300 linhas duplicadas). Sem extração comum.
|
|
- **Sem retry HTTP**: 429/503 quebram sync. PR upstream #1034 propõe retry para WebDAV.
|
|
- **141 `: any` residuais**: concentrados em callbacks de error e payloads OAuth2.
|