From e6181c24124d97f2fbc932b8a68311e625463156 Mon Sep 17 00:00:00 2001 From: uzvkl Date: Tue, 11 Jun 2019 23:05:52 +0200 Subject: Move dsa related stuff to subfolder --- FireBase/ExceptionEventArgs.cs | 28 -- FireBase/Extensions/ObservableExtensions.cs | 41 -- FireBase/Extensions/TaskExtensions.cs | 23 -- FireBase/FireBase.csproj | 13 - FireBase/FirebaseClient.cs | 49 --- FireBase/FirebaseException.cs | 53 --- FireBase/FirebaseKeyGenerator.cs | 79 ---- FireBase/FirebaseObject.cs | 27 -- FireBase/FirebaseOptions.cs | 52 --- FireBase/Http/HttpClientExtensions.cs | 123 ------ FireBase/Http/PostResult.cs | 13 - FireBase/ObservableExtensions.cs | 40 -- FireBase/Offline/ConcurrentOfflineDatabase.cs | 233 ----------- FireBase/Offline/DatabaseExtensions.cs | 257 ------------ FireBase/Offline/ISetHandler.cs | 10 - FireBase/Offline/InitialPullStrategy.cs | 23 -- FireBase/Offline/Internals/MemberAccessVisitor.cs | 46 --- FireBase/Offline/OfflineCacheAdapter.cs | 152 ------- FireBase/Offline/OfflineDatabase.cs | 228 ---------- FireBase/Offline/OfflineEntry.cs | 99 ----- FireBase/Offline/RealtimeDatabase.cs | 479 ---------------------- FireBase/Offline/SetHandler.cs | 19 - FireBase/Offline/StreamingOptions.cs | 23 -- FireBase/Offline/SyncOptions.cs | 28 -- FireBase/Query/AuthQuery.cs | 34 -- FireBase/Query/ChildQuery.cs | 50 --- FireBase/Query/FilterQuery.cs | 77 ---- FireBase/Query/FirebaseQuery.cs | 314 -------------- FireBase/Query/IFirebaseQuery.cs | 40 -- FireBase/Query/OrderQuery.cs | 34 -- FireBase/Query/ParameterQuery.cs | 43 -- FireBase/Query/QueryExtensions.cs | 210 ---------- FireBase/Query/QueryFactoryExtensions.cs | 187 --------- FireBase/Query/SilentQuery.cs | 18 - FireBase/Settings.StyleCop | 77 ---- FireBase/Streaming/FirebaseCache.cs | 181 -------- FireBase/Streaming/FirebaseEvent.cs | 37 -- FireBase/Streaming/FirebaseEventSource.cs | 38 -- FireBase/Streaming/FirebaseEventType.cs | 18 - FireBase/Streaming/FirebaseServerEventType.cs | 15 - FireBase/Streaming/FirebaseSubscription.cs | 217 ---------- FireBase/Streaming/NonBlockingStreamReader.cs | 63 --- 42 files changed, 3791 deletions(-) delete mode 100644 FireBase/ExceptionEventArgs.cs delete mode 100644 FireBase/Extensions/ObservableExtensions.cs delete mode 100644 FireBase/Extensions/TaskExtensions.cs delete mode 100644 FireBase/FireBase.csproj delete mode 100644 FireBase/FirebaseClient.cs delete mode 100644 FireBase/FirebaseException.cs delete mode 100644 FireBase/FirebaseKeyGenerator.cs delete mode 100644 FireBase/FirebaseObject.cs delete mode 100644 FireBase/FirebaseOptions.cs delete mode 100644 FireBase/Http/HttpClientExtensions.cs delete mode 100644 FireBase/Http/PostResult.cs delete mode 100644 FireBase/ObservableExtensions.cs delete mode 100644 FireBase/Offline/ConcurrentOfflineDatabase.cs delete mode 100644 FireBase/Offline/DatabaseExtensions.cs delete mode 100644 FireBase/Offline/ISetHandler.cs delete mode 100644 FireBase/Offline/InitialPullStrategy.cs delete mode 100644 FireBase/Offline/Internals/MemberAccessVisitor.cs delete mode 100644 FireBase/Offline/OfflineCacheAdapter.cs delete mode 100644 FireBase/Offline/OfflineDatabase.cs delete mode 100644 FireBase/Offline/OfflineEntry.cs delete mode 100644 FireBase/Offline/RealtimeDatabase.cs delete mode 100644 FireBase/Offline/SetHandler.cs delete mode 100644 FireBase/Offline/StreamingOptions.cs delete mode 100644 FireBase/Offline/SyncOptions.cs delete mode 100644 FireBase/Query/AuthQuery.cs delete mode 100644 FireBase/Query/ChildQuery.cs delete mode 100644 FireBase/Query/FilterQuery.cs delete mode 100644 FireBase/Query/FirebaseQuery.cs delete mode 100644 FireBase/Query/IFirebaseQuery.cs delete mode 100644 FireBase/Query/OrderQuery.cs delete mode 100644 FireBase/Query/ParameterQuery.cs delete mode 100644 FireBase/Query/QueryExtensions.cs delete mode 100644 FireBase/Query/QueryFactoryExtensions.cs delete mode 100644 FireBase/Query/SilentQuery.cs delete mode 100644 FireBase/Settings.StyleCop delete mode 100644 FireBase/Streaming/FirebaseCache.cs delete mode 100644 FireBase/Streaming/FirebaseEvent.cs delete mode 100644 FireBase/Streaming/FirebaseEventSource.cs delete mode 100644 FireBase/Streaming/FirebaseEventType.cs delete mode 100644 FireBase/Streaming/FirebaseServerEventType.cs delete mode 100644 FireBase/Streaming/FirebaseSubscription.cs delete mode 100644 FireBase/Streaming/NonBlockingStreamReader.cs (limited to 'FireBase') diff --git a/FireBase/ExceptionEventArgs.cs b/FireBase/ExceptionEventArgs.cs deleted file mode 100644 index 09c205a..0000000 --- a/FireBase/ExceptionEventArgs.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; - -namespace Firebase.Database -{ - /// - /// Event args holding the object. - /// - public class ExceptionEventArgs : EventArgs where T : Exception - { - public readonly T Exception; - - /// - /// Initializes a new instance of the class. - /// - /// The exception. - public ExceptionEventArgs(T exception) - { - Exception = exception; - } - } - - public class ExceptionEventArgs : ExceptionEventArgs - { - public ExceptionEventArgs(Exception exception) : base(exception) - { - } - } -} \ No newline at end of file diff --git a/FireBase/Extensions/ObservableExtensions.cs b/FireBase/Extensions/ObservableExtensions.cs deleted file mode 100644 index 0a672d7..0000000 --- a/FireBase/Extensions/ObservableExtensions.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Reactive.Linq; - -namespace Firebase.Database.Extensions -{ - public static class ObservableExtensions - { - /// - /// Returns a cold observable which retries (re-subscribes to) the source observable on error until it successfully - /// terminates. - /// - /// The source observable. - /// How long to wait between attempts. - /// A predicate determining for which exceptions to retry. Defaults to all - /// - /// A cold observable which retries (re-subscribes to) the source observable on error up to the - /// specified number of times or until it successfully terminates. - /// - public static IObservable RetryAfterDelay( - this IObservable source, - TimeSpan dueTime, - Func retryOnError) - where TException : Exception - { - var attempt = 0; - - return Observable.Defer(() => - { - return (++attempt == 1 ? source : source.DelaySubscription(dueTime)) - .Select(item => new Tuple(true, item, null)) - .Catch, TException>(e => retryOnError(e) - ? Observable.Throw>(e) - : Observable.Return(new Tuple(false, default(T), e))); - }) - .Retry() - .SelectMany(t => t.Item1 - ? Observable.Return(t.Item2) - : Observable.Throw(t.Item3)); - } - } -} \ No newline at end of file diff --git a/FireBase/Extensions/TaskExtensions.cs b/FireBase/Extensions/TaskExtensions.cs deleted file mode 100644 index c955b3a..0000000 --- a/FireBase/Extensions/TaskExtensions.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Firebase.Database.Extensions -{ - public static class TaskExtensions - { - /// - /// Instead of unwrapping it throws it as it is. - /// - public static async Task WithAggregateException(this Task source) - { - try - { - await source.ConfigureAwait(false); - } - catch (Exception ex) - { - throw source.Exception ?? ex; - } - } - } -} \ No newline at end of file diff --git a/FireBase/FireBase.csproj b/FireBase/FireBase.csproj deleted file mode 100644 index 2a47b27..0000000 --- a/FireBase/FireBase.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - netcoreapp2.2 - - - - - - - - - diff --git a/FireBase/FirebaseClient.cs b/FireBase/FirebaseClient.cs deleted file mode 100644 index 3079f3b..0000000 --- a/FireBase/FirebaseClient.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Net.Http; -using System.Runtime.CompilerServices; -using Firebase.Database.Query; - -[assembly: InternalsVisibleTo("Firebase.Database.Tests")] - -namespace Firebase.Database -{ - /// - /// Firebase client which acts as an entry point to the online database. - /// - public class FirebaseClient : IDisposable - { - private readonly string baseUrl; - internal readonly HttpClient HttpClient; - internal readonly FirebaseOptions Options; - - /// - /// Initializes a new instance of the class. - /// - /// The base url. - /// Offline database. - public FirebaseClient(string baseUrl, FirebaseOptions options = null) - { - HttpClient = new HttpClient(); - Options = options ?? new FirebaseOptions(); - - this.baseUrl = baseUrl; - - if (!this.baseUrl.EndsWith("/")) this.baseUrl += "/"; - } - - public void Dispose() - { - HttpClient?.Dispose(); - } - - /// - /// Queries for a child of the data root. - /// - /// Name of the child. - /// . - public ChildQuery Child(string resourceName) - { - return new ChildQuery(this, () => baseUrl + resourceName); - } - } -} \ No newline at end of file diff --git a/FireBase/FirebaseException.cs b/FireBase/FirebaseException.cs deleted file mode 100644 index cfc09d3..0000000 --- a/FireBase/FirebaseException.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Net; - -namespace Firebase.Database -{ - public class FirebaseException : Exception - { - public FirebaseException(string requestUrl, string requestData, string responseData, HttpStatusCode statusCode) - : base(GenerateExceptionMessage(requestUrl, requestData, responseData)) - { - RequestUrl = requestUrl; - RequestData = requestData; - ResponseData = responseData; - StatusCode = statusCode; - } - - public FirebaseException(string requestUrl, string requestData, string responseData, HttpStatusCode statusCode, - Exception innerException) - : base(GenerateExceptionMessage(requestUrl, requestData, responseData), innerException) - { - RequestUrl = requestUrl; - RequestData = requestData; - ResponseData = responseData; - StatusCode = statusCode; - } - - /// - /// Post data passed to the authentication service. - /// - public string RequestData { get; } - - /// - /// Original url of the request. - /// - public string RequestUrl { get; } - - /// - /// Response from the authentication service. - /// - public string ResponseData { get; } - - /// - /// Status code of the response. - /// - public HttpStatusCode StatusCode { get; } - - private static string GenerateExceptionMessage(string requestUrl, string requestData, string responseData) - { - return - $"Exception occured while processing the request.\nUrl: {requestUrl}\nRequest Data: {requestData}\nResponse: {responseData}"; - } - } -} \ No newline at end of file diff --git a/FireBase/FirebaseKeyGenerator.cs b/FireBase/FirebaseKeyGenerator.cs deleted file mode 100644 index 37beed5..0000000 --- a/FireBase/FirebaseKeyGenerator.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Text; - -namespace Firebase.Database -{ - /// - /// Offline key generator which mimics the official Firebase generators. - /// Credit: https://github.com/bubbafat/FirebaseSharp/blob/master/src/FirebaseSharp.Portable/FireBasePushIdGenerator.cs - /// - public class FirebaseKeyGenerator - { - // Modeled after base64 web-safe chars, but ordered by ASCII. - private const string PushCharsString = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; - private static readonly char[] PushChars; - private static readonly DateTimeOffset Epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, 0, TimeSpan.Zero); - - private static readonly Random random = new Random(); - private static readonly byte[] lastRandChars = new byte[12]; - - // Timestamp of last push, used to prevent local collisions if you push twice in one ms. - private static long lastPushTime; - - static FirebaseKeyGenerator() - { - PushChars = Encoding.UTF8.GetChars(Encoding.UTF8.GetBytes(PushCharsString)); - } - - /// - /// Returns next firebase key based on current time. - /// - /// - /// The . - /// - public static string Next() - { - // We generate 72-bits of randomness which get turned into 12 characters and - // appended to the timestamp to prevent collisions with other clients. We store the last - // characters we generated because in the event of a collision, we'll use those same - // characters except "incremented" by one. - var id = new StringBuilder(20); - var now = (long) (DateTimeOffset.Now - Epoch).TotalMilliseconds; - var duplicateTime = now == lastPushTime; - lastPushTime = now; - - var timeStampChars = new char[8]; - for (var i = 7; i >= 0; i--) - { - var index = (int) (now % PushChars.Length); - timeStampChars[i] = PushChars[index]; - now = (long) Math.Floor((double) now / PushChars.Length); - } - - if (now != 0) throw new Exception("We should have converted the entire timestamp."); - - id.Append(timeStampChars); - - if (!duplicateTime) - { - for (var i = 0; i < 12; i++) lastRandChars[i] = (byte) random.Next(0, PushChars.Length); - } - else - { - // If the timestamp hasn't changed since last push, use the same random number, - // except incremented by 1. - var lastIndex = 11; - for (; lastIndex >= 0 && lastRandChars[lastIndex] == PushChars.Length - 1; lastIndex--) - lastRandChars[lastIndex] = 0; - - lastRandChars[lastIndex]++; - } - - for (var i = 0; i < 12; i++) id.Append(PushChars[lastRandChars[i]]); - - if (id.Length != 20) throw new Exception("Length should be 20."); - - return id.ToString(); - } - } -} \ No newline at end of file diff --git a/FireBase/FirebaseObject.cs b/FireBase/FirebaseObject.cs deleted file mode 100644 index 2e0fd20..0000000 --- a/FireBase/FirebaseObject.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace Firebase.Database -{ - /// - /// Holds the object of type - /// - /// along with its key. - /// - /// Type of the underlying object. - public class FirebaseObject - { - internal FirebaseObject(string key, T obj) - { - Key = key; - Object = obj; - } - - /// - /// Gets the key of . - /// - public string Key { get; } - - /// - /// Gets the underlying object. - /// - public T Object { get; } - } -} \ No newline at end of file diff --git a/FireBase/FirebaseOptions.cs b/FireBase/FirebaseOptions.cs deleted file mode 100644 index b4a5e51..0000000 --- a/FireBase/FirebaseOptions.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; -using Firebase.Database.Offline; -using Newtonsoft.Json; - -namespace Firebase.Database -{ - public class FirebaseOptions - { - public FirebaseOptions() - { - OfflineDatabaseFactory = (t, s) => new Dictionary(); - SubscriptionStreamReaderFactory = s => new StreamReader(s); - JsonSerializerSettings = new JsonSerializerSettings(); - SyncPeriod = TimeSpan.FromSeconds(10); - } - - /// - /// Gets or sets the factory for Firebase offline database. Default is in-memory dictionary. - /// - public Func> OfflineDatabaseFactory { get; set; } - - /// - /// Gets or sets the method for retrieving auth tokens. Default is null. - /// - public Func> AuthTokenAsyncFactory { get; set; } - - /// - /// Gets or sets the factory for used for reading online streams. Default is - /// . - /// - public Func SubscriptionStreamReaderFactory { get; set; } - - /// - /// Gets or sets the json serializer settings. - /// - public JsonSerializerSettings JsonSerializerSettings { get; set; } - - /// - /// Gets or sets the time between synchronization attempts for pulling and pushing offline entities. Default is 10 - /// seconds. - /// - public TimeSpan SyncPeriod { get; set; } - - /// - /// Specify if token returned by factory will be used as "auth" url parameter or "access_token". - /// - public bool AsAccessToken { get; set; } - } -} \ No newline at end of file diff --git a/FireBase/Http/HttpClientExtensions.cs b/FireBase/Http/HttpClientExtensions.cs deleted file mode 100644 index 6582769..0000000 --- a/FireBase/Http/HttpClientExtensions.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Threading.Tasks; -using Newtonsoft.Json; - -namespace Firebase.Database.Http -{ - /// - /// The http client extensions for object deserializations. - /// - internal static class HttpClientExtensions - { - /// - /// The get object collection async. - /// - /// The client. - /// The request uri. - /// The specific JSON Serializer Settings. - /// The type of entities the collection should contain. - /// The . - public static async Task>> GetObjectCollectionAsync( - this HttpClient client, string requestUri, - JsonSerializerSettings jsonSerializerSettings) - { - var responseData = string.Empty; - var statusCode = HttpStatusCode.OK; - - try - { - var response = await client.GetAsync(requestUri).ConfigureAwait(false); - statusCode = response.StatusCode; - responseData = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - response.EnsureSuccessStatusCode(); - - var dictionary = - JsonConvert.DeserializeObject>(responseData, jsonSerializerSettings); - - if (dictionary == null) return new FirebaseObject[0]; - - return dictionary.Select(item => new FirebaseObject(item.Key, item.Value)).ToList(); - } - catch (Exception ex) - { - throw new FirebaseException(requestUri, string.Empty, responseData, statusCode, ex); - } - } - - /*/// - /// The get object collection async. - /// - /// The client. - /// The request uri. - /// /// The Data Type. - /// The specific JSON Serializer Settings. - /// The type of entities the collection should contain. - /// The . - public static async Task>> GetObjectCollectionAsync(this HttpClient client, string requestUri, - JsonSerializerSettings jsonSerializerSettings, Type dataType) - { - var responseData = string.Empty; - var statusCode = HttpStatusCode.OK; - - try - { - var response = await client.GetAsync(requestUri).ConfigureAwait(false); - statusCode = response.StatusCode; - responseData = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - response.EnsureSuccessStatusCode(); - - Type dicType = typeof(Dictionary<,>).MakeGenericType(typeof(string), dataType); - - var dictionary = JsonConvert.DeserializeObject(responseData,dicType, jsonSerializerSettings) as Dictionary; - - if (dictionary == null) - { - return new FirebaseObject[0]; - } - - return dictionary.Select(item => new FirebaseObject(item.Key, item.Value)).ToList(); - } - catch (Exception ex) - { - throw new FirebaseException(requestUri, string.Empty, responseData, statusCode, ex); - } - }*/ - - /// - /// The get object collection async. - /// - /// The json data. - /// The type of entities the collection should contain. - /// The . - public static IEnumerable> GetObjectCollection(this string data, Type elementType) - { - var dictionaryType = typeof(Dictionary<,>).MakeGenericType(typeof(string), elementType); - IDictionary dictionary = null; - - if (data.StartsWith("[")) - { - var listType = typeof(List<>).MakeGenericType(elementType); - var list = JsonConvert.DeserializeObject(data, listType) as IList; - dictionary = Activator.CreateInstance(dictionaryType) as IDictionary; - var index = 0; - foreach (var item in list) dictionary.Add(index++.ToString(), item); - } - else - { - dictionary = JsonConvert.DeserializeObject(data, dictionaryType) as IDictionary; - } - - if (dictionary == null) yield break; - - foreach (DictionaryEntry item in dictionary) - yield return new FirebaseObject((string) item.Key, item.Value); - } - } -} \ No newline at end of file diff --git a/FireBase/Http/PostResult.cs b/FireBase/Http/PostResult.cs deleted file mode 100644 index 15a4894..0000000 --- a/FireBase/Http/PostResult.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Firebase.Database.Http -{ - /// - /// Represents data returned after a successful POST to firebase server. - /// - public class PostResult - { - /// - /// Gets or sets the generated key after a successful post. - /// - public string Name { get; set; } - } -} \ No newline at end of file diff --git a/FireBase/ObservableExtensions.cs b/FireBase/ObservableExtensions.cs deleted file mode 100644 index bc46261..0000000 --- a/FireBase/ObservableExtensions.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.ObjectModel; -using Firebase.Database.Streaming; - -namespace Firebase.Database -{ - /// - /// Extensions for . - /// - public static class ObservableExtensions - { - /// - /// Starts observing on given firebase observable and propagates event into an . - /// - /// The observable. - /// Type of entity. - /// The . - public static ObservableCollection AsObservableCollection(this IObservable> observable) - { - var collection = new ObservableCollection(); - - observable.Subscribe(f => - { - if (f.EventType == FirebaseEventType.InsertOrUpdate) - { - var i = collection.IndexOf(f.Object); - if (i >= 0) collection.RemoveAt(i); - - collection.Add(f.Object); - } - else - { - collection.Remove(f.Object); - } - }); - - return collection; - } - } -} \ No newline at end of file diff --git a/FireBase/Offline/ConcurrentOfflineDatabase.cs b/FireBase/Offline/ConcurrentOfflineDatabase.cs deleted file mode 100644 index 1a9e607..0000000 --- a/FireBase/Offline/ConcurrentOfflineDatabase.cs +++ /dev/null @@ -1,233 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using LiteDB; - -namespace Firebase.Database.Offline -{ - /// - /// The offline database. - /// - public class ConcurrentOfflineDatabase : IDictionary - { - private readonly ConcurrentDictionary ccache; - private readonly LiteRepository db; - - /// - /// Initializes a new instance of the class. - /// - /// The item type which is used to determine the database file name. - /// Custom string which will get appended to the file name. - public ConcurrentOfflineDatabase(Type itemType, string filenameModifier) - { - var fullName = GetFileName(itemType.ToString()); - if (fullName.Length > 100) fullName = fullName.Substring(0, 100); - - var mapper = BsonMapper.Global; - mapper.Entity().Id(o => o.Key); - - var root = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); - var filename = fullName + filenameModifier + ".db"; - var path = Path.Combine(root, filename); - db = new LiteRepository(new LiteDatabase(path, mapper)); - - var cache = db.Database - .GetCollection() - .FindAll() - .ToDictionary(o => o.Key, o => o); - - ccache = new ConcurrentDictionary(cache); - } - - /// - /// Gets the number of elements contained in the . - /// - /// The number of elements contained in the . - public int Count => ccache.Count; - - /// - /// Gets a value indicating whether this is a read-only collection. - /// - public bool IsReadOnly => false; - - /// - /// Gets an containing the keys of the - /// . - /// - /// - /// An containing the keys of the object that - /// implements . - /// - public ICollection Keys => ccache.Keys; - - /// - /// Gets an containing the values in the - /// . - /// - /// - /// An containing the values in the object that - /// implements . - /// - public ICollection Values => ccache.Values; - - /// - /// Gets or sets the element with the specified key. - /// - /// The key of the element to get or set. - /// The element with the specified key. - public OfflineEntry this[string key] - { - get => ccache[key]; - - set - { - ccache.AddOrUpdate(key, value, (k, existing) => value); - db.Upsert(value); - } - } - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - public IEnumerator> GetEnumerator() - { - return ccache.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// Adds an item to the . - /// - /// The object to add to the . - public void Add(KeyValuePair item) - { - Add(item.Key, item.Value); - } - - /// - /// Removes all items from the . - /// - public void Clear() - { - ccache.Clear(); - db.Delete(LiteDB.Query.All()); - } - - /// - /// Determines whether the contains a specific value. - /// - /// The object to locate in the . - /// - /// True if is found in the ; - /// otherwise, false. - /// - public bool Contains(KeyValuePair item) - { - return ContainsKey(item.Key); - } - - /// - /// Copies the elements of the to an - /// , starting at a particular index. - /// - /// - /// The one-dimensional that is the destination of the elements copied - /// from . The must have - /// zero-based indexing. - /// - /// The zero-based index in at which copying begins. - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - ccache.ToList().CopyTo(array, arrayIndex); - } - - /// - /// Removes the first occurrence of a specific object from the - /// . - /// - /// The object to remove from the . - /// - /// True if was successfully removed from the - /// ; otherwise, false. This method also returns false if - /// is not found in the original . - /// - public bool Remove(KeyValuePair item) - { - return Remove(item.Key); - } - - /// - /// Determines whether the contains an element with the - /// specified key. - /// - /// The key to locate in the . - /// - /// True if the contains an element with the key; - /// otherwise, false. - /// - public bool ContainsKey(string key) - { - return ccache.ContainsKey(key); - } - - /// - /// Adds an element with the provided key and value to the . - /// - /// The object to use as the key of the element to add. - /// The object to use as the value of the element to add. - public void Add(string key, OfflineEntry value) - { - ccache.AddOrUpdate(key, value, (k, existing) => value); - db.Upsert(value); - } - - /// - /// Removes the element with the specified key from the . - /// - /// The key of the element to remove. - /// - /// True if the element is successfully removed; otherwise, false. This method also returns false if - /// was not found in the original . - /// - public bool Remove(string key) - { - ccache.TryRemove(key, out _); - return db.Delete(key); - } - - /// - /// Gets the value associated with the specified key. - /// - /// The key whose value to get. - /// - /// When this method returns, the value associated with the specified key, if the key is found; - /// otherwise, the default value for the type of the parameter. This parameter is passed - /// uninitialized. - /// - /// - /// True if the object that implements contains an - /// element with the specified key; otherwise, false. - /// - public bool TryGetValue(string key, out OfflineEntry value) - { - return ccache.TryGetValue(key, out value); - } - - private string GetFileName(string fileName) - { - var invalidChars = new[] {'`', '[', ',', '='}; - foreach (var c in invalidChars.Concat(Path.GetInvalidFileNameChars()).Distinct()) - fileName = fileName.Replace(c, '_'); - - return fileName; - } - } -} \ No newline at end of file diff --git a/FireBase/Offline/DatabaseExtensions.cs b/FireBase/Offline/DatabaseExtensions.cs deleted file mode 100644 index e7c4074..0000000 --- a/FireBase/Offline/DatabaseExtensions.cs +++ /dev/null @@ -1,257 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Reflection; -using Firebase.Database.Query; - -namespace Firebase.Database.Offline -{ - public static class DatabaseExtensions - { - /// - /// Create new instances of the . - /// - /// Type of elements. - /// Custom string which will get appended to the file name. - /// Optional custom root element of received json items. - /// Realtime streaming options. - /// Specifies what strategy should be used for initial pulling of server data. - /// - /// Specifies whether changed items should actually be pushed to the server. It this is false, - /// then Put / Post / Delete will not affect server data. - /// - /// The . - public static RealtimeDatabase AsRealtimeDatabase(this ChildQuery query, string filenameModifier = "", - string elementRoot = "", StreamingOptions streamingOptions = StreamingOptions.LatestOnly, - InitialPullStrategy initialPullStrategy = InitialPullStrategy.MissingOnly, bool pushChanges = true) - where T : class - { - return new RealtimeDatabase(query, elementRoot, query.Client.Options.OfflineDatabaseFactory, - filenameModifier, streamingOptions, initialPullStrategy, pushChanges); - } - - /// - /// Create new instances of the . - /// - /// Type of elements. - /// Type of the custom to use. - /// Custom string which will get appended to the file name. - /// Optional custom root element of received json items. - /// Realtime streaming options. - /// Specifies what strategy should be used for initial pulling of server data. - /// - /// Specifies whether changed items should actually be pushed to the server. It this is false, - /// then Put / Post / Delete will not affect server data. - /// - /// The . - public static RealtimeDatabase AsRealtimeDatabase(this ChildQuery query, - string filenameModifier = "", string elementRoot = "", - StreamingOptions streamingOptions = StreamingOptions.LatestOnly, - InitialPullStrategy initialPullStrategy = InitialPullStrategy.MissingOnly, bool pushChanges = true) - where T : class - where TSetHandler : ISetHandler, new() - { - return new RealtimeDatabase(query, elementRoot, query.Client.Options.OfflineDatabaseFactory, - filenameModifier, streamingOptions, initialPullStrategy, pushChanges, - Activator.CreateInstance()); - } - - /// - /// Overwrites existing object with given key leaving any missing properties intact in firebase. - /// - /// The key. - /// The object to set. - /// Indicates whether the item should be synced online. - /// - /// The priority. Objects with higher priority will be synced first. Higher number indicates higher - /// priority. - /// - public static void Patch(this RealtimeDatabase db, string key, T obj, bool syncOnline = true, - int priority = 1) - where T : class - { - db.Set(key, obj, syncOnline ? SyncOptions.Patch : SyncOptions.None, priority); - } - - /// - /// Overwrites existing object with given key. - /// - /// The key. - /// The object to set. - /// Indicates whether the item should be synced online. - /// - /// The priority. Objects with higher priority will be synced first. Higher number indicates higher - /// priority. - /// - public static void Put(this RealtimeDatabase db, string key, T obj, bool syncOnline = true, - int priority = 1) - where T : class - { - db.Set(key, obj, syncOnline ? SyncOptions.Put : SyncOptions.None, priority); - } - - /// - /// Adds a new entity to the Database. - /// - /// The object to add. - /// Indicates whether the item should be synced online. - /// - /// The priority. Objects with higher priority will be synced first. Higher number indicates higher - /// priority. - /// - /// The generated key for this object. - public static string Post(this RealtimeDatabase db, T obj, bool syncOnline = true, int priority = 1) - where T : class - { - var key = FirebaseKeyGenerator.Next(); - - db.Set(key, obj, syncOnline ? SyncOptions.Put : SyncOptions.None, priority); - - return key; - } - - /// - /// Deletes the entity with the given key. - /// - /// The key. - /// Indicates whether the item should be synced online. - /// - /// The priority. Objects with higher priority will be synced first. Higher number indicates higher - /// priority. - /// - public static void Delete(this RealtimeDatabase db, string key, bool syncOnline = true, int priority = 1) - where T : class - { - db.Set(key, null, syncOnline ? SyncOptions.Put : SyncOptions.None, priority); - } - - /// - /// Do a Put for a nested property specified by of an object with key - /// . - /// - /// Type of the root elements. - /// Type of the property being modified - /// Database instance. - /// Key of the root element to modify. - /// Expression on the root element leading to target value to modify. - /// Value to put. - /// Indicates whether the item should be synced online. - /// - /// The priority. Objects with higher priority will be synced first. Higher number indicates higher - /// priority. - /// - public static void Put(this RealtimeDatabase db, string key, - Expression> propertyExpression, TProperty value, bool syncOnline = true, - int priority = 1) - where T : class - { - db.Set(key, propertyExpression, value, syncOnline ? SyncOptions.Put : SyncOptions.None, priority); - } - - /// - /// Do a Patch for a nested property specified by of an object with key - /// . - /// - /// Type of the root elements. - /// Type of the property being modified - /// Database instance. - /// Key of the root element to modify. - /// Expression on the root element leading to target value to modify. - /// Value to patch. - /// Indicates whether the item should be synced online. - /// - /// The priority. Objects with higher priority will be synced first. Higher number indicates higher - /// priority. - /// - public static void Patch(this RealtimeDatabase db, string key, - Expression> propertyExpression, TProperty value, bool syncOnline = true, - int priority = 1) - where T : class - { - db.Set(key, propertyExpression, value, syncOnline ? SyncOptions.Patch : SyncOptions.None, priority); - } - - /// - /// Delete a nested property specified by of an object with key - /// . This basically does a Put with null value. - /// - /// Type of the root elements. - /// Type of the property being modified - /// Database instance. - /// Key of the root element to modify. - /// Expression on the root element leading to target value to modify. - /// Value to put. - /// Indicates whether the item should be synced online. - /// - /// The priority. Objects with higher priority will be synced first. Higher number indicates higher - /// priority. - /// - public static void Delete(this RealtimeDatabase db, string key, - Expression> propertyExpression, bool syncOnline = true, int priority = 1) - where T : class - where TProperty : class - { - db.Set(key, propertyExpression, null, syncOnline ? SyncOptions.Put : SyncOptions.None, priority); - } - - /// - /// Post a new entity into the nested dictionary specified by of an object with - /// key . - /// The key of the new entity is automatically generated. - /// - /// Type of the root elements. - /// Type of the dictionary being modified - /// Type of the value within the dictionary being modified - /// Database instance. - /// Key of the root element to modify. - /// Expression on the root element leading to target value to modify. - /// Value to put. - /// Indicates whether the item should be synced online. - /// - /// The priority. Objects with higher priority will be synced first. Higher number indicates higher - /// priority. - /// - public static void Post(this RealtimeDatabase db, string key, - Expression> propertyExpression, TProperty value, bool syncOnline = true, - int priority = 1) - where T : class - where TSelector : IDictionary - { - var nextKey = FirebaseKeyGenerator.Next(); - var expression = Expression.Lambda>( - Expression.Call(propertyExpression.Body, - typeof(TSelector).GetRuntimeMethod("get_Item", new[] {typeof(string)}), - Expression.Constant(nextKey)), propertyExpression.Parameters); - db.Set(key, expression, value, syncOnline ? SyncOptions.Put : SyncOptions.None, priority); - } - - /// - /// Delete an entity with key in the nested dictionary specified by - /// of an object with key . - /// The key of the new entity is automatically generated. - /// - /// Type of the root elements. - /// Type of the dictionary being modified - /// Type of the value within the dictionary being modified - /// Database instance. - /// Key of the root element to modify. - /// Expression on the root element leading to target value to modify. - /// Key within the nested dictionary to delete. - /// Indicates whether the item should be synced online. - /// - /// The priority. Objects with higher priority will be synced first. Higher number indicates higher - /// priority. - /// - public static void Delete(this RealtimeDatabase db, string key, - Expression>> propertyExpression, string dictionaryKey, - bool syncOnline = true, int priority = 1) - where T : class - { - var expression = Expression.Lambda>( - Expression.Call(propertyExpression.Body, - typeof(IDictionary).GetRuntimeMethod("get_Item", new[] {typeof(string)}), - Expression.Constant(dictionaryKey)), propertyExpression.Parameters); - db.Set(key, expression, null, syncOnline ? SyncOptions.Put : SyncOptions.None, priority); - } - } -} \ No newline at end of file diff --git a/FireBase/Offline/ISetHandler.cs b/FireBase/Offline/ISetHandler.cs deleted file mode 100644 index c04bd41..0000000 --- a/FireBase/Offline/ISetHandler.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Threading.Tasks; -using Firebase.Database.Query; - -namespace Firebase.Database.Offline -{ - public interface ISetHandler - { - Task SetAsync(ChildQuery query, string key, OfflineEntry entry); - } -} \ No newline at end of file diff --git a/FireBase/Offline/InitialPullStrategy.cs b/FireBase/Offline/InitialPullStrategy.cs deleted file mode 100644 index ca2bebf..0000000 --- a/FireBase/Offline/InitialPullStrategy.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Firebase.Database.Offline -{ - /// - /// Specifies the strategy for initial pull of server data. - /// - public enum InitialPullStrategy - { - /// - /// Don't pull anything. - /// - None, - - /// - /// Pull only what isn't already stored offline. - /// - MissingOnly, - - /// - /// Pull everything that exists on the server. - /// - Everything - } -} \ No newline at end of file diff --git a/FireBase/Offline/Internals/MemberAccessVisitor.cs b/FireBase/Offline/Internals/MemberAccessVisitor.cs deleted file mode 100644 index 89a77da..0000000 --- a/FireBase/Offline/Internals/MemberAccessVisitor.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Reflection; -using Newtonsoft.Json; - -namespace Firebase.Database.Offline.Internals -{ - public class MemberAccessVisitor : ExpressionVisitor - { - private readonly IList propertyNames = new List(); - - private bool wasDictionaryAccess; - - public IEnumerable PropertyNames => propertyNames; - - public override Expression Visit(Expression expr) - { - if (expr?.NodeType == ExpressionType.MemberAccess) - { - if (wasDictionaryAccess) - { - wasDictionaryAccess = false; - } - else - { - var memberExpr = (MemberExpression) expr; - var jsonAttr = memberExpr.Member.GetCustomAttribute(); - - propertyNames.Add(jsonAttr?.PropertyName ?? memberExpr.Member.Name); - } - } - else if (expr?.NodeType == ExpressionType.Call) - { - var callExpr = (MethodCallExpression) expr; - if (callExpr.Method.Name == "get_Item" && callExpr.Arguments.Count == 1) - { - var e = Expression.Lambda(callExpr.Arguments[0]).Compile(); - propertyNames.Add(e.DynamicInvoke().ToString()); - wasDictionaryAccess = callExpr.Arguments[0].NodeType == ExpressionType.MemberAccess; - } - } - - return base.Visit(expr); - } - } -} \ No newline at end of file diff --git a/FireBase/Offline/OfflineCacheAdapter.cs b/FireBase/Offline/OfflineCacheAdapter.cs deleted file mode 100644 index 3153d1b..0000000 --- a/FireBase/Offline/OfflineCacheAdapter.cs +++ /dev/null @@ -1,152 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; - -namespace Firebase.Database.Offline -{ - internal class OfflineCacheAdapter : IDictionary, IDictionary - { - private readonly IDictionary database; - - public OfflineCacheAdapter(IDictionary database) - { - this.database = database; - } - - public void CopyTo(Array array, int index) - { - throw new NotImplementedException(); - } - - public bool IsSynchronized { get; } - - public object SyncRoot { get; } - - object IDictionary.this[object key] - { - get => database[key.ToString()].Deserialize(); - - set - { - var keyString = key.ToString(); - if (database.ContainsKey(keyString)) - database[keyString] = new OfflineEntry(keyString, value, database[keyString].Priority, - database[keyString].SyncOptions); - else - database[keyString] = new OfflineEntry(keyString, value, 1, SyncOptions.None); - } - } - - ICollection IDictionary.Values { get; } - - ICollection IDictionary.Keys { get; } - - public bool Contains(object key) - { - return ContainsKey(key.ToString()); - } - - IDictionaryEnumerator IDictionary.GetEnumerator() - { - throw new NotImplementedException(); - } - - public void Remove(object key) - { - Remove(key.ToString()); - } - - public bool IsFixedSize => false; - - public void Add(object key, object value) - { - Add(key.ToString(), (T) value); - } - - public int Count => database.Count; - - public bool IsReadOnly => database.IsReadOnly; - - public ICollection Keys => database.Keys; - - public ICollection Values => database.Values.Select(o => o.Deserialize()).ToList(); - - public T this[string key] - { - get => database[key].Deserialize(); - - set - { - if (database.ContainsKey(key)) - database[key] = new OfflineEntry(key, value, database[key].Priority, database[key].SyncOptions); - else - database[key] = new OfflineEntry(key, value, 1, SyncOptions.None); - } - } - - public IEnumerator> GetEnumerator() - { - return database.Select(d => new KeyValuePair(d.Key, d.Value.Deserialize())).GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public void Add(KeyValuePair item) - { - Add(item.Key, item.Value); - } - - public void Clear() - { - database.Clear(); - } - - public bool Contains(KeyValuePair item) - { - return ContainsKey(item.Key); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - throw new NotImplementedException(); - } - - public bool Remove(KeyValuePair item) - { - return database.Remove(item.Key); - } - - public void Add(string key, T value) - { - database.Add(key, new OfflineEntry(key, value, 1, SyncOptions.None)); - } - - public bool ContainsKey(string key) - { - return database.ContainsKey(key); - } - - public bool Remove(string key) - { - return database.Remove(key); - } - - public bool TryGetValue(string key, out T value) - { - OfflineEntry val; - - if (database.TryGetValue(key, out val)) - { - value = val.Deserialize(); - return true; - } - - value = default(T); - return false; - } - } -} \ No newline at end of file diff --git a/FireBase/Offline/OfflineDatabase.cs b/FireBase/Offline/OfflineDatabase.cs deleted file mode 100644 index be0380b..0000000 --- a/FireBase/Offline/OfflineDatabase.cs +++ /dev/null @@ -1,228 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using LiteDB; - -namespace Firebase.Database.Offline -{ - /// - /// The offline database. - /// - public class OfflineDatabase : IDictionary - { - private readonly IDictionary cache; - private readonly LiteRepository db; - - /// - /// Initializes a new instance of the class. - /// - /// The item type which is used to determine the database file name. - /// Custom string which will get appended to the file name. - public OfflineDatabase(Type itemType, string filenameModifier) - { - var fullName = GetFileName(itemType.ToString()); - if (fullName.Length > 100) fullName = fullName.Substring(0, 100); - - var mapper = BsonMapper.Global; - mapper.Entity().Id(o => o.Key); - - var root = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); - var filename = fullName + filenameModifier + ".db"; - var path = Path.Combine(root, filename); - db = new LiteRepository(new LiteDatabase(path, mapper)); - - cache = db.Database.GetCollection().FindAll() - .ToDictionary(o => o.Key, o => o); - } - - /// - /// Gets the number of elements contained in the . - /// - /// The number of elements contained in the . - public int Count => cache.Count; - - /// - /// Gets a value indicating whether this is a read-only collection. - /// - public bool IsReadOnly => cache.IsReadOnly; - - /// - /// Gets an containing the keys of the - /// . - /// - /// - /// An containing the keys of the object that - /// implements . - /// - public ICollection Keys => cache.Keys; - - /// - /// Gets an containing the values in the - /// . - /// - /// - /// An containing the values in the object that - /// implements . - /// - public ICollection Values => cache.Values; - - /// - /// Gets or sets the element with the specified key. - /// - /// The key of the element to get or set. - /// The element with the specified key. - public OfflineEntry this[string key] - { - get => cache[key]; - - set - { - cache[key] = value; - db.Upsert(value); - } - } - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - public IEnumerator> GetEnumerator() - { - return cache.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// Adds an item to the . - /// - /// The object to add to the . - public void Add(KeyValuePair item) - { - Add(item.Key, item.Value); - } - - /// - /// Removes all items from the . - /// - public void Clear() - { - cache.Clear(); - db.Delete(LiteDB.Query.All()); - } - - /// - /// Determines whether the contains a specific value. - /// - /// The object to locate in the . - /// - /// True if is found in the ; - /// otherwise, false. - /// - public bool Contains(KeyValuePair item) - { - return ContainsKey(item.Key); - } - - /// - /// Copies the elements of the to an - /// , starting at a particular index. - /// - /// - /// The one-dimensional that is the destination of the elements copied - /// from . The must have - /// zero-based indexing. - /// - /// The zero-based index in at which copying begins. - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - cache.CopyTo(array, arrayIndex); - } - - /// - /// Removes the first occurrence of a specific object from the - /// . - /// - /// The object to remove from the . - /// - /// True if was successfully removed from the - /// ; otherwise, false. This method also returns false if - /// is not found in the original . - /// - public bool Remove(KeyValuePair item) - { - return Remove(item.Key); - } - - /// - /// Determines whether the contains an element with the - /// specified key. - /// - /// The key to locate in the . - /// - /// True if the contains an element with the key; - /// otherwise, false. - /// - public bool ContainsKey(string key) - { - return cache.ContainsKey(key); - } - - /// - /// Adds an element with the provided key and value to the . - /// - /// The object to use as the key of the element to add. - /// The object to use as the value of the element to add. - public void Add(string key, OfflineEntry value) - { - cache.Add(key, value); - db.Insert(value); - } - - /// - /// Removes the element with the specified key from the . - /// - /// The key of the element to remove. - /// - /// True if the element is successfully removed; otherwise, false. This method also returns false if - /// was not found in the original . - /// - public bool Remove(string key) - { - cache.Remove(key); - return db.Delete(key); - } - - /// - /// Gets the value associated with the specified key. - /// - /// The key whose value to get. - /// - /// When this method returns, the value associated with the specified key, if the key is found; - /// otherwise, the default value for the type of the parameter. This parameter is passed - /// uninitialized. - /// - /// - /// True if the object that implements contains an - /// element with the specified key; otherwise, false. - /// - public bool TryGetValue(string key, out OfflineEntry value) - { - return cache.TryGetValue(key, out value); - } - - private string GetFileName(string fileName) - { - var invalidChars = new[] {'`', '[', ',', '='}; - foreach (var c in invalidChars.Concat(Path.GetInvalidFileNameChars()).Distinct()) - fileName = fileName.Replace(c, '_'); - - return fileName; - } - } -} \ No newline at end of file diff --git a/FireBase/Offline/OfflineEntry.cs b/FireBase/Offline/OfflineEntry.cs deleted file mode 100644 index 9feffa3..0000000 --- a/FireBase/Offline/OfflineEntry.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using Newtonsoft.Json; - -namespace Firebase.Database.Offline -{ - /// - /// Represents an object stored in offline storage. - /// - public class OfflineEntry - { - private object dataInstance; - - /// - /// Initializes a new instance of the class with an already serialized object. - /// - /// The key. - /// The object. - /// - /// The priority. Objects with higher priority will be synced first. Higher number indicates higher - /// priority. - /// - /// The sync options. - public OfflineEntry(string key, object obj, string data, int priority, SyncOptions syncOptions, - bool isPartial = false) - { - Key = key; - Priority = priority; - Data = data; - Timestamp = DateTime.UtcNow; - SyncOptions = syncOptions; - IsPartial = isPartial; - - dataInstance = obj; - } - - /// - /// Initializes a new instance of the class. - /// - /// The key. - /// The object. - /// - /// The priority. Objects with higher priority will be synced first. Higher number indicates higher - /// priority. - /// - /// The sync options. - public OfflineEntry(string key, object obj, int priority, SyncOptions syncOptions, bool isPartial = false) - : this(key, obj, JsonConvert.SerializeObject(obj), priority, syncOptions, isPartial) - { - } - - /// - /// Initializes a new instance of the class. - /// - public OfflineEntry() - { - } - - /// - /// Gets or sets the key of this entry. - /// - public string Key { get; set; } - - /// - /// Gets or sets the priority. Objects with higher priority will be synced first. Higher number indicates higher - /// priority. - /// - public int Priority { get; set; } - - /// - /// Gets or sets the timestamp when this entry was last touched. - /// - public DateTime Timestamp { get; set; } - - /// - /// Gets or sets the which define what sync state this entry is in. - /// - public SyncOptions SyncOptions { get; set; } - - /// - /// Gets or sets serialized JSON data. - /// - public string Data { get; set; } - - /// - /// Specifies whether this is only a partial object. - /// - public bool IsPartial { get; set; } - - /// - /// Deserializes into . The result is cached. - /// - /// Type of object to deserialize into. - /// Instance of . - public T Deserialize() - { - return (T) (dataInstance ?? (dataInstance = JsonConvert.DeserializeObject(Data))); - } - } -} \ No newline at end of file diff --git a/FireBase/Offline/RealtimeDatabase.cs b/FireBase/Offline/RealtimeDatabase.cs deleted file mode 100644 index 973db46..0000000 --- a/FireBase/Offline/RealtimeDatabase.cs +++ /dev/null @@ -1,479 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Net; -using System.Reactive.Disposables; -using System.Reactive.Linq; -using System.Reactive.Subjects; -using System.Reactive.Threading.Tasks; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using Firebase.Database.Extensions; -using Firebase.Database.Offline.Internals; -using Firebase.Database.Query; -using Firebase.Database.Streaming; -using Newtonsoft.Json; - -namespace Firebase.Database.Offline -{ - /// - /// The real-time Database which synchronizes online and offline data. - /// - /// Type of entities. - public class RealtimeDatabase : IDisposable where T : class - { - private readonly ChildQuery childQuery; - private readonly string elementRoot; - private readonly FirebaseCache firebaseCache; - private readonly InitialPullStrategy initialPullStrategy; - private readonly bool pushChanges; - private readonly StreamingOptions streamingOptions; - private readonly Subject> subject; - private FirebaseSubscription firebaseSubscription; - - private bool isSyncRunning; - private IObservable> observable; - - /// - /// Initializes a new instance of the class. - /// - /// The child query. - /// The element Root. - /// The offline database factory. - /// Custom string which will get appended to the file name. - /// Specifies whether changes should be streamed from the server. - /// - /// Specifies if everything should be pull from the online storage on start. It only - /// makes sense when is set to true. - /// - /// - /// Specifies whether changed items should actually be pushed to the server. If this is false, - /// then Put / Post / Delete will not affect server data. - /// - public RealtimeDatabase(ChildQuery childQuery, string elementRoot, - Func> offlineDatabaseFactory, string filenameModifier, - StreamingOptions streamingOptions, InitialPullStrategy initialPullStrategy, bool pushChanges, - ISetHandler setHandler = null) - { - this.childQuery = childQuery; - this.elementRoot = elementRoot; - this.streamingOptions = streamingOptions; - this.initialPullStrategy = initialPullStrategy; - this.pushChanges = pushChanges; - Database = offlineDatabaseFactory(typeof(T), filenameModifier); - firebaseCache = new FirebaseCache(new OfflineCacheAdapter(Database)); - subject = new Subject>(); - - PutHandler = setHandler ?? new SetHandler(); - - isSyncRunning = true; - Task.Factory.StartNew(SynchronizeThread, CancellationToken.None, TaskCreationOptions.LongRunning, - TaskScheduler.Default); - } - - /// - /// Gets the backing Database. - /// - public IDictionary Database { get; } - - public ISetHandler PutHandler { private get; set; } - - public void Dispose() - { - subject.OnCompleted(); - firebaseSubscription?.Dispose(); - } - - /// - /// Event raised whenever an exception is thrown in the synchronization thread. Exception thrown in there are - /// swallowed, so this event is the only way to get to them. - /// - public event EventHandler SyncExceptionThrown; - - /// - /// Overwrites existing object with given key. - /// - /// The key. - /// The object to set. - /// Indicates whether the item should be synced online. - /// - /// The priority. Objects with higher priority will be synced first. Higher number indicates higher - /// priority. - /// - public void Set(string key, T obj, SyncOptions syncOptions, int priority = 1) - { - SetAndRaise(key, new OfflineEntry(key, obj, priority, syncOptions)); - } - - public void Set(string key, Expression> propertyExpression, object value, - SyncOptions syncOptions, int priority = 1) - { - var fullKey = GenerateFullKey(key, propertyExpression, syncOptions); - var serializedObject = JsonConvert.SerializeObject(value).Trim('"', '\\'); - - if (fullKey.Item3) - { - if (typeof(TProperty) != typeof(string) || value == null) - // don't escape non-string primitives and null; - serializedObject = $"{{ \"{fullKey.Item2}\" : {serializedObject} }}"; - else - serializedObject = $"{{ \"{fullKey.Item2}\" : \"{serializedObject}\" }}"; - } - - var setObject = firebaseCache.PushData("/" + fullKey.Item1, serializedObject).First(); - - if (!Database.ContainsKey(key) || Database[key].SyncOptions != SyncOptions.Patch && - Database[key].SyncOptions != SyncOptions.Put) - Database[fullKey.Item1] = - new OfflineEntry(fullKey.Item1, value, serializedObject, priority, syncOptions, true); - - subject.OnNext(new FirebaseEvent(key, setObject.Object, - setObject == null ? FirebaseEventType.Delete : FirebaseEventType.InsertOrUpdate, - FirebaseEventSource.Offline)); - } - - /// - /// Fetches an object with the given key and adds it to the Database. - /// - /// The key. - /// - /// The priority. Objects with higher priority will be synced first. Higher number indicates higher - /// priority. - /// - public void Pull(string key, int priority = 1) - { - if (!Database.ContainsKey(key)) - Database[key] = new OfflineEntry(key, null, priority, SyncOptions.Pull); - else if (Database[key].SyncOptions == SyncOptions.None) - // pull only if push isn't pending - Database[key].SyncOptions = SyncOptions.Pull; - } - - /// - /// Fetches everything from the remote database. - /// - public async Task PullAsync() - { - var existingEntries = await childQuery - .OnceAsync() - .ToObservable() - .RetryAfterDelay>, FirebaseException>( - childQuery.Client.Options.SyncPeriod, - ex => ex.StatusCode == - HttpStatusCode - .OK) // OK implies the request couldn't complete due to network error. - .Select(e => ResetDatabaseFromInitial(e, false)) - .SelectMany(e => e) - .Do(e => - { - Database[e.Key] = new OfflineEntry(e.Key, e.Object, 1, SyncOptions.None); - subject.OnNext(new FirebaseEvent(e.Key, e.Object, FirebaseEventType.InsertOrUpdate, - FirebaseEventSource.OnlinePull)); - }) - .ToList(); - - // Remove items not stored online - foreach (var item in Database.Keys.Except(existingEntries.Select(f => f.Key)).ToList()) - { - Database.Remove(item); - subject.OnNext(new FirebaseEvent(item, null, FirebaseEventType.Delete, - FirebaseEventSource.OnlinePull)); - } - } - - /// - /// Retrieves all offline items currently stored in local database. - /// - public IEnumerable> Once() - { - return Database - .Where(kvp => !string.IsNullOrEmpty(kvp.Value.Data) && kvp.Value.Data != "null" && !kvp.Value.IsPartial) - .Select(kvp => new FirebaseObject(kvp.Key, kvp.Value.Deserialize())) - .ToList(); - } - - /// - /// Starts observing the real-time Database. Events will be fired both when change is done locally and remotely. - /// - /// Stream of . - public IObservable> AsObservable() - { - if (!isSyncRunning) - { - isSyncRunning = true; - Task.Factory.StartNew(SynchronizeThread, CancellationToken.None, TaskCreationOptions.LongRunning, - TaskScheduler.Default); - } - - if (observable == null) - { - var initialData = Observable.Return(FirebaseEvent.Empty(FirebaseEventSource.Offline)); - if (Database.TryGetValue(elementRoot, out var oe)) - initialData = Observable.Return(oe) - .Where(offlineEntry => - !string.IsNullOrEmpty(offlineEntry.Data) && offlineEntry.Data != "null" && - !offlineEntry.IsPartial) - .Select(offlineEntry => new FirebaseEvent(offlineEntry.Key, offlineEntry.Deserialize(), - FirebaseEventType.InsertOrUpdate, FirebaseEventSource.Offline)); - else if (Database.Count > 0) - initialData = Database - .Where(kvp => - !string.IsNullOrEmpty(kvp.Value.Data) && kvp.Value.Data != "null" && !kvp.Value.IsPartial) - .Select(kvp => new FirebaseEvent(kvp.Key, kvp.Value.Deserialize(), - FirebaseEventType.InsertOrUpdate, FirebaseEventSource.Offline)) - .ToList() - .ToObservable(); - - observable = initialData - .Merge(subject) - .Merge(GetInitialPullObservable() - .RetryAfterDelay>, FirebaseException>( - childQuery.Client.Options.SyncPeriod, - ex => ex.StatusCode == - HttpStatusCode - .OK) // OK implies the request couldn't complete due to network error. - .Select(e => ResetDatabaseFromInitial(e)) - .SelectMany(e => e) - .Do(SetObjectFromInitialPull) - .Select(e => new FirebaseEvent(e.Key, e.Object, - e.Object == null ? FirebaseEventType.Delete : FirebaseEventType.InsertOrUpdate, - FirebaseEventSource.OnlineInitial)) - .Concat(Observable.Create>(observer => - InitializeStreamingSubscription(observer)))) - .Do(next => { }, e => observable = null, () => observable = null) - .Replay() - .RefCount(); - } - - return observable; - } - - private IReadOnlyCollection> ResetDatabaseFromInitial( - IReadOnlyCollection> collection, bool onlyWhenInitialEverything = true) - { - if (onlyWhenInitialEverything && initialPullStrategy != InitialPullStrategy.Everything) return collection; - - // items which are in local db, but not in the online collection - var extra = Once() - .Select(f => f.Key) - .Except(collection.Select(c => c.Key)) - .Select(k => new FirebaseObject(k, null)); - - return collection.Concat(extra).ToList(); - } - - private void SetObjectFromInitialPull(FirebaseObject e) - { - // set object with no sync only if it doesn't exist yet - // and the InitialPullStrategy != Everything - // this attempts to deal with scenario when you are offline, have local changes and go online - // in this case having the InitialPullStrategy set to everything would basically purge all local changes - if (!Database.ContainsKey(e.Key) || Database[e.Key].SyncOptions == SyncOptions.None || - Database[e.Key].SyncOptions == SyncOptions.Pull || - initialPullStrategy != InitialPullStrategy.Everything) - Database[e.Key] = new OfflineEntry(e.Key, e.Object, 1, SyncOptions.None); - } - - private IObservable>> GetInitialPullObservable() - { - FirebaseQuery query; - switch (initialPullStrategy) - { - case InitialPullStrategy.MissingOnly: - query = childQuery.OrderByKey().StartAt(() => GetLatestKey()); - break; - case InitialPullStrategy.Everything: - query = childQuery; - break; - case InitialPullStrategy.None: - default: - return Observable.Empty>>(); - } - - if (string.IsNullOrWhiteSpace(elementRoot)) - return Observable.Defer(() => query.OnceAsync().ToObservable()); - - // there is an element root, which indicates the target location is not a collection but a single element - return Observable.Defer(async () => - Observable.Return(await query.OnceSingleAsync()) - .Select(e => new[] {new FirebaseObject(elementRoot, e)})); - } - - private IDisposable InitializeStreamingSubscription(IObserver> observer) - { - var completeDisposable = Disposable.Create(() => isSyncRunning = false); - - switch (streamingOptions) - { - case StreamingOptions.LatestOnly: - // stream since the latest key - var queryLatest = childQuery.OrderByKey().StartAt(() => GetLatestKey()); - firebaseSubscription = - new FirebaseSubscription(observer, queryLatest, elementRoot, firebaseCache); - firebaseSubscription.ExceptionThrown += StreamingExceptionThrown; - - return new CompositeDisposable(firebaseSubscription.Run(), completeDisposable); - case StreamingOptions.Everything: - // stream everything - var queryAll = childQuery; - firebaseSubscription = new FirebaseSubscription(observer, queryAll, elementRoot, firebaseCache); - firebaseSubscription.ExceptionThrown += StreamingExceptionThrown; - - return new CompositeDisposable(firebaseSubscription.Run(), completeDisposable); - } - - return completeDisposable; - } - - private void SetAndRaise(string key, OfflineEntry obj, - FirebaseEventSource eventSource = FirebaseEventSource.Offline) - { - Database[key] = obj; - subject.OnNext(new FirebaseEvent(key, obj?.Deserialize(), - string.IsNullOrEmpty(obj?.Data) || obj?.Data == "null" - ? FirebaseEventType.Delete - : FirebaseEventType.InsertOrUpdate, eventSource)); - } - - private async void SynchronizeThread() - { - while (isSyncRunning) - { - try - { - var validEntries = Database.Where(e => e.Value != null); - await PullEntriesAsync(validEntries.Where(kvp => kvp.Value.SyncOptions == SyncOptions.Pull)); - - if (pushChanges) - await PushEntriesAsync(validEntries.Where(kvp => - kvp.Value.SyncOptions == SyncOptions.Put || kvp.Value.SyncOptions == SyncOptions.Patch)); - } - catch (Exception ex) - { - SyncExceptionThrown?.Invoke(this, new ExceptionEventArgs(ex)); - } - - await Task.Delay(childQuery.Client.Options.SyncPeriod); - } - } - - private string GetLatestKey() - { - var key = Database.OrderBy(o => o.Key, StringComparer.Ordinal).LastOrDefault().Key ?? string.Empty; - - if (!string.IsNullOrWhiteSpace(key)) - key = key.Substring(0, key.Length - 1) + (char) (key[key.Length - 1] + 1); - - return key; - } - - private async Task PushEntriesAsync(IEnumerable> pushEntries) - { - var groups = pushEntries.GroupBy(pair => pair.Value.Priority).OrderByDescending(kvp => kvp.Key).ToList(); - - foreach (var group in groups) - { - var tasks = group.OrderBy(kvp => kvp.Value.IsPartial).Select(kvp => - kvp.Value.IsPartial - ? ResetSyncAfterPush(PutHandler.SetAsync(childQuery, kvp.Key, kvp.Value), kvp.Key) - : ResetSyncAfterPush(PutHandler.SetAsync(childQuery, kvp.Key, kvp.Value), kvp.Key, - kvp.Value.Deserialize())); - - try - { - await Task.WhenAll(tasks).WithAggregateException(); - } - catch (Exception ex) - { - SyncExceptionThrown?.Invoke(this, new ExceptionEventArgs(ex)); - } - } - } - - private async Task PullEntriesAsync(IEnumerable> pullEntries) - { - var taskGroups = pullEntries.GroupBy(pair => pair.Value.Priority).OrderByDescending(kvp => kvp.Key); - - foreach (var group in taskGroups) - { - var tasks = group.Select(pair => - ResetAfterPull( - childQuery.Child(pair.Key == elementRoot ? string.Empty : pair.Key).OnceSingleAsync(), - pair.Key, pair.Value)); - - try - { - await Task.WhenAll(tasks).WithAggregateException(); - } - catch (Exception ex) - { - SyncExceptionThrown?.Invoke(this, new ExceptionEventArgs(ex)); - } - } - } - - private async Task ResetAfterPull(Task task, string key, OfflineEntry entry) - { - await task; - SetAndRaise(key, new OfflineEntry(key, task.Result, entry.Priority, SyncOptions.None), - FirebaseEventSource.OnlinePull); - } - - private async Task ResetSyncAfterPush(Task task, string key, T obj) - { - await ResetSyncAfterPush(task, key); - - if (streamingOptions == StreamingOptions.None) - subject.OnNext(new FirebaseEvent(key, obj, - obj == null ? FirebaseEventType.Delete : FirebaseEventType.InsertOrUpdate, - FirebaseEventSource.OnlinePush)); - } - - private async Task ResetSyncAfterPush(Task task, string key) - { - await task; - ResetSyncOptions(key); - } - - private void ResetSyncOptions(string key) - { - var item = Database[key]; - - if (item.IsPartial) - { - Database.Remove(key); - } - else - { - item.SyncOptions = SyncOptions.None; - Database[key] = item; - } - } - - private void StreamingExceptionThrown(object sender, ExceptionEventArgs e) - { - SyncExceptionThrown?.Invoke(this, new ExceptionEventArgs(e.Exception)); - } - - private Tuple GenerateFullKey(string key, - Expression> propertyGetter, SyncOptions syncOptions) - { - var visitor = new MemberAccessVisitor(); - visitor.Visit(propertyGetter); - var propertyType = typeof(TProperty).GetTypeInfo(); - var prefix = key == string.Empty ? string.Empty : key + "/"; - - // primitive types - if (syncOptions == SyncOptions.Patch && (propertyType.IsPrimitive || - Nullable.GetUnderlyingType(typeof(TProperty)) != null || - typeof(TProperty) == typeof(string))) - return Tuple.Create(prefix + string.Join("/", visitor.PropertyNames.Skip(1).Reverse()), - visitor.PropertyNames.First(), true); - - return Tuple.Create(prefix + string.Join("/", visitor.PropertyNames.Reverse()), - visitor.PropertyNames.First(), false); - } - } -} \ No newline at end of file diff --git a/FireBase/Offline/SetHandler.cs b/FireBase/Offline/SetHandler.cs deleted file mode 100644 index 6314c3c..0000000 --- a/FireBase/Offline/SetHandler.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Threading.Tasks; -using Firebase.Database.Query; - -namespace Firebase.Database.Offline -{ - public class SetHandler : ISetHandler - { - public virtual async Task SetAsync(ChildQuery query, string key, OfflineEntry entry) - { - using (var child = query.Child(key)) - { - if (entry.SyncOptions == SyncOptions.Put) - await child.PutAsync(entry.Data); - else - await child.PatchAsync(entry.Data); - } - } - } -} \ No newline at end of file diff --git a/FireBase/Offline/StreamingOptions.cs b/FireBase/Offline/StreamingOptions.cs deleted file mode 100644 index a420cbb..0000000 --- a/FireBase/Offline/StreamingOptions.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Firebase.Database.Offline -{ - public enum StreamingOptions - { - /// - /// No realtime streaming. - /// - None, - - /// - /// Streaming of only new items - not the existing ones. - /// - LatestOnly, - - /// - /// Streaming of all items. This will also pull all existing items on start, so be mindful about the number of items in - /// your DB. - /// When used, consider not setting the to - /// because you would pointlessly pull everything twice. - /// - Everything - } -} \ No newline at end of file diff --git a/FireBase/Offline/SyncOptions.cs b/FireBase/Offline/SyncOptions.cs deleted file mode 100644 index ca68d0a..0000000 --- a/FireBase/Offline/SyncOptions.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace Firebase.Database.Offline -{ - /// - /// Specifies type of sync requested for given data. - /// - public enum SyncOptions - { - /// - /// No sync needed for given data. - /// - None, - - /// - /// Data should be pulled from firebase. - /// - Pull, - - /// - /// Data should be put to firebase. - /// - Put, - - /// - /// Data should be patched in firebase. - /// - Patch - } -} \ No newline at end of file diff --git a/FireBase/Query/AuthQuery.cs b/FireBase/Query/AuthQuery.cs deleted file mode 100644 index 2cfda3c..0000000 --- a/FireBase/Query/AuthQuery.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; - -namespace Firebase.Database.Query -{ - /// - /// Represents an auth parameter in firebase query, e.g. "?auth=xyz". - /// - public class AuthQuery : ParameterQuery - { - private readonly Func tokenFactory; - - /// - /// Initializes a new instance of the class. - /// - /// The parent. - /// The authentication token factory. - /// The owner. - public AuthQuery(FirebaseQuery parent, Func tokenFactory, FirebaseClient client) : base(parent, - () => client.Options.AsAccessToken ? "access_token" : "auth", client) - { - this.tokenFactory = tokenFactory; - } - - /// - /// Build the url parameter value of this child. - /// - /// The child of this child. - /// The . - protected override string BuildUrlParameter(FirebaseQuery child) - { - return tokenFactory(); - } - } -} \ No newline at end of file diff --git a/FireBase/Query/ChildQuery.cs b/FireBase/Query/ChildQuery.cs deleted file mode 100644 index 014fe09..0000000 --- a/FireBase/Query/ChildQuery.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; - -namespace Firebase.Database.Query -{ - /// - /// Firebase query which references the child of current node. - /// - public class ChildQuery : FirebaseQuery - { - private readonly Func pathFactory; - - /// - /// Initializes a new instance of the class. - /// - /// The parent. - /// The path to the child node. - /// The owner. - public ChildQuery(FirebaseQuery parent, Func pathFactory, FirebaseClient client) - : base(parent, client) - { - this.pathFactory = pathFactory; - } - - /// - /// Initializes a new instance of the class. - /// - /// The client. - /// The path to the child node. - public ChildQuery(FirebaseClient client, Func pathFactory) - : this(null, pathFactory, client) - { - } - - /// - /// Build the url segment of this child. - /// - /// The child of this child. - /// The . - protected override string BuildUrlSegment(FirebaseQuery child) - { - var s = pathFactory(); - - if (s != string.Empty && !s.EndsWith("/")) s += '/'; - - if (!(child is ChildQuery)) return s + ".json"; - - return s; - } - } -} \ No newline at end of file diff --git a/FireBase/Query/FilterQuery.cs b/FireBase/Query/FilterQuery.cs deleted file mode 100644 index 3434d1d..0000000 --- a/FireBase/Query/FilterQuery.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Globalization; - -namespace Firebase.Database.Query -{ - /// - /// Represents a firebase filtering query, e.g. "?LimitToLast=10". - /// - public class FilterQuery : ParameterQuery - { - private readonly Func boolValueFactory; - private readonly Func doubleValueFactory; - private readonly Func valueFactory; - - /// - /// Initializes a new instance of the class. - /// - /// The parent. - /// The filter. - /// The value for filter. - /// The owning client. - public FilterQuery(FirebaseQuery parent, Func filterFactory, Func valueFactory, - FirebaseClient client) - : base(parent, filterFactory, client) - { - this.valueFactory = valueFactory; - } - - /// - /// Initializes a new instance of the class. - /// - /// The parent. - /// The filter. - /// The value for filter. - /// The owning client. - public FilterQuery(FirebaseQuery parent, Func filterFactory, Func valueFactory, - FirebaseClient client) - : base(parent, filterFactory, client) - { - doubleValueFactory = valueFactory; - } - - /// - /// Initializes a new instance of the class. - /// - /// The parent. - /// The filter. - /// The value for filter. - /// The owning client. - public FilterQuery(FirebaseQuery parent, Func filterFactory, Func valueFactory, - FirebaseClient client) - : base(parent, filterFactory, client) - { - boolValueFactory = valueFactory; - } - - /// - /// The build url parameter. - /// - /// The child. - /// Url parameter part of the resulting path. - protected override string BuildUrlParameter(FirebaseQuery child) - { - if (valueFactory != null) - { - if (valueFactory() == null) return "null"; - return $"\"{valueFactory()}\""; - } - - if (doubleValueFactory != null) - return doubleValueFactory().ToString(CultureInfo.InvariantCulture); - if (boolValueFactory != null) return $"{boolValueFactory().ToString().ToLower()}"; - - return string.Empty; - } - } -} \ No newline at end of file diff --git a/FireBase/Query/FirebaseQuery.cs b/FireBase/Query/FirebaseQuery.cs deleted file mode 100644 index 60d0289..0000000 --- a/FireBase/Query/FirebaseQuery.cs +++ /dev/null @@ -1,314 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Net.Http; -using System.Reactive.Linq; -using System.Threading.Tasks; -using Firebase.Database.Http; -using Firebase.Database.Streaming; -using Newtonsoft.Json; - -namespace Firebase.Database.Query -{ - /// - /// Represents a firebase query. - /// - public abstract class FirebaseQuery : IFirebaseQuery, IDisposable - { - protected readonly FirebaseQuery Parent; - - private HttpClient client; - protected TimeSpan DEFAULT_HTTP_CLIENT_TIMEOUT = new TimeSpan(0, 0, 180); - - /// - /// Initializes a new instance of the class. - /// - /// The parent of this query. - /// The owning client. - protected FirebaseQuery(FirebaseQuery parent, FirebaseClient client) - { - Client = client; - Parent = parent; - } - - /// - /// Disposes this instance. - /// - public void Dispose() - { - client?.Dispose(); - } - - /// - /// Gets the client. - /// - public FirebaseClient Client { get; } - - /// - /// Queries the firebase server once returning collection of items. - /// - /// Optional timeout value. - /// Type of elements. - /// Collection of holding the entities returned by server. - public async Task>> OnceAsync(TimeSpan? timeout = null) - { - var url = string.Empty; - - try - { - url = await BuildUrlAsync().ConfigureAwait(false); - } - catch (Exception ex) - { - throw new FirebaseException("Couldn't build the url", string.Empty, string.Empty, HttpStatusCode.OK, - ex); - } - - return await GetClient(timeout).GetObjectCollectionAsync(url, Client.Options.JsonSerializerSettings) - .ConfigureAwait(false); - } - - /// - /// Starts observing this query watching for changes real time sent by the server. - /// - /// Type of elements. - /// Optional custom root element of received json items. - /// Observable stream of . - public IObservable> AsObservable( - EventHandler> exceptionHandler = null, string elementRoot = "") - { - return Observable.Create>(observer => - { - var sub = new FirebaseSubscription(observer, this, elementRoot, new FirebaseCache()); - sub.ExceptionThrown += exceptionHandler; - return sub.Run(); - }); - } - - /// - /// Builds the actual URL of this query. - /// - /// The . - public async Task BuildUrlAsync() - { - // if token factory is present on the parent then use it to generate auth token - if (Client.Options.AuthTokenAsyncFactory != null) - { - var token = await Client.Options.AuthTokenAsyncFactory().ConfigureAwait(false); - return this.WithAuth(token).BuildUrl(null); - } - - return BuildUrl(null); - } - - /*public async Task>> OnceAsync(Type dataType, TimeSpan? timeout = null) - { - var url = string.Empty; - - try - { - url = await this.BuildUrlAsync().ConfigureAwait(false); - } - catch (Exception ex) - { - throw new FirebaseException("Couldn't build the url", string.Empty, string.Empty, HttpStatusCode.OK, ex); - } - - return await this.GetClient(timeout).GetObjectCollectionAsync(url, Client.Options.JsonSerializerSettings, dataType) - .ConfigureAwait(false); - }*/ - - /// - /// Assumes given query is pointing to a single object of type and retrieves it. - /// - /// Optional timeout value. - /// Type of elements. - /// Single object of type . - public async Task OnceSingleAsync(TimeSpan? timeout = null) - { - var responseData = string.Empty; - var statusCode = HttpStatusCode.OK; - var url = string.Empty; - - try - { - url = await BuildUrlAsync().ConfigureAwait(false); - } - catch (Exception ex) - { - throw new FirebaseException("Couldn't build the url", string.Empty, responseData, statusCode, ex); - } - - try - { - var response = await GetClient(timeout).GetAsync(url).ConfigureAwait(false); - statusCode = response.StatusCode; - responseData = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - response.EnsureSuccessStatusCode(); - response.Dispose(); - - return JsonConvert.DeserializeObject(responseData, Client.Options.JsonSerializerSettings); - } - catch (Exception ex) - { - throw new FirebaseException(url, string.Empty, responseData, statusCode, ex); - } - } - - /// - /// Posts given object to repository. - /// - /// The object. - /// Specifies whether the key should be generated offline instead of online. - /// Optional timeout value. - /// Type of - /// Resulting firebase object with populated key. - public async Task> PostAsync(string data, bool generateKeyOffline = true, - TimeSpan? timeout = null) - { - // post generates a new key server-side, while put can be used with an already generated local key - if (generateKeyOffline) - { - var key = FirebaseKeyGenerator.Next(); - await new ChildQuery(this, () => key, Client).PutAsync(data).ConfigureAwait(false); - - return new FirebaseObject(key, data); - } - - var c = GetClient(timeout); - var sendData = await SendAsync(c, data, HttpMethod.Post).ConfigureAwait(false); - var result = JsonConvert.DeserializeObject(sendData, Client.Options.JsonSerializerSettings); - - return new FirebaseObject(result.Name, data); - } - - /// - /// Patches data at given location instead of overwriting them. - /// - /// The object. - /// Optional timeout value. - /// Type of - /// The . - public async Task PatchAsync(string data, TimeSpan? timeout = null) - { - var c = GetClient(timeout); - - await this.Silent().SendAsync(c, data, new HttpMethod("PATCH")).ConfigureAwait(false); - } - - /// - /// Sets or overwrites data at given location. - /// - /// The object. - /// Optional timeout value. - /// Type of - /// The . - public async Task PutAsync(string data, TimeSpan? timeout = null) - { - var c = GetClient(timeout); - - await this.Silent().SendAsync(c, data, HttpMethod.Put).ConfigureAwait(false); - } - - /// - /// Deletes data from given location. - /// - /// Optional timeout value. - /// The . - public async Task DeleteAsync(TimeSpan? timeout = null) - { - var c = GetClient(timeout); - var url = string.Empty; - var responseData = string.Empty; - var statusCode = HttpStatusCode.OK; - - try - { - url = await BuildUrlAsync().ConfigureAwait(false); - } - catch (Exception ex) - { - throw new FirebaseException("Couldn't build the url", string.Empty, responseData, statusCode, ex); - } - - try - { - var result = await c.DeleteAsync(url).ConfigureAwait(false); - statusCode = result.StatusCode; - responseData = await result.Content.ReadAsStringAsync().ConfigureAwait(false); - - result.EnsureSuccessStatusCode(); - } - catch (Exception ex) - { - throw new FirebaseException(url, string.Empty, responseData, statusCode, ex); - } - } - - /// - /// Build the url segment of this child. - /// - /// The child of this query. - /// The . - protected abstract string BuildUrlSegment(FirebaseQuery child); - - private string BuildUrl(FirebaseQuery child) - { - var url = BuildUrlSegment(child); - - if (Parent != null) url = Parent.BuildUrl(this) + url; - - return url; - } - - private HttpClient GetClient(TimeSpan? timeout = null) - { - if (client == null) client = new HttpClient(); - - if (!timeout.HasValue) - client.Timeout = DEFAULT_HTTP_CLIENT_TIMEOUT; - else - client.Timeout = timeout.Value; - - return client; - } - - private async Task SendAsync(HttpClient client, string data, HttpMethod method) - { - var responseData = string.Empty; - var statusCode = HttpStatusCode.OK; - var requestData = data; - var url = string.Empty; - - try - { - url = await BuildUrlAsync().ConfigureAwait(false); - } - catch (Exception ex) - { - throw new FirebaseException("Couldn't build the url", requestData, responseData, statusCode, ex); - } - - var message = new HttpRequestMessage(method, url) - { - Content = new StringContent(requestData) - }; - - try - { - var result = await client.SendAsync(message).ConfigureAwait(false); - statusCode = result.StatusCode; - responseData = await result.Content.ReadAsStringAsync().ConfigureAwait(false); - - result.EnsureSuccessStatusCode(); - - return responseData; - } - catch (Exception ex) - { - throw new FirebaseException(url, requestData, responseData, statusCode, ex); - } - } - } -} \ No newline at end of file diff --git a/FireBase/Query/IFirebaseQuery.cs b/FireBase/Query/IFirebaseQuery.cs deleted file mode 100644 index 0da4b15..0000000 --- a/FireBase/Query/IFirebaseQuery.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Firebase.Database.Streaming; - -namespace Firebase.Database.Query -{ - /// - /// The FirebaseQuery interface. - /// - public interface IFirebaseQuery - { - /// - /// Gets the owning client of this query. - /// - FirebaseClient Client { get; } - - /// - /// Retrieves items which exist on the location specified by this query instance. - /// - /// Optional timeout value. - /// Type of the items. - /// Collection of . - Task>> OnceAsync(TimeSpan? timeout = null); - - /// - /// Returns current location as an observable which allows to real-time listening to events from the firebase server. - /// - /// Type of the items. - /// Cold observable of . - IObservable> AsObservable( - EventHandler> exceptionHandler, string elementRoot = ""); - - /// - /// Builds the actual url of this query. - /// - /// The . - Task BuildUrlAsync(); - } -} \ No newline at end of file diff --git a/FireBase/Query/OrderQuery.cs b/FireBase/Query/OrderQuery.cs deleted file mode 100644 index 302d1a3..0000000 --- a/FireBase/Query/OrderQuery.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; - -namespace Firebase.Database.Query -{ - /// - /// Represents a firebase ordering query, e.g. "?OrderBy=Foo". - /// - public class OrderQuery : ParameterQuery - { - private readonly Func propertyNameFactory; - - /// - /// Initializes a new instance of the class. - /// - /// The query parent. - /// The property name. - /// The owning client. - public OrderQuery(ChildQuery parent, Func propertyNameFactory, FirebaseClient client) - : base(parent, () => "orderBy", client) - { - this.propertyNameFactory = propertyNameFactory; - } - - /// - /// The build url parameter. - /// - /// The child. - /// The . - protected override string BuildUrlParameter(FirebaseQuery child) - { - return $"\"{propertyNameFactory()}\""; - } - } -} \ No newline at end of file diff --git a/FireBase/Query/ParameterQuery.cs b/FireBase/Query/ParameterQuery.cs deleted file mode 100644 index 572224c..0000000 --- a/FireBase/Query/ParameterQuery.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; - -namespace Firebase.Database.Query -{ - /// - /// Represents a parameter in firebase query, e.g. "?data=foo". - /// - public abstract class ParameterQuery : FirebaseQuery - { - private readonly Func parameterFactory; - private readonly string separator; - - /// - /// Initializes a new instance of the class. - /// - /// The parent of this query. - /// The parameter. - /// The owning client. - protected ParameterQuery(FirebaseQuery parent, Func parameterFactory, FirebaseClient client) - : base(parent, client) - { - this.parameterFactory = parameterFactory; - separator = Parent is ChildQuery ? "?" : "&"; - } - - /// - /// Build the url segment represented by this query. - /// - /// The child. - /// The . - protected override string BuildUrlSegment(FirebaseQuery child) - { - return $"{separator}{parameterFactory()}={BuildUrlParameter(child)}"; - } - - /// - /// The build url parameter. - /// - /// The child. - /// The . - protected abstract string BuildUrlParameter(FirebaseQuery child); - } -} \ No newline at end of file diff --git a/FireBase/Query/QueryExtensions.cs b/FireBase/Query/QueryExtensions.cs deleted file mode 100644 index df2edfc..0000000 --- a/FireBase/Query/QueryExtensions.cs +++ /dev/null @@ -1,210 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Newtonsoft.Json; - -namespace Firebase.Database.Query -{ - /// - /// Query extensions providing linq like syntax for firebase server methods. - /// - public static class QueryExtensions - { - /// - /// Adds an auth parameter to the query. - /// - /// The child. - /// The auth token. - /// The . - internal static AuthQuery WithAuth(this FirebaseQuery node, string token) - { - return node.WithAuth(() => token); - } - - /// - /// Appends print=silent to save bandwidth. - /// - /// The child. - /// The . - internal static SilentQuery Silent(this FirebaseQuery node) - { - return new SilentQuery(node, node.Client); - } - - /// - /// References a sub child of the existing node. - /// - /// The child. - /// The path of sub child. - /// The . - public static ChildQuery Child(this ChildQuery node, string path) - { - return node.Child(() => path); - } - - /// - /// Order data by given . Note that this is used mainly for following filtering queries and - /// due to firebase implementation - /// the data may actually not be ordered. - /// - /// The child. - /// The property name. - /// The . - public static OrderQuery OrderBy(this ChildQuery child, string propertyName) - { - return child.OrderBy(() => propertyName); - } - - /// - /// Instructs firebase to send data greater or equal to the . This must be preceded by an OrderBy - /// query. - /// - /// Current node. - /// Value to start at. - /// The . - public static FilterQuery StartAt(this ParameterQuery child, string value) - { - return child.StartAt(() => value); - } - - /// - /// Instructs firebase to send data lower or equal to the . This must be preceded by an OrderBy - /// query. - /// - /// Current node. - /// Value to start at. - /// The . - public static FilterQuery EndAt(this ParameterQuery child, string value) - { - return child.EndAt(() => value); - } - - /// - /// Instructs firebase to send data equal to the . This must be preceded by an OrderBy query. - /// - /// Current node. - /// Value to start at. - /// The . - public static FilterQuery EqualTo(this ParameterQuery child, string value) - { - return child.EqualTo(() => value); - } - - /// - /// Instructs firebase to send data greater or equal to the . This must be preceded by an OrderBy - /// query. - /// - /// Current node. - /// Value to start at. - /// The . - public static FilterQuery StartAt(this ParameterQuery child, double value) - { - return child.StartAt(() => value); - } - - /// - /// Instructs firebase to send data lower or equal to the . This must be preceded by an OrderBy - /// query. - /// - /// Current node. - /// Value to start at. - /// The . - public static FilterQuery EndAt(this ParameterQuery child, double value) - { - return child.EndAt(() => value); - } - - /// - /// Instructs firebase to send data equal to the . This must be preceded by an OrderBy query. - /// - /// Current node. - /// Value to start at. - /// The . - public static FilterQuery EqualTo(this ParameterQuery child, double value) - { - return child.EqualTo(() => value); - } - - /// - /// Instructs firebase to send data equal to the . This must be preceded by an OrderBy query. - /// - /// Current node. - /// Value to start at. - /// The . - public static FilterQuery EqualTo(this ParameterQuery child, bool value) - { - return child.EqualTo(() => value); - } - - /// - /// Instructs firebase to send data equal to null. This must be preceded by an OrderBy query. - /// - /// Current node. - /// The . - public static FilterQuery EqualTo(this ParameterQuery child) - { - return child.EqualTo(() => null); - } - - /// - /// Limits the result to first items. - /// - /// Current node. - /// Number of elements. - /// The . - public static FilterQuery LimitToFirst(this ParameterQuery child, int count) - { - return child.LimitToFirst(() => count); - } - - /// - /// Limits the result to last items. - /// - /// Current node. - /// Number of elements. - /// The . - public static FilterQuery LimitToLast(this ParameterQuery child, int count) - { - return child.LimitToLast(() => count); - } - - public static Task PutAsync(this FirebaseQuery query, T obj) - { - return query.PutAsync(JsonConvert.SerializeObject(obj, query.Client.Options.JsonSerializerSettings)); - } - - public static Task PatchAsync(this FirebaseQuery query, T obj) - { - return query.PatchAsync(JsonConvert.SerializeObject(obj, query.Client.Options.JsonSerializerSettings)); - } - - public static async Task> PostAsync(this FirebaseQuery query, T obj, - bool generateKeyOffline = true) - { - var result = - await query.PostAsync(JsonConvert.SerializeObject(obj, query.Client.Options.JsonSerializerSettings), - generateKeyOffline); - - return new FirebaseObject(result.Key, obj); - } - - /// - /// Fan out given item to multiple locations at once. See - /// https://firebase.googleblog.com/2015/10/client-side-fan-out-for-data-consistency_73.html for details. - /// - /// Type of object to fan out. - /// Current node. - /// Object to fan out. - /// Locations where to store the item. - public static async Task FanOut(this ChildQuery child, T item, params string[] relativePaths) - { - if (relativePaths == null) throw new ArgumentNullException(nameof(relativePaths)); - - var fanoutObject = new Dictionary(relativePaths.Length); - - foreach (var path in relativePaths) fanoutObject.Add(path, item); - - await child.PatchAsync(fanoutObject); - } - } -} \ No newline at end of file diff --git a/FireBase/Query/QueryFactoryExtensions.cs b/FireBase/Query/QueryFactoryExtensions.cs deleted file mode 100644 index 71dae5c..0000000 --- a/FireBase/Query/QueryFactoryExtensions.cs +++ /dev/null @@ -1,187 +0,0 @@ -using System; - -namespace Firebase.Database.Query -{ - /// - /// Query extensions providing linq like syntax for firebase server methods. - /// - public static class QueryFactoryExtensions - { - /// - /// Adds an auth parameter to the query. - /// - /// The child. - /// The auth token. - /// The . - internal static AuthQuery WithAuth(this FirebaseQuery node, Func tokenFactory) - { - return new AuthQuery(node, tokenFactory, node.Client); - } - - /// - /// References a sub child of the existing node. - /// - /// The child. - /// The path of sub child. - /// The . - public static ChildQuery Child(this ChildQuery node, Func pathFactory) - { - return new ChildQuery(node, pathFactory, node.Client); - } - - /// - /// Order data by given . Note that this is used mainly for following filtering - /// queries and due to firebase implementation - /// the data may actually not be ordered. - /// - /// The child. - /// The property name. - /// The . - public static OrderQuery OrderBy(this ChildQuery child, Func propertyNameFactory) - { - return new OrderQuery(child, propertyNameFactory, child.Client); - } - - /// - /// Order data by $key. Note that this is used mainly for following filtering queries and due to firebase - /// implementation - /// the data may actually not be ordered. - /// - /// The child. - /// The . - public static OrderQuery OrderByKey(this ChildQuery child) - { - return child.OrderBy("$key"); - } - - /// - /// Order data by $value. Note that this is used mainly for following filtering queries and due to firebase - /// implementation - /// the data may actually not be ordered. - /// - /// The child. - /// The . - public static OrderQuery OrderByValue(this ChildQuery child) - { - return child.OrderBy("$value"); - } - - /// - /// Order data by $priority. Note that this is used mainly for following filtering queries and due to firebase - /// implementation - /// the data may actually not be ordered. - /// - /// The child. - /// The . - public static OrderQuery OrderByPriority(this ChildQuery child) - { - return child.OrderBy("$priority"); - } - - /// - /// Instructs firebase to send data greater or equal to the . This must be preceded by an - /// OrderBy query. - /// - /// Current node. - /// Value to start at. - /// The . - public static FilterQuery StartAt(this ParameterQuery child, Func valueFactory) - { - return new FilterQuery(child, () => "startAt", valueFactory, child.Client); - } - - /// - /// Instructs firebase to send data lower or equal to the . This must be preceded by an - /// OrderBy query. - /// - /// Current node. - /// Value to start at. - /// The . - public static FilterQuery EndAt(this ParameterQuery child, Func valueFactory) - { - return new FilterQuery(child, () => "endAt", valueFactory, child.Client); - } - - /// - /// Instructs firebase to send data equal to the . This must be preceded by an OrderBy - /// query. - /// - /// Current node. - /// Value to start at. - /// The . - public static FilterQuery EqualTo(this ParameterQuery child, Func valueFactory) - { - return new FilterQuery(child, () => "equalTo", valueFactory, child.Client); - } - - /// - /// Instructs firebase to send data greater or equal to the . This must be preceded by an - /// OrderBy query. - /// - /// Current node. - /// Value to start at. - /// The . - public static FilterQuery StartAt(this ParameterQuery child, Func valueFactory) - { - return new FilterQuery(child, () => "startAt", valueFactory, child.Client); - } - - /// - /// Instructs firebase to send data lower or equal to the . This must be preceded by an - /// OrderBy query. - /// - /// Current node. - /// Value to start at. - /// The . - public static FilterQuery EndAt(this ParameterQuery child, Func valueFactory) - { - return new FilterQuery(child, () => "endAt", valueFactory, child.Client); - } - - /// - /// Instructs firebase to send data equal to the . This must be preceded by an OrderBy - /// query. - /// - /// Current node. - /// Value to start at. - /// The . - public static FilterQuery EqualTo(this ParameterQuery child, Func valueFactory) - { - return new FilterQuery(child, () => "equalTo", valueFactory, child.Client); - } - - /// - /// Instructs firebase to send data equal to the . This must be preceded by an OrderBy - /// query. - /// - /// Current node. - /// Value to start at. - /// The . - public static FilterQuery EqualTo(this ParameterQuery child, Func valueFactory) - { - return new FilterQuery(child, () => "equalTo", valueFactory, child.Client); - } - - /// - /// Limits the result to first items. - /// - /// Current node. - /// Number of elements. - /// The . - public static FilterQuery LimitToFirst(this ParameterQuery child, Func countFactory) - { - return new FilterQuery(child, () => "limitToFirst", () => countFactory(), child.Client); - } - - /// - /// Limits the result to last items. - /// - /// Current node. - /// Number of elements. - /// The . - public static FilterQuery LimitToLast(this ParameterQuery child, Func countFactory) - { - return new FilterQuery(child, () => "limitToLast", () => countFactory(), child.Client); - } - } -} \ No newline at end of file diff --git a/FireBase/Query/SilentQuery.cs b/FireBase/Query/SilentQuery.cs deleted file mode 100644 index d09d38b..0000000 --- a/FireBase/Query/SilentQuery.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Firebase.Database.Query -{ - /// - /// Appends print=silent to the url. - /// - public class SilentQuery : ParameterQuery - { - public SilentQuery(FirebaseQuery parent, FirebaseClient client) - : base(parent, () => "print", client) - { - } - - protected override string BuildUrlParameter(FirebaseQuery child) - { - return "silent"; - } - } -} \ No newline at end of file diff --git a/FireBase/Settings.StyleCop b/FireBase/Settings.StyleCop deleted file mode 100644 index 833aa39..0000000 --- a/FireBase/Settings.StyleCop +++ /dev/null @@ -1,77 +0,0 @@ - - - - auth - firebase - json - linq - oauth - - - - - - - - False - - - - - False - - - - - False - - - - - False - - - - - False - - - - - False - - - - - False - - - - - True - - - - - True - - - - - True - True - False - - - - - - - True - - - - - - - \ No newline at end of file diff --git a/FireBase/Streaming/FirebaseCache.cs b/FireBase/Streaming/FirebaseCache.cs deleted file mode 100644 index 66241e0..0000000 --- a/FireBase/Streaming/FirebaseCache.cs +++ /dev/null @@ -1,181 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Firebase.Database.Http; -using Newtonsoft.Json; - -namespace Firebase.Database.Streaming -{ - /// - /// The firebase cache. - /// - /// Type of top-level entities in the cache. - public class FirebaseCache : IEnumerable> - { - private readonly IDictionary dictionary; - private readonly bool isDictionaryType; - - private readonly JsonSerializerSettings serializerSettings = new JsonSerializerSettings - { - ObjectCreationHandling = ObjectCreationHandling.Replace - }; - - /// - /// Initializes a new instance of the class. - /// - public FirebaseCache() - : this(new Dictionary()) - { - } - - /// - /// Initializes a new instance of the class and populates it with existing data. - /// - /// The existing items. - public FirebaseCache(IDictionary existingItems) - { - dictionary = existingItems; - isDictionaryType = typeof(IDictionary).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo()); - } - - /// - /// The push data. - /// - /// The path of incoming data, separated by slash. - /// The data in json format as returned by firebase. - /// Collection of top-level entities which were affected by the push. - public IEnumerable> PushData(string path, string data, bool removeEmptyEntries = true) - { - object obj = this.dictionary; - Action primitiveObjSetter = null; - Action objDeleter = null; - - var pathElements = path.Split(new[] {"/"}, - removeEmptyEntries ? StringSplitOptions.RemoveEmptyEntries : StringSplitOptions.None); - - // first find where we should insert the data to - foreach (var element in pathElements) - if (obj is IDictionary) - { - // if it's a dictionary, then it's just a matter of inserting into it / accessing existing object by key - var dictionary = obj as IDictionary; - var valueType = obj.GetType().GenericTypeArguments[1]; - - primitiveObjSetter = d => dictionary[element] = d; - objDeleter = () => dictionary.Remove(element); - - if (dictionary.Contains(element)) - { - obj = dictionary[element]; - } - else - { - dictionary[element] = CreateInstance(valueType); - obj = dictionary[element]; - } - } - else - { - // if it's not a dictionary, try to find the property of current object with the matching name - var objParent = obj; - var property = objParent - .GetType() - .GetRuntimeProperties() - .First(p => p.Name.Equals(element, StringComparison.OrdinalIgnoreCase) || - element == p.GetCustomAttribute()?.PropertyName); - - objDeleter = () => property.SetValue(objParent, null); - primitiveObjSetter = d => property.SetValue(objParent, d); - obj = property.GetValue(obj); - if (obj == null) - { - obj = CreateInstance(property.PropertyType); - property.SetValue(objParent, obj); - } - } - - // if data is null (=empty string) delete it - if (string.IsNullOrWhiteSpace(data) || data == "null") - { - var key = pathElements[0]; - var target = dictionary[key]; - - objDeleter(); - - yield return new FirebaseObject(key, target); - yield break; - } - - // now insert the data - if (obj is IDictionary && !isDictionaryType) - { - // insert data into dictionary and return it as a collection of FirebaseObject - var dictionary = obj as IDictionary; - var valueType = obj.GetType().GenericTypeArguments[1]; - var objectCollection = data.GetObjectCollection(valueType); - - foreach (var item in objectCollection) - { - dictionary[item.Key] = item.Object; - - // top level dictionary changed - if (!pathElements.Any()) yield return new FirebaseObject(item.Key, (T) item.Object); - } - - // nested dictionary changed - if (pathElements.Any()) - { - this.dictionary[pathElements[0]] = this.dictionary[pathElements[0]]; - yield return new FirebaseObject(pathElements[0], this.dictionary[pathElements[0]]); - } - } - else - { - // set the data on a property of the given object - var valueType = obj.GetType(); - - // firebase sends strings without double quotes - var targetObject = valueType == typeof(string) - ? data - : JsonConvert.DeserializeObject(data, valueType); - - if ((valueType.GetTypeInfo().IsPrimitive || valueType == typeof(string)) && primitiveObjSetter != null) - // handle primitive (value) types separately - primitiveObjSetter(targetObject); - else - JsonConvert.PopulateObject(data, obj, serializerSettings); - - dictionary[pathElements[0]] = dictionary[pathElements[0]]; - yield return new FirebaseObject(pathElements[0], dictionary[pathElements[0]]); - } - } - - public bool Contains(string key) - { - return dictionary.Keys.Contains(key); - } - - private object CreateInstance(Type type) - { - if (type == typeof(string)) - return string.Empty; - return Activator.CreateInstance(type); - } - - #region IEnumerable - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public IEnumerator> GetEnumerator() - { - return dictionary.Select(p => new FirebaseObject(p.Key, p.Value)).GetEnumerator(); - } - - #endregion - } -} \ No newline at end of file diff --git a/FireBase/Streaming/FirebaseEvent.cs b/FireBase/Streaming/FirebaseEvent.cs deleted file mode 100644 index 1761a72..0000000 --- a/FireBase/Streaming/FirebaseEvent.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace Firebase.Database.Streaming -{ - /// - /// Firebase event which hold and the object affected by the event. - /// - /// Type of object affected by the event. - public class FirebaseEvent : FirebaseObject - { - /// - /// Initializes a new instance of the class. - /// - /// The key of the object. - /// The object. - /// The event type. - public FirebaseEvent(string key, T obj, FirebaseEventType eventType, FirebaseEventSource eventSource) - : base(key, obj) - { - EventType = eventType; - EventSource = eventSource; - } - - /// - /// Gets the source of the event. - /// - public FirebaseEventSource EventSource { get; } - - /// - /// Gets the event type. - /// - public FirebaseEventType EventType { get; } - - public static FirebaseEvent Empty(FirebaseEventSource source) - { - return new FirebaseEvent(string.Empty, default(T), FirebaseEventType.InsertOrUpdate, source); - } - } -} \ No newline at end of file diff --git a/FireBase/Streaming/FirebaseEventSource.cs b/FireBase/Streaming/FirebaseEventSource.cs deleted file mode 100644 index b1385ca..0000000 --- a/FireBase/Streaming/FirebaseEventSource.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace Firebase.Database.Streaming -{ - /// - /// Specifies the origin of given - /// - public enum FirebaseEventSource - { - /// - /// Event comes from an offline source. - /// - Offline, - - /// - /// Event comes from online source fetched during initial pull (valid only for RealtimeDatabase). - /// - OnlineInitial, - - /// - /// Event comes from online source received thru active stream. - /// - OnlineStream, - - /// - /// Event comes from online source being fetched manually. - /// - OnlinePull, - - /// - /// Event raised after successful online push (valid only for RealtimeDatabase which isn't streaming). - /// - OnlinePush, - - /// - /// Event comes from an online source. - /// - Online = OnlineInitial | OnlinePull | OnlinePush | OnlineStream - } -} \ No newline at end of file diff --git a/FireBase/Streaming/FirebaseEventType.cs b/FireBase/Streaming/FirebaseEventType.cs deleted file mode 100644 index 7606331..0000000 --- a/FireBase/Streaming/FirebaseEventType.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Firebase.Database.Streaming -{ - /// - /// The type of event. - /// - public enum FirebaseEventType - { - /// - /// Item was inserted or updated. - /// - InsertOrUpdate, - - /// - /// Item was deleted. - /// - Delete - } -} \ No newline at end of file diff --git a/FireBase/Streaming/FirebaseServerEventType.cs b/FireBase/Streaming/FirebaseServerEventType.cs deleted file mode 100644 index 79c816d..0000000 --- a/FireBase/Streaming/FirebaseServerEventType.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Firebase.Database.Streaming -{ - internal enum FirebaseServerEventType - { - Put, - - Patch, - - KeepAlive, - - Cancel, - - AuthRevoked - } -} \ No newline at end of file diff --git a/FireBase/Streaming/FirebaseSubscription.cs b/FireBase/Streaming/FirebaseSubscription.cs deleted file mode 100644 index fb0f403..0000000 --- a/FireBase/Streaming/FirebaseSubscription.cs +++ /dev/null @@ -1,217 +0,0 @@ -using System; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading; -using System.Threading.Tasks; -using Firebase.Database.Query; -using Newtonsoft.Json.Linq; - -namespace Firebase.Database.Streaming -{ - /// - /// The firebase subscription. - /// - /// Type of object to be streaming back to the called. - internal class FirebaseSubscription : IDisposable - { - private static readonly HttpClient http; - private readonly FirebaseCache cache; - private readonly CancellationTokenSource cancel; - private readonly FirebaseClient client; - private readonly string elementRoot; - private readonly IObserver> observer; - private readonly IFirebaseQuery query; - - static FirebaseSubscription() - { - var handler = new HttpClientHandler - { - AllowAutoRedirect = true, - MaxAutomaticRedirections = 10, - CookieContainer = new CookieContainer() - }; - - var httpClient = new HttpClient(handler, true); - - httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/event-stream")); - - http = httpClient; - } - - /// - /// Initializes a new instance of the class. - /// - /// The observer. - /// The query. - /// The cache. - public FirebaseSubscription(IObserver> observer, IFirebaseQuery query, string elementRoot, - FirebaseCache cache) - { - this.observer = observer; - this.query = query; - this.elementRoot = elementRoot; - cancel = new CancellationTokenSource(); - this.cache = cache; - client = query.Client; - } - - public void Dispose() - { - cancel.Cancel(); - } - - public event EventHandler> ExceptionThrown; - - public IDisposable Run() - { - Task.Run(() => ReceiveThread()); - - return this; - } - - private async void ReceiveThread() - { - while (true) - { - var url = string.Empty; - var line = string.Empty; - var statusCode = HttpStatusCode.OK; - - try - { - cancel.Token.ThrowIfCancellationRequested(); - - // initialize network connection - url = await query.BuildUrlAsync().ConfigureAwait(false); - var request = new HttpRequestMessage(HttpMethod.Get, url); - var serverEvent = FirebaseServerEventType.KeepAlive; - - var client = GetHttpClient(); - var response = await client - .SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancel.Token) - .ConfigureAwait(false); - - statusCode = response.StatusCode; - response.EnsureSuccessStatusCode(); - - using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) - using (var reader = this.client.Options.SubscriptionStreamReaderFactory(stream)) - { - while (true) - { - cancel.Token.ThrowIfCancellationRequested(); - - line = reader.ReadLine()?.Trim(); - - if (string.IsNullOrWhiteSpace(line)) continue; - - var tuple = line.Split(new[] {':'}, 2, StringSplitOptions.RemoveEmptyEntries) - .Select(s => s.Trim()).ToArray(); - - switch (tuple[0].ToLower()) - { - case "event": - serverEvent = ParseServerEvent(serverEvent, tuple[1]); - break; - case "data": - ProcessServerData(url, serverEvent, tuple[1]); - break; - } - - if (serverEvent == FirebaseServerEventType.AuthRevoked) - // auth token no longer valid, reconnect - break; - } - } - } - catch (OperationCanceledException) - { - break; - } - catch (Exception ex) when (statusCode != HttpStatusCode.OK) - { - observer.OnError(new FirebaseException(url, string.Empty, line, statusCode, ex)); - Dispose(); - break; - } - catch (Exception ex) - { - ExceptionThrown?.Invoke(this, - new ExceptionEventArgs(new FirebaseException(url, string.Empty, line, - statusCode, ex))); - - await Task.Delay(2000).ConfigureAwait(false); - } - } - } - - private FirebaseServerEventType ParseServerEvent(FirebaseServerEventType serverEvent, string eventName) - { - switch (eventName) - { - case "put": - serverEvent = FirebaseServerEventType.Put; - break; - case "patch": - serverEvent = FirebaseServerEventType.Patch; - break; - case "keep-alive": - serverEvent = FirebaseServerEventType.KeepAlive; - break; - case "cancel": - serverEvent = FirebaseServerEventType.Cancel; - break; - case "auth_revoked": - serverEvent = FirebaseServerEventType.AuthRevoked; - break; - } - - return serverEvent; - } - - private void ProcessServerData(string url, FirebaseServerEventType serverEvent, string serverData) - { - switch (serverEvent) - { - case FirebaseServerEventType.Put: - case FirebaseServerEventType.Patch: - var result = JObject.Parse(serverData); - var path = result["path"].ToString(); - var data = result["data"].ToString(); - - // If an elementRoot parameter is provided, but it's not in the cache, it was already deleted. So we can return an empty object. - if (string.IsNullOrWhiteSpace(elementRoot) || !cache.Contains(elementRoot)) - if (path == "/" && data == string.Empty) - { - observer.OnNext(FirebaseEvent.Empty(FirebaseEventSource.OnlineStream)); - return; - } - - var eventType = string.IsNullOrWhiteSpace(data) - ? FirebaseEventType.Delete - : FirebaseEventType.InsertOrUpdate; - - var items = cache.PushData(elementRoot + path, data); - - foreach (var i in items.ToList()) - observer.OnNext(new FirebaseEvent(i.Key, i.Object, eventType, - FirebaseEventSource.OnlineStream)); - - break; - case FirebaseServerEventType.KeepAlive: - break; - case FirebaseServerEventType.Cancel: - observer.OnError(new FirebaseException(url, string.Empty, serverData, HttpStatusCode.Unauthorized)); - Dispose(); - break; - } - } - - private HttpClient GetHttpClient() - { - return http; - } - } -} \ No newline at end of file diff --git a/FireBase/Streaming/NonBlockingStreamReader.cs b/FireBase/Streaming/NonBlockingStreamReader.cs deleted file mode 100644 index 8228e32..0000000 --- a/FireBase/Streaming/NonBlockingStreamReader.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.IO; -using System.Text; - -namespace Firebase.Database.Streaming -{ - /// - /// When a regular is used in a UWP app its method - /// tends to take a long - /// time for data larger then 2 KB. This extremly simple implementation of can be used - /// instead to boost performance - /// in your UWP app. Use to inject an instance of this class into your - /// . - /// - public class NonBlockingStreamReader : TextReader - { - private const int DefaultBufferSize = 16000; - private readonly byte[] buffer; - private readonly int bufferSize; - - private readonly Stream stream; - - private string cachedData; - - public NonBlockingStreamReader(Stream stream, int bufferSize = DefaultBufferSize) - { - this.stream = stream; - this.bufferSize = bufferSize; - buffer = new byte[bufferSize]; - - cachedData = string.Empty; - } - - public override string ReadLine() - { - var currentString = TryGetNewLine(); - - while (currentString == null) - { - var read = stream.Read(buffer, 0, bufferSize); - var str = Encoding.UTF8.GetString(buffer, 0, read); - - cachedData += str; - currentString = TryGetNewLine(); - } - - return currentString; - } - - private string TryGetNewLine() - { - var newLine = cachedData.IndexOf('\n'); - - if (newLine >= 0) - { - var r = cachedData.Substring(0, newLine + 1); - cachedData = cachedData.Remove(0, r.Length); - return r.Trim(); - } - - return null; - } - } -} \ No newline at end of file -- cgit v1.2.3-54-g00ecf