static void HandleItemsIteratorSession(object iterator, List <SearchItem> allItems, string id, SearchContext context, SearchFlags options) { if (iterator != null && options.HasAny(SearchFlags.Synchronous)) { using (var stackedEnumerator = new SearchEnumerator <SearchItem>(iterator)) { while (stackedEnumerator.MoveNext()) { if (stackedEnumerator.Current != null) { allItems.Add(stackedEnumerator.Current); } } } } else { var session = context.sessions.GetProviderSession(context, id); session.Reset(context, iterator, k_MaxFetchTimeMs); session.Start(); var sessionEnded = !session.FetchSome(allItems, k_MaxFetchTimeMs); if (options.HasAny(SearchFlags.FirstBatchAsync)) { session.SendItems(context.subset != null ? allItems.Intersect(context.subset) : allItems); allItems.Clear(); } if (sessionEnded) { session.Stop(); } } }
/// <summary> /// Execute a search request that will fetch search results asynchronously. /// </summary> /// <param name="context">Search context used to track asynchronous request.</param> /// <param name="options">Options defining how the query will be performed</param> /// <returns>Asynchronous list of search items.</returns> public static ISearchList Request(SearchContext context, SearchFlags options = SearchFlags.None) { ISearchList results = null; if (!InternalEditorUtility.CurrentThreadIsMainThread()) { results = new ConcurrentSearchList(context); Dispatcher.Enqueue(() => { results.AddItems(GetItems(context, options)); (results as ConcurrentSearchList)?.GetItemsDone(); }); return(results); } if (options.HasAny(SearchFlags.Sorted)) { results = new SortedSearchList(context); } else { results = new AsyncSearchList(context); } results.AddItems(GetItems(context, options)); return(results); }
/// <summary> /// Execute a search request and callback for every incoming items and when the search is completed. /// The user is responsible for disposing of the search context. /// </summary> public static void Request(SearchContext context, Action <SearchContext, IEnumerable <SearchItem> > onIncomingItems, Action <SearchContext> onSearchCompleted, SearchFlags options = SearchFlags.None) { var requestId = Guid.NewGuid().ToString("N"); if (options.HasAny(SearchFlags.Debug)) { Debug.Log($"{requestId} Request started {context.searchText} ({options | context.options})"); } var sessionCount = 0; var firstBatchResolved = false; var completed = false; var batchCount = 1; void ReceiveItems(SearchContext c, IEnumerable <SearchItem> items) { if (options.HasAny(SearchFlags.Debug)) { Debug.Log($"{requestId} #{batchCount++} Request incoming batch {context.searchText}"); } onIncomingItems?.Invoke(c, items.Where(e => e != null)); } void OnSessionStarted(SearchContext c) { if (options.HasAny(SearchFlags.Debug)) { Debug.Log($"{requestId} Request session begin {context.searchText}"); } ++sessionCount; } void OnSessionEnded(SearchContext c) { if (options.HasAny(SearchFlags.Debug)) { Debug.Log($"{requestId} Request session ended {context.searchText}"); } --sessionCount; if (sessionCount == 0 && firstBatchResolved) { if (options.HasAny(SearchFlags.Debug)) { Debug.Log($"{requestId} Request async ended {context.searchText}"); } context.asyncItemReceived -= ReceiveItems; context.sessionStarted -= OnSessionStarted; context.sessionEnded -= OnSessionEnded; onSearchCompleted?.Invoke(c); completed = true; } } context.asyncItemReceived += ReceiveItems; context.sessionStarted += OnSessionStarted; context.sessionEnded += OnSessionEnded; GetItems(context, options | SearchFlags.FirstBatchAsync); firstBatchResolved = true; if (sessionCount == 0 && !completed) { if (options.HasAny(SearchFlags.Debug)) { Debug.Log($"{requestId} Request sync ended {context.searchText}"); } context.asyncItemReceived -= ReceiveItems; context.sessionStarted -= OnSessionStarted; context.sessionEnded -= OnSessionEnded; onSearchCompleted?.Invoke(context); } }
/// <summary> /// Initiate a search and return all search items matching the search context. Other items can be found later using the asynchronous searches. /// </summary> /// <param name="context">The current search context</param> /// <param name="options">Options defining how the query will be performed</param> /// <returns>A list of search items matching the search query.</returns> public static List <SearchItem> GetItems(SearchContext context, SearchFlags options = SearchFlags.Default) { // Stop all search sessions every time there is a new search. context.sessions.StopAllAsyncSearchSessions(); context.searchFinishTime = context.searchStartTime = DateTime.Now.Ticks; context.sessionEnded -= OnSearchEnded; context.sessionEnded += OnSearchEnded; context.sessions.StartSessions(); if (options.HasAny(SearchFlags.WantsMore)) { context.wantsMore = true; } if (options.HasAny(SearchFlags.Synchronous)) { context.options |= SearchFlags.Synchronous; } int fetchProviderCount = 0; var allItems = new List <SearchItem>(3); if (TryParseExpression(context, out var expression)) { var iterator = EvaluateExpression(expression, context); HandleItemsIteratorSession(iterator, allItems, s_SearchServiceProvider.id, context, options); fetchProviderCount++; } else { foreach (var provider in context.providers) { try { var watch = new System.Diagnostics.Stopwatch(); watch.Start(); fetchProviderCount++; var iterator = provider.fetchItems(context, allItems, provider); HandleItemsIteratorSession(iterator, allItems, provider.id, context, options); provider.RecordFetchTime(watch.Elapsed.TotalMilliseconds); } catch (Exception ex) { Debug.LogException(new Exception($"Failed to get fetch {provider.name} provider items.", ex)); } } } if (fetchProviderCount == 0) { OnSearchEnded(context); context.sessions.StopAllAsyncSearchSessions(); } if (context.subset != null) { allItems = new List <SearchItem>(allItems.Intersect(context.subset)); } if (!options.HasAny(SearchFlags.Sorted)) { return(allItems); } allItems.Sort(SortItemComparer); return(allItems.GroupBy(i => i.id).Select(i => i.First()).ToList()); }
/// <summary> /// Initiate a search and return all search items matching the search context. Other items can be found later using the asynchronous searches. /// </summary> /// <param name="context">The current search context</param> /// <param name="options">Options defining how the query will be performed</param> /// <returns>A list of search items matching the search query.</returns> public static List <SearchItem> GetItems(SearchContext context, SearchFlags options = SearchFlags.Default) { // Stop all search sessions every time there is a new search. context.sessions.StopAllAsyncSearchSessions(); context.searchFinishTime = context.searchStartTime = DateTime.Now.Ticks; context.sessionEnded -= OnSearchEnded; context.sessionEnded += OnSearchEnded; if (options.HasAny(SearchFlags.WantsMore)) { context.wantsMore = true; } if (options.HasAny(SearchFlags.Synchronous)) { context.options |= SearchFlags.Synchronous; } int fetchProviderCount = 0; var allItems = new List <SearchItem>(3); foreach (var provider in context.providers) { try { var watch = new System.Diagnostics.Stopwatch(); watch.Start(); fetchProviderCount++; var iterator = provider.fetchItems(context, allItems, provider); if (iterator != null && options.HasAny(SearchFlags.Synchronous)) { using (var stackedEnumerator = new SearchEnumerator <SearchItem>(iterator)) { while (stackedEnumerator.MoveNext()) { if (stackedEnumerator.Current != null) { allItems.Add(stackedEnumerator.Current); } } } } else { var session = context.sessions.GetProviderSession(context, provider.id); session.Reset(context, iterator, k_MaxFetchTimeMs); session.Start(); var sessionEnded = !session.FetchSome(allItems, k_MaxFetchTimeMs); if (options.HasAny(SearchFlags.FirstBatchAsync)) { session.SendItems(context.subset != null ? allItems.Intersect(context.subset) : allItems); allItems.Clear(); } if (sessionEnded) { session.Stop(); } } provider.RecordFetchTime(watch.Elapsed.TotalMilliseconds); } catch (Exception ex) { Debug.LogException(new Exception($"Failed to get fetch {provider.name} provider items.", ex)); } } if (fetchProviderCount == 0) { OnSearchEnded(context); context.sessions.StopAllAsyncSearchSessions(); } if (context.subset != null) { allItems = new List <SearchItem>(allItems.Intersect(context.subset)); } if (!options.HasAny(SearchFlags.Sorted)) { return(allItems); } allItems.Sort(SortItemComparer); return(allItems.GroupBy(i => i.id).Select(i => i.First()).ToList()); }