projects/guix·blob master · refs

579 lines · 33.5 KiB

1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2021 Oleg Pykhalov <[email protected]>
3;;; Copyright © 2023 Justin Veilleux <[email protected]>
4;;; Copyright © 2025 Zacchaeus <[email protected]>
5;;;
6;;; This file is part of GNU Guix.
7;;;
8;;; GNU Guix is free software; you can redistribute it and/or modify it
9;;; under the terms of the GNU General Public License as published by
10;;; the Free Software Foundation; either version 3 of the License, or (at
11;;; your option) any later version.
12;;;
13;;; GNU Guix is distributed in the hope that it will be useful, but
14;;; WITHOUT ANY WARRANTY; without even the implied warranty of
15;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16;;; GNU General Public License for more details.
17;;;
18;;; You should have received a copy of the GNU General Public License
19;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
20
21;;; Commentary:
22;;;
23;;; This module provides a service definition for the syncthing service.
24;;;
25;;; Code:
26
27(define-module (gnu services syncthing)
28 #:use-module (gnu packages syncthing)
29 #:use-module (gnu services)
30 #:use-module (gnu services shepherd)
31 #:use-module (guix gexp)
32 #:use-module (guix records)
33 #:use-module (ice-9 match)
34 #:use-module (srfi srfi-1)
35 #:use-module (sxml simple)
36 #:export (syncthing-configuration
37 syncthing-configuration?
38 syncthing-device
39 syncthing-device?
40 syncthing-config-file
41 syncthing-config-file?
42 syncthing-folder-device
43 syncthing-folder-device?
44 syncthing-folder
45 syncthing-folder?
46 syncthing-service-type
47 syncthing-shepherd-service
48 syncthing-files-service))
49
50(define (bool->xml-string bool)
51 ;; add compatibility for the short duration where #f was specified as
52 ;; "false"
53 (if (string? bool) bool
54 ;; the expected case
55 (if bool "true" "false")))
56
57(define-record-type* <syncthing-device>
58 syncthing-device make-syncthing-device
59 syncthing-device?
60 (id syncthing-device-id)
61 (name syncthing-device-name (default ""))
62 (compression syncthing-device-compression (default "metadata"))
63 (introducer? syncthing-device-introducer? (default #f))
64 (skip-introduction-removals? syncthing-device-skip-introduction-removals? (default #f))
65 (introduced-by syncthing-device-introduced-by (default ""))
66 (addresses syncthing-device-addresses (default '("dynamic")))
67 (paused? syncthing-device-paused? (default #f))
68 (auto-accept-folders? syncthing-device-auto-accept-folders? (default #f))
69 (max-send-kbps syncthing-device-max-send-kbps (default 0))
70 (max-receive-kbps syncthing-device-max-receive-kbps (default 0))
71 (max-request-kib syncthing-device-max-request-kib (default 0))
72 (untrusted? syncthing-device-untrusted? (default #f))
73 (remote-gui-port syncthing-device-remote-gui-port (default 0))
74 (num-connections syncthing-device-num-connections (default 0)))
75
76(define syncthing-device->sxml
77 (match-record-lambda <syncthing-device>
78 (id
79 name compression introducer? skip-introduction-removals? introduced-by
80 addresses paused? auto-accept-folders? max-send-kbps max-receive-kbps
81 max-request-kib untrusted? remote-gui-port num-connections)
82 `(device (@ (id ,id)
83 (name ,name)
84 (compression ,compression)
85 (introducer ,(bool->xml-string introducer?))
86 (skipIntroductionRemovals ,(bool->xml-string skip-introduction-removals?))
87 (introducedBy ,introduced-by))
88 ,@(map (lambda (address) `(address ,address)) addresses)
89 (paused ,(bool->xml-string paused?))
90 (autoAcceptFolders ,(bool->xml-string auto-accept-folders?))
91 (maxSendKbps ,max-send-kbps)
92 (maxRecvKbps ,max-receive-kbps)
93 (maxRequestKiB ,max-request-kib)
94 (untrusted ,(bool->xml-string untrusted?))
95 (remoteGUIPort ,remote-gui-port)
96 (numConnections ,num-connections))))
97
98(define-record-type* <syncthing-folder-device>
99 syncthing-folder-device make-syncthing-folder-device
100 syncthing-folder-device?
101 (device syncthing-folder-device-device)
102 (introduced-by syncthing-folder-device-introduced-by (default (syncthing-device (id ""))))
103 (encryption-password syncthing-folder-device-encryption-password (default "")))
104
105(define syncthing-folder-device->sxml
106 (match-record-lambda <syncthing-folder-device>
107 (device introduced-by encryption-password)
108 `(device (@ (id ,(syncthing-device-id device))
109 (introducedBy ,(syncthing-device-id introduced-by)))
110 (encryptionPassword ,encryption-password))))
111
112(define-record-type* <syncthing-folder>
113 syncthing-folder make-syncthing-folder
114 syncthing-folder?
115 (id syncthing-folder-id (default #f))
116 (label syncthing-folder-label)
117 (path syncthing-folder-path)
118 (type syncthing-folder-type (default "sendreceive"))
119 (rescan-interval-seconds syncthing-folder-rescan-interval-seconds (default 3600))
120 (file-system-watcher-enabled? syncthing-folder-file-system-watcher-enabled? (default #t))
121 (file-system-watcher-delay-seconds syncthing-folder-file-system-watcher-delay-seconds (default 10))
122 (file-system-watcher-timeout-seconds syncthing-folder-file-system-watcher-timeout-seconds (default 0))
123 (ignore-permissions? syncthing-folder-ignore-permissions? (default #f))
124 (auto-normalize? syncthing-folder-auto-normalize? (default #t))
125 (devices syncthing-folder-devices (default '())
126 (sanitize (lambda (folder-device-list)
127 (map (lambda (device)
128 (if (syncthing-folder-device? device)
129 device
130 (syncthing-folder-device (device device))))
131 folder-device-list))))
132 (filesystem-type syncthing-folder-filesystem-type (default "basic"))
133 (min-disk-free-unit syncthing-folder-min-disk-free-unit (default "%"))
134 (min-disk-free syncthing-folder-min-disk-free (default 1))
135 (versioning-type syncthing-folder-versioning-type (default #f))
136 (versioning-file-system-path syncthing-folder-versioning-file-system-path (default ""))
137 (versioning-file-system-type syncthing-folder-versioning-file-system-type (default "basic"))
138 (versioning-cleanup-interval-seconds syncthing-folder-versioning-cleanup-interval-seconds (default 3600))
139 (versioning-cleanout-days syncthing-folder-versioning-cleanout-days (default #f))
140 (versioning-keep syncthing-folder-versioning-keep (default #f))
141 (versioning-max-age syncthing-folder-versioning-max-age (default #f))
142 (versioning-command syncthing-folder-versioning-command (default #f))
143 (copiers syncthing-folder-copiers (default 0))
144 (puller-max-pending-kib syncthing-folder-puller-max-pending-kib (default 0))
145 (hashers syncthing-folder-hashers (default 0))
146 (order syncthing-folder-order (default "random"))
147 (ignore-delete? syncthing-folder-ignore-delete? (default #f))
148 (scan-progress-interval-seconds syncthing-folder-scan-progress-interval-seconds (default 0))
149 (puller-pause-seconds syncthing-folder-puller-pause-seconds (default 0))
150 (max-conflicts syncthing-folder-max-conflicts (default 10))
151 (disable-sparse-files? syncthing-folder-disable-sparse-files? (default #f))
152 (disable-temp-indexes? syncthing-folder-disable-temp-indexes? (default #f))
153 (paused? syncthing-folder-paused? (default #f))
154 (weak-hash-threshold-percentage syncthing-folder-weak-hash-threshold-percentage (default 25))
155 (marker-name syncthing-folder-marker-name (default ".stfolder"))
156 (copy-ownership-from-parent? syncthing-folder-copy-ownership-from-parent? (default #f))
157 (mod-time-window-seconds syncthing-folder-mod-time-window-seconds (default 0))
158 (max-concurrent-writes syncthing-folder-max-concurrent-writes (default 16))
159 (disable-fsync? syncthing-folder-disable-fsync? (default #f))
160 (block-pull-order syncthing-folder-block-pull-order (default "standard"))
161 (copy-range-method syncthing-folder-copy-range-method (default "standard"))
162 (case-sensitive-file-system? syncthing-folder-case-sensitive-file-system? (default #f))
163 (junctions-as-dirs? syncthing-folder-junctions-as-dirs? (default #f))
164 (sync-ownership? syncthing-folder-sync-ownership? (default #f))
165 (send-ownership? syncthing-folder-send-ownership? (default #f))
166 (sync-xattrs? syncthing-folder-sync-xattrs? (default #f))
167 (send-xattrs? syncthing-folder-send-xattrs? (default #f))
168 (xattr-filter-max-single-entry-size syncthing-folder-xattr-filter-max-single-entry-size (default 1024))
169 (xattr-filter-max-total-size syncthing-folder-xattr-filter-max-total-size (default 4096)))
170
171;; Some parameters, when empty, are fully omitted from the config file. It is
172;; unknown if this causes a functional difference, but stick to the normal
173;; program's behavior to be safe.
174(define (maybe-param symbol value)
175 (if value `((param (@ (key ,(symbol->string symbol)) (val ,value)) "")) '()))
176
177(define syncthing-folder->sxml
178 (match-record-lambda <syncthing-folder>
179 (id
180 label path type rescan-interval-seconds file-system-watcher-enabled?
181 file-system-watcher-delay-seconds file-system-watcher-timeout-seconds
182 ignore-permissions? auto-normalize? devices filesystem-type
183 min-disk-free-unit min-disk-free versioning-type
184 versioning-file-system-path versioning-file-system-type
185 versioning-cleanup-interval-seconds versioning-cleanout-days
186 versioning-keep versioning-max-age versioning-command copiers
187 puller-max-pending-kib hashers order ignore-delete?
188 scan-progress-interval-seconds puller-pause-seconds max-conflicts
189 disable-sparse-files? disable-temp-indexes? paused?
190 weak-hash-threshold-percentage marker-name copy-ownership-from-parent?
191 mod-time-window-seconds max-concurrent-writes disable-fsync?
192 block-pull-order copy-range-method case-sensitive-file-system?
193 junctions-as-dirs? sync-ownership? send-ownership? sync-xattrs?
194 send-xattrs? xattr-filter-max-single-entry-size
195 xattr-filter-max-total-size)
196 `(folder (@ (id ,(if id id label))
197 (label ,label)
198 (path ,path)
199 (type ,type)
200 (rescanIntervalS ,rescan-interval-seconds)
201 (fsWatcherEnabled ,(bool->xml-string file-system-watcher-enabled?))
202 (fsWatcherDelayS ,file-system-watcher-delay-seconds)
203 (fsWatcherTimeoutS ,file-system-watcher-timeout-seconds)
204 (ignorePerms ,(bool->xml-string ignore-permissions?))
205 (autoNormalize ,(bool->xml-string auto-normalize?)))
206 (filesystemType ,filesystem-type)
207 ,@(map syncthing-folder-device->sxml
208 devices)
209 (minDiskFree (@ (unit ,min-disk-free-unit))
210 ,min-disk-free)
211 (versioning ,@(if versioning-type
212 `((@ (type ,versioning-type)))
213 '())
214 ,@(maybe-param 'cleanoutDays versioning-cleanout-days)
215 ,@(maybe-param 'keep versioning-keep)
216 ,@(maybe-param 'maxAge versioning-max-age)
217 ,@(maybe-param 'command versioning-command)
218 (cleanupIntervalS ,versioning-cleanup-interval-seconds)
219 (fsPath ,versioning-file-system-path)
220 (fsType ,versioning-file-system-type))
221 (copiers ,copiers)
222 (pullerMaxPendingKiB ,puller-max-pending-kib)
223 (hashers ,hashers)
224 (order ,order)
225 (ignoreDelete ,(bool->xml-string ignore-delete?))
226 (scanProgressIntervalS ,scan-progress-interval-seconds)
227 (pullerPauseS ,puller-pause-seconds)
228 (maxConflicts ,max-conflicts)
229 (disableSparseFiles ,(bool->xml-string disable-sparse-files?))
230 (disableTempIndexes ,(bool->xml-string disable-temp-indexes?))
231 (paused ,(bool->xml-string paused?))
232 (weakHashThresholdPct ,weak-hash-threshold-percentage)
233 (markerName ,marker-name)
234 (copyOwnershipFromParent ,(bool->xml-string copy-ownership-from-parent?))
235 (modTimeWindowS ,mod-time-window-seconds)
236 (maxConcurrentWrites ,max-concurrent-writes)
237 (disableFsync ,(bool->xml-string disable-fsync?))
238 (blockPullOrder ,block-pull-order)
239 (copyRangeMethod ,copy-range-method)
240 (caseSensitiveFS ,(bool->xml-string case-sensitive-file-system?))
241 (junctionsAsDirs ,(bool->xml-string junctions-as-dirs?))
242 (syncOwnership ,(bool->xml-string sync-ownership?))
243 (sendOwnership ,(bool->xml-string send-ownership?))
244 (syncXattrs ,(bool->xml-string sync-xattrs?))
245 (sendXattrs ,(bool->xml-string send-xattrs?))
246 (xattrFilter (maxSingleEntrySize ,xattr-filter-max-single-entry-size)
247 (maxTotalSize ,xattr-filter-max-total-size)))))
248
249(define-record-type* <syncthing-config-file>
250 syncthing-config-file make-syncthing-config-file
251 syncthing-config-file?
252 (folders syncthing-config-folders
253 ; this matches syncthing's default
254 (default (list (syncthing-folder (id "default")
255 (label "Default Folder")
256 (path "~/Sync")))))
257 (devices syncthing-config-devices
258 (default '()))
259 (gui-enabled? syncthing-config-gui-enabled? (default #t))
260 (gui-tls? syncthing-config-gui-tls? (default #f))
261 (gui-debugging? syncthing-config-gui-debugging? (default #f))
262 (gui-send-basic-authorization-prompt? syncthing-config-gui-send-basic-authorization-prompt? (default #f))
263 (gui-address syncthing-config-gui-address (default "127.0.0.1:8384"))
264 (gui-user syncthing-config-gui-user (default #f))
265 (gui-password syncthing-config-gui-password (default #f))
266 (gui-apikey syncthing-config-gui-apikey (default #f))
267 (gui-theme syncthing-config-gui-theme (default "default"))
268 (ldap-enabled? syncthing-config-ldap-enabled? (default #f))
269 (ldap-address syncthing-config-ldap-address (default ""))
270 (ldap-bind-dn syncthing-config-ldap-bind-dn (default ""))
271 (ldap-transport syncthing-config-ldap-transport (default ""))
272 (ldap-insecure-skip-verify syncthing-config-ldap-insecure-skip-verify (default ""))
273 (ldap-search-base-dn syncthing-config-ldap-search-base-dn (default ""))
274 (ldap-search-filter syncthing-config-ldap-search-filter (default ""))
275 (listen-address syncthing-config-listen-address (default "default"))
276 (global-announce-server syncthing-config-global-announce-server (default "default"))
277 (global-announce-enabled? syncthing-config-global-announce-enabled? (default #t))
278 (local-announce-enabled? syncthing-config-local-announce-enabled? (default #t))
279 (local-announce-port syncthing-config-local-announce-port (default 21027))
280 (local-announce-mac-address syncthing-config-local-announce-mac-address (default "[ff12::8384]:21027"))
281 (max-send-kbps syncthing-config-max-send-kbps (default 0))
282 (max-receive-kbps syncthing-config-max-receive-kbps (default 0))
283 (reconnection-interval-seconds syncthing-config-reconnection-interval-seconds (default 20))
284 (relays-enabled? syncthing-config-relays-enabled? (default #t))
285 (relay-reconnect-interval-minutes syncthing-config-relay-reconnect-interval-minutes (default 10))
286 (start-browser? syncthing-config-start-browser? (default #t))
287 (nat-enabled? syncthing-config-nat-enabled? (default #t))
288 (nat-lease-minutes syncthing-config-nat-lease-minutes (default 60))
289 (nat-renewal-minutes syncthing-config-nat-renewal-minutes (default 30))
290 (nat-timeout-seconds syncthing-config-nat-timeout-seconds (default 10))
291 (usage-reporting-accepted syncthing-config-usage-reporting-accepted (default 0))
292 (usage-reporting-seen syncthing-config-usage-reporting-seen (default 0))
293 (usage-reporting-unique-id syncthing-config-usage-reporting-unique-id (default ""))
294 (usage-reporting-url syncthing-config-usage-reporting-url (default "https://data.syncthing.net/newdata"))
295 (usage-reporting-post-insecurely? syncthing-config-usage-reporting-post-insecurely? (default #f))
296 (usage-reporting-initial-delay-seconds syncthing-config-usage-reporting-initial-delay-seconds (default 1800))
297 (auto-upgrade-interval-hours syncthing-config-auto-upgrade-interval-hours (default 12))
298 (upgrade-to-pre-releases? syncthing-config-upgrade-to-pre-releases? (default #f))
299 (keep-temporaries-hours syncthing-config-keep-temporaries-hours (default 24))
300 (cache-ignored-files? syncthing-config-cache-ignored-files? (default #f))
301 (progress-update-interval-seconds syncthing-config-progress-update-interval-seconds (default 5))
302 (limit-bandwidth-in-lan? syncthing-config-limit-bandwidth-in-lan? (default #f))
303 (min-home-disk-free-unit syncthing-config-min-home-disk-free-unit (default "%"))
304 (min-home-disk-free syncthing-config-min-home-disk-free (default 1))
305 (releases-url syncthing-config-releases-url (default "https://upgrades.syncthing.net/meta.json"))
306 (overwrite-remote-device-names-on-connect? syncthing-config-overwrite-remote-device-names-on-connect? (default #f))
307 (temp-index-min-blocks syncthing-config-temp-index-min-blocks (default 10))
308 (unacked-notification-id syncthing-config-unacked-notification-id (default "authenticationUserAndPassword"))
309 (traffic-class syncthing-config-traffic-class (default 0))
310 (set-low-priority? syncthing-config-set-low-priority? (default #t))
311 (max-folder-concurrency syncthing-config-max-folder-concurrency (default 0))
312 (crash-reporting-url syncthing-config-crash-reporting-url (default "https://crash.syncthing.net/newcrash"))
313 (crash-reporting-enabled? syncthing-config-crash-reporting-enabled? (default #t))
314 (stun-keepalive-start-seconds syncthing-config-stun-keepalive-start-seconds (default 180))
315 (stun-keepalive-min-seconds syncthing-config-stun-keepalive-min-seconds (default 20))
316 (stun-server syncthing-config-stun-server (default "default"))
317 (database-tuning syncthing-config-database-tuning (default "auto"))
318 (max-concurrent-incoming-request-kib syncthing-config-max-concurrent-incoming-request-kib (default 0))
319 (announce-lan-addresses? syncthing-config-announce-lan-addresses? (default #t))
320 (send-full-index-on-upgrade? syncthing-config-send-full-index-on-upgrade? (default #f))
321 (connection-limit-enough syncthing-config-connection-limit-enough (default 0))
322 (connection-limit-max syncthing-config-connection-limit-max (default 0))
323 (insecure-allow-old-tls-versions? syncthing-config-insecure-allow-old-tls-versions? (default #f))
324 (connection-priority-tcp-lan syncthing-config-connection-priority-tcp-lan (default 10))
325 (connection-priority-quic-lan syncthing-config-connection-priority-quic-lan (default 20))
326 (connection-priority-tcp-wan syncthing-config-connection-priority-tcp-wan (default 30))
327 (connection-priority-quic-wan syncthing-config-connection-priority-quic-wan (default 40))
328 (connection-priority-relay syncthing-config-connection-priority-relay (default 50))
329 (connection-priority-upgrade-threshold syncthing-config-connection-priority-upgrade-threshold (default 0))
330 (default-folder syncthing-config-default-folder
331 (default (syncthing-folder (label "") (path "~"))))
332 (default-device syncthing-config-default-device
333 (default (syncthing-device (id ""))))
334 (default-ignores syncthing-config-default-ignores (default "")))
335
336(define syncthing-config-file->sxml
337 (match-record-lambda <syncthing-config-file>
338 (folders
339 devices gui-enabled? gui-tls? gui-debugging?
340 gui-send-basic-authorization-prompt? gui-address gui-user gui-password
341 gui-apikey gui-theme ldap-enabled? ldap-address ldap-bind-dn
342 ldap-transport ldap-insecure-skip-verify ldap-search-base-dn
343 ldap-search-filter listen-address global-announce-server
344 global-announce-enabled? local-announce-enabled? local-announce-port
345 local-announce-mac-address max-send-kbps max-receive-kbps
346 reconnection-interval-seconds relays-enabled?
347 relay-reconnect-interval-minutes start-browser? nat-enabled?
348 nat-lease-minutes nat-renewal-minutes nat-timeout-seconds
349 usage-reporting-accepted usage-reporting-seen usage-reporting-unique-id
350 usage-reporting-url usage-reporting-post-insecurely?
351 usage-reporting-initial-delay-seconds auto-upgrade-interval-hours
352 upgrade-to-pre-releases? keep-temporaries-hours cache-ignored-files?
353 progress-update-interval-seconds limit-bandwidth-in-lan?
354 min-home-disk-free-unit min-home-disk-free releases-url
355 overwrite-remote-device-names-on-connect? temp-index-min-blocks
356 unacked-notification-id traffic-class set-low-priority?
357 max-folder-concurrency crash-reporting-url crash-reporting-enabled?
358 stun-keepalive-start-seconds stun-keepalive-min-seconds stun-server
359 database-tuning max-concurrent-incoming-request-kib
360 announce-lan-addresses? send-full-index-on-upgrade?
361 connection-limit-enough connection-limit-max
362 insecure-allow-old-tls-versions? connection-priority-tcp-lan
363 connection-priority-quic-lan connection-priority-tcp-wan
364 connection-priority-quic-wan connection-priority-relay
365 connection-priority-upgrade-threshold default-folder default-device
366 default-ignores)
367 `(configuration (@ (version "52"))
368 ,@(map syncthing-folder->sxml
369 folders)
370 ;; collect any devices in any folders, as well as any
371 ;; devices explicitly added.
372 ,@(map syncthing-device->sxml
373 (delete-duplicates
374 (append devices
375 (apply append
376 (map (lambda (folder)
377 (map syncthing-folder-device-device
378 (syncthing-folder-devices folder)))
379 folders)))
380 ;; devices are the same if their id's are equal
381 (lambda (device1 device2)
382 (string= (syncthing-device-id device1)
383 (syncthing-device-id device2)))))
384 (gui (@ (enabled ,(bool->xml-string gui-enabled?))
385 (tls ,(bool->xml-string gui-tls?))
386 (debugging ,(bool->xml-string gui-debugging?))
387 (sendBasicAuthPrompt ,(bool->xml-string gui-send-basic-authorization-prompt?)))
388 (address ,gui-address)
389 ,@(if gui-user `((user ,gui-user)) '())
390 ,@(if gui-password `((password ,gui-password)) '())
391 ,@(if gui-apikey `((apikey ,gui-apikey)) '())
392 (theme ,gui-theme))
393 (ldap ,(if ldap-enabled?
394 `((address ,ldap-address)
395 (bindDN ,ldap-bind-dn)
396 ,@(if ldap-transport
397 `((transport ,ldap-transport))
398 '())
399 ,@(if ldap-insecure-skip-verify
400 `((insecureSkipVerify ,ldap-insecure-skip-verify))
401 '())
402 ,@(if ldap-search-base-dn
403 `((searchBaseDN ,ldap-search-base-dn))
404 '())
405 ,@(if ldap-search-filter
406 `((searchFilter ,ldap-search-filter))
407 '()))
408 ""))
409 (options (listenAddress ,listen-address)
410 (globalAnnounceServer ,global-announce-server)
411 (globalAnnounceEnabled ,(bool->xml-string global-announce-enabled?))
412 (localAnnounceEnabled ,(bool->xml-string local-announce-enabled?))
413 (localAnnouncePort ,local-announce-port)
414 (localAnnounceMCAddr ,local-announce-mac-address)
415 (maxSendKbps ,max-send-kbps)
416 (maxRecvKbps ,max-receive-kbps)
417 (reconnectionIntervalS ,reconnection-interval-seconds)
418 (relaysEnabled ,(bool->xml-string relays-enabled?))
419 (relayReconnectIntervalM ,relay-reconnect-interval-minutes)
420 (startBrowser ,(bool->xml-string start-browser?))
421 (natEnabled ,(bool->xml-string nat-enabled?))
422 (natLeaseMinutes ,nat-lease-minutes)
423 (natRenewalMinutes ,nat-renewal-minutes)
424 (natTimeoutSeconds ,nat-timeout-seconds)
425 (urAccepted ,usage-reporting-accepted)
426 (urSeen ,usage-reporting-seen)
427 (urUniqueID ,usage-reporting-unique-id)
428 (urURL ,usage-reporting-url)
429 (urPostInsecurely ,(bool->xml-string usage-reporting-post-insecurely?))
430 (urInitialDelayS ,usage-reporting-initial-delay-seconds)
431 (autoUpgradeIntervalH ,auto-upgrade-interval-hours)
432 (upgradeToPreReleases ,(bool->xml-string upgrade-to-pre-releases?))
433 (keepTemporariesH ,keep-temporaries-hours)
434 (cacheIgnoredFiles ,(bool->xml-string cache-ignored-files?))
435 (progressUpdateIntervalS ,progress-update-interval-seconds)
436 (limitBandwidthInLan ,(bool->xml-string limit-bandwidth-in-lan?))
437 (minHomeDiskFree (@ (unit ,min-home-disk-free-unit))
438 ,min-home-disk-free)
439 (releasesURL ,releases-url)
440 (overwriteRemoteDeviceNamesOnConnect ,(bool->xml-string overwrite-remote-device-names-on-connect?))
441 (tempIndexMinBlocks ,temp-index-min-blocks)
442 (unackedNotificationID ,unacked-notification-id)
443 (trafficClass ,traffic-class)
444 (setLowPriority ,(bool->xml-string set-low-priority?))
445 (maxFolderConcurrency ,max-folder-concurrency)
446 (crashReportingURL ,crash-reporting-url)
447 (crashReportingEnabled ,(bool->xml-string crash-reporting-enabled?))
448 (stunKeepaliveStartS ,stun-keepalive-start-seconds)
449 (stunKeepaliveMinS ,stun-keepalive-min-seconds)
450 (stunServer ,stun-server)
451 (databaseTuning ,database-tuning)
452 (maxConcurrentIncomingRequestKiB ,max-concurrent-incoming-request-kib)
453 (announceLANAddresses ,(bool->xml-string announce-lan-addresses?))
454 (sendFullIndexOnUpgrade ,(bool->xml-string send-full-index-on-upgrade?))
455 (connectionLimitEnough ,connection-limit-enough)
456 (connectionLimitMax ,connection-limit-max)
457 (insecureAllowOldTLSVersions ,(bool->xml-string insecure-allow-old-tls-versions?))
458 (connectionPriorityTcpLan ,connection-priority-tcp-lan)
459 (connectionPriorityQuicLan ,connection-priority-quic-lan)
460 (connectionPriorityTcpWan ,connection-priority-tcp-wan)
461 (connectionPriorityQuicWan ,connection-priority-quic-wan)
462 (connectionPriorityRelay ,connection-priority-relay)
463 (connectionPriorityUpgradeThreshold ,connection-priority-upgrade-threshold))
464 (defaults
465 ,(syncthing-folder->sxml default-folder)
466 ,(syncthing-device->sxml default-device)
467 (ignores ,default-ignores)))))
468
469
470(define (serialize-syncthing-config-file config)
471 (with-output-to-string
472 (lambda ()
473 (sxml->xml (cons '*TOP* (list (syncthing-config-file->sxml config)))))))
474
475(define-record-type* <syncthing-configuration>
476 syncthing-configuration make-syncthing-configuration
477 syncthing-configuration?
478 (syncthing syncthing-configuration-syncthing ;file-like
479 (default syncthing))
480 (arguments syncthing-configuration-arguments ;list of strings
481 (default '()))
482 (logflags syncthing-configuration-logflags ;number
483 (default 0))
484 (user syncthing-configuration-user ;string
485 (default #f))
486 (group syncthing-configuration-group ;string
487 (default "users"))
488 (home syncthing-configuration-home ;string
489 (default #f))
490 (config-file syncthing-configuration-config-file
491 (default #f)) ; syncthing-config-file or file-like
492 (home-service? syncthing-configuration-home-service?
493 (default for-home?) (innate)))
494
495(define syncthing-shepherd-service
496 (match-record-lambda <syncthing-configuration>
497 (syncthing arguments logflags user group home home-service? config-file)
498 (list
499 (shepherd-service
500 (provision (if home-service?
501 '(syncthing)
502 (list (string->symbol
503 (string-append "syncthing-" user)))))
504 (documentation "Run syncthing.")
505 (requirement (if home-service? '() '(loopback user-processes)))
506 (start #~(lambda _
507 ;; If we are managing the config, and it's not a home
508 ;; service, then exepect the config file at
509 ;; /var/lib/syncthing-<user>. This makes sure the ownership
510 ;; is correct.
511 (unless (or #$(not config-file) #$home-service?)
512 (let ((user-pw (getpw #$user)))
513 (chown (string-append "/var/lib/syncthing-" #$user)
514 (passwd:uid user-pw)
515 (passwd:gid user-pw)))
516 (chmod (string-append "/var/lib/syncthing-" #$user) #o700))
517
518 (fork+exec-command
519 (append (list (string-append #$syncthing "/bin/syncthing")
520 ;; Do not try to try to launch a web browser on startup.
521 "--no-browser"
522 ;; If syncthing crashes, let the service fail.
523 "--no-restart"
524 (string-append "--logflags=" (number->string #$logflags)))
525 ;; Optionally move data and configuration home to
526 ;; /var/lib/syncthing-<user>.
527 (if (or #$(not config-file) #$home-service?) '()
528 (list (string-append "--home=/var/lib/syncthing-" #$user)))
529 '#$arguments)
530 #:user #$(and (not home-service?) user)
531 #:group #$(and (not home-service?) group)
532 #:environment-variables
533 (append
534 (list
535 (string-append "HOME="
536 (or #$home
537 (passwd:dir
538 (getpw (if (and #$home-service?
539 (not #$user))
540 (getuid)
541 #$user)))))
542 "SSL_CERT_DIR=/etc/ssl/certs"
543 "SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt")
544 (filter (negate ;XXX: 'remove' is not in (guile)
545 (lambda (str)
546 (or (string-prefix? "HOME=" str)
547 (string-prefix? "SSL_CERT_DIR=" str)
548 (string-prefix? "SSL_CERT_FILE=" str))))
549 (environ))))))
550 (respawn? #f)
551 (stop #~(make-kill-destructor))))))
552
553(define syncthing-files-service
554 (match-record-lambda <syncthing-configuration> (config-file user home home-service?)
555 (if config-file
556 ;; When used as a system service, this service might be executed
557 ;; before a user's home even exists, causing it to be owned by root,
558 ;; and the skeletons to never be applied to that user's home. In such
559 ;; cases, put the config at /var/lib/syncthing-<user>/config.xml
560 `((,(if home-service?
561 ".local/state/syncthing/config.xml"
562 (string-append "/var/lib/syncthing-" user "/config.xml"))
563 ,(if (file-like? config-file)
564 config-file
565 (plain-file "syncthing-config.xml" (serialize-syncthing-config-file
566 config-file)))))
567 '())))
568
569(define syncthing-service-type
570 (service-type (name 'syncthing)
571 (extensions (list (service-extension shepherd-root-service-type
572 syncthing-shepherd-service)
573 (service-extension special-files-service-type
574 syncthing-files-service)))
575 (description
576 "Run @uref{https://github.com/syncthing/syncthing, Syncthing}
577decentralized continuous file system synchronization.")))
578
579;;; syncthing.scm ends here