Skip to content

Commit

Permalink
Fixed null in JSON deserialization bug
Browse files Browse the repository at this point in the history
  • Loading branch information
cabird committed Dec 6, 2018
1 parent 82c5097 commit 4d43b58
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 15 deletions.
6 changes: 6 additions & 0 deletions PelotonData.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PelotonDataGui", "PelotonDa
EndProject
Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "PelotonDataInstaller", "PelotonDataInstaller\PelotonDataInstaller.vdproj", "{AC76E67D-6BA5-4E83-B07C-92669A68B2F1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scratch", "Scratch\Scratch.csproj", "{0D4FCDED-D5EA-4D27-B887-4E8C8F9037D6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -25,6 +27,10 @@ Global
{A1C36F5B-C414-4A3A-BA27-FA3604D8D068}.Release|Any CPU.Build.0 = Release|Any CPU
{AC76E67D-6BA5-4E83-B07C-92669A68B2F1}.Debug|Any CPU.ActiveCfg = Debug
{AC76E67D-6BA5-4E83-B07C-92669A68B2F1}.Release|Any CPU.ActiveCfg = Release
{0D4FCDED-D5EA-4D27-B887-4E8C8F9037D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0D4FCDED-D5EA-4D27-B887-4E8C8F9037D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0D4FCDED-D5EA-4D27-B887-4E8C8F9037D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0D4FCDED-D5EA-4D27-B887-4E8C8F9037D6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
2 changes: 1 addition & 1 deletion PelotonData/PelotonData.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
<Compile Include="JSONClasses\EventDetails.cs" />
<Compile Include="JSONClasses\WorkoutList.cs" />
<Compile Include="JSONClasses\WorkoutSession.cs" />
<Compile Include="Program.cs">
<Compile Include="PelotonDataDownloader.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down
37 changes: 28 additions & 9 deletions PelotonData/Program.cs → PelotonData/PelotonDataDownloader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ protected override WebRequest GetWebRequest(Uri address)
return request;
}
}
public class Program
public class PelotonDataDownloader
{
static int ThrottleMilliseconds = 2000;

JsonSerializerSettings JSonSerializerSettings = new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore };

static void Main(string[] args)
{
var p = new Program();
var p = new PelotonDataDownloader();
p.RunAsync("username", "password").RunSynchronously();
}

Expand Down Expand Up @@ -70,7 +72,7 @@ async Task RunAsync(string username, string password)
}
}

public async Task<AuthResponse> AuthenticateAsync(string user, string password, ILogger logger)
public async Task<AuthResponse> AuthenticateAsync(string user, string password, ILogger logger, string SaveJsonPath=null)
{
string authURL = "https://api.pelotoncycle.com/auth/login";
var info = new { password = password, username_or_email = user };
Expand All @@ -82,10 +84,16 @@ public async Task<AuthResponse> AuthenticateAsync(string user, string password,
var responseTask = client.UploadStringTaskAsync(authURL, infoAsString);
string response = await responseTask;

if (SaveJsonPath != null)
{
var formattedJson = JToken.Parse(response).ToString(Formatting.Indented);
File.WriteAllText(SaveJsonPath, formattedJson);
}

Debug.WriteLine(" " + response.Substring(0, 50));
Debug.WriteLine($" Length: {response.Length}");

var authResponse = JsonConvert.DeserializeObject<AuthResponse>(response);
var authResponse = JsonConvert.DeserializeObject<AuthResponse>(response, JSonSerializerSettings);
return authResponse;
}
}
Expand Down Expand Up @@ -127,7 +135,7 @@ public async Task<List<RideDatum>> GetWorkoutListAsync(AuthResponse auth, ILogge
Debug.WriteLine(" " + response.Substring(0, 50));
Debug.WriteLine($" Length: {response.Length}");

WorkoutList workoutList = JsonConvert.DeserializeObject<WorkoutList>(response);
WorkoutList workoutList = JsonConvert.DeserializeObject<WorkoutList>(response, JSonSerializerSettings);
if (logger != null) logger.Log($"Page retrieved, contains {workoutList.count} workouts");

rideDataList.AddRange(workoutList.data);
Expand Down Expand Up @@ -168,17 +176,28 @@ public async Task<EventDetails> GetWorkoutEventDetails(RideDatum ride, ILogger l
var formattedJson = JToken.Parse(response).ToString(Formatting.Indented);
File.WriteAllText(SaveJsonPath, formattedJson);
}
EventDetails details = JsonConvert.DeserializeObject<EventDetails>(response);
EventDetails details = JsonConvert.DeserializeObject<EventDetails>(response, JSonSerializerSettings);
return details;
}
}

