// Copyright © 2015 The CefSharp Authors. All rights reserved. // // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace CefSharp.Internals { /// /// Class to store TaskCompletionSources indexed by a unique id. There are two distinct ConcurrentDictionary /// instances as we have some Tasks that are created from the browser process (EvaluateScriptAsync) calls, and /// some that are created for instances for which the Id's are created /// in the render process. /// /// The type of the result produced by the tasks held. public sealed class PendingTaskRepository { private readonly ConcurrentDictionary> pendingTasks = new ConcurrentDictionary>(); private readonly ConcurrentDictionary> callbackPendingTasks = new ConcurrentDictionary>(); //should only be accessed by Interlocked.Increment private long lastId; /// /// Creates a new pending task with a timeout. /// /// The maximum running time of the task. /// The unique id of the newly created pending task and the newly created . public KeyValuePair> CreatePendingTask(TimeSpan? timeout = null) { var taskCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var id = Interlocked.Increment(ref lastId); pendingTasks.TryAdd(id, taskCompletionSource); if (timeout.HasValue) { taskCompletionSource = taskCompletionSource.WithTimeout(timeout.Value, () => RemovePendingTask(id)); } return new KeyValuePair>(id, taskCompletionSource); } /// /// Creates a new pending task with a timeout. /// /// Id passed in from the render process /// The maximum running time of the task. /// The unique id of the newly created pending task and the newly created . public KeyValuePair> CreateJavascriptCallbackPendingTask(long id, TimeSpan? timeout = null) { var taskCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); callbackPendingTasks.TryAdd(id, taskCompletionSource); if (timeout.HasValue) { taskCompletionSource = taskCompletionSource.WithTimeout(timeout.Value, () => RemoveJavascriptCallbackPendingTask(id)); } return new KeyValuePair>(id, taskCompletionSource); } /// /// If a is found matching /// then it is removed from the ConcurrentDictionary and returned. /// /// Unique id of the pending task. /// /// The associated with the given id /// or null if no matching TaskComplectionSource found. /// public TaskCompletionSource RemovePendingTask(long id) { TaskCompletionSource result; if (pendingTasks.TryRemove(id, out result)) { return result; } return null; } /// /// If a is found matching /// then it is removed from the ConcurrentDictionary and returned. /// /// Unique id of the pending task. /// /// The associated with the given id /// or null if no matching TaskComplectionSource found. /// public TaskCompletionSource RemoveJavascriptCallbackPendingTask(long id) { TaskCompletionSource result; if (callbackPendingTasks.TryRemove(id, out result)) { return result; } return null; } } }