diff --git a/AssemblyLister/AssemblyLister.NetFx/AssemblyLister.NetFx.csproj b/AssemblyLister/AssemblyLister.NetFx/AssemblyLister.NetFx.csproj new file mode 100644 index 00000000..2a780e58 --- /dev/null +++ b/AssemblyLister/AssemblyLister.NetFx/AssemblyLister.NetFx.csproj @@ -0,0 +1,55 @@ + + + + + Debug + AnyCPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B} + Library + Properties + AssemblyLister + AssemblyLister + v4.5 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/AssemblyLister/AssemblyLister.NetFx/AssemblyLister.cs b/AssemblyLister/AssemblyLister.NetFx/AssemblyLister.cs new file mode 100644 index 00000000..e9270a61 --- /dev/null +++ b/AssemblyLister/AssemblyLister.NetFx/AssemblyLister.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace AssemblyLister { + public static class Lister { + public static IEnumerable AllAssemblies { + get { + // For each of the loaded assemblies, deeply walk all of their references. + HashSet seen = new HashSet(); + return AppDomain.CurrentDomain.GetAssemblies().SelectMany(asm => asm.DeepWalkReferences(seen)); + } + } + + private static IEnumerable DeepWalkReferences(this Assembly assembly, HashSet seen = null) { + seen = seen ?? new HashSet(); + + if (!seen.Add(assembly.FullName)) { + return Enumerable.Empty(); + } + + List assemblies = new List(); + assemblies.Add(assembly); + + foreach (var reference in assembly.GetReferencedAssemblies()) { + if (seen.Contains(reference.FullName)) + continue; + + Assembly referencedAsm = Assembly.Load(reference); + assemblies.AddRange(referencedAsm.DeepWalkReferences(seen)); + } + + return assemblies; + } + } +} diff --git a/AssemblyLister/AssemblyLister.NetFx/Properties/AssemblyInfo.cs b/AssemblyLister/AssemblyLister.NetFx/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..7d88454b --- /dev/null +++ b/AssemblyLister/AssemblyLister.NetFx/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +using System.Resources; +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("AssemblyLister")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("AssemblyLister")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] + +// 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")] diff --git a/AssemblyLister/AssemblyLister.Portable/AssemblyLister.Portable.csproj b/AssemblyLister/AssemblyLister.Portable/AssemblyLister.Portable.csproj new file mode 100644 index 00000000..e546ddcd --- /dev/null +++ b/AssemblyLister/AssemblyLister.Portable/AssemblyLister.Portable.csproj @@ -0,0 +1,51 @@ + + + + + 10.0 + Debug + AnyCPU + {EA65343F-7FED-450B-A1D6-3215B33B3563} + Library + Properties + AssemblyLister + AssemblyLister + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile136 + v4.0 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + \ No newline at end of file diff --git a/AssemblyLister/AssemblyLister.Portable/AssemblyLister.cs b/AssemblyLister/AssemblyLister.Portable/AssemblyLister.cs new file mode 100644 index 00000000..2c998ad9 --- /dev/null +++ b/AssemblyLister/AssemblyLister.Portable/AssemblyLister.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace AssemblyLister { + public static class Lister { + public static IEnumerable AllAssemblies { + get { + throw new Exception("Cannot use the portable version of AssemblyLister in an end-program. Please add a reference to AssemblyLister via NuGet to your final Application."); + } + } + } +} diff --git a/AssemblyLister/AssemblyLister.Portable/Properties/AssemblyInfo.cs b/AssemblyLister/AssemblyLister.Portable/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..7d88454b --- /dev/null +++ b/AssemblyLister/AssemblyLister.Portable/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +using System.Resources; +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("AssemblyLister")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("AssemblyLister")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] + +// 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")] diff --git a/AssemblyLister/AssemblyLister.UWP/AssemblyLister.UWP.csproj b/AssemblyLister/AssemblyLister.UWP/AssemblyLister.UWP.csproj new file mode 100644 index 00000000..6a8c1c23 --- /dev/null +++ b/AssemblyLister/AssemblyLister.UWP/AssemblyLister.UWP.csproj @@ -0,0 +1,55 @@ + + + + + 12.0 + Debug + AnyCPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46} + Library + Properties + AssemblyLister + AssemblyLister + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile32 + v4.6 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/AssemblyLister/AssemblyLister.UWP/AssemblyLister.cs b/AssemblyLister/AssemblyLister.UWP/AssemblyLister.cs new file mode 100644 index 00000000..463ff199 --- /dev/null +++ b/AssemblyLister/AssemblyLister.UWP/AssemblyLister.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading.Tasks; +using Windows.ApplicationModel; +using Windows.UI.Xaml; + +namespace AssemblyLister { + /// + /// A class that lets you list all loaded assemblies in a PCL-compliant way. + /// + public static class Lister { + /// + /// Get all of the assemblies used by this application. + /// + public static IEnumerable AllAssemblies { + get { + Task> assembliesTask = Task.Run(async () => { + List results = new List(); + + var folder = Package.Current.InstalledLocation; + foreach (var file in await folder.GetFilesAsync().AsTask().ConfigureAwait(false)) { + if (file.FileType == ".dll") { + var assemblyName = new AssemblyName(file.DisplayName); + + try { + var assembly = Assembly.Load(assemblyName); + results.Add(assembly); + } catch (Exception) { + // Ignore... + } + } + } + return results; + }); + + // While we asynchronously load, give back the one assembly we know to exist (i.e. the one with the main application). + var currentAssembly = Application.Current.GetType().GetTypeInfo().Assembly; + yield return currentAssembly; + + assembliesTask.Wait(); + foreach (Assembly asm in assembliesTask.Result) { + yield return asm; + } + } + } + } +} diff --git a/AssemblyLister/AssemblyLister.UWP/Properties/AssemblyInfo.cs b/AssemblyLister/AssemblyLister.UWP/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..7d88454b --- /dev/null +++ b/AssemblyLister/AssemblyLister.UWP/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +using System.Resources; +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("AssemblyLister")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("AssemblyLister")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] + +// 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")] diff --git a/AssemblyLister/AssemblyLister.Unity/AssemblyLister.Unity.csproj b/AssemblyLister/AssemblyLister.Unity/AssemblyLister.Unity.csproj new file mode 100644 index 00000000..f0f7ea71 --- /dev/null +++ b/AssemblyLister/AssemblyLister.Unity/AssemblyLister.Unity.csproj @@ -0,0 +1,53 @@ + + + + + Debug + AnyCPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7} + Library + Properties + AssemblyLister + AssemblyLister + v3.5 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/AssemblyLister/AssemblyLister.Unity/AssemblyLister.cs b/AssemblyLister/AssemblyLister.Unity/AssemblyLister.cs new file mode 100644 index 00000000..2f2c420e --- /dev/null +++ b/AssemblyLister/AssemblyLister.Unity/AssemblyLister.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Linq; + +namespace AssemblyLister { + public static class Lister { + public static IEnumerable AllAssemblies { + get { + // For each of the loaded assemblies, deeply walk all of their references. + HashSet seen = new HashSet(); + return AppDomain.CurrentDomain.GetAssemblies().SelectMany(asm => asm.DeepWalkReferences(seen)); + } + } + + private static IEnumerable DeepWalkReferences(this Assembly assembly, HashSet seen = null) { + seen = seen ?? new HashSet(); + + if (!seen.Add(assembly.FullName)) { + return Enumerable.Empty(); + } + + List assemblies = new List(); + assemblies.Add(assembly); + + foreach (var reference in assembly.GetReferencedAssemblies()) { + if (seen.Contains(reference.FullName)) + continue; + + Assembly referencedAsm = Assembly.Load(reference); + assemblies.AddRange(referencedAsm.DeepWalkReferences(seen)); + } + + return assemblies; + } + } +} diff --git a/AssemblyLister/AssemblyLister.Unity/Properties/AssemblyInfo.cs b/AssemblyLister/AssemblyLister.Unity/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..7d88454b --- /dev/null +++ b/AssemblyLister/AssemblyLister.Unity/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +using System.Resources; +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("AssemblyLister")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("AssemblyLister")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] + +// 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")] diff --git a/AssemblyLister/AssemblyLister.nuspec b/AssemblyLister/AssemblyLister.nuspec new file mode 100644 index 00000000..f4798987 --- /dev/null +++ b/AssemblyLister/AssemblyLister.nuspec @@ -0,0 +1,31 @@ + + + + AssemblyLister + 1.0.0 + Parse + Parse + http://www.parse.com + false + A helper utility for listing the assemblies referenced of a program. + Copyright 2016 + TODO FILLME + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Parse.sln b/Parse.sln index fa91c3fa..501a8262 100644 --- a/Parse.sln +++ b/Parse.sln @@ -1,10 +1,8 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 +VisualStudioVersion = 12.0.40629.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Parse", "Parse\Parse.csproj", "{DE07A443-9619-4BD7-B540-41296F8A2959}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{68E871A4-6C4A-4BF8-AD86-E25AE2A911F7}" ProjectSection(SolutionItems) = preProject .nuget\NuGet.Config = .nuget\NuGet.Config @@ -12,19 +10,77 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{68E871 .nuget\NuGet.targets = .nuget\NuGet.targets EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Parse.NetFx45", "Parse\Parse.NetFx45.csproj", "{18203A69-17C8-4EA4-8098-65D982ACDDCB}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{D84CEB01-FEB3-4E91-B704-D47C5A146EFB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParseCommon.Portable", "ParseCommon\ParseCommon.Portable.csproj", "{DE07A443-9619-4BD7-B540-41296F8A2959}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParseCommon.Unity", "ParseCommon\ParseCommon.Unity.csproj", "{196457AA-9BA0-40BC-91A3-21BAAD6F4169}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{F9EC5355-F32F-4582-9A34-980C4B86C8A3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Push", "Push", "{C8039FEB-6AED-455D-B8AC-083EE32FBDBD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Analytics", "Analytics", "{D83E40C0-7B3D-4ED9-8424-01210E26A1E2}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{82B18FE1-2CDE-4CA4-BB38-9B68524B350A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParseAnalytics.Portable", "ParseAnalytics\ParseAnalytics.Portable.csproj", "{43AC01E1-AEB2-474D-856B-E81F27EF640B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParseAnalytics.Phone", "ParseAnalytics\ParseAnalytics.Phone.csproj", "{76490312-1E12-48D4-BD10-45C6ED4A08DC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParseAnalytics.WinRT", "ParseAnalytics\ParseAnalytics.WinRT.csproj", "{858FC395-3213-446E-BD09-72DBB11FE11C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Unity", "Unity", "{EDEE3219-FC84-426F-A36C-C035DAE932EE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unity.Compat", "Unity.Compat\Unity.Compat.csproj", "{8473BEF6-7086-4414-AAD6-264967A7FE75}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unity.Tasks", "Unity.Tasks\Unity.Tasks.csproj", "{CE75C800-A97F-4464-9A8B-3F65258456BF}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Migration", "Migration", "{CA29C2A2-D7AA-4C4F-A275-723BEB25307E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParseCore.Test.Unit.NetFx45", "ParseCore\Test\ParseCore.Test.Unit.NetFx45.csproj", "{F3937A46-F58A-4960-AFE6-AF664096C23A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{5316FB6A-7806-465C-880A-DCC9AD9E4EC5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Parse.WinRT", "Parse\Parse.WinRT.csproj", "{858FC395-3213-446E-BD09-72DBB11FE11C}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{2CEA544F-5CE8-4567-8A13-BA6CC977BB5F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Parse.Phone", "Parse\Parse.Phone.csproj", "{76490312-1E12-48D4-BD10-45C6ED4A08DC}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParseAnalytics.Test.Unit.NetFx45", "ParseAnalytics\Test\ParseAnalytics.Test.Unit.NetFx45.csproj", "{5E1D2160-915E-4F67-AD55-918BFCB57F5B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Parse.Android", "Parse\Parse.Android.csproj", "{072821C5-D6CC-4480-AA44-78DE79F52297}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParseCore.Unity", "ParseCore\ParseCore.Unity.csproj", "{27D3F5E9-CA66-426B-BE69-9B6158071A35}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Parse.iOS", "Parse\Parse.iOS.csproj", "{7A46A7B4-EE3B-4B4F-9CBF-C51D07BC7064}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParseCore.Portable", "ParseCore\ParseCore.Portable.csproj", "{F3F65351-2CE1-4412-84B4-C36F34EAB928}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Parse.Unity", "Parse\Parse.Unity.csproj", "{8473BEF6-7086-4414-AAD6-264967A7FE75}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParseCommon.Test.Unit.NetFx45", "ParseCommon\Test\ParseCommon.Test.Unit.NetFx45.csproj", "{53E714FF-3EF2-48EB-B305-36E1AB37C485}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParseTest.Unit.NetFx45", "ParseTest.Unit\ParseTest.Unit.NetFx45.csproj", "{F3937A46-F58A-4960-AFE6-AF664096C23A}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParsePush.Portable", "ParsePush\ParsePush.Portable.csproj", "{9DA3EC57-CDC7-4F9A-850D-8C63C7850409}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParsePush.Android", "ParsePush\ParsePush.Android.csproj", "{072821C5-D6CC-4480-AA44-78DE79F52297}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParsePush.iOS", "ParsePush\ParsePush.iOS.csproj", "{7A46A7B4-EE3B-4B4F-9CBF-C51D07BC7064}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParsePush.Phone", "ParsePush\ParsePush.Phone.csproj", "{DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParsePush.Unity.Android", "ParsePush\ParsePush.Unity.Android.csproj", "{CF036943-9D9C-4DC8-B31C-38C4E5A9069F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParsePush.Unity.iOS", "ParsePush\ParsePush.Unity.iOS.csproj", "{C805F141-F6F1-46B8-90F5-E8C83D7DC534}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParsePush.WinRT", "ParsePush\ParsePush.WinRT.csproj", "{871208ED-7C81-490B-BFCE-9BCF3B58A8AB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{8B71D9E7-4FD5-4192-A862-30024EAE65B9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParsePush.Test.Unit.NetFx45", "ParsePush\Test\ParsePush.Test.Unit.NetFx45.csproj", "{7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParseAnalytics.Unity", "ParseAnalytics\ParseAnalytics.Unity.csproj", "{82CB2095-581A-45B5-AB4C-46BB162C29D5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AssemblyLister", "AssemblyLister", "{55BA34E0-6E6D-44BA-AAD0-AB109685972F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssemblyLister.NetFx", "AssemblyLister\AssemblyLister.NetFx\AssemblyLister.NetFx.csproj", "{4BBCE4F8-C097-4680-8B07-B69D567EAA5B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssemblyLister.Portable", "AssemblyLister\AssemblyLister.Portable\AssemblyLister.Portable.csproj", "{EA65343F-7FED-450B-A1D6-3215B33B3563}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssemblyLister.Unity", "AssemblyLister\AssemblyLister.Unity\AssemblyLister.Unity.csproj", "{693A621E-FF3C-400F-B69D-382ACD50EDA7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssemblyLister.UWP", "AssemblyLister\AssemblyLister.UWP\AssemblyLister.UWP.csproj", "{129331F5-2DAB-4301-BE2D-3C7145C08B46}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -94,66 +150,124 @@ Global {DE07A443-9619-4BD7-B540-41296F8A2959}.Release|Mixed Platforms.Build.0 = Release|Any CPU {DE07A443-9619-4BD7-B540-41296F8A2959}.Release|x64.ActiveCfg = Release|Any CPU {DE07A443-9619-4BD7-B540-41296F8A2959}.Release|x86.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.AppStore|Any CPU.Build.0 = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.AppStore|ARM.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.AppStore|x64.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.AppStore|x86.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Debug|ARM.ActiveCfg = Debug|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Debug|x64.ActiveCfg = Debug|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Debug|x86.ActiveCfg = Debug|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Release|Any CPU.Build.0 = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Release|ARM.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Release|iPhone.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Release|x64.ActiveCfg = Release|Any CPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB}.Release|x86.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.AppStore|ARM.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.AppStore|x64.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.AppStore|x86.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Debug|Any CPU.Build.0 = Debug|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Debug|ARM.ActiveCfg = Debug|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Debug|x64.ActiveCfg = Debug|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Debug|x86.ActiveCfg = Debug|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Release|Any CPU.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Release|Any CPU.Build.0 = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Release|ARM.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Release|iPhone.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Release|x64.ActiveCfg = Release|Any CPU + {196457AA-9BA0-40BC-91A3-21BAAD6F4169}.Release|x86.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.AppStore|Any CPU.Build.0 = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.AppStore|ARM.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.AppStore|x64.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.AppStore|x86.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Debug|ARM.ActiveCfg = Debug|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Debug|x64.ActiveCfg = Debug|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Debug|x86.ActiveCfg = Debug|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Release|Any CPU.Build.0 = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Release|ARM.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Release|iPhone.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Release|x64.ActiveCfg = Release|Any CPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B}.Release|x86.ActiveCfg = Release|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Ad-Hoc|ARM.ActiveCfg = Release|ARM + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|x86 + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Ad-Hoc|x86.ActiveCfg = Release|x86 + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.AppStore|ARM.ActiveCfg = Release|ARM + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.AppStore|Mixed Platforms.ActiveCfg = Release|x86 + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.AppStore|x64.ActiveCfg = Release|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.AppStore|x86.ActiveCfg = Release|x86 + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|ARM.ActiveCfg = Debug|ARM + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|ARM.Build.0 = Debug|ARM + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|x64.ActiveCfg = Debug|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|x86.ActiveCfg = Debug|x86 + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|x86.Build.0 = Debug|x86 + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|Any CPU.Build.0 = Release|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|ARM.ActiveCfg = Release|ARM + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|ARM.Build.0 = Release|ARM + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|iPhone.ActiveCfg = Release|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|x64.ActiveCfg = Release|Any CPU + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|x86.ActiveCfg = Release|x86 + {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|x86.Build.0 = Release|x86 {858FC395-3213-446E-BD09-72DBB11FE11C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {858FC395-3213-446E-BD09-72DBB11FE11C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU {858FC395-3213-446E-BD09-72DBB11FE11C}.Ad-Hoc|ARM.ActiveCfg = Release|ARM - {858FC395-3213-446E-BD09-72DBB11FE11C}.Ad-Hoc|ARM.Build.0 = Release|ARM {858FC395-3213-446E-BD09-72DBB11FE11C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU {858FC395-3213-446E-BD09-72DBB11FE11C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU {858FC395-3213-446E-BD09-72DBB11FE11C}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|x86 - {858FC395-3213-446E-BD09-72DBB11FE11C}.Ad-Hoc|Mixed Platforms.Build.0 = Release|x86 {858FC395-3213-446E-BD09-72DBB11FE11C}.Ad-Hoc|x64.ActiveCfg = Release|x64 - {858FC395-3213-446E-BD09-72DBB11FE11C}.Ad-Hoc|x64.Build.0 = Release|x64 {858FC395-3213-446E-BD09-72DBB11FE11C}.Ad-Hoc|x86.ActiveCfg = Release|x86 - {858FC395-3213-446E-BD09-72DBB11FE11C}.Ad-Hoc|x86.Build.0 = Release|x86 {858FC395-3213-446E-BD09-72DBB11FE11C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {858FC395-3213-446E-BD09-72DBB11FE11C}.AppStore|Any CPU.Build.0 = Release|Any CPU {858FC395-3213-446E-BD09-72DBB11FE11C}.AppStore|ARM.ActiveCfg = Release|ARM - {858FC395-3213-446E-BD09-72DBB11FE11C}.AppStore|ARM.Build.0 = Release|ARM {858FC395-3213-446E-BD09-72DBB11FE11C}.AppStore|iPhone.ActiveCfg = Release|Any CPU {858FC395-3213-446E-BD09-72DBB11FE11C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU {858FC395-3213-446E-BD09-72DBB11FE11C}.AppStore|Mixed Platforms.ActiveCfg = Release|x86 - {858FC395-3213-446E-BD09-72DBB11FE11C}.AppStore|Mixed Platforms.Build.0 = Release|x86 {858FC395-3213-446E-BD09-72DBB11FE11C}.AppStore|x64.ActiveCfg = Release|x64 - {858FC395-3213-446E-BD09-72DBB11FE11C}.AppStore|x64.Build.0 = Release|x64 {858FC395-3213-446E-BD09-72DBB11FE11C}.AppStore|x86.ActiveCfg = Release|x86 - {858FC395-3213-446E-BD09-72DBB11FE11C}.AppStore|x86.Build.0 = Release|x86 {858FC395-3213-446E-BD09-72DBB11FE11C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {858FC395-3213-446E-BD09-72DBB11FE11C}.Debug|Any CPU.Build.0 = Debug|Any CPU {858FC395-3213-446E-BD09-72DBB11FE11C}.Debug|ARM.ActiveCfg = Debug|ARM @@ -161,7 +275,6 @@ Global {858FC395-3213-446E-BD09-72DBB11FE11C}.Debug|iPhone.ActiveCfg = Debug|Any CPU {858FC395-3213-446E-BD09-72DBB11FE11C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {858FC395-3213-446E-BD09-72DBB11FE11C}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {858FC395-3213-446E-BD09-72DBB11FE11C}.Debug|Mixed Platforms.Build.0 = Debug|x86 {858FC395-3213-446E-BD09-72DBB11FE11C}.Debug|x64.ActiveCfg = Debug|x64 {858FC395-3213-446E-BD09-72DBB11FE11C}.Debug|x64.Build.0 = Debug|x64 {858FC395-3213-446E-BD09-72DBB11FE11C}.Debug|x86.ActiveCfg = Debug|x86 @@ -173,55 +286,292 @@ Global {858FC395-3213-446E-BD09-72DBB11FE11C}.Release|iPhone.ActiveCfg = Release|Any CPU {858FC395-3213-446E-BD09-72DBB11FE11C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {858FC395-3213-446E-BD09-72DBB11FE11C}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {858FC395-3213-446E-BD09-72DBB11FE11C}.Release|Mixed Platforms.Build.0 = Release|x86 {858FC395-3213-446E-BD09-72DBB11FE11C}.Release|x64.ActiveCfg = Release|x64 {858FC395-3213-446E-BD09-72DBB11FE11C}.Release|x64.Build.0 = Release|x64 {858FC395-3213-446E-BD09-72DBB11FE11C}.Release|x86.ActiveCfg = Release|x86 {858FC395-3213-446E-BD09-72DBB11FE11C}.Release|x86.Build.0 = Release|x86 - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Ad-Hoc|ARM.ActiveCfg = Release|ARM - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Ad-Hoc|ARM.Build.0 = Release|ARM - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|x86 - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Ad-Hoc|Mixed Platforms.Build.0 = Release|x86 - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Ad-Hoc|x86.ActiveCfg = Release|x86 - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Ad-Hoc|x86.Build.0 = Release|x86 - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.AppStore|Any CPU.Build.0 = Release|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.AppStore|ARM.ActiveCfg = Release|ARM - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.AppStore|ARM.Build.0 = Release|ARM - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.AppStore|Mixed Platforms.ActiveCfg = Release|x86 - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.AppStore|Mixed Platforms.Build.0 = Release|x86 - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.AppStore|x64.ActiveCfg = Release|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.AppStore|x86.ActiveCfg = Release|x86 - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.AppStore|x86.Build.0 = Release|x86 - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|ARM.ActiveCfg = Debug|ARM - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|ARM.Build.0 = Debug|ARM - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|x64.ActiveCfg = Debug|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|x86.ActiveCfg = Debug|x86 - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Debug|x86.Build.0 = Debug|x86 - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|Any CPU.Build.0 = Release|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|ARM.ActiveCfg = Release|ARM - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|ARM.Build.0 = Release|ARM - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|iPhone.ActiveCfg = Release|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|Mixed Platforms.Build.0 = Release|x86 - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|x64.ActiveCfg = Release|Any CPU - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|x86.ActiveCfg = Release|x86 - {76490312-1E12-48D4-BD10-45C6ED4A08DC}.Release|x86.Build.0 = Release|x86 + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.AppStore|Any CPU.Build.0 = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.AppStore|ARM.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.AppStore|x64.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.AppStore|x86.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Debug|ARM.ActiveCfg = Debug|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Debug|x64.ActiveCfg = Debug|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Debug|x86.ActiveCfg = Debug|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Release|Any CPU.Build.0 = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Release|ARM.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Release|iPhone.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Release|x64.ActiveCfg = Release|Any CPU + {8473BEF6-7086-4414-AAD6-264967A7FE75}.Release|x86.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.AppStore|Any CPU.Build.0 = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.AppStore|ARM.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.AppStore|x64.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.AppStore|x86.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Debug|ARM.ActiveCfg = Debug|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Debug|x64.ActiveCfg = Debug|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Debug|x86.ActiveCfg = Debug|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Release|Any CPU.Build.0 = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Release|ARM.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Release|iPhone.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Release|x64.ActiveCfg = Release|Any CPU + {CE75C800-A97F-4464-9A8B-3F65258456BF}.Release|x86.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.AppStore|Any CPU.Build.0 = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.AppStore|ARM.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.AppStore|x64.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.AppStore|x86.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Debug|ARM.ActiveCfg = Debug|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Debug|x64.ActiveCfg = Debug|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Debug|x86.ActiveCfg = Debug|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Release|Any CPU.Build.0 = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Release|ARM.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Release|iPhone.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Release|x64.ActiveCfg = Release|Any CPU + {F3937A46-F58A-4960-AFE6-AF664096C23A}.Release|x86.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.AppStore|Any CPU.Build.0 = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.AppStore|ARM.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.AppStore|x64.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.AppStore|x86.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Debug|ARM.ActiveCfg = Debug|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Debug|x64.ActiveCfg = Debug|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Debug|x86.ActiveCfg = Debug|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Release|Any CPU.Build.0 = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Release|ARM.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Release|iPhone.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Release|x64.ActiveCfg = Release|Any CPU + {5E1D2160-915E-4F67-AD55-918BFCB57F5B}.Release|x86.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.AppStore|ARM.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.AppStore|x64.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.AppStore|x86.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Debug|Any CPU.Build.0 = Debug|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Debug|ARM.ActiveCfg = Debug|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Debug|x64.ActiveCfg = Debug|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Debug|x86.ActiveCfg = Debug|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Release|Any CPU.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Release|Any CPU.Build.0 = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Release|ARM.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Release|iPhone.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Release|x64.ActiveCfg = Release|Any CPU + {27D3F5E9-CA66-426B-BE69-9B6158071A35}.Release|x86.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.AppStore|Any CPU.Build.0 = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.AppStore|ARM.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.AppStore|x64.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.AppStore|x86.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Debug|ARM.ActiveCfg = Debug|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Debug|x64.ActiveCfg = Debug|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Debug|x86.ActiveCfg = Debug|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Release|Any CPU.Build.0 = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Release|ARM.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Release|iPhone.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Release|x64.ActiveCfg = Release|Any CPU + {F3F65351-2CE1-4412-84B4-C36F34EAB928}.Release|x86.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.AppStore|Any CPU.Build.0 = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.AppStore|ARM.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.AppStore|x64.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.AppStore|x86.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Debug|Any CPU.Build.0 = Debug|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Debug|ARM.ActiveCfg = Debug|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Debug|x64.ActiveCfg = Debug|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Debug|x86.ActiveCfg = Debug|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Release|Any CPU.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Release|Any CPU.Build.0 = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Release|ARM.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Release|iPhone.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Release|x64.ActiveCfg = Release|Any CPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485}.Release|x86.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.AppStore|Any CPU.Build.0 = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.AppStore|ARM.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.AppStore|x64.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.AppStore|x86.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Debug|ARM.ActiveCfg = Debug|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Debug|x64.ActiveCfg = Debug|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Debug|x86.ActiveCfg = Debug|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Release|Any CPU.Build.0 = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Release|ARM.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Release|iPhone.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Release|x64.ActiveCfg = Release|Any CPU + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409}.Release|x86.ActiveCfg = Release|Any CPU {072821C5-D6CC-4480-AA44-78DE79F52297}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU {072821C5-D6CC-4480-AA44-78DE79F52297}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU {072821C5-D6CC-4480-AA44-78DE79F52297}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU @@ -289,7 +639,6 @@ Global {7A46A7B4-EE3B-4B4F-9CBF-C51D07BC7064}.Debug|x64.ActiveCfg = Debug|iPhone {7A46A7B4-EE3B-4B4F-9CBF-C51D07BC7064}.Debug|x86.ActiveCfg = Debug|iPhone {7A46A7B4-EE3B-4B4F-9CBF-C51D07BC7064}.Release|Any CPU.ActiveCfg = Release|iPhone - {7A46A7B4-EE3B-4B4F-9CBF-C51D07BC7064}.Release|Any CPU.Build.0 = Release|iPhone {7A46A7B4-EE3B-4B4F-9CBF-C51D07BC7064}.Release|ARM.ActiveCfg = Release|iPhone {7A46A7B4-EE3B-4B4F-9CBF-C51D07BC7064}.Release|iPhone.ActiveCfg = Release|iPhone {7A46A7B4-EE3B-4B4F-9CBF-C51D07BC7064}.Release|iPhone.Build.0 = Release|iPhone @@ -299,80 +648,419 @@ Global {7A46A7B4-EE3B-4B4F-9CBF-C51D07BC7064}.Release|Mixed Platforms.Build.0 = Release|iPhone {7A46A7B4-EE3B-4B4F-9CBF-C51D07BC7064}.Release|x64.ActiveCfg = Release|iPhone {7A46A7B4-EE3B-4B4F-9CBF-C51D07BC7064}.Release|x86.ActiveCfg = Release|iPhone - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.AppStore|Any CPU.Build.0 = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.AppStore|ARM.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.AppStore|x64.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.AppStore|x86.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Debug|ARM.ActiveCfg = Debug|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Debug|x64.ActiveCfg = Debug|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Debug|x86.ActiveCfg = Debug|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Release|Any CPU.Build.0 = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Release|ARM.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Release|iPhone.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Release|x64.ActiveCfg = Release|Any CPU - {8473BEF6-7086-4414-AAD6-264967A7FE75}.Release|x86.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.AppStore|Any CPU.Build.0 = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.AppStore|ARM.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.AppStore|x64.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.AppStore|x86.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Debug|ARM.ActiveCfg = Debug|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Debug|x64.ActiveCfg = Debug|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Debug|x86.ActiveCfg = Debug|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Release|Any CPU.Build.0 = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Release|ARM.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Release|iPhone.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Release|x64.ActiveCfg = Release|Any CPU - {F3937A46-F58A-4960-AFE6-AF664096C23A}.Release|x86.ActiveCfg = Release|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Ad-Hoc|ARM.ActiveCfg = Release|ARM + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Ad-Hoc|ARM.Build.0 = Release|ARM + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|x86 + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Ad-Hoc|Mixed Platforms.Build.0 = Release|x86 + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Ad-Hoc|x86.ActiveCfg = Release|x86 + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Ad-Hoc|x86.Build.0 = Release|x86 + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.AppStore|Any CPU.Build.0 = Release|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.AppStore|ARM.ActiveCfg = Release|ARM + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.AppStore|ARM.Build.0 = Release|ARM + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.AppStore|Mixed Platforms.ActiveCfg = Release|x86 + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.AppStore|Mixed Platforms.Build.0 = Release|x86 + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.AppStore|x64.ActiveCfg = Release|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.AppStore|x86.ActiveCfg = Release|x86 + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.AppStore|x86.Build.0 = Release|x86 + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Debug|ARM.ActiveCfg = Debug|ARM + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Debug|ARM.Build.0 = Debug|ARM + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Debug|x64.ActiveCfg = Debug|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Debug|x86.ActiveCfg = Debug|x86 + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Debug|x86.Build.0 = Debug|x86 + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Release|Any CPU.Build.0 = Release|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Release|ARM.ActiveCfg = Release|ARM + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Release|ARM.Build.0 = Release|ARM + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Release|iPhone.ActiveCfg = Release|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Release|Mixed Platforms.Build.0 = Release|x86 + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Release|x64.ActiveCfg = Release|Any CPU + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Release|x86.ActiveCfg = Release|x86 + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431}.Release|x86.Build.0 = Release|x86 + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.AppStore|Any CPU.Build.0 = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.AppStore|ARM.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.AppStore|x64.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.AppStore|x86.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Debug|ARM.ActiveCfg = Debug|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Debug|x64.ActiveCfg = Debug|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Debug|x86.ActiveCfg = Debug|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Release|Any CPU.Build.0 = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Release|ARM.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Release|iPhone.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Release|x64.ActiveCfg = Release|Any CPU + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F}.Release|x86.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.AppStore|Any CPU.Build.0 = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.AppStore|ARM.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.AppStore|x64.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.AppStore|x86.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Debug|ARM.ActiveCfg = Debug|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Debug|x64.ActiveCfg = Debug|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Debug|x86.ActiveCfg = Debug|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Release|Any CPU.Build.0 = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Release|ARM.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Release|iPhone.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Release|x64.ActiveCfg = Release|Any CPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534}.Release|x86.ActiveCfg = Release|Any CPU + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Ad-Hoc|ARM.ActiveCfg = Release|ARM + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Ad-Hoc|ARM.Build.0 = Release|ARM + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|x86 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Ad-Hoc|Mixed Platforms.Build.0 = Release|x86 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Ad-Hoc|x64.ActiveCfg = Release|x64 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Ad-Hoc|x64.Build.0 = Release|x64 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Ad-Hoc|x86.ActiveCfg = Release|x86 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Ad-Hoc|x86.Build.0 = Release|x86 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.AppStore|Any CPU.Build.0 = Release|Any CPU + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.AppStore|ARM.ActiveCfg = Release|ARM + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.AppStore|ARM.Build.0 = Release|ARM + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.AppStore|Mixed Platforms.ActiveCfg = Release|x86 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.AppStore|Mixed Platforms.Build.0 = Release|x86 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.AppStore|x64.ActiveCfg = Release|x64 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.AppStore|x64.Build.0 = Release|x64 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.AppStore|x86.ActiveCfg = Release|x86 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.AppStore|x86.Build.0 = Release|x86 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Debug|ARM.ActiveCfg = Debug|ARM + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Debug|ARM.Build.0 = Debug|ARM + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Debug|x64.ActiveCfg = Debug|x64 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Debug|x64.Build.0 = Debug|x64 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Debug|x86.ActiveCfg = Debug|x86 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Debug|x86.Build.0 = Debug|x86 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Release|Any CPU.Build.0 = Release|Any CPU + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Release|ARM.ActiveCfg = Release|ARM + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Release|ARM.Build.0 = Release|ARM + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Release|iPhone.ActiveCfg = Release|Any CPU + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Release|Mixed Platforms.Build.0 = Release|x86 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Release|x64.ActiveCfg = Release|x64 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Release|x64.Build.0 = Release|x64 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Release|x86.ActiveCfg = Release|x86 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB}.Release|x86.Build.0 = Release|x86 + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.AppStore|Any CPU.Build.0 = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.AppStore|ARM.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.AppStore|x64.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.AppStore|x86.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Debug|ARM.ActiveCfg = Debug|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Debug|x64.ActiveCfg = Debug|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Debug|x86.ActiveCfg = Debug|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Release|Any CPU.Build.0 = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Release|ARM.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Release|iPhone.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Release|x64.ActiveCfg = Release|Any CPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E}.Release|x86.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.AppStore|Any CPU.Build.0 = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.AppStore|ARM.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.AppStore|x64.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.AppStore|x86.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Debug|ARM.ActiveCfg = Debug|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Debug|x64.ActiveCfg = Debug|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Debug|x86.ActiveCfg = Debug|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Release|Any CPU.Build.0 = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Release|ARM.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Release|iPhone.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Release|x64.ActiveCfg = Release|Any CPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5}.Release|x86.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.AppStore|Any CPU.Build.0 = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.AppStore|ARM.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.AppStore|x64.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.AppStore|x86.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Debug|ARM.ActiveCfg = Debug|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Debug|x64.ActiveCfg = Debug|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Debug|x86.ActiveCfg = Debug|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Release|Any CPU.Build.0 = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Release|ARM.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Release|iPhone.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Release|x64.ActiveCfg = Release|Any CPU + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B}.Release|x86.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.AppStore|Any CPU.Build.0 = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.AppStore|ARM.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.AppStore|x64.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.AppStore|x86.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Debug|ARM.ActiveCfg = Debug|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Debug|x64.ActiveCfg = Debug|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Debug|x86.ActiveCfg = Debug|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Release|Any CPU.Build.0 = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Release|ARM.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Release|iPhone.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Release|x64.ActiveCfg = Release|Any CPU + {EA65343F-7FED-450B-A1D6-3215B33B3563}.Release|x86.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.AppStore|Any CPU.Build.0 = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.AppStore|ARM.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.AppStore|x64.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.AppStore|x86.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Debug|ARM.ActiveCfg = Debug|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Debug|x64.ActiveCfg = Debug|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Debug|x86.ActiveCfg = Debug|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Release|Any CPU.Build.0 = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Release|ARM.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Release|iPhone.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Release|x64.ActiveCfg = Release|Any CPU + {693A621E-FF3C-400F-B69D-382ACD50EDA7}.Release|x86.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.AppStore|Any CPU.Build.0 = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.AppStore|ARM.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.AppStore|x64.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.AppStore|x86.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Debug|Any CPU.Build.0 = Debug|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Debug|ARM.ActiveCfg = Debug|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Debug|x64.ActiveCfg = Debug|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Debug|x86.ActiveCfg = Debug|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Release|Any CPU.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Release|Any CPU.Build.0 = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Release|ARM.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Release|iPhone.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Release|x64.ActiveCfg = Release|Any CPU + {129331F5-2DAB-4301-BE2D-3C7145C08B46}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {DE07A443-9619-4BD7-B540-41296F8A2959} = {D84CEB01-FEB3-4E91-B704-D47C5A146EFB} + {196457AA-9BA0-40BC-91A3-21BAAD6F4169} = {D84CEB01-FEB3-4E91-B704-D47C5A146EFB} + {82B18FE1-2CDE-4CA4-BB38-9B68524B350A} = {F9EC5355-F32F-4582-9A34-980C4B86C8A3} + {43AC01E1-AEB2-474D-856B-E81F27EF640B} = {D83E40C0-7B3D-4ED9-8424-01210E26A1E2} + {76490312-1E12-48D4-BD10-45C6ED4A08DC} = {D83E40C0-7B3D-4ED9-8424-01210E26A1E2} + {858FC395-3213-446E-BD09-72DBB11FE11C} = {D83E40C0-7B3D-4ED9-8424-01210E26A1E2} + {8473BEF6-7086-4414-AAD6-264967A7FE75} = {EDEE3219-FC84-426F-A36C-C035DAE932EE} + {CE75C800-A97F-4464-9A8B-3F65258456BF} = {EDEE3219-FC84-426F-A36C-C035DAE932EE} + {F3937A46-F58A-4960-AFE6-AF664096C23A} = {82B18FE1-2CDE-4CA4-BB38-9B68524B350A} + {5316FB6A-7806-465C-880A-DCC9AD9E4EC5} = {D83E40C0-7B3D-4ED9-8424-01210E26A1E2} + {2CEA544F-5CE8-4567-8A13-BA6CC977BB5F} = {D84CEB01-FEB3-4E91-B704-D47C5A146EFB} + {5E1D2160-915E-4F67-AD55-918BFCB57F5B} = {5316FB6A-7806-465C-880A-DCC9AD9E4EC5} + {27D3F5E9-CA66-426B-BE69-9B6158071A35} = {F9EC5355-F32F-4582-9A34-980C4B86C8A3} + {F3F65351-2CE1-4412-84B4-C36F34EAB928} = {F9EC5355-F32F-4582-9A34-980C4B86C8A3} + {53E714FF-3EF2-48EB-B305-36E1AB37C485} = {2CEA544F-5CE8-4567-8A13-BA6CC977BB5F} + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409} = {C8039FEB-6AED-455D-B8AC-083EE32FBDBD} + {072821C5-D6CC-4480-AA44-78DE79F52297} = {C8039FEB-6AED-455D-B8AC-083EE32FBDBD} + {7A46A7B4-EE3B-4B4F-9CBF-C51D07BC7064} = {C8039FEB-6AED-455D-B8AC-083EE32FBDBD} + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431} = {C8039FEB-6AED-455D-B8AC-083EE32FBDBD} + {CF036943-9D9C-4DC8-B31C-38C4E5A9069F} = {C8039FEB-6AED-455D-B8AC-083EE32FBDBD} + {C805F141-F6F1-46B8-90F5-E8C83D7DC534} = {C8039FEB-6AED-455D-B8AC-083EE32FBDBD} + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB} = {C8039FEB-6AED-455D-B8AC-083EE32FBDBD} + {8B71D9E7-4FD5-4192-A862-30024EAE65B9} = {C8039FEB-6AED-455D-B8AC-083EE32FBDBD} + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E} = {8B71D9E7-4FD5-4192-A862-30024EAE65B9} + {82CB2095-581A-45B5-AB4C-46BB162C29D5} = {D83E40C0-7B3D-4ED9-8424-01210E26A1E2} + {4BBCE4F8-C097-4680-8B07-B69D567EAA5B} = {55BA34E0-6E6D-44BA-AAD0-AB109685972F} + {EA65343F-7FED-450B-A1D6-3215B33B3563} = {55BA34E0-6E6D-44BA-AAD0-AB109685972F} + {693A621E-FF3C-400F-B69D-382ACD50EDA7} = {55BA34E0-6E6D-44BA-AAD0-AB109685972F} + {129331F5-2DAB-4301-BE2D-3C7145C08B46} = {55BA34E0-6E6D-44BA-AAD0-AB109685972F} + EndGlobalSection EndGlobal diff --git a/Parse/Compat/MissingExtensions.cs b/Parse/Compat/MissingExtensions.cs deleted file mode 100644 index e93c2165..00000000 --- a/Parse/Compat/MissingExtensions.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Parse.Internal { - internal static class MissingExtensions { - public static Type GetTypeInfo(this Type t) { - return t; - } - - public static bool HasFlag(this Enum enumValue, Enum flag) { - var eInt = Convert.ToInt64(enumValue); - var flagInt = Convert.ToInt64(flag); - return (eInt & flagInt) == flagInt; - } - - internal static T GetCustomAttribute(this PropertyInfo prop, bool inherit) - where T : Attribute { - return (T)prop.GetCustomAttributes(typeof(T), inherit).FirstOrDefault(); - } - - internal static T GetCustomAttribute(this PropertyInfo prop) where T : Attribute { - return prop.GetCustomAttribute(true); - } - - internal static T GetCustomAttribute(this Type type, bool inherit) where T : Attribute { - return (T)type.GetCustomAttributes(typeof(T), inherit).FirstOrDefault(); - } - - internal static T GetCustomAttribute(this Type type) where T : Attribute { - return type.GetCustomAttribute(true); - } - - internal static Task ReadToEndAsync(this StreamReader reader) { - return Task.Run(() => reader.ReadToEnd()); - } - - internal static Task CopyToAsync(this Stream stream, Stream destination) { - return stream.CopyToAsync(destination, 2048, CancellationToken.None); - } - - internal static Task CopyToAsync(this Stream stream, - Stream destination, - int bufferSize, - CancellationToken cancellationToken) { - byte[] buffer = new byte[bufferSize]; - int bytesRead = 0; - return InternalExtensions.WhileAsync(() => { - return stream.ReadAsync(buffer, 0, bufferSize, cancellationToken).OnSuccess(readTask => { - bytesRead = readTask.Result; - return bytesRead > 0; - }); - }, () => { - cancellationToken.ThrowIfCancellationRequested(); - return destination.WriteAsync(buffer, 0, bytesRead, cancellationToken) - .OnSuccess(_ => cancellationToken.ThrowIfCancellationRequested()); - }); - } - - internal static Task ReadAsync(this Stream stream, - byte[] buffer, - int offset, - int count, - CancellationToken cancellationToken) { - if (cancellationToken.IsCancellationRequested) { - var tcs = new TaskCompletionSource(); - tcs.SetCanceled(); - return tcs.Task; - } - return Task.Factory.FromAsync(stream.BeginRead, - stream.EndRead, - buffer, - offset, - count, - null); - } - - internal static Task WriteAsync(this Stream stream, - byte[] buffer, - int offset, - int count, - CancellationToken cancellationToken) { - if (cancellationToken.IsCancellationRequested) { - var tcs = new TaskCompletionSource(); - tcs.SetCanceled(); - return tcs.Task; - } - return Task.Factory.FromAsync(stream.BeginWrite, - stream.EndWrite, - buffer, - offset, - count, - null); - } - - internal static IEnumerable Zip(this IEnumerable list1, - IEnumerable list2, - Func zipper) { - var e1 = list1.GetEnumerator(); - var e2 = list2.GetEnumerator(); - while (e1.MoveNext() && e2.MoveNext()) { - yield return zipper(e1.Current, e2.Current); - } - } - } -} diff --git a/Parse/Compat/Progress.cs b/Parse/Compat/Progress.cs deleted file mode 100644 index 8ab5c493..00000000 --- a/Parse/Compat/Progress.cs +++ /dev/null @@ -1,58 +0,0 @@ -using Parse.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace System { - /// - /// Provides a convenient implementation for - /// handling progress update notifications. - /// - /// The progress event argument type. - public class Progress : IProgress where T : EventArgs { - private SynchronizedEventHandler progressChanged = new SynchronizedEventHandler(); - - /// - /// Constructs a new Progress handler. - /// - public Progress() { - ProgressChanged += (sender, args) => OnReport(args); - } - - /// - /// Constructs a new Progress handler that will invoke the given action when - /// progress events are raised. - /// - /// The action to invoke when progress changes. - public Progress(Action handler) - : this() { - ProgressChanged += (sender, args) => handler(args); - ProgressChanged += (sender, args) => OnReport(args); - } - - void IProgress.Report(T value) { - progressChanged.Invoke(this, value); - } - - /// - /// A method that is called whenever progress events are raised. Override - /// this method to handle the event. - /// - /// The updated progress. - protected virtual void OnReport(T value) { - } - - /// - /// An event that is raised whenever progress changes are reported. - /// - public event EventHandler ProgressChanged { - add { - progressChanged.Add(value); - } - remove { - progressChanged.Remove(value); - } - } - } -} diff --git a/Parse/Internal/Authentication/FacebookAuthenticationProvider.cs b/Parse/Internal/Authentication/FacebookAuthenticationProvider.cs deleted file mode 100644 index 518d288a..00000000 --- a/Parse/Internal/Authentication/FacebookAuthenticationProvider.cs +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using System.Linq; - -namespace Parse.Internal { - class FacebookAuthenticationProvider : IParseAuthenticationProvider { - internal static readonly Uri LoginDialogUrl = - new Uri("https://www.facebook.com/dialog/oauth", UriKind.Absolute); - private static readonly Uri TokenExtensionUrl = - new Uri("https://graph.facebook.com/oauth/access_token", UriKind.Absolute); - internal static readonly Uri ResponseUrl = - new Uri("https://www.facebook.com/connect/login_success.html", UriKind.Absolute); - private static readonly Uri MeUrl = - new Uri("https://graph.facebook.com/me", UriKind.Absolute); - private TaskCompletionSource> pendingTask; - private CancellationToken pendingCancellationToken; - - public FacebookAuthenticationProvider() { - } - - internal Uri LoginDialogUrlOverride { get; set; } - internal Uri ResponseUrlOverride { get; set; } - - public IEnumerable Permissions { get; set; } - public string AppId { get; set; } - public string AccessToken { get; set; } - - public event Action Navigate; - - /// - /// Parses a uri, looking for a base uri that represents facebook login completion, and then - /// converting the query string into a dictionary of key-value pairs. (e.g. access_token) - /// - private bool TryParseOAuthCallbackUrl(Uri uri, out IDictionary result) { - if (!uri.AbsoluteUri.StartsWith((ResponseUrlOverride ?? ResponseUrl).AbsoluteUri) || - uri.Fragment == null) { - result = null; - return false; - } - string fragmentOrQuery; - if (!string.IsNullOrEmpty(uri.Fragment)) { - fragmentOrQuery = uri.Fragment; - } else { - fragmentOrQuery = uri.Query; - } - // Trim the # or ? off of the fragment/query and then parse the querystring - result = ParseClient.DecodeQueryString(fragmentOrQuery.Substring(1)); - return true; - } - - public IDictionary GetAuthData(string facebookId, string accessToken, DateTime expiration) { - return new Dictionary { - {"id", facebookId}, - {"access_token", accessToken}, - {"expiration_date", expiration.ToString(ParseClient.DateFormatStrings.First())} - }; - } - - public bool HandleNavigation(Uri uri) { - IDictionary result; - if (TryParseOAuthCallbackUrl(uri, out result)) { - Action getUserId = () => { - try { - if (result.ContainsKey("error")) { - pendingTask.TrySetException(new ParseException(ParseException.ErrorCode.OtherCause, - string.Format("{0}: {1}", result["error_description"], result["error"]))); - return; - } - var parameters = new Dictionary(); - parameters["access_token"] = result["access_token"]; - parameters["fields"] = "id"; - - var request = new HttpRequest { - Uri = new Uri(MeUrl, "?" + ParseClient.BuildQueryString(parameters)), - Method = "GET" - }; - - ParseClient.PlatformHooks.HttpClient.ExecuteAsync(request, null, null, CancellationToken.None).OnSuccess(t => { - var meResult = ParseClient.DeserializeJsonString(t.Result.Item2); - pendingTask.TrySetResult(GetAuthData( - meResult["id"] as string, - result["access_token"] as string, - (DateTime.Now + TimeSpan.FromSeconds(int.Parse(result["expires_in"]))))); - }).ContinueWith(t => { - if (t.IsFaulted) { - pendingTask.TrySetException(t.Exception); - } - }); - } catch (Exception e) { - pendingTask.TrySetException(e); - } - }; - getUserId(); - return true; - } - return false; - } - - public Task> AuthenticateAsync(CancellationToken cancellationToken) { - if (AppId == null) { - throw new InvalidOperationException( - "You must initialize ParseFacebookUtils before attempting a Facebook login."); - } - if (pendingTask != null) { - pendingTask.TrySetCanceled(); - } - TaskCompletionSource> tcs = - new TaskCompletionSource>(); - pendingCancellationToken = cancellationToken; - pendingTask = tcs; - - cancellationToken.Register(() => { - tcs.TrySetCanceled(); - }); - - var navigateHandler = Navigate; - if (navigateHandler != null) { - var parameters = new Dictionary() { - {"redirect_uri", (ResponseUrlOverride ?? ResponseUrl).AbsoluteUri}, - {"response_type", "token"}, - {"display", "popup"}, - {"client_id", AppId} - }; - if (Permissions != null) { - parameters["scope"] = string.Join(",", Permissions.ToArray()); - } - navigateHandler(new Uri(LoginDialogUrlOverride ?? LoginDialogUrl, - "?" + ParseClient.BuildQueryString(parameters))); - } - return tcs.Task; - } - - public void Deauthenticate() { - AccessToken = null; - } - - public bool RestoreAuthentication(IDictionary authData) { - if (authData == null) { - Deauthenticate(); - } else { - AccessToken = authData["access_token"] as string; - } - return true; - } - - public string AuthType { - get { return "facebook"; } - } - } -} diff --git a/Parse/Internal/Command/ParseCommand.cs b/Parse/Internal/Command/ParseCommand.cs deleted file mode 100644 index c9fa230c..00000000 --- a/Parse/Internal/Command/ParseCommand.cs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace Parse.Internal { - /// - /// ParseCommand is an with pre-populated - /// headers. - /// - internal class ParseCommand : HttpRequest { - private const string revocableSessionTokenTrueValue = "1"; - - public IDictionary DataObject { get; private set; } - public override Stream Data { - get { - if (base.Data != null) { - return base.Data; - } - - return base.Data = DataObject != null - ? new MemoryStream(Encoding.UTF8.GetBytes(Json.Encode(DataObject))) - : null; - } - internal set { base.Data = value; } - } - - public ParseCommand(string relativeUri, - string method, - string sessionToken = null, - IList> headers = null, - IDictionary data = null) : this(relativeUri: relativeUri, - method: method, - sessionToken: sessionToken, - headers: headers, - stream: null, - contentType: data != null ? "application/json" : null) { - DataObject = data; - } - - public ParseCommand(string relativeUri, - string method, - string sessionToken = null, - IList> headers = null, - Stream stream = null, - string contentType = null) { - Uri = new Uri(new Uri(ParseClient.CurrentConfiguration.Server), relativeUri); - Method = method; - Data = stream; - - // TODO (richardross): Inject configuration instead of using shared static here. - Headers = new List> { - new KeyValuePair("X-Parse-Application-Id", ParseClient.CurrentConfiguration.ApplicationId), - new KeyValuePair("X-Parse-Client-Version", ParseClient.VersionString), - new KeyValuePair("X-Parse-Installation-Id", ParseClient.InstallationId.ToString()) - }; - - if (headers != null) { - foreach (var header in headers) { - Headers.Add(header); - } - } - - if (!string.IsNullOrEmpty(ParseClient.PlatformHooks.AppBuildVersion)) { - Headers.Add(new KeyValuePair("X-Parse-App-Build-Version", ParseClient.PlatformHooks.AppBuildVersion)); - } - if (!string.IsNullOrEmpty(ParseClient.PlatformHooks.AppDisplayVersion)) { - Headers.Add(new KeyValuePair("X-Parse-App-Display-Version", ParseClient.PlatformHooks.AppDisplayVersion)); - } - if (!string.IsNullOrEmpty(ParseClient.PlatformHooks.OSVersion)) { - Headers.Add(new KeyValuePair("X-Parse-OS-Version", ParseClient.PlatformHooks.OSVersion)); - } - // TODO (richardross): I hate the idea of having this super tightly coupled static variable in here. - // Lets eventually get rid of it. - if (!string.IsNullOrEmpty(ParseClient.MasterKey)) { - Headers.Add(new KeyValuePair("X-Parse-Master-Key", ParseClient.MasterKey)); - } else { - Headers.Add(new KeyValuePair("X-Parse-Windows-Key", ParseClient.CurrentConfiguration.WindowsKey)); - } - if (!string.IsNullOrEmpty(sessionToken)) { - Headers.Add(new KeyValuePair("X-Parse-Session-Token", sessionToken)); - } - if (!string.IsNullOrEmpty(contentType)) { - Headers.Add(new KeyValuePair("Content-Type", contentType)); - } - if (ParseUser.IsRevocableSessionEnabled) { - Headers.Add(new KeyValuePair("X-Parse-Revocable-Session", revocableSessionTokenTrueValue)); - } - } - } -} diff --git a/Parse/Internal/Command/ParseCommandRunner.cs b/Parse/Internal/Command/ParseCommandRunner.cs deleted file mode 100644 index 3ef10777..00000000 --- a/Parse/Internal/Command/ParseCommandRunner.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System; -using System.Collections.Generic; -using System.Net; -using System.Threading; -using System.Threading.Tasks; - - -namespace Parse.Internal { - internal class ParseCommandRunner : IParseCommandRunner { - private readonly IHttpClient httpClient; - public ParseCommandRunner(IHttpClient httpClient) { - this.httpClient = httpClient; - } - - public Task>> RunCommandAsync(ParseCommand command, - IProgress uploadProgress = null, - IProgress downloadProgress = null, - CancellationToken cancellationToken = default(CancellationToken)) { - return httpClient.ExecuteAsync(command, uploadProgress, downloadProgress, cancellationToken).OnSuccess(t => { - cancellationToken.ThrowIfCancellationRequested(); - - var response = t.Result; - var contentString = response.Item2; - int responseCode = (int)response.Item1; - if (responseCode >= 500) { - // Server error, return InternalServerError. - throw new ParseException(ParseException.ErrorCode.InternalServerError, response.Item2); - } else if (contentString != null) { - IDictionary contentJson = null; - try { - if (contentString.StartsWith("[")) { - var arrayJson = Json.Parse(contentString); - contentJson = new Dictionary { { "results", arrayJson } }; - } else { - contentJson = Json.Parse(contentString) as IDictionary; - } - } catch (Exception e) { - throw new ParseException(ParseException.ErrorCode.OtherCause, - "Invalid response from server", e); - } - if (responseCode < 200 || responseCode > 299) { - int code = (int)(contentJson.ContainsKey("code") ? (long)contentJson["code"] : (int)ParseException.ErrorCode.OtherCause); - string error = contentJson.ContainsKey("error") ? - contentJson["error"] as string : - contentString; - throw new ParseException((ParseException.ErrorCode)code, error); - } - return new Tuple>(response.Item1, - contentJson); - } - return new Tuple>(response.Item1, null); - }); - } - } -} diff --git a/Parse/Internal/HttpClient/Android/HttpClient.Android.cs b/Parse/Internal/HttpClient/Android/HttpClient.Android.cs deleted file mode 100644 index 8c0fc8e6..00000000 --- a/Parse/Internal/HttpClient/Android/HttpClient.Android.cs +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System; -using System.IO; -using System.Net; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Parse.Internal { - internal class HttpClient : IHttpClient { - public Task> ExecuteAsync(HttpRequest httpRequest, - IProgress uploadProgress, - IProgress downloadProgress, - CancellationToken cancellationToken) { - HttpWebRequest request = HttpWebRequest.Create(httpRequest.Uri) as HttpWebRequest; - request.Method = httpRequest.Method; - cancellationToken.Register(() => request.Abort()); - uploadProgress = uploadProgress ?? new Progress(); - downloadProgress = downloadProgress ?? new Progress(); - - // Fill in zero-length data if method is post. - Stream data = httpRequest.Data; - if (data == null && httpRequest.Method.ToLower().Equals("post")) { - data = new MemoryStream(new byte[0]); - } - - // Fill in the headers - if (httpRequest.Headers != null) { - foreach (var header in httpRequest.Headers) { - if (header.Key == "Content-Type") { - // Move over Content-Type header into Content. - request.ContentType = header.Value; - } else { - request.Headers.Add(header.Key, header.Value); - } - } - } - request.IfModifiedSince = DateTime.Now; - - Task uploadTask = null; - - if (data != null) { - Task copyTask = null; - long totalLength = -1; - - try { - totalLength = data.Length; - request.ContentLength = totalLength; - } catch (NotSupportedException) { - } - - // If the length can't be determined, read it into memory first. - if (totalLength == -1) { - var memStream = new MemoryStream(); - copyTask = data.CopyToAsync(memStream).OnSuccess(_ => { - memStream.Seek(0, SeekOrigin.Begin); - totalLength = memStream.Length; - request.ContentLength = totalLength; - - data = memStream; - }); - } - - uploadProgress.Report(new ParseUploadProgressEventArgs { Progress = 0 }); - - uploadTask = copyTask.Safe().ContinueWith(_ => { - return request.GetRequestStreamAsync(); - }).Unwrap().OnSuccess(t => { - var requestStream = t.Result; - - int bufferSize = 4096; - byte[] buffer = new byte[bufferSize]; - int bytesRead = 0; - long readSoFar = 0; - - return InternalExtensions.WhileAsync(() => { - return data.ReadAsync(buffer, 0, bufferSize, cancellationToken).OnSuccess(readTask => { - bytesRead = readTask.Result; - return bytesRead > 0; - }); - }, () => { - cancellationToken.ThrowIfCancellationRequested(); - return requestStream.WriteAsync(buffer, 0, bytesRead, cancellationToken).OnSuccess(_ => { - cancellationToken.ThrowIfCancellationRequested(); - readSoFar += bytesRead; - uploadProgress.Report(new ParseUploadProgressEventArgs { Progress = 1.0 * readSoFar / totalLength }); - }); - }).ContinueWith(_ => { - requestStream.Close(); - return _; - }).Unwrap(); - }).Unwrap(); - } - - return uploadTask.Safe().OnSuccess(_ => { - return request.GetResponseAsync(); - }).Unwrap().ContinueWith(t => { - // Handle canceled - cancellationToken.ThrowIfCancellationRequested(); - - var resultStream = new MemoryStream(); - HttpWebResponse response = null; - if (t.IsFaulted) { - if (t.Exception.InnerException is WebException) { - var webException = t.Exception.InnerException as WebException; - response = (HttpWebResponse)webException.Response; - } else { - TaskCompletionSource> tcs = new TaskCompletionSource>(); - tcs.TrySetException(t.Exception); - - return tcs.Task; - } - } else { - response = (HttpWebResponse)t.Result; - } - - var responseStream = response.GetResponseStream(); - int bufferSize = 4096; - byte[] buffer = new byte[bufferSize]; - int bytesRead = 0; - long totalLength = -1; - long readSoFar = 0; - - try { - totalLength = responseStream.Length; - } catch (NotSupportedException) { - } - - return InternalExtensions.WhileAsync(() => { - return responseStream.ReadAsync(buffer, 0, bufferSize, cancellationToken).OnSuccess(readTask => { - bytesRead = readTask.Result; - return bytesRead > 0; - }); - }, () => { - cancellationToken.ThrowIfCancellationRequested(); - - return resultStream.WriteAsync(buffer, 0, bytesRead, cancellationToken).OnSuccess(_ => { - cancellationToken.ThrowIfCancellationRequested(); - readSoFar += bytesRead; - - if (totalLength > -1) { - downloadProgress.Report(new ParseDownloadProgressEventArgs { Progress = 1.0 * readSoFar / totalLength }); - } - }); - }).ContinueWith(_ => { - responseStream.Close(); - - // If getting stream size is not supported, then report download only once. - if (totalLength == -1) { - downloadProgress.Report(new ParseDownloadProgressEventArgs { Progress = 1.0 }); - } - - // Assume UTF-8 encoding. - var resultAsArray = resultStream.ToArray(); - var resultString = Encoding.UTF8.GetString(resultAsArray); - resultStream.Close(); - return new Tuple(response.StatusCode, resultString); - }); - }).Unwrap(); - } - } -} diff --git a/Parse/Internal/HttpClient/NetFx45/HttpClient.NetFx45.cs b/Parse/Internal/HttpClient/NetFx45/HttpClient.NetFx45.cs deleted file mode 100644 index 6939fc7c..00000000 --- a/Parse/Internal/HttpClient/NetFx45/HttpClient.NetFx45.cs +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System; -using System.IO; -using System.Net; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Parse.Internal { - internal class HttpClient : IHttpClient { - public Task> ExecuteAsync(HttpRequest httpRequest, - IProgress uploadProgress, - IProgress downloadProgress, - CancellationToken cancellationToken) { - HttpWebRequest request = HttpWebRequest.Create(httpRequest.Uri) as HttpWebRequest; - request.Method = httpRequest.Method; - cancellationToken.Register(() => request.Abort()); - uploadProgress = uploadProgress ?? new Progress(); - downloadProgress = downloadProgress ?? new Progress(); - - // Fill in zero-length data if method is post. - Stream data = httpRequest.Data; - if (httpRequest.Data == null && httpRequest.Method.ToLower().Equals("post")) { - data = new MemoryStream(new byte[0]); - } - - // Fill in the headers - if (httpRequest.Headers != null) { - foreach (var header in httpRequest.Headers) { - if (header.Key == "Content-Type") { - // Move over Content-Type header into Content. - request.ContentType = header.Value; - } else { - request.Headers[header.Key] = header.Value; - } - } - } - // Avoid aggressive caching on Windows Phone 8.1. - request.Headers["Cache-Control"] = "no-cache"; - - Task uploadTask = null; - - if (data != null) { - Task copyTask = null; - long totalLength = -1; - - try { - totalLength = data.Length; - } catch (NotSupportedException) { - } - - // If the length can't be determined, read it into memory first. - if (totalLength == -1) { - var memStream = new MemoryStream(); - copyTask = data.CopyToAsync(memStream).OnSuccess(_ => { - memStream.Seek(0, SeekOrigin.Begin); - totalLength = memStream.Length; - - data = memStream; - }); - } - - uploadProgress.Report(new ParseUploadProgressEventArgs { Progress = 0 }); - - uploadTask = copyTask.Safe().ContinueWith(_ => { - return request.GetRequestStreamAsync(); - }).Unwrap().OnSuccess(t => { - var requestStream = t.Result; - - int bufferSize = 4096; - byte[] buffer = new byte[bufferSize]; - int bytesRead = 0; - long readSoFar = 0; - - return InternalExtensions.WhileAsync(() => { - return data.ReadAsync(buffer, 0, bufferSize, cancellationToken).OnSuccess(readTask => { - bytesRead = readTask.Result; - return bytesRead > 0; - }); - }, () => { - cancellationToken.ThrowIfCancellationRequested(); - return requestStream.WriteAsync(buffer, 0, bytesRead, cancellationToken).OnSuccess(_ => { - cancellationToken.ThrowIfCancellationRequested(); - readSoFar += bytesRead; - uploadProgress.Report(new ParseUploadProgressEventArgs { Progress = 1.0 * readSoFar / totalLength }); - }); - }).ContinueWith(_ => { - //requestStream.Flush(); - requestStream.Dispose(); - return _; - }).Unwrap(); - }).Unwrap(); - } - - return uploadTask.Safe().OnSuccess(_ => { - return request.GetResponseAsync(); - }).Unwrap().ContinueWith(t => { - // Handle canceled - cancellationToken.ThrowIfCancellationRequested(); - - var resultStream = new MemoryStream(); - HttpWebResponse response = null; - if (t.IsFaulted) { - if (t.Exception.InnerException is WebException) { - var webException = t.Exception.InnerException as WebException; - response = (HttpWebResponse)webException.Response; - } else { - TaskCompletionSource> tcs = new TaskCompletionSource>(); - tcs.TrySetException(t.Exception); - - return tcs.Task; - } - } else { - response = (HttpWebResponse)t.Result; - } - - var responseStream = response.GetResponseStream(); - - int bufferSize = 4096; - byte[] buffer = new byte[bufferSize]; - int bytesRead = 0; - long totalLength = -1; - long readSoFar = 0; - - try { - totalLength = responseStream.Length; - } catch (NotSupportedException) { - } - - return InternalExtensions.WhileAsync(() => { - return responseStream.ReadAsync(buffer, 0, bufferSize, cancellationToken).OnSuccess(readTask => { - bytesRead = readTask.Result; - return bytesRead > 0; - }); - }, () => { - cancellationToken.ThrowIfCancellationRequested(); - - return resultStream.WriteAsync(buffer, 0, bytesRead, cancellationToken).OnSuccess(_ => { - cancellationToken.ThrowIfCancellationRequested(); - readSoFar += bytesRead; - - if (totalLength > -1) { - downloadProgress.Report(new ParseDownloadProgressEventArgs { Progress = 1.0 * readSoFar / totalLength }); - } - }); - }).ContinueWith(_ => { - responseStream.Dispose(); - return _; - }).Unwrap().OnSuccess(_ => { - // If getting stream size is not supported, then report download only once. - if (totalLength == -1) { - downloadProgress.Report(new ParseDownloadProgressEventArgs { Progress = 1.0 }); - } - - // Assume UTF-8 encoding. - var resultAsArray = resultStream.ToArray(); - var resultString = Encoding.UTF8.GetString(resultAsArray, 0, resultAsArray.Length); - resultStream.Dispose(); - return new Tuple(response.StatusCode, resultString); - }); - }).Unwrap(); - } - } -} diff --git a/Parse/Internal/HttpClient/Phone/HttpClient.Phone.cs b/Parse/Internal/HttpClient/Phone/HttpClient.Phone.cs deleted file mode 100644 index cef24e6f..00000000 --- a/Parse/Internal/HttpClient/Phone/HttpClient.Phone.cs +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System; -using System.IO; -using System.Net; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Parse.Internal { - internal class HttpClient : IHttpClient { - public Task> ExecuteAsync(HttpRequest httpRequest, - IProgress uploadProgress, - IProgress downloadProgress, - CancellationToken cancellationToken) { - var request = HttpWebRequest.Create(httpRequest.Uri); - request.Method = httpRequest.Method; - cancellationToken.Register(() => request.Abort()); - uploadProgress = uploadProgress ?? new Progress(); - downloadProgress = downloadProgress ?? new Progress(); - - // Fill in zero-length data if method is post. - Stream data = httpRequest.Data; - if (data == null && httpRequest.Method.ToLower().Equals("post")) { - data = new MemoryStream(new byte[0]); - } - - // Fill in the headers - if (httpRequest.Headers != null) { - foreach (var header in httpRequest.Headers) { - if (header.Key == "Content-Type") { - // Move over Content-Type header into Content. - request.ContentType = header.Value; - } else { - request.Headers[header.Key] = header.Value; - } - } - } - // Avoid aggressive caching on Windows Phone 8.1. - request.Headers[HttpRequestHeader.CacheControl] = "no-cache"; - request.Headers[HttpRequestHeader.IfModifiedSince] = DateTime.UtcNow.ToString(); - - Task uploadTask = null; - - if (data != null) { - Task copyTask = null; - long totalLength = -1; - - try { - totalLength = data.Length; - request.ContentLength = totalLength; - } catch (NotSupportedException) { - } - - // If the length can't be determined, read it into memory first. - if (totalLength == -1) { - var memStream = new MemoryStream(); - copyTask = data.CopyToAsync(memStream).OnSuccess(_ => { - memStream.Seek(0, SeekOrigin.Begin); - totalLength = memStream.Length; - request.ContentLength = totalLength; - - data = memStream; - }); - } - - uploadProgress.Report(new ParseUploadProgressEventArgs { Progress = 0 }); - - uploadTask = copyTask.Safe().ContinueWith(_ => { - return new TaskFactory(cancellationToken).FromAsync( - request.BeginGetRequestStream, - request.EndGetRequestStream, - TaskCreationOptions.None); - }).Unwrap() - .OnSuccess(t => { - var requestStream = t.Result; - - int bufferSize = 4096; - byte[] buffer = new byte[bufferSize]; - int bytesRead = 0; - long readSoFar = 0; - - return InternalExtensions.WhileAsync(() => { - return data.ReadAsync(buffer, 0, bufferSize, cancellationToken).OnSuccess(readTask => { - bytesRead = readTask.Result; - return bytesRead > 0; - }); - }, () => { - cancellationToken.ThrowIfCancellationRequested(); - return requestStream.WriteAsync(buffer, 0, bytesRead, cancellationToken).OnSuccess(_ => { - cancellationToken.ThrowIfCancellationRequested(); - readSoFar += bytesRead; - uploadProgress.Report(new ParseUploadProgressEventArgs { Progress = 1.0 * readSoFar / totalLength }); - }); - }).ContinueWith(_ => { - requestStream.Close(); - return _; - }).Unwrap(); - }).Unwrap(); - } - - return uploadTask.Safe().ContinueWith(_ => { - return new TaskFactory(cancellationToken).FromAsync( - request.BeginGetResponse, - request.EndGetResponse, - TaskCreationOptions.None); - }).Unwrap().ContinueWith(t => { - // Handle canceled - cancellationToken.ThrowIfCancellationRequested(); - - var resultStream = new MemoryStream(); - HttpWebResponse response = null; - if (t.IsFaulted) { - if (t.Exception.InnerException is WebException) { - var webException = t.Exception.InnerException as WebException; - response = (HttpWebResponse)webException.Response; - } else { - TaskCompletionSource> tcs = new TaskCompletionSource>(); - tcs.TrySetException(t.Exception); - - return tcs.Task; - } - } else { - response = (HttpWebResponse)t.Result; - } - - var responseStream = response.GetResponseStream(); - int bufferSize = 4096; - byte[] buffer = new byte[bufferSize]; - int bytesRead = 0; - long totalLength = -1; - long readSoFar = 0; - - try { - totalLength = responseStream.Length; - } catch (NotSupportedException) { - } - - return InternalExtensions.WhileAsync(() => { - return responseStream.ReadAsync(buffer, 0, bufferSize, cancellationToken).OnSuccess(readTask => { - bytesRead = readTask.Result; - return bytesRead > 0; - }); - }, () => { - cancellationToken.ThrowIfCancellationRequested(); - - return resultStream.WriteAsync(buffer, 0, bytesRead, cancellationToken).OnSuccess(_ => { - cancellationToken.ThrowIfCancellationRequested(); - readSoFar += bytesRead; - - if (totalLength > -1) { - downloadProgress.Report(new ParseDownloadProgressEventArgs { Progress = 1.0 * readSoFar / totalLength }); - } - }); - }).ContinueWith(_ => { - responseStream.Close(); - - // If getting stream size is not supported, then report download only once. - if (totalLength == -1) { - downloadProgress.Report(new ParseDownloadProgressEventArgs { Progress = 1.0 }); - } - - // Assume UTF-8 encoding. - var resultAsArray = resultStream.ToArray(); - var resultString = Encoding.UTF8.GetString(resultAsArray, 0, resultAsArray.Length); - resultStream.Close(); - return new Tuple(response.StatusCode, resultString); - }); - }).Unwrap(); - } - } -} diff --git a/Parse/Internal/HttpClient/WinRT/HttpClient.WinRT.cs b/Parse/Internal/HttpClient/WinRT/HttpClient.WinRT.cs deleted file mode 100644 index 6939fc7c..00000000 --- a/Parse/Internal/HttpClient/WinRT/HttpClient.WinRT.cs +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System; -using System.IO; -using System.Net; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Parse.Internal { - internal class HttpClient : IHttpClient { - public Task> ExecuteAsync(HttpRequest httpRequest, - IProgress uploadProgress, - IProgress downloadProgress, - CancellationToken cancellationToken) { - HttpWebRequest request = HttpWebRequest.Create(httpRequest.Uri) as HttpWebRequest; - request.Method = httpRequest.Method; - cancellationToken.Register(() => request.Abort()); - uploadProgress = uploadProgress ?? new Progress(); - downloadProgress = downloadProgress ?? new Progress(); - - // Fill in zero-length data if method is post. - Stream data = httpRequest.Data; - if (httpRequest.Data == null && httpRequest.Method.ToLower().Equals("post")) { - data = new MemoryStream(new byte[0]); - } - - // Fill in the headers - if (httpRequest.Headers != null) { - foreach (var header in httpRequest.Headers) { - if (header.Key == "Content-Type") { - // Move over Content-Type header into Content. - request.ContentType = header.Value; - } else { - request.Headers[header.Key] = header.Value; - } - } - } - // Avoid aggressive caching on Windows Phone 8.1. - request.Headers["Cache-Control"] = "no-cache"; - - Task uploadTask = null; - - if (data != null) { - Task copyTask = null; - long totalLength = -1; - - try { - totalLength = data.Length; - } catch (NotSupportedException) { - } - - // If the length can't be determined, read it into memory first. - if (totalLength == -1) { - var memStream = new MemoryStream(); - copyTask = data.CopyToAsync(memStream).OnSuccess(_ => { - memStream.Seek(0, SeekOrigin.Begin); - totalLength = memStream.Length; - - data = memStream; - }); - } - - uploadProgress.Report(new ParseUploadProgressEventArgs { Progress = 0 }); - - uploadTask = copyTask.Safe().ContinueWith(_ => { - return request.GetRequestStreamAsync(); - }).Unwrap().OnSuccess(t => { - var requestStream = t.Result; - - int bufferSize = 4096; - byte[] buffer = new byte[bufferSize]; - int bytesRead = 0; - long readSoFar = 0; - - return InternalExtensions.WhileAsync(() => { - return data.ReadAsync(buffer, 0, bufferSize, cancellationToken).OnSuccess(readTask => { - bytesRead = readTask.Result; - return bytesRead > 0; - }); - }, () => { - cancellationToken.ThrowIfCancellationRequested(); - return requestStream.WriteAsync(buffer, 0, bytesRead, cancellationToken).OnSuccess(_ => { - cancellationToken.ThrowIfCancellationRequested(); - readSoFar += bytesRead; - uploadProgress.Report(new ParseUploadProgressEventArgs { Progress = 1.0 * readSoFar / totalLength }); - }); - }).ContinueWith(_ => { - //requestStream.Flush(); - requestStream.Dispose(); - return _; - }).Unwrap(); - }).Unwrap(); - } - - return uploadTask.Safe().OnSuccess(_ => { - return request.GetResponseAsync(); - }).Unwrap().ContinueWith(t => { - // Handle canceled - cancellationToken.ThrowIfCancellationRequested(); - - var resultStream = new MemoryStream(); - HttpWebResponse response = null; - if (t.IsFaulted) { - if (t.Exception.InnerException is WebException) { - var webException = t.Exception.InnerException as WebException; - response = (HttpWebResponse)webException.Response; - } else { - TaskCompletionSource> tcs = new TaskCompletionSource>(); - tcs.TrySetException(t.Exception); - - return tcs.Task; - } - } else { - response = (HttpWebResponse)t.Result; - } - - var responseStream = response.GetResponseStream(); - - int bufferSize = 4096; - byte[] buffer = new byte[bufferSize]; - int bytesRead = 0; - long totalLength = -1; - long readSoFar = 0; - - try { - totalLength = responseStream.Length; - } catch (NotSupportedException) { - } - - return InternalExtensions.WhileAsync(() => { - return responseStream.ReadAsync(buffer, 0, bufferSize, cancellationToken).OnSuccess(readTask => { - bytesRead = readTask.Result; - return bytesRead > 0; - }); - }, () => { - cancellationToken.ThrowIfCancellationRequested(); - - return resultStream.WriteAsync(buffer, 0, bytesRead, cancellationToken).OnSuccess(_ => { - cancellationToken.ThrowIfCancellationRequested(); - readSoFar += bytesRead; - - if (totalLength > -1) { - downloadProgress.Report(new ParseDownloadProgressEventArgs { Progress = 1.0 * readSoFar / totalLength }); - } - }); - }).ContinueWith(_ => { - responseStream.Dispose(); - return _; - }).Unwrap().OnSuccess(_ => { - // If getting stream size is not supported, then report download only once. - if (totalLength == -1) { - downloadProgress.Report(new ParseDownloadProgressEventArgs { Progress = 1.0 }); - } - - // Assume UTF-8 encoding. - var resultAsArray = resultStream.ToArray(); - var resultString = Encoding.UTF8.GetString(resultAsArray, 0, resultAsArray.Length); - resultStream.Dispose(); - return new Tuple(response.StatusCode, resultString); - }); - }).Unwrap(); - } - } -} diff --git a/Parse/Internal/HttpClient/iOS/HttpClient.iOS.cs b/Parse/Internal/HttpClient/iOS/HttpClient.iOS.cs deleted file mode 100644 index 6b9d38a3..00000000 --- a/Parse/Internal/HttpClient/iOS/HttpClient.iOS.cs +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System; -using System.IO; -using System.Net; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Parse.Internal { - internal class HttpClient : IHttpClient { - public Task> ExecuteAsync(HttpRequest httpRequest, - IProgress uploadProgress, - IProgress downloadProgress, - CancellationToken cancellationToken) { - var request = HttpWebRequest.Create(httpRequest.Uri); - request.Method = httpRequest.Method; - cancellationToken.Register(() => request.Abort()); - uploadProgress = uploadProgress ?? new Progress(); - downloadProgress = downloadProgress ?? new Progress(); - - // Fill in zero-length data if method is post. - Stream data = httpRequest.Data; - if (data == null && httpRequest.Method.ToLower().Equals("post")) { - data = new MemoryStream(new byte[0]); - } - - // Fill in the headers - if (httpRequest.Headers != null) { - foreach (var header in httpRequest.Headers) { - if (header.Key == "Content-Type") { - // Move over Content-Type header into Content. - request.ContentType = header.Value; - } else { - request.Headers.Add(header.Key, header.Value); - } - } - } - // Avoid aggressive caching on Windows Phone 8.1. - request.Headers.Add("Cache-Control", "no-cache"); - - Task uploadTask = null; - - if (data != null) { - Task copyTask = null; - long totalLength = -1; - - try { - totalLength = data.Length; - request.ContentLength = totalLength; - } catch (NotSupportedException) { - } - - // If the length can't be determined, read it into memory first. - if (totalLength == -1) { - var memStream = new MemoryStream(); - copyTask = data.CopyToAsync(memStream).OnSuccess(_ => { - memStream.Seek(0, SeekOrigin.Begin); - totalLength = memStream.Length; - request.ContentLength = totalLength; - - data = memStream; - }); - } - - uploadProgress.Report(new ParseUploadProgressEventArgs { Progress = 0 }); - - uploadTask = copyTask.Safe().ContinueWith(_ => { - return request.GetRequestStreamAsync(); - }).Unwrap().OnSuccess(t => { - var requestStream = t.Result; - - int bufferSize = 4096; - byte[] buffer = new byte[bufferSize]; - int bytesRead = 0; - long readSoFar = 0; - - return InternalExtensions.WhileAsync(() => { - return data.ReadAsync(buffer, 0, bufferSize, cancellationToken).OnSuccess(readTask => { - bytesRead = readTask.Result; - return bytesRead > 0; - }); - }, () => { - cancellationToken.ThrowIfCancellationRequested(); - return requestStream.WriteAsync(buffer, 0, bytesRead, cancellationToken).OnSuccess(_ => { - cancellationToken.ThrowIfCancellationRequested(); - readSoFar += bytesRead; - uploadProgress.Report(new ParseUploadProgressEventArgs { Progress = 1.0 * readSoFar / totalLength }); - }); - }).ContinueWith(_ => { - requestStream.Close(); - return _; - }).Unwrap(); - }).Unwrap(); - } - - return uploadTask.Safe().OnSuccess(_ => { - return request.GetResponseAsync(); - }).Unwrap().ContinueWith(t => { - // Handle canceled - cancellationToken.ThrowIfCancellationRequested(); - - var resultStream = new MemoryStream(); - HttpWebResponse response = null; - if (t.IsFaulted) { - if (t.Exception.InnerException is WebException) { - var webException = t.Exception.InnerException as WebException; - response = (HttpWebResponse)webException.Response; - } else { - TaskCompletionSource> tcs = new TaskCompletionSource>(); - tcs.TrySetException(t.Exception); - - return tcs.Task; - } - } else { - response = (HttpWebResponse)t.Result; - } - - var responseStream = response.GetResponseStream(); - int bufferSize = 4096; - byte[] buffer = new byte[bufferSize]; - int bytesRead = 0; - long totalLength = -1; - long readSoFar = 0; - - try { - totalLength = responseStream.Length; - } catch (NotSupportedException) { - } - - return InternalExtensions.WhileAsync(() => { - return responseStream.ReadAsync(buffer, 0, bufferSize, cancellationToken).OnSuccess(readTask => { - bytesRead = readTask.Result; - return bytesRead > 0; - }); - }, () => { - cancellationToken.ThrowIfCancellationRequested(); - - return resultStream.WriteAsync(buffer, 0, bytesRead, cancellationToken).OnSuccess(_ => { - cancellationToken.ThrowIfCancellationRequested(); - readSoFar += bytesRead; - - if (totalLength > -1) { - downloadProgress.Report(new ParseDownloadProgressEventArgs { Progress = 1.0 * readSoFar / totalLength }); - } - }); - }).ContinueWith(_ => { - responseStream.Close(); - - // If getting stream size is not supported, then report download only once. - if (totalLength == -1) { - downloadProgress.Report(new ParseDownloadProgressEventArgs { Progress = 1.0 }); - } - - // Assume UTF-8 encoding. - var resultAsArray = resultStream.ToArray(); - var resultString = Encoding.UTF8.GetString(resultAsArray); - resultStream.Close(); - return new Tuple(response.StatusCode, resultString); - }); - }).Unwrap(); - } - } -} diff --git a/Parse/Internal/Installation/Controller/InstallationIdController.cs b/Parse/Internal/Installation/Controller/InstallationIdController.cs deleted file mode 100644 index 2d8b4ce5..00000000 --- a/Parse/Internal/Installation/Controller/InstallationIdController.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System; -using System.Threading; - -namespace Parse.Internal { - class InstallationIdController : IInstallationIdController { - private readonly object mutex = new object(); - private Guid? installationId; - - public void Set(Guid? installationId) { - lock (mutex) { - if (installationId == null) { - ParseClient.PlatformHooks.ApplicationSettings.Remove("InstallationId"); - } else { - ParseClient.PlatformHooks.ApplicationSettings["InstallationId"] = installationId.ToString(); - } - this.installationId = installationId; - } - } - - public Guid? Get() { - lock (mutex) { - if (installationId != null) { - return installationId; - } - object id; - ParseClient.PlatformHooks.ApplicationSettings.TryGetValue("InstallationId", out id); - try { - installationId = new Guid((string)id); - } catch (Exception) { - var newInstallationId = Guid.NewGuid(); - Set(newInstallationId); - } - return installationId; - } - } - - public void Clear() { - Set(null); - } - } -} diff --git a/Parse/Internal/Installation/Controller/ParseCurrentInstallationController.cs b/Parse/Internal/Installation/Controller/ParseCurrentInstallationController.cs deleted file mode 100644 index db6c01f9..00000000 --- a/Parse/Internal/Installation/Controller/ParseCurrentInstallationController.cs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Parse.Internal { - internal class ParseCurrentInstallationController : IParseCurrentInstallationController { - private readonly object mutex = new object(); - private readonly TaskQueue taskQueue = new TaskQueue(); - private readonly IInstallationIdController installationIdController; - - public ParseCurrentInstallationController(IInstallationIdController installationIdController) { - this.installationIdController = installationIdController; - } - - private ParseInstallation currentInstallation; - internal ParseInstallation CurrentInstallation { - get { - lock (mutex) { - return currentInstallation; - } - } - set { - lock (mutex) { - currentInstallation = value; - } - } - } - - public Task SetAsync(ParseInstallation installation, CancellationToken cancellationToken) { - return taskQueue.Enqueue(toAwait => { - return toAwait.ContinueWith(_ => { - if (installation == null) { - ParseClient.ApplicationSettings.Remove("CurrentInstallation"); - } else { - // TODO (hallucinogen): we need to use ParseCurrentCoder instead of this janky encoding - var data = installation.ServerDataToJSONObjectForSerialization(); - data["objectId"] = installation.ObjectId; - if (installation.CreatedAt != null) { - data["createdAt"] = installation.CreatedAt.Value.ToString(ParseClient.DateFormatStrings.First()); - } - if (installation.UpdatedAt != null) { - data["updatedAt"] = installation.UpdatedAt.Value.ToString(ParseClient.DateFormatStrings.First()); - } - - ParseClient.ApplicationSettings["CurrentInstallation"] = Json.Encode(data); - } - CurrentInstallation = installation; - }); - }, cancellationToken); - } - - public Task GetAsync(CancellationToken cancellationToken) { - ParseInstallation cachedCurrent; - cachedCurrent = CurrentInstallation; - - if (cachedCurrent != null) { - return Task.FromResult(cachedCurrent); - } - - return taskQueue.Enqueue(toAwait => { - return toAwait.ContinueWith(t => { - object temp; - ParseClient.ApplicationSettings.TryGetValue("CurrentInstallation", out temp); - var installationDataString = temp as string; - ParseInstallation installation = null; - if (installationDataString != null) { - var installationData = ParseClient.DeserializeJsonString(installationDataString); - var state = ParseObjectCoder.Instance.Decode(installationData, ParseDecoder.Instance); - installation = ParseObject.FromState(state, "_Installation"); - } else { - installation = ParseObject.Create(); - installation.SetIfDifferent("installationId" , installationIdController.Get().ToString()); - } - - CurrentInstallation = installation; - return installation; - }); - }, cancellationToken); - } - - public Task ExistsAsync(CancellationToken cancellationToken) { - if (CurrentInstallation != null) { - return Task.FromResult(true); - } - - return taskQueue.Enqueue(toAwait => { - return toAwait.ContinueWith(t => ParseClient.ApplicationSettings.ContainsKey("CurrentInstallation")); - }, cancellationToken); - } - - public bool IsCurrent(ParseInstallation installation) { - return CurrentInstallation == installation; - } - - public void ClearFromMemory() { - CurrentInstallation = null; - } - - public void ClearFromDisk() { - ClearFromMemory(); - - ParseClient.ApplicationSettings.Remove("CurrentInstallation"); - } - } -} diff --git a/Parse/Internal/PlatformHooks/Android/PlatformHooks.Android.cs b/Parse/Internal/PlatformHooks/Android/PlatformHooks.Android.cs deleted file mode 100644 index 020fce93..00000000 --- a/Parse/Internal/PlatformHooks/Android/PlatformHooks.Android.cs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using Android.OS; -using Parse.Internal; -using System.Threading; -using System.Threading.Tasks; -using System.Text; - -using PreserveAttribute = Android.Runtime.PreserveAttribute; - -namespace Parse { - [Preserve(AllMembers = true)] - partial class PlatformHooks : IPlatformHooks { - private IHttpClient httpClient = null; - public IHttpClient HttpClient { - get { - httpClient = httpClient ?? new HttpClient(); - return httpClient; - } - } - - public string SDKName { - get { - return "xamarin-android"; - } - } - - public string AppName { - get { - return ManifestInfo.DisplayName; - } - } - - public string AppBuildVersion { - get { - return ManifestInfo.VersionCode.ToString(); - } - } - - public string AppDisplayVersion { - get { - return ManifestInfo.VersionName; - } - } - - public string AppIdentifier { - get { - return ManifestInfo.PackageName; - } - } - - public string OSVersion { - get { - return Build.VERSION.Release; - } - } - - public string DeviceType { - get { - return "android"; - } - } - - public string DeviceTimeZone { - get { - return Java.Util.TimeZone.Default.ID; - } - } - - public void Initialize() { - if (ManifestInfo.HasPermissionForGCM()) { - GcmRegistrar.GetInstance().Register(); - } - } - - public Task ExecuteParseInstallationSaveHookAsync(ParseInstallation installation) { - // Do nothing. - return Task.FromResult(0); - } - } -} \ No newline at end of file diff --git a/Parse/Internal/PlatformHooks/IPlatformHooks.cs b/Parse/Internal/PlatformHooks/IPlatformHooks.cs deleted file mode 100644 index a9e28e1e..00000000 --- a/Parse/Internal/PlatformHooks/IPlatformHooks.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Threading; -using System.Threading.Tasks; - -namespace Parse.Internal { - interface IPlatformHooks { - /// - /// A thread-safe dictionary that persists key-value pair objects to disk. - /// - IDictionary ApplicationSettings { get; } - IHttpClient HttpClient { get; } - - void Initialize(); - - /// - /// Executes platform specific hook that mutate the installation based on - /// the device platforms. - /// - /// Installation to be mutated. - /// - Task ExecuteParseInstallationSaveHookAsync(ParseInstallation installation); - - string SDKName { get; } - string AppName { get; } - string AppBuildVersion { get; } - string AppDisplayVersion { get; } - string AppIdentifier { get; } - string OSVersion { get; } - string DeviceType { get; } - string DeviceTimeZone { get; } - } -} diff --git a/Parse/Internal/PlatformHooks/Mono/PlatformHooks.Mono.cs b/Parse/Internal/PlatformHooks/Mono/PlatformHooks.Mono.cs deleted file mode 100644 index 966bf345..00000000 --- a/Parse/Internal/PlatformHooks/Mono/PlatformHooks.Mono.cs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System.Threading.Tasks; -using System.Threading; -using System; -using System.Collections.Generic; -using System.IO.IsolatedStorage; -using System.IO; - -using Parse.Internal; - -namespace Parse { - static class MonoHelpers { - static Task ReadAsync(this Stream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken) { - cancellationToken.ThrowIfCancellationRequested(); - return Task.Factory.FromAsync( - (callback, obj) => stream.BeginRead(buffer, offset, count, callback, obj), - (Func)stream.EndRead, - TaskCreationOptions.None); - } - } - - partial class PlatformHooks : IPlatformHooks { - /// - /// Wraps an IsolatedStorageFile as an object for Parse so that it can be exposed as ApplicationSettings. - /// - private class SettingsWrapper : IDictionary { - private static readonly IsolatedStorageFile isolatedStore = IsolatedStorageFile.GetUserStoreForAssembly(); - private object mutex = new object(); - private readonly IDictionary data; - private readonly string fileName; - internal SettingsWrapper(string fileName) { - this.fileName = fileName; - if (!isolatedStore.FileExists(fileName)) { - data = new Dictionary(); - Save(); - } else { - data = ParseClient.DeserializeJsonString(ReadFile()) ?? new Dictionary(); - } - } - private string ReadFile() { - lock (mutex) { - using (var reader = new StreamReader(isolatedStore.OpenFile(fileName, FileMode.Open, FileAccess.Read))) { - return reader.ReadToEnd(); - } - } - } - private void Save() { - lock (mutex) { - using (var writer = new StreamWriter(isolatedStore.OpenFile(fileName, FileMode.Create, FileAccess.Write))) { - writer.Write(ParseClient.SerializeJsonString(data)); - } - } - } - public void Add(string key, object value) { - data.Add(key, value); - Save(); - } - - public bool ContainsKey(string key) { - return data.ContainsKey(key); - } - - public ICollection Keys { - get { return data.Keys; } - } - - public bool Remove(string key) { - if (data.Remove(key)) { - Save(); - return true; - } - return false; - } - - public bool TryGetValue(string key, out object value) { - return data.TryGetValue(key, out value); - } - - public ICollection Values { - get { return data.Values; } - } - - public object this[string key] { - get { - return data[key]; - } - set { - data[key] = value; - Save(); - } - } - - public void Add(KeyValuePair item) { - data.Add(item); - Save(); - } - - public void Clear() { - data.Clear(); - Save(); - } - - public bool Contains(KeyValuePair item) { - return data.Contains(item); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) { - data.CopyTo(array, arrayIndex); - } - - public int Count { - get { return data.Count; } - } - - public bool IsReadOnly { - get { return data.IsReadOnly; } - } - - public bool Remove(KeyValuePair item) { - if (data.Remove(item)) { - Save(); - return true; - } - return false; - } - - public IEnumerator> GetEnumerator() { - return data.GetEnumerator(); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { - return data.GetEnumerator(); - } - } - - private readonly Lazy settings = - new Lazy(() => new SettingsWrapper("ApplicationSettings"), true); - public IDictionary ApplicationSettings { - get { return settings.Value; } - } - } -} diff --git a/Parse/Internal/PlatformHooks/NetFx45/PlatformHooks.NetFx45.cs b/Parse/Internal/PlatformHooks/NetFx45/PlatformHooks.NetFx45.cs deleted file mode 100644 index 6752d674..00000000 --- a/Parse/Internal/PlatformHooks/NetFx45/PlatformHooks.NetFx45.cs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using Parse.Internal; -using System; -using System.Reflection; -using System.Threading.Tasks; - -namespace Parse { - partial class PlatformHooks : IPlatformHooks { - private IHttpClient httpClient = null; - public IHttpClient HttpClient { - get { - httpClient = httpClient ?? new HttpClient(); - return httpClient; - } - } - - public string SDKName { - get { - return "netfx"; - } - } - - public string AppName { - get { - var assembly = Assembly.GetEntryAssembly(); - if (assembly == null) { - return null; - } else { - return assembly.GetName().Name; - } - } - } - - public string AppBuildVersion { - get { - var assembly = Assembly.GetEntryAssembly(); - if (assembly == null) { - return null; - } else { - return assembly.GetName().Version.ToString(); - } - } - } - - public string AppDisplayVersion { - get { - var assembly = Assembly.GetEntryAssembly(); - if (assembly == null) { - return null; - } else { - return assembly.GetName().Version.ToString(); - } - } - } - - public string AppIdentifier { - get { - ApplicationIdentity appId = AppDomain.CurrentDomain.ApplicationIdentity; - if (appId == null) { - return null; - } else { - return appId.FullName; - } - } - } - - public string OSVersion { - get { - return Environment.OSVersion.ToString(); - } - } - - public string DeviceType { - get { - return "dotnet"; - } - } - - public string DeviceTimeZone { - get { - string windowsName = TimeZoneInfo.Local.StandardName; - if (ParseInstallation.TimeZoneNameMap.ContainsKey(windowsName)) { - return ParseInstallation.TimeZoneNameMap[windowsName]; - } else { - return null; - } - } - } - - public void Initialize() { - // Do nothing. - } - - public Task ExecuteParseInstallationSaveHookAsync(ParseInstallation installation) { - // Do nothing. - return Task.FromResult(0); - } - } -} diff --git a/Parse/Internal/PlatformHooks/SettingsStorage/PlatformHooks.SettingsStorage.cs b/Parse/Internal/PlatformHooks/SettingsStorage/PlatformHooks.SettingsStorage.cs deleted file mode 100644 index fa871cfb..00000000 --- a/Parse/Internal/PlatformHooks/SettingsStorage/PlatformHooks.SettingsStorage.cs +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using Parse.Internal; -using Parse.Properties; -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Linq; -using System.Text; - -namespace Parse { - partial class PlatformHooks : IPlatformHooks { - private static readonly IDictionary settings; - static PlatformHooks() { - try { - settings = SettingsWrapper.Wrapper; - } catch (ConfigurationException) { - settings = new Dictionary(); - } - } - /// - /// Wraps the custom settings object for Parse so that it can be exposed as ApplicationSettings. - /// - private class SettingsWrapper : IDictionary { - private static SettingsWrapper wrapper; - public static SettingsWrapper Wrapper { - get { - wrapper = wrapper ?? new SettingsWrapper(); - return wrapper; - } - } - private readonly IDictionary data; - private SettingsWrapper() { - if (string.IsNullOrEmpty(Settings.Default.ApplicationSettings)) { - data = new Dictionary(); - Save(); - } else { - data = ParseClient.DeserializeJsonString(Settings.Default.ApplicationSettings); - } - } - private void Save() { - Settings.Default.ApplicationSettings = ParseClient.SerializeJsonString(data); - Settings.Default.Save(); - } - public void Add(string key, object value) { - data.Add(key, value); - Save(); - } - - public bool ContainsKey(string key) { - return data.ContainsKey(key); - } - - public ICollection Keys { - get { return data.Keys; } - } - - public bool Remove(string key) { - if (data.Remove(key)) { - Save(); - return true; - } - return false; - } - - public bool TryGetValue(string key, out object value) { - return data.TryGetValue(key, out value); - } - - public ICollection Values { - get { return data.Values; } - } - - public object this[string key] { - get { - return data[key]; - } - set { - data[key] = value; - Save(); - } - } - - public void Add(KeyValuePair item) { - data.Add(item); - Save(); - } - - public void Clear() { - data.Clear(); - Save(); - } - - public bool Contains(KeyValuePair item) { - return data.Contains(item); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) { - data.CopyTo(array, arrayIndex); - } - - public int Count { - get { return data.Count; } - } - - public bool IsReadOnly { - get { return data.IsReadOnly; } - } - - public bool Remove(KeyValuePair item) { - if (data.Remove(item)) { - Save(); - return true; - } - return false; - } - - public IEnumerator> GetEnumerator() { - return data.GetEnumerator(); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { - return data.GetEnumerator(); - } - } - - /// - /// Provides a dictionary that gets persisted on the filesystem between runs of the app. - /// This is analogous to NSUserDefaults in iOS. - /// - public IDictionary ApplicationSettings { - get { - return settings; - } - } - } -} diff --git a/Parse/Internal/PlatformHooks/Unity/PlatformHooks.Unity.cs b/Parse/Internal/PlatformHooks/Unity/PlatformHooks.Unity.cs deleted file mode 100644 index 8e9127bf..00000000 --- a/Parse/Internal/PlatformHooks/Unity/PlatformHooks.Unity.cs +++ /dev/null @@ -1,1190 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using Parse.Internal; -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading; -using System.Threading.Tasks; -using UnityEngine; - -namespace Parse { - partial class PlatformHooks : IPlatformHooks { - private static IDictionary settings; - private static string settingsPath; - - private IHttpClient httpClient = null; - public IHttpClient HttpClient { - get { - httpClient = httpClient ?? new HttpClient(); - return httpClient; - } - } - - public string SDKName { - get { - return "unity"; - } - } - - private string appName; - public string AppName { - get { - return appName; - } - } - - private string appBuildVersion; - public string AppBuildVersion { - get { - return appBuildVersion; - } - } - - private string appDisplayVersion; - public string AppDisplayVersion { - get { - return appDisplayVersion; - } - } - - public string AppIdentifier { - get { - ApplicationIdentity appId = AppDomain.CurrentDomain.ApplicationIdentity; - if (appId == null) { - return null; - } else { - return appId.FullName; - } - } - } - - private string osVersion; - public string OSVersion { - get { - return osVersion; - } - } - - public string DeviceType { - get { - if (PlatformHooks.IsAndroid) { - return "android"; - } else if (PlatformHooks.IsIOS) { - return "ios"; - } else if (PlatformHooks.IsWindowsPhone8) { - return "winphone"; - } else { - return "unknown"; - } - } - } - - public string DeviceTimeZone { - get { - try { - // We need the system string to be in english so we'll have the proper key in our lookup table. - // If it's not in english then we will attempt to fallback to the closest Time Zone we can find. - TimeZoneInfo tzInfo = TimeZoneInfo.Local; - - string deviceTimeZone = null; - if (ParseInstallation.TimeZoneNameMap.TryGetValue(tzInfo.StandardName, out deviceTimeZone)) { - return deviceTimeZone; - } - - TimeSpan utcOffset = tzInfo.BaseUtcOffset; - - // If we have an offset that is not a round hour, then use our second map to see if we can - // convert it or not. - if (ParseInstallation.TimeZoneOffsetMap.TryGetValue(utcOffset, out deviceTimeZone)) { - return deviceTimeZone; - } - - // NOTE: Etc/GMT{+/-} format is inverted from the UTC offset we use as normal people - - // a negative value means ahead of UTC, a positive value means behind UTC. - bool negativeOffset = utcOffset.Ticks < 0; - return String.Format("Etc/GMT{0}{1}", negativeOffset ? "+" : "-", Math.Abs(utcOffset.Hours)); - } catch (TimeZoneNotFoundException) { - return null; - } - } - } - - private static bool isCompiledByIL2CPP = System.AppDomain.CurrentDomain.FriendlyName.Equals("IL2CPP Root Domain"); - /// - /// Returns true if current running platform is run from a project generated by IL2CPP compiler. - /// - internal static bool IsCompiledByIL2CPP { - get { - return isCompiledByIL2CPP; - } - } - - private static bool isWebPlayer; - /// - /// Returns true if current running platform is a web player. - /// - internal static bool IsWebPlayer { - get { - if (settingsPath == null) { - throw new InvalidOperationException("Parse must be initialized before making any calls."); - } - return isWebPlayer; - } - } - - /// - /// Returns true if current running platform is Android. - /// - internal static bool IsAndroid { - get { - if (settingsPath == null) { - throw new InvalidOperationException("Parse must be initialized before making any calls."); - } - return Application.platform == RuntimePlatform.Android; - } - } - - /// - /// Returns true if current running platform is iPhone or iPad. - /// - internal static bool IsIOS { - get { - if (settingsPath == null) { - throw new InvalidOperationException("Parse must be initialized before making any calls."); - } - return Application.platform == RuntimePlatform.IPhonePlayer; - } - } - - /// - /// Returns true if the current platform is tvOS. - /// - internal static bool IsTvOS { - get { - if (settingsPath == null) { - throw new InvalidOperationException("Parse must be initialized before making any calls."); - } - return Application.platform == RuntimePlatform.tvOS; - } - } - - /// - /// Returns true if current running platform is Windows Phone 8. - /// - internal static bool IsWindowsPhone8 { - get { - if (settingsPath == null) { - throw new InvalidOperationException("Parse must be initialized before making any calls."); - } - return Application.platform == RuntimePlatform.WP8Player; - } - } - - #region Unity Reflection Helpers - - internal static Type GetTypeFromUnityEngine(string typeName) { - return Type.GetType(string.Format("UnityEngine.{0}, UnityEngine", typeName)); - } - - /// - /// Calls a static method under Unity Java plugin with reflection. - /// - /// - /// Warning: Unity Android only. - /// - /// Basically what we want to do: - /// - /// AndroidJavaClass javaUnityHelper = new AndroidJavaClass(className); - /// javaUnityHelper.CallStatic(methodName, parameters); - /// But we can't because AndroidJavaClass is not cross-platform. It won't compile on iOS. - /// - /// - /// - /// - /// - internal static void CallStaticJavaUnityMethod(string className, string methodName, object[] parameters) { - Type androidJavaClassType = PlatformHooks.GetTypeFromUnityEngine("AndroidJavaClass"); - if (androidJavaClassType != null) { - // Yo dawg, I heard you like reflection. So I used reflection to invoke a method via reflection inside Java - // which calls another reflection in Java. - var javaUnityHelper = Activator.CreateInstance(androidJavaClassType, className); - var callStaticMethod = androidJavaClassType.GetMethods() - .Where(x => x.Name == "CallStatic") - .First(x => !x.ContainsGenericParameters); - if (callStaticMethod != null) { - callStaticMethod.Invoke(javaUnityHelper, new object[] { methodName, parameters }); - } - } - } - - #endregion - - /// - /// Wraps the custom settings object for Parse so that it can be exposed as ApplicationSettings. - /// - private class SettingsWrapper : IDictionary { - private readonly IDictionary data; - - private static SettingsWrapper wrapper; - public static SettingsWrapper Wrapper { - get { - wrapper = wrapper ?? new SettingsWrapper(); - return wrapper; - } - } - - private SettingsWrapper() { - var existingSettings = Load(); - if (string.IsNullOrEmpty(existingSettings)) { - data = new Dictionary(); - Save(); - } else { - data = ParseClient.DeserializeJsonString(existingSettings); - } - } - - private string Load() { - if (settingsPath == null) { - throw new InvalidOperationException("Parse must be initialized before making any calls."); - } - lock (this) { - try { - if (IsWebPlayer) { - return PlayerPrefs.GetString("Parse.settings", null); - } else if (IsTvOS) { - Debug.Log("Running on TvOS, prefs cannot be loaded."); - return null; - } else { - using (var fs = new FileStream(settingsPath, FileMode.Open, FileAccess.Read)) { - var reader = new StreamReader(fs); - return reader.ReadToEnd(); - } - } - } catch (Exception) { - return null; - } - } - } - - private void Save() { - if (settingsPath == null) { - throw new InvalidOperationException("Parse must be initialized before making any calls."); - } - lock (this) { - if (IsWebPlayer) { - PlayerPrefs.SetString("Parse.settings", ParseClient.SerializeJsonString(data)); - PlayerPrefs.Save(); - } else if (IsTvOS) { - Debug.Log("Running on TvOS, prefs cannot be saved."); - } else { - using (var fs = new FileStream(settingsPath, FileMode.Create, FileAccess.Write)) { - using (var writer = new StreamWriter(fs)) { - writer.Write(ParseClient.SerializeJsonString(data)); - } - } - } - } - } - - public void Add(string key, object value) { - data.Add(key, value); - Save(); - } - - public bool ContainsKey(string key) { - return data.ContainsKey(key); - } - - public ICollection Keys { - get { return data.Keys; } - } - - public bool Remove(string key) { - if (data.Remove(key)) { - Save(); - return true; - } - return false; - } - - public bool TryGetValue(string key, out object value) { - return data.TryGetValue(key, out value); - } - - public ICollection Values { - get { return data.Values; } - } - - public object this[string key] { - get { - return data[key]; - } - set { - data[key] = value; - Save(); - } - } - - public void Add(KeyValuePair item) { - data.Add(item); - Save(); - } - - public void Clear() { - data.Clear(); - Save(); - } - - public bool Contains(KeyValuePair item) { - return data.Contains(item); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) { - data.CopyTo(array, arrayIndex); - } - - public int Count { - get { return data.Count; } - } - - public bool IsReadOnly { - get { return data.IsReadOnly; } - } - - public bool Remove(KeyValuePair item) { - if (data.Remove(item)) { - Save(); - return true; - } - return false; - } - - public IEnumerator> GetEnumerator() { - return data.GetEnumerator(); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { - return data.GetEnumerator(); - } - } - - /// - /// Provides a dictionary that gets persisted on the filesystem between runs of the app. - /// This is analogous to NSUserDefaults in iOS. - /// - public IDictionary ApplicationSettings { - get { - if (settings == null) { - throw new InvalidOperationException("Parse must be initialized before making any calls."); - } - return settings; - } - } - - /// - /// Exists to ensure that generic types are AOT-compiled for the conversions we support. - /// Any new value types that we add support for will need to be registered here. - /// The method itself is never called, but by virtue of the Preserve attribute being set - /// on the PlatformHooks class, these types will be AOT-compiled. - /// - private static List CreateWrapperTypes() { - return new List { - (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(() => ParseCloud.CallFunctionAsync>(null, null, CancellationToken.None)), - (Action)(() => ParseCloud.CallFunctionAsync>(null, null, CancellationToken.None)), - - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - typeof(FlexibleListWrapper>), - typeof(FlexibleListWrapper, object>), - - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - typeof(FlexibleDictionaryWrapper>), - typeof(FlexibleDictionaryWrapper, object>), - }; - } - - private static readonly ReaderWriterLockSlim dispatchQueueLock = new ReaderWriterLockSlim(); - private static readonly Queue dispatchQueue = new Queue(); - - /// - /// Registers a callback for network requests, running the callback on the main thread until - /// the network request is complete. - /// - internal static void RegisterNetworkRequest(WWW www, Action action) { - RunOnMainThread(() => { - var isDone = www.isDone; - action(www); - if (!isDone) { - RegisterNetworkRequest(www, action); - } - }); - } - - #region iOS Callbacks - - /// - /// Warning: iOS only. Registers a callback for device token request. - /// - /// Action to be completed when device token is received. - internal static void RegisterDeviceTokenRequest(Action action) { - RunOnMainThread(() => { - var deviceToken = UnityEngine.iOS.NotificationServices.deviceToken; - if (deviceToken != null) { - action(deviceToken); - RegisteriOSPushNotificationListener((payload) => { - ParsePush.parsePushNotificationReceived.Invoke(ParseInstallation.CurrentInstallation, new ParsePushNotificationEventArgs(payload)); - }); - } else { - RegisterDeviceTokenRequest(action); - } - }); - } - - /// - /// Warning: iOS only. Registers a callback for push notification. - /// - /// Action to be completed when push notification is received. - internal static void RegisteriOSPushNotificationListener(Action> action) { - RunOnMainThread(() => { - int remoteNotificationCount = UnityEngine.iOS.NotificationServices.remoteNotificationCount; - if (remoteNotificationCount > 0) { - var remoteNotifications = UnityEngine.iOS.NotificationServices.remoteNotifications; - foreach (var val in remoteNotifications) { - var userInfo = val.userInfo; - var payload = new Dictionary(); - foreach (var key in userInfo.Keys) { - payload[key.ToString()] = userInfo[key]; - } - - // Finally, do the action for each remote notification payload. - action(payload); - } - - UnityEngine.iOS.NotificationServices.ClearRemoteNotifications(); - } - - // Check in every frame. - RegisteriOSPushNotificationListener(action); - }); - } - - #endregion - - /// - /// Runs things inside of a Unity coroutine (some APIs require that you - /// access them from the main thread). - /// - internal static void RunOnMainThread(Action action) { - if (dispatchQueueLock.IsWriteLockHeld) { - dispatchQueue.Enqueue(action); - return; - } - dispatchQueueLock.EnterWriteLock(); - try { - dispatchQueue.Enqueue(action); - } finally { - dispatchQueueLock.ExitWriteLock(); - } - } - - /// - /// Returns an enumerator (for use in a coroutine) that runs actions that have been dispatched. - /// - internal static IEnumerator RunDispatcher() { - while (true) { - dispatchQueueLock.EnterUpgradeableReadLock(); - try { - // We'll only empty what's already in the dispatch queue in this iteration (so that a - // nested dispatch behaves like nextTick()). - int count = dispatchQueue.Count; - if (count > 0) { - dispatchQueueLock.EnterWriteLock(); - try { - while (count > 0) { - try { - dispatchQueue.Dequeue()(); - } catch (Exception e) { - // If an exception occurs, catch it and log it so that dispatches aren't broken. - Debug.LogException(e); - } - count--; - } - } finally { - dispatchQueueLock.ExitWriteLock(); - } - } - } finally { - dispatchQueueLock.ExitUpgradeableReadLock(); - } - yield return null; - } - } - - /// - /// Initialize the app. Called from . Guaranteed to be run on main thread. - /// - public void Initialize() { - if (settingsPath != null) { - return; - } - - settingsPath = Path.Combine(Application.persistentDataPath, "Parse.settings"); - // We can only set some values here since we can be sure that Initialize is always called - // from main thread. - isWebPlayer = Application.isWebPlayer; - osVersion = SystemInfo.deviceModel; - appBuildVersion = Application.version; - appDisplayVersion = Application.bundleIdentifier; - appName = Application.productName; - - settings = SettingsWrapper.Wrapper; - - // TODO (hallucinogen): We might not want to do this automagically... - ParseFacebookUtils.Initialize(); - - if (IsAndroid) { - try { - CallStaticJavaUnityMethod("com.parse.ParsePushUnityHelper", "registerGcm", null); - } catch (Exception e) { - // We don't care about the exception. If it reaches this point, it means the Plugin is misconfigured/we don't want to use - // PushNotification. Let's just log it to developer. - Debug.LogException(e); - } - } - } - - public Task ExecuteParseInstallationSaveHookAsync(ParseInstallation installation) { - return Task.Run(() => { - installation.SetIfDifferent("badge", installation.Badge); - }); - } - } -} diff --git a/Parse/Internal/PlatformHooks/WinRT/PlatformHooks.WinRT.cs b/Parse/Internal/PlatformHooks/WinRT/PlatformHooks.WinRT.cs deleted file mode 100644 index e28b2009..00000000 --- a/Parse/Internal/PlatformHooks/WinRT/PlatformHooks.WinRT.cs +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using Parse.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml.Linq; -using Windows.ApplicationModel; -using Windows.Networking.PushNotifications; -using Windows.Storage; -using Windows.Storage.Streams; - -namespace Parse { - partial class PlatformHooks : IPlatformHooks { - /// - /// Future proofing: Right now there's only one valid channel for the app, but we will likely - /// want to allow additional channels for auxiliary tiles (i.e. a contacts app can have a new - /// channel for each contact and the UI needs to pop up on the right tile). The expansion job - /// generically has one _Installation field it passes to device-specific code, so we store a map - /// of tag -> channel URI. Right now, there is only one valid tag and it is automatic. - /// Unused variable warnings are suppressed because this const is used in WinRT and WinPhone but not NetFx. - /// - private static readonly string defaultChannelTag = "_Default"; - - // This must be wrapped in a property so other classes may continue on this task - // during their static initialization. - private static Lazy> getChannelTask = new Lazy>(() => - PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync().AsTask() - ); - internal static Task GetChannelTask { - get { - return getChannelTask.Value; - } - } - - static PlatformHooks() { - var _ = GetChannelTask; - } - - private IHttpClient httpClient = null; - public IHttpClient HttpClient { - get { - httpClient = httpClient ?? new HttpClient(); - return httpClient; - } - } - - public string SDKName { - get { - return "winrt"; - } - } - - public string AppName { - get { - var task = Package.Current.InstalledLocation.GetFileAsync("AppxManifest.xml").AsTask().OnSuccess(t => { - return FileIO.ReadTextAsync(t.Result).AsTask(); - }).Unwrap().OnSuccess(t => { - var doc = XDocument.Parse(t.Result); - - // Define the default namespace to be used - var propertiesXName = XName.Get("Properties", "http://schemas.microsoft.com/appx/2010/manifest"); - var displayNameXName = XName.Get("DisplayName", "http://schemas.microsoft.com/appx/2010/manifest"); - - return doc.Descendants(propertiesXName).Single().Descendants(displayNameXName).Single().Value; - }); - task.Wait(); - return task.Result; - } - } - - public string AppBuildVersion { - get { - var version = Package.Current.Id.Version; - return string.Format("{0}.{1}.{2}.{3}", version.Major, version.Minor, version.Build, version.Revision); - } - } - - public string AppDisplayVersion { - get { - return AppBuildVersion; - } - } - - public string AppIdentifier { - get { - return Package.Current.Id.Name; - } - } - - public string OSVersion { - get { - // It's impossible to do with WinRT. - return ""; - } - } - - public string DeviceType { - get { - return "winrt"; - } - } - - public string DeviceTimeZone { - get { - string windowsName = TimeZoneInfo.Local.StandardName; - if (ParseInstallation.TimeZoneNameMap.ContainsKey(windowsName)) { - return ParseInstallation.TimeZoneNameMap[windowsName]; - } else { - return null; - } - } - } - - public void Initialize() { - // Do nothing. - } - - public Task ExecuteParseInstallationSaveHookAsync(ParseInstallation installation) { - return GetChannelTask.ContinueWith(t => { - installation.SetIfDifferent("deviceUris", new Dictionary { - { defaultChannelTag, t.Result.Uri } - }); - }); - } - - /// - /// Wraps the LocalSettings for Parse so that large strings can be stored in multiple keys. - /// It accomplishes this by adding a __Count version of the field and then splits the value - /// across __### fields. - /// - private class SettingsWrapper : IDictionary { - private static readonly object mutex = new object(); - private static readonly string Delimiter = "__"; - private static readonly string CountSuffix = Delimiter + "Count"; - private const int ShardSize = 1024; - private static SettingsWrapper wrapper; - public static SettingsWrapper Wrapper { - get { - lock (mutex) { - wrapper = wrapper ?? new SettingsWrapper(); - return wrapper; - } - } - } - - private readonly IDictionary data; - private SettingsWrapper() { - var container = ApplicationData.Current.LocalSettings - .CreateContainer("Parse", ApplicationDataCreateDisposition.Always); - data = container.Values; - } - - public void Add(string key, object value) { - lock (mutex) { - if (ContainsKey(key)) { - throw new ArgumentException("Key already exists in dictionary.", "key"); - } - this[key] = value; - } - } - - public bool ContainsKey(string key) { - lock (mutex) { - return data.ContainsKey(key) || data.ContainsKey(key + CountSuffix); - } - } - - public ICollection Keys { - get { - lock (mutex) { - return (from k in data.Keys - where k.EndsWith(CountSuffix) || !k.Contains(Delimiter) - select k.Split(new string[] { Delimiter }, - 1, StringSplitOptions.None)[0]).ToList(); - } - } - } - - public bool Remove(string key) { - lock (mutex) { - var suffixed = key + CountSuffix; - if (data.ContainsKey(suffixed)) { - int count = (int)data[suffixed]; - data.Remove(suffixed); - var delimitedKey = key + Delimiter; - for (int i = 0; i < count; i++) { - data.Remove(delimitedKey + i); - } - return true; - } - if (data.Remove(key)) { - return true; - } - return false; - } - } - - public bool TryGetValue(string key, out object value) { - lock (mutex) { - var suffixed = key + CountSuffix; - if (data.ContainsKey(suffixed)) { - // Reassemble the sharded string. - int count = (int)data[suffixed]; - var builder = new StringBuilder(count * ShardSize); - var delimitedKey = key + Delimiter; - for (int i = 0; i < count; i++) { - object shard; - if (!data.TryGetValue(delimitedKey + i, out shard)) { - value = null; - return false; - } - builder.Append((string)shard); - } - value = builder.ToString(); - return true; - } - return data.TryGetValue(key, out value); - } - } - - public ICollection Values { - get { - lock (mutex) { - return (from k in Keys - select this[k]).ToList(); - } - } - } - - public object this[string key] { - get { - object value; - if (TryGetValue(key, out value)) { - return value; - } - throw new IndexOutOfRangeException(); - } - set { - lock (mutex) { - this.Remove(key); - // If the value is a large string (> 1k characters), split it into multiple shards. - var stringValue = value as string; - if (stringValue != null && stringValue.Length > ShardSize) { - var delimitedKey = key + Delimiter; - int count = 0; - for (int start = 0; start < stringValue.Length; start += ShardSize) { - string shard = stringValue.Substring(start, - Math.Min(ShardSize, stringValue.Length - start)); - data[delimitedKey + count] = shard; - count++; - } - data[key + CountSuffix] = count; - } else { - data[key] = value; - } - } - } - } - - public void Add(KeyValuePair item) { - this.Add(item.Key, item.Value); - } - - public void Clear() { - lock (mutex) { - data.Clear(); - } - } - - public bool Contains(KeyValuePair item) { - lock (mutex) { - return this.ContainsKey(item.Key) && this[item.Key] == item.Value; - } - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) { - this.ToList().CopyTo(array, arrayIndex); - } - - public int Count { - get { return Keys.Count; } - } - - public bool IsReadOnly { - get { return false; } - } - - public bool Remove(KeyValuePair item) { - lock (mutex) { - if (!this.Contains(item)) { - return false; - } - return this.Remove(item.Key); - } - } - - public IEnumerator> GetEnumerator() { - return (from k in this.Keys - select new KeyValuePair(k, this[k])).GetEnumerator(); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { - return this.GetEnumerator(); - } - } - public IDictionary ApplicationSettings { - get { - return SettingsWrapper.Wrapper; - } - } - } -} diff --git a/Parse/Internal/Push/Controller/ParsePushController.cs b/Parse/Internal/Push/Controller/ParsePushController.cs deleted file mode 100644 index a204f10a..00000000 --- a/Parse/Internal/Push/Controller/ParsePushController.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System; -using System.Threading.Tasks; -using System.Threading; -using System.Collections.Generic; - -namespace Parse.Internal { - internal class ParsePushController : IParsePushController { - public Task SendPushNotificationAsync(IPushState state, String sessionToken, CancellationToken cancellationToken) { - var command = new ParseCommand("push", - method: "POST", - sessionToken: sessionToken, - data: ParsePushEncoder.Instance.Encode(state)); - - return ParseClient.ParseCommandRunner.RunCommandAsync(command, cancellationToken: cancellationToken); - } - } -} diff --git a/Parse/Internal/Utilities/InternalExtensions.cs b/Parse/Internal/Utilities/InternalExtensions.cs deleted file mode 100644 index 5202d731..00000000 --- a/Parse/Internal/Utilities/InternalExtensions.cs +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Runtime.ExceptionServices; -using System.Text; -using System.Threading.Tasks; - -namespace Parse.Internal { - /// - /// Provides helper methods that allow us to use terser code elsewhere. - /// - internal static class InternalExtensions { - /// - /// Ensures a task (even null) is awaitable. - /// - /// - /// - /// - internal static Task Safe(this Task task) { - return task ?? Task.FromResult(default(T)); - } - - /// - /// Ensures a task (even null) is awaitable. - /// - /// - /// - internal static Task Safe(this Task task) { - return task ?? Task.FromResult(null); - } - - internal delegate void PartialAccessor(ref T arg); - - internal static TValue GetOrDefault(this IDictionary self, - TKey key, - TValue defaultValue) { - TValue value; - if (self.TryGetValue(key, out value)) { - return value; - } - return defaultValue; - } - - internal static bool CollectionsEqual(this IEnumerable a, IEnumerable b) { - return Object.Equals(a, b) || - (a != null && b != null && - a.SequenceEqual(b)); - } - - /// - /// Partial methods cannot return a value, so we instead make partial accessors - /// use ref params. This helper can be used to write code more normally so we get - /// the out-param or default when calling a partial method. Given a partial method: - /// partial void GetFoo(ref string foo) - /// we can say string foo = this.GetPartial<string>(GetFoo); - /// - /// - /// - /// - internal static T GetPartial(this ParseObject self, PartialAccessor action) { - return GetPartial(action); - } - - internal static T GetPartial(PartialAccessor action) { - T value = default(T); - action(ref value); - return value; - } - - /// - /// Partial methods cannot return a value, so we instead make partial accessors - /// use ref params. This means you cannot effectively make a partial which is - /// async. This code helps create a design pattern where a partial takes a ref Task - /// param and we can await the PartialAsync of it. Given a partial method: - /// partial void FooAsync(ref Task<string> task) - /// we can say string foo = await PartialAsync<string>(FooAsync); - /// - /// - /// - /// - /// - internal static Task PartialAsync(this object self, PartialAccessor> partial) { - return PartialAsync(partial); - } - - internal static Task PartialAsync(PartialAccessor> partial) { - Task task = null; - partial(ref task); - return task.Safe(); - } - - internal static Task PartialAsync(this object self, PartialAccessor partial) { - return PartialAsync(partial); - } - - internal static Task PartialAsync(PartialAccessor partial) { - Task task = null; - partial(ref task); - return task.Safe(); - } - - internal static Task OnSuccess(this Task task, - Func, TResult> continuation) { - return ((Task)task).OnSuccess(t => continuation((Task)t)); - } - - internal static Task OnSuccess(this Task task, Action> continuation) { - return task.OnSuccess((Func, object>)(t => { - continuation(t); - return null; - })); - } - - internal static Task OnSuccess(this Task task, - Func continuation) { - return task.ContinueWith(t => { - if (t.IsFaulted) { - var ex = t.Exception.Flatten(); - if (ex.InnerExceptions.Count == 1) { - ExceptionDispatchInfo.Capture(ex.InnerExceptions[0]).Throw(); - } else { - ExceptionDispatchInfo.Capture(ex).Throw(); - } - // Unreachable - return Task.FromResult(default(TResult)); - } else if (t.IsCanceled) { - var tcs = new TaskCompletionSource(); - tcs.SetCanceled(); - return tcs.Task; - } else { - return Task.FromResult(continuation(t)); - } - }).Unwrap(); - } - - internal static Task OnSuccess(this Task task, Action continuation) { - return task.OnSuccess((Func)(t => { - continuation(t); - return null; - })); - } - - internal static Task WhileAsync(Func> predicate, Func body) { - Func iterate = null; - iterate = () => { - return predicate().OnSuccess(t => { - if (!t.Result) { - return Task.FromResult(0); - } - return body().OnSuccess(_ => iterate()).Unwrap(); - }).Unwrap(); - }; - return iterate(); - } - } -} diff --git a/Parse/Properties/AssemblyInfo.Portable.cs b/Parse/Properties/AssemblyInfo.Portable.cs deleted file mode 100644 index 4dc17ccb..00000000 --- a/Parse/Properties/AssemblyInfo.Portable.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System.Runtime.CompilerServices; - -// Platform specific libraries can see Parse internals. -[assembly: InternalsVisibleTo("Parse")] - -// Internal visibility for platform-specific libraries. -[assembly: InternalsVisibleTo("Parse.WinRT")] -[assembly: InternalsVisibleTo("Parse.NetFx45")] -[assembly: InternalsVisibleTo("Parse.Phone")] - -// Internal visibility for test libraries. -[assembly: InternalsVisibleTo("ParseTest.Integration.WinRT")] -[assembly: InternalsVisibleTo("ParseTest.Integration.NetFx45")] -[assembly: InternalsVisibleTo("ParseTest.Integration.Phone")] - -[assembly: InternalsVisibleTo("ParseTest.Unit.NetFx45")] -[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] - -#if MONO -[assembly: InternalsVisibleTo("ParseTestIntegrationiOS")] -[assembly: InternalsVisibleTo("ParseTest.Integration.Android")] -#endif - -#if UNITY -[assembly: InternalsVisibleTo("ParseTest.Integration.Unity")] -#endif \ No newline at end of file diff --git a/Parse/Properties/Settings.Designer.cs b/Parse/Properties/Settings.Designer.cs deleted file mode 100644 index 11935cd0..00000000 --- a/Parse/Properties/Settings.Designer.cs +++ /dev/null @@ -1,38 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18010 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Parse.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("")] - public string ApplicationSettings { - get { - return ((string)(this["ApplicationSettings"])); - } - set { - this["ApplicationSettings"] = value; - } - } - } -} diff --git a/Parse/Properties/Settings.settings b/Parse/Properties/Settings.settings deleted file mode 100644 index 2962cdea..00000000 --- a/Parse/Properties/Settings.settings +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/Parse/Public/NetFx45/WPF/ParseFacebookUtils.NetFx45.cs b/Parse/Public/NetFx45/WPF/ParseFacebookUtils.NetFx45.cs deleted file mode 100644 index e3644d2e..00000000 --- a/Parse/Public/NetFx45/WPF/ParseFacebookUtils.NetFx45.cs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Controls; -using System.Windows.Navigation; - -namespace Parse { - public static partial class ParseFacebookUtils { - /// - /// Logs in a using Facebook for authentication. If a user for the - /// given Facebook credentials does not already exist, a new user will be created. - /// - /// The user will be logged in through Facebook's OAuth web flow, so you must supply a - /// that will be navigated to Facebook's authentication pages. - /// - /// A web view that will be used to present the authorization pages - /// to the user. - /// A list of Facebook permissions to request. - /// The cancellation token. - /// The user that was either logged in or created. - public static async Task LogInAsync(WebBrowser webView, - IEnumerable permissions, - CancellationToken cancellationToken) { - authProvider.Permissions = permissions; - LoadCompletedEventHandler loadCompleted = (_, e) => authProvider.HandleNavigation(e.Uri); - webView.LoadCompleted += loadCompleted; - Action navigate = uri => webView.Navigate(uri); - authProvider.Navigate += navigate; - var result = await ParseUser.LogInWithAsync("facebook", cancellationToken); - authProvider.Navigate -= navigate; - webView.LoadCompleted -= loadCompleted; - return result; - } - - /// - /// Links a to a Facebook account, allowing you to use Facebook - /// for authentication, and providing access to Facebook data for the user. - /// - /// The user will be logged in through Facebook's OAuth web flow, so you must supply a - /// that will be navigated to Facebook's authentication pages. - /// - /// The user to link with Facebook. - /// A web view that will be used to present the authorization pages - /// to the user. - /// A list of Facebook permissions to request. - /// The cancellation token. - public static async Task LinkAsync(ParseUser user, - WebBrowser webView, - IEnumerable permissions, - CancellationToken cancellationToken) { - authProvider.Permissions = permissions; - LoadCompletedEventHandler loadCompleted = (_, e) => authProvider.HandleNavigation(e.Uri); - webView.LoadCompleted += loadCompleted; - Action navigate = uri => webView.Navigate(uri); - authProvider.Navigate += navigate; - await user.LinkWithAsync("facebook", cancellationToken); - authProvider.Navigate -= navigate; - webView.LoadCompleted -= loadCompleted; - } - - /// - /// Logs in a using Facebook for authentication. If a user for the - /// given Facebook credentials does not already exist, a new user will be created. - /// - /// The user will be logged in through Facebook's OAuth web flow, so you must supply a - /// that will be navigated to Facebook's authentication pages. - /// - /// A web view that will be used to present the authorization pages - /// to the user. - /// A list of Facebook permissions to request. - /// The user that was either logged in or created. - public static Task LogInAsync(WebBrowser webView, IEnumerable permissions) { - return LogInAsync(webView, permissions, CancellationToken.None); - } - - /// - /// Links a to a Facebook account, allowing you to use Facebook - /// for authentication, and providing access to Facebook data for the user. - /// - /// The user will be logged in through Facebook's OAuth web flow, so you must supply a - /// that will be navigated to Facebook's authentication pages. - /// - /// The user to link with Facebook. - /// A web view that will be used to present the authorization pages - /// to the user. - /// A list of Facebook permissions to request. - public static Task LinkAsync(ParseUser user, WebBrowser webView, IEnumerable permissions) { - return LinkAsync(user, webView, permissions, CancellationToken.None); - } - } -} diff --git a/Parse/Public/Partial/ParseFacebookUtils.cs b/Parse/Public/Partial/ParseFacebookUtils.cs deleted file mode 100644 index 103655c5..00000000 --- a/Parse/Public/Partial/ParseFacebookUtils.cs +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using Parse.Internal; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Parse { - /// - /// Provides a set of utilities for using Parse with Facebook. - /// - public static partial class ParseFacebookUtils { - private static readonly FacebookAuthenticationProvider authProvider = - new FacebookAuthenticationProvider(); - -#if !UNITY - /// - /// Gets the Facebook Application ID as supplied to - /// - public static string ApplicationId { - get { - return authProvider.AppId; - } - } -#endif - - /// - /// Gets the access token for the currently logged in Facebook user. This can be used with a - /// Facebook SDK to get access to Facebook user data. - /// - public static string AccessToken { - get { - return authProvider.AccessToken; - } - } - -#if !UNITY - /// - /// Initializes Facebook for use with Parse. - /// - /// Your Facebook application ID. - public static void Initialize(string applicationId) { - authProvider.AppId = applicationId; - ParseUser.RegisterProvider(authProvider); - } -#else - /// - /// Unity will just auto-initialize this. Since we're not responsible for login, we don't - /// need the application id -- just the tokens. - /// - internal static void Initialize() { - ParseUser.RegisterProvider(authProvider); - } -#endif - - /// - /// Logs in a using Facebook for authentication. If a user for the - /// given Facebook credentials does not already exist, a new user will be created. - /// - /// The user's Facebook ID. - /// A valid access token for the user. - /// The expiration date of the access token. - /// The cancellation token. - /// The user that was either logged in or created. - public static Task LogInAsync(string facebookId, - string accessToken, - DateTime expiration, - CancellationToken cancellationToken) { - return ParseUser.LogInWithAsync("facebook", - authProvider.GetAuthData(facebookId, accessToken, expiration), - cancellationToken); - } - - /// - /// Logs in a using Facebook for authentication. If a user for the - /// given Facebook credentials does not already exist, a new user will be created. - /// - /// The user's Facebook ID. - /// A valid access token for the user. - /// The expiration date of the access token. - /// The user that was either logged in or created. - public static Task LogInAsync(string facebookId, - string accessToken, - DateTime expiration) { - return LogInAsync(facebookId, accessToken, expiration, CancellationToken.None); - } - - /// - /// Links a to a Facebook account, allowing you to use Facebook - /// for authentication, and providing access to Facebook data for the user. - /// - /// The user to link to a Facebook account. - /// The user's Facebook ID. - /// A valid access token for the user. - /// The expiration date of the access token. - /// The cancellation token. - public static Task LinkAsync(ParseUser user, - string facebookId, - string accessToken, - DateTime expiration, - CancellationToken cancellationToken) { - return user.LinkWithAsync("facebook", - authProvider.GetAuthData(facebookId, accessToken, expiration), - cancellationToken); - } - - /// - /// Links a to a Facebook account, allowing you to use Facebook - /// for authentication, and providing access to Facebook data for the user. - /// - /// The user to link to a Facebook account. - /// The user's Facebook ID. - /// A valid access token for the user. - /// The expiration date of the access token. - public static Task LinkAsync(ParseUser user, - string facebookId, - string accessToken, - DateTime expiration) { - return LinkAsync(user, facebookId, accessToken, expiration, CancellationToken.None); - } - - /// - /// Gets whether the given user is linked to a Facebook account. This can only be used on - /// the currently authorized user. - /// - /// The user to check. - /// true if the user is linked to a Facebook account. - public static bool IsLinked(ParseUser user) { - return user.IsLinked("facebook"); - } - - /// - /// Unlinks a user from a Facebook account. Unlinking a user will save the user's data. - /// - /// The user to unlink. - /// The cancellation token. - public static Task UnlinkAsync(ParseUser user, CancellationToken cancellationToken) { - return user.UnlinkFromAsync("facebook", cancellationToken); - } - - /// - /// Unlinks a user from a Facebook account. Unlinking a user will save the user's data. - /// - /// The user to unlink. - public static Task UnlinkAsync(ParseUser user) { - return UnlinkAsync(user, CancellationToken.None); - } - } -} diff --git a/Parse/Public/Phone/ParseFacebookUtils.Phone.cs b/Parse/Public/Phone/ParseFacebookUtils.Phone.cs deleted file mode 100644 index be828926..00000000 --- a/Parse/Public/Phone/ParseFacebookUtils.Phone.cs +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using Microsoft.Phone.Controls; -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Navigation; -using System.Xml.Linq; -using System.Linq; -using Parse.Internal; -using Windows.System; -using System.Windows.Controls; - -namespace Parse { - public static partial class ParseFacebookUtils { - - /// - /// Fetches the app's ProductID from its manifest. - /// - private static string GetProductId() { - return (from manifest in XElement.Load("WMAppManifest.xml") - .Descendants("App") - select manifest).SingleOrDefault().Attribute("ProductID").Value.Trim('{', '}'); - } - - private static string nativeLoginAppPrefix; - private static string NativeLoginAppPrefix { - get { - return nativeLoginAppPrefix = nativeLoginAppPrefix ?? - string.Format("msft-{0}://authorize/", GetProductId().Replace("-", "")); - } - } - - private static Uri NativeLoginDialogUrl { - get { - return new Uri("fbconnect://authorize"); - } - } - - private static Uri NativeResponseUrl { - get { - return new Uri(NativeLoginAppPrefix); - } - } - - /// - /// Checks whether the Uri passed into your application comes from the Facebook - /// app as a result of a completed login attempt. - /// - /// Your code will usually look like this: - /// - /// RootFrame.Navigating += async (sender, e) => { - /// if (ParseFacebookUtils.IsLoginRedirect(e.Uri)) { - /// ParseUser user = await ParseFacebookUtils.EndLoginAsync( - /// sender, e, new Uri("/LandingPage.xaml", UriKind.Relative)); - /// // A new user is now logged in. - /// } - /// }; - /// - /// - /// - /// true iff the Uri is a Facebook login redirect, false - /// otherwise - public static bool IsLogInRedirect(Uri uri) { - if (uri.ToString().StartsWith("/Protocol?")) { - if (!uri.IsAbsoluteUri) { - uri = new Uri(new Uri("dummy:///"), uri); - } - var queryString = ParseClient.DecodeQueryString(uri.Query.Substring(1)); - var launchUri = new Uri(Uri.UnescapeDataString(queryString["encodedLaunchUri"])); - if (launchUri.IsAbsoluteUri && - launchUri.AbsoluteUri.StartsWith(NativeLoginAppPrefix)) { - return true; - } - } - return false; - } - - /// - /// Call this method within your RootFrame.Navigating event handler to complete native Facebook - /// sign-on. When handling a Facebook login redirect URI, this method will cancel the - /// pending navigation, begin asynchronously logging in the user, and immediately navigate - /// to the . - /// - /// Your code will usually look like this: - /// - /// RootFrame.Navigating += async (sender, e) => { - /// if (ParseFacebookUtils.IsLoginRedirect(e.Uri)) { - /// ParseUser user = await ParseFacebookUtils.EndLoginAsync( - /// sender, e, new Uri("/LandingPage.xaml", UriKind.Relative)); - /// // A new user is now logged in. - /// } - /// }; - /// - /// - /// The sender for the Navigating event. - /// The Navigating event args. - /// The Uri within your app to redirect to. - /// The ParseUser created or logged in using Facebook credentials, or null if - /// this was not a Facebook login redirect. - public async static Task EndLogInAsync(object sender, - NavigatingCancelEventArgs e, - Uri redirectUri) { - if (!IsLogInRedirect(e.Uri)) { - return null; - } - authProvider.ResponseUrlOverride = NativeResponseUrl; - Action navigate = (_) => { }; - authProvider.Navigate += navigate; - try { - var cts = new CancellationTokenSource(); - // Kicks off a dummy to restart authentication. - var result = ParseUser.LogInWithAsync("facebook", cts.Token); - // Complete the authentication. - var uri = new Uri(new Uri("dummy:///"), e.Uri); - var queryString = ParseClient.DecodeQueryString(uri.Query.Substring(1)); - var launchUri = new Uri(Uri.UnescapeDataString(queryString["encodedLaunchUri"])); - if (!authProvider.HandleNavigation(launchUri)) { - // Cancel the pending attempt to log in if for some reason this wasn't actually - // a facebook login navigation (unlikely at this point) - cts.Cancel(); - } - - // Cancel navigation and redirect to the new Uri. - e.Cancel = true; - var navService = sender as NavigationService; - if (navService == null) { - throw new ArgumentException("sender must be a NavigationService", "sender"); - } - // Welcome to Windows Phone... sometimes you just have to dispatch for no - // particularly good reason. - Deployment.Current.Dispatcher.BeginInvoke(() => navService.Navigate(redirectUri)); - return await result; - } finally { - authProvider.Navigate -= navigate; - authProvider.ResponseUrlOverride = null; - } - } - - /// - /// Logs in a using Facebook for authentication. If a user for the - /// given Facebook credentials does not already exist, a new user will be created. - /// - /// The user will be logged in through the Facebook app's single sign-on mechanism. - /// - /// You must add a handler to your RootFrame's Navigating event that calls EndLogInAsync so - /// that ParseFacebookUtils can handle incoming navigation attempts. - /// = - /// A list of Facebook permissions to request. - public static void BeginLogIn(IEnumerable permissions) { - authProvider.Permissions = permissions; - authProvider.LoginDialogUrlOverride = NativeLoginDialogUrl; - authProvider.ResponseUrlOverride = NativeResponseUrl; - Action navigate = async (uri) => await Launcher.LaunchUriAsync(uri); - authProvider.Navigate += navigate; - try { - // Kicks off the authentication. This will probably kill the process. - var _ = authProvider.AuthenticateAsync(CancellationToken.None); - } finally { - authProvider.Navigate -= navigate; - authProvider.LoginDialogUrlOverride = null; - authProvider.ResponseUrlOverride = null; - } - } - - /// - /// Logs in a using Facebook for authentication. If a user for the - /// given Facebook credentials does not already exist, a new user will be created. - /// - /// The user will be logged in through Facebook's OAuth web flow, so you must supply a - /// that will be navigated to Facebook's authentication pages. - /// - /// A web view that will be used to present the authorization pages - /// to the user. - /// A list of Facebook permissions to request. - /// The cancellation token. - /// The user that was either logged in or created. - public static async Task LogInAsync(WebBrowser webView, - IEnumerable permissions, - CancellationToken cancellationToken) { - authProvider.Permissions = permissions; - LoadCompletedEventHandler loadCompleted = (_, e) => authProvider.HandleNavigation(e.Uri); - webView.LoadCompleted += loadCompleted; - Action navigate = uri => webView.Navigate(uri); - authProvider.Navigate += navigate; - var result = await ParseUser.LogInWithAsync("facebook", cancellationToken); - authProvider.Navigate -= navigate; - webView.LoadCompleted -= loadCompleted; - return result; - } - - /// - /// Links a to a Facebook account, allowing you to use Facebook - /// for authentication, and providing access to Facebook data for the user. - /// - /// The user will be logged in through Facebook's OAuth web flow, so you must supply a - /// that will be navigated to Facebook's authentication pages. - /// - /// The user to link with Facebook. - /// A web view that will be used to present the authorization pages - /// to the user. - /// A list of Facebook permissions to request. - /// The cancellation token. - public static async Task LinkAsync(ParseUser user, - WebBrowser webView, - IEnumerable permissions, - CancellationToken cancellationToken) { - authProvider.Permissions = permissions; - LoadCompletedEventHandler loadCompleted = (_, e) => authProvider.HandleNavigation(e.Uri); - webView.LoadCompleted += loadCompleted; - Action navigate = uri => webView.Navigate(uri); - authProvider.Navigate += navigate; - await user.LinkWithAsync("facebook", cancellationToken); - authProvider.Navigate -= navigate; - webView.LoadCompleted -= loadCompleted; - } - - /// - /// Logs in a using Facebook for authentication . If a user for the - /// given Facebook credentials does not already exist, a new user will be created. - /// - /// The user will be logged in through Facebook's OAuth web flow, so you must supply a - /// that will be navigated to Facebook's authentication pages. - /// - /// A web view that will be used to present the authorization pages - /// to the user. - /// A list of Facebook permissions to request. - /// The user that was either logged in or created. - public static Task LogInAsync(WebBrowser webView, IEnumerable permissions) { - return LogInAsync(webView, permissions, CancellationToken.None); - } - - /// - /// Links a to a Facebook account, allowing you to use Facebook - /// for authentication, and providing access to Facebook data for the user. - /// - /// The user will be logged in through Facebook's OAuth web flow, so you must supply a - /// that will be navigated to Facebook's authentication pages. - /// - /// The user to link with Facebook. - /// A web view that will be used to present the authorization pages - /// to the user. - /// A list of Facebook permissions to request. - public static Task LinkAsync(ParseUser user, WebBrowser webView, IEnumerable permissions) { - return LinkAsync(user, webView, permissions, CancellationToken.None); - } - } -} diff --git a/Parse/Public/Unity/ParseInitializeBehaviour.cs b/Parse/Public/Unity/ParseInitializeBehaviour.cs deleted file mode 100644 index 60ccebc7..00000000 --- a/Parse/Public/Unity/ParseInitializeBehaviour.cs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; - -namespace Parse { - /// - /// Mandatory MonoBehaviour for scenes that use Parse. Set the application ID and .NET key - /// in the editor. - /// - // TODO (hallucinogen): somehow because of Push, we need this class to be added in a GameObject - // called `ParseInitializeBehaviour`. We might want to fix this. - public class ParseInitializeBehaviour : MonoBehaviour { - private static bool isInitialized = false; - - /// - /// The Parse applicationId used in this app. You can get this value from the Parse website. - /// - [SerializeField] - public string applicationID; - - /// - /// The Parse dotnetKey used in this app. You can get this value from the Parse website. - /// - [SerializeField] - public string dotnetKey; - - /// - /// Initializes the Parse SDK and begins running network requests created by Parse. - /// - public virtual void Awake() { - Initialize(); - // Force the name to be `ParseInitializeBehaviour` in runtime. - gameObject.name = "ParseInitializeBehaviour"; - - if (PlatformHooks.IsIOS) { - PlatformHooks.RegisterDeviceTokenRequest((deviceToken) => { - if (deviceToken != null) { - ParseInstallation installation = ParseInstallation.CurrentInstallation; - installation.SetDeviceTokenFromData(deviceToken); - - // Optimistically assume this will finish. - installation.SaveAsync(); - } - }); - } - } - - /// - /// Delegate function that will be called when the player pauses the game. - /// - /// - /// true if the application is paused. - public void OnApplicationPause(bool paused) { - if (PlatformHooks.IsAndroid) { - PlatformHooks.CallStaticJavaUnityMethod("com.parse.ParsePushUnityHelper", "setApplicationPaused", new object[] { paused }); - } - } - - private void Initialize() { - if (!isInitialized) { - isInitialized = true; - // Keep this gameObject around, even when the scene changes. - GameObject.DontDestroyOnLoad(gameObject); - - ParseClient.Initialize(applicationID, dotnetKey); - - // Kick off the dispatcher. - StartCoroutine(PlatformHooks.RunDispatcher()); - } - } - - #region Android Callbacks - - /// - /// The callback that will be called from the Android Java land via UnityPlayer.UnitySendMessage(string) - /// when the device receive a push notification. - /// - /// the push payload as string - internal void OnPushNotificationReceived(string pushPayloadString) { - Initialize(); - - ParsePush.parsePushNotificationReceived.Invoke(ParseInstallation.CurrentInstallation, new ParsePushNotificationEventArgs(pushPayloadString)); - } - - /// - /// The callback that will be called from the Android Java land via UnityPlayer.UnitySendMessage(string) - /// when the device receive a GCM registration id. - /// - /// the GCM registration id - internal void OnGcmRegistrationReceived(string registrationId) { - Initialize(); - - var installation = ParseInstallation.CurrentInstallation; - installation.DeviceToken = registrationId; - // Set `pushType` via internal `Set` method since we want to skip mutability check. - installation.Set("pushType", "gcm"); - - // We can't really wait for this or else we'll block the thread. - // We can only hope this operation will finish. - installation.SaveAsync(); - } - - #endregion - } -} diff --git a/Parse/Public/WinRT/ParseFacebookUtils.WinRT.cs b/Parse/Public/WinRT/ParseFacebookUtils.WinRT.cs deleted file mode 100644 index 56611402..00000000 --- a/Parse/Public/WinRT/ParseFacebookUtils.WinRT.cs +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using Parse.Internal; -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Windows.Security.Authentication.Web; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Navigation; - -namespace Parse { - public static partial class ParseFacebookUtils { - /// - /// Logs in a using Facebook for authentication. If a user for the - /// given Facebook credentials does not already exist, a new user will be created. - /// - /// The user will be logged in through Facebook's OAuth web flow using the Windows - /// WebAuthenticationBroker. - /// - /// A list of Facebook permissions to request. - /// The cancellation token. - /// The user that was either logged in or created. - public static async Task LogInAsync(IEnumerable permissions, - CancellationToken cancellationToken) { - var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - authProvider.Permissions = permissions; - authProvider.ResponseUrlOverride = WebAuthenticationBroker.GetCurrentApplicationCallbackUri(); - Action navigate = async uri => { - var result = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, - uri); - if (result.ResponseStatus != WebAuthenticationStatus.Success) { - cts.Cancel(); - } else { - authProvider.HandleNavigation(new Uri(result.ResponseData)); - } - }; - authProvider.Navigate += navigate; - try { - return await ParseUser.LogInWithAsync("facebook", cts.Token); - } finally { - authProvider.Navigate -= navigate; - authProvider.ResponseUrlOverride = null; - } - } - - /// - /// Links a to a Facebook account, allowing you to use Facebook - /// for authentication, and providing access to Facebook data for the user. - /// - /// The user will be logged in through Facebook's OAuth web flow using the Windows - /// WebAuthenticationBroker. - /// - /// The user to link with Facebook. - /// A list of Facebook permissions to request. - /// The cancellation token. - public static async Task LinkAsync(ParseUser user, - IEnumerable permissions, - CancellationToken cancellationToken) { - var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - authProvider.Permissions = permissions; - Action navigate = async uri => { - var result = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, - uri, - FacebookAuthenticationProvider.ResponseUrl); - if (result.ResponseStatus != WebAuthenticationStatus.Success) { - cts.Cancel(); - } else { - authProvider.HandleNavigation(new Uri(result.ResponseData)); - } - }; - authProvider.Navigate += navigate; - try { - await user.LinkWithAsync("facebook", cts.Token); - } finally { - authProvider.Navigate -= navigate; - } - } - - /// - /// Logs in a using Facebook for authentication. If a user for the - /// given Facebook credentials does not already exist, a new user will be created. - /// - /// The user will be logged in through Facebook's OAuth web flow using the Windows - /// WebAuthenticationBroker. - /// - /// A list of Facebook permissions to request. - /// The user that was either logged in or created. - public static Task LogInAsync(IEnumerable permissions) { - return LogInAsync(permissions, CancellationToken.None); - } - - /// - /// Links a to a Facebook account, allowing you to use Facebook - /// for authentication, and providing access to Facebook data for the user. - /// - /// The user will be logged in through Facebook's OAuth web flow using the Windows - /// WebAuthenticationBroker. - /// - /// The user to link with Facebook. - /// A list of Facebook permissions to request. - public static Task LinkAsync(ParseUser user, - IEnumerable permissions) { - return LinkAsync(user, permissions, CancellationToken.None); - } - - /// - /// Logs in a using Facebook for authentication. If a user for the - /// given Facebook credentials does not already exist, a new user will be created. - /// - /// The user will be logged in through Facebook's OAuth web flow, so you must supply a - /// that will be navigated to Facebook's authentication pages. - /// - /// A web view that will be used to present the authorization pages - /// to the user. - /// A list of Facebook permissions to request. - /// The cancellation token. - /// The user that was either logged in or created. - public static async Task LogInAsync(WebView webView, - IEnumerable permissions, - CancellationToken cancellationToken) { - authProvider.Permissions = permissions; - LoadCompletedEventHandler loadCompleted = (_, e) => authProvider.HandleNavigation(e.Uri); - webView.LoadCompleted += loadCompleted; - Action navigate = uri => webView.Navigate(uri); - authProvider.Navigate += navigate; - var result = await ParseUser.LogInWithAsync("facebook", cancellationToken); - authProvider.Navigate -= navigate; - webView.LoadCompleted -= loadCompleted; - return result; - } - - /// - /// Links a to a Facebook account, allowing you to use Facebook - /// for authentication, and providing access to Facebook data for the user. - /// - /// The user will be logged in through Facebook's OAuth web flow, so you must supply a - /// that will be navigated to Facebook's authentication pages. - /// - /// The user to link with Facebook. - /// A web view that will be used to present the authorization pages - /// to the user. - /// A list of Facebook permissions to request. - /// The cancellation token. - public static async Task LinkAsync(ParseUser user, - WebView webView, - IEnumerable permissions, - CancellationToken cancellationToken) { - authProvider.Permissions = permissions; - LoadCompletedEventHandler loadCompleted = (_, e) => authProvider.HandleNavigation(e.Uri); - webView.LoadCompleted += loadCompleted; - Action navigate = uri => webView.Navigate(uri); - authProvider.Navigate += navigate; - await user.LinkWithAsync("facebook", cancellationToken); - authProvider.Navigate -= navigate; - webView.LoadCompleted -= loadCompleted; - } - - /// - /// Logs in a using Facebook for authentication. If a user for the - /// given Facebook credentials does not already exist, a new user will be created. - /// - /// The user will be logged in through Facebook's OAuth web flow, so you must supply a - /// that will be navigated to Facebook's authentication pages. - /// - /// A web view that will be used to present the authorization pages - /// to the user. - /// A list of Facebook permissions to request. - /// The user that was either logged in or created. - public static Task LogInAsync(WebView webView, IEnumerable permissions) { - return LogInAsync(webView, permissions, CancellationToken.None); - } - - /// - /// Links a to a Facebook account, allowing you to use Facebook - /// for authentication, and providing access to Facebook data for the user. - /// - /// The user will be logged in through Facebook's OAuth web flow, so you must supply a - /// that will be navigated to Facebook's authentication pages. - /// - /// The user to link with Facebook. - /// A web view that will be used to present the authorization pages - /// to the user. - /// A list of Facebook permissions to request. - public static Task LinkAsync(ParseUser user, WebView webView, IEnumerable permissions) { - return LinkAsync(user, webView, permissions, CancellationToken.None); - } - } -} diff --git a/Parse/Internal/Analytics/Controller/IParseAnalyticsController.cs b/ParseAnalytics/Internal/Analytics/Controller/IParseAnalyticsController.cs similarity index 88% rename from Parse/Internal/Analytics/Controller/IParseAnalyticsController.cs rename to ParseAnalytics/Internal/Analytics/Controller/IParseAnalyticsController.cs index 665c4da7..8ef2d841 100644 --- a/Parse/Internal/Analytics/Controller/IParseAnalyticsController.cs +++ b/ParseAnalytics/Internal/Analytics/Controller/IParseAnalyticsController.cs @@ -3,8 +3,9 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -namespace Parse.Internal { - interface IParseAnalyticsController { + +namespace Parse.Analytics.Internal { + public interface IParseAnalyticsController { Task TrackEventAsync(string name, IDictionary dimensions, string sessionToken, diff --git a/Parse/Internal/Analytics/Controller/ParseAnalyticsController.cs b/ParseAnalytics/Internal/Analytics/Controller/ParseAnalyticsController.cs similarity index 89% rename from Parse/Internal/Analytics/Controller/ParseAnalyticsController.cs rename to ParseAnalytics/Internal/Analytics/Controller/ParseAnalyticsController.cs index 326c287f..87808e4b 100644 --- a/Parse/Internal/Analytics/Controller/ParseAnalyticsController.cs +++ b/ParseAnalytics/Internal/Analytics/Controller/ParseAnalyticsController.cs @@ -4,11 +4,13 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -namespace Parse.Internal { - internal class ParseAnalyticsController : IParseAnalyticsController { +using Parse.Core.Internal; + +namespace Parse.Analytics.Internal { + public class ParseAnalyticsController : IParseAnalyticsController { private readonly IParseCommandRunner commandRunner; - internal ParseAnalyticsController(IParseCommandRunner commandRunner) { + public ParseAnalyticsController(IParseCommandRunner commandRunner) { this.commandRunner = commandRunner; } diff --git a/Parse/Properties/SharedAssemblyInfo.cs b/ParseAnalytics/Internal/IParseAnalyticsPlugins.cs similarity index 53% rename from Parse/Properties/SharedAssemblyInfo.cs rename to ParseAnalytics/Internal/IParseAnalyticsPlugins.cs index 80afce20..d2b8dc9c 100644 --- a/Parse/Properties/SharedAssemblyInfo.cs +++ b/ParseAnalytics/Internal/IParseAnalyticsPlugins.cs @@ -1,6 +1,13 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. -using System.Reflection; -// Generated Parse version attributes -[assembly: AssemblyVersion("1.7.0.0")] -[assembly: AssemblyFileVersion("1.7.0.0")] +using Parse.Core.Internal; +using System; + +namespace Parse.Analytics.Internal { + public interface IParseAnalyticsPlugins { + void Reset(); + + IParseCorePlugins CorePlugins { get; } + IParseAnalyticsController AnalyticsController { get; } + } +} \ No newline at end of file diff --git a/ParseAnalytics/Internal/ParseAnalyticsPlugins.cs b/ParseAnalytics/Internal/ParseAnalyticsPlugins.cs new file mode 100644 index 00000000..de564e94 --- /dev/null +++ b/ParseAnalytics/Internal/ParseAnalyticsPlugins.cs @@ -0,0 +1,64 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using Parse.Core.Internal; + +namespace Parse.Analytics.Internal { + public class ParseAnalyticsPlugins : IParseAnalyticsPlugins { + private static readonly object instanceMutex = new object(); + private static IParseAnalyticsPlugins instance; + public static IParseAnalyticsPlugins Instance { + get { + lock (instanceMutex) { + instance = instance ?? new ParseAnalyticsPlugins(); + return instance; + } + } + set { + lock (instanceMutex) { + instance = value; + } + } + } + + private readonly object mutex = new object(); + + private IParseCorePlugins corePlugins; + private IParseAnalyticsController analyticsController; + + public void Reset() { + lock (mutex) { + CorePlugins = null; + AnalyticsController = null; + } + } + + public IParseCorePlugins CorePlugins { + get { + lock (mutex) { + corePlugins = corePlugins ?? ParseCorePlugins.Instance; + return corePlugins; + } + } + set { + lock (mutex) { + corePlugins = value; + } + } + } + + public IParseAnalyticsController AnalyticsController { + get { + lock (mutex) { + analyticsController = analyticsController ?? new ParseAnalyticsController(CorePlugins.CommandRunner); + return analyticsController; + } + } + set { + lock (mutex) { + analyticsController = value; + } + } + } + } +} \ No newline at end of file diff --git a/Parse/Parse.Phone.csproj b/ParseAnalytics/ParseAnalytics.Phone.csproj similarity index 86% rename from Parse/Parse.Phone.csproj rename to ParseAnalytics/ParseAnalytics.Phone.csproj index 522a3669..89d1ebf9 100644 --- a/Parse/Parse.Phone.csproj +++ b/ParseAnalytics/ParseAnalytics.Phone.csproj @@ -9,8 +9,8 @@ {C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} Library Properties - Parse - Parse.Phone + Parse.Analytics + Parse.Analytics WindowsPhone v8.0 $(TargetFrameworkVersion) @@ -86,20 +86,21 @@ prompt 4 + + + **\WinRT\**; + + - - - - - - - - + + + + - - {DE07A443-9619-4BD7-B540-41296F8A2959} - Parse + + {de07a443-9619-4bd7-b540-41296f8a2959} + ParseCommon.Portable @@ -109,11 +110,11 @@ - - + \ No newline at end of file diff --git a/ParseAnalytics/ParseAnalytics.Portable.csproj b/ParseAnalytics/ParseAnalytics.Portable.csproj new file mode 100644 index 00000000..6fbf4d68 --- /dev/null +++ b/ParseAnalytics/ParseAnalytics.Portable.csproj @@ -0,0 +1,75 @@ + + + + + 11.0 + Debug + AnyCPU + {43AC01E1-AEB2-474D-856B-E81F27EF640B} + Library + Properties + Parse.Analytics + Parse.Analytics + v4.5 + Profile78 + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\ + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AnyCPU + bin\Debug\Parse.Analytics.xml + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\Parse.Analytics.xml + + + + + **\Phone\**; + **\WinRT\**; + + + + + + + + + + + {de07a443-9619-4bd7-b540-41296f8a2959} + ParseCommon.Portable + + + {f3f65351-2ce1-4412-84b4-c36f34eab928} + ParseCore.Portable + + + + false + + + + + \ No newline at end of file diff --git a/ParseAnalytics/ParseAnalytics.Unity.csproj b/ParseAnalytics/ParseAnalytics.Unity.csproj new file mode 100644 index 00000000..fd185ae7 --- /dev/null +++ b/ParseAnalytics/ParseAnalytics.Unity.csproj @@ -0,0 +1,90 @@ + + + + + Debug + AnyCPU + {82CB2095-581A-45B5-AB4C-46BB162C29D5} + Library + Properties + Parse.Analytics + Parse.Analytics + v3.5 + 512 + + + ..\ + true + 10.0.0 + 2.0 + + + true + full + false + bin\Debug\Unity\ + TRACE;DEBUG;UNITY + prompt + 4 + 5 + + + pdbonly + true + bin\Release\Unity\ + TRACE;UNITY + prompt + 4 + 5 + bin\Release\Unity\Parse.Common.xml + + + + + + False + ..\UnityEngine.dll + False + + + + + + **\Phone\**; + **\WinRT\**; + + + + + + + + + + + + + + {196457aa-9ba0-40bc-91a3-21baad6f4169} + ParseCommon.Unity + + + {27d3f5e9-ca66-426b-be69-9b6158071a35} + ParseCore.Unity + + + {8473bef6-7086-4414-aad6-264967a7fe75} + Unity.Compat + + + {ce75c800-a97f-4464-9a8b-3f65258456bf} + Unity.Tasks + + + \ No newline at end of file diff --git a/Parse/Parse.WinRT.csproj b/ParseAnalytics/ParseAnalytics.WinRT.csproj similarity index 86% rename from Parse/Parse.WinRT.csproj rename to ParseAnalytics/ParseAnalytics.WinRT.csproj index 1bfe5dbd..0d57286a 100644 --- a/Parse/Parse.WinRT.csproj +++ b/ParseAnalytics/ParseAnalytics.WinRT.csproj @@ -9,8 +9,8 @@ {858FC395-3213-446E-BD09-72DBB11FE11C} Library Properties - Parse - Parse.WinRT + Parse.Analytics + Parse.Analytics en-US 512 {BC8A1FFA-BEE3-4634-8014-F334798102B3};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} @@ -25,7 +25,7 @@ DEBUG;TRACE;NETFX_CORE prompt 4 - bin\Debug\WinRT\Parse.WinRT.xml + bin\Debug\WinRT\Parse.Analytics.xml pdbonly @@ -34,7 +34,7 @@ TRACE;NETFX_CORE prompt 4 - bin\Release\WinRT\Parse.WinRT.xml + bin\Release\WinRT\Parse.Analytics.xml true @@ -102,20 +102,21 @@ prompt true + + + **\Phone\**; + + - - - - - - - - + + + + - + {de07a443-9619-4bd7-b540-41296f8a2959} - Parse + ParseCommon.Portable @@ -129,11 +130,11 @@ - - + \ No newline at end of file diff --git a/ParseAnalytics/Properties/AssemblyInfo.cs b/ParseAnalytics/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..cd8ac4a6 --- /dev/null +++ b/ParseAnalytics/Properties/AssemblyInfo.cs @@ -0,0 +1,21 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using Parse.Analytics.Internal; +using Parse.Common.Internal; +using System; +using System.Reflection; +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("Parse")] +[assembly: AssemblyDescription("Makes accessing services from Parse native and straightforward.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Parse")] +[assembly: AssemblyCopyright("Copyright © Parse 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(true)] diff --git a/Parse/Public/Partial/ParseAnalytics.cs b/ParseAnalytics/Public/ParseAnalytics.cs similarity index 82% rename from Parse/Public/Partial/ParseAnalytics.cs rename to ParseAnalytics/Public/ParseAnalytics.cs index 6a8b7639..fae63910 100644 --- a/Parse/Public/Partial/ParseAnalytics.cs +++ b/ParseAnalytics/Public/ParseAnalytics.cs @@ -2,21 +2,29 @@ using System; using System.Collections.Generic; -using Parse.Internal; using System.Threading.Tasks; using System.Threading; +using Parse.Common.Internal; +using Parse.Analytics.Internal; +using Parse.Core.Internal; namespace Parse { /// /// Provides an interface to Parse's logging and analytics backend. - /// + /// /// Methods will return immediately and cache requests (along with timestamps) - /// to be handled in the background. + /// to be handled in the background. /// public partial class ParseAnalytics { internal static IParseAnalyticsController AnalyticsController { get { - return ParseCorePlugins.Instance.AnalyticsController; + return ParseAnalyticsPlugins.Instance.AnalyticsController; + } + } + + internal static IParseCurrentUserController CurrentUserController { + get { + return ParseAnalyticsPlugins.Instance.CorePlugins.CurrentUserController; } } @@ -87,10 +95,13 @@ public static Task TrackEventAsync(string name, IDictionary dime throw new ArgumentException("A name for the custom event must be provided."); } - return AnalyticsController.TrackEventAsync(name, + return CurrentUserController.GetCurrentSessionTokenAsync(CancellationToken.None) + .OnSuccess(t => { + return AnalyticsController.TrackEventAsync(name, dimensions, - ParseUser.CurrentSessionToken, + t.Result, CancellationToken.None); + }).Unwrap(); } /// @@ -101,9 +112,12 @@ public static Task TrackEventAsync(string name, IDictionary dime /// passed down from the server. /// An Async Task that can be waited on or ignored. private static Task TrackAppOpenedWithPushHashAsync(string pushHash = null) { - return AnalyticsController.TrackAppOpenedAsync(pushHash, - ParseUser.CurrentSessionToken, - CancellationToken.None); + return CurrentUserController.GetCurrentSessionTokenAsync(CancellationToken.None) + .OnSuccess(t => { + return AnalyticsController.TrackAppOpenedAsync(pushHash, + t.Result, + CancellationToken.None); + }).Unwrap(); } } } diff --git a/Parse/Public/Phone/ParseAnalytics.Phone.cs b/ParseAnalytics/Public/Phone/ParseAnalytics.Phone.cs similarity index 71% rename from Parse/Public/Phone/ParseAnalytics.Phone.cs rename to ParseAnalytics/Public/Phone/ParseAnalytics.Phone.cs index 4e47e95d..bf0a3f3b 100644 --- a/Parse/Public/Phone/ParseAnalytics.Phone.cs +++ b/ParseAnalytics/Public/Phone/ParseAnalytics.Phone.cs @@ -1,9 +1,11 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. using Microsoft.Phone.Controls; +using Parse.Common.Internal; using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Text; using System.Threading.Tasks; using System.Windows; @@ -14,9 +16,9 @@ public partial class ParseAnalytics { /// This method adds event listeners to track app opens from tiles, the app list, /// and push notifications. Windows Phone 8 developers should use TrackAppOpens instead of /// TrackAppOpenedAsync, which this method will call automatically. - /// + /// /// This method can be called in Application_Launching or as follows in the Application constructor: - /// + /// /// /// this.Startup += (sender, args) => { /// ParseAnalytics.TrackAppOpens(RootFrame); @@ -38,12 +40,29 @@ public static void TrackAppOpens(PhoneApplicationFrame frame) { if (args.NavigationMode != System.Windows.Navigation.NavigationMode.New) { return; } - var json = ParsePush.PushJson(args.Uri.ToString()); + var json = PushJson(args.Uri.ToString()); object hash = null; if (json.TryGetValue("push_hash", out hash) || alwaysReport) { await TrackAppOpenedWithPushHashAsync((string)hash); } }; } + + + /// + /// Extract the JSON dictionary used to send this push. + /// + /// The args parameter passed to a push received event. + private static IDictionary PushJson(string uri) { + var queryTokens = uri.Substring(uri.LastIndexOf('?') + 1).Split('&'); + foreach (var token in queryTokens) { + if (token.StartsWith("pushJson=")) { + var rawValue = token.Substring("pushJson=".Length); + var decoded = HttpUtility.UrlDecode(rawValue); + return Json.Parse(decoded) as IDictionary; + } + } + return new Dictionary(); + } } } diff --git a/Parse/Public/WinRT/ParseAnalytics.WinRT.cs b/ParseAnalytics/Public/WinRT/ParseAnalytics.WinRT.cs similarity index 59% rename from Parse/Public/WinRT/ParseAnalytics.WinRT.cs rename to ParseAnalytics/Public/WinRT/ParseAnalytics.WinRT.cs index 563997bf..d9a1fc3e 100644 --- a/Parse/Public/WinRT/ParseAnalytics.WinRT.cs +++ b/ParseAnalytics/Public/WinRT/ParseAnalytics.WinRT.cs @@ -1,5 +1,6 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. +using Parse.Common.Internal; using System; using System.Collections.Generic; using System.IO; @@ -10,8 +11,6 @@ using System.Threading.Tasks; using Windows.ApplicationModel.Activation; -using Parse.Internal; - namespace Parse { public static partial class ParseAnalytics { /// @@ -32,9 +31,33 @@ public static Task TrackAppOpenedAsync(ILaunchActivatedEventArgs launchArgs) { } object pushHash; - IDictionary contentJson = ParsePush.PushJson(launchArgs); + IDictionary contentJson = PushJson(launchArgs); contentJson.TryGetValue("push_hash", out pushHash); return ParseAnalytics.TrackAppOpenedWithPushHashAsync((string)pushHash); } + + /// + /// Helper method to extract the full Push JSON provided to Parse, including any + /// non-visual custom information. Overloads exist for all data types which may be + /// provided by Windows, I.E. LaunchActivatedEventArgs and PushNotificationReceivedEventArgs. + /// Returns an empty dictionary if this push type cannot include non-visual data or + /// this event was not triggered by a push. + /// + private static IDictionary PushJson(ILaunchActivatedEventArgs eventArgs) { + if (eventArgs == null || + eventArgs.Kind != ActivationKind.Launch || + eventArgs.Arguments == null) { + return new Dictionary(); + } + return PushJson(eventArgs.Arguments); + } + + private static IDictionary PushJson(string jsonString) { + try { + return Json.Parse(jsonString) as IDictionary ?? new Dictionary(); + } catch (Exception) { + return new Dictionary(); + } + } } } diff --git a/ParseTest.Unit/AnalyticsControllerTests.cs b/ParseAnalytics/Test/AnalyticsControllerTests.cs similarity index 95% rename from ParseTest.Unit/AnalyticsControllerTests.cs rename to ParseAnalytics/Test/AnalyticsControllerTests.cs index d0648868..22c3f820 100644 --- a/ParseTest.Unit/AnalyticsControllerTests.cs +++ b/ParseAnalytics/Test/AnalyticsControllerTests.cs @@ -1,13 +1,18 @@ using Moq; using NUnit.Framework; using Parse; -using Parse.Internal; +using Parse.Analytics.Internal; +using Parse.Core.Internal; +using Parse.Common.Internal; using System; using System.Collections.Generic; using System.Net; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using System.Reflection; +using System.Linq; +using AssemblyLister; namespace ParseTest { [TestFixture] diff --git a/ParseTest.Unit/AnalyticsTests.cs b/ParseAnalytics/Test/AnalyticsTests.cs similarity index 55% rename from ParseTest.Unit/AnalyticsTests.cs rename to ParseAnalytics/Test/AnalyticsTests.cs index 5e57341f..410b29f8 100644 --- a/ParseTest.Unit/AnalyticsTests.cs +++ b/ParseAnalytics/Test/AnalyticsTests.cs @@ -1,7 +1,8 @@ using Moq; using NUnit.Framework; using Parse; -using Parse.Internal; +using Parse.Analytics.Internal; +using Parse.Core.Internal; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; @@ -13,17 +14,28 @@ namespace ParseTest { public class AnalyticsTests { [TearDown] public void TearDown() { - ParseCorePlugins.Instance.AnalyticsController = null; - ParseCorePlugins.Instance.CurrentUserController = null; + ParseAnalyticsPlugins.Instance.Reset(); } [Test] [AsyncStateMachine(typeof(AnalyticsTests))] public Task TestTrackEvent() { var mockController = new Mock(); + var mockCorePlugins = new Mock(); var mockCurrentUserController = new Mock(); - ParseCorePlugins.Instance.AnalyticsController = mockController.Object; - ParseCorePlugins.Instance.CurrentUserController = mockCurrentUserController.Object; + + mockCorePlugins + .Setup(corePlugins => corePlugins.CurrentUserController) + .Returns(mockCurrentUserController.Object); + + mockCurrentUserController + .Setup(controller => controller.GetCurrentSessionTokenAsync(It.IsAny())) + .Returns(Task.FromResult("sessionToken")); + + ParseAnalyticsPlugins plugins = new ParseAnalyticsPlugins(); + plugins.AnalyticsController = mockController.Object; + plugins.CorePlugins = mockCorePlugins.Object; + ParseAnalyticsPlugins.Instance = plugins; return ParseAnalytics.TrackEventAsync("SomeEvent").ContinueWith(t => { Assert.IsFalse(t.IsFaulted); @@ -39,12 +51,25 @@ public Task TestTrackEvent() { [AsyncStateMachine(typeof(AnalyticsTests))] public Task TestTrackEventWithDimension() { var mockController = new Mock(); + var mockCorePlugins = new Mock(); var mockCurrentUserController = new Mock(); + + mockCorePlugins + .Setup(corePlugins => corePlugins.CurrentUserController) + .Returns(mockCurrentUserController.Object); + + mockCurrentUserController + .Setup(controller => controller.GetCurrentSessionTokenAsync(It.IsAny())) + .Returns(Task.FromResult("sessionToken")); + + ParseAnalyticsPlugins plugins = new ParseAnalyticsPlugins(); + plugins.AnalyticsController = mockController.Object; + plugins.CorePlugins = mockCorePlugins.Object; + ParseAnalyticsPlugins.Instance = plugins; + var dimensions = new Dictionary() { { "facebook", "hq" } }; - ParseCorePlugins.Instance.AnalyticsController = mockController.Object; - ParseCorePlugins.Instance.CurrentUserController = mockCurrentUserController.Object; return ParseAnalytics.TrackEventAsync("SomeEvent", dimensions).ContinueWith(t => { Assert.IsFalse(t.IsFaulted); @@ -60,9 +85,21 @@ public Task TestTrackEventWithDimension() { [AsyncStateMachine(typeof(AnalyticsTests))] public Task TestTrackAppOpened() { var mockController = new Mock(); + var mockCorePlugins = new Mock(); var mockCurrentUserController = new Mock(); - ParseCorePlugins.Instance.AnalyticsController = mockController.Object; - ParseCorePlugins.Instance.CurrentUserController = mockCurrentUserController.Object; + + mockCorePlugins + .Setup(corePlugins => corePlugins.CurrentUserController) + .Returns(mockCurrentUserController.Object); + + mockCurrentUserController + .Setup(controller => controller.GetCurrentSessionTokenAsync(It.IsAny())) + .Returns(Task.FromResult("sessionToken")); + + ParseAnalyticsPlugins plugins = new ParseAnalyticsPlugins(); + plugins.AnalyticsController = mockController.Object; + plugins.CorePlugins = mockCorePlugins.Object; + ParseAnalyticsPlugins.Instance = plugins; return ParseAnalytics.TrackAppOpenedAsync().ContinueWith(t => { Assert.IsFalse(t.IsFaulted); diff --git a/ParseTest.Unit/ParseTest.Unit.NetFx45.csproj b/ParseAnalytics/Test/ParseAnalytics.Test.Unit.NetFx45.csproj similarity index 64% rename from ParseTest.Unit/ParseTest.Unit.NetFx45.csproj rename to ParseAnalytics/Test/ParseAnalytics.Test.Unit.NetFx45.csproj index 96d8d352..e39a084b 100644 --- a/ParseTest.Unit/ParseTest.Unit.NetFx45.csproj +++ b/ParseAnalytics/Test/ParseAnalytics.Test.Unit.NetFx45.csproj @@ -3,11 +3,11 @@ Debug AnyCPU - {F3937A46-F58A-4960-AFE6-AF664096C23A} + {5E1D2160-915E-4F67-AD55-918BFCB57F5B} Library Properties ParseTest - ParseTest.Unit.NetFx45 + ParseAnalytics.Test.Unit.NetFx45 v4.5 512 {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} @@ -40,27 +40,37 @@ false - - ..\packages\Moq.4.2.1507.0118\lib\net40\Moq.dll + + ..\..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll + True - - ..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll - False + + ..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll + True - - ..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll - False + + ..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll + True - - ..\packages\NUnit.2.6.3\lib\nunit.framework.dll + + ..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll + True - - ..\packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll - False + + ..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll + True - - ..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll - False + + ..\..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll + True + + + ..\..\packages\PCLStorage.1.0.2\lib\net45\PCLStorage.dll + True + + + ..\..\packages\PCLStorage.1.0.2\lib\net45\PCLStorage.Abstractions.dll + True @@ -75,48 +85,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + {4bbce4f8-c097-4680-8b07-b69d567eaa5b} + AssemblyLister.NetFx + + {de07a443-9619-4bd7-b540-41296f8a2959} - Parse + ParseCommon.Portable - - {18203a69-17c8-4ea4-8098-65d982acddcb} - Parse.NetFx45 + + {f3f65351-2ce1-4412-84b4-c36f34eab928} + ParseCore.Portable + + + {43ac01e1-aeb2-474d-856b-e81f27ef640b} + ParseAnalytics.Portable - - - + @@ -151,4 +143,4 @@ --> - + \ No newline at end of file diff --git a/ParseTest.Unit/Properties/AssemblyInfo.cs b/ParseAnalytics/Test/Properties/AssemblyInfo.cs similarity index 97% rename from ParseTest.Unit/Properties/AssemblyInfo.cs rename to ParseAnalytics/Test/Properties/AssemblyInfo.cs index 3ee2c343..c29d1b95 100644 --- a/ParseTest.Unit/Properties/AssemblyInfo.cs +++ b/ParseAnalytics/Test/Properties/AssemblyInfo.cs @@ -1,6 +1,6 @@ using System.Reflection; -// General Information about an assembly is controlled through the following +// 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("ParseTest")] diff --git a/ParseTest.Unit/packages.config b/ParseAnalytics/Test/packages.config similarity index 61% rename from ParseTest.Unit/packages.config rename to ParseAnalytics/Test/packages.config index 2e6590d8..81ee6a88 100644 --- a/ParseTest.Unit/packages.config +++ b/ParseAnalytics/Test/packages.config @@ -1,6 +1,7 @@  - + + \ No newline at end of file diff --git a/ParseCommon/Internal/Dispatcher/Unity/UnityDispatcher.cs b/ParseCommon/Internal/Dispatcher/Unity/UnityDispatcher.cs new file mode 100644 index 00000000..3303235e --- /dev/null +++ b/ParseCommon/Internal/Dispatcher/Unity/UnityDispatcher.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using UnityEngine; + +namespace Parse.Common.Internal { + /// + /// This class represents the internal Unity dispatcher used by the Parse SDK. + /// + /// It should be initialized once in your game, usually via ParseInitializeBehavior. + /// + /// In certain, advanced use-cases, you may wish to use + /// this to set up your dispatcher manually. + /// + // TODO: (richardross) Review this interface before going public. + public sealed class Dispatcher { + static Dispatcher() { + Instance = new Dispatcher(); + } + + private Dispatcher() { + DispatcherCoroutine = CreateDispatcherCoroutine(); + } + + public static Dispatcher Instance { get; private set; } + + public GameObject GameObject { get; set; } + public IEnumerator DispatcherCoroutine { get; private set; } + + private readonly ReaderWriterLockSlim dispatchQueueLock = new ReaderWriterLockSlim(); + private readonly Queue dispatchQueue = new Queue(); + + public void Post(Action action) { + if (dispatchQueueLock.IsWriteLockHeld) { + dispatchQueue.Enqueue(action); + return; + } + + dispatchQueueLock.EnterWriteLock(); + try { + dispatchQueue.Enqueue(action); + } finally { + dispatchQueueLock.ExitWriteLock(); + } + } + + private IEnumerator CreateDispatcherCoroutine() { + // We must stop the first invocation here, so that we don't actually do anything until we begin looping. + yield return null; + while (true) { + dispatchQueueLock.EnterUpgradeableReadLock(); + try { + // We'll only empty what's already in the dispatch queue in this iteration (so that a + // nested dispatch behaves like nextTick()). + int count = dispatchQueue.Count; + if (count > 0) { + dispatchQueueLock.EnterWriteLock(); + try { + while (count > 0) { + try { + dispatchQueue.Dequeue()(); + } catch (Exception e) { + // If an exception occurs, catch it and log it so that dispatches aren't broken. + Debug.LogException(e); + } + count--; + } + } finally { + dispatchQueueLock.ExitWriteLock(); + } + } + } finally { + dispatchQueueLock.ExitUpgradeableReadLock(); + } + yield return null; + } + } + } +} diff --git a/Parse/Internal/HttpClient/HttpRequest.cs b/ParseCommon/Internal/HttpClient/HttpRequest.cs similarity index 70% rename from Parse/Internal/HttpClient/HttpRequest.cs rename to ParseCommon/Internal/HttpClient/HttpRequest.cs index b08e51df..b112cedd 100644 --- a/Parse/Internal/HttpClient/HttpRequest.cs +++ b/ParseCommon/Internal/HttpClient/HttpRequest.cs @@ -4,22 +4,22 @@ using System.Collections.Generic; using System.IO; -namespace Parse.Internal { +namespace Parse.Common.Internal { /// /// IHttpRequest is an interface that provides an API to execute HTTP request data. /// - internal class HttpRequest { - public Uri Uri { get; internal set; } - public IList> Headers { get; internal set; } - + public class HttpRequest { + public Uri Uri { get; set; } + public IList> Headers { get; set; } + /// /// Data stream to be uploaded. /// - public virtual Stream Data { get; internal set; } + public virtual Stream Data { get; set; } /// /// HTTP method. One of DELETE, GET, HEAD, POST or PUT /// - public string Method { get; internal set; } + public string Method { get; set; } } } diff --git a/Parse/Internal/HttpClient/IHttpClient.cs b/ParseCommon/Internal/HttpClient/IHttpClient.cs similarity index 94% rename from Parse/Internal/HttpClient/IHttpClient.cs rename to ParseCommon/Internal/HttpClient/IHttpClient.cs index a69700f9..1fb5c9b8 100644 --- a/Parse/Internal/HttpClient/IHttpClient.cs +++ b/ParseCommon/Internal/HttpClient/IHttpClient.cs @@ -5,8 +5,8 @@ using System.Threading; using System.Threading.Tasks; -namespace Parse.Internal { - interface IHttpClient { +namespace Parse.Common.Internal { + public interface IHttpClient { /// /// Executes HTTP request to a with HTTP verb /// and . diff --git a/ParseCommon/Internal/HttpClient/Portable/HttpClient.Portable.cs b/ParseCommon/Internal/HttpClient/Portable/HttpClient.Portable.cs new file mode 100644 index 00000000..73756ec6 --- /dev/null +++ b/ParseCommon/Internal/HttpClient/Portable/HttpClient.Portable.cs @@ -0,0 +1,132 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.IO; +using System.Net; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Net.Http; +using System.Linq; + +using NetHttpClient = System.Net.Http.HttpClient; +using System.Net.Http.Headers; +using System.Collections.Generic; + +namespace Parse.Common.Internal { + public class HttpClient : IHttpClient { + private static HashSet HttpContentHeaders = new HashSet { + { "Allow" }, + { "Content-Disposition" }, + { "Content-Encoding" }, + { "Content-Language" }, + { "Content-Length" }, + { "Content-Location" }, + { "Content-MD5" }, + { "Content-Range" }, + { "Content-Type" }, + { "Expires" }, + { "Last-Modified" } + }; + + public HttpClient(): this(new NetHttpClient()) { + } + + public HttpClient(NetHttpClient client) { + this.client = client; + } + + private NetHttpClient client; + + public Task> ExecuteAsync(HttpRequest httpRequest, + IProgress uploadProgress, + IProgress downloadProgress, + CancellationToken cancellationToken) { + uploadProgress = uploadProgress ?? new Progress(); + downloadProgress = downloadProgress ?? new Progress(); + + HttpMethod httpMethod = new HttpMethod(httpRequest.Method); + HttpRequestMessage message = new HttpRequestMessage(httpMethod, httpRequest.Uri); + + // Fill in zero-length data if method is post. + Stream data = httpRequest.Data; + if (httpRequest.Data == null && httpRequest.Method.ToLower().Equals("post")) { + data = new MemoryStream(new byte[0]); + } + + message.Content = new StreamContent(data); + + if (httpRequest.Headers != null) { + foreach (var header in httpRequest.Headers) { + if (HttpContentHeaders.Contains(header.Key)) { + message.Content.Headers.Add(header.Key, header.Value); + } else { + message.Headers.Add(header.Key, header.Value); + } + } + } + + // Avoid aggressive caching on Windows Phone 8.1. + message.Headers.Add("Cache-Control", "no-cache"); + message.Headers.IfModifiedSince = DateTimeOffset.UtcNow; + + // TODO: (richardross) investigate progress here, maybe there's something we're missing in order to support this. + uploadProgress.Report(new ParseUploadProgressEventArgs { Progress = 0 }); + + return client.SendAsync(message, HttpCompletionOption.ResponseHeadersRead, cancellationToken) + .ContinueWith(httpMessageTask => { + var response = httpMessageTask.Result; + + uploadProgress.Report(new ParseUploadProgressEventArgs { Progress = 1 }); + + return response.Content.ReadAsStreamAsync().ContinueWith(streamTask => { + var resultStream = new MemoryStream(); + var responseStream = streamTask.Result; + + int bufferSize = 4096; + byte[] buffer = new byte[bufferSize]; + int bytesRead = 0; + long totalLength = -1; + long readSoFar = 0; + + try { + totalLength = responseStream.Length; + } catch (NotSupportedException) { + } + + return InternalExtensions.WhileAsync(() => { + return responseStream.ReadAsync(buffer, 0, bufferSize, cancellationToken).OnSuccess(readTask => { + bytesRead = readTask.Result; + return bytesRead > 0; + }); + }, () => { + cancellationToken.ThrowIfCancellationRequested(); + + return resultStream.WriteAsync(buffer, 0, bytesRead, cancellationToken).OnSuccess(_ => { + cancellationToken.ThrowIfCancellationRequested(); + readSoFar += bytesRead; + + if (totalLength > -1) { + downloadProgress.Report(new ParseDownloadProgressEventArgs { Progress = 1.0 * readSoFar / totalLength }); + } + }); + }).ContinueWith(_ => { + responseStream.Dispose(); + return _; + }).Unwrap().OnSuccess(_ => { + // If getting stream size is not supported, then report download only once. + if (totalLength == -1) { + downloadProgress.Report(new ParseDownloadProgressEventArgs { Progress = 1.0 }); + } + + // Assume UTF-8 encoding. + var resultAsArray = resultStream.ToArray(); + var resultString = Encoding.UTF8.GetString(resultAsArray, 0, resultAsArray.Length); + resultStream.Dispose(); + return new Tuple(response.StatusCode, resultString); + }); + }); + }).Unwrap().Unwrap(); + } + } +} diff --git a/Parse/Internal/HttpClient/Unity/HttpClient.Unity.cs b/ParseCommon/Internal/HttpClient/Unity/HttpClient.Unity.cs similarity index 90% rename from Parse/Internal/HttpClient/Unity/HttpClient.Unity.cs rename to ParseCommon/Internal/HttpClient/Unity/HttpClient.Unity.cs index 68d53cd0..52446a92 100644 --- a/Parse/Internal/HttpClient/Unity/HttpClient.Unity.cs +++ b/ParseCommon/Internal/HttpClient/Unity/HttpClient.Unity.cs @@ -11,8 +11,10 @@ using System.Threading.Tasks; using UnityEngine; -namespace Parse.Internal { - internal class HttpClient : IHttpClient { +namespace Parse.Common.Internal { + public class HttpClient : IHttpClient { + private static bool isCompiledByIL2CPP = System.AppDomain.CurrentDomain.FriendlyName.Equals("IL2CPP Root Domain"); + public Task> ExecuteAsync(HttpRequest httpRequest, IProgress uploadProgress, IProgress downloadProgress, @@ -45,7 +47,7 @@ public Task> ExecuteAsync(HttpRequest httpRequest, toDisposeAfterReading = reader; Task streamReaderTask; - if (PlatformHooks.IsCompiledByIL2CPP) { + if (isCompiledByIL2CPP) { streamReaderTask = Task.FromResult(reader.ReadToEnd()); } else { streamReaderTask = reader.ReadToEndAsync(); @@ -76,8 +78,8 @@ public Task> ExecuteAsync(HttpRequest httpRequest, float oldDownloadProgress = 0; float oldUploadProgress = 0; - PlatformHooks.RunOnMainThread(() => { - PlatformHooks.RegisterNetworkRequest(GenerateWWWInstance(httpRequest.Uri.AbsoluteUri, bytes, headerTable), www => { + Dispatcher.Instance.Post(() => { + WaitForHttpRequest(GenerateWWWInstance(httpRequest.Uri.AbsoluteUri, bytes, headerTable), www => { if (cancellationToken.IsCancellationRequested) { tcs.TrySetCanceled(); return; @@ -117,7 +119,7 @@ public Task> ExecuteAsync(HttpRequest httpRequest, return tcs.Task.ContinueWith(t => { var dispatchTcs = new TaskCompletionSource(); // ThreadPool doesn't work well in IL2CPP environment, but Thread does! - if (PlatformHooks.IsCompiledByIL2CPP) { + if (isCompiledByIL2CPP) { var thread = new Thread(_ => { dispatchTcs.TrySetResult(null); }); @@ -160,5 +162,15 @@ private static WWW GenerateWWWInstance(string uri, byte[] bytes, Hashtable heade } return new WWW(uri, bytes, newHeader); } + + private static void WaitForHttpRequest(WWW www, Action action) { + Dispatcher.Instance.Post(() => { + var isDone = www.isDone; + action(www); + if (!isDone) { + WaitForHttpRequest(www, action); + } + }); + } } } diff --git a/ParseCommon/Internal/Modules/IParseModule.cs b/ParseCommon/Internal/Modules/IParseModule.cs new file mode 100644 index 00000000..79bb5ae5 --- /dev/null +++ b/ParseCommon/Internal/Modules/IParseModule.cs @@ -0,0 +1,8 @@ +using System; + +namespace Parse.Common.Internal { + public interface IParseModule { + void OnModuleRegistered(); + void OnParseInitialized(); + } +} \ No newline at end of file diff --git a/ParseCommon/Internal/Modules/ParseModuleAttribute.cs b/ParseCommon/Internal/Modules/ParseModuleAttribute.cs new file mode 100644 index 00000000..8202a088 --- /dev/null +++ b/ParseCommon/Internal/Modules/ParseModuleAttribute.cs @@ -0,0 +1,16 @@ +using System; + +namespace Parse.Common.Internal { + [AttributeUsage(AttributeTargets.Assembly)] + public class ParseModuleAttribute : Attribute { + /// + /// Instantiates a new ParseModuleAttribute. + /// + /// The type to which this module is applied. + public ParseModuleAttribute(Type ModuleType) { + this.ModuleType = ModuleType; + } + + public Type ModuleType { get; private set; } + } +} \ No newline at end of file diff --git a/ParseCommon/Internal/Modules/ParseModuleController.cs b/ParseCommon/Internal/Modules/ParseModuleController.cs new file mode 100644 index 00000000..df505d9c --- /dev/null +++ b/ParseCommon/Internal/Modules/ParseModuleController.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using AssemblyLister; + +namespace Parse.Common.Internal { + /// + /// The class which controls the loading of other ParseModules + /// + public class ParseModuleController { + private static readonly ParseModuleController instance = new ParseModuleController(); + public static ParseModuleController Instance { + get { return instance; } + } + + private readonly object mutex = new object(); + private readonly List modules = new List(); + + private bool isParseInitialized = false; + + public void RegisterModule(IParseModule module) { + if (module == null) { + return; + } + + lock (mutex) { + modules.Add(module); + module.OnModuleRegistered(); + + if (isParseInitialized) { + module.OnParseInitialized(); + } + } + } + + public void ScanForModules() { + var moduleTypes = Lister.AllAssemblies + .SelectMany(asm => asm.GetCustomAttributes()) + .Select(attr => attr.ModuleType) + .Where(type => type != null && type.GetTypeInfo().ImplementedInterfaces.Contains(typeof(IParseModule))); + + lock (mutex) { + foreach (Type moduleType in moduleTypes) { + try { + ConstructorInfo constructor = moduleType.FindConstructor(); + if (constructor != null) { + var module = constructor.Invoke(new object[] {}) as IParseModule; + RegisterModule(module); + } + } catch (Exception) { + // Ignore, either constructor threw or was private. + } + } + } + } + + public void Reset() { + lock (mutex) { + modules.Clear(); + isParseInitialized = false; + } + } + + public void ParseDidInitialize() { + lock (mutex) { + foreach (IParseModule module in modules) { + module.OnParseInitialized(); + } + isParseInitialized = true; + } + } + } +} \ No newline at end of file diff --git a/ParseCommon/Internal/Storage/IStorageController.cs b/ParseCommon/Internal/Storage/IStorageController.cs new file mode 100644 index 00000000..54bb9dd2 --- /dev/null +++ b/ParseCommon/Internal/Storage/IStorageController.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Parse.Common.Internal { + /// + /// An abstraction for accessing persistent storage in the Parse SDK. + /// + public interface IStorageController { + /// + /// Load the contents of this storage controller asynchronously. + /// + /// + Task> LoadAsync(); + + /// + /// Overwrites the contents of this storage controller asynchronously. + /// + /// + /// + Task> SaveAsync(IDictionary contents); + } + + /// + /// An interface for a dictionary that is persisted to disk asynchronously. + /// + /// They key type of the dictionary. + /// The value type of the dictionary. + public interface IStorageDictionary : IEnumerable> { + int Count { get; } + TValue this[TKey key] { get; } + + IEnumerable Keys { get; } + IEnumerable Values { get; } + + bool ContainsKey(TKey key); + bool TryGetValue(TKey key, out TValue value); + + /// + /// Adds a key to this dictionary, and saves it asynchronously. + /// + /// The key to insert. + /// The value to insert. + /// + Task AddAsync(TKey key, TValue value); + + /// + /// Removes a key from this dictionary, and saves it asynchronously. + /// + /// + /// + Task RemoveAsync(TKey key); + } +} \ No newline at end of file diff --git a/ParseCommon/Internal/Storage/Portable/StorageController.cs b/ParseCommon/Internal/Storage/Portable/StorageController.cs new file mode 100644 index 00000000..ae4dce31 --- /dev/null +++ b/ParseCommon/Internal/Storage/Portable/StorageController.cs @@ -0,0 +1,151 @@ +using System; +using System.Threading.Tasks; +using System.Linq; +using PCLStorage; +using System.Collections.Generic; +using System.Threading; + +namespace Parse.Common.Internal { + /// + /// Implements `IStorageController` for PCL targets, based off of PCLStorage. + /// + public class StorageController : IStorageController { + private class StorageDictionary : IStorageDictionary { + private object mutex; + private Dictionary dictionary; + private IFile file; + + public StorageDictionary(IFile file) { + this.file = file; + + mutex = new Object(); + dictionary = new Dictionary(); + } + + internal Task SaveAsync() { + string json; + lock (mutex) { + json = Json.Encode(dictionary); + } + return file.WriteAllTextAsync(json); + } + + internal Task LoadAsync() { + return file.ReadAllTextAsync().ContinueWith(t => { + string text = t.Result; + Dictionary result = null; + try { + result = Json.Parse(text) as Dictionary; + } catch (Exception) { + // Do nothing, JSON error. Probaby was empty string. + } + + lock (mutex) { + dictionary = result ?? new Dictionary(); + } + }); + } + + internal void Update(IDictionary contents) { + lock (mutex) { + dictionary = contents.ToDictionary(p => p.Key, p => p.Value); + } + } + + public Task AddAsync(string key, object value) { + lock (mutex) { + dictionary[key] = value; + } + return SaveAsync(); + } + + public Task RemoveAsync(string key) { + lock (mutex) { + dictionary.Remove(key); + } + return SaveAsync(); + } + + public bool ContainsKey(string key) { + lock (mutex) { + return dictionary.ContainsKey(key); + } + } + + public IEnumerable Keys { + get { lock (mutex) { return dictionary.Keys; } } + } + + public bool TryGetValue(string key, out object value) { + lock (mutex) { + return dictionary.TryGetValue(key, out value); + } + } + + public IEnumerable Values { + get { lock (mutex) { return dictionary.Values; } } + } + + public object this[string key] { + get { lock (mutex) { return dictionary[key]; } } + } + + public int Count { + get { lock (mutex) { return dictionary.Count; } } + } + + public IEnumerator> GetEnumerator() { + lock (mutex) { + return dictionary.GetEnumerator(); + } + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { + lock (mutex) { + return dictionary.GetEnumerator(); + } + } + } + + private const string ParseStorageFileName = "ApplicationSettings"; + private readonly TaskQueue taskQueue = new TaskQueue(); + private readonly Task fileTask; + private StorageDictionary storageDictionary; + + public StorageController() { + fileTask = taskQueue.Enqueue(t => t.ContinueWith(_ => { + return FileSystem.Current.LocalStorage.CreateFileAsync(ParseStorageFileName, CreationCollisionOption.OpenIfExists); + }).Unwrap(), CancellationToken.None); + } + + public StorageController(IFile file) { + this.fileTask = Task.FromResult(file); + } + + public Task> LoadAsync() { + return taskQueue.Enqueue(toAwait => { + return toAwait.ContinueWith(_ => { + if (storageDictionary != null) { + return Task.FromResult>(storageDictionary); + } + + storageDictionary = new StorageDictionary(fileTask.Result); + return storageDictionary.LoadAsync().OnSuccess(__ => storageDictionary as IStorageDictionary); + }).Unwrap(); + }, CancellationToken.None); + } + + public Task> SaveAsync(IDictionary contents) { + return taskQueue.Enqueue(toAwait => { + return toAwait.ContinueWith(_ => { + if (storageDictionary == null) { + storageDictionary = new StorageDictionary(fileTask.Result); + } + + storageDictionary.Update(contents); + return storageDictionary.SaveAsync().OnSuccess(__ => storageDictionary as IStorageDictionary); + }).Unwrap(); + }, CancellationToken.None); + } + } +} diff --git a/ParseCommon/Internal/Storage/Unity/StorageController.cs b/ParseCommon/Internal/Storage/Unity/StorageController.cs new file mode 100644 index 00000000..e01c7769 --- /dev/null +++ b/ParseCommon/Internal/Storage/Unity/StorageController.cs @@ -0,0 +1,181 @@ +using System; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEngine; +using System.Threading; + +namespace Parse.Common.Internal { + /// + /// Implements `IStorageController` for PCL targets, based off of PCLStorage. + /// + public class StorageController : IStorageController { + private const string ParseStorageFileName = "Parse.settings"; + + private TaskQueue taskQueue = new TaskQueue(); + private string settingsPath; + private StorageDictionary storageDictionary; + + private class StorageDictionary : IStorageDictionary { + private object mutex; + private Dictionary dictionary; + private string settingsPath; + + public StorageDictionary(string settingsPath) { + this.settingsPath = settingsPath; + + mutex = new object(); + dictionary = new Dictionary(); + } + + internal Task SaveAsync() { + string jsonEncoded; + lock (mutex) { + jsonEncoded = Json.Encode(dictionary); + } + + if (Application.isWebPlayer) { + PlayerPrefs.SetString(ParseStorageFileName, jsonEncoded); + PlayerPrefs.Save(); + } else if (Application.platform == RuntimePlatform.tvOS) { + Debug.Log("Running on TvOS, prefs cannot be saved."); + } else { + using (var fs = new FileStream(settingsPath, FileMode.Create, FileAccess.Write)) { + using (var writer = new StreamWriter(fs)) { + writer.Write(jsonEncoded); + } + } + } + + return Task.FromResult(null); + } + + internal Task LoadAsync() { + string jsonString = null; + + try { + if (Application.isWebPlayer) { + jsonString = PlayerPrefs.GetString(ParseStorageFileName, null); + } else if (Application.platform == RuntimePlatform.tvOS) { + Debug.Log("Running on TvOS, prefs cannot be loaded."); + } else { + using (var fs = new FileStream(settingsPath, FileMode.Open, FileAccess.Read)) { + var reader = new StreamReader(fs); + jsonString = reader.ReadToEnd(); + } + } + } catch (Exception) { + // Do nothing + } + + if (jsonString == null) { + lock (mutex) { + dictionary = new Dictionary(); + return Task.FromResult(null); + } + } + + Dictionary decoded = Json.Parse(jsonString) as Dictionary; + lock (mutex) { + dictionary = decoded ?? new Dictionary(); + return Task.FromResult(null); + } + } + + internal void Update(IDictionary contents) { + lock (mutex) { + dictionary = contents.ToDictionary(p => p.Key, p => p.Value); + } + } + + public Task AddAsync(string key, object value) { + lock (mutex) { + dictionary[key] = value; + } + return SaveAsync(); + } + + public Task RemoveAsync(string key) { + lock (mutex) { + dictionary.Remove(key); + } + return SaveAsync(); + } + + public bool ContainsKey(string key) { + lock (mutex) { + return dictionary.ContainsKey(key); + } + } + + public IEnumerable Keys { + get { lock (mutex) { return dictionary.Keys; } } + } + + public bool TryGetValue(string key, out object value) { + lock (mutex) { + return dictionary.TryGetValue(key, out value); + } + } + + public IEnumerable Values { + get { lock (mutex) { return dictionary.Values; } } + } + + public object this[string key] { + get { lock (mutex) { return dictionary[key]; } } + } + + public int Count { + get { lock (mutex) { return dictionary.Count; } } + } + + public IEnumerator> GetEnumerator() { + lock (mutex) { + return dictionary.GetEnumerator(); + } + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { + lock (mutex) { + return dictionary.GetEnumerator(); + } + } + } + + public StorageController() { + settingsPath = Path.Combine(Application.persistentDataPath, ParseStorageFileName); + } + + public StorageController(String settingsPath) { + this.settingsPath = settingsPath; + } + + public Task> LoadAsync() { + return taskQueue.Enqueue(toAwait => { + return toAwait.ContinueWith(_ => { + if (storageDictionary != null) { + return Task.FromResult>(storageDictionary); + } + + storageDictionary = new StorageDictionary(settingsPath); + return storageDictionary.LoadAsync().OnSuccess(__ => storageDictionary as IStorageDictionary); + }).Unwrap(); + }, CancellationToken.None); + } + + public Task> SaveAsync(IDictionary contents) { + return taskQueue.Enqueue(toAwait => { + return toAwait.ContinueWith(_ => { + if (storageDictionary == null) { + storageDictionary = new StorageDictionary(settingsPath); + } + + storageDictionary.Update(contents); + return storageDictionary.SaveAsync().OnSuccess(__ => storageDictionary as IStorageDictionary); + }).Unwrap(); + }, CancellationToken.None); + } + } +} diff --git a/Parse/Internal/Utilities/FlexibleDictionaryWrapper.cs b/ParseCommon/Internal/Utilities/FlexibleDictionaryWrapper.cs similarity index 91% rename from Parse/Internal/Utilities/FlexibleDictionaryWrapper.cs rename to ParseCommon/Internal/Utilities/FlexibleDictionaryWrapper.cs index 4517be80..a2d40e92 100644 --- a/Parse/Internal/Utilities/FlexibleDictionaryWrapper.cs +++ b/ParseCommon/Internal/Utilities/FlexibleDictionaryWrapper.cs @@ -4,13 +4,7 @@ using System.Linq; using Parse.Utilities; -#if IOS -using PreserveAttribute = Foundation.PreserveAttribute; -#elif ANDROID -using PreserveAttribute = Android.Runtime.PreserveAttribute; -#endif - -namespace Parse.Internal { +namespace Parse.Common.Internal { /// /// Provides a Dictionary implementation that can delegate to any other /// dictionary, regardless of its value type. Used for coercion of @@ -18,10 +12,8 @@ namespace Parse.Internal { /// /// The resulting type of value in the dictionary. /// The original type of value in the dictionary. -#if MONO - [Preserve(AllMembers = true)] -#endif - class FlexibleDictionaryWrapper : IDictionary { + [Preserve(AllMembers = true, Conditional = false)] + public class FlexibleDictionaryWrapper : IDictionary { private readonly IDictionary toWrap; public FlexibleDictionaryWrapper(IDictionary toWrap) { this.toWrap = toWrap; diff --git a/Parse/Internal/Utilities/FlexibleListWrapper.cs b/ParseCommon/Internal/Utilities/FlexibleListWrapper.cs similarity index 89% rename from Parse/Internal/Utilities/FlexibleListWrapper.cs rename to ParseCommon/Internal/Utilities/FlexibleListWrapper.cs index ced55852..8db8e577 100644 --- a/Parse/Internal/Utilities/FlexibleListWrapper.cs +++ b/ParseCommon/Internal/Utilities/FlexibleListWrapper.cs @@ -5,13 +5,7 @@ using System.Linq; using Parse.Utilities; -#if IOS -using PreserveAttribute = Foundation.PreserveAttribute; -#elif ANDROID -using PreserveAttribute = Android.Runtime.PreserveAttribute; -#endif - -namespace Parse.Internal { +namespace Parse.Common.Internal { /// /// Provides a List implementation that can delegate to any other /// list, regardless of its value type. Used for coercion of @@ -19,10 +13,8 @@ namespace Parse.Internal { /// /// The resulting type of value in the list. /// The original type of value in the list. -#if MONO - [Preserve(AllMembers = true)] -#endif - class FlexibleListWrapper : IList { + [Preserve(AllMembers = true, Conditional = false)] + public class FlexibleListWrapper : IList { private IList toWrap; public FlexibleListWrapper(IList toWrap) { this.toWrap = toWrap; diff --git a/Parse/Internal/Utilities/IJsonConvertible.cs b/ParseCommon/Internal/Utilities/IJsonConvertible.cs similarity index 89% rename from Parse/Internal/Utilities/IJsonConvertible.cs rename to ParseCommon/Internal/Utilities/IJsonConvertible.cs index 92817eb1..f754f31b 100644 --- a/Parse/Internal/Utilities/IJsonConvertible.cs +++ b/ParseCommon/Internal/Utilities/IJsonConvertible.cs @@ -3,11 +3,11 @@ using System; using System.Collections.Generic; -namespace Parse.Internal { +namespace Parse.Common.Internal { /// /// Represents an object that can be converted into JSON. /// - interface IJsonConvertible { + public interface IJsonConvertible { /// /// Converts the object to a data structure that can be converted to JSON. /// diff --git a/Parse/Internal/Utilities/IdentityEqualityComparer.cs b/ParseCommon/Internal/Utilities/IdentityEqualityComparer.cs similarity index 89% rename from Parse/Internal/Utilities/IdentityEqualityComparer.cs rename to ParseCommon/Internal/Utilities/IdentityEqualityComparer.cs index cbc05875..5ebb5927 100644 --- a/Parse/Internal/Utilities/IdentityEqualityComparer.cs +++ b/ParseCommon/Internal/Utilities/IdentityEqualityComparer.cs @@ -3,14 +3,14 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; -namespace Parse.Internal +namespace Parse.Common.Internal { /// /// An equality comparer that uses the object identity (i.e. ReferenceEquals) /// rather than .Equals, allowing identity to be used for checking equality in /// ISets and IDictionaries. /// - class IdentityEqualityComparer : IEqualityComparer + public class IdentityEqualityComparer : IEqualityComparer { public bool Equals(T x, T y) { diff --git a/ParseCommon/Internal/Utilities/InternalExtensions.cs b/ParseCommon/Internal/Utilities/InternalExtensions.cs new file mode 100644 index 00000000..22036925 --- /dev/null +++ b/ParseCommon/Internal/Utilities/InternalExtensions.cs @@ -0,0 +1,107 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.ExceptionServices; +using System.Text; +using System.Threading.Tasks; + +namespace Parse.Common.Internal { + /// + /// Provides helper methods that allow us to use terser code elsewhere. + /// + public static class InternalExtensions { + /// + /// Ensures a task (even null) is awaitable. + /// + /// + /// + /// + public static Task Safe(this Task task) { + return task ?? Task.FromResult(default(T)); + } + + /// + /// Ensures a task (even null) is awaitable. + /// + /// + /// + public static Task Safe(this Task task) { + return task ?? Task.FromResult(null); + } + + public delegate void PartialAccessor(ref T arg); + + public static TValue GetOrDefault(this IDictionary self, + TKey key, + TValue defaultValue) { + TValue value; + if (self.TryGetValue(key, out value)) { + return value; + } + return defaultValue; + } + + public static bool CollectionsEqual(this IEnumerable a, IEnumerable b) { + return Object.Equals(a, b) || + (a != null && b != null && + a.SequenceEqual(b)); + } + + public static Task OnSuccess(this Task task, + Func, TResult> continuation) { + return ((Task)task).OnSuccess(t => continuation((Task)t)); + } + + public static Task OnSuccess(this Task task, Action> continuation) { + return task.OnSuccess((Func, object>)(t => { + continuation(t); + return null; + })); + } + + public static Task OnSuccess(this Task task, + Func continuation) { + return task.ContinueWith(t => { + if (t.IsFaulted) { + var ex = t.Exception.Flatten(); + if (ex.InnerExceptions.Count == 1) { + ExceptionDispatchInfo.Capture(ex.InnerExceptions[0]).Throw(); + } else { + ExceptionDispatchInfo.Capture(ex).Throw(); + } + // Unreachable + return Task.FromResult(default(TResult)); + } else if (t.IsCanceled) { + var tcs = new TaskCompletionSource(); + tcs.SetCanceled(); + return tcs.Task; + } else { + return Task.FromResult(continuation(t)); + } + }).Unwrap(); + } + + public static Task OnSuccess(this Task task, Action continuation) { + return task.OnSuccess((Func)(t => { + continuation(t); + return null; + })); + } + + public static Task WhileAsync(Func> predicate, Func body) { + Func iterate = null; + iterate = () => { + return predicate().OnSuccess(t => { + if (!t.Result) { + return Task.FromResult(0); + } + return body().OnSuccess(_ => iterate()).Unwrap(); + }).Unwrap(); + }; + return iterate(); + } + } +} diff --git a/Parse/Internal/Utilities/Json.cs b/ParseCommon/Internal/Utilities/Json.cs similarity index 98% rename from Parse/Internal/Utilities/Json.cs rename to ParseCommon/Internal/Utilities/Json.cs index 29d3c5d6..1facf036 100644 --- a/Parse/Internal/Utilities/Json.cs +++ b/ParseCommon/Internal/Utilities/Json.cs @@ -4,16 +4,17 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; -namespace Parse.Internal { +namespace Parse.Common.Internal { /// /// A simple recursive-descent JSON Parser based on the grammar defined at http://www.json.org /// and http://tools.ietf.org/html/rfc4627 /// - class Json { + public class Json { /// /// Place at the start of a regex to force the match to begin wherever the search starts (i.e. /// anchored at the index of the first character of the search, even when that search starts @@ -419,7 +420,7 @@ public static string Encode(object obj) { return "false"; } } - if (!ReflectionHelpers.IsPrimitive(obj.GetType())) { + if (!obj.GetType().GetTypeInfo().IsPrimitive) { throw new ArgumentException("Unable to encode objects of type " + obj.GetType()); } return Convert.ToString(obj, CultureInfo.InvariantCulture); diff --git a/Parse/Internal/Utilities/LockSet.cs b/ParseCommon/Internal/Utilities/LockSet.cs similarity index 95% rename from Parse/Internal/Utilities/LockSet.cs rename to ParseCommon/Internal/Utilities/LockSet.cs index ca0011ef..cf480870 100644 --- a/Parse/Internal/Utilities/LockSet.cs +++ b/ParseCommon/Internal/Utilities/LockSet.cs @@ -8,8 +8,8 @@ using System.Threading; using System.Threading.Tasks; -namespace Parse.Internal { - class LockSet { +namespace Parse.Common.Internal { + public class LockSet { private static readonly ConditionalWeakTable stableIds = new ConditionalWeakTable(); private static long nextStableId = 0; diff --git a/Parse/Internal/Utilities/ReflectionHelpers.cs b/ParseCommon/Internal/Utilities/ReflectionHelpers.cs similarity index 69% rename from Parse/Internal/Utilities/ReflectionHelpers.cs rename to ParseCommon/Internal/Utilities/ReflectionHelpers.cs index 6dac7d03..212bdd37 100644 --- a/Parse/Internal/Utilities/ReflectionHelpers.cs +++ b/ParseCommon/Internal/Utilities/ReflectionHelpers.cs @@ -5,9 +5,9 @@ using System.Collections.Generic; using System.Linq; -namespace Parse.Internal { - static class ReflectionHelpers { - internal static IEnumerable GetProperties(Type type) { +namespace Parse.Common.Internal { + public static class ReflectionHelpers { + public static IEnumerable GetProperties(Type type) { #if MONO || UNITY return type.GetProperties(); #else @@ -15,7 +15,7 @@ internal static IEnumerable GetProperties(Type type) { #endif } - internal static MethodInfo GetMethod(Type type, string name, Type[] parameters) { + public static MethodInfo GetMethod(Type type, string name, Type[] parameters) { #if MONO || UNITY return type.GetMethod(name, parameters); #else @@ -23,15 +23,15 @@ internal static MethodInfo GetMethod(Type type, string name, Type[] parameters) #endif } - internal static bool IsPrimitive(Type type) { -#if MONO + public static bool IsPrimitive(Type type) { +#if MONO || UNITY return type.IsPrimitive; #else return type.GetTypeInfo().IsPrimitive; #endif } - internal static IEnumerable GetInterfaces(Type type) { + public static IEnumerable GetInterfaces(Type type) { #if MONO || UNITY return type.GetInterfaces(); #else @@ -39,7 +39,7 @@ internal static IEnumerable GetInterfaces(Type type) { #endif } - internal static bool IsConstructedGenericType(Type type) { + public static bool IsConstructedGenericType(Type type) { #if UNITY return type.IsGenericType && !type.IsGenericTypeDefinition; #else @@ -47,7 +47,7 @@ internal static bool IsConstructedGenericType(Type type) { #endif } - internal static IEnumerable GetConstructors(Type type) { + public static IEnumerable GetConstructors(Type type) { #if UNITY BindingFlags searchFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; return type.GetConstructors(searchFlags); @@ -57,7 +57,7 @@ internal static IEnumerable GetConstructors(Type type) { #endif } - internal static Type[] GetGenericTypeArguments(Type type) { + public static Type[] GetGenericTypeArguments(Type type) { #if UNITY return type.GetGenericArguments(); #else @@ -65,7 +65,7 @@ internal static Type[] GetGenericTypeArguments(Type type) { #endif } - internal static PropertyInfo GetProperty(Type type, string name) { + public static PropertyInfo GetProperty(Type type, string name) { #if MONO || UNITY return type.GetProperty(name); #else @@ -81,7 +81,7 @@ internal static PropertyInfo GetProperty(Type type, string name) { /// /// /// - internal static ConstructorInfo FindConstructor(this Type self, params Type[] parameterTypes) { + public static ConstructorInfo FindConstructor(this Type self, params Type[] parameterTypes) { var constructors = from constructor in GetConstructors(self) let parameters = constructor.GetParameters() @@ -91,7 +91,7 @@ where types.SequenceEqual(parameterTypes) return constructors.SingleOrDefault(); } - internal static bool IsNullable(Type t) { + public static bool IsNullable(Type t) { bool isGeneric; #if UNITY isGeneric = t.IsGenericType && !t.IsGenericTypeDefinition; @@ -100,6 +100,13 @@ internal static bool IsNullable(Type t) { #endif return isGeneric && t.GetGenericTypeDefinition().Equals(typeof(Nullable<>)); } + + public static IEnumerable GetCustomAttributes(this Assembly assembly) where T: Attribute { +#if UNITY + return assembly.GetCustomAttributes(typeof(T), false).Select(attr => attr as T); +#else + return CustomAttributeExtensions.GetCustomAttributes(assembly); +#endif + } } } - diff --git a/Parse/Internal/Utilities/SynchronizedEventHandler.cs b/ParseCommon/Internal/Utilities/SynchronizedEventHandler.cs similarity index 96% rename from Parse/Internal/Utilities/SynchronizedEventHandler.cs rename to ParseCommon/Internal/Utilities/SynchronizedEventHandler.cs index d65aa123..4b8fa5dd 100644 --- a/Parse/Internal/Utilities/SynchronizedEventHandler.cs +++ b/ParseCommon/Internal/Utilities/SynchronizedEventHandler.cs @@ -7,13 +7,13 @@ using System.Threading; using System.Threading.Tasks; -namespace Parse.Internal { +namespace Parse.Common.Internal { /// /// Represents an event handler that calls back from the synchronization context /// that subscribed. /// Should look like an EventArgs, but may not inherit EventArgs if T is implemented by the Windows team. /// - class SynchronizedEventHandler { + public class SynchronizedEventHandler { private LinkedList> delegates = new LinkedList>(); public void Add(Delegate del) { diff --git a/Parse/Internal/Utilities/TaskQueue.cs b/ParseCommon/Internal/Utilities/TaskQueue.cs similarity index 98% rename from Parse/Internal/Utilities/TaskQueue.cs rename to ParseCommon/Internal/Utilities/TaskQueue.cs index 952a8168..621a59cc 100644 --- a/Parse/Internal/Utilities/TaskQueue.cs +++ b/ParseCommon/Internal/Utilities/TaskQueue.cs @@ -5,11 +5,11 @@ using System.Threading; using System.Threading.Tasks; -namespace Parse.Internal { +namespace Parse.Common.Internal { /// /// A helper class for enqueuing tasks /// - class TaskQueue { + public class TaskQueue { /// /// We only need to keep the tail of the queue. Cancelled tasks will /// just complete normally/immediately when their turn arrives. diff --git a/Parse/Internal/PlatformHooks/iOS/PlatformHooks.iOS.cs b/ParseCommon/Internal/Utilities/XamarinAttributes.cs similarity index 55% rename from Parse/Internal/PlatformHooks/iOS/PlatformHooks.iOS.cs rename to ParseCommon/Internal/Utilities/XamarinAttributes.cs index 8b327312..33cb0a5a 100644 --- a/Parse/Internal/PlatformHooks/iOS/PlatformHooks.iOS.cs +++ b/ParseCommon/Internal/Utilities/XamarinAttributes.cs @@ -1,127 +1,34 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using System; -using System.Reflection; -using System.Linq; -using System.Linq.Expressions; -using Foundation; -using UIKit; - -using Parse.Internal; - -using PreserveAttribute = Foundation.PreserveAttribute; +using System; using System.Collections.Generic; -using System.Threading.Tasks; -using System.Threading; - -namespace Parse { - [Preserve(AllMembers = true)] - partial class PlatformHooks : IPlatformHooks { - private IHttpClient httpClient = null; - public IHttpClient HttpClient { - get { - httpClient = httpClient ?? new HttpClient(); - return httpClient; - } - } - - public string SDKName { - get { - return "xamarin-ios"; - } - } - - public string AppName { - get { - return GetAppAttribute("CFBundleDisplayName"); - } - } - - public string AppBuildVersion { - get { - return GetAppAttribute("CFBundleVersion"); - } - } - - public string AppDisplayVersion { - get { - return GetAppAttribute("CFBundleShortVersionString"); - } - } - - public string AppIdentifier { - get { - return GetAppAttribute("CFBundleIdentifier"); - } - } - - public string OSVersion { - get { - return UIDevice.CurrentDevice.SystemVersion; - } - } - - public string DeviceType { - get { - return "ios"; - } - } - - public string DeviceTimeZone { - get { - Foundation.NSTimeZone.ResetSystemTimeZone(); - return Foundation.NSTimeZone.SystemTimeZone.Name; - } - } - - public void Initialize() { - // Do nothing. - } - public Task ExecuteParseInstallationSaveHookAsync(ParseInstallation installation) { - return Task.Run(() => { - installation.SetIfDifferent("badge", installation.Badge); - }); - } - - /// - /// Gets an attribute from the Info.plist. - /// - /// the attribute name - /// the attribute value - /// This is a duplicate of what we have in ParseInstallation. We do it because - /// it's easier to maintain this way (rather than referencing PlatformHooks everywhere). - private string GetAppAttribute(string attributeName) { - var appAttributes = NSBundle.MainBundle; +namespace Parse.Common.Internal { + /// + /// A reimplementation of Xamarin's PreserveAttribute. + /// This allows us to support AOT and linking for Xamarin platforms. + /// + [AttributeUsage(AttributeTargets.All)] + internal class PreserveAttribute : Attribute { + public bool AllMembers; + public bool Conditional; + } - var attribute = appAttributes.ObjectForInfoDictionary(attributeName); - return attribute == null ? null : attribute.ToString(); - } + [AttributeUsage(AttributeTargets.All)] + internal class LinkerSafeAttribute : Attribute { + public LinkerSafeAttribute() { } + } + [Preserve(AllMembers = true)] + internal class PreserveWrapperTypes { /// /// Exists to ensure that generic types are AOT-compiled for the conversions we support. /// Any new value types that we add support for will need to be registered here. /// The method itself is never called, but by virtue of the Preserve attribute being set - /// on the PlatformHooks class, these types will be AOT-compiled. + /// on the class, these types will be AOT-compiled. + /// + /// This also applies to Unity. /// private static List CreateWrapperTypes() { return new List { - (Action)(async () => await ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(async () => await ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(async () => await ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(async () => await ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(async () => await ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(async () => await ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(async () => await ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(async () => await ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(async () => await ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(async () => await ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(async () => await ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(async () => await ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(async () => await ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), - (Action)(async () => await ParseCloud.CallFunctionAsync>(null, null, CancellationToken.None)), - (Action)(async () => await ParseCloud.CallFunctionAsync>(null, null, CancellationToken.None)), - typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), @@ -135,7 +42,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), - + typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), @@ -149,7 +56,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), - + typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), @@ -163,7 +70,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), - + typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), @@ -177,7 +84,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), - + typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), @@ -191,7 +98,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), - + typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), @@ -205,7 +112,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), - + typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), @@ -219,7 +126,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), - + typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), @@ -233,7 +140,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), - + typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), @@ -247,7 +154,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), - + typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), @@ -261,7 +168,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), - + typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), @@ -275,7 +182,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), - + typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), @@ -289,7 +196,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), - + typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), @@ -303,12 +210,10 @@ private static List CreateWrapperTypes() { typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), - + typeof(FlexibleListWrapper), typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - typeof(FlexibleListWrapper), - + typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), @@ -322,7 +227,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), - + typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), @@ -336,7 +241,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), - + typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), @@ -350,7 +255,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), - + typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), @@ -364,7 +269,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), - + typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), @@ -378,7 +283,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), - + typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), @@ -392,7 +297,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), - + typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), @@ -406,7 +311,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), - + typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), @@ -420,7 +325,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), - + typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), @@ -434,7 +339,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), - + typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), @@ -448,7 +353,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), - + typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), @@ -462,7 +367,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), - + typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), @@ -476,7 +381,7 @@ private static List CreateWrapperTypes() { typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), - + typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), @@ -490,266 +395,10 @@ private static List CreateWrapperTypes() { typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), - + typeof(FlexibleDictionaryWrapper), typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), - typeof(FlexibleDictionaryWrapper), }; } } - - static class MonoHelpersiOS { - internal static BinaryExpression Update(this BinaryExpression expr, - Expression left, - LambdaExpression conversion, - Expression right) { - return Expression.MakeBinary(expr.NodeType, left, right, expr.IsLiftedToNull, expr.Method, conversion); - } - - internal static ConditionalExpression Update(this ConditionalExpression expr, - Expression test, - Expression isTrue, - Expression isFalse) { - return Expression.Condition(test, isTrue, isFalse); - } - - internal static ElementInit Update(this ElementInit init, IEnumerable arguments) { - return Expression.ElementInit(init.AddMethod, arguments); - } - - internal static LambdaExpression Update(this LambdaExpression expr, - Expression body, - IEnumerable parameters) { - return Expression.Lambda(expr.Type, body, parameters); - } - - internal static ListInitExpression Update(this ListInitExpression expr, - NewExpression newExpr, - IEnumerable initializers) { - return Expression.ListInit(newExpr, initializers); - } - - internal static MemberExpression Update(this MemberExpression expr, Expression obj) { - return Expression.MakeMemberAccess(obj, expr.Member); - } - - internal static MemberAssignment Update(this MemberAssignment assign, Expression expr) { - return Expression.Bind(assign.Member, expr); - } - - internal static InvocationExpression Update(this InvocationExpression expr, - Expression root, - IEnumerable args) { - return Expression.Invoke(root, args); - } - - internal static MemberInitExpression Update(this MemberInitExpression expr, - NewExpression newExpr, - IEnumerable bindings) { - return Expression.MemberInit(newExpr, bindings); - } - - internal static MemberListBinding Update(this MemberListBinding binding, IEnumerable initializers) { - return Expression.ListBind(binding.Member, initializers); - } - - internal static MemberMemberBinding Update(this MemberMemberBinding binding, IEnumerable bindings) { - return Expression.MemberBind(binding.Member, bindings); - } - - internal static MethodCallExpression Update(this MethodCallExpression expr, - Expression root, - IEnumerable args) { - return Expression.Call(root, expr.Method, args); - } - - internal static NewExpression Update(this NewExpression expr, IEnumerable args) { - return Expression.New(expr.Constructor, args, expr.Members); - } - - internal static NewArrayExpression Update(this NewArrayExpression expr, IEnumerable args) { - return Expression.NewArrayInit(expr.Type, args); - } - - internal static TypeBinaryExpression Update(this TypeBinaryExpression expr, Expression body) { - return Expression.TypeIs(body, expr.TypeOperand); - } - - internal static UnaryExpression Update(this UnaryExpression expr, Expression body) { - return Expression.MakeUnary(expr.NodeType, body, expr.Type, expr.Method); - } - } - - // TODO: Revisit this after discussing whether Xamarin can make this class public. - internal abstract class ExpressionVisitor { - public ExpressionVisitor() { - } - - public virtual Expression Visit(Expression expr) { - if (expr == null) { - return null; - } - - var bin = expr as BinaryExpression; - if (bin != null) { - return VisitBinary(bin); - } - - var cond = expr as ConditionalExpression; - if (cond != null) { - return VisitConditional(cond); - } - - var constant = expr as ConstantExpression; - if (constant != null) { - return VisitConstant(constant); - } - - var lambda = expr as LambdaExpression; - if (lambda != null) { - var lambdaType = lambda.GetType().GetGenericArguments()[0]; - Func, Expression> visitLambdaDelegate = VisitLambda; - MethodInfo method = visitLambdaDelegate.Method.GetGenericMethodDefinition().MakeGenericMethod(lambdaType); - return (Expression)method.Invoke(this, new[] { lambda }); - } - - var listInit = expr as ListInitExpression; - if (listInit != null) { - return VisitListInit(listInit); - } - - var member = expr as MemberExpression; - if (member != null) { - return VisitMember(member); - } - - var memberInit = expr as MemberInitExpression; - if (memberInit != null) { - return VisitMemberInit(memberInit); - } - - var methodCall = expr as MethodCallExpression; - if (methodCall != null) { - return VisitMethodCall(methodCall); - } - - var newExpr = expr as NewExpression; - if (newExpr != null) { - return VisitNew(newExpr); - } - - var newArrayExpr = expr as NewArrayExpression; - if (newArrayExpr != null) { - return VisitNewArray(newArrayExpr); - } - - var param = expr as ParameterExpression; - if (param != null) { - return VisitParameter(param); - } - - var typeBinary = expr as TypeBinaryExpression; - if (typeBinary != null) { - return VisitTypeBinary(typeBinary); - } - - var unary = expr as UnaryExpression; - if (unary != null) { - return VisitUnary(unary); - } - - var invocation = expr as InvocationExpression; - if (invocation != null) { - return VisitInvocation(invocation); - } - - throw new NotSupportedException("Expressions of type " + expr.Type + " are not supported."); - } - - protected virtual Expression VisitBinary(BinaryExpression expr) { - return expr.Update(Visit(expr.Left), (LambdaExpression)Visit(expr.Conversion), Visit(expr.Right)); - } - - protected virtual Expression VisitConditional(ConditionalExpression expr) { - return expr.Update(Visit(expr.Test), Visit(expr.IfTrue), Visit(expr.IfFalse)); - } - - protected virtual Expression VisitConstant(ConstantExpression expr) { - return expr; - } - - protected virtual ElementInit VisitElementInit(ElementInit init) { - return init.Update(init.Arguments.Select(a => Visit(a))); - } - - protected virtual Expression VisitLambda(Expression expr) { - return expr.Update(Visit(expr.Body), expr.Parameters.Select(p => (ParameterExpression)VisitParameter(p))); - } - - protected virtual Expression VisitListInit(ListInitExpression expr) { - return expr.Update((NewExpression)Visit(expr.NewExpression), expr.Initializers.Select(i => VisitElementInit(i))); - } - - protected virtual Expression VisitMember(MemberExpression expr) { - return expr.Update(Visit(expr.Expression)); - } - - protected virtual MemberAssignment VisitMemberAssignment(MemberAssignment assign) { - return assign.Update(Visit(assign.Expression)); - } - - protected virtual MemberBinding VisitMemberBinding(MemberBinding binding) { - switch (binding.BindingType) { - case MemberBindingType.Assignment: - return VisitMemberAssignment((MemberAssignment)binding); - case MemberBindingType.ListBinding: - return VisitMemberListBinding((MemberListBinding)binding); - case MemberBindingType.MemberBinding: - return VisitMemberMemberBinding((MemberMemberBinding)binding); - default: - throw new NotSupportedException("Bad member binding type: " + binding); - } - } - - protected virtual Expression VisitInvocation(InvocationExpression expr) { - return expr.Update(Visit(expr.Expression), expr.Arguments.Select(a => Visit(a))); - } - - protected virtual Expression VisitMemberInit(MemberInitExpression expr) { - return expr.Update((NewExpression)Visit(expr.NewExpression), expr.Bindings.Select(b => VisitMemberBinding(b))); - } - - protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding binding) { - return binding.Update(binding.Initializers.Select(i => VisitElementInit(i))); - } - - protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding binding) { - return binding.Update(binding.Bindings.Select(b => VisitMemberBinding(b))); - } - - protected virtual Expression VisitMethodCall(MethodCallExpression expr) { - return expr.Update(Visit(expr.Object), expr.Arguments.Select(a => Visit(a))); - } - - protected virtual Expression VisitNew(NewExpression expr) { - return expr.Update(expr.Arguments.Select(a => Visit(a))); - } - - protected virtual Expression VisitNewArray(NewArrayExpression expr) { - return expr.Update(expr.Expressions.Select(a => Visit(a))); - } - - protected virtual Expression VisitParameter(ParameterExpression expr) { - return expr; - } - - protected virtual Expression VisitTypeBinary(TypeBinaryExpression expr) { - return expr.Update(Visit(expr.Expression)); - } - - protected virtual Expression VisitUnary(UnaryExpression expr) { - return expr.Update(Visit(expr.Operand)); - } - } } diff --git a/ParseCommon/ParseCommon.Portable.csproj b/ParseCommon/ParseCommon.Portable.csproj new file mode 100644 index 00000000..8ec80fcc --- /dev/null +++ b/ParseCommon/ParseCommon.Portable.csproj @@ -0,0 +1,95 @@ + + + + + 11.0 + Debug + AnyCPU + {DE07A443-9619-4BD7-B540-41296F8A2959} + Library + Properties + Parse.Common + Parse.Common + v4.5 + Profile78 + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\ + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AnyCPU + bin\Debug\Parse.Common.xml + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\Parse.Common.xml + + + + + **\Unity\** + + + + + + + + + + + + + + ..\packages\PCLStorage.1.0.2\lib\portable-net45+wp8+wpa81+win8+monoandroid+monotouch+Xamarin.iOS+Xamarin.Mac\PCLStorage.dll + True + + + ..\packages\PCLStorage.1.0.2\lib\portable-net45+wp8+wpa81+win8+monoandroid+monotouch+Xamarin.iOS+Xamarin.Mac\PCLStorage.Abstractions.dll + True + + + ..\packages\Microsoft.Net.Http.2.2.29\lib\portable-net40+sl4+win8+wp71+wpa81\System.Net.Http.dll + True + + + ..\packages\Microsoft.Net.Http.2.2.29\lib\portable-net40+sl4+win8+wp71+wpa81\System.Net.Http.Extensions.dll + True + + + ..\packages\Microsoft.Net.Http.2.2.29\lib\portable-net40+sl4+win8+wp71+wpa81\System.Net.Http.Primitives.dll + True + + + + + {ea65343f-7fed-450b-a1d6-3215b33b3563} + AssemblyLister.Portable + + + + false + + + + + \ No newline at end of file diff --git a/Parse/Parse.Unity.csproj b/ParseCommon/ParseCommon.Unity.csproj similarity index 74% rename from Parse/Parse.Unity.csproj rename to ParseCommon/ParseCommon.Unity.csproj index 91836156..7fc68450 100644 --- a/Parse/Parse.Unity.csproj +++ b/ParseCommon/ParseCommon.Unity.csproj @@ -4,11 +4,11 @@ Debug AnyCPU - {8473BEF6-7086-4414-AAD6-264967A7FE75} + {196457AA-9BA0-40BC-91A3-21BAAD6F4169} Library Properties - Parse - Parse.Unity + Parse.Common + Parse.Common v3.5 512 @@ -36,51 +36,50 @@ prompt 4 5 - bin\Release\Unity\Parse.Unity.xml + bin\Release\Unity\Parse.Common.xml - False - .\UnityEngine.dll + ..\UnityEngine.dll False - - - **\Android\**; - **\iOS\**; - **\Mono\**; - **\NetFx45\**; - **\Phone\**; - **\WinRT\**; - **\SettingsStorage\**; - **\ParseQueryExtensions.cs; + + **\Portable\** - - - - - - - - + + + {693a621e-ff3c-400f-b69d-382acd50eda7} + AssemblyLister.Unity + + + {8473bef6-7086-4414-aad6-264967a7fe75} + Unity.Compat + + + {ce75c800-a97f-4464-9a8b-3f65258456bf} + Unity.Tasks + + + \ No newline at end of file diff --git a/ParseCommon/Properties/AssemblyInfo.cs b/ParseCommon/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..f87dfcb5 --- /dev/null +++ b/ParseCommon/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using Parse.Common.Internal; + +// 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("Parse")] +[assembly: AssemblyDescription("Makes accessing services from Parse native and straightforward.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Parse")] +[assembly: AssemblyCopyright("Copyright © Parse 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(true)] diff --git a/Parse/Public/ParseDownloadProgressEventArgs.cs b/ParseCommon/Public/ParseDownloadProgressEventArgs.cs similarity index 75% rename from Parse/Public/ParseDownloadProgressEventArgs.cs rename to ParseCommon/Public/ParseDownloadProgressEventArgs.cs index 2f87769b..8eb815b6 100644 --- a/Parse/Public/ParseDownloadProgressEventArgs.cs +++ b/ParseCommon/Public/ParseDownloadProgressEventArgs.cs @@ -6,12 +6,12 @@ namespace Parse { /// /// Represents download progress. /// - internal class ParseDownloadProgressEventArgs : EventArgs { - internal ParseDownloadProgressEventArgs() { } + public class ParseDownloadProgressEventArgs : EventArgs { + public ParseDownloadProgressEventArgs() { } /// /// Gets the progress (a number between 0.0 and 1.0) of a download. /// - public double Progress { get; internal set; } + public double Progress { get; set; } } } diff --git a/Parse/Public/ParseUploadProgressEventArgs.cs b/ParseCommon/Public/ParseUploadProgressEventArgs.cs similarity index 85% rename from Parse/Public/ParseUploadProgressEventArgs.cs rename to ParseCommon/Public/ParseUploadProgressEventArgs.cs index 6db618d7..700c3cba 100644 --- a/Parse/Public/ParseUploadProgressEventArgs.cs +++ b/ParseCommon/Public/ParseUploadProgressEventArgs.cs @@ -7,11 +7,11 @@ namespace Parse { /// Represents upload progress. /// public class ParseUploadProgressEventArgs : EventArgs { - internal ParseUploadProgressEventArgs() { } + public ParseUploadProgressEventArgs() { } /// /// Gets the progress (a number between 0.0 and 1.0) of an upload. /// - public double Progress { get; internal set; } + public double Progress { get; set; } } } diff --git a/Parse/Public/Utilities/Conversion.cs b/ParseCommon/Public/Utilities/Conversion.cs similarity index 99% rename from Parse/Public/Utilities/Conversion.cs rename to ParseCommon/Public/Utilities/Conversion.cs index edc91614..fbbb259e 100644 --- a/Parse/Public/Utilities/Conversion.cs +++ b/ParseCommon/Public/Utilities/Conversion.cs @@ -1,8 +1,8 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. -using Parse.Internal; using System; using System.Collections.Generic; +using Parse.Common.Internal; namespace Parse.Utilities { /// diff --git a/ParseTest.Unit/JsonTests.cs b/ParseCommon/Test/JsonTests.cs similarity index 99% rename from ParseTest.Unit/JsonTests.cs rename to ParseCommon/Test/JsonTests.cs index 6e38c77b..784b0d97 100644 --- a/ParseTest.Unit/JsonTests.cs +++ b/ParseCommon/Test/JsonTests.cs @@ -1,5 +1,5 @@ using Parse; -using Parse.Internal; +using Parse.Common.Internal; using NUnit.Framework; using System; using System.Collections; diff --git a/ParseCommon/Test/ParseCommon.Test.Unit.NetFx45.csproj b/ParseCommon/Test/ParseCommon.Test.Unit.NetFx45.csproj new file mode 100644 index 00000000..440373c3 --- /dev/null +++ b/ParseCommon/Test/ParseCommon.Test.Unit.NetFx45.csproj @@ -0,0 +1,146 @@ + + + + Debug + AnyCPU + {53E714FF-3EF2-48EB-B305-36E1AB37C485} + Library + Properties + ParseTest + ParseCommon.Test.Unit.NetFx45 + v4.5 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + ..\ + true + + + true + full + false + bin\Debug\ + TRACE;DEBUG;NETFX + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + false + + + + ..\..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll + True + + + ..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll + True + + + ..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll + True + + + ..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll + True + + + ..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll + True + + + ..\..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll + True + + + ..\..\packages\PCLStorage.1.0.2\lib\net45\PCLStorage.dll + True + + + ..\..\packages\PCLStorage.1.0.2\lib\net45\PCLStorage.Abstractions.dll + True + + + + + + + + + + + + + + + + + + + + + + {4bbce4f8-c097-4680-8b07-b69d567eaa5b} + AssemblyLister.NetFx + + + {de07a443-9619-4bd7-b540-41296f8a2959} + ParseCommon.Portable + + + {f3f65351-2ce1-4412-84b4-c36f34eab928} + ParseCore.Portable + + + {43ac01e1-aeb2-474d-856b-e81f27ef640b} + ParseAnalytics.Portable + + + + + + + + False + + + False + + + False + + + False + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/ParseTest.Unit/ProgressTests.cs b/ParseCommon/Test/ProgressTests.cs similarity index 98% rename from ParseTest.Unit/ProgressTests.cs rename to ParseCommon/Test/ProgressTests.cs index 2de32c0f..0438fe21 100644 --- a/ParseTest.Unit/ProgressTests.cs +++ b/ParseCommon/Test/ProgressTests.cs @@ -1,7 +1,7 @@ using Moq; using NUnit.Framework; using Parse; -using Parse.Internal; +using Parse.Core.Internal; using System; using System.Threading; using System.Globalization; diff --git a/ParseCommon/Test/Properties/AssemblyInfo.cs b/ParseCommon/Test/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..c29d1b95 --- /dev/null +++ b/ParseCommon/Test/Properties/AssemblyInfo.cs @@ -0,0 +1,16 @@ +using System.Reflection; + +// 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("ParseTest")] +[assembly: AssemblyDescription("Parse unit test project.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ParseTest")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/ParseCommon/Test/packages.config b/ParseCommon/Test/packages.config new file mode 100644 index 00000000..81ee6a88 --- /dev/null +++ b/ParseCommon/Test/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/ParseCommon/packages.config b/ParseCommon/packages.config new file mode 100644 index 00000000..03278ed1 --- /dev/null +++ b/ParseCommon/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Parse/Internal/Authentication/IParseAuthenticationProvider.cs b/ParseCore/Internal/Authentication/IParseAuthenticationProvider.cs similarity index 94% rename from Parse/Internal/Authentication/IParseAuthenticationProvider.cs rename to ParseCore/Internal/Authentication/IParseAuthenticationProvider.cs index dcd0c2cd..ff5ee0f7 100644 --- a/Parse/Internal/Authentication/IParseAuthenticationProvider.cs +++ b/ParseCore/Internal/Authentication/IParseAuthenticationProvider.cs @@ -4,14 +4,14 @@ using System.Threading; using System.Threading.Tasks; -namespace Parse.Internal { - interface IParseAuthenticationProvider { +namespace Parse.Core.Internal { + public interface IParseAuthenticationProvider { /// /// Authenticates with the service. /// /// The cancellation token. Task> AuthenticateAsync(CancellationToken cancellationToken); - + /// /// Deauthenticates (logs out) the user associated with this provider. This /// call may block. diff --git a/Parse/Internal/Cloud/Controller/IParseCloudCodeController.cs b/ParseCore/Internal/Cloud/Controller/IParseCloudCodeController.cs similarity index 87% rename from Parse/Internal/Cloud/Controller/IParseCloudCodeController.cs rename to ParseCore/Internal/Cloud/Controller/IParseCloudCodeController.cs index c75c1f6e..0b77c1b3 100644 --- a/Parse/Internal/Cloud/Controller/IParseCloudCodeController.cs +++ b/ParseCore/Internal/Cloud/Controller/IParseCloudCodeController.cs @@ -5,8 +5,8 @@ using System.Threading; using System.Threading.Tasks; -namespace Parse.Internal { - interface IParseCloudCodeController { +namespace Parse.Core.Internal { + public interface IParseCloudCodeController { Task CallFunctionAsync(String name, IDictionary parameters, string sessionToken, diff --git a/Parse/Internal/Cloud/Controller/ParseCloudCodeController.cs b/ParseCore/Internal/Cloud/Controller/ParseCloudCodeController.cs similarity index 83% rename from Parse/Internal/Cloud/Controller/ParseCloudCodeController.cs rename to ParseCore/Internal/Cloud/Controller/ParseCloudCodeController.cs index c5f09e45..24d946ef 100644 --- a/Parse/Internal/Cloud/Controller/ParseCloudCodeController.cs +++ b/ParseCore/Internal/Cloud/Controller/ParseCloudCodeController.cs @@ -5,12 +5,13 @@ using System.Threading; using System.Threading.Tasks; using Parse.Utilities; +using Parse.Common.Internal; -namespace Parse.Internal { - internal class ParseCloudCodeController : IParseCloudCodeController { +namespace Parse.Core.Internal { + public class ParseCloudCodeController : IParseCloudCodeController { private readonly IParseCommandRunner commandRunner; - internal ParseCloudCodeController(IParseCommandRunner commandRunner) { + public ParseCloudCodeController(IParseCommandRunner commandRunner) { this.commandRunner = commandRunner; } @@ -22,13 +23,13 @@ public Task CallFunctionAsync(String name, method: "POST", sessionToken: sessionToken, data: NoObjectsEncoder.Instance.Encode(parameters) as IDictionary); - + return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { var decoded = ParseDecoder.Instance.Decode(t.Result.Item2) as IDictionary; if (!decoded.ContainsKey("result")) { return default(T); } - return (T)Conversion.ConvertTo(decoded["result"]); + return Conversion.To(decoded["result"]); }); } } diff --git a/Parse/Internal/Command/IParseCommandRunner.cs b/ParseCore/Internal/Command/IParseCommandRunner.cs similarity index 94% rename from Parse/Internal/Command/IParseCommandRunner.cs rename to ParseCore/Internal/Command/IParseCommandRunner.cs index f99e0f63..b2d4e5ea 100644 --- a/Parse/Internal/Command/IParseCommandRunner.cs +++ b/ParseCore/Internal/Command/IParseCommandRunner.cs @@ -6,8 +6,8 @@ using System.Threading; using System.Threading.Tasks; -namespace Parse.Internal { - internal interface IParseCommandRunner { +namespace Parse.Core.Internal { + public interface IParseCommandRunner { /// /// Executes and convert the result into Dictionary. /// diff --git a/ParseCore/Internal/Command/ParseCommand.cs b/ParseCore/Internal/Command/ParseCommand.cs new file mode 100644 index 00000000..e5d73e09 --- /dev/null +++ b/ParseCore/Internal/Command/ParseCommand.cs @@ -0,0 +1,69 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Parse.Common.Internal; +using System.Linq; + +namespace Parse.Core.Internal { + /// + /// ParseCommand is an with pre-populated + /// headers. + /// + public class ParseCommand : HttpRequest { + public IDictionary DataObject { get; private set; } + public override Stream Data { + get { + if (base.Data != null) { + return base.Data; + } + + return base.Data = (DataObject != null + ? new MemoryStream(Encoding.UTF8.GetBytes(Json.Encode(DataObject))) + : null); + } + set { base.Data = value; } + } + + public ParseCommand(string relativeUri, + string method, + string sessionToken = null, + IList> headers = null, + IDictionary data = null) : this(relativeUri: relativeUri, + method: method, + sessionToken: sessionToken, + headers: headers, + stream: null, + contentType: data != null ? "application/json" : null) { + DataObject = data; + } + + public ParseCommand(string relativeUri, + string method, + string sessionToken = null, + IList> headers = null, + Stream stream = null, + string contentType = null) { + Uri = new Uri(new Uri(ParseClient.CurrentConfiguration.Server), relativeUri); + Method = method; + Data = stream; + Headers = new List>(headers ?? Enumerable.Empty>()); + + if (!string.IsNullOrEmpty(sessionToken)) { + Headers.Add(new KeyValuePair("X-Parse-Session-Token", sessionToken)); + } + if (!string.IsNullOrEmpty(contentType)) { + Headers.Add(new KeyValuePair("Content-Type", contentType)); + } + } + + public ParseCommand(ParseCommand other) { + this.Uri = other.Uri; + this.Method = other.Method; + this.DataObject = other.DataObject; + this.Headers = new List>(other.Headers); + } + } +} diff --git a/ParseCore/Internal/Command/ParseCommandRunner.cs b/ParseCore/Internal/Command/ParseCommandRunner.cs new file mode 100644 index 00000000..04cc9bae --- /dev/null +++ b/ParseCore/Internal/Command/ParseCommandRunner.cs @@ -0,0 +1,108 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Parse.Common.Internal; + +namespace Parse.Core.Internal { + public class ParseCommandRunner : IParseCommandRunner { + private readonly IHttpClient httpClient; + private readonly IInstallationIdController installationIdController; + + public ParseCommandRunner(IHttpClient httpClient, IInstallationIdController installationIdController) { + this.httpClient = httpClient; + this.installationIdController = installationIdController; + } + + public Task>> RunCommandAsync(ParseCommand command, + IProgress uploadProgress = null, + IProgress downloadProgress = null, + CancellationToken cancellationToken = default(CancellationToken)) { + return PrepareCommand(command).ContinueWith(commandTask => { + return httpClient.ExecuteAsync(commandTask.Result, uploadProgress, downloadProgress, cancellationToken).OnSuccess(t => { + cancellationToken.ThrowIfCancellationRequested(); + + var response = t.Result; + var contentString = response.Item2; + int responseCode = (int)response.Item1; + if (responseCode >= 500) { + // Server error, return InternalServerError. + throw new ParseException(ParseException.ErrorCode.InternalServerError, response.Item2); + } else if (contentString != null) { + IDictionary contentJson = null; + try { + if (contentString.StartsWith("[")) { + var arrayJson = Json.Parse(contentString); + contentJson = new Dictionary { { "results", arrayJson } }; + } else { + contentJson = Json.Parse(contentString) as IDictionary; + } + } catch (Exception e) { + throw new ParseException(ParseException.ErrorCode.OtherCause, + "Invalid response from server", e); + } + if (responseCode < 200 || responseCode > 299) { + int code = (int)(contentJson.ContainsKey("code") ? (long)contentJson["code"] : (int)ParseException.ErrorCode.OtherCause); + string error = contentJson.ContainsKey("error") ? + contentJson["error"] as string : + contentString; + throw new ParseException((ParseException.ErrorCode)code, error); + } + return new Tuple>(response.Item1, + contentJson); + } + return new Tuple>(response.Item1, null); + }); + }).Unwrap(); + } + + private const string revocableSessionTokenTrueValue = "1"; + private Task PrepareCommand(ParseCommand command) { + ParseCommand newCommand = new ParseCommand(command); + + Task installationIdTask = installationIdController.GetAsync().ContinueWith(t => { + newCommand.Headers.Add(new KeyValuePair("X-Parse-Installation-Id", t.Result.ToString())); + return newCommand; + }); + + // TODO (richardross): Inject configuration instead of using shared static here. + ParseClient.Configuration configuration = ParseClient.CurrentConfiguration; + newCommand.Headers.Add(new KeyValuePair("X-Parse-Application-Id", configuration.ApplicationId)); + newCommand.Headers.Add(new KeyValuePair("X-Parse-Client-Version", ParseClient.VersionString)); + + if (configuration.AdditionalHTTPHeaders != null) { + foreach (var header in configuration.AdditionalHTTPHeaders) { + newCommand.Headers.Add(header); + } + } + + if (!string.IsNullOrEmpty(configuration.VersionInfo.BuildVersion)) { + newCommand.Headers.Add(new KeyValuePair("X-Parse-App-Build-Version", configuration.VersionInfo.BuildVersion)); + } + if (!string.IsNullOrEmpty(configuration.VersionInfo.DisplayVersion)) { + newCommand.Headers.Add(new KeyValuePair("X-Parse-App-Display-Version", configuration.VersionInfo.DisplayVersion)); + } + if (!string.IsNullOrEmpty(configuration.VersionInfo.OSVersion)) { + newCommand.Headers.Add(new KeyValuePair("X-Parse-OS-Version", configuration.VersionInfo.OSVersion)); + } + + // TODO (richardross): I hate the idea of having this super tightly coupled static variable in here. + // Lets eventually get rid of it. + if (!string.IsNullOrEmpty(ParseClient.MasterKey)) { + newCommand.Headers.Add(new KeyValuePair("X-Parse-Master-Key", ParseClient.MasterKey)); + } else { + newCommand.Headers.Add(new KeyValuePair("X-Parse-Windows-Key", configuration.WindowsKey)); + } + + // TODO (richardross): Inject this instead of using static here. + if (ParseUser.IsRevocableSessionEnabled) { + newCommand.Headers.Add(new KeyValuePair("X-Parse-Revocable-Session", revocableSessionTokenTrueValue)); + } + + return installationIdTask; + } + } +} diff --git a/Parse/Internal/Config/Controller/IParseConfigController.cs b/ParseCore/Internal/Config/Controller/IParseConfigController.cs similarity index 92% rename from Parse/Internal/Config/Controller/IParseConfigController.cs rename to ParseCore/Internal/Config/Controller/IParseConfigController.cs index 667941bb..453482cf 100644 --- a/Parse/Internal/Config/Controller/IParseConfigController.cs +++ b/ParseCore/Internal/Config/Controller/IParseConfigController.cs @@ -4,8 +4,8 @@ using System.Threading.Tasks; using System.Threading; -namespace Parse.Internal { - interface IParseConfigController { +namespace Parse.Core.Internal { + public interface IParseConfigController { /// /// Gets the current config controller. /// diff --git a/Parse/Internal/Config/Controller/IParseCurrentConfigController.cs b/ParseCore/Internal/Config/Controller/IParseCurrentConfigController.cs similarity index 93% rename from Parse/Internal/Config/Controller/IParseCurrentConfigController.cs rename to ParseCore/Internal/Config/Controller/IParseCurrentConfigController.cs index 871ecb02..8fb1b464 100644 --- a/Parse/Internal/Config/Controller/IParseCurrentConfigController.cs +++ b/ParseCore/Internal/Config/Controller/IParseCurrentConfigController.cs @@ -3,8 +3,8 @@ using System; using System.Threading.Tasks; -namespace Parse.Internal { - interface IParseCurrentConfigController { +namespace Parse.Core.Internal { + public interface IParseCurrentConfigController { /// /// Gets the current config async. /// diff --git a/Parse/Internal/Config/Controller/ParseConfigController.cs b/ParseCore/Internal/Config/Controller/ParseConfigController.cs similarity index 73% rename from Parse/Internal/Config/Controller/ParseConfigController.cs rename to ParseCore/Internal/Config/Controller/ParseConfigController.cs index 7ebcafd2..6417e3c1 100644 --- a/Parse/Internal/Config/Controller/ParseConfigController.cs +++ b/ParseCore/Internal/Config/Controller/ParseConfigController.cs @@ -3,19 +3,24 @@ using System; using System.Threading.Tasks; using System.Threading; +using Parse.Common.Internal; -namespace Parse.Internal { +namespace Parse.Core.Internal { /// /// Config controller. /// internal class ParseConfigController : IParseConfigController { + private readonly IParseCommandRunner commandRunner; + /// /// Initializes a new instance of the class. /// - public ParseConfigController() { - CurrentConfigController = new ParseCurrentConfigController(); + public ParseConfigController(IParseCommandRunner commandRunner, IStorageController storageController) { + this.commandRunner = commandRunner; + CurrentConfigController = new ParseCurrentConfigController(storageController); } + public IParseCommandRunner CommandRunner { get; internal set; } public IParseCurrentConfigController CurrentConfigController { get; internal set; } public Task FetchConfigAsync(String sessionToken, CancellationToken cancellationToken) { @@ -24,7 +29,7 @@ public Task FetchConfigAsync(String sessionToken, CancellationToken sessionToken: sessionToken, data: null); - return ParseClient.ParseCommandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(task => { + return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(task => { cancellationToken.ThrowIfCancellationRequested(); return new ParseConfig(task.Result.Item2); }).OnSuccess(task => { diff --git a/Parse/Internal/Config/Controller/ParseCurrentConfigController.cs b/ParseCore/Internal/Config/Controller/ParseCurrentConfigController.cs similarity index 52% rename from Parse/Internal/Config/Controller/ParseCurrentConfigController.cs rename to ParseCore/Internal/Config/Controller/ParseCurrentConfigController.cs index f68a7cc3..89d69ff7 100644 --- a/Parse/Internal/Config/Controller/ParseCurrentConfigController.cs +++ b/ParseCore/Internal/Config/Controller/ParseCurrentConfigController.cs @@ -4,59 +4,69 @@ using System.Threading.Tasks; using System.Threading; using System.Collections.Generic; +using Parse.Common.Internal; -namespace Parse.Internal { +namespace Parse.Core.Internal { /// /// Parse current config controller. /// - class ParseCurrentConfigController : IParseCurrentConfigController { + internal class ParseCurrentConfigController : IParseCurrentConfigController { private const string CurrentConfigKey = "CurrentConfig"; private readonly TaskQueue taskQueue; private ParseConfig currentConfig; + private IStorageController storageController; + /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public ParseCurrentConfigController() { + public ParseCurrentConfigController(IStorageController storageController) { + this.storageController = storageController; + taskQueue = new TaskQueue(); } public Task GetCurrentConfigAsync() { return taskQueue.Enqueue(toAwait => toAwait.ContinueWith(_ => { if (currentConfig == null) { - object tmp; - ParseClient.ApplicationSettings.TryGetValue(CurrentConfigKey, out tmp); - - string propertiesString = tmp as string; - if (propertiesString != null) { - var dictionary = ParseClient.DeserializeJsonString(propertiesString); - currentConfig = new ParseConfig(dictionary); - } else { - currentConfig = new ParseConfig(); - } + return storageController.LoadAsync().OnSuccess(t => { + object tmp; + t.Result.TryGetValue(CurrentConfigKey, out tmp); + + string propertiesString = tmp as string; + if (propertiesString != null) { + var dictionary = ParseClient.DeserializeJsonString(propertiesString); + currentConfig = new ParseConfig(dictionary); + } else { + currentConfig = new ParseConfig(); + } + + return currentConfig; + }); } - return currentConfig; - }), CancellationToken.None); + return Task.FromResult(currentConfig); + }), CancellationToken.None).Unwrap(); } public Task SetCurrentConfigAsync(ParseConfig config) { - return taskQueue.Enqueue(toAwait => toAwait.ContinueWith(_ => { + return taskQueue.Enqueue(toAwait => toAwait.ContinueWith(_ => { currentConfig = config; var jsonObject = ((IJsonConvertible)config).ToJSON(); var jsonString = ParseClient.SerializeJsonString(jsonObject); - ParseClient.ApplicationSettings[CurrentConfigKey] = jsonString; - }), CancellationToken.None); + return storageController.LoadAsync().OnSuccess(t => t.Result.AddAsync(CurrentConfigKey, jsonString)); + }).Unwrap().Unwrap(), CancellationToken.None); } public Task ClearCurrentConfigAsync() { return taskQueue.Enqueue(toAwait => toAwait.ContinueWith(_ => { currentConfig = null; - ParseClient.ApplicationSettings.Remove(CurrentConfigKey); - }), CancellationToken.None); + + return storageController.LoadAsync().OnSuccess(t => t.Result.RemoveAsync(CurrentConfigKey)); + }).Unwrap().Unwrap(), CancellationToken.None); } public Task ClearCurrentConfigInMemoryAsync() { diff --git a/Parse/Internal/Encoding/NoObjectsEncoder.cs b/ParseCore/Internal/Encoding/NoObjectsEncoder.cs similarity index 92% rename from Parse/Internal/Encoding/NoObjectsEncoder.cs rename to ParseCore/Internal/Encoding/NoObjectsEncoder.cs index fbff813c..72630af8 100644 --- a/Parse/Internal/Encoding/NoObjectsEncoder.cs +++ b/ParseCore/Internal/Encoding/NoObjectsEncoder.cs @@ -3,12 +3,12 @@ using System; using System.Collections.Generic; -namespace Parse.Internal { +namespace Parse.Core.Internal { /// /// A that throws an exception if it attempts to encode /// a /// - internal class NoObjectsEncoder : ParseEncoder { + public class NoObjectsEncoder : ParseEncoder { // This class isn't really a Singleton, but since it has no state, it's more efficient to get // the default instance. private static readonly NoObjectsEncoder instance = new NoObjectsEncoder(); diff --git a/Parse/Internal/Encoding/ParseDecoder.cs b/ParseCore/Internal/Encoding/ParseDecoder.cs similarity index 91% rename from Parse/Internal/Encoding/ParseDecoder.cs rename to ParseCore/Internal/Encoding/ParseDecoder.cs index 6bcb39eb..250f435c 100644 --- a/Parse/Internal/Encoding/ParseDecoder.cs +++ b/ParseCore/Internal/Encoding/ParseDecoder.cs @@ -6,8 +6,8 @@ using System.Globalization; using Parse.Utilities; -namespace Parse.Internal { - internal class ParseDecoder { +namespace Parse.Core.Internal { + public class ParseDecoder { // This class isn't really a Singleton, but since it has no state, it's more efficient to get // the default instance. private static readonly ParseDecoder instance = new ParseDecoder(); @@ -60,8 +60,8 @@ public object Decode(object data) { } if (typeString == "GeoPoint") { - return new ParseGeoPoint((double)Conversion.ConvertTo(dict["latitude"]), - (double)Conversion.ConvertTo(dict["longitude"])); + return new ParseGeoPoint(Conversion.To(dict["latitude"]), + Conversion.To(dict["longitude"])); } if (typeString == "Object") { @@ -93,7 +93,7 @@ protected virtual object DecodePointer(string className, string objectId) { return ParseObject.CreateWithoutData(className, objectId); } - internal static DateTime ParseDate(string input) { + public static DateTime ParseDate(string input) { // TODO(hallucinogen): Figure out if we should be more flexible with the date formats // we accept. return DateTime.ParseExact(input, diff --git a/Parse/Internal/Encoding/ParseEncoder.cs b/ParseCore/Internal/Encoding/ParseEncoder.cs similarity index 83% rename from Parse/Internal/Encoding/ParseEncoder.cs rename to ParseCore/Internal/Encoding/ParseEncoder.cs index ce28c7d7..285ead0d 100644 --- a/Parse/Internal/Encoding/ParseEncoder.cs +++ b/ParseCore/Internal/Encoding/ParseEncoder.cs @@ -5,14 +5,21 @@ using System.Globalization; using System.Linq; using Parse.Utilities; +using Parse.Common.Internal; -namespace Parse.Internal { +namespace Parse.Core.Internal { /// /// A ParseEncoder can be used to transform objects such as into JSON /// data structures. /// /// - internal abstract class ParseEncoder { + public abstract class ParseEncoder { +#if UNITY + private static readonly bool isCompiledByIL2CPP = AppDomain.CurrentDomain.FriendlyName.Equals("IL2CPP Root Domain"); +#else + private static readonly bool isCompiledByIL2CPP = false; +#endif + public static bool IsValidType(object value) { return value == null || ReflectionHelpers.IsPrimitive(value.GetType()) || @@ -24,8 +31,8 @@ value is ParseGeoPoint || value is ParseRelationBase || value is DateTime || value is byte[] || - Conversion.ConvertTo>(value) is IDictionary || - Conversion.ConvertTo>(value) is IList; + Conversion.As>(value) != null || + Conversion.As>(value) != null; } public object Encode(object value) { @@ -56,7 +63,7 @@ public object Encode(object value) { return jsonConvertible.ToJSON(); } - var dict = Conversion.ConvertTo>(value) as IDictionary; + var dict = Conversion.As>(value); if (dict != null) { var json = new Dictionary(); foreach (var pair in dict) { @@ -65,7 +72,7 @@ public object Encode(object value) { return json; } - var list = Conversion.ConvertTo>(value) as IList; + var list = Conversion.As>(value); if (list != null) { return EncodeList(list); } @@ -83,13 +90,11 @@ public object Encode(object value) { private object EncodeList(IList list) { var newArray = new List(); -#if UNITY // We need to explicitly cast `list` to `List` rather than // `IList` because IL2CPP is stricter than the usual Unity AOT compiler pipeline. - if (PlatformHooks.IsCompiledByIL2CPP && list.GetType().IsArray) { + if (isCompiledByIL2CPP && list.GetType().IsArray) { list = new List(list); } -#endif foreach (var item in list) { if (!IsValidType(item)) { throw new ArgumentException("Invalid type for value in an array"); diff --git a/Parse/Internal/Encoding/ParseObjectCoder.cs b/ParseCore/Internal/Encoding/ParseObjectCoder.cs similarity index 95% rename from Parse/Internal/Encoding/ParseObjectCoder.cs rename to ParseCore/Internal/Encoding/ParseObjectCoder.cs index c564ee31..aa535009 100644 --- a/Parse/Internal/Encoding/ParseObjectCoder.cs +++ b/ParseCore/Internal/Encoding/ParseObjectCoder.cs @@ -3,8 +3,9 @@ using System; using System.Collections.Generic; -namespace Parse.Internal { - internal class ParseObjectCoder { +namespace Parse.Core.Internal { + // TODO: (richardross) refactor entire parse coder interfaces. + public class ParseObjectCoder { private static readonly ParseObjectCoder instance = new ParseObjectCoder(); public static ParseObjectCoder Instance { get { diff --git a/Parse/Internal/Encoding/PointerOrLocalIdEncoder.cs b/ParseCore/Internal/Encoding/PointerOrLocalIdEncoder.cs similarity index 93% rename from Parse/Internal/Encoding/PointerOrLocalIdEncoder.cs rename to ParseCore/Internal/Encoding/PointerOrLocalIdEncoder.cs index 6b599a43..d560740f 100644 --- a/Parse/Internal/Encoding/PointerOrLocalIdEncoder.cs +++ b/ParseCore/Internal/Encoding/PointerOrLocalIdEncoder.cs @@ -3,12 +3,12 @@ using System; using System.Collections.Generic; -namespace Parse.Internal { +namespace Parse.Core.Internal { /// /// A that encode as pointers. If the object /// does not have an , uses a local id. /// - internal class PointerOrLocalIdEncoder : ParseEncoder { + public class PointerOrLocalIdEncoder : ParseEncoder { // This class isn't really a Singleton, but since it has no state, it's more efficient to get // the default instance. private static readonly PointerOrLocalIdEncoder instance = new PointerOrLocalIdEncoder(); diff --git a/Parse/Internal/File/Controller/IParseFileController.cs b/ParseCore/Internal/File/Controller/IParseFileController.cs similarity index 88% rename from Parse/Internal/File/Controller/IParseFileController.cs rename to ParseCore/Internal/File/Controller/IParseFileController.cs index bbd0b1d9..4580560b 100644 --- a/Parse/Internal/File/Controller/IParseFileController.cs +++ b/ParseCore/Internal/File/Controller/IParseFileController.cs @@ -5,8 +5,8 @@ using System.Threading; using System.Threading.Tasks; -namespace Parse.Internal { - interface IParseFileController { +namespace Parse.Core.Internal { + public interface IParseFileController { Task SaveAsync(FileState state, Stream dataStream, String sessionToken, diff --git a/Parse/Internal/File/Controller/ParseFileController.cs b/ParseCore/Internal/File/Controller/ParseFileController.cs similarity index 91% rename from Parse/Internal/File/Controller/ParseFileController.cs rename to ParseCore/Internal/File/Controller/ParseFileController.cs index a766bc90..a6b729b9 100644 --- a/Parse/Internal/File/Controller/ParseFileController.cs +++ b/ParseCore/Internal/File/Controller/ParseFileController.cs @@ -4,12 +4,13 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +using Parse.Common.Internal; -namespace Parse.Internal { - internal class ParseFileController : IParseFileController { +namespace Parse.Core.Internal { + public class ParseFileController : IParseFileController { private readonly IParseCommandRunner commandRunner; - internal ParseFileController(IParseCommandRunner commandRunner) { + public ParseFileController(IParseCommandRunner commandRunner) { this.commandRunner = commandRunner; } diff --git a/Parse/Internal/File/State/FileState.cs b/ParseCore/Internal/File/State/FileState.cs similarity index 80% rename from Parse/Internal/File/State/FileState.cs rename to ParseCore/Internal/File/State/FileState.cs index e47f016d..00c8123c 100644 --- a/Parse/Internal/File/State/FileState.cs +++ b/ParseCore/Internal/File/State/FileState.cs @@ -2,14 +2,14 @@ using System; -namespace Parse.Internal { - internal class FileState { +namespace Parse.Core.Internal { + public class FileState { private const string ParseFileSecureScheme = "https"; private const string ParseFileSecureDomain = "files.parsetfss.com"; - public string Name { get; internal set; } - public string MimeType { get; internal set; } - public Uri Url { get; internal set; } + public string Name { get; set; } + public string MimeType { get; set; } + public Uri Url { get; set; } public Uri SecureUrl { get { Uri uri = Url; diff --git a/ParseCore/Internal/IParseCorePlugins.cs b/ParseCore/Internal/IParseCorePlugins.cs new file mode 100644 index 00000000..fd8f5cd9 --- /dev/null +++ b/ParseCore/Internal/IParseCorePlugins.cs @@ -0,0 +1,25 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using Parse.Common.Internal; +using System; + +namespace Parse.Core.Internal { + public interface IParseCorePlugins { + void Reset(); + + IHttpClient HttpClient { get; } + IParseCommandRunner CommandRunner { get; } + IStorageController StorageController { get; } + + IParseCloudCodeController CloudCodeController { get; } + IParseConfigController ConfigController { get; } + IParseFileController FileController { get; } + IParseObjectController ObjectController { get; } + IParseQueryController QueryController { get; } + IParseSessionController SessionController { get; } + IParseUserController UserController { get; } + IObjectSubclassingController SubclassingController { get; } + IParseCurrentUserController CurrentUserController { get; } + IInstallationIdController InstallationIdController { get; } + } +} \ No newline at end of file diff --git a/Parse/Internal/Installation/Controller/IInstallationIdController.cs b/ParseCore/Internal/InstallationId/Controller/IInstallationIdController.cs similarity index 83% rename from Parse/Internal/Installation/Controller/IInstallationIdController.cs rename to ParseCore/Internal/InstallationId/Controller/IInstallationIdController.cs index 61bf597a..5fb191f4 100644 --- a/Parse/Internal/Installation/Controller/IInstallationIdController.cs +++ b/ParseCore/Internal/InstallationId/Controller/IInstallationIdController.cs @@ -4,23 +4,23 @@ using System.Threading; using System.Threading.Tasks; -namespace Parse.Internal { - interface IInstallationIdController { +namespace Parse.Core.Internal { + public interface IInstallationIdController { /// /// Sets current installationId and saves it to local storage. /// /// The installationId to be saved. - void Set(Guid? installationId); + Task SetAsync(Guid? installationId); /// /// Gets current installationId from local storage. Generates a none exists. /// /// Current installationId. - Guid? Get(); + Task GetAsync(); /// /// Clears current installationId from memory and local storage. /// - void Clear(); + Task ClearAsync(); } } diff --git a/ParseCore/Internal/InstallationId/Controller/InstallationIdController.cs b/ParseCore/Internal/InstallationId/Controller/InstallationIdController.cs new file mode 100644 index 00000000..6ce3ba9b --- /dev/null +++ b/ParseCore/Internal/InstallationId/Controller/InstallationIdController.cs @@ -0,0 +1,68 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using Parse.Common.Internal; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Parse.Core.Internal { + public class InstallationIdController : IInstallationIdController { + private const string InstallationIdKey = "InstallationId"; + private readonly object mutex = new object(); + private Guid? installationId; + + private readonly IStorageController storageController; + public InstallationIdController(IStorageController storageController) { + this.storageController = storageController; + } + + public Task SetAsync(Guid? installationId) { + lock (mutex) { + Task saveTask; + + if (installationId == null) { + saveTask = storageController + .LoadAsync() + .OnSuccess(storage => storage.Result.RemoveAsync(InstallationIdKey)) + .Unwrap(); + } else { + saveTask = storageController + .LoadAsync() + .OnSuccess(storage => storage.Result.AddAsync(InstallationIdKey, installationId.ToString())) + .Unwrap(); + } + this.installationId = installationId; + return saveTask; + } + } + + public Task GetAsync() { + lock (mutex) { + if (installationId != null) { + return Task.FromResult(installationId); + } + } + + return storageController + .LoadAsync() + .OnSuccess, Task>(s => { + object id; + s.Result.TryGetValue(InstallationIdKey, out id); + try { + lock (mutex) { + installationId = new Guid((string)id); + return Task.FromResult(installationId); + } + } catch (Exception) { + var newInstallationId = Guid.NewGuid(); + return SetAsync(newInstallationId).OnSuccess(_ => newInstallationId); + } + }) + .Unwrap(); + } + + public Task ClearAsync() { + return SetAsync(null); + } + } +} diff --git a/Parse/Internal/Object/Controller/IParseObjectController.cs b/ParseCore/Internal/Object/Controller/IParseObjectController.cs similarity index 93% rename from Parse/Internal/Object/Controller/IParseObjectController.cs rename to ParseCore/Internal/Object/Controller/IParseObjectController.cs index 73dde353..5914e727 100644 --- a/Parse/Internal/Object/Controller/IParseObjectController.cs +++ b/ParseCore/Internal/Object/Controller/IParseObjectController.cs @@ -5,8 +5,8 @@ using System.Threading; using System.Threading.Tasks; -namespace Parse.Internal { - interface IParseObjectController { +namespace Parse.Core.Internal { + public interface IParseObjectController { Task FetchAsync(IObjectState state, string sessionToken, CancellationToken cancellationToken); diff --git a/Parse/Internal/Object/Controller/IParseObjectCurrentController.cs b/ParseCore/Internal/Object/Controller/IParseObjectCurrentController.cs similarity index 95% rename from Parse/Internal/Object/Controller/IParseObjectCurrentController.cs rename to ParseCore/Internal/Object/Controller/IParseObjectCurrentController.cs index 47b9d576..e4df82c9 100644 --- a/Parse/Internal/Object/Controller/IParseObjectCurrentController.cs +++ b/ParseCore/Internal/Object/Controller/IParseObjectCurrentController.cs @@ -4,14 +4,14 @@ using System.Threading; using System.Threading.Tasks; -namespace Parse.Internal { +namespace Parse.Core.Internal { /// /// IParseObjectCurrentController controls the single-instance /// persistence used throughout the code-base. Sample usages are and /// . /// /// Type of object being persisted. - internal interface IParseObjectCurrentController where T : ParseObject { + public interface IParseObjectCurrentController where T : ParseObject { /// /// Persists current . /// diff --git a/Parse/Internal/Object/Controller/ParseObjectController.cs b/ParseCore/Internal/Object/Controller/ParseObjectController.cs similarity index 97% rename from Parse/Internal/Object/Controller/ParseObjectController.cs rename to ParseCore/Internal/Object/Controller/ParseObjectController.cs index 1b399a54..ab9dbef7 100644 --- a/Parse/Internal/Object/Controller/ParseObjectController.cs +++ b/ParseCore/Internal/Object/Controller/ParseObjectController.cs @@ -6,12 +6,13 @@ using System.Threading; using System.Threading.Tasks; using Parse.Utilities; +using Parse.Common.Internal; -namespace Parse.Internal { - internal class ParseObjectController : IParseObjectController { +namespace Parse.Core.Internal { + public class ParseObjectController : IParseObjectController { private readonly IParseCommandRunner commandRunner; - internal ParseObjectController(IParseCommandRunner commandRunner) { + public ParseObjectController(IParseCommandRunner commandRunner) { this.commandRunner = commandRunner; } diff --git a/Parse/Internal/Object/State/IObjectState.cs b/ParseCore/Internal/Object/State/IObjectState.cs similarity index 85% rename from Parse/Internal/Object/State/IObjectState.cs rename to ParseCore/Internal/Object/State/IObjectState.cs index ca25e63b..a713325c 100644 --- a/Parse/Internal/Object/State/IObjectState.cs +++ b/ParseCore/Internal/Object/State/IObjectState.cs @@ -3,8 +3,8 @@ using System; using System.Collections.Generic; -namespace Parse.Internal { - internal interface IObjectState : IEnumerable> { +namespace Parse.Core.Internal { + public interface IObjectState : IEnumerable> { bool IsNew { get; } string ClassName { get; } string ObjectId { get; } diff --git a/Parse/Internal/Object/State/MutableObjectState.cs b/ParseCore/Internal/Object/State/MutableObjectState.cs similarity index 86% rename from Parse/Internal/Object/State/MutableObjectState.cs rename to ParseCore/Internal/Object/State/MutableObjectState.cs index dbcca269..a385d6bd 100644 --- a/Parse/Internal/Object/State/MutableObjectState.cs +++ b/ParseCore/Internal/Object/State/MutableObjectState.cs @@ -4,17 +4,17 @@ using System.Linq; using System.Collections.Generic; -namespace Parse.Internal { - internal class MutableObjectState : IObjectState { - public bool IsNew { get; internal set; } - public string ClassName { get; internal set; } - public string ObjectId { get; internal set; } - public DateTime? UpdatedAt { get; internal set; } - public DateTime? CreatedAt { get; internal set; } +namespace Parse.Core.Internal { + public class MutableObjectState : IObjectState { + public bool IsNew { get; set; } + public string ClassName { get; set; } + public string ObjectId { get; set; } + public DateTime? UpdatedAt { get; set; } + public DateTime? CreatedAt { get; set; } // Initialize serverData to avoid further null checking. private IDictionary serverData = new Dictionary(); - internal IDictionary ServerData { + public IDictionary ServerData { get { return serverData; } diff --git a/Parse/Internal/Object/Subclassing/IObjectSubclassingController.cs b/ParseCore/Internal/Object/Subclassing/IObjectSubclassingController.cs similarity index 76% rename from Parse/Internal/Object/Subclassing/IObjectSubclassingController.cs rename to ParseCore/Internal/Object/Subclassing/IObjectSubclassingController.cs index 0d118a39..a81e4a78 100644 --- a/Parse/Internal/Object/Subclassing/IObjectSubclassingController.cs +++ b/ParseCore/Internal/Object/Subclassing/IObjectSubclassingController.cs @@ -4,8 +4,8 @@ using System.Text; using System.Threading.Tasks; -namespace Parse.Internal { - internal interface IObjectSubclassingController { +namespace Parse.Core.Internal { + public interface IObjectSubclassingController { String GetClassName(Type type); Type GetType(String className); @@ -14,6 +14,8 @@ internal interface IObjectSubclassingController { void RegisterSubclass(Type t); void UnregisterSubclass(Type t); + void AddRegisterHook(Type t, Action action); + ParseObject Instantiate(String className); IDictionary GetPropertyMappings(String className); } diff --git a/Parse/Internal/Object/Subclassing/ObjectSubclassInfo.cs b/ParseCore/Internal/Object/Subclassing/ObjectSubclassInfo.cs similarity index 94% rename from Parse/Internal/Object/Subclassing/ObjectSubclassInfo.cs rename to ParseCore/Internal/Object/Subclassing/ObjectSubclassInfo.cs index b5be7551..ae20863a 100644 --- a/Parse/Internal/Object/Subclassing/ObjectSubclassInfo.cs +++ b/ParseCore/Internal/Object/Subclassing/ObjectSubclassInfo.cs @@ -5,12 +5,9 @@ using System.Threading; using System.Threading.Tasks; using System.Reflection; +using Parse.Common.Internal; -#if UNITY -using TypeInfo = System.Type; -#endif - -namespace Parse.Internal { +namespace Parse.Core.Internal { internal class ObjectSubclassInfo { public ObjectSubclassInfo(Type type, ConstructorInfo constructor) { TypeInfo = type.GetTypeInfo(); diff --git a/Parse/Internal/Object/Subclassing/ObjectSubclassingController.cs b/ParseCore/Internal/Object/Subclassing/ObjectSubclassingController.cs similarity index 88% rename from Parse/Internal/Object/Subclassing/ObjectSubclassingController.cs rename to ParseCore/Internal/Object/Subclassing/ObjectSubclassingController.cs index 8cb0c301..b44d8dcc 100644 --- a/Parse/Internal/Object/Subclassing/ObjectSubclassingController.cs +++ b/ParseCore/Internal/Object/Subclassing/ObjectSubclassingController.cs @@ -3,12 +3,9 @@ using System.Linq; using System.Reflection; using System.Threading; +using Parse.Common.Internal; -#if UNITY -using TypeInfo = System.Type; -#endif - -namespace Parse.Internal { +namespace Parse.Core.Internal { internal class ObjectSubclassingController : IObjectSubclassingController { // Class names starting with _ are documented to be reserved. Use this one // here to allow us to 'inherit' certain properties. @@ -16,12 +13,12 @@ internal class ObjectSubclassingController : IObjectSubclassingController { private readonly ReaderWriterLockSlim mutex; private readonly IDictionary registeredSubclasses; - private IDictionary registerActions; + private Dictionary registerActions; - public ObjectSubclassingController(IDictionary actions) { + public ObjectSubclassingController() { mutex = new ReaderWriterLockSlim(); registeredSubclasses = new Dictionary(); - registerActions = actions.ToDictionary(p => GetClassName(p.Key), p => p.Value); + registerActions = new Dictionary(); // Register the ParseObject subclass, so we get access to the ACL, // objectId, and other ParseFieldName properties. @@ -99,8 +96,13 @@ public void RegisterSubclass(Type type) { mutex.ExitWriteLock(); } - Action toPerform = null; - if (registerActions.TryGetValue(className, out toPerform)) { + Action toPerform; + + mutex.EnterReadLock(); + registerActions.TryGetValue(className, out toPerform); + mutex.ExitReadLock(); + + if (toPerform != null) { toPerform(); } } @@ -111,6 +113,12 @@ public void UnregisterSubclass(Type type) { mutex.ExitWriteLock(); } + public void AddRegisterHook(Type t, Action action) { + mutex.EnterWriteLock(); + registerActions.Add(GetClassName(t), action); + mutex.ExitWriteLock(); + } + public ParseObject Instantiate(String className) { ObjectSubclassInfo info = null; @@ -134,5 +142,6 @@ public IDictionary GetPropertyMappings(String className) { return info.PropertyMappings; } + } } diff --git a/Parse/Internal/Operation/IParseFieldOperation.cs b/ParseCore/Internal/Operation/IParseFieldOperation.cs similarity index 96% rename from Parse/Internal/Operation/IParseFieldOperation.cs rename to ParseCore/Internal/Operation/IParseFieldOperation.cs index a5a4b553..96dfb0c3 100644 --- a/Parse/Internal/Operation/IParseFieldOperation.cs +++ b/ParseCore/Internal/Operation/IParseFieldOperation.cs @@ -1,13 +1,13 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. -namespace Parse.Internal { +namespace Parse.Core.Internal { /// /// A ParseFieldOperation represents a modification to a value in a ParseObject. /// For example, setting, deleting, or incrementing a value are all different kinds of /// ParseFieldOperations. ParseFieldOperations themselves can be considered to be /// immutable. /// - interface IParseFieldOperation { + public interface IParseFieldOperation { /// /// Converts the ParseFieldOperation to a data structure that can be converted to JSON and sent to /// Parse as part of a save operation. @@ -32,7 +32,7 @@ interface IParseFieldOperation { /// Returns a new estimated value based on a previous value and this operation. This /// value is not intended to be sent to Parse, but it is used locally on the client to /// inspect the most likely current value for a field. - /// + /// /// The key and object are used solely for ParseRelation to be able to construct objects /// that refer back to their parents. /// diff --git a/Parse/Internal/Operation/ParseAddOperation.cs b/ParseCore/Internal/Operation/ParseAddOperation.cs similarity index 87% rename from Parse/Internal/Operation/ParseAddOperation.cs rename to ParseCore/Internal/Operation/ParseAddOperation.cs index 29d03fa8..45491cb7 100644 --- a/Parse/Internal/Operation/ParseAddOperation.cs +++ b/ParseCore/Internal/Operation/ParseAddOperation.cs @@ -6,8 +6,8 @@ using System.Linq; using Parse.Utilities; -namespace Parse.Internal { - class ParseAddOperation : IParseFieldOperation { +namespace Parse.Core.Internal { + public class ParseAddOperation : IParseFieldOperation { private ReadOnlyCollection objects; public ParseAddOperation(IEnumerable objects) { this.objects = new ReadOnlyCollection(objects.ToList()); @@ -29,7 +29,7 @@ public IParseFieldOperation MergeWithPrevious(IParseFieldOperation previous) { } if (previous is ParseSetOperation) { var setOp = (ParseSetOperation)previous; - var oldList = (IList)Conversion.ConvertTo>(setOp.Value); + var oldList = Conversion.To>(setOp.Value); return new ParseSetOperation(oldList.Concat(objects).ToList()); } if (previous is ParseAddOperation) { @@ -42,7 +42,7 @@ public object Apply(object oldValue, string key) { if (oldValue == null) { return objects.ToList(); } - var oldList = (IList)Conversion.ConvertTo>(oldValue); + var oldList = Conversion.To>(oldValue); return oldList.Concat(objects).ToList(); } diff --git a/Parse/Internal/Operation/ParseAddUniqueOperation.cs b/ParseCore/Internal/Operation/ParseAddUniqueOperation.cs similarity index 89% rename from Parse/Internal/Operation/ParseAddUniqueOperation.cs rename to ParseCore/Internal/Operation/ParseAddUniqueOperation.cs index 638cbd8b..aa89f256 100644 --- a/Parse/Internal/Operation/ParseAddUniqueOperation.cs +++ b/ParseCore/Internal/Operation/ParseAddUniqueOperation.cs @@ -6,8 +6,8 @@ using System.Linq; using Parse.Utilities; -namespace Parse.Internal { - class ParseAddUniqueOperation : IParseFieldOperation { +namespace Parse.Core.Internal { + public class ParseAddUniqueOperation : IParseFieldOperation { private ReadOnlyCollection objects; public ParseAddUniqueOperation(IEnumerable objects) { this.objects = new ReadOnlyCollection(objects.Distinct().ToList()); @@ -29,7 +29,7 @@ public IParseFieldOperation MergeWithPrevious(IParseFieldOperation previous) { } if (previous is ParseSetOperation) { var setOp = (ParseSetOperation)previous; - var oldList = (IList)Conversion.ConvertTo>(setOp.Value); + var oldList = Conversion.To>(setOp.Value); var result = this.Apply(oldList, null); return new ParseSetOperation(result); } @@ -44,7 +44,7 @@ public object Apply(object oldValue, string key) { if (oldValue == null) { return objects.ToList(); } - var newList = ((IList)Conversion.ConvertTo>(oldValue)).ToList(); + var newList = Conversion.To>(oldValue).ToList(); var comparer = ParseFieldOperations.ParseObjectComparer; foreach (var objToAdd in objects) { if (objToAdd is ParseObject) { diff --git a/Parse/Internal/Operation/ParseDeleteOperation.cs b/ParseCore/Internal/Operation/ParseDeleteOperation.cs similarity index 91% rename from Parse/Internal/Operation/ParseDeleteOperation.cs rename to ParseCore/Internal/Operation/ParseDeleteOperation.cs index ba1e7062..a498e832 100644 --- a/Parse/Internal/Operation/ParseDeleteOperation.cs +++ b/ParseCore/Internal/Operation/ParseDeleteOperation.cs @@ -2,11 +2,11 @@ using System.Collections.Generic; -namespace Parse.Internal { +namespace Parse.Core.Internal { /// /// An operation where a field is deleted from the object. /// - class ParseDeleteOperation : IParseFieldOperation { + public class ParseDeleteOperation : IParseFieldOperation { internal static readonly object DeleteToken = new object(); private static ParseDeleteOperation _Instance = new ParseDeleteOperation(); public static ParseDeleteOperation Instance { diff --git a/Parse/Internal/Operation/ParseFieldOperations.cs b/ParseCore/Internal/Operation/ParseFieldOperations.cs similarity index 92% rename from Parse/Internal/Operation/ParseFieldOperations.cs rename to ParseCore/Internal/Operation/ParseFieldOperations.cs index c49d4ef9..68fdf6b4 100644 --- a/Parse/Internal/Operation/ParseFieldOperations.cs +++ b/ParseCore/Internal/Operation/ParseFieldOperations.cs @@ -3,8 +3,8 @@ using System; using System.Collections.Generic; -namespace Parse.Internal { - class ParseObjectIdComparer : IEqualityComparer { +namespace Parse.Core.Internal { + public class ParseObjectIdComparer : IEqualityComparer { bool IEqualityComparer.Equals(object p1, object p2) { var parseObj1 = p1 as ParseObject; var parseObj2 = p2 as ParseObject; diff --git a/Parse/Internal/Operation/ParseIncrementOperation.cs b/ParseCore/Internal/Operation/ParseIncrementOperation.cs similarity index 99% rename from Parse/Internal/Operation/ParseIncrementOperation.cs rename to ParseCore/Internal/Operation/ParseIncrementOperation.cs index 23d9c228..ba7a3682 100644 --- a/Parse/Internal/Operation/ParseIncrementOperation.cs +++ b/ParseCore/Internal/Operation/ParseIncrementOperation.cs @@ -4,8 +4,8 @@ using System.Collections.Generic; using System.Linq; -namespace Parse.Internal { - class ParseIncrementOperation : IParseFieldOperation { +namespace Parse.Core.Internal { + public class ParseIncrementOperation : IParseFieldOperation { private static readonly IDictionary, Func> adders; static ParseIncrementOperation() { diff --git a/Parse/Internal/Operation/ParseRelationOperation.cs b/ParseCore/Internal/Operation/ParseRelationOperation.cs similarity index 98% rename from Parse/Internal/Operation/ParseRelationOperation.cs rename to ParseCore/Internal/Operation/ParseRelationOperation.cs index 72267608..dfecf1cf 100644 --- a/Parse/Internal/Operation/ParseRelationOperation.cs +++ b/ParseCore/Internal/Operation/ParseRelationOperation.cs @@ -7,8 +7,8 @@ using System.Text; using System.Threading.Tasks; -namespace Parse.Internal { - class ParseRelationOperation : IParseFieldOperation { +namespace Parse.Core.Internal { + public class ParseRelationOperation : IParseFieldOperation { private readonly IList adds; private readonly IList removes; private readonly string targetClassName; diff --git a/Parse/Internal/Operation/ParseRemoveOperation.cs b/ParseCore/Internal/Operation/ParseRemoveOperation.cs similarity index 95% rename from Parse/Internal/Operation/ParseRemoveOperation.cs rename to ParseCore/Internal/Operation/ParseRemoveOperation.cs index 5458c173..ca745355 100644 --- a/Parse/Internal/Operation/ParseRemoveOperation.cs +++ b/ParseCore/Internal/Operation/ParseRemoveOperation.cs @@ -7,8 +7,8 @@ using Parse.Utilities; -namespace Parse.Internal { - class ParseRemoveOperation : IParseFieldOperation { +namespace Parse.Core.Internal { + public class ParseRemoveOperation : IParseFieldOperation { private ReadOnlyCollection objects; public ParseRemoveOperation(IEnumerable objects) { this.objects = new ReadOnlyCollection(objects.Distinct().ToList()); diff --git a/Parse/Internal/Operation/ParseSetOperation.cs b/ParseCore/Internal/Operation/ParseSetOperation.cs similarity index 88% rename from Parse/Internal/Operation/ParseSetOperation.cs rename to ParseCore/Internal/Operation/ParseSetOperation.cs index 477a4206..4a76c0c2 100644 --- a/Parse/Internal/Operation/ParseSetOperation.cs +++ b/ParseCore/Internal/Operation/ParseSetOperation.cs @@ -1,7 +1,7 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. -namespace Parse.Internal { - class ParseSetOperation : IParseFieldOperation { +namespace Parse.Core.Internal { + public class ParseSetOperation : IParseFieldOperation { public ParseSetOperation(object value) { Value = value; } diff --git a/Parse/Internal/ParseCorePlugins.cs b/ParseCore/Internal/ParseCorePlugins.cs similarity index 61% rename from Parse/Internal/ParseCorePlugins.cs rename to ParseCore/Internal/ParseCorePlugins.cs index ab0a959c..c9f4e1bf 100644 --- a/Parse/Internal/ParseCorePlugins.cs +++ b/ParseCore/Internal/ParseCorePlugins.cs @@ -4,14 +4,24 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using Parse.Internal; +using Parse.Common.Internal; +using Parse.Core.Internal; -namespace Parse.Internal { - internal class ParseCorePlugins { - private static readonly ParseCorePlugins instance = new ParseCorePlugins(); - public static ParseCorePlugins Instance { +namespace Parse.Core.Internal { + public class ParseCorePlugins : IParseCorePlugins { + private static readonly object instanceMutex = new object(); + private static IParseCorePlugins instance; + public static IParseCorePlugins Instance { get { - return instance; + lock (instanceMutex) { + instance = instance ?? new ParseCorePlugins(); + return instance; + } + } + set { + lock (instanceMutex) { + instance = value; + } } } @@ -19,7 +29,10 @@ public static ParseCorePlugins Instance { #region Server Controllers - private IParseAnalyticsController analyticsController; + private IHttpClient httpClient; + private IParseCommandRunner commandRunner; + private IStorageController storageController; + private IParseCloudCodeController cloudCodeController; private IParseConfigController configController; private IParseFileController fileController; @@ -27,44 +40,73 @@ public static ParseCorePlugins Instance { private IParseQueryController queryController; private IParseSessionController sessionController; private IParseUserController userController; - private IParsePushController pushController; - private IParsePushChannelsController pushChannelsController; private IObjectSubclassingController subclassingController; #endregion #region Current Instance Controller - private IInstallationIdController installationIdController; - private IParseCurrentInstallationController currentInstallationController; private IParseCurrentUserController currentUserController; + private IInstallationIdController installationIdController; #endregion - internal void Reset() { + public void Reset() { lock (mutex) { - AnalyticsController = null; + HttpClient = null; + CommandRunner = null; + StorageController = null; + CloudCodeController = null; FileController = null; ObjectController = null; SessionController = null; UserController = null; + SubclassingController = null; - CurrentInstallationController = null; CurrentUserController = null; + InstallationIdController = null; + } + } + + public IHttpClient HttpClient { + get { + lock (mutex) { + httpClient = httpClient ?? new HttpClient(); + return httpClient; + } + } + set { + lock (mutex) { + httpClient = value; + } + } + } + + public IParseCommandRunner CommandRunner { + get { + lock (mutex) { + commandRunner = commandRunner ?? new ParseCommandRunner(HttpClient, InstallationIdController); + return commandRunner; + } + } + set { + lock (mutex) { + commandRunner = value; + } } } - public IParseAnalyticsController AnalyticsController { + public IStorageController StorageController { get { lock (mutex) { - analyticsController = analyticsController ?? new ParseAnalyticsController(ParseClient.ParseCommandRunner); - return analyticsController; + storageController = storageController ?? new StorageController(); + return storageController; } } - internal set { + set { lock (mutex) { - analyticsController = value; + storageController = value; } } } @@ -72,11 +114,11 @@ internal set { public IParseCloudCodeController CloudCodeController { get { lock (mutex) { - cloudCodeController = cloudCodeController ?? new ParseCloudCodeController(ParseClient.ParseCommandRunner); + cloudCodeController = cloudCodeController ?? new ParseCloudCodeController(CommandRunner); return cloudCodeController; } } - internal set { + set { lock (mutex) { cloudCodeController = value; } @@ -86,11 +128,11 @@ internal set { public IParseFileController FileController { get { lock (mutex) { - fileController = fileController ?? new ParseFileController(ParseClient.ParseCommandRunner); + fileController = fileController ?? new ParseFileController(CommandRunner); return fileController; } } - internal set { + set { lock (mutex) { fileController = value; } @@ -101,12 +143,12 @@ public IParseConfigController ConfigController { get { lock (mutex) { if (configController == null) { - configController = new ParseConfigController(); + configController = new ParseConfigController(CommandRunner, StorageController); } return configController; } } - internal set { + set { lock (mutex) { configController = value; } @@ -116,11 +158,11 @@ internal set { public IParseObjectController ObjectController { get { lock (mutex) { - objectController = objectController ?? new ParseObjectController(ParseClient.ParseCommandRunner); + objectController = objectController ?? new ParseObjectController(CommandRunner); return objectController; } } - internal set { + set { lock (mutex) { objectController = value; } @@ -131,13 +173,12 @@ public IParseQueryController QueryController { get { lock (mutex) { if (queryController == null) { - queryController = new ParseQueryController(); + queryController = new ParseQueryController(CommandRunner); } return queryController; } } - - internal set { + set { lock (mutex) { queryController = value; } @@ -147,12 +188,11 @@ internal set { public IParseSessionController SessionController { get { lock (mutex) { - sessionController = sessionController ?? new ParseSessionController(ParseClient.ParseCommandRunner); + sessionController = sessionController ?? new ParseSessionController(CommandRunner); return sessionController; } } - - internal set { + set { lock (mutex) { sessionController = value; } @@ -162,41 +202,44 @@ internal set { public IParseUserController UserController { get { lock (mutex) { - userController = userController ?? new ParseUserController(ParseClient.ParseCommandRunner); + userController = userController ?? new ParseUserController(CommandRunner); return userController; } } - internal set { + set { lock (mutex) { userController = value; } } } - public IParsePushController PushController { + public IParseCurrentUserController CurrentUserController { get { lock (mutex) { - pushController = pushController ?? new ParsePushController(); - return pushController; + currentUserController = currentUserController ?? new ParseCurrentUserController(StorageController); + return currentUserController; } } - internal set { + set { lock (mutex) { - pushController = value; + currentUserController = value; } } } - public IParsePushChannelsController PushChannelsController { + public IObjectSubclassingController SubclassingController { get { lock (mutex) { - pushChannelsController = pushChannelsController ?? new ParsePushChannelsController(); - return pushChannelsController; + if (subclassingController == null) { + subclassingController = new ObjectSubclassingController(); + subclassingController.AddRegisterHook(typeof(ParseUser), () => CurrentUserController.ClearFromMemory()); + } + return subclassingController; } } - internal set { + set { lock (mutex) { - pushChannelsController = value; + subclassingController = value; } } } @@ -204,64 +247,15 @@ internal set { public IInstallationIdController InstallationIdController { get { lock (mutex) { - installationIdController = installationIdController ?? new InstallationIdController(); + installationIdController = installationIdController ?? new InstallationIdController(StorageController); return installationIdController; } } - internal set { + set { lock (mutex) { installationIdController = value; } } } - - public IParseCurrentInstallationController CurrentInstallationController { - get { - lock (mutex) { - if (currentInstallationController == null) { - currentInstallationController = new ParseCurrentInstallationController(InstallationIdController); - } - return currentInstallationController; - } - } - internal set { - lock (mutex) { - currentInstallationController = value; - } - } - } - - public IParseCurrentUserController CurrentUserController { - get { - lock (mutex) { - currentUserController = currentUserController ?? new ParseCurrentUserController(); - return currentUserController; - } - } - internal set { - lock (mutex) { - currentUserController = value; - } - } - } - - public IObjectSubclassingController SubclassingController { - get { - lock (mutex) { - subclassingController = subclassingController ?? new ObjectSubclassingController(new Dictionary { - // Do these as explicit closures instead of method references, - // as we should still lazy-load the controllers. - { typeof(ParseUser), () => CurrentUserController.ClearFromMemory() }, - { typeof(ParseInstallation), () => CurrentInstallationController.ClearFromMemory() } - }); - return subclassingController; - } - } - internal set { - lock (mutex) { - subclassingController = value; - } - } - } } } diff --git a/Parse/Internal/Query/Controller/IParseQueryController.cs b/ParseCore/Internal/Query/Controller/IParseQueryController.cs similarity index 92% rename from Parse/Internal/Query/Controller/IParseQueryController.cs rename to ParseCore/Internal/Query/Controller/IParseQueryController.cs index 4c6730e3..9af77417 100644 --- a/Parse/Internal/Query/Controller/IParseQueryController.cs +++ b/ParseCore/Internal/Query/Controller/IParseQueryController.cs @@ -6,8 +6,8 @@ using System.Threading; using System.Threading.Tasks; -namespace Parse.Internal { - interface IParseQueryController { +namespace Parse.Core.Internal { + public interface IParseQueryController { Task> FindAsync(ParseQuery query, ParseUser user, CancellationToken cancellationToken) where T : ParseObject; diff --git a/Parse/Internal/Query/Controller/ParseQueryController.cs b/ParseCore/Internal/Query/Controller/ParseQueryController.cs similarity index 89% rename from Parse/Internal/Query/Controller/ParseQueryController.cs rename to ParseCore/Internal/Query/Controller/ParseQueryController.cs index 298fb8fd..572c3fd4 100644 --- a/Parse/Internal/Query/Controller/ParseQueryController.cs +++ b/ParseCore/Internal/Query/Controller/ParseQueryController.cs @@ -6,9 +6,16 @@ using System.Collections.ObjectModel; using System.Threading; using System.Threading.Tasks; +using Parse.Common.Internal; -namespace Parse.Internal { +namespace Parse.Core.Internal { internal class ParseQueryController : IParseQueryController { + private readonly IParseCommandRunner commandRunner; + + public ParseQueryController(IParseCommandRunner commandRunner) { + this.commandRunner = commandRunner; + } + public Task> FindAsync(ParseQuery query, ParseUser user, CancellationToken cancellationToken) where T : ParseObject { @@ -66,7 +73,7 @@ private Task> FindAsync(string className, sessionToken: sessionToken, data: null); - return ParseClient.ParseCommandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { + return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { return t.Result.Item2; }); } diff --git a/Parse/Internal/Session/Controller/IParseSessionController.cs b/ParseCore/Internal/Session/Controller/IParseSessionController.cs similarity index 83% rename from Parse/Internal/Session/Controller/IParseSessionController.cs rename to ParseCore/Internal/Session/Controller/IParseSessionController.cs index 03ad97b0..1b2f4711 100644 --- a/Parse/Internal/Session/Controller/IParseSessionController.cs +++ b/ParseCore/Internal/Session/Controller/IParseSessionController.cs @@ -4,12 +4,14 @@ using System.Threading; using System.Threading.Tasks; -namespace Parse.Internal { - interface IParseSessionController { +namespace Parse.Core.Internal { + public interface IParseSessionController { Task GetSessionAsync(string sessionToken, CancellationToken cancellationToken); Task RevokeAsync(string sessionToken, CancellationToken cancellationToken); Task UpgradeToRevocableSessionAsync(string sessionToken, CancellationToken cancellationToken); + + bool IsRevocableSessionToken(string sessionToken); } } diff --git a/Parse/Internal/Session/Controller/ParseSessionController.cs b/ParseCore/Internal/Session/Controller/ParseSessionController.cs similarity index 85% rename from Parse/Internal/Session/Controller/ParseSessionController.cs rename to ParseCore/Internal/Session/Controller/ParseSessionController.cs index 2847b475..28669f08 100644 --- a/Parse/Internal/Session/Controller/ParseSessionController.cs +++ b/ParseCore/Internal/Session/Controller/ParseSessionController.cs @@ -4,12 +4,13 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Parse.Common.Internal; -namespace Parse.Internal { - internal class ParseSessionController : IParseSessionController { +namespace Parse.Core.Internal { + public class ParseSessionController : IParseSessionController { private readonly IParseCommandRunner commandRunner; - internal ParseSessionController(IParseCommandRunner commandRunner) { + public ParseSessionController(IParseCommandRunner commandRunner) { this.commandRunner = commandRunner; } @@ -43,5 +44,9 @@ public Task UpgradeToRevocableSessionAsync(string sessionToken, Ca return ParseObjectCoder.Instance.Decode(t.Result.Item2, ParseDecoder.Instance); }); } + + public bool IsRevocableSessionToken(string sessionToken) { + return sessionToken.Contains("r:"); + } } } diff --git a/Parse/Internal/User/Controller/IParseCurrentUserController.cs b/ParseCore/Internal/User/Controller/IParseCurrentUserController.cs similarity index 80% rename from Parse/Internal/User/Controller/IParseCurrentUserController.cs rename to ParseCore/Internal/User/Controller/IParseCurrentUserController.cs index b2996e02..0a35ed82 100644 --- a/Parse/Internal/User/Controller/IParseCurrentUserController.cs +++ b/ParseCore/Internal/User/Controller/IParseCurrentUserController.cs @@ -4,8 +4,8 @@ using System.Threading; using System.Threading.Tasks; -namespace Parse.Internal { - interface IParseCurrentUserController : IParseObjectCurrentController { +namespace Parse.Core.Internal { + public interface IParseCurrentUserController : IParseObjectCurrentController { Task GetCurrentSessionTokenAsync(CancellationToken cancellationToken); Task LogOutAsync(CancellationToken cancellationToken); diff --git a/Parse/Internal/User/Controller/IParseUserController.cs b/ParseCore/Internal/User/Controller/IParseUserController.cs similarity index 92% rename from Parse/Internal/User/Controller/IParseUserController.cs rename to ParseCore/Internal/User/Controller/IParseUserController.cs index ce2a7a20..46f9d01a 100644 --- a/Parse/Internal/User/Controller/IParseUserController.cs +++ b/ParseCore/Internal/User/Controller/IParseUserController.cs @@ -5,12 +5,12 @@ using System.Threading; using System.Threading.Tasks; -namespace Parse.Internal { - internal interface IParseUserController { +namespace Parse.Core.Internal { + public interface IParseUserController { Task SignUpAsync(IObjectState state, IDictionary operations, CancellationToken cancellationToken); - + Task LogInAsync(string username, string password, CancellationToken cancellationToken); diff --git a/Parse/Internal/User/Controller/ParseCurrentUserController.cs b/ParseCore/Internal/User/Controller/ParseCurrentUserController.cs similarity index 61% rename from Parse/Internal/User/Controller/ParseCurrentUserController.cs rename to ParseCore/Internal/User/Controller/ParseCurrentUserController.cs index f070e4a4..54799c9f 100644 --- a/Parse/Internal/User/Controller/ParseCurrentUserController.cs +++ b/ParseCore/Internal/User/Controller/ParseCurrentUserController.cs @@ -5,14 +5,21 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Parse.Common.Internal; -namespace Parse.Internal { - class ParseCurrentUserController : IParseCurrentUserController { +namespace Parse.Core.Internal { + public class ParseCurrentUserController : IParseCurrentUserController { private readonly object mutex = new object(); private readonly TaskQueue taskQueue = new TaskQueue(); + private IStorageController storageController; + + public ParseCurrentUserController(IStorageController storageController) { + this.storageController = storageController; + } + private ParseUser currentUser; - internal ParseUser CurrentUser { + public ParseUser CurrentUser { get { lock (mutex) { return currentUser; @@ -28,8 +35,12 @@ internal ParseUser CurrentUser { public Task SetAsync(ParseUser user, CancellationToken cancellationToken) { return taskQueue.Enqueue(toAwait => { return toAwait.ContinueWith(_ => { + Task saveTask = null; if (user == null) { - ParseClient.ApplicationSettings.Remove("CurrentUser"); + saveTask = storageController + .LoadAsync() + .OnSuccess(t => t.Result.RemoveAsync("CurrentUser")) + .Unwrap(); } else { // TODO (hallucinogen): we need to use ParseCurrentCoder instead of this janky encoding var data = user.ServerDataToJSONObjectForSerialization(); @@ -41,10 +52,15 @@ public Task SetAsync(ParseUser user, CancellationToken cancellationToken) { data["updatedAt"] = user.UpdatedAt.Value.ToString(ParseClient.DateFormatStrings.First()); } - ParseClient.ApplicationSettings["CurrentUser"] = Json.Encode(data); + saveTask = storageController + .LoadAsync() + .OnSuccess(t => t.Result.AddAsync("CurrentUser", Json.Encode(data))) + .Unwrap(); } CurrentUser = user; - }); + + return saveTask; + }).Unwrap(); }, cancellationToken); } @@ -60,20 +76,22 @@ public Task GetAsync(CancellationToken cancellationToken) { } return taskQueue.Enqueue(toAwait => { - return toAwait.ContinueWith(t => { - object temp; - ParseClient.ApplicationSettings.TryGetValue("CurrentUser", out temp); - var userDataString = temp as string; - ParseUser user = null; - if (userDataString != null) { - var userData = Json.Parse(userDataString) as IDictionary; - var state = ParseObjectCoder.Instance.Decode(userData, ParseDecoder.Instance); - user = ParseObject.FromState(state, "_User"); - } + return toAwait.ContinueWith(_ => { + return storageController.LoadAsync().OnSuccess(t => { + object temp; + t.Result.TryGetValue("CurrentUser", out temp); + var userDataString = temp as string; + ParseUser user = null; + if (userDataString != null) { + var userData = Json.Parse(userDataString) as IDictionary; + var state = ParseObjectCoder.Instance.Decode(userData, ParseDecoder.Instance); + user = ParseObject.FromState(state, "_User"); + } - CurrentUser = user; - return user; - }); + CurrentUser = user; + return user; + }); + }).Unwrap(); }, cancellationToken); } @@ -83,7 +101,9 @@ public Task ExistsAsync(CancellationToken cancellationToken) { } return taskQueue.Enqueue(toAwait => { - return toAwait.ContinueWith(t => ParseClient.ApplicationSettings.ContainsKey("CurrentUser")); + return toAwait.ContinueWith(_ => + storageController.LoadAsync().OnSuccess(t => t.Result.ContainsKey("CurrentUser")) + ).Unwrap(); }, cancellationToken); } @@ -101,7 +121,11 @@ public void ClearFromDisk() { lock (mutex) { ClearFromMemory(); - ParseClient.ApplicationSettings.Remove("CurrentUser"); + taskQueue.Enqueue(toAwait => { + return toAwait.ContinueWith(_ => { + return storageController.LoadAsync().OnSuccess(t => t.Result.RemoveAsync("CurrentUser")); + }).Unwrap().Unwrap(); + }, CancellationToken.None); } } diff --git a/Parse/Internal/User/Controller/ParseUserController.cs b/ParseCore/Internal/User/Controller/ParseUserController.cs similarity index 95% rename from Parse/Internal/User/Controller/ParseUserController.cs rename to ParseCore/Internal/User/Controller/ParseUserController.cs index 9c712de8..ceb11aab 100644 --- a/Parse/Internal/User/Controller/ParseUserController.cs +++ b/ParseCore/Internal/User/Controller/ParseUserController.cs @@ -4,12 +4,13 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Parse.Common.Internal; -namespace Parse.Internal { - internal class ParseUserController : IParseUserController { +namespace Parse.Core.Internal { + public class ParseUserController : IParseUserController { private readonly IParseCommandRunner commandRunner; - internal ParseUserController(IParseCommandRunner commandRunner) { + public ParseUserController(IParseCommandRunner commandRunner) { this.commandRunner = commandRunner; } diff --git a/ParseCore/Internal/Utilities/ParseConfigExtensions.cs b/ParseCore/Internal/Utilities/ParseConfigExtensions.cs new file mode 100644 index 00000000..39d52f56 --- /dev/null +++ b/ParseCore/Internal/Utilities/ParseConfigExtensions.cs @@ -0,0 +1,22 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.Collections.Generic; + +namespace Parse.Core.Internal { + /// + /// So here's the deal. We have a lot of internal APIs for ParseObject, ParseUser, etc. + /// + /// These cannot be 'internal' anymore if we are fully modularizing things out, because + /// they are no longer a part of the same library, especially as we create things like + /// Installation inside push library. + /// + /// So this class contains a bunch of extension methods that can live inside another + /// namespace, which 'wrap' the intenral APIs that already exist. + /// + public static class ParseConfigExtensions { + public static ParseConfig Create(IDictionary fetchedConfig) { + return new ParseConfig(fetchedConfig); + } + } +} diff --git a/ParseCore/Internal/Utilities/ParseFileExtensions.cs b/ParseCore/Internal/Utilities/ParseFileExtensions.cs new file mode 100644 index 00000000..8b2b1bf3 --- /dev/null +++ b/ParseCore/Internal/Utilities/ParseFileExtensions.cs @@ -0,0 +1,22 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.Collections.Generic; + +namespace Parse.Core.Internal { + /// + /// So here's the deal. We have a lot of internal APIs for ParseObject, ParseUser, etc. + /// + /// These cannot be 'internal' anymore if we are fully modularizing things out, because + /// they are no longer a part of the same library, especially as we create things like + /// Installation inside push library. + /// + /// So this class contains a bunch of extension methods that can live inside another + /// namespace, which 'wrap' the intenral APIs that already exist. + /// + public static class ParseFileExtensions { + public static ParseFile Create(string name, Uri uri, string mimeType = null) { + return new ParseFile(name, uri, mimeType); + } + } +} diff --git a/ParseCore/Internal/Utilities/ParseObjectExtensions.cs b/ParseCore/Internal/Utilities/ParseObjectExtensions.cs new file mode 100644 index 00000000..00a42f3b --- /dev/null +++ b/ParseCore/Internal/Utilities/ParseObjectExtensions.cs @@ -0,0 +1,50 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.Collections.Generic; + +namespace Parse.Core.Internal { + /// + /// So here's the deal. We have a lot of internal APIs for ParseObject, ParseUser, etc. + /// + /// These cannot be 'internal' anymore if we are fully modularizing things out, because + /// they are no longer a part of the same library, especially as we create things like + /// Installation inside push library. + /// + /// So this class contains a bunch of extension methods that can live inside another + /// namespace, which 'wrap' the intenral APIs that already exist. + /// + public static class ParseObjectExtensions { + public static T FromState(IObjectState state, string defaultClassName) where T : ParseObject { + return ParseObject.FromState(state, defaultClassName); + } + + public static IObjectState GetState(this ParseObject obj) { + return obj.State; + } + + public static void HandleFetchResult(this ParseObject obj, IObjectState serverState) { + obj.HandleFetchResult(serverState); + } + + public static IDictionary GetCurrentOperations(this ParseObject obj) { + return obj.CurrentOperations; + } + + public static IEnumerable DeepTraversal(object root, bool traverseParseObjects = false, bool yieldRoot = false) { + return ParseObject.DeepTraversal(root, traverseParseObjects, yieldRoot); + } + + public static void SetIfDifferent(this ParseObject obj, string key, T value) { + obj.SetIfDifferent(key, value); + } + + public static IDictionary ServerDataToJSONObjectForSerialization(this ParseObject obj) { + return obj.ServerDataToJSONObjectForSerialization(); + } + + public static void Set(this ParseObject obj, string key, object value) { + obj.Set(key, value); + } + } +} diff --git a/ParseCore/Internal/Utilities/ParseQueryExtensions.cs b/ParseCore/Internal/Utilities/ParseQueryExtensions.cs new file mode 100644 index 00000000..04d1d19e --- /dev/null +++ b/ParseCore/Internal/Utilities/ParseQueryExtensions.cs @@ -0,0 +1,30 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.Collections.Generic; + +namespace Parse.Core.Internal { + /// + /// So here's the deal. We have a lot of internal APIs for ParseObject, ParseUser, etc. + /// + /// These cannot be 'internal' anymore if we are fully modularizing things out, because + /// they are no longer a part of the same library, especially as we create things like + /// Installation inside push library. + /// + /// So this class contains a bunch of extension methods that can live inside another + /// namespace, which 'wrap' the intenral APIs that already exist. + /// + public static class ParseQueryExtensions { + public static string GetClassName(this ParseQuery query) where T: ParseObject { + return query.ClassName; + } + + public static IDictionary BuildParameters(this ParseQuery query) where T: ParseObject { + return query.BuildParameters(false); + } + + public static object GetConstraint(this ParseQuery query, string key) where T : ParseObject { + return query.GetConstraint(key); + } + } +} diff --git a/ParseCore/Internal/Utilities/ParseRelationExtensions.cs b/ParseCore/Internal/Utilities/ParseRelationExtensions.cs new file mode 100644 index 00000000..c37f6b35 --- /dev/null +++ b/ParseCore/Internal/Utilities/ParseRelationExtensions.cs @@ -0,0 +1,30 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.Collections.Generic; + +namespace Parse.Core.Internal { + /// + /// So here's the deal. We have a lot of internal APIs for ParseObject, ParseUser, etc. + /// + /// These cannot be 'internal' anymore if we are fully modularizing things out, because + /// they are no longer a part of the same library, especially as we create things like + /// Installation inside push library. + /// + /// So this class contains a bunch of extension methods that can live inside another + /// namespace, which 'wrap' the intenral APIs that already exist. + /// + public static class ParseRelationExtensions { + public static ParseRelation Create(ParseObject parent, string childKey) where T : ParseObject { + return new ParseRelation(parent, childKey); + } + + public static ParseRelation Create(ParseObject parent, string childKey, string targetClassName) where T: ParseObject { + return new ParseRelation(parent, childKey, targetClassName); + } + + public static string GetTargetClassName(this ParseRelation relation) where T : ParseObject { + return relation.TargetClassName; + } + } +} diff --git a/ParseCore/Internal/Utilities/ParseSessionExtensions.cs b/ParseCore/Internal/Utilities/ParseSessionExtensions.cs new file mode 100644 index 00000000..fec49ce3 --- /dev/null +++ b/ParseCore/Internal/Utilities/ParseSessionExtensions.cs @@ -0,0 +1,28 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Parse.Core.Internal { + /// + /// So here's the deal. We have a lot of internal APIs for ParseObject, ParseUser, etc. + /// + /// These cannot be 'internal' anymore if we are fully modularizing things out, because + /// they are no longer a part of the same library, especially as we create things like + /// Installation inside push library. + /// + /// So this class contains a bunch of extension methods that can live inside another + /// namespace, which 'wrap' the intenral APIs that already exist. + /// + public static class ParseSessionExtensions { + public static Task UpgradeToRevocableSessionAsync(string sessionToken, CancellationToken cancellationToken) { + return ParseSession.UpgradeToRevocableSessionAsync(sessionToken, cancellationToken); + } + + public static Task RevokeAsync(string sessionToken, CancellationToken cancellationToken) { + return ParseSession.RevokeAsync(sessionToken, cancellationToken); + } + } +} diff --git a/ParseCore/Internal/Utilities/ParseUserExtensions.cs b/ParseCore/Internal/Utilities/ParseUserExtensions.cs new file mode 100644 index 00000000..ae15ab7d --- /dev/null +++ b/ParseCore/Internal/Utilities/ParseUserExtensions.cs @@ -0,0 +1,48 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Parse.Core.Internal { + /// + /// So here's the deal. We have a lot of internal APIs for ParseObject, ParseUser, etc. + /// + /// These cannot be 'internal' anymore if we are fully modularizing things out, because + /// they are no longer a part of the same library, especially as we create things like + /// Installation inside push library. + /// + /// So this class contains a bunch of extension methods that can live inside another + /// namespace, which 'wrap' the intenral APIs that already exist. + /// + public static class ParseUserExtensions { + public static IDictionary> GetAuthData(this ParseUser user) { + return user.AuthData; + } + + public static Task UnlinkFromAsync(this ParseUser user, string authType, CancellationToken cancellationToken) { + return user.UnlinkFromAsync(authType, cancellationToken); + } + + public static Task LogInWithAsync(string authType, CancellationToken cancellationToken) { + return ParseUser.LogInWithAsync(authType, cancellationToken); + } + + public static Task LogInWithAsync(string authType, IDictionary data, CancellationToken cancellationToken) { + return ParseUser.LogInWithAsync(authType, data, cancellationToken); + } + + public static Task LinkWithAsync(this ParseUser user, string authType, CancellationToken cancellationToken) { + return user.LinkWithAsync(authType, cancellationToken); + } + + public static Task LinkWithAsync(this ParseUser user, string authType, IDictionary data, CancellationToken cancellationToken) { + return user.LinkWithAsync(authType, data, cancellationToken); + } + + public static Task UpgradeToRevocableSessionAsync(this ParseUser user, CancellationToken cancellationToken) { + return user.UpgradeToRevocableSessionAsync(cancellationToken); + } + } +} diff --git a/ParseCore/Internal/Utilities/XamarinAttributes.cs b/ParseCore/Internal/Utilities/XamarinAttributes.cs new file mode 100644 index 00000000..d68a8c12 --- /dev/null +++ b/ParseCore/Internal/Utilities/XamarinAttributes.cs @@ -0,0 +1,59 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Generic; +using Parse; +using Parse.Common.Internal; + +namespace Parse.Core.Internal { + /// + /// A reimplementation of Xamarin's PreserveAttribute. + /// This allows us to support AOT and linking for Xamarin platforms. + /// + [AttributeUsage(AttributeTargets.All)] + internal class PreserveAttribute : Attribute { + public bool AllMembers; + public bool Conditional; + } + + [AttributeUsage(AttributeTargets.All)] + internal class LinkerSafeAttribute : Attribute { + public LinkerSafeAttribute() { } + } + + [Preserve(AllMembers = true)] + internal class PreserveWrapperTypes { + /// + /// Exists to ensure that generic types are AOT-compiled for the conversions we support. + /// Any new value types that we add support for will need to be registered here. + /// The method itself is never called, but by virtue of the Preserve attribute being set + /// on the class, these types will be AOT-compiled. + /// + /// This also applies to Unity. + /// + private static List CreateWrapperTypes() { + return new List { + (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), + (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), + (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), + (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), + (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), + (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), + (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), + (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), + (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), + (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), + (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), + (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), + (Action)(() => ParseCloud.CallFunctionAsync(null, null, CancellationToken.None)), + (Action)(() => ParseCloud.CallFunctionAsync>(null, null, CancellationToken.None)), + (Action)(() => ParseCloud.CallFunctionAsync>(null, null, CancellationToken.None)), + + typeof(FlexibleListWrapper), + typeof(FlexibleListWrapper), + typeof(FlexibleDictionaryWrapper), + typeof(FlexibleDictionaryWrapper), + }; + } + } +} diff --git a/Parse/Parse.NetFx45.csproj b/ParseCore/ParseCore.Portable.csproj similarity index 51% rename from Parse/Parse.NetFx45.csproj rename to ParseCore/ParseCore.Portable.csproj index 2399fa47..66c1f657 100644 --- a/Parse/Parse.NetFx45.csproj +++ b/ParseCore/ParseCore.Portable.csproj @@ -2,15 +2,18 @@ + 11.0 Debug AnyCPU - {18203A69-17C8-4EA4-8098-65D982ACDDCB} + {F3F65351-2CE1-4412-84B4-C36F34EAB928} Library Properties - Parse - Parse.NetFx45 + Parse.Core + Parse.Core v4.5 + Profile78 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} ..\ true @@ -18,69 +21,40 @@ true full false - bin\Debug\NetFx45\ + bin\Debug\ DEBUG;TRACE prompt 4 - bin\Debug\NetFx45\Parse.NetFx45.xml + AnyCPU + bin\Debug\Parse.Core.xml pdbonly true - bin\Release\NetFx45\ + bin\Release\ TRACE prompt 4 - bin\Release\NetFx45\Parse.NetFx45.xml + bin\Release\Parse.Core.xml - - - - - - - - - - - - - - - - - - - - - True - True - Settings.settings - - - - - - - - - SettingsSingleFileGenerator - Settings.Designer.cs - + + + + - + {de07a443-9619-4bd7-b540-41296f8a2959} - Parse + ParseCommon.Portable false - + - + + + + + + + + + + {196457aa-9ba0-40bc-91a3-21baad6f4169} + ParseCommon.Unity + + + {8473bef6-7086-4414-aad6-264967a7fe75} + Unity.Compat + + + {ce75c800-a97f-4464-9a8b-3f65258456bf} + Unity.Tasks + + + \ No newline at end of file diff --git a/ParseCore/Properties/AssemblyInfo.cs b/ParseCore/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..f87dfcb5 --- /dev/null +++ b/ParseCore/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using Parse.Common.Internal; + +// 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("Parse")] +[assembly: AssemblyDescription("Makes accessing services from Parse native and straightforward.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Parse")] +[assembly: AssemblyCopyright("Copyright © Parse 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(true)] diff --git a/Parse/Public/ParseACL.cs b/ParseCore/Public/ParseACL.cs similarity index 99% rename from Parse/Public/ParseACL.cs rename to ParseCore/Public/ParseACL.cs index 1129af8c..26079690 100644 --- a/Parse/Public/ParseACL.cs +++ b/ParseCore/Public/ParseACL.cs @@ -3,7 +3,8 @@ using System; using System.Collections.Generic; using System.Linq; -using Parse.Internal; +using Parse.Core.Internal; +using Parse.Common.Internal; namespace Parse { /// diff --git a/Parse/Public/ParseClassNameAttribute.cs b/ParseCore/Public/ParseClassNameAttribute.cs similarity index 100% rename from Parse/Public/ParseClassNameAttribute.cs rename to ParseCore/Public/ParseClassNameAttribute.cs diff --git a/Parse/Public/ParseClient.cs b/ParseCore/Public/ParseClient.cs similarity index 74% rename from Parse/Public/ParseClient.cs rename to ParseCore/Public/ParseClient.cs index 05e49c38..7e0b8a2c 100644 --- a/Parse/Public/ParseClient.cs +++ b/ParseCore/Public/ParseClient.cs @@ -1,6 +1,7 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. -using Parse.Internal; +using Parse.Common.Internal; +using Parse.Core.Internal; using System; using System.Collections.Generic; using System.Globalization; @@ -31,56 +32,70 @@ public static partial class ParseClient { /// /// Represents the configuration of the Parse SDK. /// - public struct Configuration { + public struct Configuration { + /// + /// In the event that you would like to use the Parse SDK + /// from a completely portable project, with no platform-specific library required, + /// to get full access to all of our features available on Parse.com + /// (A/B testing, slow queries, etc.), you must set the values of this struct + /// to be appropriate for your platform. + /// + /// Any values set here will overwrite those that are automatically configured by + /// any platform-specific migration library your app includes. + /// + public struct VersionInformation { + /// + /// The build number of your app. + /// + public String BuildVersion { get; set; } + + /// + /// The human friendly version number of your happ. + /// + public String DisplayVersion { get; set; } + + /// + /// The operating system version of the platform the SDK is operating in.. + /// + public String OSVersion { get; set; } + } + /// /// The Parse.com application ID of your app. /// - public String ApplicationId { get; set; } - - /// - /// The Parse.com API server to connect to. - /// - /// Only needs to be set if you're using another server than https://api.parse.com/1. - /// + public String ApplicationId { get; set; } + + /// + /// The Parse.com API server to connect to. + /// + /// Only needs to be set if you're using another server than https://api.parse.com/1. + /// public String Server { get; set; } /// /// The Parse.com .NET key for your app. /// public String WindowsKey { get; set; } + + /// + /// Gets or sets additional HTTP headers to be sent with network requests from the SDK. + /// + public IDictionary AdditionalHTTPHeaders { get; set; } + + /// + /// The version information of your application environment. + /// + public VersionInformation VersionInfo { get; set; } } private static readonly object mutex = new object(); - private static readonly string[] assemblyNames = { - "Parse.Phone", "Parse.WinRT", "Parse.NetFx45", "Parse.iOS", "Parse.Android", "Parse.Unity" - }; static ParseClient() { - Type platformHookType = GetParseType("PlatformHooks"); - if (platformHookType == null) { - throw new InvalidOperationException("You must include a reference to a platform-specific Parse library."); - } - platformHooks = Activator.CreateInstance(platformHookType) as IPlatformHooks; - commandRunner = new ParseCommandRunner(platformHooks.HttpClient); - versionString = "net-" + platformHooks.SDKName + Version; - } + versionString = "net-portable-" + Version; - private static Type GetParseType(string name) { - foreach (var assembly in assemblyNames) { - Type type = Type.GetType(string.Format("Parse.{0}, {1}", name, assembly)); - if (type != null) { - return type; - } - } - return null; + ParseModuleController.Instance.ScanForModules(); } - private static readonly IPlatformHooks platformHooks; - internal static IPlatformHooks PlatformHooks { get { return platformHooks; } } - - private static readonly IParseCommandRunner commandRunner; - internal static IParseCommandRunner ParseCommandRunner { get { return commandRunner; } } - /// /// The current configuration that parse has been initialized with. /// @@ -127,26 +142,15 @@ public static void Initialize(string applicationId, string dotnetKey) { /// The configuration to initialize Parse with. /// public static void Initialize(Configuration configuration) { - lock (mutex) { - configuration.Server = configuration.Server ?? "https://api.parse.com/1/"; + lock (mutex) { + configuration.Server = configuration.Server ?? "https://api.parse.com/1/"; CurrentConfiguration = configuration; ParseObject.RegisterSubclass(); - ParseObject.RegisterSubclass(); ParseObject.RegisterSubclass(); ParseObject.RegisterSubclass(); - // Give platform-specific libraries a chance to do additional initialization. - PlatformHooks.Initialize(); - } - } - - internal static Guid? InstallationId { - get { - return ParseCorePlugins.Instance.InstallationIdController.Get(); - } - set { - ParseCorePlugins.Instance.InstallationIdController.Set(value); + ParseModuleController.Instance.ParseDidInitialize(); } } @@ -176,11 +180,5 @@ internal static IDictionary DeserializeJsonString(string jsonDat internal static string SerializeJsonString(IDictionary jsonData) { return Json.Encode(jsonData); } - - internal static IDictionary ApplicationSettings { - get { - return PlatformHooks.ApplicationSettings; - } - } } } diff --git a/Parse/Public/ParseCloud.cs b/ParseCore/Public/ParseCloud.cs similarity index 98% rename from Parse/Public/ParseCloud.cs rename to ParseCore/Public/ParseCloud.cs index 57483c85..d8cf45c8 100644 --- a/Parse/Public/ParseCloud.cs +++ b/ParseCore/Public/ParseCloud.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Parse.Internal; +using Parse.Core.Internal; namespace Parse { /// @@ -14,7 +14,7 @@ namespace Parse { /// For example, this sample code calls the /// "validateGame" Cloud Function and calls processResponse if the call succeeded /// and handleError if it failed. - /// + /// /// /// var result = /// await ParseCloud.CallFunctionAsync<IDictionary<string, object>>("validateGame", parameters); diff --git a/Parse/Public/ParseConfig.cs b/ParseCore/Public/ParseConfig.cs similarity index 91% rename from Parse/Public/ParseConfig.cs rename to ParseCore/Public/ParseConfig.cs index 0ca3ff62..edee95e6 100644 --- a/Parse/Public/ParseConfig.cs +++ b/ParseCore/Public/ParseConfig.cs @@ -5,8 +5,9 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; -using Parse.Internal; +using Parse.Core.Internal; using Parse.Utilities; +using Parse.Common.Internal; namespace Parse { /// @@ -36,8 +37,8 @@ internal static void ClearCurrentConfigInMemory() { ConfigController.CurrentConfigController.ClearCurrentConfigInMemoryAsync().Wait(); } - private static IParseConfigController ConfigController { - get { return ParseCorePlugins.Instance.ConfigController; } + private static IParseConfigController ConfigController { + get { return ParseCorePlugins.Instance.ConfigController; } } internal ParseConfig() @@ -78,7 +79,7 @@ public static Task GetAsync(CancellationToken cancellationToken) { /// The property under this /// key was found, but of a different type. public T Get(string key) { - return (T)Conversion.ConvertTo(this.properties[key]); + return Conversion.To(this.properties[key]); } /// @@ -91,16 +92,14 @@ public T Get(string key) { /// true if the lookup and conversion succeeded, otherwise false. public bool TryGetValue(string key, out T result) { if (this.properties.ContainsKey(key)) { - var temp = Conversion.ConvertTo(this.properties[key]); - if (temp is T || - (temp == null && - (!typeof(T).GetTypeInfo().IsValueType || ReflectionHelpers.IsNullable(typeof(T)))) - ) { - result = (T)temp; + try { + var temp = Conversion.To(this.properties[key]); + result = temp; return true; + } catch (Exception ex) { + // Could not convert, do nothing } } - result = default(T); return false; } diff --git a/Parse/Public/ParseException.cs b/ParseCore/Public/ParseException.cs similarity index 100% rename from Parse/Public/ParseException.cs rename to ParseCore/Public/ParseException.cs diff --git a/Parse/Public/ParseExtensions.cs b/ParseCore/Public/ParseExtensions.cs similarity index 99% rename from Parse/Public/ParseExtensions.cs rename to ParseCore/Public/ParseExtensions.cs index db6672ee..23e91347 100644 --- a/Parse/Public/ParseExtensions.cs +++ b/ParseCore/Public/ParseExtensions.cs @@ -4,7 +4,8 @@ using System.Threading; using System.Threading.Tasks; using System.Linq; -using Parse.Internal; +using Parse.Core.Internal; +using Parse.Common.Internal; namespace Parse { /// diff --git a/Parse/Public/ParseFieldNameAttribute.cs b/ParseCore/Public/ParseFieldNameAttribute.cs similarity index 100% rename from Parse/Public/ParseFieldNameAttribute.cs rename to ParseCore/Public/ParseFieldNameAttribute.cs diff --git a/Parse/Public/ParseFile.cs b/ParseCore/Public/ParseFile.cs similarity index 98% rename from Parse/Public/ParseFile.cs rename to ParseCore/Public/ParseFile.cs index f4466404..9063c520 100644 --- a/Parse/Public/ParseFile.cs +++ b/ParseCore/Public/ParseFile.cs @@ -1,12 +1,13 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. -using Parse.Internal; +using Parse.Core.Internal; using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Threading; using System.Threading.Tasks; +using Parse.Common.Internal; namespace Parse { /// @@ -15,7 +16,7 @@ namespace Parse { /// /// The workflow is to construct a with data and a filename, /// then save it and set it as a field on a ParseObject: - /// + /// /// /// var file = new ParseFile("hello.txt", /// new MemoryStream(Encoding.UTF8.GetBytes("hello"))); @@ -95,7 +96,7 @@ public string Name { /// /// Gets the MIME type of the file. This is either passed in to the constructor or - /// inferred from the file extension. "unknown/unknown" will be used if neither is + /// inferred from the file extension. "unknown/unknown" will be used if neither is /// available. /// public string MimeType { diff --git a/Parse/Public/ParseGeoDistance.cs b/ParseCore/Public/ParseGeoDistance.cs similarity index 100% rename from Parse/Public/ParseGeoDistance.cs rename to ParseCore/Public/ParseGeoDistance.cs diff --git a/Parse/Public/ParseGeoPoint.cs b/ParseCore/Public/ParseGeoPoint.cs similarity index 98% rename from Parse/Public/ParseGeoPoint.cs rename to ParseCore/Public/ParseGeoPoint.cs index d970b3fe..2edccf6c 100644 --- a/Parse/Public/ParseGeoPoint.cs +++ b/ParseCore/Public/ParseGeoPoint.cs @@ -2,14 +2,15 @@ using System; using System.Collections.Generic; -using Parse.Internal; +using Parse.Core.Internal; +using Parse.Common.Internal; namespace Parse { /// /// ParseGeoPoint represents a latitude / longitude point that may be associated /// with a key in a ParseObject or used as a reference point for geo queries. /// This allows proximity-based queries on the key. - /// + /// /// Only one key in a class may contain a GeoPoint. /// public struct ParseGeoPoint : IJsonConvertible { diff --git a/Parse/Public/ParseObject.cs b/ParseCore/Public/ParseObject.cs similarity index 98% rename from Parse/Public/ParseObject.cs rename to ParseCore/Public/ParseObject.cs index dd93d6df..b5400b2e 100644 --- a/Parse/Public/ParseObject.cs +++ b/ParseCore/Public/ParseObject.cs @@ -1,6 +1,6 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. -using Parse.Internal; +using Parse.Core.Internal; using Parse.Utilities; using System; using System.Collections.Generic; @@ -11,6 +11,7 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using Parse.Common.Internal; namespace Parse { /// @@ -30,6 +31,13 @@ namespace Parse { public class ParseObject : IEnumerable>, INotifyPropertyChanged { private static readonly string AutoClassName = "_Automatic"; +#if UNITY + private static readonly bool isCompiledByIL2CPP = AppDomain.CurrentDomain.FriendlyName.Equals("IL2CPP Root Domain"); +#else + private static readonly bool isCompiledByIL2CPP = false; +#endif + + internal readonly object mutex = new object(); private readonly LinkedList> operationSetQueue = @@ -444,11 +452,7 @@ internal static IEnumerable DeepTraversal( private static IEnumerable DeepTraversalInternal( object root, bool traverseParseObjects, ICollection seen) { seen.Add(root); -#if UNITY - var itemsToVisit = PlatformHooks.IsCompiledByIL2CPP ? (System.Collections.IEnumerable)null : (IEnumerable)null; -#else - var itemsToVisit = (IEnumerable)null; -#endif + var itemsToVisit = isCompiledByIL2CPP ? (System.Collections.IEnumerable)null : (IEnumerable)null; var dict = Conversion.As>(root); if (dict != null) { itemsToVisit = dict.Values; @@ -527,7 +531,7 @@ internal IDictionary StartSave() { } } - internal virtual Task SaveAsync(Task toAwait, + protected virtual Task SaveAsync(Task toAwait, CancellationToken cancellationToken) { IDictionary currentOperations = null; if (!IsDirty) { @@ -1264,7 +1268,7 @@ public bool ContainsKey(string key) { /// retrieved and is not found. /// public T Get(string key) { - return (T)Conversion.ConvertTo(this[key]); + return Conversion.To(this[key]); } /// @@ -1292,10 +1296,13 @@ public ParseRelation GetRelation(string key) where T : ParseObject { public bool TryGetValue(string key, out T result) { lock (mutex) { if (ContainsKey(key)) { - var temp = Conversion.ConvertTo(this[key]); - if (temp is T || (temp == null && (!typeof(T).GetTypeInfo().IsValueType || ReflectionHelpers.IsNullable(typeof(T))))) { - result = (T)temp; + try { + var temp = Conversion.To(this[key]); + result = temp; return true; + } catch (InvalidCastException ex) { + result = default(T); + return false; } } result = default(T); @@ -1336,7 +1343,7 @@ private void CheckKeyIsMutable(string key) { } } - internal virtual bool IsKeyMutable(string key) { + protected virtual bool IsKeyMutable(string key) { return true; } diff --git a/Parse/Public/ParseQuery.cs b/ParseCore/Public/ParseQuery.cs similarity index 99% rename from Parse/Public/ParseQuery.cs rename to ParseCore/Public/ParseQuery.cs index 0bb11ed2..003a035b 100644 --- a/Parse/Public/ParseQuery.cs +++ b/ParseCore/Public/ParseQuery.cs @@ -8,7 +8,8 @@ using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; -using Parse.Internal; +using Parse.Core.Internal; +using Parse.Common.Internal; namespace Parse { diff --git a/Parse/Public/ParseQueryExtensions.cs b/ParseCore/Public/ParseQueryExtensions.cs similarity index 99% rename from Parse/Public/ParseQueryExtensions.cs rename to ParseCore/Public/ParseQueryExtensions.cs index 0d576966..e11ea8f1 100644 --- a/Parse/Public/ParseQueryExtensions.cs +++ b/ParseCore/Public/ParseQueryExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. -using Parse.Internal; +using Parse.Common.Internal; +using Parse.Core.Internal; using System; using System.Collections.Generic; using System.Linq; @@ -129,7 +130,6 @@ private static bool IsParseObjectGet(MethodCallExpression node) { /// "foo.bar.baz" /// private class ObjectNormalizer : ExpressionVisitor { -#if !IOS protected override Expression VisitIndex(IndexExpression node) { var visitedObject = Visit(node.Object); var indexer = visitedObject as MethodCallExpression; @@ -145,7 +145,6 @@ protected override Expression VisitIndex(IndexExpression node) { } return base.VisitIndex(node); } -#endif /// /// Check for a ParseFieldName attribute and use that as the path component, turning diff --git a/Parse/Public/ParseRelation.cs b/ParseCore/Public/ParseRelation.cs similarity index 95% rename from Parse/Public/ParseRelation.cs rename to ParseCore/Public/ParseRelation.cs index 3d9e54d3..57233a18 100644 --- a/Parse/Public/ParseRelation.cs +++ b/ParseCore/Public/ParseRelation.cs @@ -1,6 +1,6 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. -using Parse.Internal; +using Parse.Core.Internal; using System; using System.Collections.Generic; using System.ComponentModel; @@ -9,6 +9,7 @@ using System.Linq.Expressions; using System.Reflection; using System.Text; +using Parse.Common.Internal; namespace Parse { /// @@ -87,12 +88,6 @@ internal string TargetClassName { internal static ParseRelationBase CreateRelation(ParseObject parent, string key, string targetClassName) { - // `Expression` is unstable in IL2CPP environment. Let's call the method directly! -#if UNITY - if (PlatformHooks.IsCompiledByIL2CPP) { - return CreateRelation(parent, key, targetClassName); - } -#endif var targetType = SubclassingController.GetType(targetClassName) ?? typeof(ParseObject); Expression>> createRelationExpr = diff --git a/Parse/Public/ParseRole.cs b/ParseCore/Public/ParseRole.cs similarity index 99% rename from Parse/Public/ParseRole.cs rename to ParseCore/Public/ParseRole.cs index 801b4106..1b15f29f 100644 --- a/Parse/Public/ParseRole.cs +++ b/ParseCore/Public/ParseRole.cs @@ -1,6 +1,6 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. -using Parse.Internal; +using Parse.Core.Internal; using System; using System.Collections.Generic; using System.Linq; @@ -15,7 +15,7 @@ namespace Parse { /// specifying a for a . Roles /// are specified by their sets of child users and child roles, all of which are granted /// any permissions that the parent role has. - /// + /// /// Roles must have a name (that cannot be changed after creation of the role), /// and must specify an ACL. /// diff --git a/Parse/Public/ParseSession.cs b/ParseCore/Public/ParseSession.cs similarity index 90% rename from Parse/Public/ParseSession.cs rename to ParseCore/Public/ParseSession.cs index 7c413c26..ac0d94c1 100644 --- a/Parse/Public/ParseSession.cs +++ b/ParseCore/Public/ParseSession.cs @@ -1,10 +1,11 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. -using Parse.Internal; +using Parse.Core.Internal; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Parse.Common.Internal; namespace Parse { /// @@ -16,7 +17,7 @@ public class ParseSession : ParseObject { "sessionToken", "createdWith", "restricted", "user", "expiresAt", "installationId" }; - internal override bool IsKeyMutable(string key) { + protected override bool IsKeyMutable(string key) { return !readOnlyKeys.Contains(key); } @@ -74,14 +75,14 @@ public static Task GetCurrentSessionAsync(CancellationToken cancel } internal static Task RevokeAsync(string sessionToken, CancellationToken cancellationToken) { - if (sessionToken == null || !IsRevocableSessionToken(sessionToken)) { + if (sessionToken == null || !SessionController.IsRevocableSessionToken(sessionToken)) { return Task.FromResult(0); } return SessionController.RevokeAsync(sessionToken, cancellationToken); } internal static Task UpgradeToRevocableSessionAsync(string sessionToken, CancellationToken cancellationToken) { - if (sessionToken == null || IsRevocableSessionToken(sessionToken)) { + if (sessionToken == null || SessionController.IsRevocableSessionToken(sessionToken)) { return Task.FromResult(sessionToken); } @@ -90,9 +91,5 @@ internal static Task UpgradeToRevocableSessionAsync(string sessionToken, return session.SessionToken; }); } - - internal static bool IsRevocableSessionToken(string sessionToken) { - return sessionToken.Contains("r:"); - } } } diff --git a/Parse/Public/ParseUser.cs b/ParseCore/Public/ParseUser.cs similarity index 98% rename from Parse/Public/ParseUser.cs rename to ParseCore/Public/ParseUser.cs index 3273f2a6..be1a0475 100644 --- a/Parse/Public/ParseUser.cs +++ b/ParseCore/Public/ParseUser.cs @@ -1,6 +1,6 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. -using Parse.Internal; +using Parse.Core.Internal; using System; using System.Collections.Generic; using System.Linq; @@ -8,6 +8,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Parse.Common.Internal; namespace Parse { /// @@ -60,7 +61,7 @@ public override void Remove(string key) { base.Remove(key); } - internal override bool IsKeyMutable(string key) { + protected override bool IsKeyMutable(string key) { return !readOnlyKeys.Contains(key); } @@ -75,7 +76,7 @@ internal override void HandleSave(IObjectState serverState) { }); } - internal string SessionToken { + public string SessionToken { get { if (State.ContainsKey("sessionToken")) { return State["sessionToken"] as string; @@ -242,7 +243,7 @@ public static Task BecomeAsync(string sessionToken, CancellationToken }).Unwrap(); } - internal override Task SaveAsync(Task toAwait, CancellationToken cancellationToken) { + protected override Task SaveAsync(Task toAwait, CancellationToken cancellationToken) { lock (mutex) { if (ObjectId == null) { throw new InvalidOperationException("You must call SignUpAsync before calling SaveAsync."); @@ -293,7 +294,7 @@ public static Task LogOutAsync() { /// /// Logs out the currently logged in user session. This will remove the session from disk, log out of /// linked services, and future calls to will return null. - /// + /// /// This is preferable to using , unless your code is already running from a /// background thread. /// diff --git a/ParseCore/Public/Unity/ParseInitializeBehaviour.cs b/ParseCore/Public/Unity/ParseInitializeBehaviour.cs new file mode 100644 index 00000000..85ec6b74 --- /dev/null +++ b/ParseCore/Public/Unity/ParseInitializeBehaviour.cs @@ -0,0 +1,66 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using Parse.Common.Internal; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; + +namespace Parse { + /// + /// Mandatory MonoBehaviour for scenes that use Parse. Set the application ID and .NET key + /// in the editor. + /// + // TODO (hallucinogen): somehow because of Push, we need this class to be added in a GameObject + // called `ParseInitializeBehaviour`. We might want to fix this. + public class ParseInitializeBehaviour : MonoBehaviour { + private static bool isInitialized = false; + + /// + /// The Parse applicationId used in this app. You can get this value from the Parse website. + /// + [SerializeField] + public string applicationID; + + /// + /// The Parse dotnetKey used in this app. You can get this value from the Parse website. + /// + [SerializeField] + public string dotnetKey; + + [SerializeField] + public string server; + + /// + /// Initializes the Parse SDK and begins running network requests created by Parse. + /// + public virtual void Awake() { + Initialize(); + + // Force the name to be `ParseInitializeBehaviour` in runtime. + gameObject.name = "ParseInitializeBehaviour"; + } + + public void Initialize() { + if (isInitialized) { + return; + } + + isInitialized = true; + // Keep this gameObject around, even when the scene changes. + GameObject.DontDestroyOnLoad(gameObject); + + ParseClient.Initialize(new ParseClient.Configuration { + ApplicationId = applicationID, + WindowsKey = dotnetKey, + Server = string.IsNullOrEmpty(server) ? null : server + }); + + Dispatcher.Instance.GameObject = gameObject; + + // Kick off the dispatcher. + StartCoroutine(Dispatcher.Instance.DispatcherCoroutine); + } + } +} diff --git a/ParseTest.Unit/CloudControllerTests.cs b/ParseCore/Test/CloudControllerTests.cs similarity index 99% rename from ParseTest.Unit/CloudControllerTests.cs rename to ParseCore/Test/CloudControllerTests.cs index cc334f41..5c958e7d 100644 --- a/ParseTest.Unit/CloudControllerTests.cs +++ b/ParseCore/Test/CloudControllerTests.cs @@ -1,5 +1,5 @@ using Parse; -using Parse.Internal; +using Parse.Core.Internal; using NUnit.Framework; using Moq; using System; diff --git a/ParseTest.Unit/CloudTests.cs b/ParseCore/Test/CloudTests.cs similarity index 81% rename from ParseTest.Unit/CloudTests.cs rename to ParseCore/Test/CloudTests.cs index b8ca6389..ef510ec5 100644 --- a/ParseTest.Unit/CloudTests.cs +++ b/ParseCore/Test/CloudTests.cs @@ -1,5 +1,5 @@ using Parse; -using Parse.Internal; +using Parse.Core.Internal; using NUnit.Framework; using Moq; using System; @@ -13,8 +13,7 @@ namespace ParseTest { public class CloudTests { [TearDown] public void TearDown() { - ParseCorePlugins.Instance.CloudCodeController = null; - ParseCorePlugins.Instance.CurrentUserController = null; + ParseCorePlugins.Instance.Reset(); } [Test] @@ -30,8 +29,11 @@ public Task TestCloudFunctions() { It.IsAny(), It.IsAny())).Returns(Task.FromResult(response)); var mockCurrentUserController = new Mock(); - ParseCorePlugins.Instance.CloudCodeController = mockController.Object; - ParseCorePlugins.Instance.CurrentUserController = mockCurrentUserController.Object; + + ParseCorePlugins plugins = new ParseCorePlugins(); + plugins.CloudCodeController = mockController.Object; + plugins.CurrentUserController = mockCurrentUserController.Object; + ParseCorePlugins.Instance = plugins; return ParseCloud.CallFunctionAsync>("someFunction", null, CancellationToken.None).ContinueWith(t => { Assert.IsFalse(t.IsFaulted); diff --git a/ParseTest.Unit/CommandTests.cs b/ParseCore/Test/CommandTests.cs similarity index 83% rename from ParseTest.Unit/CommandTests.cs rename to ParseCore/Test/CommandTests.cs index 78404715..c91f1cde 100644 --- a/ParseTest.Unit/CommandTests.cs +++ b/ParseCore/Test/CommandTests.cs @@ -1,7 +1,8 @@ using Moq; using NUnit.Framework; using Parse; -using Parse.Internal; +using Parse.Common.Internal; +using Parse.Core.Internal; using System; using System.Linq; using System.Threading; @@ -23,7 +24,7 @@ public void SetUp() { [TearDown] public void TearDown() { - ParseClient.ApplicationSettings.Clear(); + ParseCorePlugins.Instance.Reset(); } [Test] @@ -37,20 +38,22 @@ public void TestMakeCommand() { Assert.AreEqual("/1/endpoint", command.Uri.AbsolutePath); Assert.AreEqual("GET", command.Method); Assert.IsTrue(command.Headers.Any(pair => pair.Key == "X-Parse-Session-Token" && pair.Value == "abcd")); - Assert.Greater(command.Headers.Count, 2); } [Test] [AsyncStateMachine(typeof(CommandTests))] public Task TestRunCommand() { var mockHttpClient = new Mock(); + var mockInstallationIdController = new Mock(); var fakeResponse = Task>.FromResult(new Tuple(HttpStatusCode.OK, "{}")); mockHttpClient.Setup(obj => obj.ExecuteAsync(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())).Returns(fakeResponse); - ParseCommandRunner commandRunner = new ParseCommandRunner(mockHttpClient.Object); + mockInstallationIdController.Setup(i => i.GetAsync()).Returns(Task.FromResult(null)); + + ParseCommandRunner commandRunner = new ParseCommandRunner(mockHttpClient.Object, mockInstallationIdController.Object); var command = new ParseCommand("endpoint", method: "GET", data: null); return commandRunner.RunCommandAsync(command).ContinueWith(t => { Assert.False(t.IsFaulted); @@ -64,13 +67,16 @@ public Task TestRunCommand() { [AsyncStateMachine(typeof(CommandTests))] public Task TestRunCommandWithArrayResult() { var mockHttpClient = new Mock(); + var mockInstallationIdController = new Mock(); var fakeResponse = Task>.FromResult(new Tuple(HttpStatusCode.OK, "[]")); mockHttpClient.Setup(obj => obj.ExecuteAsync(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())).Returns(fakeResponse); - ParseCommandRunner commandRunner = new ParseCommandRunner(mockHttpClient.Object); + mockInstallationIdController.Setup(i => i.GetAsync()).Returns(Task.FromResult(null)); + + ParseCommandRunner commandRunner = new ParseCommandRunner(mockHttpClient.Object, mockInstallationIdController.Object); var command = new ParseCommand("endpoint", method: "GET", data: null); return commandRunner.RunCommandAsync(command).ContinueWith(t => { Assert.False(t.IsFaulted); @@ -86,13 +92,16 @@ public Task TestRunCommandWithArrayResult() { [AsyncStateMachine(typeof(CommandTests))] public Task TestRunCommandWithInvalidString() { var mockHttpClient = new Mock(); + var mockInstallationIdController = new Mock(); var fakeResponse = Task>.FromResult(new Tuple(HttpStatusCode.OK, "invalid")); mockHttpClient.Setup(obj => obj.ExecuteAsync(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())).Returns(fakeResponse); - ParseCommandRunner commandRunner = new ParseCommandRunner(mockHttpClient.Object); + mockInstallationIdController.Setup(i => i.GetAsync()).Returns(Task.FromResult(null)); + + ParseCommandRunner commandRunner = new ParseCommandRunner(mockHttpClient.Object, mockInstallationIdController.Object); var command = new ParseCommand("endpoint", method: "GET", data: null); return commandRunner.RunCommandAsync(command).ContinueWith(t => { Assert.True(t.IsFaulted); @@ -107,13 +116,16 @@ public Task TestRunCommandWithInvalidString() { [AsyncStateMachine(typeof(CommandTests))] public Task TestRunCommandWithErrorCode() { var mockHttpClient = new Mock(); + var mockInstallationIdController = new Mock(); var fakeResponse = Task>.FromResult(new Tuple(HttpStatusCode.NotFound, "{ \"code\": 101, \"error\": \"Object not found.\" }")); mockHttpClient.Setup(obj => obj.ExecuteAsync(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())).Returns(fakeResponse); - ParseCommandRunner commandRunner = new ParseCommandRunner(mockHttpClient.Object); + mockInstallationIdController.Setup(i => i.GetAsync()).Returns(Task.FromResult(null)); + + ParseCommandRunner commandRunner = new ParseCommandRunner(mockHttpClient.Object, mockInstallationIdController.Object); var command = new ParseCommand("endpoint", method: "GET", data: null); return commandRunner.RunCommandAsync(command).ContinueWith(t => { Assert.True(t.IsFaulted); @@ -129,13 +141,16 @@ public Task TestRunCommandWithErrorCode() { [AsyncStateMachine(typeof(CommandTests))] public Task TestRunCommandWithInternalServerError() { var mockHttpClient = new Mock(); + var mockInstallationIdController = new Mock(); var fakeResponse = Task>.FromResult(new Tuple(HttpStatusCode.InternalServerError, null)); mockHttpClient.Setup(obj => obj.ExecuteAsync(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())).Returns(fakeResponse); - ParseCommandRunner commandRunner = new ParseCommandRunner(mockHttpClient.Object); + mockInstallationIdController.Setup(i => i.GetAsync()).Returns(Task.FromResult(null)); + + ParseCommandRunner commandRunner = new ParseCommandRunner(mockHttpClient.Object, mockInstallationIdController.Object); var command = new ParseCommand("endpoint", method: "GET", data: null); return commandRunner.RunCommandAsync(command).ContinueWith(t => { Assert.True(t.IsFaulted); diff --git a/ParseTest.Unit/ConfigTests.cs b/ParseCore/Test/ConfigTests.cs similarity index 86% rename from ParseTest.Unit/ConfigTests.cs rename to ParseCore/Test/ConfigTests.cs index 08060a54..e60116e4 100644 --- a/ParseTest.Unit/ConfigTests.cs +++ b/ParseCore/Test/ConfigTests.cs @@ -1,7 +1,8 @@ using Moq; using NUnit.Framework; using Parse; -using Parse.Internal; +using Parse.Common.Internal; +using Parse.Core.Internal; using System; using System.Collections.Generic; using System.IO; @@ -17,7 +18,7 @@ private IParseConfigController MockedConfigController { var mockedConfigController = new Mock(); var mockedCurrentConfigController = new Mock(); - ParseConfig theConfig = new ParseConfig(new Dictionary {{ + ParseConfig theConfig = ParseConfigExtensions.Create(new Dictionary {{ "params", new Dictionary {{ "testKey", "testValue" }} @@ -45,14 +46,15 @@ private IParseConfigController MockedConfigController { [SetUp] public void SetUp() { - ParseCorePlugins.Instance.ConfigController = MockedConfigController; - ParseCorePlugins.Instance.CurrentUserController = new Mock().Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + ConfigController = MockedConfigController, + CurrentUserController = new Mock().Object + }; } [TearDown] public void TearDown() { - ParseCorePlugins.Instance.ConfigController = null; - ParseCorePlugins.Instance.CurrentUserController = null; + ParseCorePlugins.Instance = null; } [Test] diff --git a/ParseTest.Unit/CurrentUserControllerTests.cs b/ParseCore/Test/CurrentUserControllerTests.cs similarity index 64% rename from ParseTest.Unit/CurrentUserControllerTests.cs rename to ParseCore/Test/CurrentUserControllerTests.cs index 791675d1..80b28d82 100644 --- a/ParseTest.Unit/CurrentUserControllerTests.cs +++ b/ParseCore/Test/CurrentUserControllerTests.cs @@ -1,9 +1,11 @@ using Parse; -using Parse.Internal; +using Parse.Common.Internal; +using Parse.Core.Internal; using System; using System.Threading; using System.Threading.Tasks; using System.Runtime.CompilerServices; +using Moq; using NUnit.Framework; using System.Collections.Generic; @@ -17,24 +19,38 @@ public void SetUp() { [TearDown] public void TearDown() { - ParseObject.UnregisterSubclass(); + ParseCorePlugins.Instance.Reset(); } [Test] public void TestConstructor() { - var controller = new ParseCurrentUserController(); + var storageController = new Mock(); + var controller = new ParseCurrentUserController(storageController.Object); Assert.IsNull(controller.CurrentUser); } [Test] [AsyncStateMachine(typeof(CurrentUserControllerTests))] public Task TestGetSetAsync() { - var controller = new ParseCurrentUserController(); + var storageController = new Mock(MockBehavior.Strict); + var mockedStorage = new Mock>(); + var controller = new ParseCurrentUserController(storageController.Object); var user = new ParseUser(); + storageController.Setup(s => s.LoadAsync()).Returns(Task.FromResult(mockedStorage.Object)); + return controller.SetAsync(user, CancellationToken.None).OnSuccess(_ => { Assert.AreEqual(user, controller.CurrentUser); + object jsonObject = null; + Predicate predicate = o => { + jsonObject = o; + return true; + }; + + mockedStorage.Verify(s => s.AddAsync("CurrentUser", Match.Create(predicate))); + mockedStorage.Setup(s => s.TryGetValue("CurrentUser", out jsonObject)).Returns(true); + return controller.GetAsync(CancellationToken.None); }).Unwrap() .OnSuccess(t => { @@ -54,39 +70,58 @@ public Task TestGetSetAsync() { [Test] [AsyncStateMachine(typeof(CurrentUserControllerTests))] public Task TestExistsAsync() { - var controller = new ParseCurrentUserController(); + var storageController = new Mock(); + var mockedStorage = new Mock>(); + var controller = new ParseCurrentUserController(storageController.Object); var user = new ParseUser(); + storageController.Setup(c => c.LoadAsync()).Returns(Task.FromResult(mockedStorage.Object)); + + bool contains = false; + mockedStorage.Setup(s => s.AddAsync("CurrentUser", It.IsAny())).Callback(() => { + contains = true; + }).Returns(Task.FromResult(null)).Verifiable(); + + mockedStorage.Setup(s => s.RemoveAsync("CurrentUser")).Callback(() => { + contains = false; + }).Returns(Task.FromResult(null)).Verifiable(); + + mockedStorage.Setup(s => s.ContainsKey("CurrentUser")).Returns(() => contains); + return controller.SetAsync(user, CancellationToken.None).OnSuccess(_ => { Assert.AreEqual(user, controller.CurrentUser); + return controller.ExistsAsync(CancellationToken.None); }).Unwrap() .OnSuccess(t => { Assert.IsTrue(t.Result); controller.ClearFromMemory(); - return controller.ExistsAsync(CancellationToken.None); }).Unwrap() .OnSuccess(t => { Assert.IsTrue(t.Result); controller.ClearFromDisk(); - return controller.ExistsAsync(CancellationToken.None); }).Unwrap() .OnSuccess(t => { Assert.IsFalse(t.Result); + mockedStorage.Verify(); }); } [Test] [AsyncStateMachine(typeof(CurrentUserControllerTests))] public Task TestIsCurrent() { - var controller = new ParseCurrentUserController(); + var storageController = new Mock(MockBehavior.Strict); + var mockedStorage = new Mock>(); + var controller = new ParseCurrentUserController(storageController.Object); var user = new ParseUser(); var user2 = new ParseUser(); + storageController.Setup(s => s.LoadAsync()).Returns(Task.FromResult(mockedStorage.Object)); + return controller.SetAsync(user, CancellationToken.None).OnSuccess(t => { Assert.IsTrue(controller.IsCurrent(user)); Assert.IsFalse(controller.IsCurrent(user2)); @@ -116,7 +151,11 @@ public Task TestIsCurrent() { [Test] [AsyncStateMachine(typeof(CurrentUserControllerTests))] public Task TestCurrentSessionToken() { - var controller = new ParseCurrentUserController(); + var storageController = new Mock(); + var mockedStorage = new Mock>(); + var controller = new ParseCurrentUserController(storageController.Object); + + storageController.Setup(c => c.LoadAsync()).Returns(Task.FromResult(mockedStorage.Object)); return controller.GetCurrentSessionTokenAsync(CancellationToken.None).OnSuccess(t => { Assert.IsNull(t.Result); @@ -139,7 +178,8 @@ public Task TestCurrentSessionToken() { } public Task TestLogOut() { - var controller = new ParseCurrentUserController(); + var storageController = new Mock(MockBehavior.Strict); + var controller = new ParseCurrentUserController(storageController.Object); var user = new ParseUser(); return controller.SetAsync(user, CancellationToken.None).OnSuccess(_ => { diff --git a/ParseTest.Unit/DecoderTests.cs b/ParseCore/Test/DecoderTests.cs similarity index 96% rename from ParseTest.Unit/DecoderTests.cs rename to ParseCore/Test/DecoderTests.cs index b60ce2c6..d4627cb4 100644 --- a/ParseTest.Unit/DecoderTests.cs +++ b/ParseCore/Test/DecoderTests.cs @@ -1,6 +1,6 @@ using NUnit.Framework; using Parse; -using Parse.Internal; +using Parse.Core.Internal; using System; using System.Collections.Generic; @@ -181,7 +181,7 @@ public void TestDecodeRelation() { ParseRelation relation = ParseDecoder.Instance.Decode(value) as ParseRelation; Assert.IsNotNull(relation); - Assert.AreEqual("Corgi", relation.TargetClassName); + Assert.AreEqual("Corgi", relation.GetTargetClassName()); } [Test] @@ -190,7 +190,7 @@ public void TestDecodeDictionary() { { "megurine", "luka" }, { "hatsune", new ParseObject("Miku") }, { - "decodedGeoPoint", new Dictionary() { + "decodedGeoPoint", new Dictionary() { { "__type", "GeoPoint" }, { "latitude", 0.9 }, { "longitude", 0.3 } @@ -198,7 +198,7 @@ public void TestDecodeDictionary() { }, { "listWithSomething", new List() { - new Dictionary() { + new Dictionary() { { "__type", "GeoPoint" }, { "latitude", 0.9 }, { "longitude", 0.3 } @@ -229,12 +229,12 @@ public void TestDecodeDictionary() { public void TestDecodeList() { IList value = new List() { 1, new ParseACL(), "wiz", - new Dictionary() { + new Dictionary() { { "__type", "GeoPoint" }, { "latitude", 0.9 }, { "longitude", 0.3 } }, new List() { - new Dictionary() { + new Dictionary() { { "__type", "GeoPoint" }, { "latitude", 0.9 }, { "longitude", 0.3 } diff --git a/ParseTest.Unit/EncoderTests.cs b/ParseCore/Test/EncoderTests.cs similarity index 94% rename from ParseTest.Unit/EncoderTests.cs rename to ParseCore/Test/EncoderTests.cs index 49da5142..99297caa 100644 --- a/ParseTest.Unit/EncoderTests.cs +++ b/ParseCore/Test/EncoderTests.cs @@ -1,11 +1,11 @@ using Moq; using NUnit.Framework; using Parse; -using Parse.Internal; using System; using System.IO; using System.Collections.Generic; using System.Threading.Tasks; +using Parse.Core.Internal; // TODO (hallucinogen): mock ParseACL, ParseObject, ParseUser once we have their Interfaces namespace ParseTest { @@ -30,15 +30,18 @@ protected override IDictionary EncodeParseObject(ParseObject val [Test] public void TestIsValidType() { + var corgi = new ParseObject("Corgi"); + var corgiRelation = corgi.GetRelation("corgi"); + Assert.IsTrue(ParseEncoder.IsValidType(322)); Assert.IsTrue(ParseEncoder.IsValidType(0.3f)); Assert.IsTrue(ParseEncoder.IsValidType(new byte[]{ 1, 2, 3, 4 })); Assert.IsTrue(ParseEncoder.IsValidType("corgi")); - Assert.IsTrue(ParseEncoder.IsValidType(new ParseObject("Corgi"))); + Assert.IsTrue(ParseEncoder.IsValidType(corgi)); Assert.IsTrue(ParseEncoder.IsValidType(new ParseACL())); Assert.IsTrue(ParseEncoder.IsValidType(new ParseFile("Corgi", new byte[0]))); Assert.IsTrue(ParseEncoder.IsValidType(new ParseGeoPoint(1, 2))); - Assert.IsTrue(ParseEncoder.IsValidType(new ParseRelation(new ParseObject("Corgi"), "corgi"))); + Assert.IsTrue(ParseEncoder.IsValidType(corgiRelation)); Assert.IsTrue(ParseEncoder.IsValidType(new DateTime())); Assert.IsTrue(ParseEncoder.IsValidType(new List())); Assert.IsTrue(ParseEncoder.IsValidType(new Dictionary())); @@ -79,7 +82,7 @@ public void TestEncodeParseObjectWithPointerOrLocalIdEncoder() { [Test] public void TestEncodeParseFile() { - ParseFile file1 = new ParseFile("Corgi.png", new Uri("http://corgi.xyz/gogo.png")); + ParseFile file1 = ParseFileExtensions.Create("Corgi.png", new Uri("http://corgi.xyz/gogo.png")); IDictionary value = ParseEncoderTestClass.Instance.Encode(file1) as IDictionary; Assert.AreEqual("File", value["__type"]); Assert.AreEqual("Corgi.png", value["name"]); @@ -121,7 +124,7 @@ public void TestEncodeACL() { [Test] public void TestEncodeParseRelation() { var obj = new ParseObject("Corgi"); - ParseRelation relation = new ParseRelation(obj, "nano", "Husky"); + ParseRelation relation = ParseRelationExtensions.Create(obj, "nano", "Husky"); IDictionary value = ParseEncoderTestClass.Instance.Encode(relation) as IDictionary; Assert.AreEqual("Relation", value["__type"]); Assert.AreEqual("Husky", value["className"]); diff --git a/ParseTest.Unit/FileControllerTests.cs b/ParseCore/Test/FileControllerTests.cs similarity index 99% rename from ParseTest.Unit/FileControllerTests.cs rename to ParseCore/Test/FileControllerTests.cs index 1559d3a3..1a391e51 100644 --- a/ParseTest.Unit/FileControllerTests.cs +++ b/ParseCore/Test/FileControllerTests.cs @@ -1,7 +1,7 @@ using Moq; using NUnit.Framework; using Parse; -using Parse.Internal; +using Parse.Core.Internal; using System; using System.Collections.Generic; using System.IO; diff --git a/ParseTest.Unit/FileStateTests.cs b/ParseCore/Test/FileStateTests.cs similarity index 97% rename from ParseTest.Unit/FileStateTests.cs rename to ParseCore/Test/FileStateTests.cs index 2419c29b..76f4c4f5 100644 --- a/ParseTest.Unit/FileStateTests.cs +++ b/ParseCore/Test/FileStateTests.cs @@ -1,6 +1,6 @@ using System; using Parse; -using Parse.Internal; +using Parse.Core.Internal; using System.Text; using System.Collections.Generic; using NUnit.Framework; diff --git a/ParseTest.Unit/FileTests.cs b/ParseCore/Test/FileTests.cs similarity index 81% rename from ParseTest.Unit/FileTests.cs rename to ParseCore/Test/FileTests.cs index 405a384f..d9787d20 100644 --- a/ParseTest.Unit/FileTests.cs +++ b/ParseCore/Test/FileTests.cs @@ -1,7 +1,7 @@ using Moq; using NUnit.Framework; using Parse; -using Parse.Internal; +using Parse.Core.Internal; using System; using System.Collections.Generic; using System.IO; @@ -14,8 +14,7 @@ namespace ParseTest { public class FileTests { [TearDown] public void TearDown() { - ParseCorePlugins.Instance.FileController = null; - ParseCorePlugins.Instance.CurrentUserController = null; + ParseCorePlugins.Instance = null; } [Test] @@ -33,8 +32,10 @@ public Task TestFileSave() { It.IsAny>(), It.IsAny())).Returns(Task.FromResult(response)); var mockCurrentUserController = new Mock(); - ParseCorePlugins.Instance.FileController = mockController.Object; - ParseCorePlugins.Instance.CurrentUserController = mockCurrentUserController.Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + FileController = mockController.Object, + CurrentUserController = mockCurrentUserController.Object + }; ParseFile file = new ParseFile("bekti.jpeg", new MemoryStream(), "image/jpeg"); Assert.AreEqual("bekti.jpeg", file.Name); @@ -56,13 +57,13 @@ public void TestSecureUrl() { Uri secureUri = new Uri("https://files.parsetfss.com/yolo.txt"); Uri randomUri = new Uri("http://random.server.local/file.foo"); - ParseFile file = new ParseFile("Foo", unsecureUri); + ParseFile file = ParseFileExtensions.Create("Foo", unsecureUri); Assert.AreEqual(secureUri, file.Url); - file = new ParseFile("Bar", secureUri); + file = ParseFileExtensions.Create("Bar", secureUri); Assert.AreEqual(secureUri, file.Url); - file = new ParseFile("Baz", randomUri); + file = ParseFileExtensions.Create("Baz", randomUri); Assert.AreEqual(randomUri, file.Url); } } diff --git a/ParseTest.Unit/GeoPointTests.cs b/ParseCore/Test/GeoPointTests.cs similarity index 94% rename from ParseTest.Unit/GeoPointTests.cs rename to ParseCore/Test/GeoPointTests.cs index 271c9a0d..84dc3504 100644 --- a/ParseTest.Unit/GeoPointTests.cs +++ b/ParseCore/Test/GeoPointTests.cs @@ -1,6 +1,7 @@ using NUnit.Framework; using Parse; -using Parse.Internal; +using Parse.Common.Internal; +using Parse.Core.Internal; using System; using System.Threading; using System.Globalization; @@ -15,12 +16,11 @@ public void TestGeoPointCultureInvariantParsing() { foreach (var c in CultureInfo.GetCultures(CultureTypes.AllCultures)) { Thread.CurrentThread.CurrentCulture = c; var point = new ParseGeoPoint(1.234, 1.234); - var serialized = ParseClient.SerializeJsonString( + var serialized = Json.Encode( new Dictionary { { "point", NoObjectsEncoder.Instance.Encode(point) } }); - var deserialized = ParseDecoder.Instance.Decode( - ParseClient.DeserializeJsonString(serialized)) as IDictionary; + var deserialized = ParseDecoder.Instance.Decode(Json.Parse(serialized)) as IDictionary; var pointAgain = (ParseGeoPoint)deserialized["point"]; Assert.AreEqual(1.234, pointAgain.Latitude); Assert.AreEqual(1.234, pointAgain.Longitude); diff --git a/ParseCore/Test/InstallationIdControllerTests.cs b/ParseCore/Test/InstallationIdControllerTests.cs new file mode 100644 index 00000000..db0bebcd --- /dev/null +++ b/ParseCore/Test/InstallationIdControllerTests.cs @@ -0,0 +1,124 @@ +using Parse; +using Parse.Core.Internal; +using Moq; +using NUnit.Framework; +using System; +using Parse.Common.Internal; +using System.Threading.Tasks; +using System.Runtime.CompilerServices; + +namespace ParseTest { + [TestFixture] + public class InstallationIdControllerTests { + [TearDown] + public void TearDown() { + ParseCorePlugins.Instance = null; + } + + [Test] + public void TestConstructor() { + var storageMock = new Mock(MockBehavior.Strict); + var controller = new InstallationIdController(storageMock.Object); + + // Make sure it didn't touch storageMock. + storageMock.Verify(); + } + + [Test] + [AsyncStateMachine(typeof(InstallationIdControllerTests))] + public Task TestGet() { + var storageMock = new Mock(MockBehavior.Strict); + var storageDictionary = new Mock>(); + + storageMock.Setup(s => s.LoadAsync()).Returns(Task.FromResult(storageDictionary.Object)); + + var controller = new InstallationIdController(storageMock.Object); + return controller.GetAsync().ContinueWith(installationIdTask => { + Assert.False(installationIdTask.IsFaulted); + + object verified = null; + storageDictionary.Verify(s => s.TryGetValue("InstallationId", out verified)); + storageDictionary.Verify(s => s.AddAsync("InstallationId", It.IsAny())); + + return controller.GetAsync().ContinueWith(newInstallationIdTask => { + Assert.False(newInstallationIdTask.IsFaulted); + + // Ensure nothing more has happened with our dictionary. + storageDictionary.VerifyAll(); + + Assert.AreEqual(installationIdTask.Result, newInstallationIdTask.Result); + + return controller.ClearAsync(); + }).Unwrap().ContinueWith(clearTask => { + Assert.False(clearTask.IsFaulted); + + storageDictionary.Verify(storage => storage.RemoveAsync("InstallationId")); + + return controller.GetAsync(); + }).Unwrap().ContinueWith(newInstallationIdTask => { + Assert.False(newInstallationIdTask.IsFaulted); + + Assert.AreNotEqual(installationIdTask.Result, newInstallationIdTask.Result); + + storageDictionary.Verify(s => s.TryGetValue("InstallationId", out verified)); + storageDictionary.Verify(s => s.AddAsync("InstallationId", It.IsAny())); + }); + }).Unwrap(); + } + + [Test] + [AsyncStateMachine(typeof(InstallationIdControllerTests))] + public Task TestSet() { + var storageMock = new Mock(MockBehavior.Strict); + var storageDictionary = new Mock>(); + + storageMock.Setup(s => s.LoadAsync()).Returns(Task.FromResult(storageDictionary.Object)); + + var controller = new InstallationIdController(storageMock.Object); + + return controller.GetAsync().ContinueWith(installationIdTask => { + Assert.False(installationIdTask.IsFaulted); + + object verified = null; + storageDictionary.Verify(s => s.TryGetValue("InstallationId", out verified)); + storageDictionary.Verify(s => s.AddAsync("InstallationId", It.IsAny())); + + var installationId = installationIdTask.Result; + var installationId2 = Guid.NewGuid(); + + return controller.SetAsync(installationId2).ContinueWith(setTask => { + Assert.False(setTask.IsFaulted); + + storageDictionary.Verify(s => s.AddAsync("InstallationId", installationId2.ToString())); + + return controller.GetAsync(); + }).Unwrap().ContinueWith(installationId3Task => { + Assert.False(installationId3Task.IsFaulted); + + storageDictionary.Verify(s => s.TryGetValue("InstallationId", out verified)); + + var installationId3 = installationId3Task.Result; + Assert.AreEqual(installationId2, installationId3); + + return controller.SetAsync(installationId); + }).Unwrap().ContinueWith(setTask => { + Assert.False(setTask.IsFaulted); + + storageDictionary.Verify(s => s.AddAsync("InstallationId", installationId.ToString())); + + return controller.ClearAsync(); + }).Unwrap().ContinueWith(clearTask => { + Assert.False(clearTask.IsFaulted); + + storageDictionary.Verify(s => s.RemoveAsync("InstallationId")); + + return controller.SetAsync(installationId2); + }).Unwrap().ContinueWith(setTask => { + Assert.False(setTask.IsFaulted); + + storageDictionary.Verify(s => s.AddAsync("InstallationId", installationId2.ToString())); + }); + }).Unwrap(); + } + } +} diff --git a/ParseCore/Test/MoqExtensions.cs b/ParseCore/Test/MoqExtensions.cs new file mode 100644 index 00000000..da636490 --- /dev/null +++ b/ParseCore/Test/MoqExtensions.cs @@ -0,0 +1,36 @@ +using Moq.Language; +using Moq.Language.Flow; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace ParseTest { + // MIT licensed, w/ attribution: + // http://stackoverflow.com/a/19598345/427309 + public static class MoqExtensions { + public delegate void OutAction(out TOut outVal); + public delegate void OutAction(T1 arg1, out TOut outVal); + + public static IReturnsThrows OutCallback(this ICallback mock, OutAction action) + where TMock : class { + return OutCallbackInternal(mock, action); + } + + public static IReturnsThrows OutCallback(this ICallback mock, OutAction action) + where TMock : class { + return OutCallbackInternal(mock, action); + } + + private static IReturnsThrows OutCallbackInternal(ICallback mock, object action) + where TMock : class { + mock.GetType() + .Assembly.GetType("Moq.MethodCall") + .InvokeMember("SetCallbackWithArguments", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, mock, + new[] { action }); + return mock as IReturnsThrows; + } + } +} diff --git a/ParseTest.Unit/ObjectControllerTests.cs b/ParseCore/Test/ObjectControllerTests.cs similarity index 99% rename from ParseTest.Unit/ObjectControllerTests.cs rename to ParseCore/Test/ObjectControllerTests.cs index 4db59ad6..75333026 100644 --- a/ParseTest.Unit/ObjectControllerTests.cs +++ b/ParseCore/Test/ObjectControllerTests.cs @@ -1,5 +1,5 @@ using Parse; -using Parse.Internal; +using Parse.Core.Internal; using NUnit.Framework; using Moq; using System; diff --git a/ParseTest.Unit/ObjectStateTests.cs b/ParseCore/Test/ObjectStateTests.cs similarity index 99% rename from ParseTest.Unit/ObjectStateTests.cs rename to ParseCore/Test/ObjectStateTests.cs index 1d9cdfb2..5f202b8d 100644 --- a/ParseTest.Unit/ObjectStateTests.cs +++ b/ParseCore/Test/ObjectStateTests.cs @@ -1,6 +1,6 @@ using NUnit.Framework; using Parse; -using Parse.Internal; +using Parse.Core.Internal; using System; using System.Linq; using System.Collections.Generic; diff --git a/ParseTest.Unit/ObjectTests.cs b/ParseCore/Test/ObjectTests.cs similarity index 89% rename from ParseTest.Unit/ObjectTests.cs rename to ParseCore/Test/ObjectTests.cs index 026d61a2..c7aef0d7 100644 --- a/ParseTest.Unit/ObjectTests.cs +++ b/ParseCore/Test/ObjectTests.cs @@ -1,7 +1,7 @@ using Moq; using NUnit.Framework; using Parse; -using Parse.Internal; +using Parse.Core.Internal; using System; using System.Linq; using System.Collections.Generic; @@ -23,8 +23,7 @@ private class UnregisteredSubClass : ParseObject { [TearDown] public void TearDown() { - ParseCorePlugins.Instance.ObjectController = null; - ParseCorePlugins.Instance.CurrentUserController = null; + ParseCorePlugins.Instance.Reset(); } [Test] @@ -68,8 +67,6 @@ public void TestParseObjectCreateWithGeneric() { Assert.Null(obj2.CreatedAt); Assert.False(obj2.IsDataAvailable); Assert.False(obj2.IsDirty); - - ParseObject.UnregisterSubclass(); } [Test] @@ -88,7 +85,7 @@ public void TestFromState() { { "sessionToken", "se551onT0k3n" } } }; - ParseObject obj = ParseObject.FromState(state, "Omitted"); + ParseObject obj = ParseObjectExtensions.FromState(state, "Omitted"); Assert.AreEqual("waGiManPutr4Pet1r", obj.ObjectId); Assert.AreEqual("Pagi", obj.ClassName); @@ -105,10 +102,10 @@ public void TestRegisterSubclass() { ParseObject.RegisterSubclass(); Assert.DoesNotThrow(() => ParseObject.Create()); - ParseObject.UnregisterSubclass(); + ParseCorePlugins.Instance.SubclassingController.UnregisterSubclass(typeof(UnregisteredSubClass)); Assert.DoesNotThrow(() => ParseObject.Create()); - ParseObject.UnregisterSubclass(); + ParseCorePlugins.Instance.SubclassingController.UnregisterSubclass(typeof(SubClass)); Assert.Throws(() => ParseObject.Create()); } @@ -118,13 +115,13 @@ public void TestRevert() { obj["gogo"] = true; Assert.True(obj.IsDirty); - Assert.AreEqual(1, obj.CurrentOperations.Count); + Assert.AreEqual(1, obj.GetCurrentOperations().Count); Assert.True(obj.ContainsKey("gogo")); obj.Revert(); Assert.True(obj.IsDirty); - Assert.AreEqual(0, obj.CurrentOperations.Count); + Assert.AreEqual(0, obj.GetCurrentOperations().Count); Assert.False(obj.ContainsKey("gogo")); } @@ -141,18 +138,18 @@ public void TestDeepTraversal() { obj["someBool"] = true; obj["someInt"] = 23; - IEnumerable traverseResult = ParseObject.DeepTraversal(obj, true, true); + IEnumerable traverseResult = ParseObjectExtensions.DeepTraversal(obj, true, true); Assert.AreEqual(8, traverseResult.Count()); // Don't traverse beyond the root (since root is ParseObject) - traverseResult = ParseObject.DeepTraversal(obj, false, true); + traverseResult = ParseObjectExtensions.DeepTraversal(obj, false, true); Assert.AreEqual(1, traverseResult.Count()); - traverseResult = ParseObject.DeepTraversal(someDict, false, true); + traverseResult = ParseObjectExtensions.DeepTraversal(someDict, false, true); Assert.AreEqual(2, traverseResult.Count()); // Should ignore root - traverseResult = ParseObject.DeepTraversal(obj, true, false); + traverseResult = ParseObjectExtensions.DeepTraversal(obj, true, false); Assert.AreEqual(7, traverseResult.Count()); } @@ -176,7 +173,7 @@ public void TestRemove() { } }; - obj = ParseObject.FromState(state, "Corgi"); + obj = ParseObjectExtensions.FromState(state, "Corgi"); Assert.True(obj.ContainsKey("username")); Assert.True(obj.ContainsKey("sessionToken")); @@ -224,7 +221,7 @@ public void TestPropertiesGetterSetter() { { "sessionToken", "se551onT0k3n" } } }; - ParseObject obj = ParseObject.FromState(state, "Omitted"); + ParseObject obj = ParseObjectExtensions.FromState(state, "Omitted"); Assert.AreEqual("Pagi", obj.ClassName); Assert.AreEqual(now, obj.CreatedAt); @@ -300,7 +297,7 @@ public void TestTryGetValue() { { "sessionToken", "se551onT0k3n" } } }; - ParseObject obj = ParseObject.FromState(state, "Omitted"); + ParseObject obj = ParseObjectExtensions.FromState(state, "Omitted"); string res = null; obj.TryGetValue("username", out res); Assert.AreEqual("kevin", res); @@ -324,7 +321,7 @@ public void TestGet() { { "sessionToken", "se551onT0k3n" } } }; - ParseObject obj = ParseObject.FromState(state, "Omitted"); + ParseObject obj = ParseObjectExtensions.FromState(state, "Omitted"); Assert.AreEqual("kevin", obj.Get("username")); Assert.Throws(() => obj.Get("username")); Assert.Throws(() => obj.Get("missingItem")); @@ -351,7 +348,7 @@ public void TestKeys() { { "sessionToken", "se551onT0k3n" } } }; - ParseObject obj = ParseObject.FromState(state, "Omitted"); + ParseObject obj = ParseObjectExtensions.FromState(state, "Omitted"); Assert.AreEqual(2, obj.Keys.Count); obj["additional"] = true; @@ -372,7 +369,7 @@ public void TestAdd() { { "sessionToken", "se551onT0k3n" } } }; - ParseObject obj = ParseObject.FromState(state, "Omitted"); + ParseObject obj = ParseObjectExtensions.FromState(state, "Omitted"); Assert.Throws(() => obj.Add("username", "kevin")); obj.Add("zeus", "bewithyou"); @@ -390,7 +387,7 @@ public void TestEnumerator() { { "sessionToken", "se551onT0k3n" } } }; - ParseObject obj = ParseObject.FromState(state, "Omitted"); + ParseObject obj = ParseObjectExtensions.FromState(state, "Omitted"); int count = 0; foreach (var key in obj) { @@ -411,11 +408,11 @@ public void TestGetQuery() { ParseObject.RegisterSubclass(); ParseQuery query = ParseObject.GetQuery("UnregisteredSubClass"); - Assert.AreEqual("UnregisteredSubClass", query.ClassName); + Assert.AreEqual("UnregisteredSubClass", query.GetClassName()); Assert.Throws(() => ParseObject.GetQuery("SubClass")); - ParseObject.UnregisterSubclass(); + ParseCorePlugins.Instance.SubclassingController.UnregisterSubclass(typeof(SubClass)); } [Test] diff --git a/ParseCore/Test/ParseCore.Test.Unit.NetFx45.csproj b/ParseCore/Test/ParseCore.Test.Unit.NetFx45.csproj new file mode 100644 index 00000000..0c7ba218 --- /dev/null +++ b/ParseCore/Test/ParseCore.Test.Unit.NetFx45.csproj @@ -0,0 +1,173 @@ + + + + Debug + AnyCPU + {F3937A46-F58A-4960-AFE6-AF664096C23A} + Library + Properties + ParseTest + ParseTest.Unit.NetFx45 + v4.5 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + ..\ + true + + + true + full + false + bin\Debug\ + TRACE;DEBUG;NETFX + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + false + + + + ..\..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll + True + + + ..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll + True + + + ..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll + True + + + ..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll + True + + + ..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll + True + + + ..\..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll + True + + + ..\..\packages\PCLStorage.1.0.2\lib\net45\PCLStorage.dll + True + + + ..\..\packages\PCLStorage.1.0.2\lib\net45\PCLStorage.Abstractions.dll + True + + + + + ..\..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll + True + + + ..\..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer + + + + + {4bbce4f8-c097-4680-8b07-b69d567eaa5b} + AssemblyLister.NetFx + + + {de07a443-9619-4bd7-b540-41296f8a2959} + ParseCommon.Portable + + + {f3f65351-2ce1-4412-84b4-c36f34eab928} + ParseCore.Portable + + + + + + + False + + + False + + + False + + + False + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/ParseCore/Test/Properties/AssemblyInfo.cs b/ParseCore/Test/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..c29d1b95 --- /dev/null +++ b/ParseCore/Test/Properties/AssemblyInfo.cs @@ -0,0 +1,16 @@ +using System.Reflection; + +// 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("ParseTest")] +[assembly: AssemblyDescription("Parse unit test project.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ParseTest")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/ParseTest.Unit/RelationTests.cs b/ParseCore/Test/RelationTests.cs similarity index 79% rename from ParseTest.Unit/RelationTests.cs rename to ParseCore/Test/RelationTests.cs index c9123f07..56e5796e 100644 --- a/ParseTest.Unit/RelationTests.cs +++ b/ParseCore/Test/RelationTests.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using NUnit.Framework; using Parse; -using Parse.Internal; +using Parse.Core.Internal; namespace ParseTest { [TestFixture] @@ -10,12 +10,12 @@ public class RelationTests { public void TestRelationQuery() { ParseObject parent = ParseObject.CreateWithoutData("Foo", "abcxyz"); - ParseRelation relation = new ParseRelation(parent, "child"); + ParseRelation relation = parent.GetRelation("child"); ParseQuery query = relation.Query; // Client side, the query will appear to be for the wrong class. // When the server recieves it, the class name will be redirected using the 'redirectClassNameForKey' option. - Assert.AreEqual("Foo", query.ClassName); + Assert.AreEqual("Foo", query.GetClassName()); IDictionary encoded = query.BuildParameters(); diff --git a/ParseTest.Unit/SessionControllerTests.cs b/ParseCore/Test/SessionControllerTests.cs similarity index 88% rename from ParseTest.Unit/SessionControllerTests.cs rename to ParseCore/Test/SessionControllerTests.cs index f8cd3e63..380f341a 100644 --- a/ParseTest.Unit/SessionControllerTests.cs +++ b/ParseCore/Test/SessionControllerTests.cs @@ -1,5 +1,5 @@ using Parse; -using Parse.Internal; +using Parse.Core.Internal; using NUnit.Framework; using Moq; using System; @@ -107,6 +107,18 @@ public Task TestUpgradeToRevocableSession() { }); } + [Test] + public void TestIsRevocableSessionToken() { + IParseSessionController sessionController = new ParseSessionController(Mock.Of()); + Assert.True(sessionController.IsRevocableSessionToken("r:session")); + Assert.True(sessionController.IsRevocableSessionToken("r:session:r:")); + Assert.True(sessionController.IsRevocableSessionToken("session:r:")); + Assert.False(sessionController.IsRevocableSessionToken("session:s:d:r")); + Assert.False(sessionController.IsRevocableSessionToken("s:ession:s:d:r")); + Assert.False(sessionController.IsRevocableSessionToken("")); + } + + private Mock CreateMockRunner(Tuple> response) { var mockRunner = new Mock(); mockRunner.Setup(obj => obj.RunCommandAsync(It.IsAny(), diff --git a/ParseTest.Unit/SessionTests.cs b/ParseCore/Test/SessionTests.cs similarity index 71% rename from ParseTest.Unit/SessionTests.cs rename to ParseCore/Test/SessionTests.cs index 9bd51e63..6f304731 100644 --- a/ParseTest.Unit/SessionTests.cs +++ b/ParseCore/Test/SessionTests.cs @@ -1,5 +1,5 @@ using Parse; -using Parse.Internal; +using Parse.Core.Internal; using NUnit.Framework; using Moq; using System; @@ -19,10 +19,7 @@ public void SetUp() { [TearDown] public void TearDown() { - ParseCorePlugins.Instance.SessionController = null; - ParseCorePlugins.Instance.CurrentUserController = null; - ParseObject.UnregisterSubclass(); - ParseObject.UnregisterSubclass(); + ParseCorePlugins.Instance.Reset(); } [Test] @@ -37,21 +34,11 @@ public void TestGetSessionToken() { { "sessionToken", "llaKcolnu" } } }; - ParseSession session = ParseObject.FromState(state, "_Session"); + ParseSession session = ParseObjectExtensions.FromState(state, "_Session"); Assert.NotNull(session); Assert.AreEqual("llaKcolnu", session.SessionToken); } - [Test] - public void TestIsRevocableSessionToken() { - Assert.True(ParseSession.IsRevocableSessionToken("r:session")); - Assert.True(ParseSession.IsRevocableSessionToken("r:session:r:")); - Assert.True(ParseSession.IsRevocableSessionToken("session:r:")); - Assert.False(ParseSession.IsRevocableSessionToken("session:s:d:r")); - Assert.False(ParseSession.IsRevocableSessionToken("s:ession:s:d:r")); - Assert.False(ParseSession.IsRevocableSessionToken("")); - } - [Test] [AsyncStateMachine(typeof(SessionTests))] public Task TestGetCurrentSession() { @@ -69,13 +56,15 @@ public Task TestGetCurrentSession() { { "sessionToken", "llaKcolnu" } } }; - ParseUser user = ParseObject.FromState(userState, "_User"); + ParseUser user = ParseObjectExtensions.FromState(userState, "_User"); var mockCurrentUserController = new Mock(); mockCurrentUserController.Setup(obj => obj.GetAsync(It.IsAny())) .Returns(Task.FromResult(user)); - - ParseCorePlugins.Instance.SessionController = mockController.Object; - ParseCorePlugins.Instance.CurrentUserController = mockCurrentUserController.Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + SessionController = mockController.Object, + CurrentUserController = mockCurrentUserController.Object, + }; + ParseObject.RegisterSubclass(); return ParseSession.GetCurrentSessionAsync().ContinueWith(t => { Assert.False(t.IsFaulted); @@ -93,8 +82,10 @@ public Task TestGetCurrentSession() { public Task TestGetCurrentSessionWithNoCurrentUser() { var mockController = new Mock(); var mockCurrentUserController = new Mock(); - ParseCorePlugins.Instance.SessionController = mockController.Object; - ParseCorePlugins.Instance.CurrentUserController = mockCurrentUserController.Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + SessionController = mockController.Object, + CurrentUserController = mockCurrentUserController.Object, + }; return ParseSession.GetCurrentSessionAsync().ContinueWith(t => { Assert.False(t.IsFaulted); @@ -107,10 +98,16 @@ public Task TestGetCurrentSessionWithNoCurrentUser() { [AsyncStateMachine(typeof(SessionTests))] public Task TestRevoke() { var mockController = new Mock(); - ParseCorePlugins.Instance.SessionController = mockController.Object; + mockController + .Setup(sessionController => sessionController.IsRevocableSessionToken(It.IsAny())) + .Returns(true); + + ParseCorePlugins.Instance = new ParseCorePlugins { + SessionController = mockController.Object + }; CancellationTokenSource source = new CancellationTokenSource(); - return ParseSession.RevokeAsync("r:someSession", source.Token).ContinueWith(t => { + return ParseSessionExtensions.RevokeAsync("r:someSession", source.Token).ContinueWith(t => { Assert.False(t.IsFaulted); Assert.False(t.IsCanceled); mockController.Verify(obj => obj.RevokeAsync(It.Is(sessionToken => sessionToken == "r:someSession"), @@ -131,11 +128,15 @@ public Task TestUpgradeToRevocableSession() { It.IsAny())).Returns(Task.FromResult(state)); var mockCurrentUserController = new Mock(); - ParseCorePlugins.Instance.SessionController = mockController.Object; - ParseCorePlugins.Instance.CurrentUserController = mockCurrentUserController.Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + SessionController = mockController.Object, + CurrentUserController = mockCurrentUserController.Object, + }; + ParseObject.RegisterSubclass(); + ParseObject.RegisterSubclass(); CancellationTokenSource source = new CancellationTokenSource(); - return ParseSession.UpgradeToRevocableSessionAsync("someSession", source.Token).ContinueWith(t => { + return ParseSessionExtensions.UpgradeToRevocableSessionAsync("someSession", source.Token).ContinueWith(t => { Assert.False(t.IsFaulted); Assert.False(t.IsCanceled); mockController.Verify(obj => obj.UpgradeToRevocableSessionAsync(It.Is(sessionToken => sessionToken == "someSession"), diff --git a/ParseTest.Unit/UserControllerTests.cs b/ParseCore/Test/UserControllerTests.cs similarity index 99% rename from ParseTest.Unit/UserControllerTests.cs rename to ParseCore/Test/UserControllerTests.cs index 851cafaf..8e1db0cc 100644 --- a/ParseTest.Unit/UserControllerTests.cs +++ b/ParseCore/Test/UserControllerTests.cs @@ -1,5 +1,5 @@ using Parse; -using Parse.Internal; +using Parse.Core.Internal; using NUnit.Framework; using Moq; using System; diff --git a/ParseTest.Unit/UserTests.cs b/ParseCore/Test/UserTests.cs similarity index 74% rename from ParseTest.Unit/UserTests.cs rename to ParseCore/Test/UserTests.cs index e9438dfe..2989d4a3 100644 --- a/ParseTest.Unit/UserTests.cs +++ b/ParseCore/Test/UserTests.cs @@ -1,5 +1,5 @@ using Parse; -using Parse.Internal; +using Parse.Core.Internal; using NUnit.Framework; using Moq; using System; @@ -19,12 +19,7 @@ public void SetUp() { [TearDown] public void TearDown() { - ParseCorePlugins.Instance.UserController = null; - ParseCorePlugins.Instance.CurrentUserController = null; - ParseCorePlugins.Instance.SessionController = null; - ParseCorePlugins.Instance.ObjectController = null; - ParseObject.UnregisterSubclass(); - ParseObject.UnregisterSubclass(); + ParseCorePlugins.Instance = null; } [Test] @@ -35,7 +30,7 @@ public void TestRemoveFields() { { "name", "andrew" } } }; - ParseUser user = ParseObject.FromState(state, "_User"); + ParseUser user = ParseObjectExtensions.FromState(state, "_User"); Assert.Throws(() => user.Remove("username")); Assert.DoesNotThrow(() => user.Remove("name")); Assert.False(user.ContainsKey("name")); @@ -49,7 +44,7 @@ public void TestSessionTokenGetter() { { "sessionToken", "se551onT0k3n" } } }; - ParseUser user = ParseObject.FromState(state, "_User"); + ParseUser user = ParseObjectExtensions.FromState(state, "_User"); Assert.AreEqual("se551onT0k3n", user.SessionToken); } @@ -60,7 +55,7 @@ public void TestUsernameGetterSetter() { { "username", "kevin" }, } }; - ParseUser user = ParseObject.FromState(state, "_User"); + ParseUser user = ParseObjectExtensions.FromState(state, "_User"); Assert.AreEqual("kevin", user.Username); user.Username = "ilya"; Assert.AreEqual("ilya", user.Username); @@ -74,10 +69,10 @@ public void TestPasswordGetterSetter() { { "password", "hurrah" }, } }; - ParseUser user = ParseObject.FromState(state, "_User"); - Assert.AreEqual("hurrah", user.State["password"]); + ParseUser user = ParseObjectExtensions.FromState(state, "_User"); + Assert.AreEqual("hurrah", user.GetState()["password"]); user.Password = "david"; - Assert.NotNull(user.CurrentOperations["password"]); + Assert.NotNull(user.GetCurrentOperations()["password"]); } [Test] @@ -89,7 +84,7 @@ public void TestEmailGetterSetter() { { "sessionToken", "se551onT0k3n" } } }; - ParseUser user = ParseObject.FromState(state, "_User"); + ParseUser user = ParseObjectExtensions.FromState(state, "_User"); Assert.AreEqual("james@parse.com", user.Email); user.Email = "bryan@parse.com"; Assert.AreEqual("bryan@parse.com", user.Email); @@ -107,9 +102,9 @@ public void TestAuthDataGetter() { }} } }; - ParseUser user = ParseObject.FromState(state, "_User"); - Assert.AreEqual(1, user.AuthData.Count); - Assert.IsInstanceOf>(user.AuthData["facebook"]); + ParseUser user = ParseObjectExtensions.FromState(state, "_User"); + Assert.AreEqual(1, user.GetAuthData().Count); + Assert.IsInstanceOf>(user.GetAuthData()["facebook"]); } [Test] @@ -125,11 +120,15 @@ public void TestIsAuthenticated() { { "sessionToken", "llaKcolnu" } } }; - ParseUser user = ParseObject.FromState(state, "_User"); + ParseUser user = ParseObjectExtensions.FromState(state, "_User"); var mockCurrentUserController = new Mock(); mockCurrentUserController.Setup(obj => obj.GetAsync(It.IsAny())) .Returns(Task.FromResult(user)); - ParseCorePlugins.Instance.CurrentUserController = mockCurrentUserController.Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + CurrentUserController = mockCurrentUserController.Object + }; + ParseObject.RegisterSubclass(); + ParseObject.RegisterSubclass(); Assert.True(user.IsAuthenticated); } @@ -148,12 +147,16 @@ public void TestIsAuthenticatedWithOtherParseUser() { { "sessionToken", "llaKcolnu" } } }; - ParseUser user = ParseObject.FromState(state, "_User"); - ParseUser user2 = ParseObject.FromState(state2, "_User"); + ParseUser user = ParseObjectExtensions.FromState(state, "_User"); + ParseUser user2 = ParseObjectExtensions.FromState(state2, "_User"); var mockCurrentUserController = new Mock(); mockCurrentUserController.Setup(obj => obj.GetAsync(It.IsAny())) .Returns(Task.FromResult(user)); - ParseCorePlugins.Instance.CurrentUserController = mockCurrentUserController.Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + CurrentUserController = mockCurrentUserController.Object + }; + ParseObject.RegisterSubclass(); + ParseObject.RegisterSubclass(); Assert.False(user2.IsAuthenticated); } @@ -166,7 +169,7 @@ public Task TestSignUpWithInvalidServerData() { { "sessionToken", "llaKcolnu" } } }; - ParseUser user = ParseObject.FromState(state, "_User"); + ParseUser user = ParseObjectExtensions.FromState(state, "_User"); return user.SignUpAsync().ContinueWith(t => { Assert.True(t.IsFaulted); @@ -187,12 +190,16 @@ public Task TestSignUp() { IObjectState newState = new MutableObjectState { ObjectId = "some0neTol4v4" }; - ParseUser user = ParseObject.FromState(state, "_User"); + ParseUser user = ParseObjectExtensions.FromState(state, "_User"); var mockController = new Mock(); mockController.Setup(obj => obj.SignUpAsync(It.IsAny(), It.IsAny>(), It.IsAny())).Returns(Task.FromResult(newState)); - ParseCorePlugins.Instance.UserController = mockController.Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + UserController = mockController.Object + }; + ParseObject.RegisterSubclass(); + ParseObject.RegisterSubclass(); return user.SignUpAsync().ContinueWith(t => { Assert.False(t.IsFaulted); @@ -202,7 +209,7 @@ public Task TestSignUp() { It.IsAny()), Times.Exactly(1)); Assert.False(user.IsDirty); Assert.AreEqual("ihave", user.Username); - Assert.False(user.State.ContainsKey("password")); + Assert.False(user.GetState().ContainsKey("password")); Assert.AreEqual("some0neTol4v4", user.ObjectId); }); } @@ -224,7 +231,11 @@ public Task TestLogIn() { mockController.Setup(obj => obj.LogInAsync("ihave", "adream", It.IsAny())).Returns(Task.FromResult(newState)); - ParseCorePlugins.Instance.UserController = mockController.Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + UserController = mockController.Object + }; + ParseObject.RegisterSubclass(); + ParseObject.RegisterSubclass(); return ParseUser.LogInAsync("ihave", "adream").ContinueWith(t => { Assert.False(t.IsFaulted); @@ -252,7 +263,11 @@ public Task TestBecome() { var mockController = new Mock(); mockController.Setup(obj => obj.GetUserAsync("llaKcolnu", It.IsAny())).Returns(Task.FromResult(state)); - ParseCorePlugins.Instance.UserController = mockController.Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + UserController = mockController.Object + }; + ParseObject.RegisterSubclass(); + ParseObject.RegisterSubclass(); return ParseUser.BecomeAsync("llaKcolnu").ContinueWith(t => { Assert.False(t.IsFaulted); @@ -274,13 +289,19 @@ public Task TestLogOut() { { "sessionToken", "r:llaKcolnu" } } }; - ParseUser user = ParseObject.FromState(state, "_User"); + ParseUser user = ParseObjectExtensions.FromState(state, "_User"); var mockCurrentUserController = new Mock(); mockCurrentUserController.Setup(obj => obj.GetAsync(It.IsAny())) .Returns(Task.FromResult(user)); var mockSessionController = new Mock(); - ParseCorePlugins.Instance.CurrentUserController = mockCurrentUserController.Object; - ParseCorePlugins.Instance.SessionController = mockSessionController.Object; + mockSessionController.Setup(c => c.IsRevocableSessionToken(It.IsAny())).Returns(true); + + ParseCorePlugins.Instance = new ParseCorePlugins { + CurrentUserController = mockCurrentUserController.Object, + SessionController = mockSessionController.Object + }; + ParseObject.RegisterSubclass(); + ParseObject.RegisterSubclass(); return ParseUser.LogOutAsync().ContinueWith(t => { Assert.False(t.IsFaulted); @@ -297,11 +318,15 @@ public void TestCurrentUser() { { "sessionToken", "llaKcolnu" } } }; - ParseUser user = ParseObject.FromState(state, "_User"); + ParseUser user = ParseObjectExtensions.FromState(state, "_User"); var mockCurrentUserController = new Mock(); mockCurrentUserController.Setup(obj => obj.GetAsync(It.IsAny())) .Returns(Task.FromResult(user)); - ParseCorePlugins.Instance.CurrentUserController = mockCurrentUserController.Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + CurrentUserController = mockCurrentUserController.Object, + }; + ParseObject.RegisterSubclass(); + ParseObject.RegisterSubclass(); Assert.AreEqual(user, ParseUser.CurrentUser); } @@ -309,7 +334,11 @@ public void TestCurrentUser() { [Test] public void TestCurrentUserWithEmptyResult() { var mockCurrentUserController = new Mock(); - ParseCorePlugins.Instance.CurrentUserController = mockCurrentUserController.Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + CurrentUserController = mockCurrentUserController.Object + }; + ParseObject.RegisterSubclass(); + ParseObject.RegisterSubclass(); Assert.Null(ParseUser.CurrentUser); } @@ -327,13 +356,17 @@ public Task TestRevocableSession() { { "sessionToken", "r:llaKcolnu" } } }; - ParseUser user = ParseObject.FromState(state, "_User"); + ParseUser user = ParseObjectExtensions.FromState(state, "_User"); var mockSessionController = new Mock(); mockSessionController.Setup(obj => obj.UpgradeToRevocableSessionAsync("llaKcolnu", It.IsAny())).Returns(Task.FromResult(newState)); - ParseCorePlugins.Instance.SessionController = mockSessionController.Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + SessionController = mockSessionController.Object + }; + ParseObject.RegisterSubclass(); + ParseObject.RegisterSubclass(); - return user.UpgradeToRevocableSessionAsync().ContinueWith(t => { + return user.UpgradeToRevocableSessionAsync(CancellationToken.None).ContinueWith(t => { Assert.False(t.IsFaulted); Assert.False(t.IsCanceled); mockSessionController.Verify(obj => obj.UpgradeToRevocableSessionAsync("llaKcolnu", @@ -346,7 +379,11 @@ public Task TestRevocableSession() { [AsyncStateMachine(typeof(UserTests))] public Task TestRequestPasswordReset() { var mockController = new Mock(); - ParseCorePlugins.Instance.UserController = mockController.Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + UserController = mockController.Object + }; + ParseObject.RegisterSubclass(); + ParseObject.RegisterSubclass(); return ParseUser.RequestPasswordResetAsync("gogo@parse.com").ContinueWith(t => { Assert.False(t.IsFaulted); @@ -372,14 +409,18 @@ public Task TestUserSave() { { "Alliance", "rekt" } } }; - ParseUser user = ParseObject.FromState(state, "_User"); + ParseUser user = ParseObjectExtensions.FromState(state, "_User"); var mockObjectController = new Mock(); mockObjectController.Setup(obj => obj.SaveAsync(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(newState)); - ParseCorePlugins.Instance.ObjectController = mockObjectController.Object; - ParseCorePlugins.Instance.CurrentUserController = new Mock().Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + ObjectController = mockObjectController.Object, + CurrentUserController = new Mock().Object + }; + ParseObject.RegisterSubclass(); + ParseObject.RegisterSubclass(); user["Alliance"] = "rekt"; return user.SaveAsync().ContinueWith(t => { @@ -391,7 +432,7 @@ public Task TestUserSave() { It.IsAny()), Times.Exactly(1)); Assert.False(user.IsDirty); Assert.AreEqual("ihave", user.Username); - Assert.False(user.State.ContainsKey("password")); + Assert.False(user.GetState().ContainsKey("password")); Assert.AreEqual("some0neTol4v4", user.ObjectId); Assert.AreEqual("rekt", user["Alliance"]); }); @@ -413,13 +454,17 @@ public Task TestUserFetch() { { "Alliance", "rekt" } } }; - ParseUser user = ParseObject.FromState(state, "_User"); + ParseUser user = ParseObjectExtensions.FromState(state, "_User"); var mockObjectController = new Mock(); mockObjectController.Setup(obj => obj.FetchAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(newState)); - ParseCorePlugins.Instance.ObjectController = mockObjectController.Object; - ParseCorePlugins.Instance.CurrentUserController = new Mock().Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + ObjectController = mockObjectController.Object, + CurrentUserController = new Mock().Object + }; + ParseObject.RegisterSubclass(); + ParseObject.RegisterSubclass(); user["Alliance"] = "rekt"; return user.FetchAsync().ContinueWith(t => { @@ -430,7 +475,7 @@ public Task TestUserFetch() { It.IsAny()), Times.Exactly(1)); Assert.True(user.IsDirty); Assert.AreEqual("ihave", user.Username); - Assert.True(user.State.ContainsKey("password")); + Assert.True(user.GetState().ContainsKey("password")); Assert.AreEqual("some0neTol4v4", user.ObjectId); Assert.AreEqual("rekt", user["Alliance"]); }); @@ -450,14 +495,18 @@ public Task TestLink() { { "garden", "ofWords" } } }; - ParseUser user = ParseObject.FromState(state, "_User"); + ParseUser user = ParseObjectExtensions.FromState(state, "_User"); var mockObjectController = new Mock(); mockObjectController.Setup(obj => obj.SaveAsync(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(newState)); - ParseCorePlugins.Instance.ObjectController = mockObjectController.Object; - ParseCorePlugins.Instance.CurrentUserController = new Mock().Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + ObjectController = mockObjectController.Object, + CurrentUserController = new Mock().Object + }; + ParseObject.RegisterSubclass(); + ParseObject.RegisterSubclass(); return user.LinkWithAsync("parse", new Dictionary(), CancellationToken.None).ContinueWith(t => { Assert.False(t.IsFaulted); @@ -467,8 +516,8 @@ public Task TestLink() { It.IsAny(), It.IsAny()), Times.Exactly(1)); Assert.False(user.IsDirty); - Assert.NotNull(user.AuthData); - Assert.NotNull(user.AuthData["parse"]); + Assert.NotNull(user.GetAuthData()); + Assert.NotNull(user.GetAuthData()["parse"]); Assert.AreEqual("some0neTol4v4", user.ObjectId); Assert.AreEqual("ofWords", user["garden"]); }); @@ -491,7 +540,7 @@ public Task TestUnlink() { { "garden", "ofWords" } } }; - ParseUser user = ParseObject.FromState(state, "_User"); + ParseUser user = ParseObjectExtensions.FromState(state, "_User"); var mockObjectController = new Mock(); mockObjectController.Setup(obj => obj.SaveAsync(It.IsAny(), It.IsAny>(), @@ -499,8 +548,12 @@ public Task TestUnlink() { It.IsAny())).Returns(Task.FromResult(newState)); var mockCurrentUserController = new Mock(); mockCurrentUserController.Setup(obj => obj.IsCurrent(user)).Returns(true); - ParseCorePlugins.Instance.ObjectController = mockObjectController.Object; - ParseCorePlugins.Instance.CurrentUserController = mockCurrentUserController.Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + ObjectController = mockObjectController.Object, + CurrentUserController = mockCurrentUserController.Object, + }; + ParseObject.RegisterSubclass(); + ParseObject.RegisterSubclass(); return user.UnlinkFromAsync("parse", CancellationToken.None).ContinueWith(t => { Assert.False(t.IsFaulted); @@ -510,8 +563,8 @@ public Task TestUnlink() { It.IsAny(), It.IsAny()), Times.Exactly(1)); Assert.False(user.IsDirty); - Assert.NotNull(user.AuthData); - Assert.False(user.AuthData.ContainsKey("parse")); + Assert.NotNull(user.GetAuthData()); + Assert.False(user.GetAuthData().ContainsKey("parse")); Assert.AreEqual("some0neTol4v4", user.ObjectId); Assert.AreEqual("ofWords", user["garden"]); }); @@ -534,7 +587,7 @@ public Task TestUnlinkNonCurrentUser() { { "garden", "ofWords" } } }; - ParseUser user = ParseObject.FromState(state, "_User"); + ParseUser user = ParseObjectExtensions.FromState(state, "_User"); var mockObjectController = new Mock(); mockObjectController.Setup(obj => obj.SaveAsync(It.IsAny(), It.IsAny>(), @@ -542,8 +595,12 @@ public Task TestUnlinkNonCurrentUser() { It.IsAny())).Returns(Task.FromResult(newState)); var mockCurrentUserController = new Mock(); mockCurrentUserController.Setup(obj => obj.IsCurrent(user)).Returns(false); - ParseCorePlugins.Instance.ObjectController = mockObjectController.Object; - ParseCorePlugins.Instance.CurrentUserController = mockCurrentUserController.Object; + ParseCorePlugins.Instance = new ParseCorePlugins { + ObjectController = mockObjectController.Object, + CurrentUserController = mockCurrentUserController.Object, + }; + ParseObject.RegisterSubclass(); + ParseObject.RegisterSubclass(); return user.UnlinkFromAsync("parse", CancellationToken.None).ContinueWith(t => { Assert.False(t.IsFaulted); @@ -553,9 +610,9 @@ public Task TestUnlinkNonCurrentUser() { It.IsAny(), It.IsAny()), Times.Exactly(1)); Assert.False(user.IsDirty); - Assert.NotNull(user.AuthData); - Assert.True(user.AuthData.ContainsKey("parse")); - Assert.Null(user.AuthData["parse"]); + Assert.NotNull(user.GetAuthData()); + Assert.True(user.GetAuthData().ContainsKey("parse")); + Assert.Null(user.GetAuthData()["parse"]); Assert.AreEqual("some0neTol4v4", user.ObjectId); Assert.AreEqual("ofWords", user["garden"]); }); @@ -574,9 +631,14 @@ public Task TestLogInWith() { mockController.Setup(obj => obj.LogInAsync("parse", It.IsAny>(), It.IsAny())).Returns(Task.FromResult(state)); - ParseCorePlugins.Instance.UserController = mockController.Object; - return ParseUser.LogInWithAsync("parse", new Dictionary(), CancellationToken.None).ContinueWith(t => { + ParseCorePlugins.Instance = new ParseCorePlugins { + UserController = mockController.Object + }; + ParseObject.RegisterSubclass(); + ParseObject.RegisterSubclass(); + + return ParseUserExtensions.LogInWithAsync("parse", new Dictionary(), CancellationToken.None).ContinueWith(t => { Assert.False(t.IsFaulted); Assert.False(t.IsCanceled); mockController.Verify(obj => obj.LogInAsync("parse", @@ -584,8 +646,8 @@ public Task TestLogInWith() { It.IsAny()), Times.Exactly(1)); var user = t.Result; - Assert.NotNull(user.AuthData); - Assert.NotNull(user.AuthData["parse"]); + Assert.NotNull(user.GetAuthData()); + Assert.NotNull(user.GetAuthData()["parse"]); Assert.AreEqual("some0neTol4v4", user.ObjectId); }); } diff --git a/ParseCore/Test/app.config b/ParseCore/Test/app.config new file mode 100644 index 00000000..940d25ca --- /dev/null +++ b/ParseCore/Test/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/ParseCore/Test/packages.config b/ParseCore/Test/packages.config new file mode 100644 index 00000000..499bc7cb --- /dev/null +++ b/ParseCore/Test/packages.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Parse/Internal/Push/Android/GcmRegistrar.cs b/ParsePush/Internal/Android/GcmRegistrar.cs similarity index 99% rename from Parse/Internal/Push/Android/GcmRegistrar.cs rename to ParsePush/Internal/Android/GcmRegistrar.cs index 5357611f..7b9a115d 100644 --- a/Parse/Internal/Push/Android/GcmRegistrar.cs +++ b/ParsePush/Internal/Android/GcmRegistrar.cs @@ -5,6 +5,7 @@ using Android.Content; using Android.OS; using System.Threading.Tasks; +using Parse.Core.Internal; namespace Parse { internal class GcmRegistrar { @@ -120,7 +121,7 @@ private Request(Context context, string senderId) { this.senderId = senderId; appIntent = PendingIntent.GetBroadcast(context, 0, new Intent(), 0); } - + private void Send() { Intent intent = new Intent(IntentRegisterAction); intent.SetPackage("com.google.android.gsf"); @@ -137,4 +138,3 @@ private void Send() { } } } - diff --git a/Parse/Internal/Utilities/Android/ManifestInfo.cs b/ParsePush/Internal/Android/ManifestInfo.cs similarity index 99% rename from Parse/Internal/Utilities/Android/ManifestInfo.cs rename to ParsePush/Internal/Android/ManifestInfo.cs index 670ad3dd..115a27c0 100644 --- a/Parse/Internal/Utilities/Android/ManifestInfo.cs +++ b/ParsePush/Internal/Android/ManifestInfo.cs @@ -325,4 +325,3 @@ private static PackageInfo getPackageInfo(string name) { } } } - diff --git a/Parse/Internal/Push/Android/NotificationCompat.cs b/ParsePush/Internal/Android/NotificationCompat.cs similarity index 100% rename from Parse/Internal/Push/Android/NotificationCompat.cs rename to ParsePush/Internal/Android/NotificationCompat.cs diff --git a/Parse/Internal/Push/Android/ParseWakefulHelper.cs b/ParsePush/Internal/Android/ParseWakefulHelper.cs similarity index 100% rename from Parse/Internal/Push/Android/ParseWakefulHelper.cs rename to ParsePush/Internal/Android/ParseWakefulHelper.cs diff --git a/Parse/Internal/Push/Coder/ParsePushEncoder.cs b/ParsePush/Internal/Coder/ParsePushEncoder.cs similarity index 87% rename from Parse/Internal/Push/Coder/ParsePushEncoder.cs rename to ParsePush/Internal/Coder/ParsePushEncoder.cs index 034e6723..c3e8fd89 100644 --- a/Parse/Internal/Push/Coder/ParsePushEncoder.cs +++ b/ParsePush/Internal/Coder/ParsePushEncoder.cs @@ -1,10 +1,13 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. using System; +using System.Linq; using System.Collections.Generic; +using Parse.Common.Internal; +using Parse.Core.Internal; -namespace Parse.Internal { - internal class ParsePushEncoder { +namespace Parse.Push.Internal { + public class ParsePushEncoder { private static readonly ParsePushEncoder instance = new ParsePushEncoder(); public static ParsePushEncoder Instance { get { @@ -29,7 +32,7 @@ public IDictionary Encode(IPushState state) { } var payload = new Dictionary { { "data", data }, - { "where", query.BuildParameters(false).GetOrDefault("where", new Dictionary()) }, + { "where", query.BuildParameters().GetOrDefault("where", new Dictionary()) }, }; if (state.Expiration.HasValue) { payload["expiration_time"] = state.Expiration.Value.ToString("yyyy-MM-ddTHH:mm:ssZ"); diff --git a/Parse/Internal/Push/Controller/IParsePushChannelsController.cs b/ParsePush/Internal/Controller/IParsePushChannelsController.cs similarity index 88% rename from Parse/Internal/Push/Controller/IParsePushChannelsController.cs rename to ParsePush/Internal/Controller/IParsePushChannelsController.cs index 657624d8..9b462d3e 100644 --- a/Parse/Internal/Push/Controller/IParsePushChannelsController.cs +++ b/ParsePush/Internal/Controller/IParsePushChannelsController.cs @@ -6,8 +6,8 @@ using System.Threading; using System.Collections.Generic; -namespace Parse.Internal { - internal interface IParsePushChannelsController { +namespace Parse.Push.Internal { + public interface IParsePushChannelsController { Task SubscribeAsync(IEnumerable channels, CancellationToken cancellationToken); Task UnsubscribeAsync(IEnumerable channels, CancellationToken cancellationToken); } diff --git a/Parse/Internal/Push/Controller/IParsePushController.cs b/ParsePush/Internal/Controller/IParsePushController.cs similarity index 66% rename from Parse/Internal/Push/Controller/IParsePushController.cs rename to ParsePush/Internal/Controller/IParsePushController.cs index 3ea6d2f9..f04d0daf 100644 --- a/Parse/Internal/Push/Controller/IParsePushController.cs +++ b/ParsePush/Internal/Controller/IParsePushController.cs @@ -4,8 +4,8 @@ using System.Threading.Tasks; using System.Threading; -namespace Parse.Internal { - internal interface IParsePushController { - Task SendPushNotificationAsync(IPushState state, String sessionToken, CancellationToken cancellationToken); +namespace Parse.Push.Internal { + public interface IParsePushController { + Task SendPushNotificationAsync(IPushState state, CancellationToken cancellationToken); } } diff --git a/Parse/Internal/Push/Controller/ParsePushChannelsController.cs b/ParsePush/Internal/Controller/ParsePushChannelsController.cs similarity index 97% rename from Parse/Internal/Push/Controller/ParsePushChannelsController.cs rename to ParsePush/Internal/Controller/ParsePushChannelsController.cs index 2f683bbb..5f986462 100644 --- a/Parse/Internal/Push/Controller/ParsePushChannelsController.cs +++ b/ParsePush/Internal/Controller/ParsePushChannelsController.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Threading; -namespace Parse.Internal { +namespace Parse.Push.Internal { internal class ParsePushChannelsController : IParsePushChannelsController { public Task SubscribeAsync(IEnumerable channels, CancellationToken cancellationToken) { ParseInstallation installation = ParseInstallation.CurrentInstallation; diff --git a/ParsePush/Internal/Controller/ParsePushController.cs b/ParsePush/Internal/Controller/ParsePushController.cs new file mode 100644 index 00000000..26d4da31 --- /dev/null +++ b/ParsePush/Internal/Controller/ParsePushController.cs @@ -0,0 +1,31 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.Threading.Tasks; +using System.Threading; +using System.Collections.Generic; +using Parse.Common.Internal; +using Parse.Core.Internal; + +namespace Parse.Push.Internal { + internal class ParsePushController : IParsePushController { + private readonly IParseCommandRunner commandRunner; + private readonly IParseCurrentUserController currentUserController; + + public ParsePushController(IParseCommandRunner commandRunner, IParseCurrentUserController currentUserController) { + this.commandRunner = commandRunner; + this.currentUserController = currentUserController; + } + + public Task SendPushNotificationAsync(IPushState state, CancellationToken cancellationToken) { + return currentUserController.GetCurrentSessionTokenAsync(cancellationToken).OnSuccess(sessionTokenTask => { + var command = new ParseCommand("push", + method: "POST", + sessionToken: sessionTokenTask.Result, + data: ParsePushEncoder.Instance.Encode(state)); + + return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken); + }).Unwrap(); + } + } +} diff --git a/ParsePush/Internal/DeviceInfo/Android/DeviceInfoController.cs b/ParsePush/Internal/DeviceInfo/Android/DeviceInfoController.cs new file mode 100644 index 00000000..1be53aae --- /dev/null +++ b/ParsePush/Internal/DeviceInfo/Android/DeviceInfoController.cs @@ -0,0 +1,51 @@ +using System; +using System.Threading.Tasks; + +namespace Parse.Push.Internal { + /// + /// This is a concrete implementation of IDeviceInfoController. + /// Everything is implemented to be a no-op, as an installation + /// on portable targets can't be used for push notifications. + /// + public class DeviceInfoController : IDeviceInfoController { + public string DeviceType { + get { + return "android"; + } + } + + public string DeviceTimeZone { + get { + return Java.Util.TimeZone.Default.ID; + } + } + + public string AppBuildVersion { + get { + return ManifestInfo.VersionCode.ToString(); + } + } + + public string AppIdentifier { + get { + return ManifestInfo.PackageName; + } + } + + public string AppName { + get { + return ManifestInfo.DisplayName; + } + } + + public Task ExecuteParseInstallationSaveHookAsync(ParseInstallation installation) { + return Task.FromResult(null); + } + + public void Initialize() { + if (ManifestInfo.HasPermissionForGCM()) { + GcmRegistrar.GetInstance().Register(); + } + } + } +} diff --git a/ParsePush/Internal/DeviceInfo/IDeviceInfoController.cs b/ParsePush/Internal/DeviceInfo/IDeviceInfoController.cs new file mode 100644 index 00000000..3243d5fe --- /dev/null +++ b/ParsePush/Internal/DeviceInfo/IDeviceInfoController.cs @@ -0,0 +1,23 @@ +using System; +using System.Threading.Tasks; + +namespace Parse.Push.Internal { + public interface IDeviceInfoController { + string DeviceType { get; } + string DeviceTimeZone { get; } + string AppBuildVersion { get; } + string AppIdentifier { get; } + string AppName { get; } + + + /// + /// Executes platform specific hook that mutate the installation based on + /// the device platforms. + /// + /// Installation to be mutated. + /// + Task ExecuteParseInstallationSaveHookAsync(ParseInstallation installation); + + void Initialize(); + } +} diff --git a/Parse/Resources/Resource.Designer.cs b/ParsePush/Internal/DeviceInfo/NetFx45/DeviceInfoController.cs similarity index 100% rename from Parse/Resources/Resource.Designer.cs rename to ParsePush/Internal/DeviceInfo/NetFx45/DeviceInfoController.cs diff --git a/Parse/Internal/PlatformHooks/Phone/PlatformHooks.Phone.cs b/ParsePush/Internal/DeviceInfo/Phone/DeviceInfoController.cs similarity index 60% rename from Parse/Internal/PlatformHooks/Phone/PlatformHooks.Phone.cs rename to ParsePush/Internal/DeviceInfo/Phone/DeviceInfoController.cs index 81a9e25f..6c7885ae 100644 --- a/Parse/Internal/PlatformHooks/Phone/PlatformHooks.Phone.cs +++ b/ParsePush/Internal/DeviceInfo/Phone/DeviceInfoController.cs @@ -1,114 +1,41 @@ -// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. - -using Microsoft.Phone.Notification; -using Parse.Internal; using System; -using System.Linq; -using System.Collections.Generic; -using System.Globalization; -using System.IO.IsolatedStorage; -using System.Threading; using System.Threading.Tasks; using System.Xml; +using Parse.Core.Internal; +using System.Collections.Generic; +using Microsoft.Phone.Notification; -namespace Parse { - partial class PlatformHooks : IPlatformHooks { - /// - /// Future proofing: Right now there's only one valid channel for the app, but we will likely - /// want to allow additional channels for auxiliary tiles (i.e. a contacts app can have a new - /// channel for each contact and the UI needs to pop up on the right tile). The expansion job - /// generically has one _Installation field it passes to device-specific code, so we store a map - /// of tag -> channel URI. Right now, there is only one valid tag and it is automatic. - /// Unused variable warnings are suppressed because this const is used in WinRT and WinPhone but not NetFx. - /// - static readonly string toastChannelTag = "_Toast"; - - private static Lazy> getToastChannelTask = new Lazy>(() => - Task.Run(() => { - try { - HttpNotificationChannel toastChannel = HttpNotificationChannel.Find(toastChannelTag); - if (toastChannel == null) { - toastChannel = new HttpNotificationChannel(toastChannelTag); - - // Note: We could bind to the ChannelUriUpdated event & automatically save instead of checking - // whether the channel has changed on demand. This is more seamless but adds API requests for a - // feature that may not be in use. Maybe we should build an auto-update feature in the future? - // Or maybe Push.subscribe calls will always be a save & that should be good enough for us. - toastChannel.Open(); - } +namespace Parse.Push.Internal { + public class DeviceInfoController : IDeviceInfoController { + public string DeviceType { + get { + return "winphone"; + } + } - // You cannot call BindToShellToast willy nilly across restarts. This was somehow built in a non-idempotent way. - if (!toastChannel.IsShellToastBound) { - toastChannel.BindToShellToast(); - } - return toastChannel; + public string DeviceTimeZone { + get { + // We need the system string to be in english so we'll have the proper key in our lookup table. + // If it's not in english then we will attempt to fallback to the closest Time Zone we can find. + TimeZoneInfo tzInfo = TimeZoneInfo.Local; - // If the app manifest does not declare ID_CAP_PUSH_NOTIFICATION - } catch (UnauthorizedAccessException) { - return null; + string deviceTimeZone = null; + if (ParseInstallation.TimeZoneNameMap.TryGetValue(tzInfo.StandardName, out deviceTimeZone)) { + return deviceTimeZone; } - }) - ); - private static Lazy> getToastUriTask = new Lazy>(async () => { - var channel = await getToastChannelTask.Value; - if (channel == null) { - return null; - } + TimeSpan utcOffset = tzInfo.BaseUtcOffset; - var source = new TaskCompletionSource(); - EventHandler handler = null; - EventHandler errorHandler = null; - handler = (sender, args) => { - // Prevent NullReferenceException - if (args.ChannelUri == null) { - source.TrySetResult(null); - } else { - source.TrySetResult(args.ChannelUri.AbsoluteUri); + // If we have an offset that is not a round hour, then use our second map to see if we can + // convert it or not. + if (ParseInstallation.TimeZoneOffsetMap.TryGetValue(utcOffset, out deviceTimeZone)) { + return deviceTimeZone; } - }; - errorHandler = (sender, args) => { - source.TrySetException(new ApplicationException(args.Message)); - }; - - channel.ChannelUriUpdated += handler; - channel.ErrorOccurred += errorHandler; - - // Sometimes the channel isn't ready yet. Sometimes it is. - if (channel.ChannelUri != null && !source.Task.IsCompleted) { - source.TrySetResult(channel.ChannelUri.AbsoluteUri); - } - - return await source.Task.ContinueWith(t => { - // Cleanup the handler. - channel.ChannelUriUpdated -= handler; - channel.ErrorOccurred -= errorHandler; - - return t; - }).Unwrap(); - }); - - internal static Task GetToastChannelTask { - get { - return getToastChannelTask.Value; - } - } - static PlatformHooks() { - var _ = GetToastChannelTask; - } - - private IHttpClient httpClient = null; - public IHttpClient HttpClient { - get { - httpClient = httpClient ?? new HttpClient(); - return httpClient; - } - } - - public string SDKName { - get { - return "wp"; + // NOTE: Etc/GMT{+/-} format is inverted from the UTC offset we use as normal people - + // a negative value means ahead of UTC, a positive value means behind UTC. + bool negativeOffset = utcOffset.Ticks < 0; + return String.Format("Etc/GMT{0}{1}", negativeOffset ? "+" : "-", Math.Abs(utcOffset.Hours)); } } @@ -136,57 +63,18 @@ public string AppIdentifier { } } - public string OSVersion { - get { - return Environment.OSVersion.ToString(); - } - } - - public string DeviceType { - get { - return "winphone"; - } - } - - public string DeviceTimeZone { - get { - // We need the system string to be in english so we'll have the proper key in our lookup table. - // If it's not in english then we will attempt to fallback to the closest Time Zone we can find. - TimeZoneInfo tzInfo = TimeZoneInfo.Local; - - string deviceTimeZone = null; - if (ParseInstallation.TimeZoneNameMap.TryGetValue(tzInfo.StandardName, out deviceTimeZone)) { - return deviceTimeZone; - } - - TimeSpan utcOffset = tzInfo.BaseUtcOffset; - - // If we have an offset that is not a round hour, then use our second map to see if we can - // convert it or not. - if (ParseInstallation.TimeZoneOffsetMap.TryGetValue(utcOffset, out deviceTimeZone)) { - return deviceTimeZone; - } - - // NOTE: Etc/GMT{+/-} format is inverted from the UTC offset we use as normal people - - // a negative value means ahead of UTC, a positive value means behind UTC. - bool negativeOffset = utcOffset.Ticks < 0; - return String.Format("Etc/GMT{0}{1}", negativeOffset ? "+" : "-", Math.Abs(utcOffset.Hours)); - } - } - - public void Initialize() { - // Do nothing. - } - public Task ExecuteParseInstallationSaveHookAsync(ParseInstallation installation) { return getToastUriTask.Value.ContinueWith(t => { installation.SetIfDifferent("deviceUris", t.Result == null ? null : - new Dictionary { - { toastChannelTag, t.Result } + new Dictionary { + { toastChannelTag, t.Result } }); }); } + public void Initialize() { + } + /// /// Gets an attribute from the Windows Phone App Manifest App element /// @@ -212,108 +100,88 @@ private string GetAppAttribute(string attributeName) { } /// - /// Wraps the custom settings object for Parse so that it can be exposed as ApplicationSettings. + /// Future proofing: Right now there's only one valid channel for the app, but we will likely + /// want to allow additional channels for auxiliary tiles (i.e. a contacts app can have a new + /// channel for each contact and the UI needs to pop up on the right tile). The expansion job + /// generically has one _Installation field it passes to device-specific code, so we store a map + /// of tag -> channel URI. Right now, there is only one valid tag and it is automatic. + /// Unused variable warnings are suppressed because this const is used in WinRT and WinPhone but not NetFx. /// - private class SettingsWrapper : IDictionary { - private static readonly string prefix = "Parse."; - private static SettingsWrapper wrapper; - public static SettingsWrapper Wrapper { - get { - wrapper = wrapper ?? new SettingsWrapper(); - return wrapper; - } - } - private IDictionary data; - private SettingsWrapper() { - try { - data = Windows.Storage.ApplicationData.Current.LocalSettings.Values; - } catch (System.NotImplementedException) { - data = IsolatedStorageSettings.ApplicationSettings; - } - } - public void Add(string key, object value) { - data.Add(prefix + key, value); - } - - public bool ContainsKey(string key) { - return data.ContainsKey(prefix + key); - } - - public ICollection Keys { - get { return this.Select(kvp => kvp.Key).ToList(); } - } + static readonly string toastChannelTag = "_Toast"; - public bool Remove(string key) { - return data.Remove(prefix + key); - } + private static Lazy> getToastChannelTask = new Lazy>(() => + Task.Run(() => { + try { + HttpNotificationChannel toastChannel = HttpNotificationChannel.Find(toastChannelTag); + if (toastChannel == null) { + toastChannel = new HttpNotificationChannel(toastChannelTag); - public bool TryGetValue(string key, out object value) { - return data.TryGetValue(prefix + key, out value); - } + // Note: We could bind to the ChannelUriUpdated event & automatically save instead of checking + // whether the channel has changed on demand. This is more seamless but adds API requests for a + // feature that may not be in use. Maybe we should build an auto-update feature in the future? + // Or maybe Push.subscribe calls will always be a save & that should be good enough for us. + toastChannel.Open(); + } - public ICollection Values { - get { return this.Select(kvp => kvp.Value).ToList(); } - } + // You cannot call BindToShellToast willy nilly across restarts. This was somehow built in a non-idempotent way. + if (!toastChannel.IsShellToastBound) { + toastChannel.BindToShellToast(); + } + return toastChannel; - public object this[string key] { - get { - return data[prefix + key]; - } - set { - data[prefix + key] = value; + // If the app manifest does not declare ID_CAP_PUSH_NOTIFICATION + } catch (UnauthorizedAccessException) { + return null; } - } + }) + ); - public void Add(KeyValuePair item) { - data.Add(new KeyValuePair(prefix + item.Key, item.Value)); + private static Lazy> getToastUriTask = new Lazy>(async () => { + var channel = await getToastChannelTask.Value; + if (channel == null) { + return null; } - public void Clear() { - foreach (var key in Keys) { - data.Remove(key); + var source = new TaskCompletionSource(); + EventHandler handler = null; + EventHandler errorHandler = null; + handler = (sender, args) => { + // Prevent NullReferenceException + if (args.ChannelUri == null) { + source.TrySetResult(null); + } else { + source.TrySetResult(args.ChannelUri.AbsoluteUri); } - } - - public bool Contains(KeyValuePair item) { - return data.Contains(new KeyValuePair(prefix + item.Key, item.Value)); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) { - this.ToList().CopyTo(array, arrayIndex); - } + }; + errorHandler = (sender, args) => { + source.TrySetException(new ApplicationException(args.Message)); + }; - public int Count { - get { return Keys.Count; } - } + channel.ChannelUriUpdated += handler; + channel.ErrorOccurred += errorHandler; - public bool IsReadOnly { - get { return data.IsReadOnly; } + // Sometimes the channel isn't ready yet. Sometimes it is. + if (channel.ChannelUri != null && !source.Task.IsCompleted) { + source.TrySetResult(channel.ChannelUri.AbsoluteUri); } - public bool Remove(KeyValuePair item) { - return data.Remove(new KeyValuePair(prefix + item.Key, item.Value)); - } + return await source.Task.ContinueWith(t => { + // Cleanup the handler. + channel.ChannelUriUpdated -= handler; + channel.ErrorOccurred -= errorHandler; - public IEnumerator> GetEnumerator() { - return data - .Where(kvp => kvp.Key.StartsWith(prefix)) - .Select(kvp => new KeyValuePair(kvp.Key.Substring(prefix.Length), kvp.Value)) - .GetEnumerator(); - } + return t; + }).Unwrap(); + }); - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { - return this.GetEnumerator(); + internal static Task GetToastChannelTask { + get { + return getToastChannelTask.Value; } } - /// - /// Provides a dictionary that gets persisted on the filesystem between runs of the app. - /// This is analogous to NSUserDefaults in iOS. - /// - public IDictionary ApplicationSettings { - get { - return SettingsWrapper.Wrapper; - } + static DeviceInfoController() { + var _ = GetToastChannelTask; } } -} +} \ No newline at end of file diff --git a/ParsePush/Internal/DeviceInfo/Portable/DeviceInfoController.cs b/ParsePush/Internal/DeviceInfo/Portable/DeviceInfoController.cs new file mode 100644 index 00000000..1d85c0d5 --- /dev/null +++ b/ParsePush/Internal/DeviceInfo/Portable/DeviceInfoController.cs @@ -0,0 +1,38 @@ +using System; +using System.Threading.Tasks; + +namespace Parse.Push.Internal { + /// + /// This is a concrete implementation of IDeviceInfoController. + /// Everything is implemented to be a no-op, as an installation + /// on portable targets can't be used for push notifications. + /// + public class DeviceInfoController : IDeviceInfoController { + public string DeviceType { + get { return null; } + } + + public string DeviceTimeZone { + get { return null; } + } + + public string AppBuildVersion { + get { return null; } + } + + public string AppIdentifier { + get { return null; } + } + + public string AppName { + get { return null; } + } + + public Task ExecuteParseInstallationSaveHookAsync(ParseInstallation installation) { + return Task.FromResult(null); + } + + public void Initialize() { + } + } +} \ No newline at end of file diff --git a/ParsePush/Internal/DeviceInfo/Unity.Android/DeviceInfoController.cs b/ParsePush/Internal/DeviceInfo/Unity.Android/DeviceInfoController.cs new file mode 100644 index 00000000..94efda02 --- /dev/null +++ b/ParsePush/Internal/DeviceInfo/Unity.Android/DeviceInfoController.cs @@ -0,0 +1,138 @@ +using System; +using System.Threading.Tasks; +using Parse.Core.Internal; +using UnityEngine; +using Parse.Common.Internal; + +namespace Parse.Push.Internal { + /// + /// This is a concrete implementation of IDeviceInfoController for Unity Android targets. + /// + public class DeviceInfoController : IDeviceInfoController { + /// + /// Helper class that can listen to android-specific unity messages. + /// + private class GCMRegistrationCallbackBehavior : MonoBehaviour { + /// + /// Delegate function that will be called when the player pauses the game. + /// + /// + /// true if the application is paused. + public void OnApplicationPause(bool paused) { + AndroidJavaClass javaUnityHelper = new AndroidJavaClass("com.parse.ParsePushUnityHelper"); + javaUnityHelper.CallStatic("setApplicationPaused", new object[] { paused }); + } + + /// + /// The callback that will be called from the Android Java land via UnityPlayer.UnitySendMessage(string) + /// when the device receive a push notification. + /// + /// the push payload as string + internal void OnPushNotificationReceived(string pushPayloadString) { + ParseInitializeBehaviour behavior = gameObject.GetComponent(); + if (behavior != null) { + behavior.Initialize(); + } + + ParsePush.parsePushNotificationReceived.Invoke(ParseInstallation.CurrentInstallation, new ParsePushNotificationEventArgs(pushPayloadString)); + } + + /// + /// The callback that will be called from the Android Java land via UnityPlayer.UnitySendMessage(string) + /// when the device receive a GCM registration id. + /// + /// the GCM registration id + internal void OnGcmRegistrationReceived(string registrationId) { + Initialize(); + + var installation = ParseInstallation.CurrentInstallation; + installation.DeviceToken = registrationId; + // Set `pushType` via internal `Set` method since we want to skip mutability check. + installation.Set("pushType", "gcm"); + + // We can't really wait for this or else we'll block the thread. + // We can only hope this operation will finish. + installation.SaveAsync(); + } + } + + public string DeviceType { + get { return "android"; } + } + + public string DeviceTimeZone { + get { + try { + // We need the system string to be in english so we'll have the proper key in our lookup table. + // If it's not in english then we will attempt to fallback to the closest Time Zone we can find. + TimeZoneInfo tzInfo = TimeZoneInfo.Local; + + string deviceTimeZone = null; + if (ParseInstallation.TimeZoneNameMap.TryGetValue(tzInfo.StandardName, out deviceTimeZone)) { + return deviceTimeZone; + } + + TimeSpan utcOffset = tzInfo.BaseUtcOffset; + + // If we have an offset that is not a round hour, then use our second map to see if we can + // convert it or not. + if (ParseInstallation.TimeZoneOffsetMap.TryGetValue(utcOffset, out deviceTimeZone)) { + return deviceTimeZone; + } + + // NOTE: Etc/GMT{+/-} format is inverted from the UTC offset we use as normal people - + // a negative value means ahead of UTC, a positive value means behind UTC. + bool negativeOffset = utcOffset.Ticks < 0; + return String.Format("Etc/GMT{0}{1}", negativeOffset ? "+" : "-", Math.Abs(utcOffset.Hours)); + } catch (TimeZoneNotFoundException) { + return null; + } + } + } + + private string appBuildVersion; + public string AppBuildVersion { + get { return appBuildVersion; } + } + + public string AppIdentifier { + get { + ApplicationIdentity identity = AppDomain.CurrentDomain.ApplicationIdentity; + if (identity == null) { + return null; + } + return identity.FullName; + } + } + + private string appName; + public string AppName { + get { return appName; } + } + + public Task ExecuteParseInstallationSaveHookAsync(ParseInstallation installation) { + return Task.Run(() => { + installation.SetIfDifferent("badge", installation.Badge); + }); + } + + public void Initialize() { + // We can only set some values here since we can be sure that Initialize is always called + // from main thread. + appBuildVersion = Application.version; + appName = Application.productName; + + // Add our GCM callback listener + Dispatcher.Instance.GameObject.AddComponent(); + + try { + AndroidJavaClass javaUnityHelper = new AndroidJavaClass("com.parse.ParsePushUnityHelper"); + javaUnityHelper.CallStatic("registerGcm", null); + } catch (Exception e) { + // We don't care about the exception. If it reaches this point, it means the Plugin is misconfigured/we don't want to use + // PushNotification. Let's just log it to developer. + Debug.LogException(e); + } + } + } +} \ No newline at end of file diff --git a/ParsePush/Internal/DeviceInfo/Unity.iOS/DeviceInfoController.cs b/ParsePush/Internal/DeviceInfo/Unity.iOS/DeviceInfoController.cs new file mode 100644 index 00000000..54926c96 --- /dev/null +++ b/ParsePush/Internal/DeviceInfo/Unity.iOS/DeviceInfoController.cs @@ -0,0 +1,142 @@ +using System; +using System.Threading.Tasks; +using Parse.Core.Internal; +using Parse.Common.Internal; +using System.Collections.Generic; +using NotificationServices = UnityEngine.iOS.NotificationServices; +using UnityEngine; + +namespace Parse.Push.Internal { + /// + /// This is a concrete implementation of IDeviceInfoController for Unity iOS targets. + /// + public class DeviceInfoController : IDeviceInfoController { + public string DeviceType { + get { return "ios"; } + } + + public string DeviceTimeZone { + get { + try { + // We need the system string to be in english so we'll have the proper key in our lookup table. + // If it's not in english then we will attempt to fallback to the closest Time Zone we can find. + TimeZoneInfo tzInfo = TimeZoneInfo.Local; + + string deviceTimeZone = null; + if (ParseInstallation.TimeZoneNameMap.TryGetValue(tzInfo.StandardName, out deviceTimeZone)) { + return deviceTimeZone; + } + + TimeSpan utcOffset = tzInfo.BaseUtcOffset; + + // If we have an offset that is not a round hour, then use our second map to see if we can + // convert it or not. + if (ParseInstallation.TimeZoneOffsetMap.TryGetValue(utcOffset, out deviceTimeZone)) { + return deviceTimeZone; + } + + // NOTE: Etc/GMT{+/-} format is inverted from the UTC offset we use as normal people - + // a negative value means ahead of UTC, a positive value means behind UTC. + bool negativeOffset = utcOffset.Ticks < 0; + return String.Format("Etc/GMT{0}{1}", negativeOffset ? "+" : "-", Math.Abs(utcOffset.Hours)); + } catch (TimeZoneNotFoundException) { + return null; + } + } + } + + private string appBuildVersion; + public string AppBuildVersion { + get { return appBuildVersion; } + } + + public string AppIdentifier { + get { + ApplicationIdentity identity = AppDomain.CurrentDomain.ApplicationIdentity; + if (identity == null) { + return null; + } + return identity.FullName; + } + } + + private string appName; + public string AppName { + get { return appName; } + } + + public Task ExecuteParseInstallationSaveHookAsync(ParseInstallation installation) { + return Task.Run(() => { + installation.SetIfDifferent("badge", installation.Badge); + }); + } + + public void Initialize() { + // We can only set some values here since we can be sure that Initialize is always called + // from main thread. + appBuildVersion = Application.version; + appName = Application.productName; + + RegisterDeviceTokenRequest(deviceToken => { + if (deviceToken == null) { + return; + } + + ParseInstallation installation = ParseInstallation.CurrentInstallation; + installation.SetDeviceTokenFromData(deviceToken); + + // Optimistically assume this will finish. + installation.SaveAsync(); + }); + } + + /// + /// Registers a callback for a device token request. + /// + /// + private void RegisterDeviceTokenRequest(Action action) { + Dispatcher.Instance.Post(() => { + var deviceToken = NotificationServices.deviceToken; + if (deviceToken == null) { + RegisterDeviceTokenRequest(action); + return; + } + + action(deviceToken); + RegisteriOSPushNotificationListener((payload) => { + ParsePush.parsePushNotificationReceived.Invoke(ParseInstallation.CurrentInstallation, new ParsePushNotificationEventArgs(payload)); + }); + }); + } + + /// + /// Registers a callback for push notifications. + /// + /// + private void RegisteriOSPushNotificationListener(Action> action) { + Dispatcher.Instance.Post(() => { + // Check in every frame + RegisteriOSPushNotificationListener(action); + + int remoteNotificationCount = NotificationServices.remoteNotificationCount; + if (remoteNotificationCount == 0) { + return; + } + + var remoteNotifications = NotificationServices.remoteNotifications; + foreach (var val in remoteNotifications) { + var userInfo = val.userInfo; + var payload = new Dictionary(); + foreach (var key in userInfo.Keys) { + payload[key.ToString()] = userInfo[key]; + } + + // Finally, invoke the action for the remote notification payload. + action(payload); + } + + NotificationServices.ClearRemoteNotifications(); + }); + } + } +} \ No newline at end of file diff --git a/ParsePush/Internal/DeviceInfo/WinRT/DeviceInfoController.cs b/ParsePush/Internal/DeviceInfo/WinRT/DeviceInfoController.cs new file mode 100644 index 00000000..26643640 --- /dev/null +++ b/ParsePush/Internal/DeviceInfo/WinRT/DeviceInfoController.cs @@ -0,0 +1,120 @@ +using System; +using System.Threading.Tasks; +using System.Xml; +using System.Linq; +using Parse.Common.Internal; +using Parse.Core.Internal; +using System.Collections.Generic; +using Windows.ApplicationModel; +using Windows.Networking.PushNotifications; +using Windows.Storage; +using System.Xml.Linq; + +namespace Parse.Push.Internal { + public class DeviceInfoController : IDeviceInfoController { + public string DeviceType { + get { + return "winrt"; + } + } + + public string DeviceTimeZone { + get { + // We need the system string to be in english so we'll have the proper key in our lookup table. + // If it's not in english then we will attempt to fallback to the closest Time Zone we can find. + TimeZoneInfo tzInfo = TimeZoneInfo.Local; + + string deviceTimeZone = null; + if (ParseInstallation.TimeZoneNameMap.TryGetValue(tzInfo.StandardName, out deviceTimeZone)) { + return deviceTimeZone; + } + + TimeSpan utcOffset = tzInfo.BaseUtcOffset; + + // If we have an offset that is not a round hour, then use our second map to see if we can + // convert it or not. + if (ParseInstallation.TimeZoneOffsetMap.TryGetValue(utcOffset, out deviceTimeZone)) { + return deviceTimeZone; + } + + // NOTE: Etc/GMT{+/-} format is inverted from the UTC offset we use as normal people - + // a negative value means ahead of UTC, a positive value means behind UTC. + bool negativeOffset = utcOffset.Ticks < 0; + return String.Format("Etc/GMT{0}{1}", negativeOffset ? "+" : "-", Math.Abs(utcOffset.Hours)); + } + } + + public string AppName { + get { + var task = Package.Current.InstalledLocation.GetFileAsync("AppxManifest.xml").AsTask().OnSuccess(t => { + return FileIO.ReadTextAsync(t.Result).AsTask(); + }).Unwrap().OnSuccess(t => { + var doc = XDocument.Parse(t.Result); + + // Define the default namespace to be used + var propertiesXName = XName.Get("Properties", "http://schemas.microsoft.com/appx/2010/manifest"); + var displayNameXName = XName.Get("DisplayName", "http://schemas.microsoft.com/appx/2010/manifest"); + + return doc.Descendants(propertiesXName).Single().Descendants(displayNameXName).Single().Value; + }); + task.Wait(); + return task.Result; + } + } + + public string AppBuildVersion { + get { + var version = Package.Current.Id.Version; + return string.Format("{0}.{1}.{2}.{3}", version.Major, version.Minor, version.Build, version.Revision); + } + } + + public string AppDisplayVersion { + get { + return AppBuildVersion; + } + } + + public string AppIdentifier { + get { + return Package.Current.Id.Name; + } + } + + public Task ExecuteParseInstallationSaveHookAsync(ParseInstallation installation) { + return GetChannelTask.ContinueWith(t => { + installation.SetIfDifferent("deviceUris", new Dictionary { + { defaultChannelTag, t.Result.Uri } + }); + }); + } + + public void Initialize() { + } + + /// + /// Future proofing: Right now there's only one valid channel for the app, but we will likely + /// want to allow additional channels for auxiliary tiles (i.e. a contacts app can have a new + /// channel for each contact and the UI needs to pop up on the right tile). The expansion job + /// generically has one _Installation field it passes to device-specific code, so we store a map + /// of tag -> channel URI. Right now, there is only one valid tag and it is automatic. + /// Unused variable warnings are suppressed because this const is used in WinRT and WinPhone but not NetFx. + /// + private static readonly string defaultChannelTag = "_Default"; + + // This must be wrapped in a property so other classes may continue on this task + // during their static initialization. + private static Lazy> getChannelTask = new Lazy>(() => + PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync().AsTask() + ); + internal static Task GetChannelTask { + get { + return getChannelTask.Value; + } + } + + static DeviceInfoController() { + var _ = GetChannelTask; + } + } +} \ No newline at end of file diff --git a/ParsePush/Internal/DeviceInfo/iOS/DeviceInfoController.cs b/ParsePush/Internal/DeviceInfo/iOS/DeviceInfoController.cs new file mode 100644 index 00000000..7375fe18 --- /dev/null +++ b/ParsePush/Internal/DeviceInfo/iOS/DeviceInfoController.cs @@ -0,0 +1,59 @@ +using System; +using System.Threading.Tasks; +using Parse.Core.Internal; +using Foundation; + +namespace Parse.Push.Internal { + /// + /// This is a concrete implementation of IDeviceInfoController. + /// Everything is implemented to be a no-op, as an installation + /// on portable targets can't be used for push notifications. + /// + public class DeviceInfoController : IDeviceInfoController { + public string DeviceType { + get { return "ios"; } + } + + public string DeviceTimeZone { + get { + NSTimeZone.ResetSystemTimeZone(); + return NSTimeZone.SystemTimeZone.Name; + } + } + + public string AppBuildVersion { + get { return GetAppAttribute("CFBundleVersion"); } + } + + public string AppIdentifier { + get { return GetAppAttribute("CFBundleIdentifier"); } + } + + public string AppName { + get { return GetAppAttribute("CFBundleDisplayName"); } + } + + public Task ExecuteParseInstallationSaveHookAsync(ParseInstallation installation) { + return Task.Run(() => { + installation.SetIfDifferent("badge", installation.Badge); + }); + } + + public void Initialize() { + } + + /// + /// Gets an attribute from the Info.plist. + /// + /// the attribute name + /// the attribute value + /// This is a duplicate of what we have in ParseInstallation. We do it because + /// it's easier to maintain this way (rather than referencing PlatformHooks everywhere). + private string GetAppAttribute(string attributeName) { + var appAttributes = NSBundle.MainBundle; + + var attribute = appAttributes.ObjectForInfoDictionary(attributeName); + return attribute == null ? null : attribute.ToString(); + } + } +} diff --git a/ParsePush/Internal/IParsePushPlugins.cs b/ParsePush/Internal/IParsePushPlugins.cs new file mode 100644 index 00000000..d4ab6466 --- /dev/null +++ b/ParsePush/Internal/IParsePushPlugins.cs @@ -0,0 +1,14 @@ +using System; +using Parse.Core.Internal; + +namespace Parse.Push.Internal { + public interface IParsePushPlugins { + void Reset(); + + IParseCorePlugins CorePlugins { get; } + IParsePushChannelsController PushChannelsController { get; } + IParsePushController PushController { get; } + IParseCurrentInstallationController CurrentInstallationController { get; } + IDeviceInfoController DeviceInfoController { get; } + } +} \ No newline at end of file diff --git a/ParsePush/Internal/Installation/Coder/IParseInstallationCoder.cs b/ParsePush/Internal/Installation/Coder/IParseInstallationCoder.cs new file mode 100644 index 00000000..4a889c7e --- /dev/null +++ b/ParsePush/Internal/Installation/Coder/IParseInstallationCoder.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using Parse; + +namespace Parse.Push.Internal { + // TODO: (richardross) once coder is refactored, make this extend IParseObjectCoder. + public interface IParseInstallationCoder { + IDictionary Encode(ParseInstallation installation); + + ParseInstallation Decode(IDictionary data); + } +} \ No newline at end of file diff --git a/ParsePush/Internal/Installation/Coder/ParseInstallationCoder.cs b/ParsePush/Internal/Installation/Coder/ParseInstallationCoder.cs new file mode 100644 index 00000000..8007385c --- /dev/null +++ b/ParsePush/Internal/Installation/Coder/ParseInstallationCoder.cs @@ -0,0 +1,35 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using Parse; +using Parse.Core.Internal; + +namespace Parse.Push.Internal { + public class ParseInstallationCoder : IParseInstallationCoder { + private static readonly ParseInstallationCoder instance = new ParseInstallationCoder(); + public static ParseInstallationCoder Instance { + get { + return instance; + } + } + private const string ISO8601Format = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'"; + + public IDictionary Encode(ParseInstallation installation) { + var state = installation.GetState(); + var data = PointerOrLocalIdEncoder.Instance.Encode(state.ToDictionary(x => x.Key, x => x.Value)) as IDictionary; + data["objectId"] = state.ObjectId; + if (state.CreatedAt != null) { + data["createdAt"] = state.CreatedAt.Value.ToString(ISO8601Format); + } + if (state.UpdatedAt != null) { + data["updatedAt"] = state.UpdatedAt.Value.ToString(ISO8601Format); + } + return data; + } + + public ParseInstallation Decode(IDictionary data) { + var state = ParseObjectCoder.Instance.Decode(data, ParseDecoder.Instance); + return ParseObjectExtensions.FromState(state, "_Installation"); + } + } +} \ No newline at end of file diff --git a/Parse/Internal/Installation/Controller/IParseCurrentInstallationController.cs b/ParsePush/Internal/Installation/Controller/IParseCurrentInstallationController.cs similarity index 64% rename from Parse/Internal/Installation/Controller/IParseCurrentInstallationController.cs rename to ParsePush/Internal/Installation/Controller/IParseCurrentInstallationController.cs index 066b3353..b3dbca3e 100644 --- a/Parse/Internal/Installation/Controller/IParseCurrentInstallationController.cs +++ b/ParsePush/Internal/Installation/Controller/IParseCurrentInstallationController.cs @@ -1,8 +1,9 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. +using Parse.Core.Internal; using System; -namespace Parse.Internal { - interface IParseCurrentInstallationController : IParseObjectCurrentController { +namespace Parse.Push.Internal { + public interface IParseCurrentInstallationController : IParseObjectCurrentController { } } diff --git a/ParsePush/Internal/Installation/Controller/ParseCurrentInstallationController.cs b/ParsePush/Internal/Installation/Controller/ParseCurrentInstallationController.cs new file mode 100644 index 00000000..893f9e8a --- /dev/null +++ b/ParsePush/Internal/Installation/Controller/ParseCurrentInstallationController.cs @@ -0,0 +1,125 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using Parse.Common.Internal; +using Parse.Core.Internal; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Parse.Push.Internal { + internal class ParseCurrentInstallationController : IParseCurrentInstallationController { + private const string ParseInstallationKey = "CurrentInstallation"; + + private readonly object mutex = new object(); + private readonly TaskQueue taskQueue = new TaskQueue(); + private readonly IInstallationIdController installationIdController; + private readonly IStorageController storageController; + private readonly IParseInstallationCoder installationCoder; + + public ParseCurrentInstallationController(IInstallationIdController installationIdController, IStorageController storageController, IParseInstallationCoder installationCoder) { + this.installationIdController = installationIdController; + this.storageController = storageController; + this.installationCoder = installationCoder; + } + + private ParseInstallation currentInstallation; + internal ParseInstallation CurrentInstallation { + get { + lock (mutex) { + return currentInstallation; + } + } + set { + lock (mutex) { + currentInstallation = value; + } + } + } + + public Task SetAsync(ParseInstallation installation, CancellationToken cancellationToken) { + return taskQueue.Enqueue(toAwait => { + return toAwait.ContinueWith(_ => { + Task saveTask = storageController.LoadAsync().OnSuccess(storage => { + if (installation == null) { + return storage.Result.RemoveAsync(ParseInstallationKey); + } else { + var data = installationCoder.Encode(installation); + return storage.Result.AddAsync(ParseInstallationKey, Json.Encode(data)); + } + }).Unwrap(); + + CurrentInstallation = installation; + return saveTask; + }).Unwrap(); + }, cancellationToken); + } + + public Task GetAsync(CancellationToken cancellationToken) { + ParseInstallation cachedCurrent; + cachedCurrent = CurrentInstallation; + + if (cachedCurrent != null) { + return Task.FromResult(cachedCurrent); + } + + return taskQueue.Enqueue(toAwait => { + return toAwait.ContinueWith(_ => { + return storageController.LoadAsync().OnSuccess(stroage => { + Task fetchTask; + object temp; + stroage.Result.TryGetValue(ParseInstallationKey, out temp); + var installationDataString = temp as string; + ParseInstallation installation = null; + if (installationDataString != null) { + var installationData = Json.Parse(installationDataString) as IDictionary; + installation = installationCoder.Decode(installationData); + + fetchTask = Task.FromResult(null); + } else { + installation = ParseObject.Create(); + fetchTask = installationIdController.GetAsync().ContinueWith(t => { + installation.SetIfDifferent("installationId" , t.Result.ToString()); + }); + } + + CurrentInstallation = installation; + return fetchTask.ContinueWith(t => installation); + }); + }).Unwrap().Unwrap(); + }, cancellationToken); + } + + public Task ExistsAsync(CancellationToken cancellationToken) { + if (CurrentInstallation != null) { + return Task.FromResult(true); + } + + return taskQueue.Enqueue(toAwait => { + return toAwait.ContinueWith(_ => { + return storageController.LoadAsync().OnSuccess(s => s.Result.ContainsKey(ParseInstallationKey)); + }).Unwrap(); + }, cancellationToken); + } + + public bool IsCurrent(ParseInstallation installation) { + return CurrentInstallation == installation; + } + + public void ClearFromMemory() { + CurrentInstallation = null; + } + + public void ClearFromDisk() { + ClearFromMemory(); + + taskQueue.Enqueue(toAwait => { + return toAwait.ContinueWith(_ => { + return storageController.LoadAsync().OnSuccess(storage => storage.Result.RemoveAsync(ParseInstallationKey)); + }).Unwrap().Unwrap(); + }, CancellationToken.None); + } + } +} diff --git a/ParsePush/Internal/ParsePushModule.cs b/ParsePush/Internal/ParsePushModule.cs new file mode 100644 index 00000000..c17524cd --- /dev/null +++ b/ParsePush/Internal/ParsePushModule.cs @@ -0,0 +1,20 @@ +using Parse.Common.Internal; +using Parse.Core.Internal; +using System; + +namespace Parse.Push.Internal { + public class ParsePushModule : IParseModule { + public void OnModuleRegistered() { + } + + public void OnParseInitialized() { + ParseObject.RegisterSubclass(); + + ParseCorePlugins.Instance.SubclassingController.AddRegisterHook(typeof(ParseInstallation), () => { + ParsePushPlugins.Instance.CurrentInstallationController.ClearFromMemory(); + }); + + ParsePushPlugins.Instance.DeviceInfoController.Initialize(); + } + } +} \ No newline at end of file diff --git a/ParsePush/Internal/ParsePushPlugins.cs b/ParsePush/Internal/ParsePushPlugins.cs new file mode 100644 index 00000000..50d35db8 --- /dev/null +++ b/ParsePush/Internal/ParsePushPlugins.cs @@ -0,0 +1,110 @@ +using Parse.Core.Internal; +using System; + +namespace Parse.Push.Internal { + public class ParsePushPlugins : IParsePushPlugins { + private static readonly object instanceMutex = new object(); + private static IParsePushPlugins instance; + public static IParsePushPlugins Instance { + get { + instance = instance ?? new ParsePushPlugins(); + return instance; + } + set { + lock (instanceMutex) { + instance = value; + } + } + } + + private readonly object mutex = new object(); + + private IParseCorePlugins corePlugins; + private IParsePushChannelsController pushChannelsController; + private IParsePushController pushController; + private IParseCurrentInstallationController currentInstallationController; + private IDeviceInfoController deviceInfoController; + + public void Reset() { + lock (mutex) { + CorePlugins = null; + PushChannelsController = null; + PushController = null; + CurrentInstallationController = null; + DeviceInfoController = null; + } + } + + public IParseCorePlugins CorePlugins { + get { + lock (mutex) { + corePlugins = corePlugins ?? ParseCorePlugins.Instance; + return corePlugins; + } + } + set { + lock (mutex) { + corePlugins = value; + } + } + } + + public IParsePushChannelsController PushChannelsController { + get { + lock (mutex) { + pushChannelsController = pushChannelsController ?? new ParsePushChannelsController(); + return pushChannelsController; + } + } + set { + lock (mutex) { + pushChannelsController = value; + } + } + } + + public IParsePushController PushController { + get { + lock (mutex) { + pushController = pushController ?? new ParsePushController(CorePlugins.CommandRunner, CorePlugins.CurrentUserController); + return pushController; + } + } + set { + lock (mutex) { + pushController = value; + } + } + } + + public IParseCurrentInstallationController CurrentInstallationController { + get { + lock (mutex) { + currentInstallationController = currentInstallationController ?? new ParseCurrentInstallationController( + CorePlugins.InstallationIdController, CorePlugins.StorageController, ParseInstallationCoder.Instance + ); + return currentInstallationController; + } + } + set { + lock (mutex) { + currentInstallationController = value; + } + } + } + + public IDeviceInfoController DeviceInfoController { + get { + lock (mutex) { + deviceInfoController = deviceInfoController ?? new DeviceInfoController(); + return deviceInfoController; + } + } + set { + lock (mutex) { + deviceInfoController = value; + } + } + } + } +} diff --git a/Parse/Internal/Push/State/IPushState.cs b/ParsePush/Internal/State/IPushState.cs similarity index 91% rename from Parse/Internal/Push/State/IPushState.cs rename to ParsePush/Internal/State/IPushState.cs index 9ecce04b..af4cc395 100644 --- a/Parse/Internal/Push/State/IPushState.cs +++ b/ParsePush/Internal/State/IPushState.cs @@ -3,8 +3,8 @@ using System; using System.Collections.Generic; -namespace Parse.Internal { - internal interface IPushState { +namespace Parse.Push.Internal { + public interface IPushState { ParseQuery Query { get; } IEnumerable Channels { get; } DateTime? Expiration { get; } diff --git a/Parse/Internal/Push/State/MutablePushState.cs b/ParsePush/Internal/State/MutablePushState.cs similarity index 94% rename from Parse/Internal/Push/State/MutablePushState.cs rename to ParsePush/Internal/State/MutablePushState.cs index 1d555ef5..665eea00 100644 --- a/Parse/Internal/Push/State/MutablePushState.cs +++ b/ParsePush/Internal/State/MutablePushState.cs @@ -3,9 +3,10 @@ using System; using System.Linq; using System.Collections.Generic; +using Parse.Common.Internal; -namespace Parse.Internal { - internal class MutablePushState : IPushState { +namespace Parse.Push.Internal { + public class MutablePushState : IPushState { public ParseQuery Query { get; set; } public IEnumerable Channels { get; set; } public DateTime? Expiration { get; set; } diff --git a/ParsePush/build.gradle b/ParsePush/Native/build.gradle similarity index 100% rename from ParsePush/build.gradle rename to ParsePush/Native/build.gradle diff --git a/ParsePush/gradle/wrapper/gradle-wrapper.jar b/ParsePush/Native/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from ParsePush/gradle/wrapper/gradle-wrapper.jar rename to ParsePush/Native/gradle/wrapper/gradle-wrapper.jar diff --git a/ParsePush/gradle/wrapper/gradle-wrapper.properties b/ParsePush/Native/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from ParsePush/gradle/wrapper/gradle-wrapper.properties rename to ParsePush/Native/gradle/wrapper/gradle-wrapper.properties diff --git a/ParsePush/gradlew b/ParsePush/Native/gradlew similarity index 100% rename from ParsePush/gradlew rename to ParsePush/Native/gradlew diff --git a/ParsePush/gradlew.bat b/ParsePush/Native/gradlew.bat similarity index 96% rename from ParsePush/gradlew.bat rename to ParsePush/Native/gradlew.bat index aec99730..8a0b282a 100644 --- a/ParsePush/gradlew.bat +++ b/ParsePush/Native/gradlew.bat @@ -1,90 +1,90 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ParsePush/libs/README.md b/ParsePush/Native/libs/README.md similarity index 100% rename from ParsePush/libs/README.md rename to ParsePush/Native/libs/README.md diff --git a/ParsePush/libs/classes.jar b/ParsePush/Native/libs/classes.jar similarity index 100% rename from ParsePush/libs/classes.jar rename to ParsePush/Native/libs/classes.jar diff --git a/ParsePush/src/main/AndroidManifest.xml b/ParsePush/Native/src/main/AndroidManifest.xml similarity index 100% rename from ParsePush/src/main/AndroidManifest.xml rename to ParsePush/Native/src/main/AndroidManifest.xml diff --git a/ParsePush/src/main/java/com/parse/ManifestInfo.java b/ParsePush/Native/src/main/java/com/parse/ManifestInfo.java similarity index 100% rename from ParsePush/src/main/java/com/parse/ManifestInfo.java rename to ParsePush/Native/src/main/java/com/parse/ManifestInfo.java diff --git a/ParsePush/src/main/java/com/parse/ParsePushBroadcastReceiver.java b/ParsePush/Native/src/main/java/com/parse/ParsePushBroadcastReceiver.java similarity index 100% rename from ParsePush/src/main/java/com/parse/ParsePushBroadcastReceiver.java rename to ParsePush/Native/src/main/java/com/parse/ParsePushBroadcastReceiver.java diff --git a/ParsePush/src/main/java/com/parse/ParsePushService.java b/ParsePush/Native/src/main/java/com/parse/ParsePushService.java similarity index 100% rename from ParsePush/src/main/java/com/parse/ParsePushService.java rename to ParsePush/Native/src/main/java/com/parse/ParsePushService.java diff --git a/ParsePush/src/main/java/com/parse/ParsePushUnityHelper.java b/ParsePush/Native/src/main/java/com/parse/ParsePushUnityHelper.java similarity index 100% rename from ParsePush/src/main/java/com/parse/ParsePushUnityHelper.java rename to ParsePush/Native/src/main/java/com/parse/ParsePushUnityHelper.java diff --git a/ParsePush/src/main/java/com/parse/PushType.java b/ParsePush/Native/src/main/java/com/parse/PushType.java similarity index 100% rename from ParsePush/src/main/java/com/parse/PushType.java rename to ParsePush/Native/src/main/java/com/parse/PushType.java diff --git a/Parse/Parse.Android.csproj b/ParsePush/ParsePush.Android.csproj similarity index 81% rename from Parse/Parse.Android.csproj rename to ParsePush/ParsePush.Android.csproj index abdf89fd..a76dbe42 100644 --- a/Parse/Parse.Android.csproj +++ b/ParsePush/ParsePush.Android.csproj @@ -9,8 +9,8 @@ {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} Library Properties - Parse.Android - Parse.Android + Parse.Push + Parse.Push 512 Resources\Resource.Designer.cs Off @@ -38,7 +38,7 @@ 4 SdkOnly false - bin\Release\Android\Parse.Android.xml + bin\Release\Android\Parse.Push.xml @@ -52,28 +52,39 @@ + **\Portable\**; **\iOS\**; **\NetFx45\**; **\Phone\**; **\Unity\**; + **\Unity.iOS\**; + **\Unity.Android\**; **\WinRT\**; - **\SettingsStorage\**; - + - - + + + {de07a443-9619-4bd7-b540-41296f8a2959} + ParseCommon.Portable + + + {f3f65351-2ce1-4412-84b4-c36f34eab928} + ParseCore.Portable + + \ No newline at end of file diff --git a/ParsePush/ParsePush.Phone.csproj b/ParsePush/ParsePush.Phone.csproj new file mode 100644 index 00000000..b143c0e9 --- /dev/null +++ b/ParsePush/ParsePush.Phone.csproj @@ -0,0 +1,133 @@ + + + + Debug + AnyCPU + 10.0.20506 + 2.0 + {DEEDCDFE-A3BD-44F5-B076-EA01E6D64431} + {C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + Parse.Push + Parse.Push + WindowsPhone + v8.0 + $(TargetFrameworkVersion) + false + true + 11.0 + true + ..\ + true + + + true + full + false + Bin\Debug\Phone\ + DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + Bin\Debug\Parse.Phone.xml + + + pdbonly + true + Bin\Release\Phone\ + TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + Bin\Release\Parse.Phone.xml + + + true + full + false + Bin\x86\Debug + DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + pdbonly + true + Bin\x86\Release + TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + true + full + false + Bin\ARM\Debug + DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + pdbonly + true + Bin\ARM\Release + TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + + **\Portable\**; + **\Android\**; + **\iOS\**; + **\Mono\**; + **\NetFx45\**; + **\Unity\**; + **\Unity.iOS\**; + **\Unity.Android\**; + **\WinRT\**; + **\SettingsStorage\**; + + + + + + + + + + + {de07a443-9619-4bd7-b540-41296f8a2959} + ParseCommon.Portable + + + {f3f65351-2ce1-4412-84b4-c36f34eab928} + ParseCore.Portable + + + + false + + + + + + + \ No newline at end of file diff --git a/Parse/Parse.csproj b/ParsePush/ParsePush.Portable.csproj similarity index 71% rename from Parse/Parse.csproj rename to ParsePush/ParsePush.Portable.csproj index a6fcc792..6f4c25ff 100644 --- a/Parse/Parse.csproj +++ b/ParsePush/ParsePush.Portable.csproj @@ -5,11 +5,11 @@ 11.0 Debug AnyCPU - {DE07A443-9619-4BD7-B540-41296F8A2959} + {9DA3EC57-CDC7-4F9A-850D-8C63C7850409} Library Properties - Parse - Parse + Parse.Push + Parse.Push v4.5 Profile78 512 @@ -26,7 +26,7 @@ prompt 4 AnyCPU - bin\Debug\Parse.xml + bin\Debug\Parse.Push.xml pdbonly @@ -35,12 +35,11 @@ TRACE prompt 4 - bin\Release\Parse.xml + bin\Release\Parse.Push.xml - - + **\Partial\**; **\Android\**; **\iOS\**; @@ -48,23 +47,34 @@ **\NetFx45\**; **\Phone\**; **\Unity\**; + **\Unity.iOS\**; + **\Unity.Android\**; **\WinRT\**; **\SettingsStorage\**; - - - - - + + + + + + + + {de07a443-9619-4bd7-b540-41296f8a2959} + ParseCommon.Portable + + + {f3f65351-2ce1-4412-84b4-c36f34eab928} + ParseCore.Portable + false - + + + **\Android\**; + **\iOS\**; + **\Portable\**; + **\Mono\**; + **\NetFx45\**; + **\Phone\**; + **\WinRT\**; + **\Unity.iOS\**; + + + + + + + + + + + + + + + + {196457aa-9ba0-40bc-91a3-21baad6f4169} + ParseCommon.Unity + + + {27d3f5e9-ca66-426b-be69-9b6158071a35} + ParseCore.Unity + + + {8473bef6-7086-4414-aad6-264967a7fe75} + Unity.Compat + + + {ce75c800-a97f-4464-9a8b-3f65258456bf} + Unity.Tasks + + + \ No newline at end of file diff --git a/ParsePush/ParsePush.Unity.iOS.csproj b/ParsePush/ParsePush.Unity.iOS.csproj new file mode 100644 index 00000000..e862845c --- /dev/null +++ b/ParsePush/ParsePush.Unity.iOS.csproj @@ -0,0 +1,98 @@ + + + + + Debug + AnyCPU + {C805F141-F6F1-46B8-90F5-E8C83D7DC534} + Library + Properties + Parse.Push + Parse.Push + v3.5 + 512 + + + ..\ + true + 10.0.0 + 2.0 + + + true + full + false + bin\Debug\Unity\ + TRACE;DEBUG;UNITY + prompt + 4 + 5 + + + pdbonly + true + bin\Release\Unity\ + TRACE;UNITY + prompt + 4 + 5 + bin\Release\Unity\Parse.Push.xml + + + + + + False + ..\UnityEngine.dll + False + + + + + + **\Android\**; + **\Portable\**; + **\iOS\**; + **\Mono\**; + **\NetFx45\**; + **\Phone\**; + **\WinRT\**; + **\Unity.Android\**; + + + + + + + + + + + + + + + + {196457aa-9ba0-40bc-91a3-21baad6f4169} + ParseCommon.Unity + + + {27d3f5e9-ca66-426b-be69-9b6158071a35} + ParseCore.Unity + + + {8473bef6-7086-4414-aad6-264967a7fe75} + Unity.Compat + + + {ce75c800-a97f-4464-9a8b-3f65258456bf} + Unity.Tasks + + + diff --git a/ParsePush/ParsePush.WinRT.csproj b/ParsePush/ParsePush.WinRT.csproj new file mode 100644 index 00000000..053b3578 --- /dev/null +++ b/ParsePush/ParsePush.WinRT.csproj @@ -0,0 +1,153 @@ + + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {871208ED-7C81-490B-BFCE-9BCF3B58A8AB} + Library + Properties + Parse.Push + Parse.Push + en-US + 512 + {BC8A1FFA-BEE3-4634-8014-F334798102B3};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\ + true + + + true + full + false + bin\Debug\WinRT\ + DEBUG;TRACE;NETFX_CORE + prompt + 4 + bin\Debug\WinRT\Parse.Push.xml + + + pdbonly + true + bin\Release\WinRT\ + TRACE;NETFX_CORE + prompt + 4 + bin\Release\WinRT\Parse.Push.xml + + + true + bin\ARM\Debug\ + DEBUG;TRACE;NETFX_CORE + ;2008 + full + ARM + false + prompt + true + + + bin\ARM\Release\ + TRACE;NETFX_CORE + true + ;2008 + pdbonly + ARM + false + prompt + true + + + true + bin\x64\Debug\ + DEBUG;TRACE;NETFX_CORE + ;2008 + full + x64 + false + prompt + true + + + bin\x64\Release\ + TRACE;NETFX_CORE + true + ;2008 + pdbonly + x64 + false + prompt + true + + + true + bin\x86\Debug\ + DEBUG;TRACE;NETFX_CORE + ;2008 + full + x86 + false + prompt + true + + + bin\x86\Release\ + TRACE;NETFX_CORE + true + ;2008 + pdbonly + x86 + false + prompt + true + + + + **\Portable\**; + **\Android\**; + **\iOS\**; + **\Mono\**; + **\NetFx45\**; + **\Unity\**; + **\Unity.iOS\**; + **\Unity.Android\**; + **\Phone\**; + **\SettingsStorage\**; + + + + + + + + + + + {de07a443-9619-4bd7-b540-41296f8a2959} + ParseCommon.Portable + + + {f3f65351-2ce1-4412-84b4-c36f34eab928} + ParseCore.Portable + + + + 11.0 + + + + + + false + + + + + \ No newline at end of file diff --git a/Parse/Parse.iOS.csproj b/ParsePush/ParsePush.iOS.csproj similarity index 89% rename from Parse/Parse.iOS.csproj rename to ParsePush/ParsePush.iOS.csproj index e2c40773..3a44d83a 100644 --- a/Parse/Parse.iOS.csproj +++ b/ParsePush/ParsePush.iOS.csproj @@ -1,132 +1,147 @@ - - - - Debug - iPhoneSimulator - 8.0.30703 - 2.0 - {7A46A7B4-EE3B-4B4F-9CBF-C51D07BC7064} - {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - Parse.iOS - Resources - ..\ - true - - - True - full - False - bin\iPhoneSimulator\Debug - DEBUG;MONO;IOS - prompt - 4 - False - None - True - Parse.iOS - - - none - True - bin\iPhoneSimulator\Release - prompt - 4 - False - None - True - Parse - MONO;IOS - - - True - full - False - bin\iPhone\Debug - DEBUG;MONO;IOS - prompt - 4 - False - True - iPhone Developer - Parse.iOS - - - none - True - bin\Release\iOS\ - prompt - 4 - False - iPhone Developer - Parse.iOS - MONO;IOS - bin\Release\iOS\Parse.iOS.xml - - - none - True - bin\iPhone\Ad-Hoc - prompt - 4 - False - iPhone Distribution - True - Parse.iOS - MONO;IOS - - - none - True - bin\iPhone\AppStore - prompt - 4 - False - iPhone Distribution - Parse.iOS - MONO;IOS - - - MONO;IOS - bin\Ad-Hoc - ParseiOS - none - 4 - false - - - MONO;IOS - bin\AppStore - ParseiOS - none - 4 - false - - - + + + + Debug + iPhoneSimulator + 8.0.30703 + 2.0 + {7A46A7B4-EE3B-4B4F-9CBF-C51D07BC7064} + {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Parse.Push + Resources + ..\ + true + + + True + full + False + bin\iPhoneSimulator\Debug + DEBUG;MONO;IOS + prompt + 4 + False + None + True + Parse.iOS + + + none + True + bin\iPhoneSimulator\Release + prompt + 4 + False + None + True + Parse + MONO;IOS + + + True + full + False + bin\iPhone\Debug + DEBUG;MONO;IOS + prompt + 4 + False + True + iPhone Developer + Parse.iOS + + + none + True + bin\Release\iOS\ + prompt + 4 + False + iPhone Developer + Parse.iOS + MONO;IOS + bin\Release\iOS\Parse.iOS.xml + + + none + True + bin\iPhone\Ad-Hoc + prompt + 4 + False + iPhone Distribution + True + Parse.iOS + MONO;IOS + + + none + True + bin\iPhone\AppStore + prompt + 4 + False + iPhone Distribution + Parse.iOS + MONO;IOS + + + MONO;IOS + bin\Ad-Hoc + ParseiOS + none + 4 + false + + + MONO;IOS + bin\AppStore + ParseiOS + none + 4 + false + + + **\Android\**; **\NetFx45\**; **\Phone\**; + **\Portable\**; **\Unity\**; + **\Unity.iOS\**; + **\Unity.Android\**; **\WinRT\**; **\SettingsStorage\**; - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + Parse.Push + + + + + + + + + + + + + + + + + + + {de07a443-9619-4bd7-b540-41296f8a2959} + ParseCommon.Portable + + + {f3f65351-2ce1-4412-84b4-c36f34eab928} + ParseCore.Portable + + + diff --git a/ParsePush/Properties/AssemblyInfo.cs b/ParsePush/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..b6d9e57d --- /dev/null +++ b/ParsePush/Properties/AssemblyInfo.cs @@ -0,0 +1,23 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using Parse.Common.Internal; +using Parse.Push.Internal; + +// 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("Parse")] +[assembly: AssemblyDescription("Makes accessing services from Parse native and straightforward.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Parse")] +[assembly: AssemblyCopyright("Copyright © Parse 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(true)] + +[assembly: ParseModule(typeof(ParsePushModule))] diff --git a/Parse/Public/Android/ParseInstallation.Android.cs b/ParsePush/Public/Android/ParseInstallation.Android.cs similarity index 100% rename from Parse/Public/Android/ParseInstallation.Android.cs rename to ParsePush/Public/Android/ParseInstallation.Android.cs diff --git a/Parse/Public/Android/ParsePush.Android.cs b/ParsePush/Public/Android/ParsePush.Android.cs similarity index 97% rename from Parse/Public/Android/ParsePush.Android.cs rename to ParsePush/Public/Android/ParsePush.Android.cs index 497e6c4e..fb940e4b 100644 --- a/Parse/Public/Android/ParsePush.Android.cs +++ b/ParsePush/Public/Android/ParsePush.Android.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using Android.Content; using Android.App; +using Parse.Common.Internal; namespace Parse { public partial class ParsePush { @@ -85,7 +86,7 @@ internal static IDictionary PushJson(Intent intent) { // We encode the data payload as JSON string. Deserialize that string now. if (pushDataString != null) { - pushData = ParseClient.DeserializeJsonString(pushDataString); + pushData = Json.Parse(pushDataString) as IDictionary; } if (pushData != null) { diff --git a/Parse/Public/Android/ParsePushBroadcastReceiver.cs b/ParsePush/Public/Android/ParsePushBroadcastReceiver.cs similarity index 99% rename from Parse/Public/Android/ParsePushBroadcastReceiver.cs rename to ParsePush/Public/Android/ParsePushBroadcastReceiver.cs index d6c7f86d..dbc1bc18 100644 --- a/Parse/Public/Android/ParsePushBroadcastReceiver.cs +++ b/ParsePush/Public/Android/ParsePushBroadcastReceiver.cs @@ -60,4 +60,3 @@ public override sealed void OnReceive(Context context, Intent intent) { } } } - diff --git a/Parse/Public/Android/ParsePushService.cs b/ParsePush/Public/Android/ParsePushService.cs similarity index 99% rename from Parse/Public/Android/ParsePushService.cs rename to ParsePush/Public/Android/ParsePushService.cs index 16935afa..8abac864 100644 --- a/Parse/Public/Android/ParsePushService.cs +++ b/ParsePush/Public/Android/ParsePushService.cs @@ -47,4 +47,3 @@ protected override void OnHandleIntent(Intent intent) { } } } - diff --git a/Parse/Public/ParseInstallation.cs b/ParsePush/Public/ParseInstallation.cs similarity index 91% rename from Parse/Public/ParseInstallation.cs rename to ParsePush/Public/ParseInstallation.cs index 5186fdad..d256796b 100644 --- a/Parse/Public/ParseInstallation.cs +++ b/ParsePush/Public/ParseInstallation.cs @@ -1,6 +1,9 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. -using Parse.Internal; +using Parse; +using Parse.Common.Internal; +using Parse.Core.Internal; +using Parse.Push.Internal; using System; using System.Collections.Generic; using System.Globalization; @@ -25,7 +28,13 @@ public partial class ParseInstallation : ParseObject { internal static IParseCurrentInstallationController CurrentInstallationController { get { - return ParseCorePlugins.Instance.CurrentInstallationController; + return ParsePushPlugins.Instance.CurrentInstallationController; + } + } + + internal static IDeviceInfoController DeviceInfoController { + get { + return ParsePushPlugins.Instance.DeviceInfoController; } } @@ -58,13 +67,13 @@ internal static void ClearInMemoryInstallation() { /// /// /// Only the following types of queries are allowed for installations: - /// + /// /// /// query.GetAsync(objectId) /// query.WhereEqualTo(key, value) /// query.WhereMatchesKeyInQuery<TOther>(key, keyInQuery, otherQuery) /// - /// + /// /// You can add additional query conditions, but one of the above must appear as a top-level AND /// clause in the query. /// @@ -199,10 +208,6 @@ private set { } } - private Version GetParseVersion() { - return ParseClient.Version; - } - /// /// A sequence of arbitrary strings which are used to identify this installation for push notifications. /// By convention, the empty string is known as the "Broadcast" channel. @@ -213,29 +218,30 @@ public IList Channels { set { SetProperty(value, "Channels"); } } - internal override bool IsKeyMutable(string key) { + protected override bool IsKeyMutable(string key) { return !readOnlyKeys.Contains(key); } - internal override Task SaveAsync(Task toAwait, CancellationToken cancellationToken) { + protected override Task SaveAsync(Task toAwait, CancellationToken cancellationToken) { Task platformHookTask = null; if (CurrentInstallationController.IsCurrent(this)) { - SetIfDifferent("deviceType", ParseClient.PlatformHooks.DeviceType); - SetIfDifferent("timeZone", ParseClient.PlatformHooks.DeviceTimeZone); - SetIfDifferent("localeIdentifier", GetLocaleIdentifier()); - SetIfDifferent("parseVersion", GetParseVersion().ToString()); - SetIfDifferent("appVersion", ParseClient.PlatformHooks.AppBuildVersion); - SetIfDifferent("appIdentifier", ParseClient.PlatformHooks.AppIdentifier); - SetIfDifferent("appName", ParseClient.PlatformHooks.AppName); + var configuration = ParseClient.CurrentConfiguration; + + // 'this' is required in order for the extension method to be used. + this.SetIfDifferent("deviceType", DeviceInfoController.DeviceType); + this.SetIfDifferent("timeZone", DeviceInfoController.DeviceTimeZone); + this.SetIfDifferent("localeIdentifier", GetLocaleIdentifier()); + this.SetIfDifferent("parseVersion", GetParseVersion().ToString()); + this.SetIfDifferent("appVersion", configuration.VersionInfo.BuildVersion ?? DeviceInfoController.AppBuildVersion); + this.SetIfDifferent("appIdentifier", DeviceInfoController.AppIdentifier); + this.SetIfDifferent("appName", DeviceInfoController.AppName); - // TODO (hallucinogen): this probably should have been a controller. - platformHookTask = ParseClient.PlatformHooks.ExecuteParseInstallationSaveHookAsync(this); + platformHookTask = DeviceInfoController.ExecuteParseInstallationSaveHookAsync(this); } return platformHookTask.Safe().OnSuccess(_ => { return base.SaveAsync(toAwait, cancellationToken); - }).Unwrap() - .OnSuccess(_ => { + }).Unwrap().OnSuccess(_ => { if (CurrentInstallationController.IsCurrent(this)) { return Task.FromResult(0); } @@ -243,8 +249,12 @@ internal override Task SaveAsync(Task toAwait, CancellationToken cancellationTok }).Unwrap(); } + private Version GetParseVersion() { + return new AssemblyName(typeof(ParseInstallation).GetTypeInfo().Assembly.FullName).Version; + } + /// - /// This mapping of Windows names to a standard everyone else uses is maintained + /// This mapping of Windows names to a standard everyone else uses is maintained /// by the Unicode consortium, which makes this officially the first helpful /// interaction between Unicode and Microsoft. /// Unfortunately this is a little lossy in that we only store the first mapping in each zone because diff --git a/Parse/Public/Partial/ParsePush.cs b/ParsePush/Public/ParsePush.cs similarity index 98% rename from Parse/Public/Partial/ParsePush.cs rename to ParsePush/Public/ParsePush.cs index 94cf28bc..7e011f21 100644 --- a/Parse/Public/Partial/ParsePush.cs +++ b/ParsePush/Public/ParsePush.cs @@ -4,7 +4,9 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Parse.Internal; +using Parse.Push.Internal; +using Parse.Core.Internal; +using Parse.Common.Internal; namespace Parse { /// @@ -171,13 +173,13 @@ private void MutateState(Action func) { private static IParsePushController PushController { get { - return ParseCorePlugins.Instance.PushController; + return ParsePushPlugins.Instance.PushController; } } private static IParsePushChannelsController PushChannelsController { get { - return ParseCorePlugins.Instance.PushChannelsController; + return ParsePushPlugins.Instance.PushChannelsController; } } @@ -202,7 +204,7 @@ public Task SendAsync() { /// /// CancellationToken to cancel the current operation. public Task SendAsync(CancellationToken cancellationToken) { - return PushController.SendPushNotificationAsync(state, ParseUser.CurrentSessionToken, cancellationToken); + return PushController.SendPushNotificationAsync(state, cancellationToken); } /// diff --git a/Parse/Public/ParsePushNotificationEventArgs.cs b/ParsePush/Public/ParsePushNotificationEventArgs.cs similarity index 85% rename from Parse/Public/ParsePushNotificationEventArgs.cs rename to ParsePush/Public/ParsePushNotificationEventArgs.cs index 5dc78940..1fc03f76 100644 --- a/Parse/Public/ParsePushNotificationEventArgs.cs +++ b/ParsePush/Public/ParsePushNotificationEventArgs.cs @@ -1,5 +1,6 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. +using Parse.Common.Internal; using System; using System.Collections.Generic; @@ -12,17 +13,18 @@ internal ParsePushNotificationEventArgs(IDictionary payload) { Payload = payload; #if !IOS - StringPayload = ParseClient.SerializeJsonString(payload); + StringPayload = Json.Encode(payload); #endif } +// TODO: (richardross) investigate this. // Obj-C type -> .NET type is impossible to do flawlessly (especially -// on NSNumber). We can't transform NSDictionary into string because of this reason. +// on NSNumber). We can't transform NSDictionary into string because of this reason. #if !IOS internal ParsePushNotificationEventArgs(string stringPayload) { StringPayload = stringPayload; - Payload = ParseClient.DeserializeJsonString(stringPayload); + Payload = Json.Parse(stringPayload) as IDictionary; } #endif diff --git a/Parse/Public/Phone/ParsePush.Phone.cs b/ParsePush/Public/Phone/ParsePush.Phone.cs similarity index 94% rename from Parse/Public/Phone/ParsePush.Phone.cs rename to ParsePush/Public/Phone/ParsePush.Phone.cs index aba7a9e0..df944f39 100644 --- a/Parse/Public/Phone/ParsePush.Phone.cs +++ b/ParsePush/Public/Phone/ParsePush.Phone.cs @@ -1,7 +1,6 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. using Microsoft.Phone.Notification; -using Parse.Internal; using System; using System.Collections.Generic; using System.Linq; @@ -10,11 +9,13 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Navigation; +using Parse.Common.Internal; +using Parse.Push.Internal; namespace Parse { public partial class ParsePush { static ParsePush() { - PlatformHooks.GetToastChannelTask.ContinueWith(t => { + DeviceInfoController.GetToastChannelTask.ContinueWith(t => { if (t.Result != null) { t.Result.ShellToastNotificationReceived += (sender, args) => { toastNotificationReceived.Invoke(ParseInstallation.CurrentInstallation, args); @@ -30,7 +31,7 @@ static ParsePush() { var payloadString = streamReader.ReadToEnd(); // Always assume it's a JSON payload. - var payload = ParseClient.DeserializeJsonString(payloadString); + var payload = Json.Parse(payloadString) as IDictionary; parsePushNotificationReceived.Invoke(ParseInstallation.CurrentInstallation, new ParsePushNotificationEventArgs(payload)); }; } @@ -81,7 +82,7 @@ public static IDictionary PushJson(NotificationEventArgs args) { /// /// A method for getting the JSON dictionary used to send a push notification from the /// OnNavigated event handler, i.e. - /// + /// /// /// public override void OnNavigatedTo(NavigationEventArgs args) { /// var json = PushJson(args); @@ -101,7 +102,7 @@ internal static IDictionary PushJson(string uri) { if (token.StartsWith("pushJson=")) { var rawValue = token.Substring("pushJson=".Length); var decoded = HttpUtility.UrlDecode(rawValue); - return ParseClient.DeserializeJsonString(decoded); + return Json.Parse(decoded) as IDictionary; } } return new Dictionary(); diff --git a/ParsePush/Public/Unity.Android/ParseInstallation.Unity.Android.cs b/ParsePush/Public/Unity.Android/ParseInstallation.Unity.Android.cs new file mode 100644 index 00000000..ac4c9f39 --- /dev/null +++ b/ParsePush/Public/Unity.Android/ParseInstallation.Unity.Android.cs @@ -0,0 +1,28 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Collections; +using System.Reflection; +using System.Threading.Tasks; +using UnityEngine; + +namespace Parse { + public partial class ParseInstallation : ParseObject { + /// + /// iOS Badge. + /// + [ParseFieldName("badge")] + public int Badge { + get { + return GetProperty("Badge"); + } + set { + int badge = value; + SetProperty(badge, "Badge"); + } + } + } +} diff --git a/ParsePush/Public/Unity.iOS/ParseInstallation.Unity.iOS.cs b/ParsePush/Public/Unity.iOS/ParseInstallation.Unity.iOS.cs new file mode 100644 index 00000000..6dd1616d --- /dev/null +++ b/ParsePush/Public/Unity.iOS/ParseInstallation.Unity.iOS.cs @@ -0,0 +1,43 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Collections; +using System.Reflection; +using System.Threading.Tasks; +using Parse.Common.Internal; +using UnityEngine; +using LocalNotification = UnityEngine.iOS.LocalNotification; +using NotificationServices = UnityEngine.iOS.NotificationServices; + +namespace Parse { + public partial class ParseInstallation : ParseObject { + /// + /// iOS Badge. + /// + [ParseFieldName("badge")] + public int Badge { + get { + Dispatcher.Instance.Post(() => { + if (NotificationServices.localNotificationCount > 0) { + SetProperty(NotificationServices.localNotifications[0].applicationIconBadgeNumber, "Badge"); + } + }); + return GetProperty("Badge"); + } + set { + int badge = value; + SetProperty(badge, "Badge"); + + Dispatcher.Instance.Post(() => { + LocalNotification notification = new LocalNotification(); + notification.applicationIconBadgeNumber = badge; + notification.hasAction = false; + NotificationServices.PresentLocalNotificationNow(notification); + }); + } + } + } +} diff --git a/Parse/Public/Unity/ParseInstallation.Unity.cs b/ParsePush/Public/Unity/ParseInstallation.Unity.cs similarity index 57% rename from Parse/Public/Unity/ParseInstallation.Unity.cs rename to ParsePush/Public/Unity/ParseInstallation.Unity.cs index 70acae3e..c5352f8f 100644 --- a/Parse/Public/Unity/ParseInstallation.Unity.cs +++ b/ParsePush/Public/Unity/ParseInstallation.Unity.cs @@ -1,6 +1,5 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. -using Parse.Internal; using System; using System.Collections.Generic; using System.Linq; @@ -35,34 +34,5 @@ public void SetDeviceTokenFromData(byte[] deviceToken) { } DeviceToken = builder.ToString(); } - - /// - /// iOS Badge. - /// - [ParseFieldName("badge")] - public int Badge { - get { - if (PlatformHooks.IsIOS) { - PlatformHooks.RunOnMainThread(() => { - if (UnityEngine.iOS.NotificationServices.localNotificationCount > 0) { - SetProperty(UnityEngine.iOS.NotificationServices.localNotifications[0].applicationIconBadgeNumber, "Badge"); - } - }); - } - return GetProperty("Badge"); - } - set { - int badge = value; - SetProperty(badge, "Badge"); - if (PlatformHooks.IsIOS) { - PlatformHooks.RunOnMainThread(() => { - UnityEngine.iOS.LocalNotification notification = new UnityEngine.iOS.LocalNotification (); - notification.applicationIconBadgeNumber = badge; - notification.hasAction = false; - UnityEngine.iOS.NotificationServices.PresentLocalNotificationNow(notification); - }); - } - } - } } } diff --git a/Parse/Public/WinRT/ParsePush.WinRT.cs b/ParsePush/Public/WinRT/ParsePush.WinRT.cs similarity index 94% rename from Parse/Public/WinRT/ParsePush.WinRT.cs rename to ParsePush/Public/WinRT/ParsePush.WinRT.cs index e1af6315..6f7fc2be 100644 --- a/Parse/Public/WinRT/ParsePush.WinRT.cs +++ b/ParsePush/Public/WinRT/ParsePush.WinRT.cs @@ -1,6 +1,7 @@ // Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. -using Parse.Internal; +using Parse.Common.Internal; +using Parse.Push.Internal; using System; using System.Collections.Generic; using System.Linq; @@ -14,7 +15,7 @@ namespace Parse { public partial class ParsePush { static ParsePush() { - PlatformHooks.GetChannelTask.ContinueWith(t => + DeviceInfoController.GetChannelTask.ContinueWith(t => t.Result.PushNotificationReceived += (sender, args) => { PushNotificationReceived(ParseInstallation.CurrentInstallation, args); @@ -94,7 +95,7 @@ internal static IDictionary PushJson(ToastNotification toast) { private static IDictionary PushJson(string jsonString) { try { - return ParseClient.DeserializeJsonString(jsonString) ?? new Dictionary(); + return Json.Parse(jsonString) as IDictionary ?? new Dictionary(); } catch (Exception) { return new Dictionary(); } diff --git a/Parse/Public/iOS/ParseInstallation.iOS.cs b/ParsePush/Public/iOS/ParseInstallation.iOS.cs similarity index 100% rename from Parse/Public/iOS/ParseInstallation.iOS.cs rename to ParsePush/Public/iOS/ParseInstallation.iOS.cs diff --git a/Parse/Public/iOS/ParsePush.iOS.cs b/ParsePush/Public/iOS/ParsePush.iOS.cs similarity index 98% rename from Parse/Public/iOS/ParsePush.iOS.cs rename to ParsePush/Public/iOS/ParsePush.iOS.cs index e41659d3..3f6191aa 100644 --- a/Parse/Public/iOS/ParsePush.iOS.cs +++ b/ParsePush/Public/iOS/ParsePush.iOS.cs @@ -6,7 +6,6 @@ using System.Text; using Foundation; using UIKit; -using Parse.Internal; namespace Parse { public partial class ParsePush { diff --git a/ParseTest.Unit/InstallationTests.cs b/ParsePush/Test/InstallationTests.cs similarity index 78% rename from ParseTest.Unit/InstallationTests.cs rename to ParsePush/Test/InstallationTests.cs index 08bd4ec4..15aba43b 100644 --- a/ParseTest.Unit/InstallationTests.cs +++ b/ParsePush/Test/InstallationTests.cs @@ -1,5 +1,6 @@ using Parse; -using Parse.Internal; +using Parse.Core.Internal; +using Parse.Push.Internal; using NUnit.Framework; using Moq; using System; @@ -18,10 +19,7 @@ public void SetUp() { [TearDown] public void TearDown() { - ParseCorePlugins.Instance.ObjectController = null; - ParseCorePlugins.Instance.CurrentInstallationController = null; - ParseCorePlugins.Instance.CurrentUserController = null; - ParseObject.UnregisterSubclass(); + ParseCorePlugins.Instance = null; } [Test] @@ -37,12 +35,12 @@ public void TestInstallationIdGetterSetter() { { "installationId", guid.ToString() } } }; - ParseInstallation installation = ParseObject.FromState(state, "_Installation"); + ParseInstallation installation = ParseObjectExtensions.FromState(state, "_Installation"); Assert.NotNull(installation); Assert.AreEqual(guid, installation.InstallationId); var newGuid = Guid.NewGuid(); - Assert.Throws(() => installation.InstallationId = newGuid); + Assert.Throws(() => installation["installationId"] = newGuid); installation.SetIfDifferent("installationId", newGuid.ToString()); Assert.AreEqual(newGuid, installation.InstallationId); } @@ -54,11 +52,11 @@ public void TestDeviceTypeGetterSetter() { { "deviceType", "parseOS" } } }; - ParseInstallation installation = ParseObject.FromState(state, "_Installation"); + ParseInstallation installation = ParseObjectExtensions.FromState(state, "_Installation"); Assert.NotNull(installation); Assert.AreEqual("parseOS", installation.DeviceType); - Assert.Throws(() => installation.DeviceType = "gogoOS"); + Assert.Throws(() => installation["deviceType"] = "gogoOS"); installation.SetIfDifferent("deviceType", "gogoOS"); Assert.AreEqual("gogoOS", installation.DeviceType); } @@ -70,11 +68,11 @@ public void TestAppNameGetterSetter() { { "appName", "parseApp" } } }; - ParseInstallation installation = ParseObject.FromState(state, "_Installation"); + ParseInstallation installation = ParseObjectExtensions.FromState(state, "_Installation"); Assert.NotNull(installation); Assert.AreEqual("parseApp", installation.AppName); - Assert.Throws(() => installation.AppName = "gogoApp"); + Assert.Throws(() => installation["appName"] = "gogoApp"); installation.SetIfDifferent("appName", "gogoApp"); Assert.AreEqual("gogoApp", installation.AppName); } @@ -86,11 +84,11 @@ public void TestAppVersionGetterSetter() { { "appVersion", "1.2.3" } } }; - ParseInstallation installation = ParseObject.FromState(state, "_Installation"); + ParseInstallation installation = ParseObjectExtensions.FromState(state, "_Installation"); Assert.NotNull(installation); Assert.AreEqual("1.2.3", installation.AppVersion); - Assert.Throws(() => installation.AppVersion = "1.2.4"); + Assert.Throws(() => installation["appVersion"] = "1.2.4"); installation.SetIfDifferent("appVersion", "1.2.4"); Assert.AreEqual("1.2.4", installation.AppVersion); } @@ -102,11 +100,11 @@ public void TestAppIdentifierGetterSetter() { { "appIdentifier", "com.parse.app" } } }; - ParseInstallation installation = ParseObject.FromState(state, "_Installation"); + ParseInstallation installation = ParseObjectExtensions.FromState(state, "_Installation"); Assert.NotNull(installation); Assert.AreEqual("com.parse.app", installation.AppIdentifier); - Assert.Throws(() => installation.AppIdentifier = "com.parse.newapp"); + Assert.Throws(() => installation["appIdentifier"] = "com.parse.newapp"); installation.SetIfDifferent("appIdentifier", "com.parse.newapp"); Assert.AreEqual("com.parse.newapp", installation.AppIdentifier); } @@ -118,7 +116,7 @@ public void TestTimeZoneGetter() { { "timeZone", "America/Los_Angeles" } } }; - ParseInstallation installation = ParseObject.FromState(state, "_Installation"); + ParseInstallation installation = ParseObjectExtensions.FromState(state, "_Installation"); Assert.NotNull(installation); Assert.AreEqual("America/Los_Angeles", installation.TimeZone); } @@ -130,7 +128,7 @@ public void TestLocaleIdentifierGetter() { { "localeIdentifier", "en-US" } } }; - ParseInstallation installation = ParseObject.FromState(state, "_Installation"); + ParseInstallation installation = ParseObjectExtensions.FromState(state, "_Installation"); Assert.NotNull(installation); Assert.AreEqual("en-US", installation.LocaleIdentifier); } @@ -143,7 +141,7 @@ public void TestChannelGetterSetter() { { "channels", channels } } }; - ParseInstallation installation = ParseObject.FromState(state, "_Installation"); + ParseInstallation installation = ParseObjectExtensions.FromState(state, "_Installation"); Assert.NotNull(installation); Assert.AreEqual("the", installation.Channels[0]); Assert.AreEqual("richard", installation.Channels[1]); @@ -161,11 +159,13 @@ public void TestGetCurrentInstallation() { { "installationId", guid.ToString() } } }; - ParseInstallation installation = ParseObject.FromState(state, "_Installation"); + ParseInstallation installation = ParseObjectExtensions.FromState(state, "_Installation"); var mockController = new Mock(); mockController.Setup(obj => obj.GetAsync(It.IsAny())).Returns(Task.FromResult(installation)); - ParseCorePlugins.Instance.CurrentInstallationController = mockController.Object; + ParsePushPlugins.Instance = new ParsePushPlugins { + CurrentInstallationController = mockController.Object + }; var currentInstallation = ParseInstallation.CurrentInstallation; Assert.NotNull(currentInstallation); diff --git a/ParsePush/Test/ParsePush.Test.Unit.NetFx45.csproj b/ParsePush/Test/ParsePush.Test.Unit.NetFx45.csproj new file mode 100644 index 00000000..dfa6663c --- /dev/null +++ b/ParsePush/Test/ParsePush.Test.Unit.NetFx45.csproj @@ -0,0 +1,160 @@ + + + + Debug + AnyCPU + {7A50B92C-63AB-4CFB-BBE6-DDABCA94699E} + Library + Properties + ParseTest + ParseTest.Unit.NetFx45 + v4.5 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + ..\ + true + + + true + full + false + bin\Debug\ + TRACE;DEBUG;NETFX + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + false + + + + ..\..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll + True + + + ..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll + True + + + ..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll + True + + + ..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll + True + + + ..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll + True + + + ..\..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll + True + + + ..\..\packages\PCLStorage.1.0.2\lib\net45\PCLStorage.dll + True + + + ..\..\packages\PCLStorage.1.0.2\lib\net45\PCLStorage.Abstractions.dll + True + + + + + ..\..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll + True + + + ..\..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll + True + + + + + + + + + + + + + + + + + + + + + + Designer + + + + + {4bbce4f8-c097-4680-8b07-b69d567eaa5b} + AssemblyLister.NetFx + + + {de07a443-9619-4bd7-b540-41296f8a2959} + ParseCommon.Portable + + + {f3f65351-2ce1-4412-84b4-c36f34eab928} + ParseCore.Portable + + + {9da3ec57-cdc7-4f9a-850d-8c63c7850409} + ParsePush.Portable + + + + + + + False + + + False + + + False + + + False + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/ParsePush/Test/Properties/AssemblyInfo.cs b/ParsePush/Test/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..c29d1b95 --- /dev/null +++ b/ParsePush/Test/Properties/AssemblyInfo.cs @@ -0,0 +1,16 @@ +using System.Reflection; + +// 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("ParseTest")] +[assembly: AssemblyDescription("Parse unit test project.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ParseTest")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/ParseTest.Unit/PushEncoderTests.cs b/ParsePush/Test/PushEncoderTests.cs similarity index 98% rename from ParseTest.Unit/PushEncoderTests.cs rename to ParsePush/Test/PushEncoderTests.cs index dae1eba5..55d56f00 100644 --- a/ParseTest.Unit/PushEncoderTests.cs +++ b/ParsePush/Test/PushEncoderTests.cs @@ -1,5 +1,5 @@ using NUnit.Framework; -using Parse.Internal; +using Parse.Push.Internal; using System; using System.Collections.Generic; diff --git a/ParseTest.Unit/PushStateTests.cs b/ParsePush/Test/PushStateTests.cs similarity index 96% rename from ParseTest.Unit/PushStateTests.cs rename to ParsePush/Test/PushStateTests.cs index f8098341..8dde24ad 100644 --- a/ParseTest.Unit/PushStateTests.cs +++ b/ParsePush/Test/PushStateTests.cs @@ -1,5 +1,5 @@ using NUnit.Framework; -using Parse.Internal; +using Parse.Push.Internal; namespace ParseTest { [TestFixture] diff --git a/ParseTest.Unit/PushTests.cs b/ParsePush/Test/PushTests.cs similarity index 86% rename from ParseTest.Unit/PushTests.cs rename to ParsePush/Test/PushTests.cs index 7ecd8dbb..faf55ec0 100644 --- a/ParseTest.Unit/PushTests.cs +++ b/ParsePush/Test/PushTests.cs @@ -1,7 +1,9 @@ using Moq; using NUnit.Framework; using Parse; -using Parse.Internal; +using Parse.Common.Internal; +using Parse.Core.Internal; +using Parse.Push.Internal; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Threading; @@ -16,7 +18,6 @@ private IParsePushController GetMockedPushController(IPushState expectedPushStat mockedController.Setup( obj => obj.SendPushNotificationAsync( It.Is(s => s.Equals(expectedPushState)), - It.IsAny(), It.IsAny() ) ).Returns(Task.FromResult(false)); @@ -44,6 +45,12 @@ private IParsePushChannelsController GetMockedPushChannelsController(IEnumerable return mockedChannelsController.Object; } + [TearDown] + public void TearDown() { + ParseCorePlugins.Instance = null; + ParsePushPlugins.Instance = null; + } + [Test] [AsyncStateMachine(typeof(PushTests))] public Task TestSendPush() { @@ -52,7 +59,9 @@ public Task TestSendPush() { }; ParsePush thePush = new ParsePush(); - ParseCorePlugins.Instance.PushController = GetMockedPushController(state); + ParsePushPlugins.Instance = new ParsePushPlugins { + PushController = GetMockedPushController(state) + }; thePush.Alert = "Alert"; state.Alert = "Alert"; @@ -77,8 +86,6 @@ public Task TestSendPush() { }).Unwrap().ContinueWith(t => { Assert.True(t.IsCompleted); Assert.False(t.IsFaulted); - - ParseCorePlugins.Instance.PushController = null; }); } @@ -86,7 +93,9 @@ public Task TestSendPush() { [AsyncStateMachine(typeof(PushTests))] public Task TestSubscribe() { List channels = new List(); - ParseCorePlugins.Instance.PushChannelsController = GetMockedPushChannelsController(channels); + ParsePushPlugins.Instance = new ParsePushPlugins { + PushChannelsController = GetMockedPushChannelsController(channels) + }; channels.Add("test"); return ParsePush.SubscribeAsync("test").ContinueWith(t => { @@ -103,8 +112,6 @@ public Task TestSubscribe() { }).Unwrap().ContinueWith(t => { Assert.IsTrue(t.IsCompleted); Assert.IsFalse(t.IsFaulted); - - ParseCorePlugins.Instance.PushChannelsController = null; }); } @@ -112,7 +119,9 @@ public Task TestSubscribe() { [AsyncStateMachine(typeof(PushTests))] public Task TestUnsubscribe() { List channels = new List(); - ParseCorePlugins.Instance.PushChannelsController = GetMockedPushChannelsController(channels); + ParsePushPlugins.Instance = new ParsePushPlugins { + PushChannelsController = GetMockedPushChannelsController(channels) + }; channels.Add("test"); return ParsePush.UnsubscribeAsync("test").ContinueWith(t => { @@ -129,8 +138,6 @@ public Task TestUnsubscribe() { }).ContinueWith(t => { Assert.IsTrue(t.IsCompleted); Assert.IsFalse(t.IsFaulted); - - ParseCorePlugins.Instance.PushChannelsController = null; }); } } diff --git a/ParsePush/Test/app.config b/ParsePush/Test/app.config new file mode 100644 index 00000000..940d25ca --- /dev/null +++ b/ParsePush/Test/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/ParsePush/Test/packages.config b/ParsePush/Test/packages.config new file mode 100644 index 00000000..499bc7cb --- /dev/null +++ b/ParsePush/Test/packages.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/ParseTest.Unit/CurrentInstallationControllerTests.cs b/ParseTest.Unit/CurrentInstallationControllerTests.cs deleted file mode 100644 index 789a50a9..00000000 --- a/ParseTest.Unit/CurrentInstallationControllerTests.cs +++ /dev/null @@ -1,132 +0,0 @@ -using Parse; -using Parse.Internal; -using Moq; -using NUnit.Framework; -using System; -using System.Threading; -using System.Threading.Tasks; -using System.Runtime.CompilerServices; - -namespace ParseTest { - [TestFixture] - public class CurrentInstallationControllerTests { - [SetUp] - public void SetUp() { - ParseObject.RegisterSubclass(); - } - - [TearDown] - public void TearDown() { - ParseObject.UnregisterSubclass(); - } - - [Test] - public void TestConstructor() { - var mockInstallationIdController = new Mock(); - var guid = Guid.NewGuid(); - mockInstallationIdController.Setup(obj => obj.Get()).Returns(guid); - - var controller = new ParseCurrentInstallationController(new Mock().Object); - Assert.IsNull(controller.CurrentInstallation); - } - - [Test] - [AsyncStateMachine(typeof(CurrentInstallationControllerTests))] - public Task TestGetSetAsync() { - var mockInstallationIdController = new Mock(); - var guid = Guid.NewGuid(); - mockInstallationIdController.Setup(obj => obj.Get()).Returns(guid); - - var controller = new ParseCurrentInstallationController(mockInstallationIdController.Object); - var installation = new ParseInstallation(); - - return controller.SetAsync(installation, CancellationToken.None).OnSuccess(_ => { - Assert.AreEqual(installation, controller.CurrentInstallation); - - return controller.GetAsync(CancellationToken.None); - }).Unwrap() - .OnSuccess(t => { - Assert.AreEqual(installation, controller.CurrentInstallation); - - controller.ClearFromMemory(); - Assert.AreNotEqual(installation, controller.CurrentInstallation); - - return controller.GetAsync(CancellationToken.None); - }).Unwrap() - .OnSuccess(t => { - Assert.AreNotSame(installation, controller.CurrentInstallation); - Assert.IsNotNull(controller.CurrentInstallation); - }); - } - - [Test] - [AsyncStateMachine(typeof(CurrentInstallationControllerTests))] - public Task TestExistsAsync() { - var mockInstallationIdController = new Mock(); - var guid = Guid.NewGuid(); - mockInstallationIdController.Setup(obj => obj.Get()).Returns(guid); - - var controller = new ParseCurrentInstallationController(mockInstallationIdController.Object); - var installation = new ParseInstallation(); - - return controller.SetAsync(installation, CancellationToken.None).OnSuccess(_ => { - Assert.AreEqual(installation, controller.CurrentInstallation); - return controller.ExistsAsync(CancellationToken.None); - }).Unwrap() - .OnSuccess(t => { - Assert.IsTrue(t.Result); - - controller.ClearFromMemory(); - - return controller.ExistsAsync(CancellationToken.None); - }).Unwrap() - .OnSuccess(t => { - Assert.IsTrue(t.Result); - - controller.ClearFromDisk(); - - return controller.ExistsAsync(CancellationToken.None); - }).Unwrap() - .OnSuccess(t => { - Assert.IsFalse(t.Result); - }); - } - - [Test] - [AsyncStateMachine(typeof(CurrentInstallationControllerTests))] - public Task TestIsCurrent() { - var mockInstallationIdController = new Mock(); - var guid = Guid.NewGuid(); - mockInstallationIdController.Setup(obj => obj.Get()).Returns(guid); - - var controller = new ParseCurrentInstallationController(mockInstallationIdController.Object); - var installation = new ParseInstallation(); - var installation2 = new ParseInstallation(); - - return controller.SetAsync(installation, CancellationToken.None).OnSuccess(t => { - Assert.IsTrue(controller.IsCurrent(installation)); - Assert.IsFalse(controller.IsCurrent(installation2)); - - controller.ClearFromMemory(); - - Assert.IsFalse(controller.IsCurrent(installation)); - - return controller.SetAsync(installation, CancellationToken.None); - }).Unwrap() - .OnSuccess(t => { - Assert.IsTrue(controller.IsCurrent(installation)); - Assert.IsFalse(controller.IsCurrent(installation2)); - - controller.ClearFromDisk(); - - Assert.IsFalse(controller.IsCurrent(installation)); - - return controller.SetAsync(installation2, CancellationToken.None); - }).Unwrap() - .OnSuccess(t => { - Assert.IsFalse(controller.IsCurrent(installation)); - Assert.IsTrue(controller.IsCurrent(installation2)); - }); - } - } -} diff --git a/ParseTest.Unit/InstallationIdControllerTests.cs b/ParseTest.Unit/InstallationIdControllerTests.cs deleted file mode 100644 index 63cde976..00000000 --- a/ParseTest.Unit/InstallationIdControllerTests.cs +++ /dev/null @@ -1,66 +0,0 @@ -using Parse; -using Parse.Internal; -using NUnit.Framework; -using System; - -namespace ParseTest { - [TestFixture] - public class InstallationIdControllerTests { - [TearDown] - public void TearDown() { - ParseClient.ApplicationSettings.Clear(); - } - - [Test] - public void TestConstructor() { - var controller = new InstallationIdController(); - Assert.False(ParseClient.ApplicationSettings.ContainsKey("InstallationId")); - } - - [Test] - public void TestGet() { - var controller = new InstallationIdController(); - var installationId = controller.Get(); - Assert.True(ParseClient.ApplicationSettings.ContainsKey("InstallationId")); - - ParseClient.ApplicationSettings.Clear(); - - var newInstallationId = controller.Get(); - Assert.AreEqual(installationId, newInstallationId); - Assert.False(ParseClient.ApplicationSettings.ContainsKey("InstallationId")); - - controller.Clear(); - - newInstallationId = controller.Get(); - Assert.AreNotEqual(installationId, newInstallationId); - Assert.True(ParseClient.ApplicationSettings.ContainsKey("InstallationId")); - } - - [Test] - public void TestSet() { - var controller = new InstallationIdController(); - var installationId = controller.Get(); - Assert.True(ParseClient.ApplicationSettings.ContainsKey("InstallationId")); - - var installationId2 = Guid.NewGuid(); - controller.Set(installationId2); - Assert.True(ParseClient.ApplicationSettings.ContainsKey("InstallationId")); - Assert.AreEqual(installationId2.ToString(), ParseClient.ApplicationSettings["InstallationId"]); - - var installationId3 = controller.Get(); - Assert.AreEqual(installationId2, installationId3); - - ParseClient.ApplicationSettings.Clear(); - - controller.Set(installationId); - Assert.True(ParseClient.ApplicationSettings.ContainsKey("InstallationId")); - Assert.AreEqual(installationId.ToString(), ParseClient.ApplicationSettings["InstallationId"]); - - controller.Clear(); - - controller.Set(installationId2); - Assert.True(ParseClient.ApplicationSettings.ContainsKey("InstallationId")); - Assert.AreEqual(installationId2.ToString(), ParseClient.ApplicationSettings["InstallationId"]); - } - } -} diff --git a/Parse/Properties/AssemblyInfo.cs b/Unity.Compat/Properties/AssemblyInfo.cs similarity index 98% rename from Parse/Properties/AssemblyInfo.cs rename to Unity.Compat/Properties/AssemblyInfo.cs index 130ed925..1994cc02 100644 --- a/Parse/Properties/AssemblyInfo.cs +++ b/Unity.Compat/Properties/AssemblyInfo.cs @@ -4,7 +4,7 @@ using System.Reflection; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// 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("Parse")] diff --git a/Parse/Compat/ConditionalWeakTable.cs b/Unity.Compat/Public/ConditionalWeakTable.cs similarity index 94% rename from Parse/Compat/ConditionalWeakTable.cs rename to Unity.Compat/Public/ConditionalWeakTable.cs index 87602c1d..847bb79a 100644 --- a/Parse/Compat/ConditionalWeakTable.cs +++ b/Unity.Compat/Public/ConditionalWeakTable.cs @@ -4,7 +4,8 @@ using System.Text; namespace System.Runtime.CompilerServices { - internal class ConditionalWeakTable + // TODO: (richardross) make this thread-safe. + public class ConditionalWeakTable where TKey : class where TValue : class { diff --git a/Parse/Compat/ExceptionDispatchInfo.cs b/Unity.Compat/Public/ExceptionDispatchInfo.cs similarity index 92% rename from Parse/Compat/ExceptionDispatchInfo.cs rename to Unity.Compat/Public/ExceptionDispatchInfo.cs index 26f7d294..de3f3ead 100644 --- a/Parse/Compat/ExceptionDispatchInfo.cs +++ b/Unity.Compat/Public/ExceptionDispatchInfo.cs @@ -4,7 +4,7 @@ using System.Text; namespace System.Runtime.ExceptionServices { - internal class ExceptionDispatchInfo { + public class ExceptionDispatchInfo { public static ExceptionDispatchInfo Capture(Exception ex) { return new ExceptionDispatchInfo(ex); } diff --git a/Unity.Compat/Public/ExpressionVisitor.cs b/Unity.Compat/Public/ExpressionVisitor.cs new file mode 100644 index 00000000..69ff888a --- /dev/null +++ b/Unity.Compat/Public/ExpressionVisitor.cs @@ -0,0 +1,320 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace System.Linq.Expressions { + public abstract class IndexExpression : Expression { + public IndexExpression() + : base(ExpressionType.ArrayIndex, typeof(object)) { + } + + public abstract Collection Arguments { get; } + public abstract bool CanReduce { get; } + public abstract PropertyInfo Indexer { get; } + public abstract Expression Object { get; } + } + + public abstract class ExpressionVisitor { + protected ExpressionVisitor() { + } + + public virtual Expression Visit(Expression exp) { + if (exp == null) + return exp; + switch (exp.NodeType) { + case ExpressionType.Negate: + case ExpressionType.NegateChecked: + case ExpressionType.Not: + case ExpressionType.Convert: + case ExpressionType.ConvertChecked: + case ExpressionType.ArrayLength: + case ExpressionType.Quote: + case ExpressionType.TypeAs: + return this.VisitUnary((UnaryExpression)exp); + case ExpressionType.Add: + case ExpressionType.AddChecked: + case ExpressionType.Subtract: + case ExpressionType.SubtractChecked: + case ExpressionType.Multiply: + case ExpressionType.MultiplyChecked: + case ExpressionType.Divide: + case ExpressionType.Modulo: + case ExpressionType.And: + case ExpressionType.AndAlso: + case ExpressionType.Or: + case ExpressionType.OrElse: + case ExpressionType.LessThan: + case ExpressionType.LessThanOrEqual: + case ExpressionType.GreaterThan: + case ExpressionType.GreaterThanOrEqual: + case ExpressionType.Equal: + case ExpressionType.NotEqual: + case ExpressionType.Coalesce: + case ExpressionType.ArrayIndex: + case ExpressionType.RightShift: + case ExpressionType.LeftShift: + case ExpressionType.ExclusiveOr: + return this.VisitBinary((BinaryExpression)exp); + case ExpressionType.TypeIs: + return this.VisitTypeIs((TypeBinaryExpression)exp); + case ExpressionType.Conditional: + return this.VisitConditional((ConditionalExpression)exp); + case ExpressionType.Constant: + return this.VisitConstant((ConstantExpression)exp); + case ExpressionType.Parameter: + return this.VisitParameter((ParameterExpression)exp); + case ExpressionType.MemberAccess: + return this.VisitMember((MemberExpression)exp); + case ExpressionType.Call: + return this.VisitMethodCall((MethodCallExpression)exp); + case ExpressionType.Lambda: + return this.VisitLambda((LambdaExpression)exp); + case ExpressionType.New: + return this.VisitNew((NewExpression)exp); + case ExpressionType.NewArrayInit: + case ExpressionType.NewArrayBounds: + return this.VisitNewArray((NewArrayExpression)exp); + case ExpressionType.Invoke: + return this.VisitInvocation((InvocationExpression)exp); + case ExpressionType.MemberInit: + return this.VisitMemberInit((MemberInitExpression)exp); + case ExpressionType.ListInit: + return this.VisitListInit((ListInitExpression)exp); + default: + throw new Exception(string.Format("Unhandled expression type: '{0}'", exp.NodeType)); + } + } + + protected virtual MemberBinding VisitBinding(MemberBinding binding) { + switch (binding.BindingType) { + case MemberBindingType.Assignment: + return this.VisitMemberAssignment((MemberAssignment)binding); + case MemberBindingType.MemberBinding: + return this.VisitMemberMemberBinding((MemberMemberBinding)binding); + case MemberBindingType.ListBinding: + return this.VisitMemberListBinding((MemberListBinding)binding); + default: + throw new Exception(string.Format("Unhandled binding type '{0}'", binding.BindingType)); + } + } + + protected virtual ElementInit VisitElementInitializer(ElementInit initializer) { + ReadOnlyCollection arguments = this.VisitExpressionList(initializer.Arguments); + if (arguments != initializer.Arguments) { + return Expression.ElementInit(initializer.AddMethod, arguments); + } + return initializer; + } + + protected virtual Expression VisitUnary(UnaryExpression u) { + Expression operand = this.Visit(u.Operand); + if (operand != u.Operand) { + return Expression.MakeUnary(u.NodeType, operand, u.Type, u.Method); + } + return u; + } + + protected virtual Expression VisitBinary(BinaryExpression b) { + Expression left = this.Visit(b.Left); + Expression right = this.Visit(b.Right); + Expression conversion = this.Visit(b.Conversion); + if (left != b.Left || right != b.Right || conversion != b.Conversion) { + if (b.NodeType == ExpressionType.Coalesce && b.Conversion != null) + return Expression.Coalesce(left, right, conversion as LambdaExpression); + else + return Expression.MakeBinary(b.NodeType, left, right, b.IsLiftedToNull, b.Method); + } + return b; + } + + protected virtual Expression VisitIndex(IndexExpression e) { + return e; + } + + protected virtual Expression VisitTypeIs(TypeBinaryExpression b) { + Expression expr = this.Visit(b.Expression); + if (expr != b.Expression) { + return Expression.TypeIs(expr, b.TypeOperand); + } + return b; + } + + protected virtual Expression VisitConstant(ConstantExpression c) { + return c; + } + + protected virtual Expression VisitConditional(ConditionalExpression c) { + Expression test = this.Visit(c.Test); + Expression ifTrue = this.Visit(c.IfTrue); + Expression ifFalse = this.Visit(c.IfFalse); + if (test != c.Test || ifTrue != c.IfTrue || ifFalse != c.IfFalse) { + return Expression.Condition(test, ifTrue, ifFalse); + } + return c; + } + + protected virtual Expression VisitParameter(ParameterExpression p) { + return p; + } + + protected virtual Expression VisitMember(MemberExpression m) { + Expression exp = this.Visit(m.Expression); + if (exp != m.Expression) { + return Expression.MakeMemberAccess(exp, m.Member); + } + return m; + } + + protected virtual Expression VisitMethodCall(MethodCallExpression m) { + Expression obj = this.Visit(m.Object); + IEnumerable args = this.VisitExpressionList(m.Arguments); + if (obj != m.Object || args != m.Arguments) { + return Expression.Call(obj, m.Method, args); + } + return m; + } + + protected virtual ReadOnlyCollection VisitExpressionList(ReadOnlyCollection original) { + List list = null; + for (int i = 0, n = original.Count; i < n; i++) { + Expression p = this.Visit(original[i]); + if (list != null) { + list.Add(p); + } else if (p != original[i]) { + list = new List(n); + for (int j = 0; j < i; j++) { + list.Add(original[j]); + } + list.Add(p); + } + } + if (list != null) { + return list.AsReadOnly(); + } + return original; + } + + protected virtual MemberAssignment VisitMemberAssignment(MemberAssignment assignment) { + Expression e = this.Visit(assignment.Expression); + if (e != assignment.Expression) { + return Expression.Bind(assignment.Member, e); + } + return assignment; + } + + protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding binding) { + IEnumerable bindings = this.VisitBindingList(binding.Bindings); + if (bindings != binding.Bindings) { + return Expression.MemberBind(binding.Member, bindings); + } + return binding; + } + + protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding binding) { + IEnumerable initializers = this.VisitElementInitializerList(binding.Initializers); + if (initializers != binding.Initializers) { + return Expression.ListBind(binding.Member, initializers); + } + return binding; + } + + protected virtual IEnumerable VisitBindingList(ReadOnlyCollection original) { + List list = null; + for (int i = 0, n = original.Count; i < n; i++) { + MemberBinding b = this.VisitBinding(original[i]); + if (list != null) { + list.Add(b); + } else if (b != original[i]) { + list = new List(n); + for (int j = 0; j < i; j++) { + list.Add(original[j]); + } + list.Add(b); + } + } + if (list != null) + return list; + return original; + } + + protected virtual IEnumerable VisitElementInitializerList(ReadOnlyCollection original) { + List list = null; + for (int i = 0, n = original.Count; i < n; i++) { + ElementInit init = this.VisitElementInitializer(original[i]); + if (list != null) { + list.Add(init); + } else if (init != original[i]) { + list = new List(n); + for (int j = 0; j < i; j++) { + list.Add(original[j]); + } + list.Add(init); + } + } + if (list != null) + return list; + return original; + } + + protected virtual Expression VisitLambda(LambdaExpression lambda) { + Expression body = this.Visit(lambda.Body); + if (body != lambda.Body) { + return Expression.Lambda(lambda.Type, body, lambda.Parameters); + } + return lambda; + } + + protected virtual NewExpression VisitNew(NewExpression nex) { + IEnumerable args = this.VisitExpressionList(nex.Arguments); + if (args != nex.Arguments) { + if (nex.Members != null) + return Expression.New(nex.Constructor, args, nex.Members); + else + return Expression.New(nex.Constructor, args); + } + return nex; + } + + protected virtual Expression VisitMemberInit(MemberInitExpression init) { + NewExpression n = this.VisitNew(init.NewExpression); + IEnumerable bindings = this.VisitBindingList(init.Bindings); + if (n != init.NewExpression || bindings != init.Bindings) { + return Expression.MemberInit(n, bindings); + } + return init; + } + + protected virtual Expression VisitListInit(ListInitExpression init) { + NewExpression n = this.VisitNew(init.NewExpression); + IEnumerable initializers = this.VisitElementInitializerList(init.Initializers); + if (n != init.NewExpression || initializers != init.Initializers) { + return Expression.ListInit(n, initializers); + } + return init; + } + + protected virtual Expression VisitNewArray(NewArrayExpression na) { + IEnumerable exprs = this.VisitExpressionList(na.Expressions); + if (exprs != na.Expressions) { + if (na.NodeType == ExpressionType.NewArrayInit) { + return Expression.NewArrayInit(na.Type.GetElementType(), exprs); + } else { + return Expression.NewArrayBounds(na.Type.GetElementType(), exprs); + } + } + return na; + } + + protected virtual Expression VisitInvocation(InvocationExpression iv) { + IEnumerable args = this.VisitExpressionList(iv.Arguments); + Expression expr = this.Visit(iv.Expression); + if (args != iv.Arguments || expr != iv.Expression) { + return Expression.Invoke(expr, args); + } + return iv; + } + } +} diff --git a/Parse/Compat/Func.cs b/Unity.Compat/Public/Func.cs similarity index 69% rename from Parse/Compat/Func.cs rename to Unity.Compat/Public/Func.cs index 8e6ddce7..5fd48d06 100644 --- a/Parse/Compat/Func.cs +++ b/Unity.Compat/Public/Func.cs @@ -4,6 +4,6 @@ using System.Text; namespace System { - internal delegate TResult Func( + public delegate TResult Func( TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5); } diff --git a/Parse/Compat/IProgress.cs b/Unity.Compat/Public/IProgress.cs similarity index 100% rename from Parse/Compat/IProgress.cs rename to Unity.Compat/Public/IProgress.cs diff --git a/Unity.Compat/Public/MissingExtensions.cs b/Unity.Compat/Public/MissingExtensions.cs new file mode 100644 index 00000000..fcb9bc38 --- /dev/null +++ b/Unity.Compat/Public/MissingExtensions.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; + +namespace System { + public static class MissingExtensions { + public static bool HasFlag(this Enum enumValue, Enum flag) { + var eInt = Convert.ToInt64(enumValue); + var flagInt = Convert.ToInt64(flag); + return (eInt & flagInt) == flagInt; + } + + public static T GetCustomAttribute(this PropertyInfo prop, bool inherit) + where T : Attribute { + return (T)prop.GetCustomAttributes(typeof(T), inherit).FirstOrDefault(); + } + + public static T GetCustomAttribute(this PropertyInfo prop) where T : Attribute { + return prop.GetCustomAttribute(true); + } + + public static T GetCustomAttribute(this MemberInfo member, bool inherit) + where T : Attribute { + return (T)member.GetCustomAttributes(typeof(T), inherit).FirstOrDefault(); + } + + public static T GetCustomAttribute(this MemberInfo member) where T : Attribute { + return member.GetCustomAttribute(true); + } + + public static IEnumerable Zip(this IEnumerable list1, + IEnumerable list2, + Func zipper) { + var e1 = list1.GetEnumerator(); + var e2 = list2.GetEnumerator(); + while (e1.MoveNext() && e2.MoveNext()) { + yield return zipper(e1.Current, e2.Current); + } + } + } +} diff --git a/Unity.Compat/Public/Progress.cs b/Unity.Compat/Public/Progress.cs new file mode 100644 index 00000000..c4bba61c --- /dev/null +++ b/Unity.Compat/Public/Progress.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; + +namespace System { + /// + /// Separate class so we don't have one synchronization context per generic instantiation of Progress. + /// + internal static class ProgressSynchronizationContext { + internal static readonly SynchronizationContext SharedContext = new SynchronizationContext(); + } + + /// + /// Provides a convenient implementation for + /// handling progress update notifications. + /// + /// The progress event argument type. + public class Progress : IProgress where T : EventArgs { + private SynchronizationContext synchronizationContext; + private SendOrPostCallback synchronizationCallback; + private Action eventHandler; + + /// + /// Constructs a new Progress handler. + /// + public Progress() { + synchronizationContext = SynchronizationContext.Current ?? ProgressSynchronizationContext.SharedContext; + synchronizationCallback = NotifyDelegates; + } + + /// + /// Constructs a new Progress handler that will invoke the given action when + /// progress events are raised. + /// + /// The action to invoke when progress changes. + public Progress(Action handler) + : this() { + eventHandler = handler; + } + + void IProgress.Report(T value) { + OnReport(value); + } + + /// + /// A method that is called whenever progress events are raised. Override + /// this method to handle the event. + /// + /// The updated progress. + protected virtual void OnReport(T value) { + synchronizationContext.Post(synchronizationCallback, value); + } + + /// + /// An event that is raised whenever progress changes are reported. + /// + public event EventHandler ProgressChanged; + + /// + /// Notify all listening delegates of the change. + /// + /// Don't call this manually, only invoke it from the proper + /// synchronization context by posting a message to it. + /// + private void NotifyDelegates(object newValue) { + var value = (T)newValue; + + // Make a copy of these values so we don't run into a TOCTTOU bug. + var handler = this.eventHandler; + var progressChanged = ProgressChanged; + + if (handler != null) { + handler(value); + } + + if (progressChanged != null) { + progressChanged(this, value); + } + } + } +} diff --git a/Parse/Compat/ThreadLocal.cs b/Unity.Compat/Public/ThreadLocal.cs similarity index 97% rename from Parse/Compat/ThreadLocal.cs rename to Unity.Compat/Public/ThreadLocal.cs index 10f1f077..16cd4bbc 100644 --- a/Parse/Compat/ThreadLocal.cs +++ b/Unity.Compat/Public/ThreadLocal.cs @@ -5,7 +5,7 @@ using System.Threading; namespace System.Threading { - internal class ThreadLocal : IDisposable { + public class ThreadLocal : IDisposable { private static long lastId = -1; [ThreadStatic] private static IDictionary threadLocalData; diff --git a/Parse/Compat/Tuple.cs b/Unity.Compat/Public/Tuple.cs similarity index 93% rename from Parse/Compat/Tuple.cs rename to Unity.Compat/Public/Tuple.cs index 60824a6a..0f0360f3 100644 --- a/Parse/Compat/Tuple.cs +++ b/Unity.Compat/Public/Tuple.cs @@ -4,14 +4,14 @@ using System.Text; namespace System { - internal static class Tuple { + public static class Tuple { // This is useful because it allows for type inference, which normally cannot be done with constructors, but can be done for static methods. public static Tuple Create(T1 t1, T2 t2) { return new Tuple(t1, t2); } } - internal class Tuple { + public class Tuple { public T1 Item1 { get; private set; } public T2 Item2 { get; private set; } public Tuple(T1 item1, T2 item2) { diff --git a/Parse/Compat/Type.cs b/Unity.Compat/Public/Type.cs similarity index 79% rename from Parse/Compat/Type.cs rename to Unity.Compat/Public/Type.cs index 6f7edec4..4f6f0b5c 100644 --- a/Parse/Compat/Type.cs +++ b/Unity.Compat/Public/Type.cs @@ -1,4 +1,5 @@ using System; +using System.Reflection; namespace System { /// @@ -10,9 +11,13 @@ namespace System { /// This class simply implements some of the simple missing methods on Type to make it as API-compatible /// as possible to TypeInfo. /// - internal static class TypeExtensions { + public static class TypeExtensions { public static Type AsType(this Type type) { return type; } + + public static TypeInfo GetTypeInfo(this Type type) { + return TypeInfo.FromType(type); + } } } diff --git a/Unity.Compat/Public/TypeInfo.cs b/Unity.Compat/Public/TypeInfo.cs new file mode 100644 index 00000000..65a4d34f --- /dev/null +++ b/Unity.Compat/Public/TypeInfo.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.CompilerServices; + +namespace System.Reflection { + public class TypeInfo : Type { + private static ConditionalWeakTable typeInfoMap = new ConditionalWeakTable(); + + internal static TypeInfo FromType(Type type) { + return typeInfoMap.GetValue(type, _ => { + return new TypeInfo(type); + }); + } + + private TypeInfo(Type underlyingType) { + this.underlyingType = underlyingType; + } + + private Type underlyingType; + + #region Missing Methods + + public T GetCustomAttribute(bool inherit) where T : Attribute { + return (T)underlyingType.GetCustomAttributes(typeof(T), inherit).FirstOrDefault(); + } + + public T GetCustomAttribute() where T : Attribute { + return GetCustomAttribute(true); + } + + public IEnumerable ImplementedInterfaces { + get { + return underlyingType.GetInterfaces(); + } + } + + #endregion + + #region Inherited from System.Type + + public override Assembly Assembly { + get { return underlyingType.Assembly; } + } + + public override string AssemblyQualifiedName { + get { return underlyingType.AssemblyQualifiedName; } + } + + public override Type BaseType { + get { return underlyingType.BaseType; } + } + + public override string FullName { + get { return underlyingType.FullName; } + } + + public override Guid GUID { + get { return underlyingType.GUID; } + } + + protected override TypeAttributes GetAttributeFlagsImpl() { + return underlyingType.Attributes; + } + + protected override ConstructorInfo GetConstructorImpl(BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) { + return underlyingType.GetConstructor(bindingAttr, binder, callConvention, types, modifiers); + } + + public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) { + return underlyingType.GetConstructors(bindingAttr); + } + + public override Type GetElementType() { + return underlyingType.GetElementType(); + } + + public override EventInfo GetEvent(string name, BindingFlags bindingAttr) { + return underlyingType.GetEvent(name, bindingAttr); + } + + public override EventInfo[] GetEvents(BindingFlags bindingAttr) { + return underlyingType.GetEvents(bindingAttr); + } + + public override FieldInfo GetField(string name, BindingFlags bindingAttr) { + return underlyingType.GetField(name, bindingAttr); + } + + public override FieldInfo[] GetFields(BindingFlags bindingAttr) { + return underlyingType.GetFields(bindingAttr); + } + + public override Type GetInterface(string name, bool ignoreCase) { + return underlyingType.GetInterface(name, ignoreCase); + } + + public override Type[] GetInterfaces() { + return underlyingType.GetInterfaces(); + } + + public override MemberInfo[] GetMembers(BindingFlags bindingAttr) { + return underlyingType.GetMembers(bindingAttr); + } + + protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) { + return underlyingType.GetMethod(name, bindingAttr, binder, callConvention, types, modifiers); + } + + public override MethodInfo[] GetMethods(BindingFlags bindingAttr) { + return underlyingType.GetMethods(bindingAttr); + } + + public override Type GetNestedType(string name, BindingFlags bindingAttr) { + return underlyingType.GetNestedType(name, bindingAttr); + } + + public override Type[] GetNestedTypes(BindingFlags bindingAttr) { + return underlyingType.GetNestedTypes(bindingAttr); + } + + public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) { + return underlyingType.GetProperties(bindingAttr); + } + + protected override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) { + return underlyingType.GetProperty(name, bindingAttr, binder, returnType, types, modifiers); + } + + protected override bool HasElementTypeImpl() { + return underlyingType.HasElementType; + } + + public override object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, Globalization.CultureInfo culture, string[] namedParameters) { + return underlyingType.InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters); + } + + protected override bool IsArrayImpl() { + return underlyingType.IsArray; + } + + protected override bool IsByRefImpl() { + return underlyingType.IsByRef; + } + + protected override bool IsCOMObjectImpl() { + return underlyingType.IsCOMObject; + } + + protected override bool IsPointerImpl() { + return underlyingType.IsPointer; + } + + protected override bool IsPrimitiveImpl() { + return underlyingType.IsPrimitive; + } + + public override Module Module { + get { return underlyingType.Module; } + } + + public override string Namespace { + get { return underlyingType.Namespace; } + } + + public override Type UnderlyingSystemType { + get { return underlyingType.UnderlyingSystemType; } + } + + public override object[] GetCustomAttributes(Type attributeType, bool inherit) { + return underlyingType.GetCustomAttributes(attributeType, inherit); + } + + public override object[] GetCustomAttributes(bool inherit) { + return underlyingType.GetCustomAttributes(inherit); + } + + public override bool IsDefined(Type attributeType, bool inherit) { + return underlyingType.IsDefined(attributeType, inherit); + } + + public override string Name { + get { return underlyingType.Name; } + } + + #endregion + } +} \ No newline at end of file diff --git a/Unity.Compat/Unity.Compat.csproj b/Unity.Compat/Unity.Compat.csproj new file mode 100644 index 00000000..b05d7183 --- /dev/null +++ b/Unity.Compat/Unity.Compat.csproj @@ -0,0 +1,66 @@ + + + + + Debug + AnyCPU + {8473BEF6-7086-4414-AAD6-264967A7FE75} + Library + Properties + Unity.Compat + Unity.Compat + v3.5 + 512 + + + ..\ + true + 10.0.0 + 2.0 + + + true + full + false + bin\Debug\Unity\ + TRACE;DEBUG;UNITY + prompt + 4 + 5 + + + pdbonly + true + bin\Release\Unity\ + TRACE;UNITY + prompt + 4 + 5 + bin\Release\Unity\Unity.Compat.xml + + + + + + False + ..\UnityEngine.dll + False + + + + + + + + + + + + + \ No newline at end of file diff --git a/Unity.Tasks/Internal/InternalExtensions.cs b/Unity.Tasks/Internal/InternalExtensions.cs new file mode 100644 index 00000000..0ecb88c9 --- /dev/null +++ b/Unity.Tasks/Internal/InternalExtensions.cs @@ -0,0 +1,70 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.ExceptionServices; +using System.Text; +using System.Threading.Tasks; + +namespace Unity.Tasks.Internal { + /// + /// Provides helper methods that allow us to use terser code elsewhere. + /// + internal static class InternalExtensions { + internal static Task OnSuccess(this Task task, + Func, TResult> continuation) { + return ((Task)task).OnSuccess(t => continuation((Task)t)); + } + + internal static Task OnSuccess(this Task task, Action> continuation) { + return task.OnSuccess((Func, object>)(t => { + continuation(t); + return null; + })); + } + + internal static Task OnSuccess(this Task task, + Func continuation) { + return task.ContinueWith(t => { + if (t.IsFaulted) { + var ex = t.Exception.Flatten(); + if (ex.InnerExceptions.Count == 1) { + ExceptionDispatchInfo.Capture(ex.InnerExceptions[0]).Throw(); + } else { + ExceptionDispatchInfo.Capture(ex).Throw(); + } + // Unreachable + return Task.FromResult(default(TResult)); + } else if (t.IsCanceled) { + var tcs = new TaskCompletionSource(); + tcs.SetCanceled(); + return tcs.Task; + } else { + return Task.FromResult(continuation(t)); + } + }).Unwrap(); + } + + internal static Task OnSuccess(this Task task, Action continuation) { + return task.OnSuccess((Func)(t => { + continuation(t); + return null; + })); + } + + internal static Task WhileAsync(Func> predicate, Func body) { + Func iterate = null; + iterate = () => { + return predicate().OnSuccess(t => { + if (!t.Result) { + return Task.FromResult(0); + } + return body().OnSuccess(_ => iterate()).Unwrap(); + }).Unwrap(); + }; + return iterate(); + } + } +} diff --git a/Unity.Tasks/Properties/AssemblyInfo.cs b/Unity.Tasks/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..1994cc02 --- /dev/null +++ b/Unity.Tasks/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +// Copyright (c) 2015-present, Parse, LLC. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. An additional grant of patent rights can be found in the PATENTS file in the same directory. + +using System; +using System.Reflection; +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("Parse")] +[assembly: AssemblyDescription("Makes accessing services from Parse native and straightforward.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Parse")] +[assembly: AssemblyCopyright("Copyright © Parse 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(true)] \ No newline at end of file diff --git a/Parse/Tasks/AggregateException.cs b/Unity.Tasks/Public/AggregateException.cs similarity index 100% rename from Parse/Tasks/AggregateException.cs rename to Unity.Tasks/Public/AggregateException.cs diff --git a/Parse/Tasks/CancellationToken.cs b/Unity.Tasks/Public/CancellationToken.cs similarity index 100% rename from Parse/Tasks/CancellationToken.cs rename to Unity.Tasks/Public/CancellationToken.cs diff --git a/Parse/Tasks/CancellationTokenRegistration.cs b/Unity.Tasks/Public/CancellationTokenRegistration.cs similarity index 100% rename from Parse/Tasks/CancellationTokenRegistration.cs rename to Unity.Tasks/Public/CancellationTokenRegistration.cs diff --git a/Parse/Tasks/CancellationTokenSource.cs b/Unity.Tasks/Public/CancellationTokenSource.cs similarity index 100% rename from Parse/Tasks/CancellationTokenSource.cs rename to Unity.Tasks/Public/CancellationTokenSource.cs diff --git a/Parse/Tasks/Task.cs b/Unity.Tasks/Public/Task.cs similarity index 99% rename from Parse/Tasks/Task.cs rename to Unity.Tasks/Public/Task.cs index 0d8ac1bf..25798109 100644 --- a/Parse/Tasks/Task.cs +++ b/Unity.Tasks/Public/Task.cs @@ -2,7 +2,7 @@ using System.Linq; using System.Text; using System.Threading; -using Parse.Internal; +using Unity.Tasks.Internal; namespace System.Threading.Tasks { /// @@ -35,7 +35,7 @@ public abstract class Task { internal Task() { } - internal static TaskFactory Factory { + public static TaskFactory Factory { get { return new TaskFactory(); } diff --git a/Parse/Tasks/TaskCompletionSource.cs b/Unity.Tasks/Public/TaskCompletionSource.cs similarity index 100% rename from Parse/Tasks/TaskCompletionSource.cs rename to Unity.Tasks/Public/TaskCompletionSource.cs diff --git a/Parse/Tasks/TaskContinuationOptions.cs b/Unity.Tasks/Public/TaskContinuationOptions.cs similarity index 80% rename from Parse/Tasks/TaskContinuationOptions.cs rename to Unity.Tasks/Public/TaskContinuationOptions.cs index 95a66ce0..534eea42 100644 --- a/Parse/Tasks/TaskContinuationOptions.cs +++ b/Unity.Tasks/Public/TaskContinuationOptions.cs @@ -4,7 +4,7 @@ using System.Text; namespace System.Threading.Tasks { - internal enum TaskContinuationOptions { + public enum TaskContinuationOptions { None, ExecuteSynchronously = 524288 } diff --git a/Parse/Tasks/TaskCreationOptions.cs b/Unity.Tasks/Public/TaskCreationOptions.cs similarity index 78% rename from Parse/Tasks/TaskCreationOptions.cs rename to Unity.Tasks/Public/TaskCreationOptions.cs index 55092670..f94dcf81 100644 --- a/Parse/Tasks/TaskCreationOptions.cs +++ b/Unity.Tasks/Public/TaskCreationOptions.cs @@ -4,7 +4,7 @@ using System.Text; namespace System.Threading.Tasks { - internal enum TaskCreationOptions { + public enum TaskCreationOptions { None } } diff --git a/Parse/Tasks/TaskExtensions.cs b/Unity.Tasks/Public/TaskExtensions.cs similarity index 54% rename from Parse/Tasks/TaskExtensions.cs rename to Unity.Tasks/Public/TaskExtensions.cs index dcb138cc..3ae77df6 100644 --- a/Parse/Tasks/TaskExtensions.cs +++ b/Unity.Tasks/Public/TaskExtensions.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; +using Unity.Tasks.Internal; namespace System.Threading.Tasks { /// @@ -67,5 +69,67 @@ public static Task Unwrap(this Task> task) { }); return tcs.Task; } + + public static Task ReadToEndAsync(this StreamReader reader) { + return Task.Run(() => reader.ReadToEnd()); + } + + public static Task CopyToAsync(this Stream stream, Stream destination) { + return stream.CopyToAsync(destination, 2048, CancellationToken.None); + } + + public static Task CopyToAsync(this Stream stream, + Stream destination, + int bufferSize, + CancellationToken cancellationToken) { + byte[] buffer = new byte[bufferSize]; + int bytesRead = 0; + return InternalExtensions.WhileAsync(() => { + return stream.ReadAsync(buffer, 0, bufferSize, cancellationToken).OnSuccess(readTask => { + bytesRead = readTask.Result; + return bytesRead > 0; + }); + }, () => { + cancellationToken.ThrowIfCancellationRequested(); + return destination.WriteAsync(buffer, 0, bytesRead, cancellationToken) + .OnSuccess(_ => cancellationToken.ThrowIfCancellationRequested()); + }); + } + + public static Task ReadAsync(this Stream stream, + byte[] buffer, + int offset, + int count, + CancellationToken cancellationToken) { + if (cancellationToken.IsCancellationRequested) { + var tcs = new TaskCompletionSource(); + tcs.SetCanceled(); + return tcs.Task; + } + return Task.Factory.FromAsync(stream.BeginRead, + stream.EndRead, + buffer, + offset, + count, + null); + } + + public static Task WriteAsync(this Stream stream, + byte[] buffer, + int offset, + int count, + CancellationToken cancellationToken) { + if (cancellationToken.IsCancellationRequested) { + var tcs = new TaskCompletionSource(); + tcs.SetCanceled(); + return tcs.Task; + } + return Task.Factory.FromAsync(stream.BeginWrite, + stream.EndWrite, + buffer, + offset, + count, + null); + } } } diff --git a/Parse/Tasks/TaskFactory.cs b/Unity.Tasks/Public/TaskFactory.cs similarity index 99% rename from Parse/Tasks/TaskFactory.cs rename to Unity.Tasks/Public/TaskFactory.cs index 6f8556d6..75462c1f 100644 --- a/Parse/Tasks/TaskFactory.cs +++ b/Unity.Tasks/Public/TaskFactory.cs @@ -4,7 +4,7 @@ using System.Text; namespace System.Threading.Tasks { - internal class TaskFactory { + public class TaskFactory { private readonly TaskScheduler scheduler; private readonly CancellationToken cancellationToken; diff --git a/Parse/Tasks/TaskScheduler.cs b/Unity.Tasks/Public/TaskScheduler.cs similarity index 94% rename from Parse/Tasks/TaskScheduler.cs rename to Unity.Tasks/Public/TaskScheduler.cs index 9f1768c9..34a60825 100644 --- a/Parse/Tasks/TaskScheduler.cs +++ b/Unity.Tasks/Public/TaskScheduler.cs @@ -5,7 +5,7 @@ using System.Threading; namespace System.Threading.Tasks { - internal class TaskScheduler { + public class TaskScheduler { private static SynchronizationContext defaultContext = new SynchronizationContext(); private SynchronizationContext context; public TaskScheduler(SynchronizationContext context) { diff --git a/Unity.Tasks/Unity.Tasks.csproj b/Unity.Tasks/Unity.Tasks.csproj new file mode 100644 index 00000000..e385ce3d --- /dev/null +++ b/Unity.Tasks/Unity.Tasks.csproj @@ -0,0 +1,71 @@ + + + + + Debug + AnyCPU + {CE75C800-A97F-4464-9A8B-3F65258456BF} + Library + Properties + Unity.Tasks + Unity.Tasks + v3.5 + 512 + + + ..\ + true + 10.0.0 + 2.0 + + + true + full + false + bin\Debug\Unity\ + TRACE;DEBUG;UNITY + prompt + 4 + 5 + + + pdbonly + true + bin\Release\Unity\ + TRACE;UNITY + prompt + 4 + 5 + bin\Release\Unity\Unity.Tasks.xml + + + + + + False + ..\UnityEngine.dll + False + + + + + + + + + + + + + + {8473bef6-7086-4414-aad6-264967a7fe75} + Unity.Compat + + + \ No newline at end of file diff --git a/Parse/UnityEngine.dll b/UnityEngine.dll similarity index 100% rename from Parse/UnityEngine.dll rename to UnityEngine.dll