Exemple #1
0
        public static async Task <CrawlResults> RunOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger log)
        {
            var request = context.GetInput <CrawlRequest>();

            var state = new CrawlState(configuration: request);

            state.AddUrl($"{request.Host}/sitemap.xml");

            var currentDepth = 0;

            while (state.HasAwaiting && currentDepth < MAX_CRAWL_DEPTH)
            {
                var urlsToCrawl = state.Awaiting();

                var crawlTasks = urlsToCrawl
                                 .Select(x => new CrawlUrlRequest {
                    Host = request.Host, Url = x
                })
                                 .Select(x => context.CallActivityAsync <UrlInfo>("CrawlUrl", x))
                                 .ToList();

                await Task.WhenAll(crawlTasks.ToArray());

                var result = crawlTasks.Select(x => x.Result).ToList();

                state.UpdateWithResults(result);

                currentDepth++;
            }

            return(new CrawlResults(request.Host, state));
        }
Exemple #2
0
        private Transformer(CxRestContext ctx, CancellationToken token,
                            String previousStatePath, IProjectFilter filter)
        {
            RestContext = ctx;
            CancelToken = token;
            Filter      = filter;
            _state      = new CrawlState(previousStatePath);

            ResolveScans().Wait();
        }
Exemple #3
0
 /// <summary>
 /// Creates a crawling spider with an undefined data origin.
 /// </summary>
 public Spider()
 {
     this.state = CrawlState.Stopped;
     this.lastUpdated = DateTime.MinValue;
 }
Exemple #4
0
 /// <summary>
 /// An event handler called when the spider starts crawling.
 /// </summary>
 protected void OnStarted()
 {
     lock (this.sync)
     {
         // If the spider is in the running state, throw an exception.
         if (this.state != CrawlState.Stopped) throw new SpiderException("Cannot begin spider crawling because the spider is not in the stopped state.");
         // Change the spider state to running.
         this.state = CrawlState.Running;
         // Raise the events.
         if (this.StateChanged != null) this.StateChanged(this, new SpiderEventArgs(this));
         if (this.CrawlStarted != null) this.CrawlStarted(this, new SpiderEventArgs(this));
     }
 }
Exemple #5
0
 /// <summary>
 /// An event handler called when the spider finishes crawling.
 /// </summary>
 protected void OnFinished()
 {
     lock (this.sync)
     {
         // If the spider is not in the running state, throw an exception.
         if (this.state == CrawlState.Stopped) throw new SpiderException("Cannot finish spider crawling because the spider is already in the stopped state.");
         // Change the spider state to running.
         this.state = CrawlState.Stopped;
         // Raise the event.
         if (this.StateChanged != null) this.StateChanged(this, new SpiderEventArgs(this));
         if (this.CrawlFinished != null) this.CrawlFinished(this, new SpiderEventArgs(this));
     }
 }
Exemple #6
0
 /// <summary>
 /// An event handler called when the user cancels the spider crawling.
 /// </summary>
 protected void OnCanceled()
 {
     lock (this.sync)
     {
         // If the spider is not in the running state, throw an exception.
         if (this.state != CrawlState.Running) throw new SpiderException("Cannot cancel spider crawling because the spider is not in the running state.");
         // Change the spider state to canceling.
         this.state = CrawlState.Canceling;
         // Raise the event.
         if (this.StateChanged != null) this.StateChanged(this, new SpiderEventArgs(this));
     }
 }
