GNU bug report logs - #75959
[PATCH] (home-)syncthing-service: added support for config serialization

Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.

Package: guix-patches; Reported by: Zacchaeus <eikcaz@HIDDEN>; Keywords: patch; dated Fri, 31 Jan 2025 04:18:03 UTC; Maintainer for guix-patches is guix-patches@HIDDEN.

Message received at 75959 <at> debbugs.gnu.org:


Received: (at 75959) by debbugs.gnu.org; 1 Feb 2025 08:58:59 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Feb 01 03:58:59 2025
Received: from localhost ([127.0.0.1]:56232 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1te9L8-0004iT-MD
	for submit <at> debbugs.gnu.org; Sat, 01 Feb 2025 03:58:59 -0500
Received: from [47.204.136.169] (port=52960 helo=hun.zacchae.us)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <eikcaz@HIDDEN>) id 1te9L6-0004iD-O4
 for 75959 <at> debbugs.gnu.org; Sat, 01 Feb 2025 03:58:57 -0500
DKIM-Signature: v=1; a=ed25519-sha256; q=dns/txt; c=relaxed/relaxed;
 d=zacchae.us; s=my_ed_sel; h=Content-Type:MIME-Version:Message-ID:Date:
 Subject:To:From:Sender:Reply-To:Cc:Content-Transfer-Encoding:Content-ID:
 Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc
 :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:
 List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=0ZSYgPCZIg40wM3od4xf4ZW3dE/+RIQJH4MGOJOe6yE=; i=zacchae.us; b=JbxATJ083WmX
 QiIH48KnVtx1+VV5gvrCEzNuWMMUFiQ7ocE5IU+Nnca2GtL3tXPjiW6tIRo6QLY5eVtNfMleAw==; 
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=zacchae.us; 
 s=my_rsa_sel;
 h=Content-Type:MIME-Version:Message-ID:Date:Subject:To:From:
 Sender:Reply-To:Cc:Content-Transfer-Encoding:Content-ID:Content-Description:
 Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:
 In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:
 List-Post:List-Owner:List-Archive;
 bh=0ZSYgPCZIg40wM3od4xf4ZW3dE/+RIQJH4MGOJOe6yE=; i=zacchae.us; b=VBMr4/TpADRT
 90WcHr9oV8mu9b7leI+wj87Jorbd/6HPKES3o6ryWMtCQc4kcOkxupqzgiSaPLDVKFjo5ntebdXro
 FkF2QWFZvKJsK3mm62P3PyLsCD2TxrYxlSO6xWbFWWCxBEA9QB1xpJFl+UhNYpzxuGeJCbWl0yNMg
 orXE1v/NjCOCLi0+W2x/D/fe+n3q4i3rCFPIWdpqAYTAdMOhzLjTS9r42UM72RxhK5jihSUNf+G6y
 qxOe3yoJ6LsulKhA+P3/FBq5wDGTA6SP2YY7szOh0N3NNwZ1wYmVNBxmxUtZp9gN1GnnOJ5LvAwUh
 WqOuW+4zc3Q2DrPsDi/NVA==;
Received: from localhost.home ([127.0.0.1]:37806 helo=hun)
 by hun.zacchae.us with esmtps (TLS1.3) tls
 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98)
 (envelope-from <eikcaz@HIDDEN>) id 1te9Ky-000000005Mo-1jXp
 for 75959 <at> debbugs.gnu.org; Sat, 01 Feb 2025 03:58:48 -0500
From: Zacchaeus <eikcaz@HIDDEN>
To: 75959 <at> debbugs.gnu.org
Subject: Re: [PATCH] (home-)syncthing-service: added support for config
 serialization
Date: Sat, 01 Feb 2025 03:58:48 -0500
Message-ID: <87bjvmjb1z.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain
X-Spam-Score: 1.3 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 Content preview:  Hi Guix! In order to test my implementation, I compared two
 pairs of configs: - the default config generated by syncthing with the default
 config generated by (syncthing-configuration (syncthing-config-file
 (syncthing-config-file))).
 Content analysis details:   (1.3 points, 10.0 required)
 pts rule name              description
 ---- ---------------------- --------------------------------------------------
 0.0 RCVD_IN_VALIDITY_SAFE_BLOCKED RBL: ADMINISTRATOR NOTICE: The
 query to Validity was blocked.  See
 https://knowledge.validity.com/hc/en-us/articles/20961730681243
 for more information.
 [47.204.136.169 listed in sa-accredit.habeas.com]
 0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
 -0.0 SPF_PASS               SPF: sender matches SPF record
 0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The
 query to Validity was blocked.  See
 https://knowledge.validity.com/hc/en-us/articles/20961730681243
 for more information.
 [47.204.136.169 listed in bl.score.senderscore.com]
 1.3 RDNS_NONE Delivered to internal network by a host with no rDNS
X-Debbugs-Envelope-To: 75959
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 0.3 (/)

Hi Guix!


In order to test my implementation, I compared two pairs of configs:

 - the default config generated by syncthing with the default config
   generated by (syncthing-configuration (syncthing-config-file
   (syncthing-config-file))).

 - my syncthing-gui-generated config with the config generated by a
   syncthing-config-file reflecting my (rather complex) setup.

There are a few differences:

 - The core differences hinge around the fact that the current device ID
   is not known in advance.  Of course, if you have already run
   syncthing and know your device ID, you can specify that in your
   config.

   - The default ~/Sync folder normally includes the current device.
     The documentaiton makes it clear that this is OK (and also I have
     tested this).

   - The config does not include the current device.  The documentation
     says "One or more device elements must be present in the file", but
     it seems to work fine dispite this.

   - The default folder template normally includes the current device.
     Also fine.

 - There are also three miscelaneous differences:

   - The default device template normally omits the "name" field.  I
     suppose I could have added code to fix this, but I know it doesn't
     break anything so I opted for slightly simpler code.

   - The API key doesn't match.  Of course it doesn't.

   - The ~/Sync folder is normally specified by /home/<user>/Sync, but
     since I know ~/Sync works, I found that better than trying to
     compute ~/ in scheme.
   
In summary, there are differences, but those differences have been
accounted for and don't introduce bugs.  There were a few undocumented
behaviors around the absense or presense of a value.  In such cases, I
implemented whatever behavior was observed in a config file maintained
by the Syncthing GUI.

I considered submitting this as two patches, one for the home service
and one for the system service, but patching just the system service
broke the home service.  Is that a valid reason to make it one patch?
If not, I can split up the patches and resubmit.

Addressing the elephant in the room, as I mentioned in the
documentation, I used camelCase only to match syncthing documentation.
For instance, the ldap searchFilter setting is configured by
(syncthing-config-file (ldap-searchFilter "...")).  As nauseous as it
made me to write something like that, I think translating names to
snake-case adds too much confusion/complexity no matter where you add
it.  It is useful when refencencing Syncthing documentation to know
exactly what keyword too look for.  Though I believe exceptions exist to
every rule, and that this is maybe the only ecxeption to the no
camelcase rule, please do tell me if there is a better way and I will
resubmit the patch.


eikcaz-




Information forwarded to guix-patches@HIDDEN:
bug#75959; Package guix-patches. Full text available.

Message received at submit <at> debbugs.gnu.org:


Received: (at submit) by debbugs.gnu.org; 31 Jan 2025 04:17:38 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Jan 30 23:17:38 2025
Received: from localhost ([127.0.0.1]:48851 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tdiTH-0001pQ-Vs
	for submit <at> debbugs.gnu.org; Thu, 30 Jan 2025 23:17:38 -0500
Received: from lists.gnu.org ([2001:470:142::17]:54118)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <eikcaz@HIDDEN>) id 1tdccl-0007O5-Vc
 for submit <at> debbugs.gnu.org; Thu, 30 Jan 2025 17:03:02 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eikcaz@HIDDEN>) id 1tdccc-0006O8-CK
 for guix-patches@HIDDEN; Thu, 30 Jan 2025 17:02:50 -0500
