/// <summary> /// Parse Flux CSV response to <see cref="IFluxResponseConsumer"/>. /// </summary> /// <param name="source">CSV Data source</param> /// <param name="cancellable">to cancel parsing</param> /// <param name="consumer">to accept <see cref="FluxTable"/> or <see cref="FluxRecord"/></param> public void ParseFluxResponse(Stream source, ICancellable cancellable, IFluxResponseConsumer consumer) { Arguments.CheckNotNull(source, "source"); using var csv = new CsvReader(new StreamReader(source), CultureInfo.InvariantCulture); var state = new ParseFluxResponseState { csv = csv }; while (csv.Read()) { if (cancellable != null && cancellable.IsCancelled()) { return; } foreach (var(table, record) in ParseNextFluxResponse(state)) { if (record == null) { consumer.Accept(state.tableIndex, cancellable, table); } else { consumer.Accept(state.tableIndex - 1, cancellable, record); } } } }
/// <summary> /// Parse Flux CSV response to <see cref="IAsyncEnumerable{T}"/>. /// </summary> /// <param name="reader">CSV Data source reader</param> /// <param name="cancellationToken">cancellation token</param> public async IAsyncEnumerable <(FluxTable, FluxRecord)> ParseFluxResponseAsync(StringReader reader, [EnumeratorCancellation] CancellationToken cancellationToken) { Arguments.CheckNotNull(reader, nameof(reader)); using var csv = new CsvReader(reader, CultureInfo.InvariantCulture); var state = new ParseFluxResponseState { csv = csv }; while (await csv.ReadAsync() && !cancellationToken.IsCancellationRequested) { foreach (var response in ParseNextFluxResponse(state)) { yield return(response); } } }
private IEnumerable <(FluxTable, FluxRecord)> ParseNextFluxResponse(ParseFluxResponseState state) { // // Response has HTTP status ok, but response is error. // if ("error".Equals(state.csv[1]) && "reference".Equals(state.csv[2])) { state.parsingState = ParsingState.InError; yield break; } // // Throw InfluxException with error response // if (ParsingState.InError.Equals(state.parsingState)) { var error = state.csv[1]; var referenceValue = state.csv[2]; var reference = 0; if (referenceValue != null && !String.IsNullOrEmpty(referenceValue)) { reference = Convert.ToInt32(referenceValue); } throw new FluxQueryException(error, reference); } var token = state.csv[0]; //// start new table if ("#datatype".Equals(token)) { state.startNewTable = true; state.table = new FluxTable(); yield return(state.table, null); state.tableIndex++; state.tableId = -1; } else if (state.table == null) { throw new FluxCsvParserException( "Unable to parse CSV response. FluxTable definition was not found."); } //#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string if ("#datatype".Equals(token)) { AddDataTypes(state.table, state.csv); } else if ("#group".Equals(token)) { AddGroups(state.table, state.csv); } else if ("#default".Equals(token)) { AddDefaultEmptyValues(state.table, state.csv); } else { // parse column names if (state.startNewTable) { AddColumnNamesAndTags(state.table, state.csv); state.startNewTable = false; yield break; } int currentId; try { currentId = Convert.ToInt32(state.csv[1 + 1]); } catch (Exception) { throw new FluxCsvParserException("Unable to parse CSV response."); } if (state.tableId == -1) { state.tableId = currentId; } if (state.tableId != currentId) { //create new table with previous column headers settings var fluxColumns = state.table.Columns; state.table = new FluxTable(); state.table.Columns.AddRange(fluxColumns); yield return(state.table, null); state.tableIndex++; state.tableId = currentId; } yield return(state.table, ParseRecord(state.tableIndex - 1, state.table, state.csv)); } }