Compare commits

..
17 Commits
Author SHA1 Message Date
Syncthing .stignore Fork b5825e49cb apply stignore synchronization patch 2026-09-07 03:52:21 +00:00
Syncthing Release Automation ed8d87f251 chore(gui, man, authors): update docs, translations, and contributors 2026-09-07 03:52:21 +00:00
Jakob Borg 9af3c75f37 chore: set User-Agent on all outgoing HTTP requests (#10867)
It's only polite, and it enables better troubleshooting in situations
like weird-ass requests to the upgrades download service.

---------

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2026-08-24 18:26:23 +00:00
Syncthing Release Automation e009ec07ff chore(gui, man, authors): update docs, translations, and contributors 2026-08-24 04:29:39 +00:00
Jakob Borg 38ac58c82e build(deps): update dependencies (#10865)
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2026-08-20 11:09:34 +02:00
Jakob Borg 82f3e86424 build: use Go 1.27, minimum version is Go 1.26 (#10864)
### Purpose

🎉

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2026-08-19 20:23:21 +02:00
Jakob Borg 305162e0af Merge branch 'infrastructure'
* infrastructure:
  fix(stdiscosrv): slightly increase reannounce times and smoothing
  fix(stdiscosrv): 500 errors should be accompanied by log entry
  fix(ursrv): data problems are the clients fault
  build: sign docker images
2026-08-18 11:32:52 +02:00
Jakob Borg a907594914 fix(stdiscosrv): slightly increase reannounce times and smoothing
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2026-08-18 11:30:52 +02:00
Jakob Borg db2b02c44d fix(stdiscosrv): 500 errors should be accompanied by log entry
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2026-08-18 11:30:52 +02:00
Jakob Borg 34b3603052 fix(ursrv): data problems are the clients fault
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2026-08-18 11:30:52 +02:00
Jakob Borg bb9dac4f75 build: sign docker images
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2026-08-18 11:28:52 +02:00
Syncthing Release Automation 0fc519fac7 chore(gui, man, authors): update docs, translations, and contributors 2026-08-17 04:01:37 +00:00
Jakob Borg 058bcd7334 fix: open GUI when relaunched instead of printing error (fixes #10727) (#10852)
This is primarily to improve the experience in environments that start
Syncthing from a graphical environment, e.g., Windows.

When already running, instead of printing an error we open the GUI. If
the GUI is not available (but the lockfile indicates we are running),
print an error and exit.

If --no-browser is given or STNOBROWSER is set, act like before.

Closes #10736. Marking as `fix` because this does not deserve to trigger
a minor release on its own.

---------

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2026-08-11 11:17:09 +00:00
Syncthing Release Automation 42ea7231c5 chore(gui, man, authors): update docs, translations, and contributors 2026-08-10 04:17:57 +00:00
Jakob Borg 328d910aee fix(api): correctly return metrics, support bundle (fixes #10847) (#10849)
Our faked request wasn't good enough; improve it, adding a test.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2026-08-05 18:35:17 +00:00
Jakob Borg d7df27a367 fix(model): correctly handle receive-only changed directories (fixes #8004) (#10843)
When adding a folder in receive-only mode where the contents were
already identical to a remote device, directories would remain as
locally changed when everything else had consolidated. The reason this
happened is that we only did the matching between locally changed files
and their global equivalent for changed items, but directories are
typically not "changed" much as we don't track their mtime, so they
wouldn't pass through this stage when scanning.

Now, instead, do the check when we're anyway walking all the files in
phase two of scanning. This catches all cases of identical items, files
or directories, regardless of how they came to be in the index.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2026-08-05 20:23:53 +02:00
Jakob Borg 8ea09c0094 chore: style fixes from go fix (#10846)
Just `go fix ./...`

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2026-08-05 20:23:22 +02:00
197 changed files with 1901 additions and 544 deletions
+142
View File
@@ -0,0 +1,142 @@
name: custom release
permissions:
contents: write
releases: write
on:
push:
branches:
- main
paths:
- ".gitea/workflows/custom-release.yml"
- "patches/**"
- "scripts/update-custom-release.sh"
- "scripts/sync-upstream.sh"
workflow_dispatch:
inputs:
upstream_tag:
description: "Optional upstream Syncthing tag, for example v2.1.0"
required: false
suffix:
description: "Optional custom release suffix, for example stignore.7"
required: false
schedule:
- cron: "17 04 * * *"
jobs:
build-custom-release:
runs-on: ffmini_macos_arm64
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: false
- name: Configure Git author
run: |
git config user.name "Gitea Actions"
git config user.email "actions@git.felixfoertsch.de"
- name: Mirror upstream and rebuild patched main
run: ./scripts/sync-upstream.sh
env:
SYNC_REMOTE: origin
- name: Set up tea
run: |
go install code.gitea.io/tea@v0.14.1
echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH"
"$(go env GOPATH)/bin/tea" logins delete actions >/dev/null 2>&1 || true
"$(go env GOPATH)/bin/tea" logins add --name actions --url https://git.felixfoertsch.de --token "$GITEA_TOKEN" --no-version-check
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
- name: Import Developer ID certificate
run: |
set -euo pipefail
keychain_dir="$HOME/Library/Keychains"
mkdir -p "$keychain_dir"
keychain_path="$keychain_dir/syncthing-release-signing-${GITHUB_RUN_ID:-$$}.keychain-db"
keychain_password="$(openssl rand -hex 24)"
certificate_path="$RUNNER_TEMP/developer-id-application.p12"
previous_default_keychain="$(security default-keychain -d user 2>/dev/null | sed 's/[ "]//g' || true)"
echo "CUSTOM_RELEASE_KEYCHAIN_PATH=$keychain_path" >> "$GITHUB_ENV"
echo "CUSTOM_RELEASE_KEYCHAIN_PASSWORD=$keychain_password" >> "$GITHUB_ENV"
echo "CUSTOM_RELEASE_PREVIOUS_DEFAULT_KEYCHAIN=$previous_default_keychain" >> "$GITHUB_ENV"
if [ -z "$DEVELOPER_ID_APPLICATION_P12_BASE64" ]; then
echo "DEVELOPER_ID_APPLICATION_P12_BASE64 secret is required" >&2
exit 1
fi
printf '%s' "$DEVELOPER_ID_APPLICATION_P12_BASE64" | base64 -D > "$certificate_path"
rm -f "$keychain_path"
security create-keychain -p "$keychain_password" "$keychain_path"
security set-keychain-settings -lut 21600 "$keychain_path"
security unlock-keychain -p "$keychain_password" "$keychain_path"
security import "$certificate_path" -k "$keychain_path" -P "$DEVELOPER_ID_APPLICATION_P12_PASSWORD" -A -T /usr/bin/codesign -T /usr/bin/security
existing_keychains=()
while IFS= read -r existing_keychain; do
existing_keychain="$(printf '%s' "$existing_keychain" | sed 's/[ "]//g')"
if [ -n "$existing_keychain" ] && [ -e "$existing_keychain" ] && [[ "$existing_keychain" != *"/syncthing-release-signing-"*".keychain-db" ]]; then
existing_keychains+=("$existing_keychain")
fi
done < <(security list-keychains)
security list-keychains -s "$keychain_path" "${existing_keychains[@]}"
security list-keychains -d user -s "$keychain_path" "${existing_keychains[@]}" || true
security default-keychain -d user -s "$keychain_path" || true
security list-keychains
security list-keychains -d user || true
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$keychain_password" "$keychain_path"
identity_output="$(security find-identity -v -p codesigning "$keychain_path")"
printf '%s\n' "$identity_output"
security find-identity -v -p codesigning
codesign_identity_sha1="$(printf '%s\n' "$identity_output" | awk '/"Developer ID Application:/ { print $2; exit }')"
codesign_identity="$(printf '%s\n' "$identity_output" | sed -n 's/.*"\(Developer ID Application:[^"]*\)".*/\1/p' | head -n 1)"
if [ -z "$codesign_identity" ]; then
echo "Developer ID Application signing identity is required in DEVELOPER_ID_APPLICATION_P12_BASE64" >&2
exit 1
fi
probe_binary="$RUNNER_TEMP/codesign-probe"
cp /usr/bin/true "$probe_binary"
codesign --force --dryrun --sign "$codesign_identity" --keychain "$keychain_path" --options runtime --timestamp "$probe_binary"
echo "CUSTOM_RELEASE_CODESIGN_IDENTITY=$codesign_identity" >> "$GITHUB_ENV"
echo "CUSTOM_RELEASE_CODESIGN_IDENTITY_SHA1=$codesign_identity_sha1" >> "$GITHUB_ENV"
env:
DEVELOPER_ID_APPLICATION_P12_BASE64: ${{ secrets.DEVELOPER_ID_APPLICATION_P12_BASE64 }}
DEVELOPER_ID_APPLICATION_P12_PASSWORD: ${{ secrets.DEVELOPER_ID_APPLICATION_P12_PASSWORD }}
- name: Build patched Syncthing release
run: ./scripts/update-custom-release.sh
env:
CUSTOM_RELEASE_UPSTREAM_TAG: ${{ github.event.inputs.upstream_tag }}
CUSTOM_RELEASE_SUFFIX: ${{ github.event.inputs.suffix }}
CUSTOM_RELEASE_PUSH: "1"
CUSTOM_RELEASE_PUSH_BRANCH: "0"
CUSTOM_RELEASE_REMOTE: origin
CUSTOM_RELEASE_BUILDS: "darwin/arm64/zip/1 linux/amd64/tar/0 linux/arm64/tar/0"
CUSTOM_RELEASE_CODESIGN_TEAM_ID: "NG5W75WE8U"
CUSTOM_RELEASE_SIGN_DARWIN: "1"
CUSTOM_RELEASE_REQUIRE_GATEKEEPER_ASSESSMENT: "0"
CUSTOM_RELEASE_CREATE_GITEA_RELEASE: "1"
CUSTOM_RELEASE_TEA_REPO: felixfoertsch/syncthing
- name: Delete temporary keychain
if: always()
run: |
if [ -n "${CUSTOM_RELEASE_PREVIOUS_DEFAULT_KEYCHAIN:-}" ] && [ -e "$CUSTOM_RELEASE_PREVIOUS_DEFAULT_KEYCHAIN" ]; then
security default-keychain -d user -s "$CUSTOM_RELEASE_PREVIOUS_DEFAULT_KEYCHAIN" || true
fi
if [ -n "${CUSTOM_RELEASE_KEYCHAIN_PATH:-}" ]; then
security delete-keychain "$CUSTOM_RELEASE_KEYCHAIN_PATH" || true
fi
+13 -3
View File
@@ -7,7 +7,7 @@ on:
- infra-*
env:
GO_VERSION: "~1.26.0"
GO_VERSION: "~1.27.0"
CGO_ENABLED: "0"
BUILD_USER: docker
BUILD_HOST: github.syncthing.net
@@ -15,6 +15,7 @@ env:
permissions:
contents: read
packages: write
id-token: write
jobs:
docker-syncthing:
@@ -30,11 +31,11 @@ jobs:
- stupgrades
- ursrv
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # was: actions/checkout@v5
with:
fetch-depth: 0
- uses: actions/setup-go@v6
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # was: actions/setup-go@v6
with:
go-version: ${{ env.GO_VERSION }}
check-latest: true
@@ -77,6 +78,7 @@ jobs:
echo "TAGS=$tags" >> $GITHUB_ENV
- name: Build and push
id: build
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5
with:
context: .
@@ -86,3 +88,11 @@ jobs:
tags: ${{ env.TAGS }}
labels: |
org.opencontainers.image.revision=${{ github.sha }}
- name: Install Cosign
if: github.ref == 'refs/heads/infrastructure'
uses: sigstore/cosign-installer@ba7bc0a3fef59531c69a25acd34668d6d3fe6f22 # v4.1.0
- name: Sign image
if: github.ref == 'refs/heads/infrastructure'
run: cosign sign --yes --recursive ghcr.io/syncthing/infra/${{ matrix.pkg }}:latest@${{ steps.build.outputs.digest }}
+20 -2
View File
@@ -18,7 +18,7 @@ env:
# The go version to use for builds. We set check-latest to true when
# installing, so we get the latest patch version that matches the
# expression.
GO_VERSION: "~1.26.0"
GO_VERSION: "~1.27.0"
# Optimize compatibility on the slow architectures.
GOMIPS: softfloat
@@ -108,7 +108,7 @@ jobs:
runner: ["windows-latest", "ubuntu-latest", "macos-latest"]
# The oldest version in this list should match what we have in our go.mod.
# Variables don't seem to be supported here, or we could have done something nice.
go: ["~1.25.0", "~1.26.0"]
go: ["~1.26.0", "~1.27.0"]
runs-on: ${{ matrix.runner }}
steps:
- name: Set git to use LF
@@ -1012,6 +1012,7 @@ jobs:
permissions:
contents: read
packages: write
id-token: write
needs:
- facts
env:
@@ -1115,6 +1116,7 @@ jobs:
mv bin/* script ctx
- name: Build and push Docker image
id: build
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
with:
context: ctx
@@ -1126,6 +1128,22 @@ jobs:
org.opencontainers.image.version=${{ env.VERSION }}
org.opencontainers.image.revision=${{ github.sha }}
- name: Install Cosign
if: github.event_name == 'push'
uses: sigstore/cosign-installer@ba7bc0a3fef59531c69a25acd34668d6d3fe6f22 # v4.1.0
- name: Sign image
if: github.event_name == 'push'
env:
DIGEST: ${{ steps.build.outputs.digest }}
run: |
IFS="," read -ra tags <<< $DOCKER_TAGS
images=""
for tag in ${tags[@]}; do
images+="${tag}@${DIGEST} "
done
cosign sign --yes --recursive ${images}
#
# Sync images to Docker hub. This takes the images already pushed to GHCR
# and copies them to Docker hub. Runs for releases only.
+150
View File
@@ -0,0 +1,150 @@
name: custom release
permissions:
contents: write
on:
push:
branches:
- main
paths:
- ".github/workflows/custom-release.yml"
- "patches/**"
- "scripts/update-custom-release.sh"
- "scripts/sync-upstream.sh"
workflow_dispatch:
inputs:
upstream_tag:
description: "Optional upstream Syncthing tag, for example v2.1.3"
required: false
suffix:
description: "Optional custom release suffix, for example stignore.7"
required: false
schedule:
- cron: "17 04 * * *"
jobs:
build-custom-release:
runs-on: macos-14
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: false
- name: Configure Git author
run: |
git config user.name "GitHub Actions"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Mirror upstream and rebuild patched main
run: ./scripts/sync-upstream.sh
env:
SYNC_REMOTE: origin
- name: Import Developer ID certificate
run: |
set -euo pipefail
keychain_path="$RUNNER_TEMP/syncthing-release-signing.keychain-db"
keychain_password="$(openssl rand -hex 24)"
certificate_path="$RUNNER_TEMP/developer-id-application.p12"
previous_default_keychain="$(security default-keychain -d user 2>/dev/null | sed 's/[ "]//g' || true)"
echo "::add-mask::$keychain_password"
echo "CUSTOM_RELEASE_KEYCHAIN_PATH=$keychain_path" >> "$GITHUB_ENV"
echo "CUSTOM_RELEASE_KEYCHAIN_PASSWORD=$keychain_password" >> "$GITHUB_ENV"
echo "CUSTOM_RELEASE_CERTIFICATE_PATH=$certificate_path" >> "$GITHUB_ENV"
echo "CUSTOM_RELEASE_PREVIOUS_DEFAULT_KEYCHAIN=$previous_default_keychain" >> "$GITHUB_ENV"
if [ -z "$DEVELOPER_ID_APPLICATION_P12_BASE64" ]; then
echo "DEVELOPER_ID_APPLICATION_P12_BASE64 secret is required" >&2
exit 1
fi
if [ -z "$DEVELOPER_ID_APPLICATION_P12_PASSWORD" ]; then
echo "DEVELOPER_ID_APPLICATION_P12_PASSWORD secret is required" >&2
exit 1
fi
printf '%s' "$DEVELOPER_ID_APPLICATION_P12_BASE64" | base64 -D > "$certificate_path"
security create-keychain -p "$keychain_password" "$keychain_path"
security set-keychain-settings -lut 21600 "$keychain_path"
security unlock-keychain -p "$keychain_password" "$keychain_path"
security import "$certificate_path" -k "$keychain_path" -P "$DEVELOPER_ID_APPLICATION_P12_PASSWORD" -A -T /usr/bin/codesign -T /usr/bin/security
security list-keychains -d user -s "$keychain_path"
security default-keychain -d user -s "$keychain_path"
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$keychain_password" "$keychain_path"
identity_output="$(security find-identity -v -p codesigning "$keychain_path")"
printf '%s\n' "$identity_output"
codesign_identity="$(printf '%s\n' "$identity_output" | sed -n 's/.*"\(Developer ID Application:[^"]*\)".*/\1/p' | head -n 1)"
if [ -z "$codesign_identity" ]; then
echo "Developer ID Application signing identity is required in DEVELOPER_ID_APPLICATION_P12_BASE64" >&2
exit 1
fi
probe_binary="$RUNNER_TEMP/codesign-probe"
cp /usr/bin/true "$probe_binary"
codesign --force --dryrun --sign "$codesign_identity" --keychain "$keychain_path" --options runtime --timestamp "$probe_binary"
echo "CUSTOM_RELEASE_CODESIGN_IDENTITY=$codesign_identity" >> "$GITHUB_ENV"
env:
DEVELOPER_ID_APPLICATION_P12_BASE64: ${{ secrets.DEVELOPER_ID_APPLICATION_P12_BASE64 }}
DEVELOPER_ID_APPLICATION_P12_PASSWORD: ${{ secrets.DEVELOPER_ID_APPLICATION_P12_PASSWORD }}
- name: Build patched Syncthing release
run: |
case "$(uname -m)" in
arm64) darwin_arch=arm64 ;;
x86_64) darwin_arch=amd64 ;;
*) echo "Unsupported macOS runner architecture: $(uname -m)" >&2; exit 1 ;;
esac
export CUSTOM_RELEASE_BUILDS="darwin/$darwin_arch/zip/1 linux/amd64/tar/0 linux/arm64/tar/0"
./scripts/update-custom-release.sh
env:
CUSTOM_RELEASE_UPSTREAM_TAG: ${{ github.event.inputs.upstream_tag }}
CUSTOM_RELEASE_SUFFIX: ${{ github.event.inputs.suffix }}
CUSTOM_RELEASE_PUSH: "1"
CUSTOM_RELEASE_PUSH_BRANCH: "0"
CUSTOM_RELEASE_REMOTE: origin
CUSTOM_RELEASE_CODESIGN_TEAM_ID: "NG5W75WE8U"
CUSTOM_RELEASE_SIGN_DARWIN: "1"
CUSTOM_RELEASE_REQUIRE_GATEKEEPER_ASSESSMENT: "0"
CUSTOM_RELEASE_CREATE_GITEA_RELEASE: "0"
GH_TOKEN: ${{ github.token }}
- name: Publish GitHub release
run: |
tag="${CUSTOM_RELEASE_UPSTREAM_TAG:-$(git ls-remote --refs --tags --sort='version:refname' https://github.com/syncthing/syncthing.git 'v[0-9]*' | awk '{ tag = $2; sub("refs/tags/", "", tag); if (tag ~ /^v[0-9]+\.[0-9]+\.[0-9]+$/) latest = tag } END { print latest }')}-$CUSTOM_RELEASE_SUFFIX"
if gh release view "$tag" >/dev/null 2>&1; then
echo "GitHub release $tag already exists; nothing to do."
exit 0
fi
assets=()
for asset in dist/*; do
[ -f "$asset" ] || continue
[ "$(basename "$asset")" = release-notes.md ] && continue
assets+=("$asset")
done
gh release create "$tag" "${assets[@]}" --title "$tag" --notes-file dist/release-notes.md --verify-tag
env:
CUSTOM_RELEASE_UPSTREAM_TAG: ${{ github.event.inputs.upstream_tag }}
CUSTOM_RELEASE_SUFFIX: ${{ github.event.inputs.suffix || 'stignore.7' }}
GH_TOKEN: ${{ github.token }}
- name: Delete temporary keychain
if: always()
run: |
if [ -n "${CUSTOM_RELEASE_PREVIOUS_DEFAULT_KEYCHAIN:-}" ] && [ -e "$CUSTOM_RELEASE_PREVIOUS_DEFAULT_KEYCHAIN" ]; then
security default-keychain -d user -s "$CUSTOM_RELEASE_PREVIOUS_DEFAULT_KEYCHAIN" || true
fi
if [ -n "${CUSTOM_RELEASE_KEYCHAIN_PATH:-}" ]; then
security delete-keychain "$CUSTOM_RELEASE_KEYCHAIN_PATH" || true
fi
if [ -n "${CUSTOM_RELEASE_CERTIFICATE_PATH:-}" ]; then
rm -f "$CUSTOM_RELEASE_CERTIFICATE_PATH"
fi
+8
View File
@@ -1,3 +1,11 @@
# Syncthing with `.stignore` synchronization
This fork synchronizes the root-level `.stignore` file as regular folder
content, while keeping `.stfolder` and `.stversions` protected as Syncthing
internals. The `upstream` branch mirrors the official Syncthing `main` branch;
this fork's `main` branch and releases apply the `.stignore` synchronization
patch.
[![Syncthing][14]][15]
---
+4 -4
View File
@@ -17,10 +17,10 @@ import (
)
type event struct {
ID int `json:"id"`
Type string `json:"type"`
Time time.Time `json:"time"`
Data map[string]interface{} `json:"data"`
ID int `json:"id"`
Type string `json:"type"`
Time time.Time `json:"time"`
Data map[string]any `json:"data"`
}
func main() {
-1
View File
@@ -60,7 +60,6 @@ func checkServers(deviceID protocol.DeviceID, servers ...string) {
t0 := time.Now()
resc := make(chan checkResult)
for _, srv := range servers {
srv := srv
go func() {
res := checkServer(deviceID, srv)
res.server = srv
+2 -5
View File
@@ -34,7 +34,7 @@ func generateFiles(dir string, files, maxexp int, srcname string) error {
return err
}
for i := 0; i < files; i++ {
for range files {
n := randomName()
if rand.Float64() < 0.05 {
@@ -51,10 +51,7 @@ func generateFiles(dir string, files, maxexp int, srcname string) error {
p1 := filepath.Join(p0, n)
s := int64(1 << uint(rand.Intn(maxexp)))
a := int64(128 * 1024)
if a > s {
a = s
}
a := min(int64(128*1024), s)
s += rand.Int63n(a)
if err := generateOneFile(fd, p1, s); err != nil {
+2 -2
View File
@@ -138,7 +138,7 @@ func printProgress(prefix string, count *atomic.Int64) {
}
}
func saveCert(priv interface{}, derBytes []byte) {
func saveCert(priv any, derBytes []byte) {
certOut, err := os.Create("cert.pem")
if err != nil {
fmt.Println(err)
@@ -179,7 +179,7 @@ func saveCert(priv interface{}, derBytes []byte) {
}
}
func pemBlockForKey(priv interface{}) (*pem.Block, error) {
func pemBlockForKey(priv any) (*pem.Block, error) {
switch k := priv.(type) {
case *rsa.PrivateKey:
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}, nil
+1 -1
View File
@@ -203,7 +203,7 @@ func loadIgnorePatterns(path string) (*ignorePatterns, error) {
}
var patterns []*regexp.Regexp
for _, line := range strings.Split(string(bs), "\n") {
for line := range strings.SplitSeq(string(bs), "\n") {
line = strings.TrimSpace(line)
if line == "" {
continue
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build noassets
// +build noassets
package auto
+1 -1
View File
@@ -587,7 +587,7 @@ func loadRelays(file string, geoip *geoip.Provider) []*relay {
}
var relays []*relay
for _, line := range strings.Split(string(content), "\n") {
for line := range strings.SplitSeq(string(content), "\n") {
if line == "" {
continue
}
+1 -1
View File
@@ -17,7 +17,7 @@ import (
)
func init() {
for i := 0; i < 10; i++ {
for i := range 10 {
u := fmt.Sprintf("permanent%d", i)
permanentRelays = append(permanentRelays, &relay{URL: u})
}
+2 -2
View File
@@ -188,7 +188,7 @@ func (p *proxy) ServeHTTP(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(resp.StatusCode)
if strings.HasPrefix(ct, "application/json") {
// Special JSON handling; clean it up a bit.
var v interface{}
var v any
if err := json.NewDecoder(resp.Body).Decode(&v); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
@@ -224,7 +224,7 @@ func filterForLatest(rels []upgrade.Release) []upgrade.Release {
return filtered
}
var userAgentOSArchExp = regexp.MustCompile(`^syncthing.*\(.+ (\w+)-(\w+)\)$`)
var userAgentOSArchExp = regexp.MustCompile(`^[Ss]yncthing.*\(.+ (\w+)-(\w+)\)$`)
func filterForCompatibility(rels []upgrade.Release, ua, osv string) []upgrade.Release {
osArch := userAgentOSArchExp.FindStringSubmatch(ua)
+2 -2
View File
@@ -311,7 +311,7 @@ func (s *server) handleNewData(w http.ResponseWriter, r *http.Request) {
bs, _ := io.ReadAll(lr)
if err := json.Unmarshal(bs, &rep); err != nil {
log.Error("Failed to decode JSON", slogutil.Error(err))
http.Error(w, "JSON Decode Error", http.StatusInternalServerError)
http.Error(w, "JSON Decode Error", http.StatusBadRequest)
return
}
@@ -321,7 +321,7 @@ func (s *server) handleNewData(w http.ResponseWriter, r *http.Request) {
if err := rep.Validate(); err != nil {
log.Error("Failed to validate report", slogutil.Error(err))
http.Error(w, "Validation Error", http.StatusInternalServerError)
http.Error(w, "Validation Error", http.StatusBadRequest)
return
}
+3 -5
View File
@@ -206,6 +206,7 @@ func (s *apiSrv) handleGET(w http.ResponseWriter, req *http.Request) {
rec, err := s.db.get(&deviceID)
if err != nil {
// some sort of internal error
slog.Warn("Failed to handle GET request", "id", reqID, "error", err)
lookupRequestsTotal.WithLabelValues("internal_error").Inc()
w.Header().Set("Retry-After", errorRetryAfterString())
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
@@ -284,7 +285,7 @@ func (s *apiSrv) handlePOST(remoteAddr *net.TCPAddr, w http.ResponseWriter, req
}
if err := s.handleAnnounce(deviceID, addresses); err != nil {
slog.Debug("Failed to handle request", "id", reqID, "error", err)
slog.Warn("Failed to handle POST request", "id", reqID, "error", err)
announceRequestsTotal.WithLabelValues("internal_error").Inc()
w.Header().Set("Retry-After", errorRetryAfterString())
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
@@ -402,10 +403,7 @@ func (s *apiSrv) certificateBytes(req *http.Request) ([]byte, error) {
b.WriteByte('\n')
for i := 0; i < len(cert); i += 64 {
end := i + 64
if end > len(cert) {
end = len(cert)
}
end := min(i+64, len(cert))
b.WriteString(cert[i:end])
b.WriteByte('\n')
}
+3 -8
View File
@@ -7,7 +7,6 @@
package main
import (
"context"
"crypto/tls"
"fmt"
"io"
@@ -120,7 +119,7 @@ func TestRetryAfterSHistogram(t *testing.T) {
numBuckets := (notFoundRetryUnknownMaxSeconds + bucketSize - 1) / bucketSize
buckets := make([]int, numBuckets)
for i := 0; i < n; i++ {
for range n {
v := tracker.retryAfterS()
if v < notFoundRetryUnknownMinSeconds || v > notFoundRetryUnknownMaxSeconds {
t.Fatalf("retryAfterS() = %d, out of range [%d, %d]", v, notFoundRetryUnknownMinSeconds, notFoundRetryUnknownMaxSeconds)
@@ -142,10 +141,7 @@ func TestRetryAfterSHistogram(t *testing.T) {
barWidth := 60
for i, c := range buckets {
lo := i*bucketSize + 1
hi := (i + 1) * bucketSize
if hi > notFoundRetryUnknownMaxSeconds {
hi = notFoundRetryUnknownMaxSeconds
}
hi := min((i+1)*bucketSize, notFoundRetryUnknownMaxSeconds)
bar := ""
if maxCount > 0 {
bar = strings.Repeat("#", c*barWidth/maxCount)
@@ -156,8 +152,7 @@ func TestRetryAfterSHistogram(t *testing.T) {
func BenchmarkAPIRequests(b *testing.B) {
db := newInMemoryStore(b.TempDir(), 0, nil)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ctx := b.Context()
go db.Serve(ctx)
api := newAPISrv("127.0.0.1:0", tls.Certificate{}, db, nil, true, true, 1000, 1000)
srv := httptest.NewServer(http.HandlerFunc(api.handler))
+4 -4
View File
@@ -35,10 +35,10 @@ const (
// Reannounce-After is set to reannounceAfterSeconds +
// random(reannounzeFuzzSeconds), similar for Retry-After
reannounceAfterSeconds = 3300
reannounzeFuzzSeconds = 300
errorRetryAfterSeconds = 1500
errorRetryFuzzSeconds = 300
reannounceAfterSeconds = 2400
reannounzeFuzzSeconds = 1800
errorRetryAfterSeconds = 1800
errorRetryFuzzSeconds = 900
// Retry for not found is notFoundRetrySeenSeconds for records we have
// seen an announcement for (but it's not active right now) and
+4 -4
View File
@@ -18,7 +18,7 @@ import (
var (
outboxesMut = sync.RWMutex{}
outboxes = make(map[syncthingprotocol.DeviceID]chan interface{})
outboxes = make(map[syncthingprotocol.DeviceID]chan any)
numConnections atomic.Int64
)
@@ -97,9 +97,9 @@ func protocolConnectionHandler(tcpConn net.Conn, config *tls.Config, token strin
id := syncthingprotocol.NewDeviceID(certs[0].Raw)
messages := make(chan interface{})
messages := make(chan any)
errors := make(chan error, 1)
outbox := make(chan interface{})
outbox := make(chan any)
// Read messages from the connection and send them on the messages
// channel. When there is an error, send it on the error channel and
@@ -364,7 +364,7 @@ func sessionConnectionHandler(conn net.Conn) {
}
}
func messageReader(conn net.Conn, messages chan<- interface{}, errors chan<- error) {
func messageReader(conn net.Conn, messages chan<- any, errors chan<- error) {
numConnections.Add(1)
defer numConnections.Add(-1)
+1 -4
View File
@@ -330,10 +330,7 @@ func take(tokens int, ls ...*rate.Limiter) {
for tokens > 0 {
// chunk is how many tokens we can consume at a time
chunk := tokens
if chunk > minBurst {
chunk = minBurst
}
chunk := min(tokens, minBurst)
// maxDelay is the longest delay mandated by any of the limiters for
// the chosen chunk size.
+2 -2
View File
@@ -38,7 +38,7 @@ func statusService(addr string) {
func getStatus(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
status := make(map[string]interface{})
status := make(map[string]any)
sessionMut.Lock()
// This can potentially be double the number of pending sessions, as each session has two keys, one for each side.
@@ -67,7 +67,7 @@ func getStatus(w http.ResponseWriter, _ *http.Request) {
rc.rate(30*60/10) * 8 / 1000,
rc.rate(60*60/10) * 8 / 1000,
}
status["options"] = map[string]interface{}{
status["options"] = map[string]any{
"network-timeout": networkTimeout / time.Second,
"ping-interval": pingInterval / time.Second,
"message-timeout": messageTimeout / time.Second,
+5 -3
View File
@@ -18,6 +18,7 @@ import (
"net/http"
"strings"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/locations"
@@ -27,7 +28,7 @@ import (
type APIClient interface {
Get(url string) (*http.Response, error)
Post(url, body string) (*http.Response, error)
PutJSON(url string, o interface{}) (*http.Response, error)
PutJSON(url string, o any) (*http.Response, error)
}
type apiClient struct {
@@ -115,6 +116,7 @@ func (c *apiClient) Endpoint() string {
func (c *apiClient) Do(req *http.Request) (*http.Response, error) {
req.Header.Set("X-Api-Key", c.apikey)
req.Header.Set("User-Agent", build.UserAgent())
resp, err := c.Client.Do(req)
if err != nil {
return nil, err
@@ -134,7 +136,7 @@ func (c *apiClient) RequestString(url, method, data string) (*http.Response, err
return c.Request(url, method, bytes.NewBufferString(data))
}
func (c *apiClient) RequestJSON(url, method string, o interface{}) (*http.Response, error) {
func (c *apiClient) RequestJSON(url, method string, o any) (*http.Response, error) {
data, err := json.Marshal(o)
if err != nil {
return nil, err
@@ -150,7 +152,7 @@ func (c *apiClient) Post(url, body string) (*http.Response, error) {
return c.RequestString(url, "POST", body)
}
func (c *apiClient) PutJSON(url string, o interface{}) (*http.Response, error) {
func (c *apiClient) PutJSON(url string, o any) (*http.Response, error) {
return c.RequestJSON(url, "PUT", o)
}
+1 -1
View File
@@ -81,7 +81,7 @@ func (c *configCommand) Run(ctx Context, outerCtx *kong.Context) error {
app.Name = "syncthing cli config"
app.HelpName = "syncthing cli config"
app.Description = outerCtx.Selected().Help
app.Metadata = map[string]interface{}{
app.Metadata = map[string]any{
"clientFactory": ctx.clientFactory,
}
app.CustomAppHelpTemplate = customAppHelpTemplate
+2 -2
View File
@@ -112,7 +112,7 @@ func getConfig(c APIClient) (config.Configuration, error) {
return cfg, nil
}
func prettyPrintJSON(data interface{}) error {
func prettyPrintJSON(data any) error {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(data)
@@ -123,7 +123,7 @@ func prettyPrintResponse(response *http.Response) error {
if err != nil {
return err
}
var data interface{}
var data any
if err := json.Unmarshal(bytes, &data); err != nil {
return err
}
+4 -1
View File
@@ -20,6 +20,7 @@ import (
"time"
"github.com/syncthing/syncthing/internal/slogutil"
"github.com/syncthing/syncthing/lib/build"
)
const (
@@ -81,6 +82,7 @@ func uploadPanicLog(ctx context.Context, urlBase, file string) error {
if err != nil {
return err
}
headReq.Header.Set("User-Agent", build.UserAgent())
// Set a reasonable timeout on the HEAD request
headCtx, headCancel := context.WithTimeout(ctx, headRequestTimeout)
@@ -101,6 +103,7 @@ func uploadPanicLog(ctx context.Context, urlBase, file string) error {
if err != nil {
return err
}
putReq.Header.Set("User-Agent", build.UserAgent())
// Set a reasonable timeout on the PUT request
putCtx, putCancel := context.WithTimeout(ctx, putRequestTimeout)
@@ -125,7 +128,7 @@ func uploadPanicLog(ctx context.Context, urlBase, file string) error {
func filterLogLines(data []byte) []byte {
filtered := data[:0]
matched := false
for _, line := range bytes.Split(data, []byte("\n")) {
for line := range bytes.SplitSeq(data, []byte("\n")) {
switch {
case !matched && bytes.HasPrefix(line, []byte("Panic ")):
// This begins the panic trace, set the matched flag and append.
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build !windows
// +build !windows
package main
+57 -35
View File
@@ -313,21 +313,6 @@ func (c *serveCmd) Run() error {
return nil
}
func openGUI() error {
cfg, err := loadOrDefaultConfig()
if err != nil {
return err
}
if guiCfg := cfg.GUI(); guiCfg.Enabled {
if err := openURL(guiCfg.URL()); err != nil {
return err
}
} else {
slog.Error("Browser: GUI is currently disabled")
}
return nil
}
func logPackages() string {
packages := slogutil.PackageDescrs()
@@ -389,6 +374,7 @@ func upgradeViaRest() error {
target := u.String()
r, _ := http.NewRequest(http.MethodPost, target, nil)
r.Header.Set("X-Api-Key", cfg.GUI().APIKey)
r.Header.Set("User-Agent", build.UserAgent())
tr := &http.Transport{
DialContext: dialer.DialContext,
@@ -418,6 +404,28 @@ func upgradeViaRest() error {
}
func (c *serveCmd) syncthingMain() {
// Ensure we are the only running instance
lf := flock.New(locations.Get(locations.LockFile))
locked, err := lf.TryLock()
switch {
case err != nil:
slog.Error("Failed to acquire lock", slogutil.Error(err))
os.Exit(svcutil.ExitError.AsInt())
case !locked && c.NoBrowser:
slog.Error("Failed to acquire lock: is another Syncthing instance already running?")
os.Exit(svcutil.ExitError.AsInt())
case !locked:
slog.Info("Seems to already be running, launching GUI instead (use --no-browser to prevent)")
cmd := browserCmd{Verify: true}
if err := cmd.Run(); err != nil {
slog.Error("Failed to open browser", slogutil.Error(err))
os.Exit(svcutil.ExitNoRestart.AsInt())
}
return
}
if c.DebugProfileBlock {
startBlockProfiler()
}
@@ -436,18 +444,7 @@ func (c *serveCmd) syncthingMain() {
)
if err != nil {
slog.Error("Failed to load/generate certificate", slogutil.Error(err))
os.Exit(1)
}
// Ensure we are the only running instance
lf := flock.New(locations.Get(locations.LockFile))
locked, err := lf.TryLock()
if err != nil {
slog.Error("Failed to acquire lock", slogutil.Error(err))
os.Exit(1)
} else if !locked {
slog.Error("Failed to acquire lock: is another Syncthing instance already running?")
os.Exit(1)
os.Exit(svcutil.ExitError.AsInt())
}
ctx, cancel := context.WithCancel(context.Background())
@@ -502,13 +499,13 @@ func (c *serveCmd) syncthingMain() {
if err := syncthing.TryMigrateDatabase(ctx, c.DBDeleteRetentionInterval); err != nil {
slog.Error("Failed to migrate old-style database", slogutil.Error(err))
os.Exit(1)
os.Exit(svcutil.ExitError.AsInt())
}
sdb, err := syncthing.OpenDatabase(locations.Get(locations.Database), c.DBDeleteRetentionInterval)
if err != nil {
slog.Error("Error opening database", slogutil.Error(err))
os.Exit(1)
os.Exit(svcutil.ExitError.AsInt())
}
if c.DebugPerfStats {
@@ -915,7 +912,7 @@ func (u upgradeCmd) Run() error {
switch {
case err != nil && !os.IsNotExist(err):
slog.Error("Failed to lock for upgrade", slogutil.Error(err))
os.Exit(1)
os.Exit(svcutil.ExitError.AsInt())
case locked || os.IsNotExist(err):
// We got the lock, or the config directory didn't exist, so we
// can do a direct upgrade
@@ -935,14 +932,39 @@ func (u upgradeCmd) Run() error {
return nil
}
type browserCmd struct{}
type browserCmd struct {
Verify bool `help:"Verify that the GUI is reachable before launching browser"`
}
func (browserCmd) Run() error {
if err := openGUI(); err != nil {
slog.Error("Failed to open web UI", slogutil.Error(err))
func (c browserCmd) Run() error {
cfg, err := loadOrDefaultConfig()
if err != nil {
return err
}
guiCfg := cfg.GUI()
if !guiCfg.Enabled {
slog.Error("Browser: GUI is currently disabled")
os.Exit(svcutil.ExitError.AsInt())
}
return nil
url := guiCfg.URL()
if c.Verify {
// Do an HTTP request to verify the GUI/API is up and available
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return err
}
req.Header.Set("User-Agent", build.UserAgent())
_, err = http.DefaultClient.Do(req) //nolint:bodyclose // we're exiting in a millisecond
if err != nil {
slog.Error("GUI not available", slogutil.Error(err))
os.Exit(svcutil.ExitError.AsInt()) //nolint:gocritic // deferred cancel
}
}
return openURL(url)
}
type debugCmd struct {
+8 -3
View File
@@ -171,10 +171,11 @@ func (c *serveCmd) monitorMain() {
exiterr := &exec.ExitError{}
if errors.As(err, &exiterr) {
exitCode := exiterr.ExitCode()
if stopped || c.NoRestart {
switch {
case stopped || c.NoRestart:
os.Exit(exitCode)
}
if exitCode == svcutil.ExitUpgrade.AsInt() {
case exitCode == svcutil.ExitUpgrade.AsInt():
// Restart the monitor process to release the .old
// binary as part of the upgrade process.
slog.Info("Restarting monitor...")
@@ -182,6 +183,10 @@ func (c *serveCmd) monitorMain() {
slog.Error("Failed to restart monitor", slogutil.Error(err))
}
os.Exit(exitCode)
case exitCode == svcutil.ExitNoRestart.AsInt():
// Requested to not restart the child
os.Exit(exitCode)
}
}
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build !windows
// +build !windows
package main
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build windows
// +build windows
package main
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build !solaris && !windows
// +build !solaris,!windows
package main
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build solaris || windows
// +build solaris windows
package main
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build go1.7
// +build go1.7
package main
+5
View File
@@ -46,3 +46,8 @@
linux: "3.2"
windows: "10.0"
- runtime: go1.27
requirements:
darwin: "22" # macOS 13 (Ventura)
linux: "3.2"
windows: "10.0"
+22 -29
View File
@@ -1,10 +1,10 @@
module github.com/syncthing/syncthing
go 1.25.0
go 1.26.2
require (
github.com/AudriusButkevicius/recli v0.0.7
github.com/alecthomas/kong v1.16.0
github.com/alecthomas/kong v1.16.1
github.com/aws/aws-sdk-go v1.55.8
github.com/calmh/incontainer v1.0.0
github.com/calmh/xdr v1.2.0
@@ -16,23 +16,23 @@ require (
github.com/gobwas/glob v0.2.3
github.com/gofrs/flock v0.13.0
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/jackpal/gateway v1.1.1
github.com/jackpal/gateway v1.2.0
github.com/jackpal/go-nat-pmp v1.0.2
github.com/jmoiron/sqlx v1.4.0
github.com/julienschmidt/httprouter v1.3.0
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/maruel/panicparse/v2 v2.5.0
github.com/mattn/go-sqlite3 v1.14.48
github.com/mattn/go-sqlite3 v1.14.50
github.com/maxmind/geoipupdate/v6 v6.1.0
github.com/miscreant/miscreant.go v0.0.0-20200214223636-26d376326b75
github.com/oschwald/geoip2-golang v1.13.0
github.com/pierrec/lz4/v4 v4.1.27
github.com/prometheus/client_golang v1.24.0
github.com/pierrec/lz4/v4 v4.1.29
github.com/prometheus/client_golang v1.24.1
github.com/puzpuzpuz/xsync/v3 v3.5.1
github.com/quic-go/quic-go v0.60.0
github.com/rabbitmq/amqp091-go v1.13.0
github.com/quic-go/quic-go v0.61.0
github.com/rabbitmq/amqp091-go v1.14.0
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9
github.com/shirou/gopsutil/v4 v4.26.6
github.com/shirou/gopsutil/v4 v4.26.7
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
@@ -40,14 +40,14 @@ require (
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0
github.com/willabides/kongplete v0.4.0
github.com/wlynxg/anet v0.0.5
golang.org/x/crypto v0.54.0
golang.org/x/exp v0.0.0-20260718201538-764159d718ef
golang.org/x/net v0.57.0
golang.org/x/crypto v0.55.0
golang.org/x/exp v0.0.0-20260813180055-c1d0aacb2297
golang.org/x/net v0.58.0
golang.org/x/sys v0.47.0
golang.org/x/text v0.40.0
golang.org/x/text v0.41.0
golang.org/x/time v0.15.0
google.golang.org/protobuf v1.36.11
modernc.org/sqlite v1.54.0
google.golang.org/protobuf v1.36.12
modernc.org/sqlite v1.57.0
sigs.k8s.io/yaml v1.6.0
)
@@ -58,48 +58,41 @@ require (
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/ebitengine/purego v0.10.0 // indirect
github.com/ebitengine/purego v0.10.2 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.8 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-isatty v0.0.24 // indirect
github.com/maxbrunsfeld/counterfeiter/v6 v6.12.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/nxadm/tail v1.4.11 // indirect
github.com/oschwald/maxminddb-golang v1.13.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/posener/complete v1.2.3 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.70.0 // indirect
github.com/prometheus/common v0.70.1 // indirect
github.com/prometheus/procfs v0.21.1 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/riywo/loginshell v0.0.0-20200815045211-7d26008be1ab // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/stretchr/testify v1.11.1 // indirect
github.com/tklauser/go-sysconf v0.3.16 // indirect
github.com/tklauser/numcpus v0.11.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect
golang.org/x/mod v0.38.0 // indirect
golang.org/x/mod v0.39.0 // indirect
golang.org/x/sync v0.22.0 // indirect
golang.org/x/telemetry v0.0.0-20260708182218-49f421fb7959 // indirect
golang.org/x/tools v0.48.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/libc v1.74.1 // indirect
golang.org/x/telemetry v0.0.0-20260811182544-a038080d80e5 // indirect
golang.org/x/tools v0.49.0 // indirect
modernc.org/libc v1.74.4 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
)
+50 -58
View File
@@ -7,8 +7,8 @@ github.com/Azure/go-ntlmssp v0.1.1/go.mod h1:NYqdhxd/8aAct/s4qSYZEerdPuH1liG2/X9
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/kong v1.16.0 h1:g92/kUxBcdcTPOM79yE63viJgtcp5dNyrB3/O2cjYT4=
github.com/alecthomas/kong v1.16.0/go.mod h1:wrlbXem1CWqUV5Vbmss5ISYhsVPkBb1Yo7YKJghju2I=
github.com/alecthomas/kong v1.16.1 h1:ixhCt93XkJ98kGposQ54+bl0IK6XwqB40AsMynU7Z8E=
github.com/alecthomas/kong v1.16.1/go.mod h1:wrlbXem1CWqUV5Vbmss5ISYhsVPkBb1Yo7YKJghju2I=
github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e h1:4dAU9FXIyQktpoUAgOJK3OTFc/xug0PCXYCqU0FgDKI=
@@ -45,8 +45,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU=
github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/ebitengine/purego v0.10.2 h1:W809HbnvzAxgdm+aOvlSekrM16wGCdT/e76+9tS7gzE=
github.com/ebitengine/purego v0.10.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
@@ -86,8 +86,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4 h1:gD0vax+4I+mAj+jEChEf25Ia07Jq7kYOFO5PPhAxFl4=
github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3 h1:LMLX+LgTNWpfvCBdFebv6EsYotImrt/Ppc5cXIriCSo=
github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3/go.mod h1:jl5iWTm0/hd5PjEYEOuwAJ57L/CibdZfrqZ5XA5GrCk=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -104,6 +104,8 @@ github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUq
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jackpal/gateway v1.2.0 h1:euPRe4t7JfTaqC5Lr78HXl2wSHo54XndTtiAcIxkb5g=
github.com/jackpal/gateway v1.2.0/go.mod h1:/jchvRi4HukAqV24da70iaBMFcSrX3rNWdR5K9VHd0A=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
@@ -128,27 +130,21 @@ github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4d
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/klauspost/compress v1.19.0 h1:sXLILfc9jV2QYWkzFOPWStmcUVH2RHEB1JCdY2oVvCQ=
github.com/klauspost/compress v1.19.0/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/klauspost/compress v1.19.1 h1:VsB4HPswih7mmZ8WleSFQ75c/Ui1M4trX5oAsJnhSlk=
github.com/klauspost/compress v1.19.1/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 h1:7UMa6KCCMjZEMDtTVdcGu0B1GmmC7QJKiCCjyTAWQy0=
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
github.com/marbens-arch/gateway v1.1.2-0.20260308173556-c567cc04e7d4 h1:8TAc8a26Pp0+8I6rj43BqhMi84D1zvtY0sPzO3IKnBw=
github.com/marbens-arch/gateway v1.1.2-0.20260308173556-c567cc04e7d4/go.mod h1:Tl1vZVtUaXx5j6P5HFmv45alhEi4yHHLfT4PRbB7eyw=
github.com/maruel/panicparse/v2 v2.5.0 h1:yCtuS0FWjfd0RTYMXGpDvWcb0kINm8xJGu18/xMUh00=
github.com/maruel/panicparse/v2 v2.5.0/go.mod h1:DA2fDiBk63bKfBf4CVZP9gb4fuvzdPbLDsSI873hweQ=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI=
github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mattn/go-sqlite3 v1.14.48 h1:7XHIgl0a8HwOaiK4E47ozLkST78rR9+OtNGx27D/TFs=
github.com/mattn/go-sqlite3 v1.14.48/go.mod h1:6JTjA44L93a0QCyJef5YvlPoKXntQPjzWv5gtm9sB6w=
github.com/mattn/go-sqlite3 v1.14.50 h1:dmdFvo1XG4MPzA4IkAmE9upVz/Nj31uRoM5+jC8hYbY=
github.com/mattn/go-sqlite3 v1.14.50/go.mod h1:6JTjA44L93a0QCyJef5YvlPoKXntQPjzWv5gtm9sB6w=
github.com/maxbrunsfeld/counterfeiter/v6 v6.12.0 h1:aOeI7xAOVdK+R6xbVsZuU9HmCZYmQVmZgPf9xJUd2Sg=
github.com/maxbrunsfeld/counterfeiter/v6 v6.12.0/go.mod h1:0hZWbtfeCYUQeAQdPLUzETiBhUSns7O6LDj9vH88xKA=
github.com/maxmind/geoipupdate/v6 v6.1.0 h1:sdtTHzzQNJlXF5+fd/EoPTucRHyMonYt/Cok8xzzfqA=
@@ -179,8 +175,8 @@ github.com/oschwald/geoip2-golang v1.13.0 h1:Q44/Ldc703pasJeP5V9+aFSZFmBN7DKHbNs
github.com/oschwald/geoip2-golang v1.13.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo=
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
github.com/pierrec/lz4/v4 v4.1.27 h1:+PhzhWDrjRj89TH2sw43nE3+4+W8lSxIuQadEHZyjUk=
github.com/pierrec/lz4/v4 v4.1.27/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
github.com/pierrec/lz4/v4 v4.1.29 h1:CDQY6qZOLI4DW0Nx6R1vRrifrCeQHnNXkMb0hZWXFjg=
github.com/pierrec/lz4/v4 v4.1.29/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -190,41 +186,40 @@ github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXq
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_golang v1.24.0 h1:5XStIklKuAtJSNpdD3s8XJj/Yv78IQmE1kbNk87JrAI=
github.com/prometheus/client_golang v1.24.0/go.mod h1:QcsNdotprC2nS4BTM2ucbcqxd2CeXTEa9jW7zHO9iDE=
github.com/prometheus/client_golang v1.24.1 h1:JnJkREXzWxUdCuPFpIWZiPispT9xVV59uiuyR2bPlnU=
github.com/prometheus/client_golang v1.24.1/go.mod h1:F+oSRECHg4sse5ucfYpYDeIv/hu68Zo0uoHKetWnzcE=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.70.0 h1:bcpru3tWPVnxGnETLgOV5jbp/JRXgYEyv65CuBLAMMI=
github.com/prometheus/common v0.70.0/go.mod h1:S/SFasQmgGiYH6C81LKCtYa8QACgthGg5zxL2udV7SY=
github.com/prometheus/common v0.70.1 h1:1HvjP4D5oL3t8RsPlwxA9onvvStjtIHYE5XuuwOi/PY=
github.com/prometheus/common v0.70.1/go.mod h1:VdFUQDMZK3VLkurFUVhia6uys/0suUp86TJz5qbJRhc=
github.com/prometheus/procfs v0.21.1 h1:GljZCt+zSTS+NZq88cyQ1LjZ+RCHp3uVuabBWA5+OJI=
github.com/prometheus/procfs v0.21.1/go.mod h1:aB55Cww9pdSJVHk0hUf0inxWyyjPogFIjmHKYgMKmtY=
github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg=
github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
github.com/quic-go/go-ossfuzz-seeds v0.1.0 h1:APacT+iIaNF6fd8AGEiN3bT/Jtkd2jz4v4TzM7MFjy0=
github.com/quic-go/go-ossfuzz-seeds v0.1.0/go.mod h1:3IOHRbJIc+L6YKMwfDtJAM9Vj9k0YY4muhuyUYk5tbk=
github.com/quic-go/quic-go v0.60.0 h1:xcQioE8OM66UQLeUMHltK1CCcOu3JbVB4JAQdDQSB+0=
github.com/quic-go/quic-go v0.60.0/go.mod h1:wpKpjmPpftl30sL6pFh7REVpjbcCVy4zt2vDyK1TuJk=
github.com/rabbitmq/amqp091-go v1.13.0 h1:L8NA1WtF76C6KA3LAoufjfLgbist/If1UQYcsOjtxXA=
github.com/rabbitmq/amqp091-go v1.13.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o=
github.com/quic-go/quic-go v0.61.0 h1:ui88A53s8MSVYLC56en0KQ17HARk+9986Dn0SBfKNvA=
github.com/quic-go/quic-go v0.61.0/go.mod h1:9So2anK4Tp22URSQq00k+Vo2PNkle96ycDPDHL4s9vs=
github.com/rabbitmq/amqp091-go v1.14.0 h1:RSaT7aOKt/OrkVUyswPDW29lnRz9psuGmfZFBmLqLek=
github.com/rabbitmq/amqp091-go v1.14.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o=
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg=
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/riywo/loginshell v0.0.0-20200815045211-7d26008be1ab h1:ZjX6I48eZSFetPb41dHudEyVr5v953N15TsNZXlkcWY=
github.com/riywo/loginshell v0.0.0-20200815045211-7d26008be1ab/go.mod h1:/PfPXh0EntGc3QAAyUaviy4S9tzy4Zp0e2ilq4voC6E=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
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.26.6 h1:Mzr/npDtQC/xpeEuQKHZt8Zo9CmPvhTj8nkR8w5TLDs=
github.com/shirou/gopsutil/v4 v4.26.6/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ=
github.com/shirou/gopsutil/v4 v4.26.7 h1:IXzpHz/dkMRYAhKkOXr1HB6SuzWU3eoyyeWe7g3bNZc=
github.com/shirou/gopsutil/v4 v4.26.7/go.mod h1:5O9FjBiXoTDFatIWjZZosqj4pV0DRtLx598xGbBehzM=
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=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -267,13 +262,13 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw=
golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk=
golang.org/x/exp v0.0.0-20260718201538-764159d718ef h1:LkZ48HFgy/TvhTI0bcWkjgFkgLyKUwcTbDjS0DUjw+A=
golang.org/x/exp v0.0.0-20260718201538-764159d718ef/go.mod h1:EdfpwwqSu+0Li0mzskwHU6FWDV3t9Q+RZDo3QMUtL3Q=
golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M=
golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis=
golang.org/x/exp v0.0.0-20260813180055-c1d0aacb2297 h1:YXnL44eJ77R+ji4/ooy8UsXIhz+lbi2Qgdlc8iRN0gY=
golang.org/x/exp v0.0.0-20260813180055-c1d0aacb2297/go.mod h1:Mkmymgv+uMpSQ/XxJ/7GpdrdYoqm3u72jEbpCLiJmNk=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk=
golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40=
golang.org/x/mod v0.39.0 h1:UF5zwQdCRRUpHfyPwr7d4UrGiVeldIsogtzWVnczL74=
golang.org/x/mod v0.39.0/go.mod h1:bvIbwjQ0HUFFf5AKukeeYQG4ZBUG9yxQbR9aEweIwYY=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -282,8 +277,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE=
golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU=
golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To=
golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -310,26 +305,25 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/telemetry v0.0.0-20260708182218-49f421fb7959 h1:RJhm5l6Fo4rmEIcndxDllNhhf/fAx8qIm4t6A7vpm2A=
golang.org/x/telemetry v0.0.0-20260708182218-49f421fb7959/go.mod h1:LV7u5Oco+Z/g6XI7PqN+EUUUGGkEcmB1uj2ceI0fOVg=
golang.org/x/telemetry v0.0.0-20260811182544-a038080d80e5 h1:ZUSxONxc981v7AW7QUg+I9WwZzSTTJ019ENBYr5pV/Q=
golang.org/x/telemetry v0.0.0-20260811182544-a038080d80e5/go.mod h1:LVehoXe41cL5SCVQilsV7Gg6BNG+Js6P9PhSbYTIUkQ=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE=
golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk=
golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI=
golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -343,11 +337,9 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
@@ -360,8 +352,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
modernc.org/cc/v4 v4.29.0 h1:CXgwL8cvxmyzBQZzbSl/6xFtMCryb6u8IOqDci39cgc=
modernc.org/cc/v4 v4.29.0/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI=
modernc.org/cc/v4 v4.29.1 h1:MKgdCV3WykTSPqpVrnxdEDS0HEd2FHpKZDzxzU5LyeI=
modernc.org/cc/v4 v4.29.1/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI=
modernc.org/ccgo/v4 v4.34.6 h1:sBgfIwyN0TQ9C5hwIeuqyeAKyMWnbvj2fvpF4L11uzU=
modernc.org/ccgo/v4 v4.34.6/go.mod h1:SZ8YcN9NG7XVsQYdm6jYBvi8PQP1qi+kqB6OhjqI3Fk=
modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM=
@@ -372,8 +364,8 @@ modernc.org/gc/v3 v3.1.4 h1:2g65LGVSmFQrXeITAw97x7hCRvZFcyE1uDP+7Vng7JI=
modernc.org/gc/v3 v3.1.4/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
modernc.org/libc v1.74.1 h1:bdR4VTKFMC4966QSNZ05XLGI/VwzVa2kTUX51Dm0riQ=
modernc.org/libc v1.74.1/go.mod h1:uH4t5bOx3G3g9Xcmj10YKlTcVISlRDwv8VoQJG9n8Os=
modernc.org/libc v1.74.4 h1:fX1Omw4o2/1C2iRkkIsrQTasJQldLhRmuPreXLoWs9k=
modernc.org/libc v1.74.4/go.mod h1:eeQAS9W3sZeKYMFubydxJpII9ybHWshk+7or7bLG9co=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
@@ -382,8 +374,8 @@ modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg=
modernc.org/opt v0.2.0/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
modernc.org/sqlite v1.54.0 h1:JCxR4qwkJvOaqAoYcgDoO25Nc+ROg6EJ2LfBVzdrgog=
modernc.org/sqlite v1.54.0/go.mod h1:4ntCLuNmnH8+GNqjka1wNg7KJd5/Hi5FYp8K+XQ7GZw=
modernc.org/sqlite v1.57.0 h1:qNQP6xnx5M0ISNtlnxoOX0+cD5bJ0/gr9aMmndFczzg=
modernc.org/sqlite v1.57.0/go.mod h1:yCJ2cmAaIkHQ25oXWrF8H4O1lIfPYPR26yCEDj2P3pQ=
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
+2
View File
@@ -125,6 +125,8 @@
"Discovery Status": "حالة الاكتشاف",
"Dismiss": "رفض",
"Do not add it to the ignore list, so this notification may recur.": "لا تقم بإضافته إلى قائمة التجاهل، لذلك قد يتكرر هذا الإشعار.",
"Do not add it to the ignore list, so this notification will reappear if the device connects again.": "لا تقم بإضافته إلى قائمة التجاهل، حتى يتم اخطارك عند اعادة اتصال الجهاز.",
"Do not add it to the ignore list, so this notification will reappear if the device offering this folder connects again.": "لا تقم بإضافته إلى قائمة التجاهل، حتى يتم اخطارك عند اعادة اتصال الجهاز المزوّد لهذا المجلد.",
"Do not restore": "الغاء الاستعادة",
"Do not restore all": "الغاء استعادة الكل",
"Do you want to enable watching for changes for all your folders?": "هل تريد تفعيل مراقبة التغيرات على كل المجلدات؟",
+2
View File
@@ -125,6 +125,8 @@
"Discovery Status": "Discovery Status",
"Dismiss": "Dismiss",
"Do not add it to the ignore list, so this notification may recur.": "Do not add it to the ignore list, so this notification may recur.",
"Do not add it to the ignore list, so this notification will reappear if the device connects again.": "Do not add it to the ignore list, so this notification will reappear if the device connects again.",
"Do not add it to the ignore list, so this notification will reappear if the device offering this folder connects again.": "Do not add it to the ignore list, so this notification will reappear if the device offering this folder connects again.",
"Do not restore": "Do not restore",
"Do not restore all": "Do not restore all",
"Do you want to enable watching for changes for all your folders?": "Do you want to enable watching for changes for all your folders?",
+29
View File
@@ -1,2 +1,31 @@
{
"A device with that ID is already added.": "یک دستگاه با این شناسه قبلاً اضافه شده است.",
"A negative number of days doesn't make sense.": "تعداد روزهای منفی قابل قبول نیست.",
"A new major version may not be compatible with previous versions.": "نسخه جدید اصلی ممکن است با نسخه قبلی سازگار نباشد.",
"API Key": "کلید API",
"About": "درباره",
"Action": "عمل",
"Actions": "اعمال",
"Active filter rules": "قوانین فیلتر فعال",
"Add": "افزودن",
"Add Device": "افزودن دستگاه",
"Add Folder": "افزودن پوشه",
"Add Remote Device": "افزودن دستگاه دیگر",
"Add filter entry": "افزودن ورودی فیلتر",
"Add ignore patterns": "افزودن الگوی نادیده گرفتن",
"Add new folder?": "افزودن پوشه جدید؟",
"Address": "نشانی",
"Addresses": "نشانی‌ها",
"Advanced": "پیشرفته",
"Advanced Configuration": "پیکربندی پیشرفته",
"All Data": "تمام داده‌ها",
"All Time": "تمام زمان",
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "تمام پوشه‌های به اشتراک گذاشته در این دستگاه باید با یک گذرواژه محافظت شوند، داده‌های ارسال شده بدون گذرواژه غیرقابل خواندن هستند.",
"Allow Anonymous Usage Reporting?": "اجازه دادن به ارسال ناشناس گزارش استفاده؟",
"Allowed Networks": "شبکه‌های مجاز",
"Alphabetic": "الفبایی",
"Altered by ignoring deletes.": "با نادیده گرفتن حذف‌ها تغییر داده شد.",
"LDAP": "LDAP",
"TCP WAN": "TCPWAN",
"Take me back": "برگرداندن"
}
+1 -1
View File
@@ -47,7 +47,7 @@
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Le système de mise à jour automatique propose le choix entre versions stables et versions préliminaires.",
"Automatic upgrades": "Mises à jour automatiques",
"Automatic upgrades are always enabled for candidate releases.": "Les mises à jour automatiques sont toujours activées pour les versions mineures.",
"Automatically create or share folders that this device advertises at the default path.": "Automatiquement créer dans le chemin par défaut les partages auxquels cet appareil vous propose de participer, ou accepter leur partage s'ils pré-existent.",
"Automatically create or share folders that this device advertises at the default path.": "Accepter automatiquement ses propositions de partage. Si le partage n'existe pas déjà ici, le répertoire correspondant sera créé dans le chemin par défaut.",
"Available debug logging facilities:": "Outils de débogage disponibles :",
"Be careful!": "Faites attention !",
"Block Indexing": "Indexation des blocs",
+3
View File
@@ -125,6 +125,8 @@
"Discovery Status": "탐지 현황",
"Dismiss": "나중에",
"Do not add it to the ignore list, so this notification may recur.": "무시 항목에 추가되지 않으니 이 알림이 다시 표시될 수 있습니다.",
"Do not add it to the ignore list, so this notification will reappear if the device connects again.": "무시 항목에 추가되지 않으니 해당 기기가 다시 연결되면 이 알림은 다시 표시될 것입니다.",
"Do not add it to the ignore list, so this notification will reappear if the device offering this folder connects again.": "무시 항목에 추가되지 않으니 이 폴더를 공유하는 기가가 연결되면 이 알림은 다시 표시될 것입니다.",
"Do not restore": "복구하지 않기",
"Do not restore all": "모두 복구하지 않기",
"Do you want to enable watching for changes for all your folders?": "변경 항목 감시를 모든 폴더에서 활성화하시겠습니까?",
@@ -395,6 +397,7 @@
"Staggered": "시차제",
"Staggered File Versioning": "시차제 파일 버전 관리",
"Start Browser": "브라우저 열기",
"Starting": "시작 중",
"Statistics": "통계",
"Stay logged in": "로그인 상태 유지",
"Stopped": "중지됨",
+2 -2
View File
@@ -125,8 +125,8 @@
"Discovery Status": "Stan odnajdywania",
"Dismiss": "Odrzuć",
"Do not add it to the ignore list, so this notification may recur.": "Nie dodaje do listy ignorowanych, więc powiadomienie to może się powtórzyć.",
"Do not add it to the ignore list, so this notification will reappear if the device connects again.": "Nie dodaje do listy ignorowanych, więc powiadomienie pojawi się ponownie, gdy urządzenie połączy się ponownie.",
"Do not add it to the ignore list, so this notification will reappear if the device offering this folder connects again.": "Nie dodaje do listy ignorowanych, więc powiadomienie pojawi się ponownie, gdy urządzenie oferujące ten folder ponownie się połączy.",
"Do not add it to the ignore list, so this notification will reappear if the device connects again.": "Nie dodaje do listy ignorowanych, więc powiadomienie pojawi się ponownie, gdy urządzenie po raz kolejny się połączy.",
"Do not add it to the ignore list, so this notification will reappear if the device offering this folder connects again.": "Nie dodaje do listy ignorowanych, więc powiadomienie pojawi się ponownie, gdy urządzenie oferujące ten folder po raz kolejny się połączy.",
"Do not restore": "Nie przywracaj",
"Do not restore all": "Nie przywracaj wszystkich",
"Do you want to enable watching for changes for all your folders?": "Czy chcesz włączyć obserwowanie zmian we wszystkich folderach?",
+3
View File
@@ -50,6 +50,7 @@
"Automatically create or share folders that this device advertises at the default path.": "Crează sau partajează automat mapele anunțate de acest dispozitiv la calea implicită.",
"Available debug logging facilities:": "Facilități disponibile pentru registrul de depanare:",
"Be careful!": "Fii atent!",
"Block Indexing": "Blochează indexarea",
"Body:": "Corp:",
"Bugs": "Bug-uri",
"Cancel": "Renunță",
@@ -82,6 +83,7 @@
"Custom Range": "Interval Personalizat",
"Danger!": "Pericol!",
"Database Location": "Locația Bazei de Date",
"Debug": "Depanează",
"Debugging Facilities": "Facilități de Depanare",
"Default": "Implicit",
"Default Configuration": "Configurare implicită",
@@ -97,6 +99,7 @@
"Device": "Dispozitiv",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Dispozitivul \"{{name}}\" ({{device}} la {{address}}) vrea să se conecteze. Adaugă un dispozitiv nou?",
"Device Certificate": "Certificatul dispozitivului",
"Device Group": "Grup de dispozitive",
"Device ID": "ID Dispozitiv",
"Device Identification": "Identificare Dispozitiv",
"Device Name": "Nume Dispozitiv",
+2 -1
View File
@@ -137,7 +137,7 @@
"Edit Device Defaults": "Изменить настройки устройств",
"Edit Folder": "Редактирование папки",
"Edit Folder Defaults": "Изменить настройки папок",
"Editing {%path%}.": "Правка {{path}}.",
"Editing {%path%}.": "Редактирование {{path}}.",
"Enable Crash Reporting": "Включить отчёты о сбоях",
"Enable NAT traversal": "Использовать обход NAT",
"Enable Relaying": "Использовать ретрансляторы",
@@ -396,6 +396,7 @@
"Staggered": "Ступенчато",
"Staggered File Versioning": "Ступенчатое управление версиями файлов",
"Start Browser": "Запускать браузер",
"Starting": "Запуск",
"Statistics": "Статистика",
"Stay logged in": "Оставаться в системе",
"Stopped": "Остановлено",
+3
View File
@@ -1017,6 +1017,9 @@
</div> <!-- /row -->
</div> <!-- /container -->
<footer class="container text-center text-muted small" aria-label="Custom build marker">
It syncs .stignore now!
</footer>
</div> <!-- /ng-cloak -->
<ng-include src="'syncthing/core/networkErrorDialogView.html'"></ng-include>
@@ -59,7 +59,6 @@ Jakob Borg, Audrius Butkevicius, Simon Frei, Tomasz Wilczyński, Alexander Graf,
<li><a href="https://github.com/ccding/go-stun">ccding/go-stun</a>, Copyright &copy; 2016 Cong Ding.</li>
<li><a href="https://github.com/cespare/xxhash/v2">cespare/xxhash/v2</a>, Copyright &copy; 2016 Caleb Spare.</li>
<li><a href="https://github.com/cpuguy83/go-md2man/v2">cpuguy83/go-md2man/v2</a>, Copyright &copy; 2014 Brian Goff.</li>
<li><a href="https://github.com/davecgh/go-spew">davecgh/go-spew</a>, Copyright &copy; 2012-2016 Dave Collins.</li>
<li><a href="https://github.com/go-asn1-ber/asn1-ber">go-asn1-ber/asn1-ber</a>, Copyright &copy; 2011-2015 Michael Mitton (mmitton@gmail.com).</li>
<li><a href="https://github.com/go-ldap/ldap">go-ldap/ldap</a>, Copyright &copy; 2011-2015 Michael Mitton (mmitton@gmail.com).</li>
<li><a href="https://github.com/gobwas/glob">gobwas/glob</a>, Copyright &copy; 2016 Sergey Kamardin.</li>
@@ -67,7 +66,6 @@ Jakob Borg, Audrius Butkevicius, Simon Frei, Tomasz Wilczyński, Alexander Graf,
<li><a href="https://github.com/golang/snappy">golang/snappy</a>, Copyright &copy; 2011 The Snappy-Go Authors.</li>
<li><a href="https://github.com/protocolbuffers/protobuf-go">google.golang.org/protobuf</a>, Copyright &copy; 2018 The Go Authors.</li>
<li><a href="https://github.com/google/uuid">google/uuid</a>, Copyright &copy; 2009,2014 Google Inc.</li>
<li><a href="https://gopkg.in/yaml.v3">gopkg.in/yaml.v3</a>, Copyright &copy; 2025, the gopkg.in/yaml.v3 authors.</li>
<li><a href="https://github.com/hashicorp/errwrap">hashicorp/errwrap</a>, Copyright &copy; 2014 HashiCorp, Inc.</li>
<li><a href="https://github.com/hashicorp/go-multierror">hashicorp/go-multierror</a>, Copyright &copy; 2014 HashiCorp, Inc.</li>
<li><a href="https://github.com/hashicorp/golang-lru">hashicorp/golang-lru</a>, Copyright &copy; 2014 HashiCorp, Inc.</li>
@@ -81,7 +79,6 @@ Jakob Borg, Audrius Butkevicius, Simon Frei, Tomasz Wilczyński, Alexander Graf,
<li><a href="https://github.com/munnerz/goautoneg">munnerz/goautoneg</a>, Copyright &copy; 2011, Open Knowledge Foundation Ltd.</li>
<li><a href="https://github.com/pierrec/lz4">pierrec/lz4</a>, Copyright &copy; 2015 Pierre Curto.</li>
<li><a href="https://github.com/pkg/errors">pkg/errors</a>, Copyright &copy; 2015, Dave Cheney.</li>
<li><a href="https://github.com/pmezard/go-difflib">pmezard/go-difflib</a>, Copyright &copy; 2013, Patrick Mezard.</li>
<li><a href="https://github.com/posener/complete">posener/complete</a>, Copyright &copy; 2017 Eyal Posener.</li>
<li><a href="https://github.com/prometheus/client_golang">prometheus/client_golang</a>, Copyright 2012-2015 The Prometheus Authors.</li>
<li><a href="https://github.com/prometheus/client_model">prometheus/client_model</a>, Copyright &copy; 2025, the prometheus/client_model authors.</li>
@@ -92,8 +89,6 @@ Jakob Borg, Audrius Butkevicius, Simon Frei, Tomasz Wilczyński, Alexander Graf,
<li><a href="https://github.com/riywo/loginshell">riywo/loginshell</a>, Copyright &copy; 2019 Ryosuke IWANAGA.</li>
<li><a href="https://github.com/russross/blackfriday/v2">russross/blackfriday/v2</a>, Copyright &copy; 2011 Russ Ross.</li>
<li><a href="https://github.com/shirou/gopsutil">shirou/gopsutil</a>, Copyright &copy; 2014, WAKAYAMA Shirou.</li>
<li><a href="https://github.com/stretchr/objx">stretchr/objx</a>, Copyright &copy; 2014 Stretchr, Inc.</li>
<li><a href="https://github.com/stretchr/testify">stretchr/testify</a>, Copyright &copy; 2012-2020 Mat Ryer, Tyler Bunnell and contributors.</li>
<li><a href="https://github.com/syndtr/goleveldb">syndtr/goleveldb</a>, Copyright &copy; 2012 Suryandaru Triandana.</li>
<li><a href="https://github.com/thejerf/suture">thejerf/suture</a>, Copyright &copy; 2014-2015 Barracuda Networks, Inc.</li>
<li><a href="https://github.com/tklauser/go-sysconf">tklauser/go-sysconf</a>, Copyright &copy; 2018-2022, Tobias Klauser.</li>
+1 -1
View File
@@ -313,7 +313,7 @@ nextScript:
// files on lines containing only a semicolon and execute them
// separately. We require it on a separate line because there are
// also statement-internal semicolons in the triggers.
for _, stmt := range strings.Split(string(bs), "\n;") {
for stmt := range strings.SplitSeq(string(bs), "\n;") {
if _, err := tx.Exec(s.expandTemplateVars(stmt)); err != nil {
if strings.Contains(stmt, "syncthing:ignore-failure") {
// We're ok with this failing. Just note it.
+1 -4
View File
@@ -474,10 +474,7 @@ func (s *folderDB) recalcGlobalForFile(txp *txPreparedStmts, file string) error
// The global version is the first one in the list that is not invalid,
// or just the first one in the list if all are invalid.
var global fileRow
globIdx := slices.IndexFunc(es, func(e fileRow) bool { return !e.IsInvalid() })
if globIdx < 0 {
globIdx = 0
}
globIdx := max(slices.IndexFunc(es, func(e fileRow) bool { return !e.IsInvalid() }), 0)
global = es[globIdx]
// We "have" the file if the position in the list of versions is at the
+2 -2
View File
@@ -41,8 +41,8 @@ func SetDefaultLevel(level slog.Level) {
}
func SetLevelOverrides(sttrace string) {
pkgs := strings.Split(sttrace, ",")
for _, pkg := range pkgs {
pkgs := strings.SplitSeq(sttrace, ",")
for pkg := range pkgs {
pkg = strings.TrimSpace(pkg)
if pkg == "" {
continue
+2 -2
View File
@@ -45,11 +45,11 @@ type adapter struct {
l *slog.Logger
}
func (a adapter) Debugln(vals ...interface{}) {
func (a adapter) Debugln(vals ...any) {
a.log(strings.TrimSpace(fmt.Sprintln(vals...)), slog.LevelDebug)
}
func (a adapter) Debugf(format string, vals ...interface{}) {
func (a adapter) Debugf(format string, vals ...any) {
a.log(fmt.Sprintf(format, vals...), slog.LevelDebug)
}
+28 -20
View File
@@ -202,7 +202,7 @@ func (s *service) getListener(guiCfg config.GUIConfiguration) (net.Listener, err
return listener, nil
}
func sendJSON(w http.ResponseWriter, jsonObject interface{}) {
func sendJSON(w http.ResponseWriter, jsonObject any) {
w.Header().Set("Content-Type", "application/json")
// Marshalling might fail, in which case we should return a 500 with the
// actual error.
@@ -696,7 +696,7 @@ func (*service) getSystemPaths(w http.ResponseWriter, _ *http.Request) {
}
func (s *service) getJSMetadata(w http.ResponseWriter, _ *http.Request) {
meta, _ := json.Marshal(map[string]interface{}{
meta, _ := json.Marshal(map[string]any{
"deviceID": s.id.String(),
"deviceIDShort": s.id.Short().String(),
"authenticated": true,
@@ -706,7 +706,7 @@ func (s *service) getJSMetadata(w http.ResponseWriter, _ *http.Request) {
}
func (*service) getSystemVersion(w http.ResponseWriter, _ *http.Request) {
sendJSON(w, map[string]interface{}{
sendJSON(w, map[string]any{
"version": build.Version,
"codename": build.Codename,
"longVersion": build.LongVersion,
@@ -838,7 +838,7 @@ func (s *service) getDBNeed(w http.ResponseWriter, r *http.Request) {
}
// Convert the struct to a more loose structure, and inject the size.
sendJSON(w, map[string]interface{}{
sendJSON(w, map[string]any{
"progress": toJsonFileInfoSlice(progress),
"queued": toJsonFileInfoSlice(queued),
"rest": toJsonFileInfoSlice(rest),
@@ -866,7 +866,7 @@ func (s *service) getDBRemoteNeed(w http.ResponseWriter, r *http.Request) {
return
}
sendJSON(w, map[string]interface{}{
sendJSON(w, map[string]any{
"files": toJsonFileInfoSlice(files),
"page": page,
"perpage": perpage,
@@ -886,7 +886,7 @@ func (s *service) getDBLocalChanged(w http.ResponseWriter, r *http.Request) {
return
}
sendJSON(w, map[string]interface{}{
sendJSON(w, map[string]any{
"files": toJsonFileInfoSlice(files),
"page": page,
"perpage": perpage,
@@ -951,7 +951,7 @@ func (s *service) getDBFile(w http.ResponseWriter, r *http.Request) {
return
}
sendJSON(w, map[string]interface{}{
sendJSON(w, map[string]any{
"global": jsonFileInfo(gf),
"local": jsonFileInfo(lf),
"availability": av,
@@ -967,7 +967,7 @@ func (s *service) getDebugFile(w http.ResponseWriter, r *http.Request) {
gf, _, _ := s.model.CurrentGlobalFile(folder, file)
av, _ := s.model.Availability(folder, protocol.FileInfo{Name: file}, protocol.BlockInfo{})
sendJSON(w, map[string]interface{}{
sendJSON(w, map[string]any{
"global": jsonFileInfo(gf),
"local": jsonFileInfo(lf),
"availability": av,
@@ -1037,7 +1037,7 @@ func (s *service) getSystemStatus(w http.ResponseWriter, _ *http.Request) {
runtime.ReadMemStats(&m)
tilde, _ := fs.ExpandTilde("~")
res := make(map[string]interface{})
res := make(map[string]any)
res["myID"] = s.id.String()
res["goroutines"] = runtime.NumGoroutine()
res["alloc"] = m.Alloc
@@ -1184,10 +1184,7 @@ func (s *service) getSupportBundle(w http.ResponseWriter, r *http.Request) {
}
// Metrics data as text
var metricsBuf bytes.Buffer
wr := bufferedResponseWriter{Writer: &metricsBuf}
promhttp.Handler().ServeHTTP(wr, &http.Request{Method: http.MethodGet})
files = append(files, fileEntry{name: "metrics.txt", data: metricsBuf.Bytes()})
files = append(files, fileEntry{name: "metrics.txt", data: prometheusMetrics()})
// Connection data as JSON
connStats := s.model.ConnectionStats()
@@ -1258,6 +1255,16 @@ func (s *service) getSupportBundle(w http.ResponseWriter, r *http.Request) {
io.Copy(w, &zipFilesBuffer)
}
func prometheusMetrics() []byte {
var metricsBuf bytes.Buffer
wr := bufferedResponseWriter{Writer: &metricsBuf}
promhttp.Handler().ServeHTTP(wr, &http.Request{
Method: http.MethodGet,
URL: &url.URL{Scheme: "http://", Host: "localhost", Path: "/metrics"},
})
return metricsBuf.Bytes()
}
func (s *service) getSystemDiscovery(w http.ResponseWriter, _ *http.Request) {
devices := make(map[string]discover.CacheEntry)
@@ -1302,7 +1309,7 @@ func (s *service) getDBIgnores(w http.ResponseWriter, r *http.Request) {
folder := qs.Get("folder")
lines, patterns, err := s.model.LoadIgnores(folder)
sendJSON(w, map[string]interface{}{
sendJSON(w, map[string]any{
"ignore": lines,
"expanded": patterns,
"error": errorString(err),
@@ -1411,7 +1418,7 @@ func (s *service) getSystemUpgrade(w http.ResponseWriter, _ *http.Request) {
httpError(w, err)
return
}
res := make(map[string]interface{})
res := make(map[string]any)
res["running"] = build.Version
res["latest"] = rel.Tag
res["newer"] = upgrade.CompareVersions(rel.Tag, build.Version) == upgrade.Newer
@@ -1439,7 +1446,7 @@ func (*service) getDeviceID(w http.ResponseWriter, r *http.Request) {
func (*service) getLang(w http.ResponseWriter, r *http.Request) {
lang := r.Header.Get("Accept-Language")
weights := make(map[string]float64)
for _, l := range strings.Split(lang, ",") {
for l := range strings.SplitSeq(lang, ",") {
parts := strings.SplitN(l, ";", 2)
code := strings.ToLower(strings.TrimSpace(parts[0]))
weights[code] = 1.0
@@ -1638,7 +1645,7 @@ func (s *service) getFolderErrors(w http.ResponseWriter, r *http.Request) {
}
}
sendJSON(w, map[string]interface{}{
sendJSON(w, map[string]any{
"folder": folder,
"errors": errors,
"page": page,
@@ -1770,8 +1777,8 @@ func (f jsonFileInfo) MarshalJSON() ([]byte, error) {
return json.Marshal(m)
}
func fileIntfJSONMap(f protocol.FileInfo) map[string]interface{} {
out := map[string]interface{}{
func fileIntfJSONMap(f protocol.FileInfo) map[string]any {
out := map[string]any{
"name": f.FileName(),
"type": f.FileType().String(),
"size": f.Size,
@@ -1946,7 +1953,8 @@ func sanitizedHostname(name string) (string, error) {
return r > unicode.MaxASCII ||
!unicode.IsLetter(r) && !unicode.IsNumber(r) &&
r != '.' && r != '-'
})))
})),
)
name, _, err := transform.String(t, name)
if err != nil {
return "", err
+1 -4
View File
@@ -311,10 +311,7 @@ func authLDAP(username string, password string, cfg config.LDAPConfiguration) bo
func formatOptionalPercentS(template string, username string) string {
var replacements []any
nReps := strings.Count(template, "%s") - strings.Count(template, "%%s")
if nReps < 0 {
nReps = 0
}
nReps := max(strings.Count(template, "%s")-strings.Count(template, "%%s"), 0)
for range nReps {
replacements = append(replacements, username)
}
+9 -2
View File
@@ -433,7 +433,6 @@ func TestAPIServiceRequests(t *testing.T) {
}
for _, tc := range cases {
tc := tc
t.Run(tc.URL, func(t *testing.T) {
t.Parallel()
testHTTPRequest(t, baseURL, tc, testAPIKey)
@@ -1723,7 +1722,7 @@ func TestConfigChanges(t *testing.T) {
return resp
}
mod := func(method, path string, data interface{}) {
mod := func(method, path string, data any) {
t.Helper()
bs, err := json.Marshal(data)
if err != nil {
@@ -1830,6 +1829,14 @@ func TestSanitizedHostname(t *testing.T) {
}
}
func TestPrometheusMetrics(t *testing.T) {
// We should get some form of reasonable metrics response
bs := prometheusMetrics()
if !bytes.Contains(bs, []byte("TYPE go_info gauge")) {
t.Error("metrics should include go_info gauge")
}
}
// runningInContainer returns true if we are inside Docker or LXC. It might
// be prone to false negatives if things change in the future, but likely
// not false positives.
+42
View File
@@ -0,0 +1,42 @@
// Copyright (C) 2026 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package auto
import (
"compress/gzip"
"io"
"strings"
"testing"
)
const customBuildMarker = "It syncs .stignore now!"
func TestCustomBuildMarkerIsEmbedded(t *testing.T) {
asset, ok := Assets()["default/index.html"]
if !ok {
t.Fatal("default/index.html is missing from embedded GUI assets")
}
content := asset.Content
if asset.Gzipped {
reader, err := gzip.NewReader(strings.NewReader(asset.Content))
if err != nil {
t.Fatal(err)
}
defer reader.Close()
data, err := io.ReadAll(reader)
if err != nil {
t.Fatal(err)
}
content = string(data)
}
if !strings.Contains(content, customBuildMarker) {
t.Fatalf("embedded GUI assets do not contain custom build marker %q", customBuildMarker)
}
}
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build noassets
// +build noassets
package auto
+1 -1
View File
@@ -441,7 +441,7 @@ func (c *configMuxBuilder) adjustLDAP(w http.ResponseWriter, r *http.Request, ld
}
// Unmarshals the content of the given body and stores it in to (i.e. to must be a pointer).
func unmarshalTo(body io.ReadCloser, to interface{}) error {
func unmarshalTo(body io.ReadCloser, to any) error {
bs, err := io.ReadAll(body)
body.Close()
if err != nil {
+4
View File
@@ -127,6 +127,10 @@ func LongVersionFor(program string) string {
return v
}
func UserAgent() string {
return fmt.Sprintf(`Syncthing/%s (%s %s-%s)`, strings.TrimPrefix(Version, "v"), runtime.Version(), runtime.GOOS, runtime.GOARCH)
}
func TagsList() []string {
tags := strings.Split(Tags, ",")
if len(tags) == 1 && tags[0] == "" {
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build race
// +build race
package build
+2 -2
View File
@@ -664,7 +664,7 @@ func (defaults *Defaults) prepare(myID protocol.DeviceID, existingDevices map[pr
defaults.Device.prepare(nil)
}
func ensureZeroForNodefault(empty interface{}, target interface{}) {
func ensureZeroForNodefault(empty any, target any) {
copyMatchingTag(empty, target, "nodefault", func(v string) bool {
if len(v) > 0 && v != "true" {
panic(fmt.Sprintf(`unexpected tag value: %s. expected untagged or "true"`, v))
@@ -674,7 +674,7 @@ func ensureZeroForNodefault(empty interface{}, target interface{}) {
}
// copyMatchingTag copies fields tagged tag:"value" from "from" struct onto "to" struct.
func copyMatchingTag(from interface{}, to interface{}, tag string, shouldCopy func(value string) bool) {
func copyMatchingTag(from any, to any, tag string, shouldCopy func(value string) bool) {
fromStruct := reflect.ValueOf(from).Elem()
fromType := fromStruct.Type()
+6 -6
View File
@@ -1158,8 +1158,8 @@ func TestInvalidDeviceIDRejected(t *testing.T) {
// Change the device ID of the first device to "invalid". Fast and loose
// with the type assertions as we know what the JSON decoder returns.
devs := cfg["devices"].([]interface{})
dev0 := devs[0].(map[string]interface{})
devs := cfg["devices"].([]any)
dev0 := devs[0].(map[string]any)
dev0["deviceID"] = tc.id
devs[0] = dev0
@@ -1197,8 +1197,8 @@ func TestInvalidFolderIDRejected(t *testing.T) {
// Change the folder ID of the first folder to the empty string.
// Fast and loose with the type assertions as we know what the JSON
// decoder returns.
devs := cfg["folders"].([]interface{})
dev0 := devs[0].(map[string]interface{})
devs := cfg["folders"].([]any)
dev0 := devs[0].(map[string]any)
dev0["id"] = tc.id
devs[0] = dev0
@@ -1324,7 +1324,7 @@ func adjustFolderConfiguration(cfg *FolderConfiguration, id, label string, fsTyp
// defaultConfigAsMap returns a valid default config as a JSON-decoded
// map[string]interface{}. This is useful to override random elements and
// re-encode into JSON.
func defaultConfigAsMap() map[string]interface{} {
func defaultConfigAsMap() map[string]any {
cfg := New(device1)
dev := cfg.Defaults.Device.Copy()
adjustDeviceConfiguration(&dev, device2, "name")
@@ -1337,7 +1337,7 @@ func defaultConfigAsMap() map[string]interface{} {
// can't happen
panic(err)
}
var tmp map[string]interface{}
var tmp map[string]any
if err := json.Unmarshal(bs, &tmp); err != nil {
// can't happen
panic(err)
+2 -3
View File
@@ -9,6 +9,7 @@ package config
import (
"encoding/json"
"encoding/xml"
"maps"
"slices"
"strings"
@@ -45,9 +46,7 @@ type internalParam struct {
func (c VersioningConfiguration) Copy() VersioningConfiguration {
cp := c
cp.Params = make(map[string]string, len(c.Params))
for k, v := range c.Params {
cp.Params[k] = v
}
maps.Copy(cp.Params, c.Params)
return cp
}
+2 -2
View File
@@ -401,7 +401,7 @@ func TestConnectionEstablishment(t *testing.T) {
}
}
func withConnectionPair(b interface{ Fatal(...interface{}) }, connUri string, h func(client, server internalConn)) {
func withConnectionPair(b interface{ Fatal(...any) }, connUri string, h func(client, server internalConn)) {
// Root of the service tree.
supervisor := suture.New("main", suture.Spec{
PassThroughPanics: true,
@@ -494,7 +494,7 @@ func withConnectionPair(b interface{ Fatal(...interface{}) }, connUri string, h
_ = serverConn.Close()
}
func mustGetCert(b interface{ Fatal(...interface{}) }) tls.Certificate {
func mustGetCert(b interface{ Fatal(...any) }) tls.Certificate {
cert, err := tlsutil.NewCertificateInMemory("bench", 10)
if err != nil {
b.Fatal(err)
+2 -2
View File
@@ -54,7 +54,7 @@ func TestDialQueueSort(t *testing.T) {
var seen1, seen2 int
for i := 0; i < 100; i++ {
for range 100 {
queue.Sort()
res := shortDevices(queue)
if reflect.DeepEqual(res, expected1) {
@@ -90,7 +90,7 @@ func TestDialQueueSort(t *testing.T) {
var seen1, seen2 int
for i := 0; i < 100; i++ {
for range 100 {
queue.Sort()
res := shortDevices(queue)
if reflect.DeepEqual(res, expected1) {
+5 -9
View File
@@ -256,18 +256,14 @@ func (w *limitedWriter) Write(buf []byte) (int, error) {
// try to be a bit adaptable. We range from the minimum write size of 1
// KiB up to the limiter burst size, aiming for about a write every
// 10ms.
singleWriteSize := int(w.waiter.Limit() / 100) // 10ms worth of data
singleWriteSize = ((singleWriteSize / 1024) + 1) * 1024 // round up to the next kibibyte
if singleWriteSize > limiterBurstSize {
singleWriteSize = limiterBurstSize
}
singleWriteSize := int(w.waiter.Limit() / 100) // 10ms worth of data
singleWriteSize = min(
// round up to the next kibibyte
((singleWriteSize/1024)+1)*1024, limiterBurstSize)
written := 0
for written < len(buf) {
toWrite := singleWriteSize
if toWrite > len(buf)-written {
toWrite = len(buf) - written
}
toWrite := min(singleWriteSize, len(buf)-written)
w.take(toWrite)
n, err := w.writer.Write(buf[written : written+toWrite])
written += n
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build go1.15 && !noquic
// +build go1.15,!noquic
package connections
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at http://mozilla.org/MPL/2.0/.
//go:build !noquic
// +build !noquic
package connections
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at http://mozilla.org/MPL/2.0/.
//go:build !noquic
// +build !noquic
package connections
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at http://mozilla.org/MPL/2.0/.
//go:build noquic
// +build noquic
package connections
+6 -6
View File
@@ -18,23 +18,23 @@ import (
type Registry struct {
mut sync.Mutex
available map[string][]interface{}
available map[string][]any
}
func New() *Registry {
return &Registry{
available: make(map[string][]interface{}),
available: make(map[string][]any),
}
}
func (r *Registry) Register(scheme string, item interface{}) {
func (r *Registry) Register(scheme string, item any) {
r.mut.Lock()
defer r.mut.Unlock()
r.available[scheme] = append(r.available[scheme], item)
}
func (r *Registry) Unregister(scheme string, item interface{}) {
func (r *Registry) Unregister(scheme string, item any) {
r.mut.Lock()
defer r.mut.Unlock()
@@ -49,12 +49,12 @@ func (r *Registry) Unregister(scheme string, item interface{}) {
// Get returns an item for a schema compatible with the given scheme.
// If any item satisfies preferred, that has precedence over other items.
func (r *Registry) Get(scheme string, preferred func(interface{}) bool) interface{} {
func (r *Registry) Get(scheme string, preferred func(any) bool) any {
r.mut.Lock()
defer r.mut.Unlock()
var (
best interface{}
best any
bestPref bool
bestScheme string
)
+4 -4
View File
@@ -14,8 +14,8 @@ import (
func TestRegistry(t *testing.T) {
r := New()
want := func(i int) func(interface{}) bool {
return func(x interface{}) bool { return x.(int) == i }
want := func(i int) func(any) bool {
return func(x any) bool { return x.(int) == i }
}
if res := r.Get("int", want(1)); res != nil {
@@ -73,7 +73,7 @@ func TestShortSchemeFirst(t *testing.T) {
r.Register("foobar", 1)
// If we don't care about the value, we should get the one with "foo".
res := r.Get("foo", func(interface{}) bool { return false })
res := r.Get("foo", func(any) bool { return false })
if res != 0 {
t.Error("unexpected", res)
}
@@ -89,7 +89,7 @@ func BenchmarkGet(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
r.Get("tcp", func(x interface{}) bool {
r.Get("tcp", func(x any) bool {
return x.(*net.TCPAddr).IP.IsUnspecified()
})
}
+3 -4
View File
@@ -19,6 +19,7 @@ import (
"fmt"
"io"
"log/slog"
"maps"
"math"
"net"
"net/url"
@@ -817,7 +818,7 @@ func (s *service) createListener(factory listenerFactory, uri *url.URL) bool {
}
func (s *service) logListenAddressesChangedEvent(l ListenerAddresses) {
s.evLogger.Log(events.ListenAddressesChanged, map[string]interface{}{
s.evLogger.Log(events.ListenAddressesChanged, map[string]any{
"address": l.URI,
"lan": l.LANAddresses,
"wan": l.WANAddresses,
@@ -995,9 +996,7 @@ func newConnectionStatusHandler() connectionStatusHandler {
func (s *connectionStatusHandler) ConnectionStatus() map[string]ConnectionStatusEntry {
result := make(map[string]ConnectionStatusEntry)
s.connectionStatusMut.RLock()
for k, v := range s.connectionStatus {
result[k] = v
}
maps.Copy(result, s.connectionStatus)
s.connectionStatusMut.RUnlock()
return result
}
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build !solaris && !windows
// +build !solaris,!windows
package dialer
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build solaris
// +build solaris
package dialer
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build windows
// +build windows
package dialer
+1 -1
View File
@@ -111,7 +111,7 @@ func DialContextReusePortFunc(registry *registry.Registry) func(ctx context.Cont
return DialContext(ctx, network, addr)
}
localAddrInterface := registry.Get(network, func(addr interface{}) bool {
localAddrInterface := registry.Get(network, func(addr any) bool {
return addr.(*net.TCPAddr).IP.IsUnspecified()
})
if localAddrInterface == nil {
+2 -3
View File
@@ -7,6 +7,7 @@
package discover
import (
"maps"
"sync"
"time"
@@ -60,9 +61,7 @@ func (c *cache) Get(id protocol.DeviceID) (CacheEntry, bool) {
func (c *cache) Cache() map[protocol.DeviceID]CacheEntry {
c.mut.Lock()
m := make(map[protocol.DeviceID]CacheEntry, len(c.entries))
for k, v := range c.entries {
m[k] = v
}
maps.Copy(m, c.entries)
c.mut.Unlock()
return m
}
+3
View File
@@ -25,6 +25,7 @@ import (
"golang.org/x/net/http2"
"github.com/syncthing/syncthing/internal/slogutil"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/connections/registry"
"github.com/syncthing/syncthing/lib/dialer"
"github.com/syncthing/syncthing/lib/events"
@@ -454,6 +455,7 @@ func (c *contextClient) Get(ctx context.Context, url string) (*http.Response, er
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", build.UserAgent())
return c.Client.Do(req)
}
@@ -463,6 +465,7 @@ func (c *contextClient) Post(ctx context.Context, url, ctype string, data io.Rea
return nil, err
}
req.Header.Set("Content-Type", ctype)
req.Header.Set("User-Agent", build.UserAgent())
return c.Client.Do(req)
}
+1 -1
View File
@@ -294,7 +294,7 @@ func (c *localClient) registerDevice(src net.Addr, device *discoproto.Announce)
})
if isNewDevice {
c.evLogger.Log(events.DeviceDiscovered, map[string]interface{}{
c.evLogger.Log(events.DeviceDiscovered, map[string]any{
"device": id.String(),
"addrs": validAddresses,
})
+7 -7
View File
@@ -235,7 +235,7 @@ const BufferSize = 64
type Logger interface {
suture.Service
Log(t EventType, data interface{})
Log(t EventType, data any)
Subscribe(mask EventType) Subscription
}
@@ -253,10 +253,10 @@ type Event struct {
// Per-subscription sequential event ID. Named "id" for backwards compatibility with the REST API
SubscriptionID int `json:"id"`
// Global ID of the event across all subscriptions
GlobalID int `json:"globalID"`
Time time.Time `json:"time"`
Type EventType `json:"type"`
Data interface{} `json:"data"`
GlobalID int `json:"globalID"`
Time time.Time `json:"time"`
Type EventType `json:"type"`
Data any `json:"data"`
}
type Subscription interface {
@@ -325,7 +325,7 @@ loop:
return nil
}
func (l *logger) Log(t EventType, data interface{}) {
func (l *logger) Log(t EventType, data any) {
l.events <- Event{
Time: time.Now(), // intentionally high precision
Type: t,
@@ -559,7 +559,7 @@ var NoopLogger Logger = &noopLogger{}
func (*noopLogger) Serve(_ context.Context) error { return nil }
func (*noopLogger) Log(_ EventType, _ interface{}) {}
func (*noopLogger) Log(_ EventType, _ any) {}
func (*noopLogger) Subscribe(_ EventType) Subscription {
return &noopSubscription{}
+4 -4
View File
@@ -127,7 +127,7 @@ func TestBufferOverflow(t *testing.T) {
t0 := time.Now()
const nEvents = BufferSize * 2
for i := 0; i < nEvents; i++ {
for range nEvents {
l.Log(DeviceConnected, "foo")
}
if d := time.Since(t0); d > 15*time.Second {
@@ -237,7 +237,7 @@ func TestBufferedSub(t *testing.T) {
bs := NewBufferedSubscription(s, 10*BufferSize)
go func() {
for i := 0; i < 10*BufferSize; i++ {
for i := range 10 * BufferSize {
l.Log(DeviceConnected, fmt.Sprintf("event-%d", i))
if i%30 == 0 {
// Give the buffer routine time to pick up the events
@@ -378,7 +378,7 @@ func TestUnsubscribeContention(t *testing.T) {
stopListeners := make(chan struct{})
var listenerWg sync.WaitGroup
for i := 0; i < listeners; i++ {
for range listeners {
listenerWg.Go(func() {
s := l.Subscribe(AllEvents)
defer s.Unsubscribe()
@@ -400,7 +400,7 @@ func TestUnsubscribeContention(t *testing.T) {
stopSenders := make(chan struct{})
defer close(stopSenders)
var senderWg sync.WaitGroup
for i := 0; i < senders; i++ {
for range senders {
senderWg.Go(func() {
t := time.NewTicker(time.Millisecond)
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build linux
// +build linux
package fs
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build windows
// +build windows
package fs
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build linux
// +build linux
package fs
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build linux || solaris
// +build linux solaris
package fs
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build !windows
// +build !windows
package fs
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build linux || android
// +build linux android
package fs
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build !linux && !android && !windows
// +build !linux,!android,!windows
package fs
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build windows
// +build windows
package fs
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build !windows
// +build !windows
package fs
+1 -1
View File
@@ -580,7 +580,7 @@ func TestXattr(t *testing.T) {
// Create a set of random attributes that we will set and read back
var attrs []protocol.Xattr
for i := 0; i < 10; i++ {
for i := range 10 {
key := fmt.Sprintf("user.test-%d", i)
value := make([]byte, xattrSize())
rand.Read(value)
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build !windows
// +build !windows
package fs
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at http://mozilla.org/MPL/2.0/.
//go:build linux
// +build linux
package fs
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at http://mozilla.org/MPL/2.0/.
//go:build !linux
// +build !linux
package fs
@@ -5,7 +5,6 @@
// You can obtain one at http://mozilla.org/MPL/2.0/.
//go:build darwin && !kqueue && cgo && !ios
// +build darwin,!kqueue,cgo,!ios
package fs
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at http://mozilla.org/MPL/2.0/.
//go:build solaris && cgo
// +build solaris,cgo
package fs
@@ -5,7 +5,6 @@
// You can obtain one at http://mozilla.org/MPL/2.0/.
//go:build linux
// +build linux
package fs
@@ -5,7 +5,6 @@
// You can obtain one at http://mozilla.org/MPL/2.0/.
//go:build dragonfly || freebsd || netbsd || openbsd || ios || kqueue
// +build dragonfly freebsd netbsd openbsd ios kqueue
package fs
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at http://mozilla.org/MPL/2.0/.
//go:build !linux && !windows && !dragonfly && !freebsd && !netbsd && !openbsd && !solaris && !darwin && !cgo && !ios
// +build !linux,!windows,!dragonfly,!freebsd,!netbsd,!openbsd,!solaris,!darwin,!cgo,!ios
// Catch all platforms that are not specifically handled to use the generic
// event types.
@@ -5,7 +5,6 @@
// You can obtain one at http://mozilla.org/MPL/2.0/.
//go:build windows
// +build windows
package fs
-1
View File
@@ -5,7 +5,6 @@
// You can obtain one at http://mozilla.org/MPL/2.0/.
//go:build !dragonfly && !freebsd && !netbsd && !openbsd && !kqueue && !ios
// +build !dragonfly,!freebsd,!netbsd,!openbsd,!kqueue,!ios
package fs

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