Google Api

This commit is contained in:
Paul Schneider 2017-06-20 02:47:52 +02:00
commit 83f9fc1bd8
123 changed files with 12961 additions and 60 deletions

View file

@ -0,0 +1,183 @@
/*
Copyright 2017 Google Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// TODO: This does not support UWP Storage.
using Google.Apis.Json;
using System;
using System.IO;
using System.Threading.Tasks;
namespace Google.Apis.Util.Store
{
/// <summary>
/// File data store that implements <see cref="IDataStore"/>. This store creates a different file for each
/// combination of type and key. This file data store stores a JSON format of the specified object.
/// </summary>
public class FileDataStore : IDataStore
{
private const string XdgDataHomeSubdirectory = "google-filedatastore";
private static readonly Task CompletedTask = Task.FromResult(0);
readonly string folderPath;
/// <summary>Gets the full folder path.</summary>
public string FolderPath { get { return folderPath; } }
/// <summary>
/// Constructs a new file data store. If <c>fullPath</c> is <c>false</c> the path will be used as relative to
/// <c>Environment.SpecialFolder.ApplicationData"</c> on Windows, or <c>$HOME</c> on Linux and MacOS,
/// otherwise the input folder will be treated as absolute.
/// The folder is created if it doesn't exist yet.
/// </summary>
/// <param name="folder">Folder path.</param>
/// <param name="fullPath">
/// Defines whether the folder parameter is absolute or relative to
/// <c>Environment.SpecialFolder.ApplicationData</c> on Windows, or<c>$HOME</c> on Linux and MacOS.
/// </param>
public FileDataStore(string folder, bool fullPath = false)
{
folderPath = fullPath
? folder
: Path.Combine(GetHomeDirectory(), folder);
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
}
private string GetHomeDirectory()
{
string appData = Environment.GetEnvironmentVariable("APPDATA");
if (!string.IsNullOrEmpty(appData))
{
// This is almost certainly windows.
// This path must be the same between the desktop FileDataStore and this netstandard FileDataStore.
return appData;
}
string home = Environment.GetEnvironmentVariable("HOME");
if (!string.IsNullOrEmpty(home))
{
// This is almost certainly Linux or MacOS.
// Follow the XDG Base Directory Specification: https://specifications.freedesktop.org/basedir-spec/latest/index.html
// Store data in subdirectory of $XDG_DATA_HOME if it exists, defaulting to $HOME/.local/share if not set.
string xdgDataHome = Environment.GetEnvironmentVariable("XDG_DATA_HOME");
if (string.IsNullOrEmpty(xdgDataHome))
{
xdgDataHome = Path.Combine(home, ".local", "share");
}
return Path.Combine(xdgDataHome, XdgDataHomeSubdirectory);
}
throw new PlatformNotSupportedException("Relative FileDataStore paths not supported on this platform.");
}
/// <summary>
/// Stores the given value for the given key. It creates a new file (named <see cref="GenerateStoredKey"/>) in
/// <see cref="FolderPath"/>.
/// </summary>
/// <typeparam name="T">The type to store in the data store.</typeparam>
/// <param name="key">The key.</param>
/// <param name="value">The value to store in the data store.</param>
public Task StoreAsync<T>(string key, T value)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentException("Key MUST have a value");
}
var serialized = NewtonsoftJsonSerializer.Instance.Serialize(value);
var filePath = Path.Combine(folderPath, GenerateStoredKey(key, typeof(T)));
File.WriteAllText(filePath, serialized);
return CompletedTask;
}
/// <summary>
/// Deletes the given key. It deletes the <see cref="GenerateStoredKey"/> named file in
/// <see cref="FolderPath"/>.
/// </summary>
/// <param name="key">The key to delete from the data store.</param>
public Task DeleteAsync<T>(string key)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentException("Key MUST have a value");
}
var filePath = Path.Combine(folderPath, GenerateStoredKey(key, typeof(T)));
if (File.Exists(filePath))
{
File.Delete(filePath);
}
return CompletedTask;
}
/// <summary>
/// Returns the stored value for the given key or <c>null</c> if the matching file (<see cref="GenerateStoredKey"/>
/// in <see cref="FolderPath"/> doesn't exist.
/// </summary>
/// <typeparam name="T">The type to retrieve.</typeparam>
/// <param name="key">The key to retrieve from the data store.</param>
/// <returns>The stored object.</returns>
public Task<T> GetAsync<T>(string key)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentException("Key MUST have a value");
}
TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();
var filePath = Path.Combine(folderPath, GenerateStoredKey(key, typeof(T)));
if (File.Exists(filePath))
{
try
{
var obj = File.ReadAllText(filePath);
tcs.SetResult(NewtonsoftJsonSerializer.Instance.Deserialize<T>(obj));
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}
else
{
tcs.SetResult(default(T));
}
return tcs.Task;
}
/// <summary>
/// Clears all values in the data store. This method deletes all files in <see cref="FolderPath"/>.
/// </summary>
public Task ClearAsync()
{
if (Directory.Exists(folderPath))
{
Directory.Delete(folderPath, true);
Directory.CreateDirectory(folderPath);
}
return CompletedTask;
}
/// <summary>Creates a unique stored key based on the key and the class type.</summary>
/// <param name="key">The object key.</param>
/// <param name="t">The type to store or retrieve.</param>
public static string GenerateStoredKey(string key, Type t)
{
return string.Format("{0}-{1}", t.FullName, key);
}
}
}

View file

@ -0,0 +1,69 @@
/*
Copyright 2017 Google Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
using System.Threading.Tasks;
namespace Google.Apis.Util.Store
{
/// <summary>
/// A null datastore. Nothing is stored, nothing is retrievable.
/// </summary>
public class NullDataStore : IDataStore
{
private static readonly Task s_completedTask = CompletedTask<int>();
private static Task<T> CompletedTask<T>()
{
var tcs = new TaskCompletionSource<T>();
tcs.SetResult(default(T));
return tcs.Task;
}
/// <summary>
/// Construct a new null datastore, that stores nothing.
/// </summary>
public NullDataStore()
{
}
/// <inheritdoc/>
public Task ClearAsync() => s_completedTask;
/// <inheritdoc/>
public Task DeleteAsync<T>(string key) => s_completedTask;
/// <summary>
/// Asynchronously returns the stored value for the given key or <c>null</c> if not found.
/// This implementation of <see cref="IDataStore"/> will always return a completed task
/// with a result of <c>null</c>.
/// </summary>
/// <typeparam name="T">The type to retrieve from the data store.</typeparam>
/// <param name="key">The key to retrieve its value.</param>
/// <returns>Always <c>null</c>.</returns>
public Task<T> GetAsync<T>(string key) => CompletedTask<T>();
/// <summary>
/// Asynchronously stores the given value for the given key (replacing any existing value).
/// This implementation of <see cref="IDataStore"/> does not store the value,
/// and will not return it in future calls to <see cref="GetAsync{T}(string)"/>.
/// </summary>
/// <typeparam name="T">The type to store in the data store.</typeparam>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
/// <returns>A task that completes immediately.</returns>
public Task StoreAsync<T>(string key, T value) => s_completedTask;
}
}