Received: from [47.204.136.169] (helo=hun.zacchae.us)
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eikcaz@HIDDEN>) id 1tdccY-0003xA-Id
 for guix-patches@HIDDEN; Thu, 30 Jan 2025 17:02:50 -0500
DKIM-Signature: v=1; a=ed25519-sha256; q=dns/txt; c=relaxed/relaxed;
 d=zacchae.us; s=my_ed_sel; h=Content-Transfer-Encoding:Content-Type:
 MIME-Version:Message-ID:Date:Subject:To:From:Sender:Reply-To:Cc:Content-ID:
 Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc
 :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:
 List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=R5kdJCRRt3O/oAWwGScGfxmSrZTOLpVp23UzckEGeco=; i=zacchae.us; b=+TEHxkxlELoD
 FMDhHTEZhtLqqYixJBK42lS0KbPCaDoUOexuiSXTnxl181x9QpS5hqo0M+Zug63TLYzFCrHWDQ==; 
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=zacchae.us; 
 s=my_rsa_sel;
 h=Content-Transfer-Encoding:Content-Type:MIME-Version:
 Message-ID:Date:Subject:To:From:Sender:Reply-To:Cc:Content-ID:
 Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc
 :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:
 List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=R5kdJCRRt3O/oAWwGScGfxmSrZTOLpVp23UzckEGeco=; i=zacchae.us; b=UbnHx/F1vj9z
 lOmioXoACwf0AhMrId+nBe5d542p+0nAO+G3i3zWdUrHT4g5NLPoYS3GEufGVQwp4Ay2ggz6RQ6O7
 vOY3VoGr5mFJU3QRgut7WuGZYTkhH9/So6kn1oYBj5FbvbGYvmQHRe8vX1FPE85H+Q2LAxD8zgtjV
 ozRFE/QdY8h7dbZuVFpttZcKYPCBtHqrebd+CKfAzQfjcIVz3Ie7hQrVy664ftsAxdrB8iZvgfhnQ
 GCadIVV+eZrW6jtcleCeJS7YZPhvTWRY7V+gZbj0SmN1VFQQZAF4eeHTZfeUivBRazNeG8N9lHc5t
 kVKs260Q2bfDMr02NhUChg==;
Received: from localhost.home ([127.0.0.1]:43730 helo=hun)
 by hun.zacchae.us with esmtps (TLS1.3) tls
 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98)
 (envelope-from <eikcaz@HIDDEN>) id 1tdccV-000000000Iw-2hrB;
 Thu, 30 Jan 2025 17:02:44 -0500
From: Zacchaeus <eikcaz@HIDDEN>
To: guix-patches@HIDDEN
Subject: [PATCH] (home-)syncthing-service: added support for config
 serialization
Date: Thu, 30 Jan 2025 13:59:12 -0800
Message-ID: <20250130215954.9394-1-eikcaz@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Host-Lookup-Failed: Reverse DNS lookup failed for 47.204.136.169 (failed)
Received-SPF: pass client-ip=47.204.136.169; envelope-from=eikcaz@HIDDEN;
 helo=hun.zacchae.us
X-Spam_score_int: -7
X-Spam_score: -0.8
X-Spam_bar: /
X-Spam_report: (-0.8 / 5.0 requ) BAYES_00=-1.9, DKIM_INVALID=0.1,
 DKIM_SIGNED=0.1, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001,
 RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001,
 SPF_PASS=-0.001, T_FILL_THIS_FORM_SHORT=0.01,
 URIBL_SBL_A=0.1 autolearn=no autolearn_force=no
X-Spam_action: no action
X-Spam-Score: 1.7 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 Content preview: From 48c227546ea15aadbd5f5832d8cd30887f65ace9 Mon Sep 17
 00:00:00
 2001 From: Zacchaeus <eikcaz@HIDDEN> Date: Sun, 21 Jul 2024 00:54:25
 -0700 Subject: [PATCH] (home-)syncthing-service: added suppor [...] 
 Content analysis details:   (1.7 points, 10.0 required)
 pts rule name              description
 ---- ---------------------- --------------------------------------------------
 0.1 URIBL_SBL_A Contains URL's A record listed in the Spamhaus SBL
 blocklist [URIs: docs.syncthing.net]
 0.6 URIBL_SBL Contains an URL's NS IP listed in the Spamhaus SBL
 blocklist [URIs: docs.syncthing.net]
 -0.0 RCVD_IN_DNSWL_NONE     RBL: Sender listed at https://www.dnswl.org/,
 no trust [2001:470:142:0:0:0:0:17 listed in] [list.dnswl.org]
 -0.0 SPF_HELO_PASS          SPF: HELO matches SPF record
 0.9 SPF_FAIL               SPF: sender does not match SPF record (fail)
 [SPF failed: Please see http://www.openspf.org/Why?s=mfrom;
 id=eikcaz%40zacchae.us; ip=2001%3A470%3A142%3A%3A17; r=debbugs.gnu.org]
 0.0 T_FILL_THIS_FORM_SHORT Fill in a short form with personal
 information
X-Debbugs-Envelope-To: submit
X-Mailman-Approved-At: Thu, 30 Jan 2025 23:17:30 -0500
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 0.7 (/)

From 48c227546ea15aadbd5f5832d8cd30887f65ace9 Mon Sep 17 00:00:00 2001
From: Zacchaeus <eikcaz@HIDDEN>
Date: Sun, 21 Jul 2024 00:54:25 -0700
Subject: [PATCH] (home-)syncthing-service: added support for config
 serialization

Change-Id: I87eeba1ee1fdada8f29c2ee881fbc6bc4113dde9
---
 doc/guix.texi                   | 281 ++++++++++++++++++-
 gnu/home/services/syncthing.scm |  17 +-
 gnu/services/syncthing.scm      | 459 +++++++++++++++++++++++++++++++-
 3 files changed, 752 insertions(+), 5 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index b1b6d98e74..966fe852a4 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -136,6 +136,7 @@ Copyright @copyright{} 2024 Troy Figiel@*
 Copyright @copyright{} 2024 Sharlatan Hellseher@*
 Copyright @copyright{} 2024 45mg@*
 Copyright @copyright{} 2025 S=C3=B6ren Tempel@*
+Copyright @copyright{} 2025 Zacchaeus@*
=20
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -22669,8 +22670,284 @@ This assumes that the specified group exists.
 Common configuration and data directory.  The default configuration
 directory is @file{$HOME} of the specified Syncthing @code{user}.
