@dra2020/dra-types 1.4.9 → 1.5.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/stats.ts ADDED
@@ -0,0 +1,203 @@
1
+ // In constrast to logging, the stats manager is responsible for tracking live server status.
2
+ // The results are stored in a compact database record which can be easily queried for current
3
+ // status. Each server instance maintains its own field in the overall "values" record in the
4
+ // stats database. The reporting tool aggregates all instances to report overall server activity.
5
+ //
6
+ // There are basically three kinds of values:
7
+ // Sum - we want to sum the value across all server instances (e.g. number of connnected clients)
8
+ // Avg - we just take average across all server instances (e.g. memory heap size)
9
+ // Rate - we want to track the rate of some activity over some time period
10
+ //
11
+
12
+ export type ValType = number;
13
+ export const ValTypeSum = 0;
14
+ export const ValTypeAvg = 1;
15
+ export const ValTypeRate = 2;
16
+
17
+ const ExpiryAge = 1000 * 60 * 60 * 24; // throw away instance record after this time period
18
+
19
+ export function statExpiryTime(): string
20
+ {
21
+ let time = new Date();
22
+ time.setTime(time.getTime() + ExpiryAge);
23
+ return time.toJSON();
24
+ }
25
+
26
+ export interface StatRecord
27
+ {
28
+ id: string;
29
+ production: boolean;
30
+ expires: string;
31
+ time: string;
32
+ index: StatEntryIndex;
33
+ }
34
+
35
+ export type StatEntry = StatValue | StatRate;
36
+
37
+ export type StatEntryIndex = { [name: string]: StatEntry };
38
+
39
+ export interface StatValue
40
+ {
41
+ valType?: ValType;
42
+ cur?: number;
43
+ min?: number;
44
+ max?: number;
45
+ tot?: number;
46
+ cnt?: number;
47
+ }
48
+
49
+ export interface StatRate
50
+ {
51
+ valType?: ValType;
52
+ thisMin?: number;
53
+ lastMin?: number;
54
+ thisHour?: number;
55
+ lastHour?: number;
56
+ thisDay?: number;
57
+ lastDay?: number;
58
+ }
59
+
60
+ // Aggregate running value. This applies both in memory (logging multiple times before
61
+ // saving to database) as well as aggregating into an instance structure in the DB.
62
+
63
+ export function statValueRecord(sv: StatValue, cur: number, valType: ValType): StatValue
64
+ {
65
+ if (sv === undefined) sv = {};
66
+ if (sv.min === undefined || cur < sv.min)
67
+ sv.min = cur;
68
+ if (sv.max === undefined || cur > sv.max)
69
+ sv.max = cur;
70
+ sv.cur = cur;
71
+ sv.valType = valType;
72
+ return sv;
73
+ }
74
+
75
+ export function statRateIncr(sr: StatRate, incr: number = 1): StatRate
76
+ {
77
+ if (sr == null) sr = {};
78
+ sr.valType = ValTypeRate;
79
+ sr.thisMin = sr.thisMin === undefined ? incr : sr.thisMin+incr;
80
+ sr.thisHour = sr.thisHour === undefined ? incr : sr.thisHour+incr;
81
+ sr.thisDay = sr.thisDay === undefined ? incr : sr.thisDay+incr;
82
+ return sr;
83
+ }
84
+
85
+ export const OneMinute = 1000 * 60;
86
+ export const OneHour = OneMinute * 60;
87
+ export const OneDay = OneHour * 24;
88
+
89
+ export function statRateRollover(sr: StatRate, period: number): void
90
+ {
91
+ if ((period % OneMinute) == 0)
92
+ {
93
+ sr.lastMin = sr.thisMin;
94
+ sr.thisMin = 0;
95
+ }
96
+ if ((period % OneHour) == 0)
97
+ {
98
+ sr.lastHour = sr.thisHour;
99
+ sr.thisHour = 0;
100
+ }
101
+ if ((period % OneDay) == 0)
102
+ {
103
+ sr.lastDay = sr.thisDay;
104
+ sr.thisDay = 0;
105
+ }
106
+ }
107
+
108
+ export function statEntryIndexMerge(accum: StatEntryIndex, si: StatEntryIndex): StatEntryIndex
109
+ {
110
+ if (accum == null) accum = {};
111
+
112
+ // We just discard and replace old rate information
113
+ Object.keys(accum).forEach((p: string) => { if (accum[p].valType == ValTypeRate) delete accum[p] });
114
+
115
+ // But merge in all the other values
116
+ Object.keys(si).forEach((p: string) => {
117
+ let se = si[p];
118
+ if (se.valType == ValTypeRate)
119
+ accum[p] = se;
120
+ else
121
+ {
122
+ let sv = se as StatValue;
123
+ accum[p] = statValueRecord(se as StatValue, sv.cur, sv.valType);
124
+ }
125
+ });
126
+ return accum;
127
+ }
128
+
129
+ export function statEntryIndexRollover(si: StatEntryIndex, period: number): void
130
+ {
131
+ Object.keys(si).forEach((p: string) => {
132
+ let se = si[p];
133
+ if (se.valType == ValTypeRate)
134
+ statRateRollover(se as StatRate, period);
135
+ });
136
+ }
137
+
138
+ export function statRecordMerge(accum: StatRecord, si: StatRecord): StatRecord
139
+ {
140
+ if (accum == null)
141
+ accum = { id: si.id, production: si.production, time: si.time, expires: si.expires, index: {} };
142
+ accum.expires = si.expires;
143
+ accum.time = si.time;
144
+ statEntryIndexMerge(accum.index, si.index);
145
+ return accum;
146
+ }
147
+
148
+ // Accumulate a set of values together (e.g. from multiple running instances)
149
+ // for reporting current state.
150
+ //
151
+
152
+ export function statValueAccum(accum: StatValue, sv: StatValue): StatEntry
153
+ {
154
+ if (accum == null)
155
+ {
156
+ accum = {};
157
+ accum.valType = sv.valType;
158
+ }
159
+ if (accum.min === undefined || sv.min < accum.min)
160
+ accum.min = sv.min;
161
+ if (accum.max === undefined || sv.max > accum.max)
162
+ accum.max = sv.max;
163
+ if (accum.valType === undefined)
164
+ accum.valType = sv.valType;
165
+ if (accum.valType == ValTypeSum)
166
+ accum.cur = (accum.cur === undefined ? sv.cur : accum.cur+sv.cur);
167
+ else if (accum.valType == ValTypeAvg)
168
+ {
169
+ accum.tot = (accum.tot === undefined ? 0 : accum.tot) + sv.cur;
170
+ accum.cnt = (accum.cnt === undefined ? 0 : accum.cnt) + 1;
171
+ accum.cur = accum.tot / accum.cnt;
172
+ }
173
+ return accum;
174
+ }
175
+
176
+ export function statRateAccum(accum: StatRate, sr: StatRate): StatRate
177
+ {
178
+ if (accum == null)
179
+ {
180
+ accum = {};
181
+ accum.valType = sr.valType;
182
+ }
183
+ accum.thisMin = accum.thisMin === undefined ? sr.thisMin : (accum.thisMin + (sr.thisMin === undefined ? 0 : sr.thisMin));
184
+ accum.lastMin = accum.lastMin === undefined ? sr.lastMin : (accum.lastMin + (sr.lastMin === undefined ? 0 : sr.lastMin));
185
+ accum.thisHour = accum.thisHour === undefined ? sr.thisHour : (accum.thisHour + (sr.thisHour === undefined ? 0 : sr.thisHour));
186
+ accum.lastHour = accum.lastHour === undefined ? sr.lastHour : (accum.lastHour + (sr.lastHour === undefined ? 0 : sr.lastHour));
187
+ accum.thisDay = accum.thisDay === undefined ? sr.thisDay : (accum.thisDay + (sr.thisDay === undefined ? 0 : sr.thisDay));
188
+ accum.lastDay = accum.lastDay === undefined ? sr.lastDay : (accum.lastDay + (sr.lastDay === undefined ? 0 : sr.lastDay));
189
+ return accum;
190
+ }
191
+
192
+ export function statIndexAccum(accum: StatEntryIndex, si: StatEntryIndex): StatEntryIndex
193
+ {
194
+ if (accum == null) accum = {};
195
+ Object.keys(si).forEach((p: string) => {
196
+ let se = si[p];
197
+ if (se.valType == ValTypeRate)
198
+ accum[p] = statRateAccum(accum[p] as StatRate, se as StatRate);
199
+ else
200
+ accum[p] = statValueAccum(accum[p] as StatValue, se as StatValue);
201
+ });
202
+ return accum;
203
+ }
@@ -0,0 +1,105 @@
1
+ // Public libraries
2
+ import * as Hash from 'object-hash';
3
+
4
+ export interface SplitBlock
5
+ {
6
+ id?: string;
7
+ chunkKey?: string;
8
+ chunk?: string;
9
+ state: string;
10
+ datasource: string;
11
+ geoid: string;
12
+ blocks: string[];
13
+ }
14
+
15
+ export type DistrictToSplitBlock = { [districtID: string]: SplitBlock[] };
16
+
17
+ // Canonical hashing of splitblock data
18
+ function hash(o: any): string
19
+ {
20
+ return Hash(o,
21
+ { respectType: false,
22
+ unorderedArrays: true,
23
+ unorderedObjects: true,
24
+ excludeKeys: (k: string) => (k === 'id' || k === 'chunk')
25
+ });
26
+ }
27
+
28
+ export function vgeoidToGeoid(vgeoid: string): string
29
+ {
30
+ let re = /vfeature_([^_]*)_.*/;
31
+ let a = re.exec(vgeoid);
32
+ if (a == null || a.length != 2)
33
+ return '';
34
+ else
35
+ return a[1];
36
+ }
37
+
38
+ export function vgeoidToChunk(vgeoid: string): string
39
+ {
40
+ // vgeoid is string of form: "vfeature_[geoid]_[chunkid]_[hash]"
41
+ // the contents are chunked into a file of form "vfeature_chunk_[chunkid]"
42
+ // So extract the chunk ID and download that.
43
+ let re = /vfeature_([^_]*)_([^_*])_(.*)/;
44
+ let a = re.exec(vgeoid);
45
+ if (a && a.length == 4)
46
+ vgeoid = `vfeature_chunk_${a[2]}`;
47
+ else
48
+ vgeoid = null;
49
+
50
+ return vgeoid;
51
+ }
52
+
53
+ export function vgeoidToHash(vgeoid: string): string
54
+ {
55
+ // vgeoid is string of form: "vfeature_[geoid]_[chunkid]_[hash]"
56
+ let re = /vfeature_([^_]*)_([^_*])_(.*)/;
57
+ let a = re.exec(vgeoid);
58
+ if (a && a.length == 4)
59
+ vgeoid = a[3];
60
+ else
61
+ vgeoid = null;
62
+
63
+ return vgeoid;
64
+ }
65
+
66
+ export function isVfeature(geoid: string): boolean
67
+ {
68
+ return geoid.indexOf('vfeature') === 0;
69
+ }
70
+
71
+ export function splitToCacheKey(s: SplitBlock): string
72
+ {
73
+ if (s.id === undefined)
74
+ s.id = hash(s);
75
+ if (s.chunk === undefined)
76
+ s.chunk = "0";
77
+
78
+ return `_${s.state}_${s.datasource}_vfeature_${s.geoid}_${s.chunk}_${s.id}.geojson`;
79
+ }
80
+
81
+ export function splitToChunkKey(s: SplitBlock): string
82
+ {
83
+ if (s.chunk === undefined)
84
+ s.chunk = "0";
85
+
86
+ return `_${s.state}_${s.datasource}_vfeature_chunk_${s.chunk}.geojson`;
87
+ }
88
+
89
+ export function splitToPrefix(s: SplitBlock): string
90
+ {
91
+ if (s.blocks === undefined)
92
+ {
93
+ let re = /_([^_]*)_(.*)_vfeature.*\.geojson$/;
94
+ let a = re.exec(s.id);
95
+ if (a && a.length == 3)
96
+ return `_${a[1]}_${a[2]}`;
97
+ return s.id;
98
+ }
99
+ return `_${s.state}_${s.datasource}`;
100
+ }
101
+
102
+ export function cacheKeysToChunkHash(keys: string[]): string
103
+ {
104
+ return hash(keys);
105
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dra2020/dra-types",
3
- "version": "1.4.9",
3
+ "version": "1.5.11",
4
4
  "description": "Shared types used between client and server.",
5
5
  "main": "dist/dra-types.js",
6
6
  "types": "./dist/all.d.ts",
@@ -24,7 +24,7 @@
24
24
  "homepage": "https://github.com/dra2020/dra-types#readme",
25
25
  "devDependencies": {
26
26
  "@types/node": "12.7.2",
27
- "@types/object-hash": "^1.3.0",
27
+ "@types/object-hash": "^1.3.1",
28
28
  "source-map-loader": "^0.2.4",
29
29
  "ts-loader": "^6.2.1",
30
30
  "tsify": "^4.0.1",
@@ -33,7 +33,7 @@
33
33
  "webpack-cli": "^3.3.11"
34
34
  },
35
35
  "dependencies": {
36
- "@dra2020/util": "^1.0.40",
37
- "object-hash": "^2.0.0"
36
+ "@dra2020/util": "^1.0.50",
37
+ "object-hash": "^2.0.3"
38
38
  }
39
39
  }