// reportData returns the data to be sent in a usage report. It's used in // various places, so not part of the usageReportingManager object. func reportData(cfg *config.Wrapper, m *model.Model) map[string]interface{} { res := make(map[string]interface{}) res["urVersion"] = usageReportVersion res["uniqueID"] = cfg.Options().URUniqueID res["version"] = Version res["longVersion"] = LongVersion res["platform"] = runtime.GOOS + "-" + runtime.GOARCH res["numFolders"] = len(cfg.Folders()) res["numDevices"] = len(cfg.Devices()) var totFiles, maxFiles int var totBytes, maxBytes int64 for folderID := range cfg.Folders() { files, _, bytes := m.GlobalSize(folderID) totFiles += files totBytes += bytes if files > maxFiles { maxFiles = files } if bytes > maxBytes { maxBytes = bytes } } res["totFiles"] = totFiles res["folderMaxFiles"] = maxFiles res["totMiB"] = totBytes / 1024 / 1024 res["folderMaxMiB"] = maxBytes / 1024 / 1024 var mem runtime.MemStats runtime.ReadMemStats(&mem) res["memoryUsageMiB"] = (mem.Sys - mem.HeapReleased) / 1024 / 1024 res["sha256Perf"] = cpuBench(5, 125*time.Millisecond) bytes, err := memorySize() if err == nil { res["memorySize"] = bytes / 1024 / 1024 } res["numCPU"] = runtime.NumCPU() var rescanIntvs []int folderUses := map[string]int{ "readonly": 0, "ignorePerms": 0, "ignoreDelete": 0, "autoNormalize": 0, } for _, cfg := range cfg.Folders() { rescanIntvs = append(rescanIntvs, cfg.RescanIntervalS) if cfg.ReadOnly { folderUses["readonly"]++ } if cfg.IgnorePerms { folderUses["ignorePerms"]++ } if cfg.IgnoreDelete { folderUses["ignoreDelete"]++ } if cfg.AutoNormalize { folderUses["autoNormalize"]++ } } sort.Ints(rescanIntvs) res["rescanIntvs"] = rescanIntvs res["folderUses"] = folderUses deviceUses := map[string]int{ "introducer": 0, "customCertName": 0, "compressAlways": 0, "compressMetadata": 0, "compressNever": 0, "dynamicAddr": 0, "staticAddr": 0, } for _, cfg := range cfg.Devices() { if cfg.Introducer { deviceUses["introducer"]++ } if cfg.CertName != "" && cfg.CertName != "syncthing" { deviceUses["customCertName"]++ } if cfg.Compression == protocol.CompressAlways { deviceUses["compressAlways"]++ } else if cfg.Compression == protocol.CompressMetadata { deviceUses["compressMetadata"]++ } else if cfg.Compression == protocol.CompressNever { deviceUses["compressNever"]++ } for _, addr := range cfg.Addresses { if addr == "dynamic" { deviceUses["dynamicAddr"]++ } else { deviceUses["staticAddr"]++ } } } res["deviceUses"] = deviceUses defaultAnnounceServersDNS, defaultAnnounceServersIP, otherAnnounceServers := 0, 0, 0 for _, addr := range cfg.Options().GlobalAnnServers { if addr == "default" || addr == "default-v4" || addr == "default-v6" { defaultAnnounceServersDNS++ } else { otherAnnounceServers++ } } res["announce"] = map[string]interface{}{ "globalEnabled": cfg.Options().GlobalAnnEnabled, "localEnabled": cfg.Options().LocalAnnEnabled, "defaultServersDNS": defaultAnnounceServersDNS, "defaultServersIP": defaultAnnounceServersIP, "otherServers": otherAnnounceServers, } defaultRelayServers, otherRelayServers := 0, 0 for _, addr := range cfg.Options().RelayServers { switch addr { case "dynamic+https://relays.syncthing.net/endpoint": defaultRelayServers++ default: otherRelayServers++ } } res["relays"] = map[string]interface{}{ "enabled": cfg.Options().RelaysEnabled, "defaultServers": defaultRelayServers, "otherServers": otherRelayServers, } res["usesRateLimit"] = cfg.Options().MaxRecvKbps > 0 || cfg.Options().MaxSendKbps > 0 res["upgradeAllowedManual"] = !(upgrade.DisabledByCompilation || noUpgrade) res["upgradeAllowedAuto"] = !(upgrade.DisabledByCompilation || noUpgrade) && cfg.Options().AutoUpgradeIntervalH > 0 return res }
func folderSummary(cfg *config.Wrapper, m *model.Model, folder string) map[string]interface{} { var res = make(map[string]interface{}) res["invalid"] = cfg.Folders()[folder].Invalid globalFiles, globalDeleted, globalBytes := m.GlobalSize(folder) res["globalFiles"], res["globalDeleted"], res["globalBytes"] = globalFiles, globalDeleted, globalBytes localFiles, localDeleted, localBytes := m.LocalSize(folder) res["localFiles"], res["localDeleted"], res["localBytes"] = localFiles, localDeleted, localBytes needFiles, needBytes := m.NeedSize(folder) res["needFiles"], res["needBytes"] = needFiles, needBytes res["inSyncFiles"], res["inSyncBytes"] = globalFiles-needFiles, globalBytes-needBytes var err error res["state"], res["stateChanged"], err = m.State(folder) if err != nil { res["error"] = err.Error() } lv, _ := m.CurrentLocalVersion(folder) rv, _ := m.RemoteLocalVersion(folder) res["version"] = lv + rv ignorePatterns, _, _ := m.GetIgnores(folder) res["ignorePatterns"] = false for _, line := range ignorePatterns { if len(line) > 0 && !strings.HasPrefix(line, "//") { res["ignorePatterns"] = true break } } return res }