public async Task<WorkoutSessionMetrics> SimpleGetWorkoutSessionMetricsAsync(string id, int secondsPerObservation)
{
using (var client = new WebClient())
{
client.Headers["accept"] = "application/json";
string url = $"https://api.onepeloton.com/api/workout/{id}/performance_graph?every_n={secondsPerObservation}";
var response = await client.DownloadStringTaskAsync(url);
return JsonConvert.DeserializeObject<WorkoutSessionMetrics>(response, JSonSerializerSettings);
}
}

public async Task<WorkoutSessionMetrics> GetWorkoutMetricsAsync(RideDatum ride, ILogger logger, string SaveJsonPath=null)
{
using (var client = new WebClient())
{
client.Headers["accept"] = "application/json";
string url = $"https://api.onepeloton.com/api/workout/{ride.id}/performance_graph?every_n=5";
string url = $"https://api.onepeloton.com/api/workout/{ride.id}/performance_graph?every_n=1";

if (logger != null) logger.Log($"Downloading metrics for workout: {ride.ride.title} on {Util.DateTimeFromEpochSeconds(ride.device_time_created_at).ToShortDateString()}");
var response = await client.DownloadStringTaskAsync(url);
Expand All @@ -188,10 +207,10 @@ public async Task<WorkoutSessionMetrics> GetWorkoutMetricsAsync(RideDatum ride,

if (SaveJsonPath != null)
{
var formattedJson = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(response), Formatting.Indented);
var formattedJson = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(response, JSonSerializerSettings), Formatting.Indented, JSonSerializerSettings);
File.WriteAllText(SaveJsonPath, formattedJson);
}
WorkoutSessionMetrics session = JsonConvert.DeserializeObject<WorkoutSessionMetrics>(response);
WorkoutSessionMetrics session = JsonConvert.DeserializeObject<WorkoutSessionMetrics>(response, JSonSerializerSettings);
return session;
}
}
Expand Down
11 changes: 6 additions & 5 deletions PelotonDataGui/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,18 +79,19 @@ private async void GetDataButton_Click(object sender, RoutedEventArgs e)
{
double progress = 0.0;

var p = new Program();
var p = new PelotonDataDownloader();

await SetProgress(0);

if (!Directory.Exists(OutputDirectoryTextBox.Text))
string outputDirectory = OutputDirectoryTextBox.Text;

if (!Directory.Exists(outputDirectory))
{
Logger.LogError($"The output directory does not exist: {OutputDirectoryTextBox.Text}\nAborting.");
Logger.LogError($"The output directory does not exist: {outputDirectory}\nAborting.");
return;
}

Logger.Log("Authenticating");
var authTask = p.AuthenticateAsync(UsernameTextBox.Text, PasswordTextBox.Password, this);
var authTask = p.AuthenticateAsync(UsernameTextBox.Text, PasswordTextBox.Password, this, Path.Combine(outputDirectory, "authentication_response.json"));
try
{
auth = await authTask;
Expand Down
6 changes: 6 additions & 0 deletions Scratch/App.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
39 changes: 39 additions & 0 deletions Scratch/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Newtonsoft.Json;
using PelotonData.JSONClasses;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Scratch
{
class Program
{
public static void Main(string[] args)
{
TestNullInJson();
}

public static void TestDownloadSessionMetrics()
{
var p = new PelotonData.PelotonDataDownloader();
string workout = "64fea3aed3b34270b9e9e20df02f7759";
var task = p.AuthenticateAsync("", "", null).Result;
//task.RunSynchronously();
var data = p.SimpleGetWorkoutSessionMetricsAsync(workout, 1).Result;
p.OutputRideCSV(data, @"C:\Users\cbird\Documents\PelotonData\test.csv");
}



public static void TestNullInJson()
{
string path = @"C:\Users\cbird\Documents\PelotonData\authentication_response.json";
var authResponse = JsonConvert.DeserializeObject<AuthResponse>(File.ReadAllText(path), new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore });
}

}
}
36 changes: 36 additions & 0 deletions Scratch/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Scratch")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Scratch")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("0d4fcded-d5ea-4d27-b887-4e8c8f9037d6")]

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
62 changes: 62 additions & 0 deletions Scratch/Scratch.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{0D4FCDED-D5EA-4D27-B887-4E8C8F9037D6}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Scratch</RootNamespace>
<AssemblyName>Scratch</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PelotonData\PelotonData.csproj">
<Project>{08c3882f-9669-4c82-a005-1be8657732b7}</Project>
<Name>PelotonData</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
4 changes: 4 additions & 0 deletions Scratch/packages.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="12.0.1" targetFramework="net45" />
</packages>

0 comments on commit 4d43b58

Please sign in to comment.