=20
-@end table
-@end deftp
+@item @code{syncthing-config-file} (default: @var{#f})
+Either a file-like object that resolves to a syncthing configuraton xml
+file, or a syncthing-config-file record (see below).
+
+@end table
+@end deftp
+
+In the below, only details specific to Guix, or related to how your
+device will ``ping'' others, are presented.  Otherwise, you should
+consult @uref{https://docs.syncthing.net/users/config.html, Syncthing
+config documentation}.  Camelcase is preserved below only as to be
+consistent with its appearance in Syncthing code/documentation.  If you
+would like to migrate to Guix-powerd Syncthing configuration, the
+generated config adds newlines/whitespace to the produced config such
+that your old config can be diff'ed with the new one.
+
+@deftp {Data Type} syncthing-config-file
+Data type representing the configuration file read by the syncthing
+daemon.
+
+@table @asis
+@item @code{folders} (default: @var{(list (syncthing-folder (id "default")=
 (label "Default Folder") (path "~/Sync")))}
+The default here is the same as Syncthing's default.  The value should
+be a list of @code{syncthing-folder}s.
+
+@item @code{devices} (default: @var{'()}
+This should be a list of @code{syncthing-device}s, or strings correspondin=
g to
+the device ids.  A device entry corresponding to the current device is
+silently ignored by Syncthing.
+
+@item @code{gui-enabled} (default: @var{"true"})
+By default, any user on the computer can access the GUI and make changes
+to Syncthing.  If you leave this enabled, you should probably set
+gui-user and gui-password (see belowe).
+
+@item @code{gui-tls} (default: @var{"false"})
+@item @code{gui-debugging} (default: @var{"false"})
+@item @code{gui-sendBasicAuthPrompt} (default: @var{"false"})
+@item @code{gui-address} (default: @var{"127.0.0.1:8384"})
+@item @code{gui-user} (default: @var{#f})
+@item @code{gui-password} (default: @var{#f})
+@item @code{gui-apikey} (default: @var{"Vuky3VHVseQEoSk9YgxhSkNTnjQmqYK9"})
+@item @code{gui-theme} (default: @var{"default"})
+@item @code{ldap-enabled} (default: @var{#f})
+@item @code{ldap-address} (default: @var{""})
+@item @code{ldap-bindDN} (default: @var{""})
+@item @code{ldap-transport} (default: @var{""})
+@item @code{ldap-insecureSkipVerify} (default: @var{""})
+@item @code{ldap-searchBaseDN} (default: @var{""})
+@item @code{ldap-searchFilter} (default: @var{""})
+@item @code{listenAddress} (default: @var{"default"})
+@item @code{globalAnnounceServer} (default: @var{"default"})
+@item @code{globalAnnounceEnabled} (default: @var{"true"})
+Global discovery servers can be used to help connect devices at unknown
+IP addresses by storing the last known IP address.
+
+@item @code{localAnnounceEnabled} (default: @var{"true"})
+This makes devices find eachother very easily on the same LAN.  Often,
+this will allow you to just plug an ethernet between two devices, or
+connect one device to the other's hotspot and start syncing.
+
+@item @code{localAnnouncePort} (default: @var{"21027"})
+@item @code{localAnnounceMCAddr} (default: @var{"[ff12::8384]:21027"})
+@item @code{maxSendKbps} (default: @var{"0"})
+@item @code{maxRecvKbps} (default: @var{"0"})
+@item @code{reconnectionIntervalS} (default: @var{"60"})
+@item @code{relaysEnabled} (default: @var{"true"})
+This option allows your Syncthing instance to coordinate with a global
+network of relays to enable syncing between devices when all other
+methods fail.
+
+@item @code{relayReconnectIntervalM} (default: @var{"10"})
+@item @code{startBrowser} (default: @var{"true"})
+@item @code{natEnabled} (default: @var{"true"})
+@item @code{natLeaseMinutes} (default: @var{"60"})
+@item @code{natRenewalMinutes} (default: @var{"30"})
+@item @code{natTimeoutSeconds} (default: @var{"10"})
+@item @code{urAccepted} (default: @var{"0"})
+ur* options control usage reporting.  Set to -1 to disable, or positive
+to enable.  The default (0) has reporting disabled, but you will be
+asked to decide in the GUI.
+
+@item @code{urSeen} (default: @var{"0"})
+@item @code{urUniqueID} (default: @var{""})
+@item @code{urURL} (default: @var{"https://data.syncthing.net/newdata"})
+@item @code{urPostInsecurely} (default: @var{"false"})
+@item @code{urInitialDelayS} (default: @var{"1800"})
+@item @code{autoUpgradeIntervalH} (default: @var{"12"})
+@item @code{upgradeToPreReleases} (default: @var{"false"})
+@item @code{keepTemporariesH} (default: @var{"24"})
+@item @code{cacheIgnoredFiles} (default: @var{"false"})
+@item @code{progressUpdateIntervalS} (default: @var{"5"})
+@item @code{limitBandwidthInLan} (default: @var{"false"})
+@item @code{minHomeDiskFree-unit} (default: @var{"%"})
+@item @code{minHomeDiskFree} (default: @var{"1"})
+@item @code{releasesURL} (default: @var{"https://upgrades.syncthing.net/me=
ta.json"})
+@item @code{overwriteRemoteDeviceNamesOnConnect} (default: @var{"false"})
+@item @code{tempIndexMinBlocks} (default: @var{"10"})
+@item @code{unackedNotificationID} (default: @var{"authenticationUserAndPa=
ssword"})
+@item @code{trafficClass} (default: @var{"0"})
+@item @code{setLowPriority} (default: @var{"true"})
+@item @code{maxFolderConcurrency} (default: @var{"0"})
+@item @code{crashReportingURL} (default: @var{"https://crash.syncthing.net=
/newcrash"})
+@item @code{crashReportingEnabled} (default: @var{"true"})
+@item @code{stunKeepaliveStartS} (default: @var{"180"})
+@item @code{stunKeepaliveMinS} (default: @var{"20"})
+@item @code{stunServer} (default: @var{"default"})
+@item @code{databaseTuning} (default: @var{"auto"})
+@item @code{maxConcurrentIncomingRequestKiB} (default: @var{"0"})
+@item @code{announceLANAddresses} (default: @var{"true"})
+@item @code{sendFullIndexOnUpgrade} (default: @var{"false"})
+@item @code{connectionLimitEnough} (default: @var{"0"})
+@item @code{connectionLimitMax} (default: @var{"0"})
+@item @code{insecureAllowOldTLSVersions} (default: @var{"false"})
+@item @code{connectionPriorityTcpLan} (default: @var{"10"})
+@item @code{connectionPriorityQuicLan} (default: @var{"20"})
+@item @code{connectionPriorityTcpWan} (default: @var{"30"})
+@item @code{connectionPriorityQuicWan} (default: @var{"40"})
+@item @code{connectionPriorityRelay} (default: @var{"50"})
+@item @code{connectionPriorityUpgradeThreshold} (default: @var{"0"})
+@item @code{default-folder} (default: @var{(syncthing-folder (label ""))})
+@item @code{default-device} (default: @var{(syncthing-device (id ""))})
+@item @code{default-ignores} (default: @var{"")})
+The default-* above do not affect folders and devices added by the Guix
+interface.  They will, however, affect folders and devices that are
+added through the GUI, or by an ``introducer''.
+@end table
+@end deftp
+
+@deftp {Data Type} syncthing-device
+Data type representing a device to sync with.
+
+@table @asis
+@item @code{id}
+A long hash tied to the keys generated by Syncthing on the first launch.
+You can obtain this from the Syncthing GUI or by inpsecting an existing
+Syncthing configuration file.
+
+@item @code{name} (default: @var{""})
+Human readable device name for viewing in the GUI or in scheme.
+
+@item @code{compression} (default: @var{"metadata"})
+@item @code{introducer} (default: @var{"false"})
+@item @code{skipIntroductionRemovals} (default: @var{"false"})
+@item @code{introducedBy} (default: @var{""})
+@item @code{addresses} (default: @var{'("dynamic")})
+List of addresses at which to search for this device.  The special value
+``dynamic'' will have syncthing use several means to find the device.
+
+@item @code{paused} (default: @var{"false"})
+@item @code{autoAcceptFolders} (default: @var{"false"})
+@item @code{maxSendKbps} (default: @var{"0"})
+@item @code{maxRecvKbps} (default: @var{"0"})
+@item @code{maxRequestKiB} (default: @var{"0"})
+@item @code{untrusted} (default: @var{"false"})
+@item @code{remoteGUIPort} (default: @var{"0"})
+@item @code{numConnections} (default: @var{"0")})
+
+@end table
+@end deftp
+
+@deftp {Data Type} syncthing-folder
+Data type representing a folder to be synced.
+
+@table @asis
+@item @code{id} (default: @var{#f})
+This id cannot match the id of any other folder on this device.  If left
+unspecified, it will default to the label (see below).
+
+@item @code{label}
+Human readable label for the folder.
+
+@item @code{path}
+The path at which to store this folder.
+
+@item @code{type} (default: @var{"sendreceive"})
+@item @code{rescanIntervalS} (default: @var{"3600"})
+@item @code{fsWatcherEnabled} (default: @var{"true"})
+@item @code{fsWatcherDelayS} (default: @var{"10"})
+@item @code{ignorePerms} (default: @var{"false"})
+@item @code{autoNormalize} (default: @var{"true"})
+@item @code{devices} (default: @var{'()})
+Devices should be a list of other Syncthing devices.  If the current
+device is included, it is silently ignored by syncthing (which makes for
+lazier scheme code).  Each device can be listed as a string representing
+the device id, a @code{syncthing-device} object, or a
+@code{syncthing-folder-device} object.
+
+@item @code{filesystemType} (default: @var{"basic"})
+@item @code{minDiskFree-unit} (default: @var{"%"})
+@item @code{minDiskFree} (default: @var{"1"})
+@item @code{versioning-type} (default: @var{#f})
+@item @code{versioning-fsPath} (default: @var{""})
+@item @code{versioning-fsType} (default: @var{"basic"})
+@item @code{versioning-cleanupIntervalS} (default: @var{"3600"})
+@item @code{versioning-cleanoutDays} (default: @var{#f})
+@item @code{versioning-keep} (default: @var{#f})
+@item @code{versioning-maxAge} (default: @var{#f})
+@item @code{versioning-command} (default: @var{#f})
+@item @code{copiers} (default: @var{"0"})
+@item @code{pullerMaxPendingKiB} (default: @var{"0"})
+@item @code{hashers} (default: @var{"0"})
+@item @code{order} (default: @var{"random"})
+@item @code{ignoreDelete} (default: @var{"false"})
+@item @code{scanProgressIntervalS} (default: @var{"0"})
+@item @code{pullerPauseS} (default: @var{"0"})
+@item @code{maxConflicts} (default: @var{"10"})
+@item @code{disableSparseFiles} (default: @var{"false"})
+@item @code{disableTempIndexes} (default: @var{"false"})
+@item @code{paused} (default: @var{"false"})
+@item @code{weakHashThresholdPct} (default: @var{"25"})
+@item @code{markerName} (default: @var{".stfolder"})
+@item @code{copyOwnershipFromParent} (default: @var{"false"})
+@item @code{modTimeWindowS} (default: @var{"0"})
+@item @code{maxConcurrentWrites} (default: @var{"2"})
+@item @code{disableFsync} (default: @var{"false"})
+@item @code{blockPullOrder} (default: @var{"standard"})
+@item @code{copyRangeMethod} (default: @var{"standard"})
+@item @code{caseSensitiveFS} (default: @var{"false"})
+@item @code{junctionsAsDirs} (default: @var{"false"})
+@item @code{syncOwnership} (default: @var{"false"})
+@item @code{sendOwnership} (default: @var{"false"})
+@item @code{syncXattrs} (default: @var{"false"})
+@item @code{sendXattrs} (default: @var{"false"})
+@item @code{xattrFilter-maxSingleEntrySize} (default: @var{"1024"})
+@item @code{xattrFilter-maxTotalSize} (default: @var{"4096")})
+@end table
+@end deftp
+
+@deftp {Data Type} syncthing-folder-device
+There is some configuration which is specific to the relationship
+between a specific folder and a specific device.  If you are fine
+leaving these as their default, then you can simply specify a
+syncthing-device instead of a syncthing-folder-device.
+
+@table @asis
+@item @code{id} (default: @var{""})
+id can be provided as a string of the id, or a @code{syncthing-device}.
+
+@item @code{introducedBy} (default: @var{""})
+@item @code{encryptionPassword} (default: @var{""})
+if encryptionPassword is non-empty, then it will be used as a password
+to encrypt file chunks as they are synced to that device.  For more info
+on syncing to devices you don't totally trust, see
+@uref{https://docs.syncthing.net/users/untrusted.html, Syncthing Documenta=
tion Untrusted}.
+Note that file transfers are always end-to-end encrypted, regardless of
+this setting.
+
+@end table
+@end deftp
+
+Here is a more complex example configuration for illustrative purposes:
+@lisp
+(service syncthing-service-type
+         (let ((laptop (syncthing-device (id "VHOD2D6-...-7XRMDEN")))
+               (desktop (syncthing-device (id "64SAZ37-...-FZJ5GUA")
+                                          (addresses '("mydomain.com"))))
+               (bob-desktop "KYIMEGO-...-FT77EAO"))
+           (syncthing-configuration
+            (user "alice")
+            (syncthing-config-file
+             (folders (list (syncthing-folder
+                             (label "some-files")
+                             (path "~/data")
+                             (devices (list desktop laptop)))
+                            (syncthing-folder
+                             (label "critical-files")
+                             (path "~/secrets")
+                             (devices
+                              (list desktop
+                                    laptop
+                                    (syncthing-folder-device
+                                     (id bob-desktop)
+                                     (encryptionPassword "mypassword")))))=
))
+             ;; any device used above should be in this list
+             (devices (list laptop desktop bob-desktop))))
+@end lisp
+
=20
 Furthermore, @code{(gnu services ssh)} provides the following services.
 @cindex SSH
diff --git a/gnu/home/services/syncthing.scm b/gnu/home/services/syncthing.=
scm
index 8d66a167ce..dd6c752ee4 100644
--- a/gnu/home/services/syncthing.scm
+++ b/gnu/home/services/syncthing.scm
@@ -1,5 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright =C2=A9 2023 Ludovic Court=C3=A8s <ludo@HIDDEN>
+;;; Copyright =C2=A9 2025 Zacchaeus <eikcaz@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -24,9 +25,23 @@ (define-module (gnu home services syncthing)
   #:use-module (gnu home services shepherd)
   #:export (home-syncthing-service-type)
   #:re-export (syncthing-configuration
-               syncthing-configuration?))
+               syncthing-configuration?
+               syncthing-config-file
+               syncthing-config-file?
+               syncthing-device
+               syncthing-device?
+               syncthing-folder
+               syncthing-folder?
+               syncthing-folder-device
+               syncthing-folder-device?))
=20
 (define home-syncthing-service-type
   (service-type
    (inherit (system->home-service-type syncthing-service-type))
+   ;; system->home-service-type does not convert special-files-service-typ=
e to
+   ;; home-files-service-type, so redefine extensios
+   (extensions (list (service-extension home-files-service-type
+                                        syncthing-files-service)
+                     (service-extension home-shepherd-service-type
+                                        syncthing-shepherd-service)))
    (default-value (for-home (syncthing-configuration)))))
diff --git a/gnu/services/syncthing.scm b/gnu/services/syncthing.scm
index a7a9c6aadd..4f0d4c1082 100644
--- a/gnu/services/syncthing.scm
+++ b/gnu/services/syncthing.scm
@@ -1,6 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright =C2=A9 2021 Oleg Pykhalov <go.wigust@HIDDEN>
 ;;; Copyright =C2=A9 2023 Justin Veilleux <terramorpha@HIDDEN>
+;;; Copyright =C2=A9 2025 Zacchaeus <eikcaz@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -25,9 +26,20 @@ (define-module (gnu services syncthing)
   #:use-module (guix records)
   #:use-module (ice-9 match)
   #:use-module (srfi srfi-1)
+  #:use-module (sxml simple)
   #:export (syncthing-configuration
             syncthing-configuration?
-            syncthing-service-type))
+            syncthing-device
+            syncthing-device?
+            syncthing-config-file
+            syncthing-config-file?
+            syncthing-folder-device
+            syncthing-folder-device?
+            syncthing-folder
+            syncthing-folder?
+            syncthing-service-type
+            syncthing-shepherd-service
+            syncthing-files-service))
=20
 ;;; Commentary:
 ;;;
@@ -35,6 +47,431 @@ (define-module (gnu services syncthing)
 ;;;
 ;;; Code:
=20
+(define-record-type* <syncthing-device>
+  syncthing-device make-syncthing-device
+  syncthing-device?
+  (id syncthing-device-id)
+  (name syncthing-device-name (default ""))
+  (compression syncthing-device-compression (default "metadata"))
+  (introducer syncthing-device-introducer (default "false"))
+  (skipIntroductionRemovals syncthing-device-skipIntroductionRemovals (def=
ault "false"))
+  (introducedBy syncthing-device-introducedBy (default ""))
+  (addresses syncthing-device-addresses (default '("dynamic")))
+  (paused syncthing-device-paused (default "false"))
+  (autoAcceptFolders syncthing-device-autoAcceptFolders (default "false"))
+  (maxSendKbps syncthing-device-maxSendKbps (default "0"))
+  (maxRecvKbps syncthing-device-maxRecvKbps (default "0"))
+  (maxRequestKiB syncthing-device-maxRequestKiB (default "0"))
+  (untrusted syncthing-device-untrusted (default "false"))
+  (remoteGUIPort syncthing-device-remoteGUIPort (default "0"))
+  (numConnections syncthing-device-numConnections (default "0")))
+
+(define syncthing-device->sxml
+  (match-record-lambda <syncthing-device>
+      (id name compression introducer skipIntroductionRemovals introducedB=
y addresses paused autoAcceptFolders maxSendKbps maxRecvKbps maxRequestKiB =
untrusted remoteGUIPort numConnections)
+    `(device (@ (id ,id)
+                (name ,name)
+                (compression ,compression)
+                (introducer ,introducer)
+                (skipIntroductionRemovals ,skipIntroductionRemovals)
+                (introducedBy ,introducedBy))
+             ,@(map (lambda (address) `(address ,address)) addresses)
+             (paused ,paused)
+             (autoAcceptFolders ,autoAcceptFolders)
+             (maxSendKbps ,maxSendKbps)
+             (maxRecvKbps ,maxRecvKbps)
+             (maxRequestKiB ,maxRequestKiB)
+             (untrusted ,untrusted)
+             (remoteGUIPort ,remoteGUIPort)
+             (numConnections ,numConnections))))
+
+(define (id-or-device->id id-or-device)
+  (if (syncthing-device? id-or-device)
+      (syncthing-device-id id-or-device)
+      id-or-device))
+
+(define-record-type* <syncthing-folder-device>
+  syncthing-folder-device make-syncthing-folder-device
+  syncthing-folder-device?
+  (id syncthing-folder-device-id
+      (sanitize id-or-device->id))
+  (introducedBy syncthing-folder-device-introducedBy (default "")
+                (sanitize id-or-device->id))
+  (encryptionPassword syncthing-folder-device-encryptionPassword (default =
"")))
+
+(define syncthing-folder-device->sxml
+  (match-record-lambda <syncthing-folder-device>
+      (id introducedBy encryptionPassword)
+    `(device (@ (id ,id)
+                (introducedBy ,introducedBy))
+             (encryptionPassword ,encryptionPassword))))
+
+(define-record-type* <syncthing-folder>
+  syncthing-folder make-syncthing-folder
+  syncthing-folder?
+  (id syncthing-folder-id (default #f))
+  (label syncthing-folder-label)
+  (path syncthing-folder-path)
+  (type syncthing-folder-type (default "sendreceive"))
+  (rescanIntervalS syncthing-folder-rescanIntervalS (default "3600"))
+  (fsWatcherEnabled syncthing-folder-fsWatcherEnabled (default "true"))
+  (fsWatcherDelayS syncthing-folder-fsWatcherDelayS (default "10"))
+  (ignorePerms syncthing-folder-ignorePerms (default "false"))
+  (autoNormalize syncthing-folder-autoNormalize (default "true"))
+  (devices syncthing-folder-devices (default '())
+           (sanitize (lambda (folder-device-list)
+                       (map (lambda (device)
+                              (if (syncthing-folder-device? device)
+                                  device
+                                  (syncthing-folder-device (id device))))
+                            folder-device-list))))
+  (filesystemType syncthing-folder-filesystemType (default "basic"))
+  (minDiskFree-unit syncthing-folder-minDiskFree-unit (default "%"))
+  (minDiskFree syncthing-folder-minDiskFree (default "1"))
+  (versioning-type syncthing-folder-versioning-type (default #f))
+  (versioning-fsPath syncthing-folder-versioning-fsPath (default ""))
+  (versioning-fsType syncthing-folder-versioning-fsType (default "basic"))
+  (versioning-cleanupIntervalS syncthing-folder-versioning-cleanupInterval=
S (default "3600"))
+  (versioning-cleanoutDays syncthing-folder-versioning-cleanoutDays (defau=
lt #f))
+  (versioning-keep syncthing-folder-versioning-keep (default #f))
+  (versioning-maxAge syncthing-folder-versioning-maxAge (default #f))
+  (versioning-command syncthing-folder-versioning-command (default #f))
+  (copiers syncthing-folder-copiers (default "0"))
+  (pullerMaxPendingKiB syncthing-folder-pullerMaxPendingKiB (default "0"))
+  (hashers syncthing-folder-hashers (default "0"))
+  (order syncthing-folder-order (default "random"))
+  (ignoreDelete syncthing-folder-ignoreDelete (default "false"))
+  (scanProgressIntervalS syncthing-folder-scanProgressIntervalS (default "=
0"))
+  (pullerPauseS syncthing-folder-pullerPauseS (default "0"))
+  (maxConflicts syncthing-folder-maxConflicts (default "10"))
+  (disableSparseFiles syncthing-folder-disableSparseFiles (default "false"=
))
+  (disableTempIndexes syncthing-folder-disableTempIndexes (default "false"=
))
+  (paused syncthing-folder-paused (default "false"))
+  (weakHashThresholdPct syncthing-folder-weakHashThresholdPct (default "25=
"))
+  (markerName syncthing-folder-markerName (default ".stfolder"))
+  (copyOwnershipFromParent syncthing-folder-copyOwnershipFromParent (defau=
lt "false"))
+  (modTimeWindowS syncthing-folder-modTimeWindowS (default "0"))
+  (maxConcurrentWrites syncthing-folder-maxConcurrentWrites (default "2"))
+  (disableFsync syncthing-folder-disableFsync (default "false"))
+  (blockPullOrder syncthing-folder-blockPullOrder (default "standard"))
+  (copyRangeMethod syncthing-folder-copyRangeMethod (default "standard"))
+  (caseSensitiveFS syncthing-folder-caseSensitiveFS (default "false"))
+  (junctionsAsDirs syncthing-folder-junctionsAsDirs (default "false"))
+  (syncOwnership syncthing-folder-syncOwnership (default "false"))
+  (sendOwnership syncthing-folder-sendOwnership (default "false"))
+  (syncXattrs syncthing-folder-syncXattrs (default "false"))
+  (sendXattrs syncthing-folder-sendXattrs (default "false"))
+  (xattrFilter-maxSingleEntrySize syncthing-folder-xattrFilter-maxSingleEn=
trySize (default "1024"))
+  (xattrFilter-maxTotalSize syncthing-folder-xattrFilter-maxTotalSize (def=
ault "4096")))
+
+;; Some parameters, when empty, are fully omitted from the config file.  I=
t is
+;; unknown if this causes a functional difference, but stick to the normal
+;; program's behavior to be safe.
+(define (maybe-param symbol value)
+  (if value `((param (@ (key ,(symbol->string symbol)) (val ,value)) "")) =
'()))
+
+(define syncthing-folder->sxml
+  (match-record-lambda <syncthing-folder>
+      (id
+       label path type rescanIntervalS fsWatcherEnabled fsWatcherDelayS
+       ignorePerms autoNormalize devices filesystemType minDiskFree-unit
+       minDiskFree versioning-type versioning-fsPath versioning-fsType
+       versioning-cleanupIntervalS versioning-cleanoutDays versioning-keep
+       versioning-maxAge versioning-command copiers pullerMaxPendingKiB
+       hashers order ignoreDelete scanProgressIntervalS pullerPauseS
+       maxConflicts disableSparseFiles disableTempIndexes paused
+       weakHashThresholdPct markerName copyOwnershipFromParent modTimeWind=
owS
+       maxConcurrentWrites disableFsync blockPullOrder copyRangeMethod
+       caseSensitiveFS junctionsAsDirs syncOwnership sendOwnership syncXat=
trs
+       sendXattrs xattrFilter-maxSingleEntrySize xattrFilter-maxTotalSize)
+    `(folder (@ (id ,(if id id label))
+                (label ,label)
+                (path ,path)
+                (type ,type)
+                (rescanIntervalS ,rescanIntervalS)
+                (fsWatcherEnabled ,fsWatcherEnabled)
+                (fsWatcherDelayS ,fsWatcherDelayS)
+                (ignorePerms ,ignorePerms)
+                (autoNormalize ,autoNormalize))
+             (filesystemType ,filesystemType)
+             ,@(map syncthing-folder-device->sxml
+                    devices)
+             (minDiskFree (@ (unit ,minDiskFree-unit))
+                          ,minDiskFree)
+             (versioning ,@(if versioning-type
+                               `((@ (type ,versioning-type)))
+                               '())
+                         ,@(maybe-param 'cleanoutDays versioning-cleanoutD=
ays)
+                         ,@(maybe-param 'keep versioning-keep)
+                         ,@(maybe-param 'maxAge versioning-maxAge)
+                         ,@(maybe-param 'command versioning-command)
+                         (cleanupIntervalS ,versioning-cleanupIntervalS)
+                         (fsPath ,versioning-fsPath)
+                         (fsType ,versioning-fsType))
+             (copiers ,copiers)
+             (pullerMaxPendingKiB ,pullerMaxPendingKiB)
+             (hashers ,hashers)
+             (order ,order)
+             (ignoreDelete ,ignoreDelete)
+             (scanProgressIntervalS ,scanProgressIntervalS)
+             (pullerPauseS ,pullerPauseS)
+             (maxConflicts ,maxConflicts)
+             (disableSparseFiles ,disableSparseFiles)
+             (disableTempIndexes ,disableTempIndexes)
+             (paused ,paused)
+             (weakHashThresholdPct ,weakHashThresholdPct)
+             (markerName ,markerName)
+             (copyOwnershipFromParent ,copyOwnershipFromParent)
+             (modTimeWindowS ,modTimeWindowS)
+             (maxConcurrentWrites ,maxConcurrentWrites)
+             (disableFsync ,disableFsync)
+             (blockPullOrder ,blockPullOrder)
+             (copyRangeMethod ,copyRangeMethod)
+             (caseSensitiveFS ,caseSensitiveFS)
+             (junctionsAsDirs ,junctionsAsDirs)
+             (syncOwnership ,syncOwnership)
+             (sendOwnership ,sendOwnership)
+             (syncXattrs ,syncXattrs)
+             (sendXattrs ,sendXattrs)
+             (xattrFilter (maxSingleEntrySize ,xattrFilter-maxSingleEntryS=
ize)
+                          (maxTotalSize ,xattrFilter-maxTotalSize)))))
+
+(define-record-type* <syncthing-config-file>
+  syncthing-config-file make-syncthing-config-file
+  syncthing-config-file?
+  (folders syncthing-config-folders
+           ; this matches syncthing's default
+           (default (list (syncthing-folder (id "default")
+                                            (label "Default Folder")
+                                            (path "~/Sync")))))
+  (devices syncthing-config-devices
+           (default '()))
+  (gui-enabled syncthing-config-gui-enabled (default "true"))
+  (gui-tls syncthing-config-gui-tls (default "false"))
+  (gui-debugging syncthing-config-gui-debugging (default "false"))
+  (gui-sendBasicAuthPrompt syncthing-config-gui-sendBasicAuthPrompt (defau=
lt "false"))
+  (gui-address syncthing-config-gui-address (default "127.0.0.1:8384"))
+  (gui-user syncthing-config-gui-user (default #f))
+  (gui-password syncthing-config-gui-password (default #f))
+  (gui-apikey syncthing-config-gui-apikey (default "Vuky3VHVseQEoSk9YgxhSk=
NTnjQmqYK9"))
+  (gui-theme syncthing-config-gui-theme (default "default"))
+  (ldap-enabled syncthing-config-ldap-enabled (default #f))
+  (ldap-address syncthing-config-ldap-address (default ""))
+  (ldap-bindDN syncthing-config-ldap-bindDN (default ""))
+  (ldap-transport syncthing-config-ldap-transport (default ""))
+  (ldap-insecureSkipVerify syncthing-config-ldap-insecureSkipVerify (defau=
lt ""))
+  (ldap-searchBaseDN syncthing-config-ldap-searchBaseDN (default ""))
+  (ldap-searchFilter syncthing-config-ldap-searchFilter (default ""))
+  (listenAddress syncthing-config-listenAddress (default "default"))
+  (globalAnnounceServer syncthing-config-globalAnnounceServer (default "de=
fault"))
+  (globalAnnounceEnabled syncthing-config-globalAnnounceEnabled (default "=
true"))
+  (localAnnounceEnabled syncthing-config-localAnnounceEnabled (default "tr=
ue"))
+  (localAnnouncePort syncthing-config-localAnnouncePort (default "21027"))
+  (localAnnounceMCAddr syncthing-config-localAnnounceMCAddr (default "[ff1=
2::8384]:21027"))
+  (maxSendKbps syncthing-config-maxSendKbps (default "0"))
+  (maxRecvKbps syncthing-config-maxRecvKbps (default "0"))
+  (reconnectionIntervalS syncthing-config-reconnectionIntervalS (default "=
60"))
+  (relaysEnabled syncthing-config-relaysEnabled (default "true"))
+  (relayReconnectIntervalM syncthing-config-relayReconnectIntervalM (defau=
lt "10"))
+  (startBrowser syncthing-config-startBrowser (default "true"))
+  (natEnabled syncthing-config-natEnabled (default "true"))
+  (natLeaseMinutes syncthing-config-natLeaseMinutes (default "60"))
+  (natRenewalMinutes syncthing-config-natRenewalMinutes (default "30"))
+  (natTimeoutSeconds syncthing-config-natTimeoutSeconds (default "10"))
+  (urAccepted syncthing-config-urAccepted (default "0"))
+  (urSeen syncthing-config-urSeen (default "0"))
+  (urUniqueID syncthing-config-urUniqueID (default ""))
+  (urURL syncthing-config-urURL (default "https://data.syncthing.net/newda=
ta"))
+  (urPostInsecurely syncthing-config-urPostInsecurely (default "false"))
+  (urInitialDelayS syncthing-config-urInitialDelayS (default "1800"))
+  (autoUpgradeIntervalH syncthing-config-autoUpgradeIntervalH (default "12=
"))
+  (upgradeToPreReleases syncthing-config-upgradeToPreReleases (default "fa=
lse"))
+  (keepTemporariesH syncthing-config-keepTemporariesH (default "24"))
+  (cacheIgnoredFiles syncthing-config-cacheIgnoredFiles (default "false"))
+  (progressUpdateIntervalS syncthing-config-progressUpdateIntervalS (defau=
lt "5"))
+  (limitBandwidthInLan syncthing-config-limitBandwidthInLan (default "fals=
e"))
+  (minHomeDiskFree-unit syncthing-config-minHomeDiskFree-unit (default "%"=
))
+  (minHomeDiskFree syncthing-config-minHomeDiskFree (default "1"))
+  (releasesURL syncthing-config-releasesURL (default "https://upgrades.syn=
cthing.net/meta.json"))
+  (overwriteRemoteDeviceNamesOnConnect syncthing-config-overwriteRemoteDev=
iceNamesOnConnect (default "false"))
+  (tempIndexMinBlocks syncthing-config-tempIndexMinBlocks (default "10"))
+  (unackedNotificationID syncthing-config-unackedNotificationID (default "=
authenticationUserAndPassword"))
+  (trafficClass syncthing-config-trafficClass (default "0"))
+  (setLowPriority syncthing-config-setLowPriority (default "true"))
+  (maxFolderConcurrency syncthing-config-maxFolderConcurrency (default "0"=
))
+  (crashReportingURL syncthing-config-crashReportingURL (default "https://=
crash.syncthing.net/newcrash"))
+  (crashReportingEnabled syncthing-config-crashReportingEnabled (default "=
true"))
+  (stunKeepaliveStartS syncthing-config-stunKeepaliveStartS (default "180"=
))
+  (stunKeepaliveMinS syncthing-config-stunKeepaliveMinS (default "20"))
+  (stunServer syncthing-config-stunServer (default "default"))
+  (databaseTuning syncthing-config-databaseTuning (default "auto"))
+  (maxConcurrentIncomingRequestKiB syncthing-config-maxConcurrentIncomingR=
equestKiB (default "0"))
+  (announceLANAddresses syncthing-config-announceLANAddresses (default "tr=
ue"))
+  (sendFullIndexOnUpgrade syncthing-config-sendFullIndexOnUpgrade (default=
 "false"))
+  (connectionLimitEnough syncthing-config-connectionLimitEnough (default "=
0"))
+  (connectionLimitMax syncthing-config-connectionLimitMax (default "0"))
+  (insecureAllowOldTLSVersions syncthing-config-insecureAllowOldTLSVersion=
s (default "false"))
+  (connectionPriorityTcpLan syncthing-config-connectionPriorityTcpLan (def=
ault "10"))
+  (connectionPriorityQuicLan syncthing-config-connectionPriorityQuicLan (d=
efault "20"))
+  (connectionPriorityTcpWan syncthing-config-connectionPriorityTcpWan (def=
ault "30"))
+  (connectionPriorityQuicWan syncthing-config-connectionPriorityQuicWan (d=
efault "40"))
+  (connectionPriorityRelay syncthing-config-connectionPriorityRelay (defau=
lt "50"))
+  (connectionPriorityUpgradeThreshold syncthing-config-connectionPriorityU=
pgradeThreshold (default "0"))
+  (default-folder syncthing-config-defaultFolder
+    (default (syncthing-folder (label "") (path "~"))))
+  (default-device syncthing-config-defaultDevice
+    (default (syncthing-device (id ""))))
+  (default-ignores syncthing-config-defaultIgnores (default "")))
+
+(define syncthing-config-file->sxml
+  (match-record-lambda <syncthing-config-file>
+      (folders
+       devices gui-enabled gui-tls gui-debugging gui-sendBasicAuthPrompt
+       gui-address gui-user gui-password gui-apikey gui-theme ldap-enabled
+       ldap-address ldap-bindDN ldap-transport ldap-insecureSkipVerify
+       ldap-searchBaseDN ldap-searchFilter listenAddress globalAnnounceSer=
ver
+       globalAnnounceEnabled localAnnounceEnabled localAnnouncePort
+       localAnnounceMCAddr maxSendKbps maxRecvKbps reconnectionIntervalS
+       relaysEnabled relayReconnectIntervalM startBrowser natEnabled
+       natLeaseMinutes natRenewalMinutes natTimeoutSeconds urAccepted
+       urSeen urUniqueID urURL urPostInsecurely urInitialDelayS
+       autoUpgradeIntervalH upgradeToPreReleases keepTemporariesH
+       cacheIgnoredFiles progressUpdateIntervalS limitBandwidthInLan
+       minHomeDiskFree-unit minHomeDiskFree releasesURL
+       overwriteRemoteDeviceNamesOnConnect tempIndexMinBlocks
+       unackedNotificationID trafficClass setLowPriority maxFolderConcurre=
ncy
+       crashReportingURL crashReportingEnabled stunKeepaliveStartS
+       stunKeepaliveMinS stunServer databaseTuning
+       maxConcurrentIncomingRequestKiB announceLANAddresses
+       sendFullIndexOnUpgrade connectionLimitEnough connectionLimitMax
+       insecureAllowOldTLSVersions connectionPriorityTcpLan
+       connectionPriorityQuicLan connectionPriorityTcpWan
+       connectionPriorityQuicWan connectionPriorityRelay
+       connectionPriorityUpgradeThreshold default-folder default-device
+       default-ignores)
+    `(configuration (@ (version "37"))
+                    ,@(map syncthing-folder->sxml
+                           folders)
+                    ,@(map syncthing-device->sxml
+                           devices)
+                    (gui (@ (enabled ,gui-enabled)
+                            (tls ,gui-tls)
+                            (debugging ,gui-debugging)
+                            (sendBasicAuthPrompt ,gui-sendBasicAuthPrompt))
+                         (address ,gui-address)
+                         ,@(if gui-user `((user ,gui-user)) '())
+                         ,@(if gui-password `((password ,gui-password)) '(=
))
+                         (apikey ,gui-apikey)
+                         (theme ,gui-theme))
+                    (ldap ,(if ldap-enabled
+                               `((address ,ldap-address)
+                                 (bindDN ,ldap-bindDN)
+                                 ,@(if ldap-transport
+                                       `((transport ,ldap-transport))
+                                       '())
+                                 ,@(if ldap-insecureSkipVerify
+                                       `((insecureSkipVerify ,ldap-insecur=
eSkipVerify))
+                                       '())
+                                 ,@(if ldap-searchBaseDN
+                                       `((searchBaseDN ,ldap-searchBaseDN))
+                                       '())
+                                 ,@(if ldap-searchFilter
+                                       `((searchFilter ,ldap-searchFilter))
+                                       '()))
+                               ""))
+                    (options (listenAddress ,listenAddress)
+                             (globalAnnounceServer ,globalAnnounceServer)
+                             (globalAnnounceEnabled ,globalAnnounceEnabled)
+                             (localAnnounceEnabled ,localAnnounceEnabled)
+                             (localAnnouncePort ,localAnnouncePort)
+                             (localAnnounceMCAddr ,localAnnounceMCAddr)
+                             (maxSendKbps ,maxSendKbps)
+                             (maxRecvKbps ,maxRecvKbps)
+                             (reconnectionIntervalS ,reconnectionIntervalS)
+                             (relaysEnabled ,relaysEnabled)
+                             (relayReconnectIntervalM ,relayReconnectInter=
valM)
+                             (startBrowser ,startBrowser)
+                             (natEnabled ,natEnabled)
+                             (natLeaseMinutes ,natLeaseMinutes)
+                             (natRenewalMinutes ,natRenewalMinutes)
+                             (natTimeoutSeconds ,natTimeoutSeconds)
+                             (urAccepted ,urAccepted)
+                             (urSeen ,urSeen)
+                             (urUniqueID ,urUniqueID)
+                             (urURL ,urURL)
+                             (urPostInsecurely ,urPostInsecurely)
+                             (urInitialDelayS ,urInitialDelayS)
+                             (autoUpgradeIntervalH ,autoUpgradeIntervalH)
+                             (upgradeToPreReleases ,upgradeToPreReleases)
+                             (keepTemporariesH ,keepTemporariesH)
+                             (cacheIgnoredFiles ,cacheIgnoredFiles)
+                             (progressUpdateIntervalS ,progressUpdateInter=
valS)
+                             (limitBandwidthInLan ,limitBandwidthInLan)
+                             (minHomeDiskFree (@ (unit ,minHomeDiskFree-un=
it))
+                                              ,minHomeDiskFree)
+                             (releasesURL ,releasesURL)
+                             (overwriteRemoteDeviceNamesOnConnect ,overwri=
teRemoteDeviceNamesOnConnect)
+                             (tempIndexMinBlocks ,tempIndexMinBlocks)
+                             (unackedNotificationID ,unackedNotificationID)
+                             (trafficClass ,trafficClass)
+                             (setLowPriority ,setLowPriority)
+                             (maxFolderConcurrency ,maxFolderConcurrency)
+                             (crashReportingURL ,crashReportingURL)
+                             (crashReportingEnabled ,crashReportingEnabled)
+                             (stunKeepaliveStartS ,stunKeepaliveStartS)
+                             (stunKeepaliveMinS ,stunKeepaliveMinS)
+                             (stunServer ,stunServer)
+                             (databaseTuning ,databaseTuning)
+                             (maxConcurrentIncomingRequestKiB ,maxConcurre=
ntIncomingRequestKiB)
+                             (announceLANAddresses ,announceLANAddresses)
+                             (sendFullIndexOnUpgrade ,sendFullIndexOnUpgra=
de)
+                             (connectionLimitEnough ,connectionLimitEnough)
+                             (connectionLimitMax ,connectionLimitMax)
+                             (insecureAllowOldTLSVersions ,insecureAllowOl=
dTLSVersions)
+                             (connectionPriorityTcpLan ,connectionPriority=
TcpLan)
+                             (connectionPriorityQuicLan ,connectionPriorit=
yQuicLan)
+                             (connectionPriorityTcpWan ,connectionPriority=
TcpWan)
+                             (connectionPriorityQuicWan ,connectionPriorit=
yQuicWan)
+                             (connectionPriorityRelay ,connectionPriorityR=
elay)
+                             (connectionPriorityUpgradeThreshold ,connecti=
onPriorityUpgradeThreshold))
+                    (defaults
+                      ,(syncthing-folder->sxml default-folder)
+                      ,(syncthing-device->sxml default-device)
+                      (ignores ,default-ignores)))))
+
+;; It is useful to be able to view the xml output by Guix, and to be able =
to
+;; diff it with a users previous config, especially when migrating one's
+;; config to Guix.  This function adds whitespace that matches the whitesp=
ace
+;; of config files managed by syncthing for easy diffing
+(define (indent-sxml sxml indent-increment current-indent)
+  (match sxml
+    (((tag ('@ properties ...) (subtags ..1) ..1) sibling-tags ...)
+     `(,current-indent (,tag (@ ,@properties) "\n"
+                             ,@(indent-sxml subtags indent-increment
+                                            (string-append indent-incremen=
t current-indent))
+                             ,current-indent) "\n"
+                       ,@(indent-sxml sibling-tags indent-increment curren=
t-indent)))
+    (((tag ('@ properties ...) primitive ...) sibling-tags ...)
+     `(,current-indent (,tag (@ ,@properties) ,@primitive) "\n"
+                       ,@(indent-sxml sibling-tags indent-increment curren=
t-indent)))
+    (((tag (subtags ..1) ..1) sibling-tags ...)
+     `(,current-indent (,tag "\n"
+                             ,@(indent-sxml subtags indent-increment
+                                            (string-append indent-incremen=
t current-indent))
+                             ,current-indent) "\n"
+                       ,@(indent-sxml sibling-tags indent-increment curren=
t-indent)))
+    (((tag primitive ...) sibling-tags ...)
+     `(,current-indent (,tag ,@primitive) "\n"
+                       ,@(indent-sxml sibling-tags indent-increment curren=
t-indent)))
+    (() '())))
+
+(define (serialize-syncthing-config-file config)
+  (with-output-to-string
+    (lambda ()
+      (sxml->xml (cons '*TOP* (indent-sxml (list (syncthing-config-file->s=
xml config))
+                                           "    "
+                                           ""))))))
+
 (define-record-type* <syncthing-configuration>
   syncthing-configuration make-syncthing-configuration
   syncthing-configuration?
@@ -50,6 +487,8 @@ (define-record-type* <syncthing-configuration>
              (default "users"))
   (home      syncthing-configuration-home      ;string
              (default #f))
+  (syncthing-config-file syncthing-configuration-syncthing-config-file
+                         (default #f))         ; syncthing-config-file or =
file-like
   (home-service? syncthing-configuration-home-service?
                  (default for-home?) (innate)))
=20
@@ -93,10 +532,26 @@ (define syncthing-shepherd-service
       (respawn? #f)
       (stop #~(make-kill-destructor))))))
=20
+
+(define syncthing-files-service
+  (match-record-lambda <syncthing-configuration> (syncthing-config-file us=
er home home-service?)
+    (if syncthing-config-file
+        `((,(if home-service?
+                ".config/syncthing/config.xml"
+                (string-join (or home (passwd:dir (getpw user)))
+                             "/.config/syncthing/config.xml"))
+           ,(if (file-like? syncthing-config-file)
+                syncthing-config-file
+                (plain-file "syncthin-config.xml" (serialize-syncthing-con=
fig-file
+                                                   syncthing-config-file))=
)))
+        '())))
+
 (define syncthing-service-type
   (service-type (name 'syncthing)
                 (extensions (list (service-extension shepherd-root-service=
-type
-                                                     syncthing-shepherd-se=
rvice)))
+                                                     syncthing-shepherd-se=
rvice)
+                                  (service-extension special-files-service=
-type
+                                                     syncthing-files-servi=
ce)))
                 (description
                  "Run @uref{https://github.com/syncthing/syncthing, Syncth=
ing}
 decentralized continuous file system synchronization.")))
--=20
2.45.2





Acknowledgement sent to Zacchaeus <eikcaz@HIDDEN>:
New bug report received and forwarded. Copy sent to guix-patches@HIDDEN. Full text available.
Report forwarded to guix-patches@HIDDEN:
bug#75959; Package guix-patches. Full text available.
Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.
Last modified: Sat, 1 Feb 2025 09:00:02 UTC

GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997 nCipher Corporation Ltd, 1994-97 Ian Jackson.