Exemple #7
0
        /// <summary>
        /// 常駐クロール処理を開始する(処理は別スレッドで非同期に進行)
        /// </summary>
        public virtual void StartAlwaysCrawl()
        {
            if (AlwaysCrawlIsRunning)
            {
                throw new InvalidOperationException("すでに常駐クロール処理が実行中です。");
            }
            if (ManualCrawlIsRunning)
            {
                throw new InvalidOperationException("手動クロールと常駐クロールを同時に実行しようとしました。");
            }

            // キャンセル用のオブジェクトを生成
            var ctSource = new CancellationTokenSource();
            var res      = new Result()
            {
                Finished = false
            };

            // 常駐クロールのメイン処理 (別スレッドで実行)
            var t = Task.Factory.StartNew(() =>
            {
                Logger.Info("常駐クロール開始");

                // 開始を報告
                ((IProgress <ProgressState>)AlwaysCrawlProgress).Report(new ProgressState()
                {
                    CurrentStep = ProgressState.Step.AlwaysCrawlBegin
                });

                // ファイル監視オブジェクトを生成
                var watchers = new List <System.IO.FileSystemWatcher>();

                // ワークスタックを初期化
                var workStack    = new Stack <IWork>();
                var workStackSet = new HashSet <IWork>(); // 処理の重複を確認するためのセット

                // 最初にフルクロールを実行
                workStack.Push(new Work.ManualCrawl(App, isBackgroundCrawl: true));

                // ファイル監視オブジェクト生成
                var fileWatcher = new FileWatcher(Logger, App.UserSettings.TargetFolders.Select(f => f.Path).OrderBy(p => p).ToList());

                // メイン処理
                try
                {
                    // 監視スタート
                    fileWatcher.Start();

                    // 無視設定を取得
                    var ignoreSettings = App.GetIgnoreSettings();

                    while (true)
                    {
                        // ファイル変更イベントがあれば、対応するワークを生成
                        if (fileWatcher.EventQueue.Count >= 1)
                        {
                            while (fileWatcher.EventQueue.Count >= 1)
                            {
                                // キューの先頭にあるイベントを取得
                                var evt = fileWatcher.EventQueue[0];
                                fileWatcher.EventQueue.RemoveAt(0);

                                if (Logger.IsTraceEnabled)
                                {
                                    Logger.Trace("FileSystemEvent: {0} {1} {2}", evt.Type, evt.TargetType, evt.Path);
                                }

                                // イベントの種類に応じたワークを生成
                                IWork work = null;
                                if (evt.Type == FileSystemEventType.UPDATE)
                                {
                                    if (evt.TargetType == FileSystemEventTargetType.FILE)
                                    {
                                        work = new Work.BackgroundFileCrawl(App, evt.Path, ignoreSettings);
                                    }
                                    else if (evt.TargetType == FileSystemEventTargetType.FOLDER)
                                    {
                                        work = new Work.BackgroundDirectoryCrawl(App, evt.Path, ignoreSettings);
                                    }
                                }
                                else if (evt.Type == FileSystemEventType.DELETE)
                                {
                                    if (evt.TargetType == FileSystemEventTargetType.FILE)
                                    {
                                        work = new Work.DBDocumentDelete(App, true, evt.Path);
                                    }
                                    else if (evt.TargetType == FileSystemEventTargetType.FOLDER)
                                    {
                                        work = new Work.DBDirectoryDelete(App, true, evt.Path);
                                    }
                                }

                                // 処理対象外イベントならスキップ
                                if (work == null)
                                {
                                    continue;
                                }

                                // スタックに登録
                                workStack.Push(work);
                                workStackSet.Add(work);
                                if (Logger.IsTraceEnabled)
                                {
                                    Logger.Trace("Work Push: {0}", work.TraceLogCaption);
                                    Logger.Trace("Work Stack ({0}): [{1}]", workStack.Count, string.Join(", ", workStack.Select(w => w.TraceLogCaption)));
                                }
                            }
                        }

                        // ワークキューにワークがあれば、1つ取得して実行
                        if (workStack.Count >= 1)
                        {
                            var nextWork = workStack.Pop();
                            nextWork.Execute(workStack, res, ctSource.Token, AlwaysCrawlProgress);
                            ctSource.Token.ThrowIfCancellationRequested(); // キャンセル受付
                        }
                        else
                        {
                            // ワークが1つも無い状態であれば、進捗を報告した上で、5秒待つ (1秒ごとにキャンセル受け付け)
                            ((IProgress <ProgressState>)AlwaysCrawlProgress).Report(new ProgressState()
                            {
                                CurrentStep = ProgressState.Step.Finish
                            });
                            for (var i = 0; i < 5; i++)
                            {
                                Thread.Sleep(1000);
                                ctSource.Token.ThrowIfCancellationRequested(); // キャンセル受付
                            }

                            // ファイル監視オブジェクトを再起動
                            fileWatcher.Restart();
                        }
                    }
                }
                catch (OperationCanceledException)
                {
                    // ファイル監視オブジェクトをすべて解放
                    fileWatcher.Stop();
                    Logger.Info("常駐クロール終了");

                    // 終了を報告
                    ((IProgress <ProgressState>)AlwaysCrawlProgress).Report(new ProgressState()
                    {
                        CurrentStep = ProgressState.Step.AlwaysCrawlEnd
                    });

                    return;
                }
                catch (Exception ex)
                {
                    Logger.Error("常駐クロール処理でエラーが発生しました");
                    Logger.Error(ex.ToString());
                }
            }, ctSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);

            // 実行状態を設定
            AlwaysCrawlState = new CrawlState(t, ctSource);
        }
