Skip to content

Commit e51380e

Browse files
committed
StatsHouse UI: raw tag value encode
1 parent 71b6dd9 commit e51380e

File tree

3 files changed

+220
-24
lines changed

3 files changed

+220
-24
lines changed

statshouse-ui/src/components2/Plot/PlotControl/PlotControlFilterTag.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { setUpdatedTag, useVariableListStore } from '@/store2/variableList';
1515
import { type PlotKey, QueryParams } from '@/url2';
1616
import { useStatsHouseShallow } from '@/store2';
1717
import { useVariableLink } from '@/hooks/useVariableLink';
18-
import { getTagDescription } from '@/view/utils2';
18+
import { getTagDescription, getTagValue } from '@/view/utils2';
1919
import { VariableControl } from '@/components/VariableControl';
2020

2121
export type PlotControlFilterTagProps = {
@@ -125,6 +125,7 @@ export const PlotControlFilterTag = memo(function PlotControlFilterTag({
125125
if (tagKey == null) {
126126
return;
127127
}
128+
values = getTagValue(meta, tagKey, values);
128129
if (variableInfo) {
129130
setParams(
130131
produce((p) => {
@@ -149,7 +150,7 @@ export const PlotControlFilterTag = memo(function PlotControlFilterTag({
149150
);
150151
}
151152
},
152-
[negativeTag, plotKey, setParams, variableInfo]
153+
[meta, negativeTag, plotKey, setParams, variableInfo]
153154
);
154155
const onSetUpdateTag = useCallback(
155156
(tagKey: TagKey | undefined, value: boolean) => {

statshouse-ui/src/view/utils2.test.ts

Lines changed: 119 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
import './../testMock/matchMedia.mock';
88

9-
import { convert, lexDecode } from './utils2';
9+
import { convert, lexDecode, parseRawToInt } from './utils2';
10+
11+
jest.useFakeTimers().setSystemTime(new Date('2020-01-01 00:00:00'));
1012

1113
describe('utils', () => {
1214
test('convert hex', () => {
@@ -18,6 +20,7 @@ describe('utils', () => {
1820
expect(convert('hex', -2142740666)).toBe('0x80485f46');
1921
expect(convert('hex', 167901850)).toBe('0x0a01fa9a');
2022
});
23+
2124
test('convert hex_bswap', () => {
2225
expect(convert('hex_bswap', 0)).toBe('0x00000000');
2326
expect(convert('hex_bswap', 1)).toBe('0x01000000');
@@ -27,13 +30,15 @@ describe('utils', () => {
2730
expect(convert('hex_bswap', -2142740666)).toBe('0x465f4880');
2831
expect(convert('hex_bswap', 167901850)).toBe('0x9afa010a');
2932
});
33+
3034
test('convert undefined', () => {
3135
expect(convert(undefined, 0)).toBe('0');
3236
expect(convert(undefined, 1)).toBe('1');
3337
expect(convert(undefined, -1)).toBe('-1');
3438
expect(convert(undefined, -2147483648)).toBe('-2147483648');
3539
expect(convert(undefined, 2147483647)).toBe('2147483647');
3640
});
41+
3742
test('convert ip', () => {
3843
expect(convert('ip', 0)).toBe('0.0.0.0');
3944
expect(convert('ip', 1)).toBe('0.0.0.1');
@@ -44,6 +49,7 @@ describe('utils', () => {
4449
expect(convert('ip', 2130730822)).toBe('127.0.95.70');
4550
expect(convert('ip', 167901850)).toBe('10.1.250.154');
4651
});
52+
4753
test('convert ip_bswap', () => {
4854
expect(convert('ip_bswap', 0)).toBe('0.0.0.0');
4955
expect(convert('ip_bswap', 1)).toBe('1.0.0.0');
@@ -54,6 +60,7 @@ describe('utils', () => {
5460
expect(convert('ip_bswap', 2130730822)).toBe('70.95.0.127');
5561
expect(convert('ip_bswap', 167901850)).toBe('154.250.1.10');
5662
});
63+
5764
test('convert uint', () => {
5865
expect(convert('uint', 0)).toBe('0');
5966
expect(convert('uint', 1)).toBe('1');
@@ -67,21 +74,17 @@ describe('utils', () => {
6774
test('convert timestamp', () => {
6875
expect(convert('timestamp', 0)).toBe('1970-01-01 00:00:00');
6976
expect(convert('timestamp', 1)).toBe('1970-01-01 00:00:01');
70-
expect(convert('timestamp', -1)).toBe('1969-12-31 23:59:59');
71-
expect(convert('timestamp', -2147483648)).toBe('1901-12-13 20:46:09');
7277
expect(convert('timestamp', 2147483647)).toBe('2038-01-19 03:14:07');
73-
expect(convert('timestamp', -2142740666)).toBe('1902-02-06 18:15:51');
7478
expect(convert('timestamp', 2130730822)).toBe('2037-07-09 05:40:22');
79+
expect(convert('timestamp', 4104803674)).toBe('2100-01-28 07:14:34');
7580
});
7681

7782
test('convert timestamp_local', () => {
7883
expect(convert('timestamp_local', 0)).toBe('1970-01-01 03:00:00');
7984
expect(convert('timestamp_local', 1)).toBe('1970-01-01 03:00:01');
80-
expect(convert('timestamp_local', -1)).toBe('1970-01-01 02:59:59');
81-
expect(convert('timestamp_local', -2147483648)).toBe('1901-12-13 23:16:09');
8285
expect(convert('timestamp_local', 2147483647)).toBe('2038-01-19 06:14:07');
83-
expect(convert('timestamp_local', -2142740666)).toBe('1902-02-06 20:45:51');
8486
expect(convert('timestamp_local', 2130730822)).toBe('2037-07-09 08:40:22');
87+
expect(convert('timestamp_local', 4104803674)).toBe('2100-01-28 10:14:34');
8588
});
8689

8790
test('test lexDecode', () => {
@@ -92,6 +95,7 @@ describe('utils', () => {
9295

9396
expect(lexDecode(-2_139_095_041)).toBe(Number.NEGATIVE_INFINITY);
9497
expect(lexDecode(0)).toBe(0);
98+
expect(lexDecode(-0)).toBe(0);
9599
expect(lexDecode(2_139_095_040)).toBe(Number.POSITIVE_INFINITY);
96100
expect(lexDecode(Number.NEGATIVE_INFINITY)).toBeNaN();
97101

@@ -135,8 +139,11 @@ describe('utils', () => {
135139
res0 = res1;
136140
}
137141
});
142+
138143
test('convert lexenc_float', () => {
139144
expect(convert('lexenc_float', 0)).toBe('0');
145+
expect(convert('lexenc_float', +0.0)).toBe('0');
146+
expect(convert('lexenc_float', -0.0)).toBe('0');
140147
expect(convert('lexenc_float', Number.NEGATIVE_INFINITY)).toBe('NaN');
141148
expect(convert('lexenc_float', -1_139_095_039)).toBe('-458.42181'); // -458.42181396484375
142149
expect(convert('lexenc_float', 1_139_094_939)).toBe('458.41879'); // 458.4187927246094
@@ -146,14 +153,117 @@ describe('utils', () => {
146153

147154
test('convert float', () => {
148155
expect(convert('float', 0)).toBe('0');
156+
expect(convert('float', -0.0)).toBe('0');
149157
expect(convert('float', -1)).toBe('NaN');
150-
expect(convert('float', 1)).toBe('1.4012985e-45'); // 1.401298464324817e-45
151-
expect(convert('float', 3212836864)).toBe('-1');
158+
expect(convert('float', 1)).toBe('0');
159+
expect(convert('float', 3212836864)).toBe('-1'); //uint
160+
expect(convert('float', -1082130432)).toBe('-1');
152161
expect(convert('float', 1065353216)).toBe('1');
153162
expect(convert('float', Number.NEGATIVE_INFINITY)).toBe('0');
154163
expect(convert('float', -1_139_095_039)).toBe('-0.0094475755'); // -0.00944757554680109
155164
expect(convert('float', 1_139_094_939)).toBe('458.41879'); // 458.4187927246094
156165
expect(convert('float', -8388709)).toBe('-3.4028032e+38'); // -3.402803183975685e+38
157166
expect(convert('float', 8388609)).toBe('1.1754945e-38'); // 1.175494490952134e-38
158167
});
168+
169+
//parse raw
170+
test('parseRawToInt hex', () => {
171+
expect(parseRawToInt('hex', '0x00000000')).toBe(0);
172+
expect(parseRawToInt('hex', '0x00000001')).toBe(1);
173+
expect(parseRawToInt('hex', '0xffffffff')).toBe(-1);
174+
expect(parseRawToInt('hex', '0x80000000')).toBe(-2147483648);
175+
expect(parseRawToInt('hex', '0x7fffffff')).toBe(2147483647);
176+
expect(parseRawToInt('hex', '0x80485f46')).toBe(-2142740666);
177+
expect(parseRawToInt('hex', '0x0a01fa9a')).toBe(167901850);
178+
});
179+
180+
test('parseRawToInt hex_bswap', () => {
181+
expect(parseRawToInt('hex_bswap', '0x00000000')).toBe(0);
182+
expect(parseRawToInt('hex_bswap', '0x01000000')).toBe(1);
183+
expect(parseRawToInt('hex_bswap', '0xffffffff')).toBe(-1);
184+
expect(parseRawToInt('hex_bswap', '0x00000080')).toBe(-2147483648);
185+
expect(parseRawToInt('hex_bswap', '0xffffff7f')).toBe(2147483647);
186+
expect(parseRawToInt('hex_bswap', '0x465f4880')).toBe(-2142740666);
187+
expect(parseRawToInt('hex_bswap', '0x9afa010a')).toBe(167901850);
188+
});
189+
190+
test('parseRawToInt undefined', () => {
191+
expect(parseRawToInt(undefined, '0')).toBe(0);
192+
expect(parseRawToInt(undefined, '1')).toBe(1);
193+
expect(parseRawToInt(undefined, '-1')).toBe(-1);
194+
expect(parseRawToInt(undefined, '-2147483648')).toBe(-2147483648);
195+
expect(parseRawToInt(undefined, '2147483647')).toBe(2147483647);
196+
});
197+
198+
test('parseRawToInt ip', () => {
199+
expect(parseRawToInt('ip', '0.0.0.0')).toBe(0);
200+
expect(parseRawToInt('ip', '0.0.0.1')).toBe(1);
201+
expect(parseRawToInt('ip', '255.255.255.255')).toBe(-1);
202+
expect(parseRawToInt('ip', '128.0.0.0')).toBe(-2147483648);
203+
expect(parseRawToInt('ip', '127.255.255.255')).toBe(2147483647);
204+
expect(parseRawToInt('ip', '128.72.95.70')).toBe(-2142740666);
205+
expect(parseRawToInt('ip', '127.0.95.70')).toBe(2130730822);
206+
expect(parseRawToInt('ip', '10.1.250.154')).toBe(167901850);
207+
});
208+
209+
test('parseRawToInt ip_bswap', () => {
210+
expect(parseRawToInt('ip_bswap', '0.0.0.0')).toBe(0);
211+
expect(parseRawToInt('ip_bswap', '1.0.0.0')).toBe(1);
212+
expect(parseRawToInt('ip_bswap', '255.255.255.255')).toBe(-1);
213+
expect(parseRawToInt('ip_bswap', '0.0.0.128')).toBe(-2147483648);
214+
expect(parseRawToInt('ip_bswap', '255.255.255.127')).toBe(2147483647);
215+
expect(parseRawToInt('ip_bswap', '70.95.72.128')).toBe(-2142740666);
216+
expect(parseRawToInt('ip_bswap', '70.95.0.127')).toBe(2130730822);
217+
expect(parseRawToInt('ip_bswap', '154.250.1.10')).toBe(167901850);
218+
});
219+
220+
test('parseRawToInt uint', () => {
221+
expect(parseRawToInt('uint', '0')).toBe(0);
222+
expect(parseRawToInt('uint', '1')).toBe(1);
223+
expect(parseRawToInt('uint', '2147483648')).toBe(-2147483648);
224+
expect(parseRawToInt('uint', '2147483647')).toBe(2147483647);
225+
expect(parseRawToInt('uint', '2152226630')).toBe(-2142740666);
226+
expect(parseRawToInt('uint', '2130730822')).toBe(2130730822);
227+
});
228+
229+
test('parseRawToInt timestamp', () => {
230+
expect(parseRawToInt('timestamp', '1970-01-01 00:00:00')).toBe(0);
231+
expect(parseRawToInt('timestamp', '1970-01-01 00:00:01')).toBe(1);
232+
expect(parseRawToInt('timestamp', '2038-01-19 03:14:07')).toBe(2147483647);
233+
expect(parseRawToInt('timestamp', '2037-07-09 05:40:22')).toBe(2130730822);
234+
expect(parseRawToInt('timestamp', '2100-01-28 07:14:34')).toBe(4104803674);
235+
});
236+
237+
test('parseRawToInt timestamp_local', () => {
238+
expect(parseRawToInt('timestamp_local', '1970-01-01 03:00:00')).toBe(0);
239+
expect(parseRawToInt('timestamp_local', '1970-01-01 03:00:01')).toBe(1);
240+
expect(parseRawToInt('timestamp_local', '2038-01-19 06:14:07')).toBe(2147483647);
241+
expect(parseRawToInt('timestamp_local', '2037-07-09 08:40:22')).toBe(2130730822);
242+
expect(parseRawToInt('timestamp_local', '2100-01-28 10:14:34')).toBe(4104803674);
243+
});
244+
245+
test('parseRawToInt lexenc_float', () => {
246+
expect(parseRawToInt('lexenc_float', '0')).toBe(0);
247+
expect(parseRawToInt('lexenc_float', '-0.0')).toBe(0);
248+
expect(parseRawToInt('lexenc_float', '+0.0')).toBe(0);
249+
expect(parseRawToInt('lexenc_float', 'NaN')).toBeNaN();
250+
expect(parseRawToInt('lexenc_float', '-458.42181')).toBe(-1_139_095_039);
251+
expect(parseRawToInt('lexenc_float', '458.41879')).toBe(1_139_094_939);
252+
expect(parseRawToInt('lexenc_float', '-1.1755084e-38')).toBe(-8388709);
253+
expect(parseRawToInt('lexenc_float', '1.1754945e-38')).toBe(8388609);
254+
});
255+
256+
test('parseRawToInt float', () => {
257+
expect(parseRawToInt('float', '0')).toBe(0);
258+
expect(parseRawToInt('float', '+0.0')).toBe(0);
259+
expect(parseRawToInt('float', '-0.0')).toBe(0);
260+
expect(parseRawToInt('float', 'NaN')).toBeNaN();
261+
expect(parseRawToInt('float', '1.4012985e-45')).toBe(1); //non 32 bit
262+
expect(parseRawToInt('float', '-1')).toBe(-1082130432);
263+
expect(parseRawToInt('float', '1')).toBe(1065353216);
264+
expect(parseRawToInt('float', '-0.0094475755')).toBe(-1_139_095_039);
265+
expect(parseRawToInt('float', '458.41879')).toBe(1_139_094_939);
266+
expect(parseRawToInt('float', '-3.4028032e+38')).toBe(-8388709);
267+
expect(parseRawToInt('float', '1.1754945e-38')).toBe(8388609);
268+
});
159269
});

statshouse-ui/src/view/utils2.ts

Lines changed: 98 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
// License, v. 2.0. If a copy of the MPL was not distributed with this
55
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
66

7-
import { MetricMetaValue } from '../api/metric';
8-
import { isTagKey, TAG_KEY, TagKey } from '../api/enum';
7+
import { MetricMetaValue } from '@/api/metric';
8+
import { isTagKey, TAG_KEY, TagKey } from '@/api/enum';
99
import uPlot from 'uplot';
10-
import { TimeRange } from '../common/TimeRange';
11-
import { formatFixed } from '../common/formatFixed';
12-
import { formatFixedFloor } from '../common/formatFixedFloor';
10+
import { TimeRange } from '@/common/TimeRange';
11+
import { formatFixed } from '@/common/formatFixed';
12+
import { formatFixedFloor } from '@/common/formatFixedFloor';
1313
import { RawValueKind } from './api';
1414

1515
export function isValidVariableName(name: string): boolean {
@@ -45,6 +45,16 @@ export function getTagDescription(meta: MetricMetaValue | undefined, tagKey: num
4545
return `tag ${tagKey}`;
4646
}
4747

48+
export function getTagValue(meta: MetricMetaValue | undefined, tagKey: TagKey | null, values: string[]): string[] {
49+
if (tagKey != null) {
50+
const infoTag = meta?.tags?.[+tagKey];
51+
if (infoTag?.raw) {
52+
return values.map((v) => (v[0] === ' ' ? v : ' ' + parseRawToInt(infoTag.raw_kind, v)));
53+
}
54+
}
55+
return values;
56+
}
57+
4858
export function secondsRangeToString(seconds: number, short?: boolean): string {
4959
const suffix: Array<[number, string, string, string]> = [
5060
[60, 'second', 'seconds', 's'],
@@ -438,11 +448,48 @@ export function ieee32ToFloat(intval: number): number {
438448
}
439449
return fval;
440450
}
451+
export function floatToIeee32(value: number): number {
452+
if (isNaN(value)) {
453+
return NaN;
454+
}
455+
if (!value) {
456+
return 0;
457+
}
458+
const dataView = new DataView(new ArrayBuffer(4));
459+
dataView.setFloat32(0, value);
460+
return dataView.getInt32(0, false);
461+
}
462+
463+
export function intToUint(value: number): number {
464+
if (isNaN(value)) {
465+
return NaN;
466+
}
467+
const dataView = new DataView(new ArrayBuffer(4));
468+
dataView.setInt32(0, value);
469+
return dataView.getUint32(0, false);
470+
}
471+
472+
export function uintToInt(value: number): number {
473+
if (isNaN(value)) {
474+
return NaN;
475+
}
476+
const dataView = new DataView(new ArrayBuffer(4));
477+
dataView.setUint32(0, value);
478+
return dataView.getInt32(0, false);
479+
}
441480

442481
export function lexDecode(intval: number): number {
443482
return ieee32ToFloat(intval < 0 ? (intval >>> 0) ^ 0x7fffffff : intval >>> 0);
444483
}
445484

485+
export function lexEncode(value: number): number {
486+
const num = floatToIeee32(value);
487+
if (isNaN(num)) {
488+
return NaN;
489+
}
490+
return num < 0 ? (num >>> 0) ^ 0x7fffffff : num >>> 0;
491+
}
492+
446493
export function convert(kind: RawValueKind | undefined, input: number): string {
447494
switch (kind) {
448495
case 'hex':
@@ -456,24 +503,62 @@ export function convert(kind: RawValueKind | undefined, input: number): string {
456503
`00${((input >> 24) & 255).toString(16)}`.slice(-2))
457504
);
458505
case 'timestamp':
459-
return fmtInputDateTime(uPlot.tzDate(new Date(input * 1000), 'UTC'));
506+
return fmtInputDateTime(uPlot.tzDate(new Date(intToUint(input) * 1000), 'UTC'));
460507
case 'timestamp_local':
461-
return fmtInputDateTime(new Date(input * 1000));
508+
return fmtInputDateTime(new Date(intToUint(input) * 1000));
462509
case 'ip':
463510
return ((input >> 24) & 255) + '.' + ((input >> 16) & 255) + '.' + ((input >> 8) & 255) + '.' + (input & 255);
464511
case 'ip_bswap':
465512
return (input & 255) + '.' + ((input >> 8) & 255) + '.' + ((input >> 16) & 255) + '.' + ((input >> 24) & 255);
466513
case 'uint':
467-
return (input >>> 0).toString(10);
514+
return intToUint(input).toString(10);
468515
case 'lexenc_float':
469516
return parseFloat(lexDecode(input).toPrecision(8)).toString(10);
517+
case 'float':
518+
return parseFloat(ieee32ToFloat(input).toPrecision(8)).toString(10);
519+
default:
520+
return input.toString(10);
521+
}
522+
}
523+
export function parseRawToInt(kind: RawValueKind | undefined, value: string): number {
524+
switch (kind) {
525+
case 'hex':
526+
return parseInt(value, 16) << 0;
527+
case 'hex_bswap':
528+
return parseInt(value.slice(-2) + value.slice(-4, -2) + value.slice(-6, -4) + value.slice(-8, -6), 16) << 0; //(
529+
case 'timestamp': {
530+
const date = new Date(value);
531+
return intToUint(Math.floor((+date - date.getTimezoneOffset() * 6e4) / 1000));
532+
}
533+
case 'timestamp_local':
534+
return intToUint(Math.floor(+new Date(value) / 1000));
535+
case 'ip': {
536+
const strSplit = value.split('.');
537+
return (
538+
parseInt(strSplit[3]) +
539+
(parseInt(strSplit[2]) << 8) +
540+
(parseInt(strSplit[1]) << 16) +
541+
(parseInt(strSplit[0]) << 24)
542+
);
543+
}
544+
case 'ip_bswap': {
545+
const strSplit = value.split('.');
546+
return (
547+
parseInt(strSplit[0]) +
548+
(parseInt(strSplit[1]) << 8) +
549+
(parseInt(strSplit[2]) << 16) +
550+
(parseInt(strSplit[3]) << 24)
551+
);
552+
}
553+
case 'uint':
554+
return uintToInt(parseInt(value, 10));
555+
case 'lexenc_float':
556+
return lexEncode(parseFloat(value));
470557
case 'float': {
471-
const buffer = new ArrayBuffer(4);
472-
const dataView = new DataView(buffer);
473-
dataView.setInt32(0, input, false);
474-
return parseFloat(dataView.getFloat32(0, false).toPrecision(8)).toString(10);
558+
const input = parseFloat(value);
559+
return floatToIeee32(input);
475560
}
476561
default:
477-
return input.toString(10);
562+
return parseInt(value);
478563
}
479564
}

0 commit comments

Comments
 (0)