protected virtual void FreeResources(ICheckoutTaskContext context, CheckoutTask task) { task.ProxyPool.Release(task.Proxy); task.Proxy = null; context?.Dispose(); TierControl.Release(); }
private bool IsCanceled(CancellationToken cancelToken, CheckoutTask task, ICheckoutTaskContext context = null, bool isTierAcquired = true) { bool ret = false; if (cancelToken.IsCancellationRequested) { task.State = CheckoutTaskState.Canceled; context?.Dispose(); if (isTierAcquired) { TierControl.Release(); } Logger.LogEvent(task.Log, $"TASK {task.Id}", "Task is canceled!"); ret = true; } return(ret); }
private void Checkout(CancellationToken cancelToken, CheckoutTask task) { ICheckoutTaskContext context = null; CheckoutStep waitProxy = new CheckoutStep(WaitProxy, "Waiting proxy", CheckoutTaskState.WaitingProxy); CheckoutStep waitProduct = new CheckoutStep(WaitProduct, "Waiting product", CheckoutTaskState.WaitingProduct); CheckoutStep addToCart = new CheckoutStep(AddToCart, "Carting", CheckoutTaskState.Carting); CheckoutStep checkCart = new CheckoutStep(CheckCart, "Checking cart", CheckoutTaskState.Checking); CheckoutStep billing = new CheckoutStep(Billing, "Billing", CheckoutTaskState.Billing); CheckoutStep waitQuota = new CheckoutStep(WaitQuota, "Waiting quota", CheckoutTaskState.WaitingQuota); CheckoutStep paying = new CheckoutStep(Paying, "Paying", CheckoutTaskState.Paying); StepResult res = StepResult.Ok; TimeSpan executionTime; if (!TierControl.Wait(cancelToken)) { if (IsCanceled(cancelToken, task, null, false)) { return; } throw new Exception(); } Logger.LogEvent(task.Log, $"TASK {task.Id}", "Initializing... done"); //res = waitProxy.Run(null, task, TimeSpan.FromMilliseconds(task.Footsite.Settings.RetryPeriod), out executionTime, cancelToken); task.Proxy = task.ProxyPool.GetOne(); if (IsCanceled(cancelToken, task)) { return; } if (res != StepResult.Ok) { Logger.LogEvent(task.Log, $"TASK {task.Id}", "ATC can not be continued without proxy"); return; } while (true) { if (res != StepResult.Ok) { cancelToken.WaitHandle.WaitOne(TimeSpan.FromMilliseconds(task.Footsite.Settings.RetryPeriod)); if (IsCanceled(cancelToken, task, context)) { return; } } context?.Dispose(); context = CreateContext(task); res = waitProduct.Run(context, task, TimeSpan.FromMilliseconds(task.Footsite.Settings.RetryPeriod), out executionTime, cancelToken); if (IsCanceled(cancelToken, task, context)) { return; } if (res != StepResult.Ok) { Logger.LogEvent(task.Log, $"TASK {task.Id}", $"{waitProduct.Name} is failed... retry"); continue; } if (task.Size == ClothesSizeSystemCollection.RandomSize) { task.Size = GetRandomSize(); Logger.LogEvent(task.Log, $"TASK {task.Id}", $"Size {task.Size} is selected"); } res = addToCart.Run(context, task, TimeSpan.FromMilliseconds(task.Footsite.Settings.RetryPeriod), out executionTime, cancelToken); if (IsCanceled(cancelToken, task, context)) { return; } if (res == StepResult.OutOfStock) { Logger.LogEvent(task.Log, $"TASK {task.Id}", $"{addToCart.Name} is failed... Out of Stock. Retry ATC"); continue; } if (res != StepResult.Ok) { Logger.LogEvent(task.Log, $"TASK {task.Id}", $"{addToCart.Name} is failed... retry ATC"); continue; } while (true) { if (res != StepResult.Ok) { cancelToken.WaitHandle.WaitOne(TimeSpan.FromMilliseconds(task.Footsite.Settings.RetryPeriod)); if (IsCanceled(cancelToken, task, context)) { return; } } res = checkCart.Run(context, task, TimeSpan.FromMilliseconds(task.Footsite.Settings.RetryPeriod), out executionTime, cancelToken); if (IsCanceled(cancelToken, task, context)) { return; } if (res != StepResult.Ok) { Logger.LogEvent(task.Log, $"TASK {task.Id}", $"{checkCart.Name} is failed... retry ATC"); break; } res = billing.Run(context, task, TimeSpan.FromMilliseconds(task.Footsite.Settings.RetryPeriod), out executionTime, cancelToken); if (IsCanceled(cancelToken, task, context)) { return; } if (res != StepResult.Ok) { Logger.LogEvent(task.Log, $"TASK {task.Id}", $"{billing.Name} is failed... retrying checkout"); } res = waitQuota.Run(context, task, TimeSpan.FromMilliseconds(task.Footsite.Settings.RetryPeriod), out executionTime, cancelToken); if (IsCanceled(cancelToken, task, context)) { return; } if (res == StepResult.Failed) { Logger.LogEvent(task.Log, $"TASK {task.Id}", "Checkout quota has ended"); } res = paying.Run(context, task, TimeSpan.FromMilliseconds(task.Footsite.Settings.RetryPeriod), out executionTime, cancelToken); if (res == StepResult.Ok) { task.Profile.Release(true); OnSuccessfulCheckout(new CheckoutInfo() { ReleaseName = Release.Name, ProductName = ProductName, ReleaseCheckoutProfile = task.Profile.ReleaseCheckoutProfile, Size = task.Size, TimeStamp = DateTime.Now }); } else { task.Profile.Release(false); } if (IsCanceled(cancelToken, task, context)) { return; } if (res != StepResult.Ok) { Logger.LogEvent(task.Log, $"TASK {task.Id}", $"{paying.Name} is failed... retrying checkout"); continue; } break; } if (res != StepResult.Ok) { continue; } break; } Logger.LogEvent(task.Log, $"TASK {task.Id}", $"Finished!"); task.State = CheckoutTaskState.Finished; FreeResources(context, task); }
public async Task <bool> Start(CancellationToken cancelToken) { bool ret = true; lock (m_lock) { if (m_state == ReleaseTaskState.Working) { ret = false; } m_state = ReleaseTaskState.Working; } if (ret) { OnPropertyChanged("State"); await Task.Run(() => { Log.Clear(); ReleaseProductInfo productInfo = new ReleaseProductInfo() { ProductLink = Release.ProductLink, KeyWords = Release.KeyWords.ToList() }; ProductMonitorTask productMonitorTask = new ProductMonitorTask() { Period = Release.Footsite.Settings.ProductMonitorPeriod, ProductInfo = productInfo, Proxy = Release.GlobalProxy }; Thread monitorThread = new Thread(() => MonitorProduct(cancelToken, Log, productMonitorTask)); monitorThread.Start(); List <CheckoutTask> checkoutTasks = new List <CheckoutTask>(); int taskId = 0; ProxyPool proxyPool = new ProxyPool(Release.Proxies.ToList(), 1); foreach (ReleaseCheckoutProfile profile in Release.Profiles) { CheckoutTaskCcProfile checkoutTaskCcProfile = new CheckoutTaskCcProfile(new ReleaseCheckoutProfile(profile) { CheckoutProfile = new CheckoutProfile(profile.CheckoutProfile) }, Release.Footsite.Settings.PurchaseLimitPerProfile); Profiles.Add(checkoutTaskCcProfile); for (int i = 0; i < profile.TasksCount; i++) { CheckoutTask checkoutTask = new CheckoutTask() { Id = taskId++, Size = profile.Size, VariantId = profile.VariantId, Profile = checkoutTaskCcProfile, ProxyPool = proxyPool, ProductAvailableEvent = productMonitorTask.ProductAvailableEvent, Footsite = Release.Footsite, ProductInfo = productInfo }; Logger.LogEvent(checkoutTask.Log, $"TASK {checkoutTask.Id}", "Initializing..."); checkoutTaskCcProfile.CheckoutTasks.Add(checkoutTask); checkoutTasks.Add(checkoutTask); } } RestockMonitorTask restockMonitorTask = new RestockMonitorTask() { Period = TimeSpan.FromMilliseconds(Release.Footsite.Settings.ProductMonitorPeriod), CheckoutTasks = checkoutTasks, ProductInfo = productInfo, }; Thread restockMonitorThread = new Thread(() => RestockMonitor(Log, restockMonitorTask, cancelToken)); restockMonitorThread.Start(); CheckoutTasksWatcher checkoutTasksWatcher = new CheckoutTasksWatcher(checkoutTasks); Task.Run(() => { foreach (CheckoutTask checkoutTask in checkoutTasks) { if (cancelToken.IsCancellationRequested) { break; } Thread checkoutThread = new Thread(() => Checkout(cancelToken, checkoutTask)); checkoutThread.Start(); } }); checkoutTasksWatcher.FinishedEvent.WaitOne(cancelToken); productMonitorTask.CompleteEvent.Set(); restockMonitorTask.CompleteEvent.Set(); }); TierControl.ReleaseQuota(Release.TasksCount, Release.Footsite.Type); State = ReleaseTaskState.Idle; } return(ret); }