Exemple #8
0
        /// <summary>
        /// 非同期に全体クロール処理の実行を開始する
        /// </summary>
        public virtual async Task <Result> RunFullCrawlAsync(
            IEnumerable <string> targetDirPaths
            , EventHandler <ProgressState> progressChangedCallback = null)
        {
            if (ManualCrawlIsRunning)
            {
                throw new InvalidOperationException("すでに手動クロール処理が実行中です。");
            }
            if (AlwaysCrawlIsRunning)
            {
                throw new InvalidOperationException("手動クロールと常駐クロールを同時に実行しようとしました。");
            }

            // 進捗報告用オブジェクトの作成
            var progress = new Progress <ProgressState>();

            if (progressChangedCallback != null)
            {
                progress.ProgressChanged += progressChangedCallback;
            }

            // 処理取り消しを可能とするためにCancellationTokenSourceを生成
            var ctSource = new CancellationTokenSource();

            // クロール結果オブジェクトを生成
            var res = new Result()
            {
                Finished = false
            };

            // 手動クロールのメイン処理(別スレッドで実行)
            var t = Task.Run(() =>
            {
                Logger.Info("手動クロール開始");

                try
                {
                    // (1) 登録ファイル数の計測 (別スレッドで並列実行)
                    //     ※内部で例外が発生した場合には、ログのみ出力して処理を中断するため注意
                    Task.Run(() =>
                    {
                        var workStack = new Stack <IWork>();
                        workStack.Push(new Work.TargetFileCount(App, isBackgroundCrawl: true, targetDirPaths: targetDirPaths));

                        // ワークスタックが空になるまで順次実行
                        while (workStack.Count >= 1)
                        {
                            var work = workStack.Pop();
                            work.Execute(workStack, res, ctSource.Token, progress);

                            Thread.Sleep(0);                               // 他のスレッドに処理を渡す
                            ctSource.Token.ThrowIfCancellationRequested(); // 取り消し判定
                        }
                    });

                    // (2) メインクロール処理
                    {
                        var workStack = new Stack <IWork>();
                        workStack.Push(new Work.ManualCrawl(App, isBackgroundCrawl: false, targetDirPaths: targetDirPaths));

                        // ワークスタックが空になるまで順次実行
                        while (workStack.Count >= 1)
                        {
                            var work = workStack.Pop();
                            work.Execute(workStack, res, ctSource.Token, progress);

                            Thread.Sleep(0);                               // 他のスレッドに処理を渡す
                            ctSource.Token.ThrowIfCancellationRequested(); // 取り消し判定
                        }
                    }
                }
                catch (OperationCanceledException)
                {
                    Logger.Info("手動クロールをキャンセル");
                    return;
                }

                Logger.Info("手動クロール完了");

                // 手動クロール処理完了を通知
                ((IProgress <ProgressState>)progress).Report(new ProgressState()
                {
                    CurrentStep = ProgressState.Step.Finish
                });
                res.Finished = true;
            }, ctSource.Token);

            // 実行状態を設定
            ManualCrawlState = new CrawlState(t, ctSource);

            // タスク完了/キャンセルを待機
            await t;

            // タスクが完了/キャンセル受付したら結果を戻す
            return(res);
        }