/// <summary> /// Get or resolve the data for a set of entity keys /// with these policies: /// /// - data for a key will be returned from local store if it is there (regardless of expiration status) /// - any key that fails to resolve (with error or otherwise) will simply be left out of results /// /// The reason to use this over, say, ResolveAll, /// is to avoid relatively expensive refreshes of data /// if what you really want is 'any valid copy of the data' /// </summary> /// <returns>The or resolve ignoring errors async.</returns> /// <param name="keys">Keys.</param> /// <param name="store">Store.</param> /// <param name="results">Results.</param> public static async System.Threading.Tasks.Task FindAllAsync( IEnumerable <string> keys, HasEntities <DataType> store, ICollection <DataType> results ) { if (keys == null) { return; } foreach (var k in keys) { DataType cur; if (!store.GetData(k, out cur)) { try { cur = await Entity <DataType> .ResolveOrThrowAsync(k, store); } catch (Exception e) { #if UNITY_EDITOR || DEBUG_UNSTRIP Debug.LogWarning("error resolving " + k + ": " + e.Message + "\n" + e.StackTrace); #endif continue; } } results.Add(cur); } }
/// <summary> /// Allows you to request an entity (from the store) and get a callback when load succeeds or fails. /// If the entity is not initially loaded, sends the usual notifications and then listens for updates /// </summary> public static Request <ResolveMultipleResultDTO <DataType> > ResolveAll( IEnumerable <string> keys, HasEntities <DataType> store, Action <Request <ResolveMultipleResultDTO <DataType> > > callback = null) { var promise = new Promise <ResolveMultipleResultDTO <DataType> >((resolve, reject, cancel, attach) => { var all = new JoinRequests(); foreach (var k in keys) { all.Add(new DataRequest(NewResolveRequest(k), store)); } all.Execute(result => { var allResult = result as JoinRequests; using (var resultRequests = ListPool <Request> .Get()) using (var resultItems = ListPool <ResolveResultDTO <DataType> > .Get()) { allResult.GetResults(resultRequests); foreach (var rr in resultRequests) { var key = (rr as DataRequest).loadKey; var reqDTO = (rr as DataRequest).requestDTO; if (rr.hasError) { resultItems.Add( ResolveResultDTO <DataType> .ResolveError( reqDTO, rr.error ) ); continue; } Entity <DataType> entity; if (!store.GetEntity(key, out entity)) { resultItems.Add( ResolveResultDTO <DataType> .ResolveError( reqDTO, "enity not in store after resolve" ) ); continue; } var status = entity.status; resultItems.Add(ResolveResultDTO <DataType> .ResolveSucceeded( reqDTO, entity.id, entity.data, status.maxAgeSecs, status.timestamp )); } resolve(new ResolveMultipleResultDTO <DataType> { entities = resultItems.ToArray() }); } }); }); promise.Execute(callback); return(promise); }
/// <summary> /// A convenience extension/wrapper around HasEntities<DataType>>::GetData /// that also issues a resolve request under specifiable conditions, /// e.g. if the entity is missing or if it is expired /// </summary> /// <returns><c>true</c>, if data was gotten, <c>false</c> otherwise.</returns> /// <param name="entities">Entities.</param> /// <param name="key">Key.</param> /// <param name="d">D.</param> /// <param name="requestResolvePolicy">Request resolve policy.</param> /// <typeparam name="DataType">The 1st type parameter.</typeparam> public static bool GetData <DataType>( this HasEntities <DataType> entities, string key, out DataType d, RequestResolvePolicyFlags requestResolvePolicy ) { Entity <DataType> entity; if (!entities.GetEntity(key, out entity) || !entity.status.hasResolved) { d = default(DataType); // By default DO NOT try to resolve an entity that is in error status if (entity.status.HasError() && !requestResolvePolicy.HasFlag(RequestResolvePolicyFlags.IF_HAS_ERROR)) { return(false); } if (requestResolvePolicy.HasFlag(RequestResolvePolicyFlags.IF_MISSING)) { Entity <DataType> .RequestResolve(new ResolveRequestDTO { key = key }); } return(false); } d = entity.data; #if UNITY_EDITOR || DEBUG_UNSTRIP if (Entity <DataType> .DEBUG) { Debug.Log("[" + Time.frameCount + "][" + typeof(Entity <DataType>).Name + "] key=" + key + " - found with timestamp=" + entity.status.timestamp + ", and maxAgeSecs=" + entity.status.maxAgeSecs + ", isExpired=" + entity.status.IsExpiredAt(DateTimeOffset.Now) + ", isResolveInProgress=" + entity.status.isResolveInProgress); } #endif if (entity.status.HasError() && !requestResolvePolicy.HasFlag(RequestResolvePolicyFlags.IF_HAS_ERROR)) { // By default DO NOT try to resolve an entity that is in error status return(true); } if (requestResolvePolicy.HasFlag(RequestResolvePolicyFlags.IF_EXPIRED)) { var status = entity.status; if (status.IsExpiredAt(DateTimeOffset.Now) && !status.isResolveInProgress) { Entity <DataType> .RequestResolve(key); } } return(true); }
public void Init(string id, HasEntities <DogData> dogs) { this.id = id; this.dogs = dogs; m_button = (m_button != null) ? m_button : GetComponentInChildren <Button>(); m_text = (m_text != null) ? m_text : GetComponentInChildren <Text>(); m_button.onClick.AddListener(this.OnClick); UpdateDisplay(); }
/// <summary> /// Resolve the data and metadata for a key from an async method using await. /// NOTE: this method will return a ResolveResult<DataType> even if the item /// fails to load, e.g. either not found or resolve error. /// Use this version if you want to handle failed responses without try/catch. /// If you'd rather an exception be thrown any time the data isn't available, /// use @see ResolveOrThrowAsync. /// </summary> /// <returns>The async.</returns> public static async System.Threading.Tasks.Task <ResolveResultDTO <DataType> > ResolveAsync( string loadKey, HasEntities <DataType> store) { var req = NewResolveRequest(loadKey); if (string.IsNullOrEmpty(loadKey)) { return(ResolveResultDTO <DataType> .ResolveError( req, "Load key cannot be null or empty" )); } var r = new ResolveResultRequest(req, store); try { await r.ExecuteAsync(); return(r.item); } catch (Exception e) { #if UNITY_EDITOR || DEBUG_UNSTRIP var ae = e as AggregateException; if (ae != null) { foreach (var ie in ae.InnerExceptions) { Debug.LogError("error on execute async for type " + typeof(DataType).Name + " and load key '" + loadKey + ": " + ie.Message + "\n" + ie.StackTrace ); } } else { Debug.LogError("error on execute async for type " + typeof(DataType).Name + " and load key '" + loadKey + ": " + e.Message ); } #endif return(ResolveResultDTO <DataType> .ResolveError( req, e.Message )); } }
/// <summary> /// Allows you to request an entity (from the store) and get a callback when load succeeds or fails. /// If the entity is not initially loaded, sends the usual notifications and then listens for updates /// </summary> public static Request <DataType> Resolve( string loadKey, HasEntities <DataType> store, Action <Request <DataType> > callback = null) { if (string.IsNullOrEmpty(loadKey)) { var err = new LocalRequest <DataType>("Load key cannot be null or empty"); err.Execute(callback); return(err); } var r = new DataRequest(NewResolveRequest(loadKey), store); r.Execute(callback); return(r); }
public static bool RequestResolveIfExpiredOrUnresolved(string key, HasEntities <DataType> entities) { ResolveStatus status; if (!entities.GetResolveStatus(key, out status)) { RequestResolve(key); return(true); } if (status.IsExpiredAt(DateTimeOffset.Now)) { RequestResolve(key); return(true); } return(false); }
public Helper(HasEntities <DataType> hasEntities) { this.hasEntities = hasEntities; }
public DataRequest(ResolveRequestDTO req, HasEntities <DataType> store) { this.store = store; this.requestDTO = req; }
public static async System.Threading.Tasks.Task <ResolveMultipleResultDTO <DataType> > ResolveAllAsync( IEnumerable <string> keys, HasEntities <DataType> store) { return(await ResolveAll(keys, store)); }
/// <summary> /// Resolve the data for a key from an async method using await. /// NOTE: this will throw an exception if the item cannot be found. /// If you want to handle 'not found' or other errors without exceptions, /// use @see ResolveAsync instead; it returns a ResolveResult<DataType> /// that would include details on failed resolves. /// </summary> public static async System.Threading.Tasks.Task <DataType> ResolveOrThrowAsync( string loadKey, HasEntities <DataType> store) { return(await Resolve(loadKey, store)); }