summaryrefslogtreecommitdiffstats
path: root/cmd/ursrv/report/aggregation_report.go
blob: b096e31a6bca7cc2262a3dfcf0157a864dd92c42 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Copyright (C) 2024 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

package report

import (
	"fmt"
	"time"
)

type AggregatedReport struct {
	Date                time.Time                 `json:"date"`
	Features            map[string][]Feature      `json:"features"`
	FeatureGroups       map[string][]FeatureGroup `json:"featureGroups"`
	Nodes               int                       `json:"nodes"`
	VersionNodes        map[string]int            `json:"versionNodes"`
	Categories          []Category                `json:"categories"`
	Versions            []Analytic                `json:"versions"`
	VersionPenetrations []Analytic                `json:"versionPenetrations"`
	Platforms           []Analytic                `json:"platforms"`
	Compilers           []Analytic                `json:"compilers"`
	Builders            []Analytic                `json:"builders"`
	Distributions       []Analytic                `json:"distributions"`
	FeatureOrder        []string                  `json:"featureOrder"`
	Locations           []Location                `json:"locations"`
	Countries           []Feature                 `json:"countries"`

	VersionCount map[string]int `json:"versionCount"`
	Performance  Performance    `json:"performance"`
	BlockStats   BlockStats     `json:"blockStats"`
}

type Category struct {
	Values [4]float64 `json:"values"`
	Descr  string     `json:"descr"`
	Unit   string     `json:"unit,omitempty"`
	Type   NumberType `json:"type"`
}

type Feature struct {
	Key     string  `json:"key"`
	Version string  `json:"version"`
	Count   int     `json:"count"`
	Pct     float64 `json:"pct"`
}

type FeatureGroup struct {
	Key     string         `json:"key"`
	Version string         `json:"version"`
	Counts  map[string]int `json:"counts"`
}

type Location struct {
	Latitude  float64 `json:"lat"`
	Longitude float64 `json:"lon"`
	Count     int     `json:"count"`
}

func (l *Location) Inc() {
	l.Count++
}

type Analytic struct {
	Key        string     `json:"key"`
	Count      int        `json:"count"`
	Percentage float64    `json:"percentage"`
	Children   []Analytic `json:"children,omitempty"`
}

type Performance struct {
	TotFiles       int     `json:"totFiles"`
	TotMib         int64   `json:"totMib"`
	Sha256Perf     float64 `json:"sha256Perf"`
	MemorySize     int64   `json:"memorySize"`
	MemoryUsageMib int64   `json:"memoryUsageMib"`
}

type BlockStats struct {
	NodeCount         int     `json:"nodeCount"`
	Total             float64 `json:"total"`
	Renamed           float64 `json:"renamed"`
	Reused            float64 `json:"reused"`
	Pulled            float64 `json:"pulled"`
	CopyOrigin        float64 `json:"copyOrigin"`
	CopyOriginShifted float64 `json:"copyOriginShifted"`
	CopyElsewhere     float64 `json:"copyElsewhere"`
}

func (b *BlockStats) Valid() bool {
	return b.Pulled >= 0 && b.Renamed >= 0 && b.Reused >= 0 && b.CopyOrigin >= 0 && b.CopyOriginShifted >= 0 && b.CopyElsewhere >= 0
}

type NumberType int

const (
	NumberMetric NumberType = iota
	NumberBinary
	NumberDuration
)

type LocationMap struct {
	mapped map[string]Location
}

func NewLocationsMap() LocationMap {
	return LocationMap{mapped: make(map[string]Location)}
}

func (lm *LocationMap) Add(lat, lon float64) {
	id := fmt.Sprintf("%g~%g", lat, lon)
	loc, ok := lm.mapped[id]
	if ok {
		loc.Inc()
	} else {
		loc = Location{Latitude: lat, Longitude: lon, Count: 1}
	}
	lm.mapped[id] = loc
}

func (lm *LocationMap) WeightedLocations() []Location {
	var locations []Location
	for _, location := range lm.mapped {
		locations = append(locations, location)
	}
	return locations
}