mirror of
https://github.com/syncthing/syncthing.git
synced 2025-12-23 22:18:14 -05:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8151bcddff | ||
|
|
d776657b52 | ||
|
|
0416103f26 | ||
|
|
7bfcdfb577 | ||
|
|
e6a9b09527 | ||
|
|
c8f52ba1bc | ||
|
|
3058aa6315 | ||
|
|
60160db23a | ||
|
|
66b28e9aed |
23
.github/workflows/build-syncthing.yaml
vendored
23
.github/workflows/build-syncthing.yaml
vendored
@@ -890,8 +890,6 @@ jobs:
|
||||
RELEASE_GENERATION: ${{ needs.facts.outputs.release-generation }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Download packages
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -899,14 +897,6 @@ jobs:
|
||||
path: packages
|
||||
|
||||
# Decide whether packages should go to stable, candidate or nightly
|
||||
- name: Prepare packages
|
||||
run: |
|
||||
if [[ $RELEASE_KIND == stable && $RELEASE_GENERATION == v2 ]] ; then
|
||||
RELEASE_KIND=stable-v2
|
||||
fi
|
||||
mkdir -p packages/syncthing/$RELEASE_KIND
|
||||
mv packages/*.deb packages/syncthing/$RELEASE_KIND
|
||||
|
||||
- name: Pull archive
|
||||
uses: docker://docker.io/rclone/rclone:latest
|
||||
env:
|
||||
@@ -918,15 +908,18 @@ jobs:
|
||||
RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
|
||||
RCLONE_CONFIG_OBJSTORE_ACL: public-read
|
||||
with:
|
||||
args: sync objstore:apt/dists dists
|
||||
args: sync objstore:apt apt
|
||||
|
||||
- name: Prepare packages
|
||||
run: |
|
||||
sudo chown -R $(id -u) apt/pool
|
||||
mv packages/*.deb apt/pool
|
||||
|
||||
- name: Update archive
|
||||
uses: docker://ghcr.io/kastelo/ezapt:latest
|
||||
with:
|
||||
args:
|
||||
publish
|
||||
--add packages
|
||||
--dists dists
|
||||
publish --root apt
|
||||
env:
|
||||
EZAPT_KEYRING_BASE64: ${{ secrets.APT_GPG_KEYRING_BASE64 }}
|
||||
|
||||
@@ -941,7 +934,7 @@ jobs:
|
||||
RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
|
||||
RCLONE_CONFIG_OBJSTORE_ACL: public-read
|
||||
with:
|
||||
args: sync -v --no-update-modtime dists objstore:apt/dists
|
||||
args: sync -v --no-update-modtime apt objstore:apt
|
||||
|
||||
#
|
||||
# Build and push (except for PRs) to GHCR.
|
||||
|
||||
@@ -122,9 +122,10 @@ type CLI struct {
|
||||
// subcommands. Their settings take effect on the `locations` package by
|
||||
// way of the command line parser, so anything using `locations.Get` etc
|
||||
// will be doing the right thing.
|
||||
ConfDir string `name:"config" short:"C" placeholder:"PATH" env:"STCONFDIR" help:"Set configuration directory (config and keys)"`
|
||||
DataDir string `name:"data" short:"D" placeholder:"PATH" env:"STDATADIR" help:"Set data directory (database and logs)"`
|
||||
HomeDir string `name:"home" short:"H" placeholder:"PATH" env:"STHOMEDIR" help:"Set configuration and data directory"`
|
||||
ConfDir string `name:"config" short:"C" placeholder:"PATH" env:"STCONFDIR" help:"Set configuration directory (config and keys)"`
|
||||
DataDir string `name:"data" short:"D" placeholder:"PATH" env:"STDATADIR" help:"Set data directory (database and logs)"`
|
||||
HomeDir string `name:"home" short:"H" placeholder:"PATH" env:"STHOMEDIR" help:"Set configuration and data directory"`
|
||||
VersionFlag bool `name:"version" help:"Show current version, then exit"`
|
||||
|
||||
Serve serveCmd `cmd:"" help:"Run Syncthing (default)" default:"withargs"`
|
||||
CLI cli.CLI `cmd:"" help:"Command line interface for Syncthing"`
|
||||
@@ -224,6 +225,12 @@ func main() {
|
||||
kongplete.Complete(parser)
|
||||
ctx, err := parser.Parse(os.Args[1:])
|
||||
parser.FatalIfErrorf(err)
|
||||
|
||||
if entrypoint.VersionFlag {
|
||||
_ = versionCmd{}.Run()
|
||||
return
|
||||
}
|
||||
|
||||
err = ctx.Run()
|
||||
parser.FatalIfErrorf(err)
|
||||
}
|
||||
@@ -472,7 +479,7 @@ func (c *serveCmd) syncthingMain() {
|
||||
})
|
||||
}
|
||||
|
||||
if err := syncthing.TryMigrateDatabase(c.DBDeleteRetentionInterval); err != nil {
|
||||
if err := syncthing.TryMigrateDatabase(ctx, c.DBDeleteRetentionInterval, cfgWrapper.GUI().Address()); err != nil {
|
||||
slog.Error("Failed to migrate old-style database", slogutil.Error(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
2
go.mod
2
go.mod
@@ -34,7 +34,7 @@ require (
|
||||
github.com/quic-go/quic-go v0.52.0
|
||||
github.com/rabbitmq/amqp091-go v1.10.0
|
||||
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9
|
||||
github.com/shirou/gopsutil/v4 v4.25.7
|
||||
github.com/shirou/gopsutil/v4 v4.25.6 // https://github.com/shirou/gopsutil/issues/1898
|
||||
github.com/syncthing/notify v0.0.0-20250528144937-c7027d4f7465
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d
|
||||
github.com/thejerf/suture/v4 v4.0.6
|
||||
|
||||
4
go.sum
4
go.sum
@@ -240,8 +240,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8=
|
||||
github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM=
|
||||
github.com/shirou/gopsutil/v4 v4.25.7 h1:bNb2JuqKuAu3tRlPv5piSmBZyMfecwQ+t/ILq+1JqVM=
|
||||
github.com/shirou/gopsutil/v4 v4.25.7/go.mod h1:XV/egmwJtd3ZQjBpJVY5kndsiOO4IRqy9TQnmm6VP7U=
|
||||
github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs=
|
||||
github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
"Click to see full identification string and QR code.": "Klicken, um die vollständige Kennung und den QR-Code anzuzeigen.",
|
||||
"Close": "Schließen",
|
||||
"Command": "Befehl",
|
||||
"Comment, when used at the start of a line": "Kommentar, wenn am Anfang der Zeile verwendet.",
|
||||
"Comment, when used at the start of a line": "Kommentar, wenn am Anfang der Zeile verwendet",
|
||||
"Compression": "Komprimierung",
|
||||
"Configuration Directory": "Konfigurationsverzeichnis",
|
||||
"Configuration File": "Konfigurationsdatei",
|
||||
@@ -82,6 +82,7 @@
|
||||
"Custom Range": "Eigener Zeitraum",
|
||||
"Danger!": "Achtung!",
|
||||
"Database Location": "Datenbank-Speicherort",
|
||||
"Debug": "Debug",
|
||||
"Debugging Facilities": "Debugging-Möglichkeiten",
|
||||
"Default": "Vorgabe",
|
||||
"Default Configuration": "Vorgabekonfiguration",
|
||||
@@ -104,7 +105,7 @@
|
||||
"Device Status": "Gerätestatus",
|
||||
"Device is untrusted, enter encryption password": "Gerät wird nicht vertraut, Verschlüsselungspasswort eingeben",
|
||||
"Device rate limits": "Datenratenbegrenzungen fürs Gerät",
|
||||
"Device that last modified the item": "Gerät, das das Element zuletzt geändert hat",
|
||||
"Device that last modified the item": "Gerät, welches das Element zuletzt geändert hat",
|
||||
"Devices": "Geräte",
|
||||
"Disable Crash Reporting": "Absturzmeldung deaktivieren",
|
||||
"Disabled": "Deaktiviert",
|
||||
@@ -183,7 +184,7 @@
|
||||
"GUI / API HTTPS Certificate": "GUI / API HTTPS-Zertifikat",
|
||||
"GUI Authentication Password": "Passwort für Zugang zur Benutzeroberfläche",
|
||||
"GUI Authentication User": "Benutzername für Zugang zur Benutzeroberfläche",
|
||||
"GUI Authentication: Set User and Password": "Authentifizierung für die Benutzeroberfläche: Geben Sie Benutzer und Passwort ein.",
|
||||
"GUI Authentication: Set User and Password": "Authentifizierung für die Benutzeroberfläche: Geben Sie Benutzer und Passwort ein",
|
||||
"GUI Listen Address": "Adresse der Benutzeroberfläche",
|
||||
"GUI Override Directory": "GUI-Ersatz-Verzeichnis",
|
||||
"GUI Theme": "GUI-Design",
|
||||
@@ -210,6 +211,7 @@
|
||||
"Incoming Rate Limit (KiB/s)": "Eingehende Datenratenbegrenzung (KiB/s)",
|
||||
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Eine falsche Konfiguration kann den Ordnerinhalt beschädigen und Syncthing in einen unausführbaren Zustand versetzen.",
|
||||
"Incorrect user name or password.": "Falscher Benutzername oder Passwort.",
|
||||
"Info": "Info",
|
||||
"Internally used paths:": "Intern verwendete Pfade:",
|
||||
"Introduced By": "Verteilt von",
|
||||
"Introducer": "Verteilergerät",
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
"Custom Range": "Raon Saincheaptha",
|
||||
"Danger!": "Contúirt!",
|
||||
"Database Location": "Suíomh an Bhunachair Sonraí",
|
||||
"Debug": "Dífhabhtú",
|
||||
"Debugging Facilities": "Áiseanna Dífhabhtaithe",
|
||||
"Default": "Réamhshocrú",
|
||||
"Default Configuration": "Cumraíocht Réamhshocraithe",
|
||||
@@ -210,6 +211,7 @@
|
||||
"Incoming Rate Limit (KiB/s)": "Teorainn Ráta Isteach (KiB/s)",
|
||||
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "D'fhéadfadh cumraíocht mhícheart dochar a dhéanamh d'inneachar d'fhillteáin agus sioncronú a dhéanamh do-oibrithe.",
|
||||
"Incorrect user name or password.": "Ainm úsáideora nó pasfhocal mícheart.",
|
||||
"Info": "Eolas",
|
||||
"Internally used paths:": "Cosáin a úsáidtear go hinmheánach:",
|
||||
"Introduced By": "Tugtha isteach ag",
|
||||
"Introducer": "Réamhrá",
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
"Custom Range": "사용자 설정 기간",
|
||||
"Danger!": "위험!",
|
||||
"Database Location": "데이터베이스 위치",
|
||||
"Debug": "디버그",
|
||||
"Debugging Facilities": "디버그 기능",
|
||||
"Default": "기본값",
|
||||
"Default Configuration": "기본 설정",
|
||||
@@ -210,6 +211,7 @@
|
||||
"Incoming Rate Limit (KiB/s)": "수신 속도 제한(KiB/s)",
|
||||
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "잘못된 설정은 폴더의 내용을 훼손하거나 Syncthing을 작동하지 못하게 할 수 있습니다.",
|
||||
"Incorrect user name or password.": "사용자 또는 비밀번호가 올바르지 않습니다.",
|
||||
"Info": "정보",
|
||||
"Internally used paths:": "내부적으로 사용되는 경로:",
|
||||
"Introduced By": "소개한 기기",
|
||||
"Introducer": "소개자",
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
"Custom Range": "Aangepast bereik",
|
||||
"Danger!": "Let op!",
|
||||
"Database Location": "Locatie van database",
|
||||
"Debug": "Debuggen",
|
||||
"Debugging Facilities": "Debugmogelijkheden",
|
||||
"Default": "Standaard",
|
||||
"Default Configuration": "Standaardconfiguratie",
|
||||
@@ -210,6 +211,7 @@
|
||||
"Incoming Rate Limit (KiB/s)": "Begrenzing downloadsnelheid (KiB/s)",
|
||||
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Verkeerde configuratie kan de inhoud van je map beschadigen en Syncthing onbruikbaar maken.",
|
||||
"Incorrect user name or password.": "Onjuiste gebruikersnaam of wachtwoord.",
|
||||
"Info": "Info",
|
||||
"Internally used paths:": "Intern gebruikte paden:",
|
||||
"Introduced By": "Geïntroduceerd door",
|
||||
"Introducer": "Introductie-apparaat",
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
"Custom Range": "Niestandardowy okres",
|
||||
"Danger!": "Niebezpieczeństwo!",
|
||||
"Database Location": "Miejsce przechowywania bazy danych",
|
||||
"Debug": "Diagnozowanie błędów",
|
||||
"Debugging Facilities": "Narzędzia do debugowania",
|
||||
"Default": "Domyślnie",
|
||||
"Default Configuration": "Domyślne ustawienia",
|
||||
@@ -210,6 +211,7 @@
|
||||
"Incoming Rate Limit (KiB/s)": "Ograniczenie prędkości pobierania (KiB/s)",
|
||||
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Niepoprawne ustawienia mogą uszkodzić zawartość folderów oraz sprawić, że Syncthing przestanie działać.",
|
||||
"Incorrect user name or password.": "Nieprawidłowa nazwa użytkownika lub hasło.",
|
||||
"Info": "Informacje",
|
||||
"Internally used paths:": "Ścieżki używane wewnętrznie:",
|
||||
"Introduced By": "Wprowadzony przez",
|
||||
"Introducer": "Wprowadzający",
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
"Custom Range": "Intervalo de tempo",
|
||||
"Danger!": "Perigo!",
|
||||
"Database Location": "Localização do banco de dados",
|
||||
"Debug": "Depuração",
|
||||
"Debugging Facilities": "Facilidades de depuração",
|
||||
"Default": "Padrão",
|
||||
"Default Configuration": "Configuração Padrão",
|
||||
@@ -210,6 +211,7 @@
|
||||
"Incoming Rate Limit (KiB/s)": "Limite de velocidade de recepção (KiB/s)",
|
||||
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "A configuração incorreta poderá causar danos aos seus dados e tornar o Syncthing inoperante.",
|
||||
"Incorrect user name or password.": "Nome de usuário ou senha incorretos.",
|
||||
"Info": "Informações",
|
||||
"Internally used paths:": "Caminhos usados internamente:",
|
||||
"Introduced By": "Introduzido por",
|
||||
"Introducer": "Apresentador",
|
||||
@@ -227,6 +229,7 @@
|
||||
"Learn more": "Saiba mais",
|
||||
"Learn more at {%url%}": "Saiba mais em {{url}}",
|
||||
"Limit": "Limite",
|
||||
"Limit Bandwidth in LAN": "Limitar largura de banda na LAN",
|
||||
"Listener Failures": "Falhas de Escuta",
|
||||
"Listener Status": "Status da Escuta",
|
||||
"Listeners": "Escutadores",
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
"Custom Range": "Anpassat intervall",
|
||||
"Danger!": "Fara!",
|
||||
"Database Location": "Databasplats",
|
||||
"Debug": "Felsökning",
|
||||
"Debugging Facilities": "Felsökningsfunktioner",
|
||||
"Default": "Standard",
|
||||
"Default Configuration": "Standardkonfiguration",
|
||||
@@ -210,6 +211,7 @@
|
||||
"Incoming Rate Limit (KiB/s)": "Ingående hastighetsgräns (KiB/s)",
|
||||
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Inkorrekt konfiguration kan skada innehållet i mappen och få Syncthing att sluta fungera.",
|
||||
"Incorrect user name or password.": "Felaktigt användarnamn eller lösenord.",
|
||||
"Info": "Info",
|
||||
"Internally used paths:": "Internt använda sökvägar:",
|
||||
"Introduced By": "Introducerad av",
|
||||
"Introducer": "Introduktör",
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
"Custom Range": "Özel Aralık",
|
||||
"Danger!": "Tehlike!",
|
||||
"Database Location": "Veritabanı Konumu",
|
||||
"Debug": "Hata Ayıklama",
|
||||
"Debugging Facilities": "Hata Ayıklama Olanakları",
|
||||
"Default": "Varsayılan",
|
||||
"Default Configuration": "Varsayılan Yapılandırma",
|
||||
@@ -210,6 +211,7 @@
|
||||
"Incoming Rate Limit (KiB/s)": "Gelen Hız Sınırı (KiB/s)",
|
||||
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Yanlış yapılandırma klasör içeriklerinize zarar verebilir ve Syncthing'i çalışamaz hale getirebilir.",
|
||||
"Incorrect user name or password.": "Yanlış kullanıcı adı ya da parola.",
|
||||
"Info": "Bilgi",
|
||||
"Internally used paths:": "Dahili olarak kullanılan yollar:",
|
||||
"Introduced By": "Tanıtan",
|
||||
"Introducer": "Tanıtıcı",
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
"Custom Range": "自定义范围",
|
||||
"Danger!": "危险!",
|
||||
"Database Location": "数据库位置",
|
||||
"Debug": "调试",
|
||||
"Debugging Facilities": "调试功能",
|
||||
"Default": "默认",
|
||||
"Default Configuration": "默认配置",
|
||||
@@ -210,6 +211,7 @@
|
||||
"Incoming Rate Limit (KiB/s)": "传入速率限制(KiB/s)",
|
||||
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "不正确的配置可能会损坏您的文件夹内容,并导致 Syncthing 无法运行。",
|
||||
"Incorrect user name or password.": "用户名或密码不正确。",
|
||||
"Info": "信息",
|
||||
"Internally used paths:": "内部使用的路径:",
|
||||
"Introduced By": "介绍自",
|
||||
"Introducer": "作为中介",
|
||||
|
||||
@@ -82,6 +82,10 @@ func Open(path string, opts ...Option) (*DB, error) {
|
||||
opt(db)
|
||||
}
|
||||
|
||||
if err := db.cleanDroppedFolders(); err != nil {
|
||||
slog.Warn("Failed to clean dropped folders", slogutil.Error(err))
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
@@ -120,10 +124,9 @@ func OpenForMigration(path string) (*DB, error) {
|
||||
folderDBOpener: openFolderDBForMigration,
|
||||
}
|
||||
|
||||
// // Touch device IDs that should always exist and have a low index
|
||||
// // numbers, and will never change
|
||||
// db.localDeviceIdx, _ = db.deviceIdxLocked(protocol.LocalDeviceID)
|
||||
// db.tplInput["LocalDeviceIdx"] = db.localDeviceIdx
|
||||
if err := db.cleanDroppedFolders(); err != nil {
|
||||
slog.Warn("Failed to clean dropped folders", slogutil.Error(err))
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
@@ -8,9 +8,14 @@ package sqlite
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/syncthing/syncthing/internal/slogutil"
|
||||
)
|
||||
|
||||
func (s *DB) DropFolder(folder string) error {
|
||||
@@ -41,6 +46,37 @@ func (s *DB) ListFolders() ([]string, error) {
|
||||
return res, wrap(err)
|
||||
}
|
||||
|
||||
// cleanDroppedFolders removes old database files for folders that no longer
|
||||
// exist in the main database.
|
||||
func (s *DB) cleanDroppedFolders() error {
|
||||
// All expected folder databeses.
|
||||
var names []string
|
||||
err := s.stmt(`SELECT database_name FROM folders`).Select(&names)
|
||||
if err != nil {
|
||||
return wrap(err)
|
||||
}
|
||||
|
||||
// All folder database files on disk.
|
||||
files, err := filepath.Glob(filepath.Join(s.pathBase, "folder.*"))
|
||||
if err != nil {
|
||||
return wrap(err)
|
||||
}
|
||||
|
||||
// Any files that don't match a name in the database are removed.
|
||||
for _, file := range files {
|
||||
base := filepath.Base(file)
|
||||
inDB := slices.ContainsFunc(names, func(name string) bool { return strings.HasPrefix(base, name) })
|
||||
if !inDB {
|
||||
if err := os.Remove(file); err != nil {
|
||||
slog.Warn("Failed to remove database file for old, dropped folder", slogutil.FilePath(base))
|
||||
} else {
|
||||
slog.Info("Cleaned out database file for old, dropped folder", slogutil.FilePath(base))
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// wrap returns the error wrapped with the calling function name and
|
||||
// optional extra context strings as prefix. A nil error wraps to nil.
|
||||
func wrap(err error, context ...string) error {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
package slogutil
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strings"
|
||||
@@ -21,10 +22,20 @@ var (
|
||||
}
|
||||
slogDef = slog.New(&formattingHandler{
|
||||
recs: []*lineRecorder{GlobalRecorder, ErrorRecorder},
|
||||
out: os.Stdout,
|
||||
out: logWriter(),
|
||||
})
|
||||
)
|
||||
|
||||
func logWriter() io.Writer {
|
||||
if os.Getenv("LOGGER_DISCARD") != "" {
|
||||
// Hack to completely disable logging, for example when running
|
||||
// benchmarks.
|
||||
return io.Discard
|
||||
}
|
||||
|
||||
return os.Stdout
|
||||
}
|
||||
|
||||
func init() {
|
||||
slog.SetDefault(slogDef)
|
||||
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
package syncthing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -156,7 +158,7 @@ func OpenDatabase(path string, deleteRetention time.Duration) (db.DB, error) {
|
||||
}
|
||||
|
||||
// Attempts migration of the old (LevelDB-based) database type to the new (SQLite-based) type
|
||||
func TryMigrateDatabase(deleteRetention time.Duration) error {
|
||||
func TryMigrateDatabase(ctx context.Context, deleteRetention time.Duration, apiAddr string) error {
|
||||
oldDBDir := locations.Get(locations.LegacyDatabase)
|
||||
if _, err := os.Lstat(oldDBDir); err != nil {
|
||||
// No old database
|
||||
@@ -170,6 +172,12 @@ func TryMigrateDatabase(deleteRetention time.Duration) error {
|
||||
}
|
||||
defer be.Close()
|
||||
|
||||
// Start a temporary API server during the migration
|
||||
api := migratingAPI{addr: apiAddr}
|
||||
apiCtx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
go api.Serve(apiCtx)
|
||||
|
||||
sdb, err := sqlite.OpenForMigration(locations.Get(locations.Database))
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -197,12 +205,20 @@ func TryMigrateDatabase(deleteRetention time.Duration) error {
|
||||
var writeErr error
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
writerDone := make(chan struct{})
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
defer close(writerDone)
|
||||
var batch []protocol.FileInfo
|
||||
files, blocks := 0, 0
|
||||
t0 := time.Now()
|
||||
t1 := time.Now()
|
||||
|
||||
if writeErr = sdb.DropFolder(folder); writeErr != nil {
|
||||
slog.Error("Failed database drop", slogutil.Error(writeErr))
|
||||
return
|
||||
}
|
||||
|
||||
for fi := range fis {
|
||||
batch = append(batch, fi)
|
||||
files++
|
||||
@@ -210,6 +226,7 @@ func TryMigrateDatabase(deleteRetention time.Duration) error {
|
||||
if len(batch) == 1000 {
|
||||
writeErr = sdb.Update(folder, protocol.LocalDeviceID, batch)
|
||||
if writeErr != nil {
|
||||
slog.Error("Failed database write", slogutil.Error(writeErr))
|
||||
return
|
||||
}
|
||||
batch = batch[:0]
|
||||
@@ -244,8 +261,12 @@ func TryMigrateDatabase(deleteRetention time.Duration) error {
|
||||
// criteria in the database
|
||||
return true
|
||||
}
|
||||
fis <- fi
|
||||
return true
|
||||
select {
|
||||
case fis <- fi:
|
||||
return true
|
||||
case <-writerDone:
|
||||
return false
|
||||
}
|
||||
})
|
||||
close(fis)
|
||||
snap.Release()
|
||||
@@ -271,3 +292,27 @@ func TryMigrateDatabase(deleteRetention time.Duration) error {
|
||||
slog.Info("Migration complete", "files", totFiles, "blocks", totBlocks/1000, "duration", time.Since(t0).Truncate(time.Second))
|
||||
return nil
|
||||
}
|
||||
|
||||
type migratingAPI struct {
|
||||
addr string
|
||||
}
|
||||
|
||||
func (m migratingAPI) Serve(ctx context.Context) error {
|
||||
srv := &http.Server{
|
||||
Addr: m.addr,
|
||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.Write([]byte("*** Database migration in progress ***\n\n"))
|
||||
for _, line := range slogutil.GlobalRecorder.Since(time.Time{}) {
|
||||
line.WriteTo(w)
|
||||
}
|
||||
}),
|
||||
}
|
||||
go func() {
|
||||
slog.InfoContext(ctx, "Starting temporary GUI/API during migration", slogutil.Address(m.addr))
|
||||
err := srv.ListenAndServe()
|
||||
slog.InfoContext(ctx, "Temporary GUI/API closed", slogutil.Address(m.addr), slogutil.Error(err))
|
||||
}()
|
||||
<-ctx.Done()
|
||||
return srv.Close()
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "STDISCOSRV" "1" "Aug 11, 2025" "v2.0.0" "Syncthing"
|
||||
.TH "STDISCOSRV" "1" "Aug 14, 2025" "v2.0.0" "Syncthing"
|
||||
.SH NAME
|
||||
stdiscosrv \- Syncthing Discovery Server
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "STRELAYSRV" "1" "Aug 11, 2025" "v2.0.0" "Syncthing"
|
||||
.TH "STRELAYSRV" "1" "Aug 14, 2025" "v2.0.0" "Syncthing"
|
||||
.SH NAME
|
||||
strelaysrv \- Syncthing Relay Server
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -28,7 +28,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "SYNCTHING-BEP" "7" "Aug 11, 2025" "v2.0.0" "Syncthing"
|
||||
.TH "SYNCTHING-BEP" "7" "Aug 14, 2025" "v2.0.0" "Syncthing"
|
||||
.SH NAME
|
||||
syncthing-bep \- Block Exchange Protocol v1
|
||||
.SH INTRODUCTION AND DEFINITIONS
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "SYNCTHING-CONFIG" "5" "Aug 11, 2025" "v2.0.0" "Syncthing"
|
||||
.TH "SYNCTHING-CONFIG" "5" "Aug 14, 2025" "v2.0.0" "Syncthing"
|
||||
.SH NAME
|
||||
syncthing-config \- Syncthing Configuration
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "SYNCTHING-DEVICE-IDS" "7" "Aug 11, 2025" "v2.0.0" "Syncthing"
|
||||
.TH "SYNCTHING-DEVICE-IDS" "7" "Aug 14, 2025" "v2.0.0" "Syncthing"
|
||||
.SH NAME
|
||||
syncthing-device-ids \- Understanding Device IDs
|
||||
.sp
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "SYNCTHING-EVENT-API" "7" "Aug 11, 2025" "v2.0.0" "Syncthing"
|
||||
.TH "SYNCTHING-EVENT-API" "7" "Aug 14, 2025" "v2.0.0" "Syncthing"
|
||||
.SH NAME
|
||||
syncthing-event-api \- Event API
|
||||
.SH DESCRIPTION
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "SYNCTHING-FAQ" "7" "Aug 11, 2025" "v2.0.0" "Syncthing"
|
||||
.TH "SYNCTHING-FAQ" "7" "Aug 14, 2025" "v2.0.0" "Syncthing"
|
||||
.SH NAME
|
||||
syncthing-faq \- Frequently Asked Questions
|
||||
.INDENT 0.0
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "SYNCTHING-GLOBALDISCO" "7" "Aug 11, 2025" "v2.0.0" "Syncthing"
|
||||
.TH "SYNCTHING-GLOBALDISCO" "7" "Aug 14, 2025" "v2.0.0" "Syncthing"
|
||||
.SH NAME
|
||||
syncthing-globaldisco \- Global Discovery Protocol v3
|
||||
.SH ANNOUNCEMENTS
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "SYNCTHING-LOCALDISCO" "7" "Aug 11, 2025" "v2.0.0" "Syncthing"
|
||||
.TH "SYNCTHING-LOCALDISCO" "7" "Aug 14, 2025" "v2.0.0" "Syncthing"
|
||||
.SH NAME
|
||||
syncthing-localdisco \- Local Discovery Protocol v4
|
||||
.SH MODE OF OPERATION
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "SYNCTHING-NETWORKING" "7" "Aug 11, 2025" "v2.0.0" "Syncthing"
|
||||
.TH "SYNCTHING-NETWORKING" "7" "Aug 14, 2025" "v2.0.0" "Syncthing"
|
||||
.SH NAME
|
||||
syncthing-networking \- Firewall Setup
|
||||
.SH ROUTER SETUP
|
||||
|
||||
@@ -28,7 +28,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "SYNCTHING-RELAY" "7" "Aug 11, 2025" "v2.0.0" "Syncthing"
|
||||
.TH "SYNCTHING-RELAY" "7" "Aug 14, 2025" "v2.0.0" "Syncthing"
|
||||
.SH NAME
|
||||
syncthing-relay \- Relay Protocol v1
|
||||
.SH WHAT IS A RELAY?
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "SYNCTHING-REST-API" "7" "Aug 11, 2025" "v2.0.0" "Syncthing"
|
||||
.TH "SYNCTHING-REST-API" "7" "Aug 14, 2025" "v2.0.0" "Syncthing"
|
||||
.SH NAME
|
||||
syncthing-rest-api \- REST API
|
||||
.sp
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "SYNCTHING-SECURITY" "7" "Aug 11, 2025" "v2.0.0" "Syncthing"
|
||||
.TH "SYNCTHING-SECURITY" "7" "Aug 14, 2025" "v2.0.0" "Syncthing"
|
||||
.SH NAME
|
||||
syncthing-security \- Security Principles
|
||||
.sp
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "SYNCTHING-STIGNORE" "5" "Aug 11, 2025" "v2.0.0" "Syncthing"
|
||||
.TH "SYNCTHING-STIGNORE" "5" "Aug 14, 2025" "v2.0.0" "Syncthing"
|
||||
.SH NAME
|
||||
syncthing-stignore \- Prevent files from being synchronized to other nodes
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "SYNCTHING-VERSIONING" "7" "Aug 11, 2025" "v2.0.0" "Syncthing"
|
||||
.TH "SYNCTHING-VERSIONING" "7" "Aug 14, 2025" "v2.0.0" "Syncthing"
|
||||
.SH NAME
|
||||
syncthing-versioning \- Keep automatic backups of deleted files by other nodes
|
||||
.sp
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "SYNCTHING" "1" "Aug 11, 2025" "v2.0.0" "Syncthing"
|
||||
.TH "SYNCTHING" "1" "Aug 14, 2025" "v2.0.0" "Syncthing"
|
||||
.SH NAME
|
||||
syncthing \- Syncthing
|
||||
.SH SYNOPSIS
|
||||
|
||||
Reference in New Issue
Block a user