@@ -4,6 +4,7 @@ import { UnControlled as CodeMirror } from 'react-codemirror2'
44import SnappyJS from 'snappyjs'
55import { Buffer } from "buffer" ;
66import { decode , encode } from "@msgpack/msgpack" ;
7+ import { Reader } from "protobufjs" ;
78
89const zlib = require ( 'zlib' ) ;
910require ( 'codemirror/mode/javascript/javascript' ) ;
@@ -34,6 +35,73 @@ const prefixToTypeName = {
3435 GA : "Gate" ,
3536} ;
3637
38+ // Helper function to parse protobuf buffer and extract field information
39+ function parseProtobufBuffer ( buffer ) {
40+ const reader = new Reader ( buffer ) ;
41+ const fields = { } ;
42+
43+ while ( reader . pos < reader . len ) {
44+ const tag = reader . uint32 ( ) ;
45+ const fieldNumber = tag >>> 3 ;
46+ const wireType = tag & 7 ;
47+
48+ let value ;
49+ switch ( wireType ) {
50+ case 0 : // Varint
51+ value = reader . uint64 ( ) . toString ( ) ;
52+ break ;
53+ case 1 : // 64-bit
54+ value = reader . fixed64 ( ) . toString ( ) ;
55+ break ;
56+ case 2 : // Length-delimited
57+ const bytes = reader . bytes ( ) ;
58+ // Try to parse as string, fallback to hex
59+ try {
60+ value = new TextDecoder ( ) . decode ( bytes ) ;
61+ // If it contains non-printable characters, show as hex
62+ if ( ! / ^ [ \x20 - \x7E ] * $ / . test ( value ) ) {
63+ value = Buffer . from ( bytes ) . toString ( 'hex' ) ;
64+ }
65+ } catch {
66+ value = Buffer . from ( bytes ) . toString ( 'hex' ) ;
67+ }
68+ break ;
69+ case 3 : // Start group (deprecated)
70+ value = "start_group" ;
71+ break ;
72+ case 4 : // End group (deprecated)
73+ value = "end_group" ;
74+ break ;
75+ case 5 : // 32-bit
76+ value = reader . fixed32 ( ) ;
77+ break ;
78+ default :
79+ value = "unknown_wire_type" ;
80+ }
81+
82+ fields [ `field_${ fieldNumber } ` ] = {
83+ field_number : fieldNumber ,
84+ wire_type : wireType ,
85+ wire_type_name : getWireTypeName ( wireType ) ,
86+ value : value
87+ } ;
88+ }
89+
90+ return fields ;
91+ }
92+
93+ function getWireTypeName ( wireType ) {
94+ const wireTypeNames = {
95+ 0 : "VARINT" ,
96+ 1 : "I64" ,
97+ 2 : "LEN" ,
98+ 3 : "SGROUP" ,
99+ 4 : "EGROUP" ,
100+ 5 : "I32"
101+ } ;
102+ return wireTypeNames [ wireType ] || "UNKNOWN" ;
103+ }
104+
37105// Additional CodeMirror options can be found here: https://github.com/JedWatson/react-codemirror
38106var inputOptions = {
39107 lineNumbers : true ,
@@ -85,9 +153,24 @@ export class JSONFormatter extends Component {
85153 var base64regex = / ^ ( [ 0 - 9 a - z A - Z + / ] { 4 } ) * ( ( [ 0 - 9 a - z A - Z + / ] { 2 } = = ) | ( [ 0 - 9 a - z A - Z + / ] { 3 } = ) ) ? $ / ;
86154 var intRegex = / ^ [ 0 - 9 ] + $ / ;
87155 if ( base64regex . test ( input ) ) {
88- var uncompressed = SnappyJS . uncompress ( Buffer . from ( input , 'base64' ) ) ;
89- let utf8decoder = new TextDecoder ( )
90- jsonString = utf8decoder . decode ( uncompressed ) ;
156+ try {
157+ // First try snappy decompression
158+ var uncompressed = SnappyJS . uncompress ( Buffer . from ( input , 'base64' ) ) ;
159+ let utf8decoder = new TextDecoder ( )
160+ jsonString = utf8decoder . decode ( uncompressed ) ;
161+ } catch ( snappyError ) {
162+ try {
163+ // If snappy fails, try protobuf parsing
164+ const protobufBuffer = Buffer . from ( input , 'base64' ) ;
165+ const parsedProtobuf = parseProtobufBuffer ( protobufBuffer ) ;
166+ jsonString = JSON . stringify ( {
167+ type : "protobuf_message" ,
168+ fields : parsedProtobuf
169+ } , null , 4 ) ;
170+ } catch ( protobufError ) {
171+ throw new Error ( "Unable to parse as snappy-compressed or protobuf data: " + protobufError . message ) ;
172+ }
173+ }
91174 }
92175 else if ( intRegex . test ( input ) ) {
93176 var intValue = parseInt ( input , 10 ) ; // base 10
0 commit comments