@@ -48,29 +48,81 @@ private class DefaultJSONOutput(
4848 private val valueMapper : (signal: Int , value: Any ) -> Any
4949) : TripLogTransformer {
5050
51+ private class SeriesData {
52+ val timestamps = mutableListOf<Long >()
53+ val values = mutableListOf<Any ?>()
54+ }
55+
5156 override fun transform (file : File , metadata : Map <String , String >): File =
5257 file.inputStream().use { input ->
5358 process(JsonReader (InputStreamReader (input)), metadata)
5459 }
5560
56- override fun transform (log : String , metadata : Map <String , String >): File = process(JsonReader (StringReader (log)), metadata)
61+ override fun transform (log : String , metadata : Map <String , String >): File =
62+ process(JsonReader (StringReader (log)), metadata)
5763
5864 private fun process (reader : JsonReader , metadata : Map <String , String >): File {
5965 Log .d(" DefaultJSONOutput" , " Received $metadata " )
6066 val tempFile =
6167 File .createTempFile(" json_buffer_" , " .tmp" ).apply {
62- // Ensures the file is cleaned up if the JVM shuts down
6368 deleteOnExit()
6469 }
6570
71+ val seriesMap = mutableMapOf<String , SeriesData >()
72+
6673 try {
67- // Nested .use calls ensure all streams are closed even if an exception occurs
74+ reader.isLenient = true
75+ parseRootToMemory(reader, seriesMap)
76+
6877 tempFile.outputStream().bufferedWriter().use { fileWriter ->
6978 JsonWriter (fileWriter).use { writer ->
70- reader.isLenient = true
71- writer.beginArray()
72- parseRoot(reader, writer, metadata)
73- writer.endArray()
79+ writer.beginObject() // Root object
80+
81+ // Write Metadata
82+ if (metadata.isNotEmpty()) {
83+ writer.name(" metadata" )
84+ writer.beginObject()
85+ metadata.forEach { (key, value) ->
86+ writer.name(key).value(value)
87+ }
88+ writer.endObject()
89+ }
90+
91+ // Write Signal Dictionary
92+ writer.name(" signal_dictionary" )
93+ writer.beginObject()
94+ seriesMap.keys.forEach { signalKey ->
95+ val idAsInt = signalKey.toIntOrNull()
96+ val translatedName = if (idAsInt != null ) {
97+ signalMapper[idAsInt] ? : signalKey
98+ } else {
99+ signalKey
100+ }
101+ writer.name(signalKey).value(translatedName.toString())
102+ }
103+ writer.endObject()
104+
105+ // Write Series Data
106+ writer.name(" series" )
107+ writer.beginObject()
108+ seriesMap.forEach { (signalId, seriesData) ->
109+ writer.name(signalId)
110+ writer.beginObject()
111+
112+ writer.name(" t" )
113+ writer.beginArray()
114+ seriesData.timestamps.forEach { writer.value(it) }
115+ writer.endArray()
116+
117+ writer.name(" v" )
118+ writer.beginArray()
119+ seriesData.values.forEach { writer.writeDynamicValue(it) }
120+ writer.endArray()
121+
122+ writer.endObject()
123+ }
124+ writer.endObject() // end series
125+ writer.endObject() // end root
74126 }
75127 }
76128 return tempFile
@@ -85,85 +137,73 @@ private class DefaultJSONOutput(
85137 }
86138 }
87139
88- private fun parseRoot (
140+ private fun parseRootToMemory (
89141 reader : JsonReader ,
90- writer : JsonWriter ,
91- metadata : Map <String , String >
142+ seriesMap : MutableMap <String , SeriesData >
92143 ) {
93- if (metadata.isNotEmpty()) {
94- writer.beginObject()
95- writer.name(" metadata" )
96- writer.beginObject()
97- metadata.forEach { (key, value) ->
98- writer.name(key).value(value)
99- }
100- writer.endObject()
101- writer.endObject()
102- }
103-
104144 reader.beginObject()
105145 while (reader.hasNext()) {
106146 if (reader.nextName() == " entries" ) {
107- parseEntries (reader, writer )
147+ parseEntriesToMemory (reader, seriesMap )
108148 } else {
109149 reader.skipValue()
110150 }
111151 }
112152 reader.endObject()
113153 }
114154
115- private fun parseEntries (
155+ private fun parseEntriesToMemory (
116156 reader : JsonReader ,
117- writer : JsonWriter
157+ seriesMap : MutableMap < String , SeriesData >
118158 ) {
119- reader.beginObject() // Start "entries" map
159+ reader.beginObject()
120160 while (reader.hasNext()) {
121161 reader.nextName() // Skip the dynamic key ("12", "99")
122- parseEntryGroup (reader, writer )
162+ parseEntryGroupToMemory (reader, seriesMap )
123163 }
124164 reader.endObject()
125165 }
126166
127- private fun parseEntryGroup (
167+ private fun parseEntryGroupToMemory (
128168 reader : JsonReader ,
129- writer : JsonWriter
169+ seriesMap : MutableMap < String , SeriesData >
130170 ) {
131- reader.beginObject() // Inside "12": {
171+ reader.beginObject()
132172 while (reader.hasNext()) {
133173 if (reader.nextName() == " metrics" ) {
134- parseMetricsArray (reader, writer )
174+ parseMetricsArrayToMemory (reader, seriesMap )
135175 } else {
136- reader.skipValue() // Skip "id", "mean", etc.
176+ reader.skipValue()
137177 }
138178 }
139179 reader.endObject()
140180 }
141181
142- private fun parseMetricsArray (
182+ private fun parseMetricsArrayToMemory (
143183 reader : JsonReader ,
144- writer : JsonWriter
184+ seriesMap : MutableMap < String , SeriesData >
145185 ) {
146- reader.beginArray() // [
186+ reader.beginArray()
147187 while (reader.hasNext()) {
148- parseSingleMetric (reader, writer )
188+ parseSingleMetricToMemory (reader, seriesMap )
149189 }
150190 reader.endArray()
151191 }
152192
153- private fun parseSingleMetric (
193+ private fun parseSingleMetricToMemory (
154194 reader : JsonReader ,
155- writer : JsonWriter
195+ seriesMap : MutableMap < String , SeriesData >
156196 ) {
157197 var ts: Long = 0
158198 var signal = 0
159199 var value: Any = 0.0
160200
161- reader.beginObject() // Metric object {
201+ reader.beginObject()
162202 while (reader.hasNext()) {
163203 when (reader.nextName()) {
164204 " ts" -> ts = reader.nextLong()
165205 " entry" -> {
166- reader.beginObject() // Nested "entry": {
206+ reader.beginObject()
167207 while (reader.hasNext()) {
168208 when (reader.nextName()) {
169209 " data" -> signal = reader.nextInt()
@@ -179,36 +219,28 @@ private class DefaultJSONOutput(
179219 }
180220 reader.endObject()
181221 }
182-
183222 else -> reader.skipValue()
184223 }
185224 }
186-
187225 reader.endObject()
188- writer.beginObject()
189- writer.name(" t" ).value(ts)
190- writer.name(" s" ).value((signalMapper[signal] ? : signal).toString())
191- val mappedResult: Any = valueMapper(signal, value)
192226
193- writer.name(" v" )
194- writer.writeDynamicValue(mappedResult)
195- writer.endObject()
227+ val signalKey = signal.toString() // Group purely by ID
228+ val mappedResult = valueMapper(signal, value)
229+
230+ val series = seriesMap.getOrPut(signalKey) { SeriesData () }
231+ series.timestamps.add(ts)
232+ series.values.add(mappedResult)
196233 }
197234
198- /* *
199- * Recursively reads a JSON object from the reader and returns it as a Map.
200- */
201235 private fun JsonReader.readMap (): Map <String , Any ?> {
202236 val map = mutableMapOf<String , Any ?>()
203237
204238 this .beginObject()
205239 while (this .hasNext()) {
206240 val key = this .nextName()
207241 val value: Any? = when (this .peek()) {
208- JsonToken .BEGIN_OBJECT -> readMap() // Recursive call for nested maps
242+ JsonToken .BEGIN_OBJECT -> readMap()
209243 JsonToken .BEGIN_ARRAY -> {
210- // Optional: Handle arrays if your source map has lists
211- // For now we just skip or you can implement readList() similarly
212244 this .skipValue()
213245 null
214246 }
@@ -227,36 +259,27 @@ private class DefaultJSONOutput(
227259 return map
228260 }
229261
230- /* *
231- * Extension to write mixed types (Number, String, Map, List) to JsonWriter.
232- */
233262 private fun JsonWriter.writeDynamicValue (value : Any? ) {
234263 when (value) {
235264 null -> this .nullValue()
236265 is Number -> this .value(value)
237266 is String -> this .value(value)
238267 is Boolean -> this .value(value)
239-
240- // Handle Map -> JSON Object
241268 is Map <* , * > -> {
242269 this .beginObject()
243270 for ((k, v) in value) {
244271 this .name(k.toString())
245- writeDynamicValue(v) // Recursive call for nested values
272+ writeDynamicValue(v)
246273 }
247274 this .endObject()
248275 }
249-
250- // Handle List/Array -> JSON Array (Optional, but good for safety)
251276 is Collection <* > -> {
252277 this .beginArray()
253278 for (item in value) {
254279 writeDynamicValue(item)
255280 }
256281 this .endArray()
257282 }
258-
259- // Fallback for unknown objects
260283 else -> this .value(value.toString())
261284 }
262285 }
0 commit comments