using System; using System.Collections.Generic; using Cysharp.Threading.Tasks; using Google.Protobuf; using Google.Protobuf.Reflection; using UnityEngine.Assertions; namespace Ubisoft.Hotel.Cache { /// /// Cache driver that works with Protobuf messages. Converts IMessage types to json and viceversa /// /// The data type managed by the cache driver. It must implement Google.Protobuf.IMessage. public class GenericProtobufCacheDriver : AbstractCacheDriver where T : IMessage, new() { public string Filepath { get; private set; } private MessageParser Parser { get; set; } //private MessageParser Parser { get; set; } private JsonFormatter Formatter { get; set; } // TODO Consumers may need to add more message descriptors public static async UniTask> CreateAsync(string rootFolder, string filePath, CacheSettings settings)//, MessageParser parser) { Assert.IsFalse(string.IsNullOrEmpty(rootFolder)); GenericProtobufCacheDriver driver = new GenericProtobufCacheDriver(); driver.RootFolder = rootFolder; driver.Filepath = filePath; // Instantiate T so that we can access its static members var t = new T(); // Get a reference to MessageParser for Protobuf message deserialization //driver.Parser = parser; driver.Parser = (MessageParser)t.Descriptor.Parser; //driver.Parser = new T().Descriptor.Parser; // Initialize json formatter for Protobuf message serialization //List descriptors = new List() { ContentServiceReflection.Descriptor }; //TypeRegistry typeRegistry = TypeRegistry.FromFiles(descriptors); TypeRegistry typeRegistry = TypeRegistry.FromMessages(t.Descriptor); driver.Formatter = new JsonFormatter(new JsonFormatter.Settings(true, typeRegistry)); // Initialize the driver await driver.InitAsync(settings); return driver; } private GenericProtobufCacheDriver() { // We can't enforce T to be a nullable type using a generic constraint (such constraint doesn't exist). So instead we do the following JIT compile-time check if (default(T) != null) { throw new InvalidOperationException("GenericProtobufCacheDriver requires T to be a nullable type"); } } public async UniTask GetDataAsync(string filter = "") { string json = await CacheManager.GetDataAsync(GetRelativeCacheFilepath(Filepath), filter); if (!string.IsNullOrEmpty(json)) { return Parser.ParseJson(json); } return default(T); // This should always be null, since T is a nullable type } public async UniTask GetCrcAsync(string filter = "") { CacheFileMetadata metadata = await CacheManager.GetFileMetadataAsync(GetRelativeCacheFilepath(Filepath), filter); if (metadata != null) { return metadata.Crc; } return null; } public async UniTask SaveDataAsync(T data, string filter = "") { string json = Formatter.Format(data); await CacheManager.UpdateDataAsync(Filepath, json, filter); } public void InvalidateData(string filter = "") { CacheManager.InvalidateFile(GetRelativeCacheFilepath(Filepath), filter); } } }