From 9056e35a58f1be1f789faa5dadf7d07eedc320de Mon Sep 17 00:00:00 2001 From: wangrong Date: Wed, 23 Sep 2026 11:00:01 +0800 Subject: [PATCH] refactor: remove daemon and searcher projects for index merge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the daemon and searcher subprojects in preparation for the upcoming index service consolidation. Shared mount_info and utils files are moved into server. Unused config files and the daemon stress test are also dropped. 移除 daemon 和 searcher 子项目,为后续索引服务合并做准备。 将共享的 mount_info 与工具文件迁移至 server 目录下,同时删除 未使用的配置文件和 daemon 压测脚本。 Log: 移除 daemon 和 searcher 项目 PMS: TASK-395961 Influence: 不再构建 deepin-anything-daemon 与 deepin-anything-searcher 可执行文件;server 保持原有功能不变,构建依赖相应减少。 --- config/dict.utf8 | 2 - config/filetypes.cfg | 93 --- debian/control | 4 - debian/deepin-anything-server.install | 2 - debian/deepin-anything-server.links | 1 - src/CMakeLists.txt | 2 - src/daemon/CMakeLists.txt | 136 --- src/daemon/deepin-anything-daemon.pc.in | 11 - src/daemon/deepin-anything-daemon.service | 11 - .../include/analyzers/AnythingAnalyzer.h | 47 -- src/daemon/include/analyzers/AnythingFilter.h | 32 - .../include/analyzers/AnythingTokenizer.h | 67 -- .../analyzers/LowerCaseNGramAnalyzer.h | 50 -- src/daemon/include/anything.hpp | 12 - src/daemon/include/common/anything_fwd.hpp | 20 - src/daemon/include/common/fs_event.h | 26 - src/daemon/include/common/vfs_genl.h | 35 - src/daemon/include/core/base_event_handler.h | 104 --- src/daemon/include/core/config.h | 75 -- .../include/core/default_event_handler.h | 81 -- src/daemon/include/core/disk_scanner.h | 28 - src/daemon/include/core/event_listener.h | 33 - src/daemon/include/core/file_index_manager.h | 129 --- src/daemon/include/core/mount_manager.h | 79 -- src/daemon/include/core/pinyin_processor.h | 40 - src/daemon/include/core/thread_pool.h | 43 - src/daemon/include/utils/enum_helper.h | 20 - src/daemon/include/utils/log.h | 157 ---- src/daemon/include/utils/running_flag.h | 81 -- src/daemon/include/utils/string_helper.h | 73 -- src/daemon/src/analyzers/AnythingAnalyzer.cpp | 36 - src/daemon/src/analyzers/AnythingFilter.cpp | 54 -- .../src/analyzers/AnythingTokenizer.cpp | 217 ----- .../src/analyzers/LowerCaseNGramAnalyzer.cpp | 49 -- src/daemon/src/core/base_event_handler.cpp | 486 ----------- src/daemon/src/core/config.cpp | 489 ----------- src/daemon/src/core/default_event_handler.cpp | 543 ------------ src/daemon/src/core/disk_scanner.cpp | 47 -- src/daemon/src/core/event_listener.cpp | 397 --------- src/daemon/src/core/file_index_manager.cpp | 772 ------------------ src/daemon/src/core/mount_manager.cpp | 237 ------ src/daemon/src/core/pinyin_processor.cpp | 190 ----- src/daemon/src/core/thread_pool.cpp | 71 -- src/daemon/src/main.cpp | 142 ---- src/daemon/src/utils/running_flag.cpp | 135 --- src/daemon/src/utils/string_helper.cpp | 10 - src/searcher/CMakeLists.txt | 46 -- src/searcher/main.cpp | 169 ---- src/searcher/searcher.cpp | 118 --- src/searcher/searcher.h | 38 - src/server/CMakeLists.txt | 6 +- src/server/event-dispatcher.c | 4 +- src/{daemon/src/core => server}/mount_info.c | 2 +- .../include/core => server}/mount_info.h | 0 src/{daemon/src/utils => server}/tools.c | 2 +- src/{daemon/include/utils => server}/tools.h | 2 +- tests/stress_stop_start.sh | 414 ---------- 57 files changed, 8 insertions(+), 6162 deletions(-) delete mode 100644 config/dict.utf8 delete mode 100644 config/filetypes.cfg delete mode 100644 debian/deepin-anything-server.links delete mode 100755 src/daemon/CMakeLists.txt delete mode 100755 src/daemon/deepin-anything-daemon.pc.in delete mode 100755 src/daemon/deepin-anything-daemon.service delete mode 100644 src/daemon/include/analyzers/AnythingAnalyzer.h delete mode 100644 src/daemon/include/analyzers/AnythingFilter.h delete mode 100644 src/daemon/include/analyzers/AnythingTokenizer.h delete mode 100644 src/daemon/include/analyzers/LowerCaseNGramAnalyzer.h delete mode 100644 src/daemon/include/anything.hpp delete mode 100644 src/daemon/include/common/anything_fwd.hpp delete mode 100644 src/daemon/include/common/fs_event.h delete mode 100644 src/daemon/include/common/vfs_genl.h delete mode 100755 src/daemon/include/core/base_event_handler.h delete mode 100755 src/daemon/include/core/config.h delete mode 100644 src/daemon/include/core/default_event_handler.h delete mode 100644 src/daemon/include/core/disk_scanner.h delete mode 100644 src/daemon/include/core/event_listener.h delete mode 100644 src/daemon/include/core/file_index_manager.h delete mode 100644 src/daemon/include/core/mount_manager.h delete mode 100644 src/daemon/include/core/pinyin_processor.h delete mode 100644 src/daemon/include/core/thread_pool.h delete mode 100644 src/daemon/include/utils/enum_helper.h delete mode 100644 src/daemon/include/utils/log.h delete mode 100755 src/daemon/include/utils/running_flag.h delete mode 100644 src/daemon/include/utils/string_helper.h delete mode 100644 src/daemon/src/analyzers/AnythingAnalyzer.cpp delete mode 100644 src/daemon/src/analyzers/AnythingFilter.cpp delete mode 100755 src/daemon/src/analyzers/AnythingTokenizer.cpp delete mode 100644 src/daemon/src/analyzers/LowerCaseNGramAnalyzer.cpp delete mode 100755 src/daemon/src/core/base_event_handler.cpp delete mode 100755 src/daemon/src/core/config.cpp delete mode 100755 src/daemon/src/core/default_event_handler.cpp delete mode 100755 src/daemon/src/core/disk_scanner.cpp delete mode 100644 src/daemon/src/core/event_listener.cpp delete mode 100755 src/daemon/src/core/file_index_manager.cpp delete mode 100644 src/daemon/src/core/mount_manager.cpp delete mode 100644 src/daemon/src/core/pinyin_processor.cpp delete mode 100644 src/daemon/src/core/thread_pool.cpp delete mode 100644 src/daemon/src/main.cpp delete mode 100755 src/daemon/src/utils/running_flag.cpp delete mode 100644 src/daemon/src/utils/string_helper.cpp delete mode 100644 src/searcher/CMakeLists.txt delete mode 100644 src/searcher/main.cpp delete mode 100644 src/searcher/searcher.cpp delete mode 100644 src/searcher/searcher.h rename src/{daemon/src/core => server}/mount_info.c (99%) rename src/{daemon/include/core => server}/mount_info.h (100%) rename src/{daemon/src/utils => server}/tools.c (99%) rename src/{daemon/include/utils => server}/tools.h (94%) delete mode 100755 tests/stress_stop_start.sh diff --git a/config/dict.utf8 b/config/dict.utf8 deleted file mode 100644 index 9db7df02..00000000 --- a/config/dict.utf8 +++ /dev/null @@ -1,2 +0,0 @@ -hello -world \ No newline at end of file diff --git a/config/filetypes.cfg b/config/filetypes.cfg deleted file mode 100644 index 61fdf736..00000000 --- a/config/filetypes.cfg +++ /dev/null @@ -1,93 +0,0 @@ -# Programming Language Files -.cpp=C++ -.cxx=C++ -.cc=C++ -.c=C -.h=C -.hpp=C++ -.cs=C# -.java=Java -.py=Python -.js=JavaScript/JS -.ts=TypeScript/TS -.html=HTML -.css=CSS -.php=PHP -.rb=Ruby -.go=Go -.swift=Swift -.kt=Kotlin -.rs=Rust -.lua=Lua -.sh=Shell/Script -.bash=Shell/Script/bash -.pl=Perl -.sql=SQL -.json=JSON -.xml=XML -.yaml=YAML -.toml=text/toml -.md=Markdown -.r=R -.jl=Julia/jl -.dart=text/dart -.scala=text/scala -.vb=VB -.asm=Assembly/ASM -.bat=Batch -.make=Makefile -.cmake=CMake -.gradle=Gradle -.dockerfile=Dockerfile -.qml=Qt/QML -.qrc=Qt/QRC -.o=OBJ - -# Document Files -.txt=TXT -.pdf=PDF -.doc=DOC -.docx=DOCX -.xls=XLS -.xlsx=XLSX -.ppt=PPT -.pptx=PPTX - -# Image Files -.jpg=Image/JPG -.jpeg=Image/JPEG -.png=Image/PNG -.gif=Image/GIF -.bmp=Image/BMP -.svg=Image/SVG -.ico=Image/ICO - -# Audio Files -.mp3=Audio/MP3 -.wav=Audio/WAV -.ogg=Audio/OGG -.flac=Audio/FLAC - -# Video Files -.mp4=Video/MP4 -.avi=Video/AVI -.mov=Video/MOV -.mkv=Video/MKV - -# Compressed Files -.zip=Compress/ZIP -.tar=Compress/TAR -.gz=Compress/GZIP/GZ -.rar=Compress/RAR -.7z=Compress/7Z - -# Other Files -.iso=ISO -.csv=CSV -.epub=EPUB -.apk=APK -.exe=EXE -.deb=Package/DEB -.a=Library/a -.so=Library/SO -.dll=Library/DLL \ No newline at end of file diff --git a/debian/control b/debian/control index 49910bf7..e47c378c 100644 --- a/debian/control +++ b/debian/control @@ -6,13 +6,9 @@ Build-Depends: cmake, debhelper (>= 10), dh-dkms | dkms, - qt6-base-dev | qtbase5-dev, pkg-config, libnl-genl-3-dev, - liblucene++-dev, libmount-dev, - libboost-filesystem-dev, - libspdlog-dev, libglib2.0-dev, Standards-Version: 3.9.8 Homepage: http://github.com/linuxdeepin/deepin-anything diff --git a/debian/deepin-anything-server.install b/debian/deepin-anything-server.install index c5c8377c..c1463473 100644 --- a/debian/deepin-anything-server.install +++ b/debian/deepin-anything-server.install @@ -1,5 +1,3 @@ -/usr/bin /usr/libexec -/usr/lib/systemd/user/deepin-anything-daemon.service /usr/lib/systemd/system/deepin-anything-logger.service /usr/share diff --git a/debian/deepin-anything-server.links b/debian/deepin-anything-server.links deleted file mode 100644 index 902d55eb..00000000 --- a/debian/deepin-anything-server.links +++ /dev/null @@ -1 +0,0 @@ -/usr/lib/systemd/user/deepin-anything-daemon.service /usr/lib/systemd/user/default.target.wants/deepin-anything-daemon.service \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 46b6a6d4..69f9d51e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,9 +16,7 @@ message("Build type:" ${CMAKE_BUILD_TYPE}) add_compile_options(-Wall -Wextra -pedantic -Werror) -add_subdirectory("daemon") add_subdirectory("server") add_subdirectory("kernelmod") -add_subdirectory("searcher") add_subdirectory("logger") add_subdirectory("dispatcher") \ No newline at end of file diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt deleted file mode 100755 index 62ba1d0e..00000000 --- a/src/daemon/CMakeLists.txt +++ /dev/null @@ -1,136 +0,0 @@ -cmake_minimum_required(VERSION 3.1) - -# --------------------------------------------------------------------------------------- -# Start deepin-anything-daemon project -# --------------------------------------------------------------------------------------- -project( - deepin-anything-daemon - VERSION 1.0.0 - DESCRIPTION "A file search engine" - LANGUAGES C CXX -) - -set(CMAKE_C_STANDARD 11) -set(CMAKE_C_STANDARD_REQUIRED ON) -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -# --------------------------------------------------------------------------------------- -# Parse version from debian/changelog -# --------------------------------------------------------------------------------------- -if(EXISTS "${CMAKE_SOURCE_DIR}/debian/changelog") - file(READ "${CMAKE_SOURCE_DIR}/debian/changelog" CHANGELOG_CONTENT) - string(REGEX MATCH "deepin-anything \\(([^)]+)\\)" VERSION_MATCH "${CHANGELOG_CONTENT}") - if(VERSION_MATCH) - string(REGEX REPLACE "deepin-anything \\(([^)]+)\\)" "\\1" DEEPIN_ANYTHING_VERSION "${VERSION_MATCH}") - message(STATUS "Found version from debian/changelog: ${DEEPIN_ANYTHING_VERSION}") - # Define the version macro - add_compile_definitions(DEEPIN_ANYTHING_VERSION="${DEEPIN_ANYTHING_VERSION}") - else() - message(WARNING "Failed to parse version from debian/changelog") - endif() -else() - message(WARNING "debian/changelog not found, version macro will not be defined") -endif() - -# --------------------------------------------------------------------------------------- -# Get git commit hash -# --------------------------------------------------------------------------------------- -find_package(Git QUIET) -if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git") - execute_process( - COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE DEEPIN_ANYTHING_COMMIT_HASH - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_QUIET - ) - if(DEEPIN_ANYTHING_COMMIT_HASH) - message(STATUS "Found git commit hash: ${DEEPIN_ANYTHING_COMMIT_HASH}") - # Define the commit hash macro - add_compile_definitions(DEEPIN_ANYTHING_COMMIT_HASH="${DEEPIN_ANYTHING_COMMIT_HASH}") - else() - message(WARNING "Failed to get git commit hash") - endif() -else() - if(NOT GIT_FOUND) - message(WARNING "Git not found, commit hash macro will not be defined") - else() - message(WARNING ".git directory not found, commit hash macro will not be defined") - endif() -endif() - -# Find the dependencies -find_package(QT NAMES Qt6 Qt5 CONFIG REQUIRED COMPONENTS Core) -find_package(Qt${QT_VERSION_MAJOR} CONFIG REQUIRED Core) -find_package(PkgConfig REQUIRED) -find_package(Boost REQUIRED) -find_package(spdlog REQUIRED) -if (Boost_VERSION_STRING VERSION_LESS "1.89.0") - message(STATUS "Boost < 1.89 → using Boost::system") - find_package(Boost REQUIRED COMPONENTS system) -endif() -pkg_check_modules(MOUNT REQUIRED mount IMPORTED_TARGET) -pkg_check_modules(LUCENE REQUIRED liblucene++) -pkg_check_modules(LUCENE_CONTRIB REQUIRED liblucene++-contrib) -pkg_check_modules(GLIB REQUIRED glib-2.0) -pkg_check_modules(GIO REQUIRED gio-2.0) -pkg_check_modules(GIO_UNIX REQUIRED gio-unix-2.0) -pkg_check_modules(GMODULE REQUIRED gmodule-2.0) - -# Found all source files -file(GLOB_RECURSE SOURCE_FILES "${PROJECT_SOURCE_DIR}/src/*.cpp" "${PROJECT_SOURCE_DIR}/src/*.c") -list(LENGTH SOURCE_FILES SRC_FILES_SIZE) -message(STATUS "Found ${SRC_FILES_SIZE} source files of deepin-anything-daemon") -foreach(source_file ${SOURCE_FILES}) - message(STATUS " ${source_file}") -endforeach() - -# Define a shared library -add_executable(${PROJECT_NAME}) - -target_sources(${PROJECT_NAME} PRIVATE ${SOURCE_FILES}) - -target_include_directories(${PROJECT_NAME} PUBLIC - $ - $ - $ - $ - # $ - $ - ${LUCENE_INCLUDE_DIRS} - ${MOUNT_INCLUDE_DIRS} - ${GLIB_INCLUDE_DIRS} - ${GIO_INCLUDE_DIRS} - ${GIO_UNIX_INCLUDE_DIRS} - ${GMODULE_INCLUDE_DIRS} - ${Qt${QT_VERSION_MAJOR}Core_INCLUDE_DIRS} -) - -target_link_libraries(${PROJECT_NAME} PUBLIC - ${LUCENE_LIBRARIES} - ${LUCENE_CONTRIB_LIBRARIES} - ${MOUNT_LIBRARIES} - ${Boost_LIBRARIES} - pthread - stdc++fs - spdlog::spdlog - ${GLIB_LIBRARIES} - ${GIO_LIBRARIES} - ${GIO_UNIX_LIBRARIES} - ${GMODULE_LIBRARIES} - Qt${QT_VERSION_MAJOR}::Core - deepin-anything-dispatcher -) - -target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Werror -Wextra) -target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17) - -target_link_options(${PROJECT_NAME} PRIVATE -pie) - -configure_file ("${PROJECT_NAME}.pc.in" "${PROJECT_NAME}.pc" @ONLY) -install(TARGETS ${PROJECT_NAME} DESTINATION libexec) -install(FILES deepin-anything-daemon.service DESTINATION lib/systemd/user) - -# Install dconfig meta file -install(FILES ${CMAKE_SOURCE_DIR}/assets/org.deepin.anything.json DESTINATION share/dsg/configs/org.deepin.anything) diff --git a/src/daemon/deepin-anything-daemon.pc.in b/src/daemon/deepin-anything-daemon.pc.in deleted file mode 100755 index 9368d37f..00000000 --- a/src/daemon/deepin-anything-daemon.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=${prefix} -libdir=${prefix}/lib/@HOST_MULTIARCH@ -includedir=${prefix}/include/@PROJECT_NAME@ - -Name: @PROJECT_NAME@ -Description: Deepin Anything Daemon -Version: @PROJECT_VERSION@ -Requires: libnl-genl-3 liblucene++ lucene++-contrib libfmt -Libs: -l@PROJECT_NAME@ -Cflags: -I${includedir} \ No newline at end of file diff --git a/src/daemon/deepin-anything-daemon.service b/src/daemon/deepin-anything-daemon.service deleted file mode 100755 index 5d7a3106..00000000 --- a/src/daemon/deepin-anything-daemon.service +++ /dev/null @@ -1,11 +0,0 @@ -[Unit] -Description=Deepin anything daemon service -After=udisks2.service - -[Service] -ExecStart=/usr/libexec/deepin-anything-daemon -Restart=on-failure -RestartSec=30 -TimeoutStopSec=3 -MemoryHigh=2G -MemoryMax=3G diff --git a/src/daemon/include/analyzers/AnythingAnalyzer.h b/src/daemon/include/analyzers/AnythingAnalyzer.h deleted file mode 100644 index 0a165d34..00000000 --- a/src/daemon/include/analyzers/AnythingAnalyzer.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef ANYTHING_ANYTHING_ANALYZER_H_ -#define ANYTHING_ANYTHING_ANALYZER_H_ - -#include -#include - -#include "common/anything_fwd.hpp" - -ANYTHING_NAMESPACE_BEGIN - -using namespace Lucene; - -class AnythingAnalyzer : public Analyzer { -public: - TokenStreamPtr tokenStream(const String&, const ReaderPtr& reader) override; - - TokenStreamPtr reusableTokenStream(const String&, const ReaderPtr& reader) override; - - template - static void forEachTerm(const String& str, Func callback) { - AnalyzerPtr analyzer = newLucene(); - TokenStreamPtr tokenStream = analyzer->tokenStream(L"", newLucene(str)); - while (tokenStream->incrementToken()) { - callback(tokenStream->getAttribute()->term()); - } - } -}; - -class AnythingAnalyzerSavedStreams : public LuceneObject { -public: - virtual ~AnythingAnalyzerSavedStreams(); - - LUCENE_CLASS(AnythingAnalyzerSavedStreams); - -public: - TokenizerPtr source; - TokenStreamPtr result; -}; - -ANYTHING_NAMESPACE_END - -#endif // ANYTHING_ANYTHING_ANALYZER_H_ \ No newline at end of file diff --git a/src/daemon/include/analyzers/AnythingFilter.h b/src/daemon/include/analyzers/AnythingFilter.h deleted file mode 100644 index a20173df..00000000 --- a/src/daemon/include/analyzers/AnythingFilter.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef ANYTHING_ANYTHING_FILTER_H_ -#define ANYTHING_ANYTHING_FILTER_H_ - -#include - -#include "common/anything_fwd.hpp" - -ANYTHING_NAMESPACE_BEGIN - -using namespace Lucene; - -class AnythingFilter : public TokenFilter { -public: - AnythingFilter(const TokenStreamPtr& input); - - bool incrementToken() override; - -private: - HashSet stopTable_; - TermAttributePtr termAtt_; - - static const wchar_t* STOP_WORDS[]; -}; - -ANYTHING_NAMESPACE_END - -#endif // ANYTHING_ANYTHING_FILTER_H_ \ No newline at end of file diff --git a/src/daemon/include/analyzers/AnythingTokenizer.h b/src/daemon/include/analyzers/AnythingTokenizer.h deleted file mode 100644 index b7b4bda9..00000000 --- a/src/daemon/include/analyzers/AnythingTokenizer.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef ANYTHING_ANYTHING_TOKENIZER_H_ -#define ANYTHING_ANYTHING_TOKENIZER_H_ - -#include - -#include - -#include "common/anything_fwd.hpp" - -ANYTHING_NAMESPACE_BEGIN - -using namespace Lucene; - -class AnythingTokenizer : public Tokenizer { -public: - AnythingTokenizer(const ReaderPtr& input); - - void initialize() override; - bool incrementToken() override; - void end() override; - void reset() override; - void reset(const ReaderPtr& input) override; - -private: - void push(wchar_t c); - bool flush(); - -public: - static bool isSymbol(wchar_t c); - static bool isPreservedSymbol(wchar_t c); - static bool isDot(wchar_t c); - static bool isLastDot(wchar_t c, int32_t offset, std::wstring buf); - bool is_word(wchar_t* buf, int32_t len); - -private: - /// word offset, used to imply which character(in) is parsed - int32_t offset_; - - /// the index used only for ioBuffer - int32_t bufferIndex_; - - /// data length - int32_t dataLen_; - - /// character buffer, store the characters which are used to compose the returned Token - CharArray buffer_; - - /// I/O buffer, used to store the content of the input (one of the members of Tokenizer) - CharArray ioBuffer_; - - TermAttributePtr termAtt_; - OffsetAttributePtr offsetAtt_; - - int32_t length_; - int32_t start_; - - std::unordered_set words_; -}; - -ANYTHING_NAMESPACE_END - -#endif // ANYTHING_ANYTHING_TOKENIZER_H_ \ No newline at end of file diff --git a/src/daemon/include/analyzers/LowerCaseNGramAnalyzer.h b/src/daemon/include/analyzers/LowerCaseNGramAnalyzer.h deleted file mode 100644 index d9706b49..00000000 --- a/src/daemon/include/analyzers/LowerCaseNGramAnalyzer.h +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef ANYTHING_LOWERCASE_NGRAM_ANALYZER_H_ -#define ANYTHING_LOWERCASE_NGRAM_ANALYZER_H_ - -#include - -#include "common/anything_fwd.hpp" - -ANYTHING_NAMESPACE_BEGIN - -using namespace Lucene; - -class LowerCaseNGramAnalyzer : public Analyzer { -public: - LowerCaseNGramAnalyzer(int32_t minGram, int32_t maxGram); - ~LowerCaseNGramAnalyzer() override; - - TokenStreamPtr tokenStream(const String &fieldName, - const ReaderPtr &reader) override; - TokenStreamPtr reusableTokenStream(const String &fieldName, - const ReaderPtr &reader) override; - -private: - int32_t m_minGram; - int32_t m_maxGram; -}; - -namespace { - -class LowerCaseNGramTokenStreams : public LuceneObject -{ -public: - LowerCaseNGramTokenStreams(const ReaderPtr &reader, int32_t minGram, int32_t maxGram) - : source(newLucene(reader, minGram, maxGram)), - result(newLucene(source)) - { - } - - NGramTokenizerPtr source; - TokenStreamPtr result; -}; - -} // namespace - -ANYTHING_NAMESPACE_END - -#endif // ANYTHING_LOWERCASE_NGRAM_ANALYZER_H_ diff --git a/src/daemon/include/anything.hpp b/src/daemon/include/anything.hpp deleted file mode 100644 index 1d4c4863..00000000 --- a/src/daemon/include/anything.hpp +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef ANYTHING_ANYTHING_HPP_ -#define ANYTHING_ANYTHING_HPP_ - -#include "core/default_event_handler.h" -#include "core/event_listener.h" -#include "utils/log.h" - -#endif // ANYTHING_ANYTHING_HPP_ \ No newline at end of file diff --git a/src/daemon/include/common/anything_fwd.hpp b/src/daemon/include/common/anything_fwd.hpp deleted file mode 100644 index 522906c7..00000000 --- a/src/daemon/include/common/anything_fwd.hpp +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef ANYTHING_FWD_HPP_ -#define ANYTHING_FWD_HPP_ - -#ifndef ANYTHING_NAMESPACE_BEGIN -#define ANYTHING_NAMESPACE_BEGIN \ - namespace anything \ - { -#endif - -#ifndef ANYTHING_NAMESPACE_END -#define ANYTHING_NAMESPACE_END \ - } // namespace anything -#endif - -#endif // ANYTHING_FWD_HPP_ \ No newline at end of file diff --git a/src/daemon/include/common/fs_event.h b/src/daemon/include/common/fs_event.h deleted file mode 100644 index 1483219a..00000000 --- a/src/daemon/include/common/fs_event.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef ANYTHING_FS_EVENT_H_ -#define ANYTHING_FS_EVENT_H_ - -#include - -#define MAX_PATH_LEN 4096 - -G_BEGIN_DECLS - -struct fs_event { - uint8_t act; - uint32_t cookie; - char src[MAX_PATH_LEN]; - char dst[MAX_PATH_LEN]; -}; - -typedef struct fs_event fs_event; - -G_END_DECLS - -#endif // ANYTHING_FS_EVENT_H_ diff --git a/src/daemon/include/common/vfs_genl.h b/src/daemon/include/common/vfs_genl.h deleted file mode 100644 index 439d08ff..00000000 --- a/src/daemon/include/common/vfs_genl.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef VFS_GENL_H -#define VFS_GENL_H - -/* protocol family */ -#define VFSMONITOR_FAMILY_NAME "vfsmonitor" - -/* attributes */ -enum { - VFSMONITOR_A_UNSPEC, - VFSMONITOR_A_ACT, - VFSMONITOR_A_COOKIE, - VFSMONITOR_A_MAJOR, - VFSMONITOR_A_MINOR, - VFSMONITOR_A_PATH, - __VFSMONITOR_A_MAX, -}; -#define VFSMONITOR_A_MAX (__VFSMONITOR_A_MAX - 1) - -/* commands */ -enum { - VFSMONITOR_C_UNSPEC, - VFSMONITOR_C_NOTIFY, - __VFSMONITOR_C_MAX, -}; -#define VFSMONITOR_C_MAX (__VFSMONITOR_C_MAX - 1) - -/* multicast group */ -#define VFSMONITOR_MCG_DENTRY_NAME VFSMONITOR_FAMILY_NAME "_de" - -#endif \ No newline at end of file diff --git a/src/daemon/include/core/base_event_handler.h b/src/daemon/include/core/base_event_handler.h deleted file mode 100755 index def56b53..00000000 --- a/src/daemon/include/core/base_event_handler.h +++ /dev/null @@ -1,104 +0,0 @@ -// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef ANYTHING_BASE_EVENT_HANDLER_H_ -#define ANYTHING_BASE_EVENT_HANDLER_H_ - -#include -#include -#include - -#include "common/anything_fwd.hpp" -#include "common/fs_event.h" -#include "core/file_index_manager.h" -#include "core/thread_pool.h" -#include "core/config.h" - -ANYTHING_NAMESPACE_BEGIN - -enum class index_job_type : char { - add, remove, update, scan, recursive_update, init_scan, refresh, - commit_volatile_index, - commit_persistent_index -}; - -struct index_job { - std::string src; - std::optional dst; - index_job_type type; - - index_job(std::string src, index_job_type type, std::optional dst = std::nullopt) - : src(std::move(src)), dst(std::move(dst)), type(type) {} -}; - -ANYTHING_NAMESPACE_END - -class base_event_handler -{ -public: - base_event_handler(const event_handler_config &config); - virtual ~base_event_handler(); - - virtual void handle(fs_event *event) = 0; - virtual void start_handle_init_scan(const std::string &path) = 0; - - void terminate_processing(); - void set_index_invalid_and_restart(); - virtual bool handle_config_change(const std::string &key, const event_handler_config &new_config); - - static gboolean trigger_commit_persistent_index(base_event_handler *handler); - -protected: - void set_batch_size(std::size_t size); - - void add_index_delay(std::string path); - void remove_index_delay(std::string path); - void update_index_delay(std::string src, std::string dst); - void update_index_delay(std::string path); - void scan_index_delay(std::string path); - void recursive_update_index_delay(std::string src, std::string dst); - void init_scan_index_delay(std::string path); - void refresh_indexes(); - void init_refresh_scan_indexes(std::vector& index_dirs); - -private: - void eat_jobs(std::vector& jobs, std::size_t number); - void eat_job(const anything::index_job& job); - void check_jobs_load(); - - void jobs_push(std::string src, anything::index_job_type type, std::optional dst = std::nullopt); - - void timer_worker(int64_t interval); - - bool scan_directory(const std::string& dir_path, std::function handler); - - // 防止竞态条件 - std::vector get_blacklist_paths(); - void set_blacklist_paths(const std::vector &paths); - -private: - event_handler_config config_; - anything::file_index_manager index_manager_; - std::size_t batch_size_; - std::vector jobs_; - anything::thread_pool pool_; - GCancellable *cancellable_; - std::mutex jobs_mtx_; - std::thread timer_; - - bool index_dirty_; - int commit_volatile_index_timeout_; - - anything::index_status index_status_; - - std::atomic stop_scan_directory_; - - std::mutex config_access_mtx_; - - gint batch_count_; - - bool wait_commit_persistent_index_; -}; - -#endif // ANYTHING_BASE_EVENT_HANDLER_H_ diff --git a/src/daemon/include/core/config.h b/src/daemon/include/core/config.h deleted file mode 100755 index a5cb92bb..00000000 --- a/src/daemon/include/core/config.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) 2025 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef CORE_CONFIG_H -#define CORE_CONFIG_H - -#include -#include -#include -#include -#include - -struct event_handler_config { - std::string persistent_index_dir; - std::string volatile_index_dir; - std::vector blacklist_paths; - std::vector indexing_paths; - std::map file_type_mapping; - std::map file_type_mapping_original; - int commit_volatile_index_timeout; - int commit_persistent_index_timeout; - int pending_events_trigger_updating; -}; - -void print_event_handler_config(const event_handler_config &config); - - -#define LOG_LEVEL_KEY "log_level" - -class Config { -public: - Config(); - ~Config(); - - // Delete copy constructor and assignment operator - Config(const Config&) = delete; - Config& operator=(const Config&) = delete; - - event_handler_config make_event_handler_config(); - - void set_config_change_handler(std::function config_change_handler); - void notify_config_changed(const std::string &key); - - std::string get_log_level(); - -private: - bool update_config(); - -private: - std::vector blacklist_paths_; - std::vector indexing_paths_; - std::map file_type_mapping_; - std::string log_level_; - int commit_volatile_index_timeout_; - int commit_persistent_index_timeout_; - int pending_events_trigger_updating_; - - void* dbus_connection_; - std::string resource_path_; - std::function config_change_handler_; - int subscription_id_; -}; - -bool is_path_in_blacklist(const std::string& path, const std::vector& blacklist_paths); - -#define APP_RESTART_CODE 1 -#define APP_QUIT_CODE 0 - -void set_app_restart(bool restart); - -int get_app_ret_code(); - -#endif // CORE_CONFIG_H \ No newline at end of file diff --git a/src/daemon/include/core/default_event_handler.h b/src/daemon/include/core/default_event_handler.h deleted file mode 100644 index ee7d9431..00000000 --- a/src/daemon/include/core/default_event_handler.h +++ /dev/null @@ -1,81 +0,0 @@ -// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef ANYTHING_EVENT_HANDLER_H_ -#define ANYTHING_EVENT_HANDLER_H_ - -#include -#include -#include -#include "core/base_event_handler.h" -#include "core/mount_info.h" - -ANYTHING_NAMESPACE_BEGIN - -struct indexing_item { - std::string origin_path; - std::string event_path; - bool different_path; - bool enable; -}; - -struct fs_event_with_full_path { - uint8_t act; - dev_t device_id; - std::string src; - std::string dst; -}; - -class default_event_handler : public base_event_handler { -public: - explicit default_event_handler(const event_handler_config &config); - virtual ~default_event_handler(); - - void handle(fs_event *event) override; - void start_handle_init_scan(const std::string &path) override; - bool handle_config_change(const std::string &key, const event_handler_config &new_config) override; - - void terminate_filter(); -private: - bool is_under_indexing_path(const std::string& path, indexing_item *&indexing_item); - - void convert_event_path_to_origin_path(std::string& path, const indexing_item& item); - - bool is_event_path_blocked(const std::string& path, indexing_item *&indexing_item); - - void filter_event(fs_event *event); - - bool prepare_event(fs_event *fs_evt, fs_event_with_full_path *out); - - static void* event_filter_thread_func(void* data); - - void handle_config_event(); - - bool handle_blacklist_paths_change(const event_handler_config &old_config, const event_handler_config &new_config); - -private: - bool has_saved_from_ = false; - fs_event saved_from_; - bool has_pending_event_ = false; - fs_event pending_event_; - // config_ 使用情况 - // 1. 主线程中实例化时使用 - // 2. 主线程中调用 handle_config_change() 时使用 - // 3. 没有在 event_filter 线程中使用 - // 所以不存在多线程使用的情况 - event_handler_config config_; - std::vector indexing_items_; - std::vector event_path_blocked_list_; - - GAsyncQueue* event_queue_; - GThread* event_filter_thread_; - - MountInfo *mount_info_; - - GAsyncQueue* config_event_queue_; -}; - -ANYTHING_NAMESPACE_END - -#endif // ANYTHING_EVENT_HANDLER_H_ diff --git a/src/daemon/include/core/disk_scanner.h b/src/daemon/include/core/disk_scanner.h deleted file mode 100644 index e4a220b4..00000000 --- a/src/daemon/include/core/disk_scanner.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef ANYTHING_DISK_SCANNER_H_ -#define ANYTHING_DISK_SCANNER_H_ - -#include -#include -#include - -#include "common/anything_fwd.hpp" - -ANYTHING_NAMESPACE_BEGIN - -namespace fs = std::filesystem; - -/// A class to scan mounted disks and perform operations on their files and directories. -struct disk_scanner { - static std::vector scan(const fs::path& root, const std::vector& blacklist_paths); - static bool is_hidden(const fs::path& p); - inline static std::atomic stop_scanning = false; -}; - -ANYTHING_NAMESPACE_END - -#endif // ANYTHING_DISK_SCANNER_H_ \ No newline at end of file diff --git a/src/daemon/include/core/event_listener.h b/src/daemon/include/core/event_listener.h deleted file mode 100644 index a33ed42b..00000000 --- a/src/daemon/include/core/event_listener.h +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef ANYTHING_EVENT_LISTENER_H_ -#define ANYTHING_EVENT_LISTENER_H_ - -#define G_LOG_USE_STRUCTURED -#include - -#include "common/fs_event.h" - -G_BEGIN_DECLS - -typedef struct EventListener EventListener; - -typedef void (*EventListenerCallback)(gpointer user_data, fs_event *event); - -typedef void (*EventListenerQuitCallback)(gpointer user_data); - -EventListener *event_listener_new(EventListenerCallback callback, - EventListenerQuitCallback quit_callback, - gpointer user_data); - -gboolean event_listener_start(EventListener *listener); - -void event_listener_stop(EventListener *listener); - -void event_listener_free(EventListener *listener); - -G_END_DECLS - -#endif // ANYTHING_EVENT_LISTENER_H_ diff --git a/src/daemon/include/core/file_index_manager.h b/src/daemon/include/core/file_index_manager.h deleted file mode 100644 index 30be9d23..00000000 --- a/src/daemon/include/core/file_index_manager.h +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef ANYTHING_FILE_INDEX_MANAGER_H_ -#define ANYTHING_FILE_INDEX_MANAGER_H_ - -#include -#include - -#include - -#include "common/anything_fwd.hpp" -#include "core/pinyin_processor.h" - -ANYTHING_NAMESPACE_BEGIN - -enum class index_status { - loading, - scanning, - monitoring, - updating, - closed, -}; - -class file_index_manager { -public: - explicit file_index_manager(const std::string& persistent_index_dir, - const std::string& volatile_index_dir, - const std::map& file_type_mapping); - ~file_index_manager(); - - /// @brief Add a path to the index. - /// @param path The full path to be added. - bool add_index(const std::string& path); - - /// @brief Remove the path from the index. - /// @param path The full path to be removed. - bool remove_index(const std::string& path); - - /// @brief Removes the old path and inserts the new path into the index. - /// @param old_path The existing path to be removed from the index. - /// @param new_path The new path to be added to the index. - bool update_index(const std::string& old_path, const std::string& new_path); - - /// @brief Update the index for a file that has been written and closed. - /// Skips the update if the target file does not exist. - /// @param path The full path of the modified file. - bool update_index(const std::string& path); - - /// Commit all changes to the index - bool commit(index_status status); - - /// @brief Persist the index to the persistent index directory - void persist_index(); - - // bool indexed() const; - - // void test(const Lucene::String& path); - // void pinyin_test(const std::string& path); - - /// @brief Return the size of the indexed documents. - /// @param nrt If true, returns the near real-time size, reflecting the most recent changes; - /// otherwise, returns the persisted size from the last commit. - /// @return The total number of indexed documents. - int32_t document_size(bool nrt = false); - - /// Return the cache directory of the index. - std::string index_directory() const; - - std::vector traverse_directory(const std::string& path, bool nrt, bool &success); - - /** - * Check if the given file path is already indexed using an exact match search. - * @param path The file path to check. - * @return true if the file path is already indexed, otherwise false. - */ - bool document_exists(const std::string& path, bool only_check_initial_index = false); - - bool refresh_indexes(const std::vector& blacklist_paths, bool nrt, bool check_exist); - - void set_index_invalid(); - - void set_index_updating(); - -private: - /// Refresh the index reader if there are changes - void try_refresh_reader(bool nrt = false); - - /** - * Perform the actual search based on the file path. - * @param exact_match If true, performs an exact match search. Otherwise, performs a fuzzy search - * (it can still perform an exact match, but requires the overhead of using the analyzer). - * @return A collection of the search results. - */ - // Lucene::TopScoreDocCollectorPtr search(const std::string& path, bool exact_match = false, bool nrt = false); - - /** - * Near Real-Time Search - * 在 NRT 模式下,即便这些数据尚未写入磁盘(commit),也可以通过获取一个近实时的 IndexReader 来从内存中读取最新的索引数据 - */ - // Lucene::TopScoreDocCollectorPtr nrt_search(const std::string& path, bool exact_match = false); - - void prepare_index(); - - void check_index_version(); - - void set_index_version(); - - void save_index_status(index_status status); -private: - std::string persistent_index_directory_; - std::string volatile_index_directory_; - Lucene::IndexWriterPtr writer_; - Lucene::SearcherPtr searcher_; - Lucene::SearcherPtr nrt_searcher_; - Lucene::IndexReaderPtr reader_; - Lucene::IndexReaderPtr nrt_reader_; - std::mutex mtx_; - std::mutex reader_mtx_; - pinyin_processor pinyin_processor_; - std::atomic search_cancelled_{false}; - const std::map file_type_mapping_; -}; - -ANYTHING_NAMESPACE_END - -#endif // ANYTHING_FILE_INDEX_MANAGER_H_ \ No newline at end of file diff --git a/src/daemon/include/core/mount_manager.h b/src/daemon/include/core/mount_manager.h deleted file mode 100644 index 282d1bc1..00000000 --- a/src/daemon/include/core/mount_manager.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef ANYTHING_MOUNT_MANAGER_H_ -#define ANYTHING_MOUNT_MANAGER_H_ - -#include -#include -#include -#include - -#include "common/anything_fwd.hpp" - -ANYTHING_NAMESPACE_BEGIN - -#define MKDEV(ma,mi) ((ma)<<8 | (mi)) - - -enum class mountinfo_field { - mount_id = 0, // 挂载点 ID - parent_id = 1, // 父级 ID - major_minor = 2, // 设备号(主:次) - root = 3, // 根路径 - mount_point = 4, // 挂载路径 - mount_options = 5, // 挂载选项 (跳过) - optional_fields = 6, // 挂载选项 (跳过) - shared_id = 7, // 共享 ID (跳过) - separator = 8, // 分隔符 (未解析) - file_system_type = 9, // 文件系统类型 - source_device = 10, // 源设备 (跳过) - fs_options = 11 // 挂载选项 (跳过) -}; - -struct mount_point { - std::string source; - std::string real_device; - std::string target; - std::string root; - std::string type; - dev_t device_id = 0; -}; - - -class mount_manager { -public: - explicit mount_manager(); - - bool update(); - - bool contains_device(unsigned int key) const; - - std::string get_mount_point(unsigned int device) const; - - const std::vector& get_mount_points(); - - ///////////////////////////// - - bool update_mount_points(); - - std::string find_mount_point(const std::string& path, bool hardreal = false); - - bool path_match_type(const std::string& path, const std::string& type); - -private: - bool write_vfs_unnamed_device(const std::string& str); - bool read_vfs_unnamed_device(std::unordered_set& devices); - bool update_vfs_unnamed_device(const std::unordered_set& new_devices); - -private: - std::string mountinfo_path_; - std::unordered_map mounts_; // key: major:minor value: mount point - std::vector mount_points_; -}; - -ANYTHING_NAMESPACE_END - -#endif // ANYTHING_MOUNT_MANAGER_H_ \ No newline at end of file diff --git a/src/daemon/include/core/pinyin_processor.h b/src/daemon/include/core/pinyin_processor.h deleted file mode 100644 index 5076e3a9..00000000 --- a/src/daemon/include/core/pinyin_processor.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef ANYTHING_PINYIN_PROCESSOR_H_ -#define ANYTHING_PINYIN_PROCESSOR_H_ - -#include -#include -#include - -#include "common/anything_fwd.hpp" - -ANYTHING_NAMESPACE_BEGIN - -class pinyin_processor { - using dict_type = std::unordered_map>; -public: - pinyin_processor() = default; - pinyin_processor(const std::string& filename); - - void load_pinyin_dict(const std::string& filename); - - void convert_to_pinyin(const std::string& sentence, std::string& pinyin_full, std::string& pinyin_acronym); - -private: - unsigned int hex_to_dec(const std::string& hex_str); - int get_utf8_char_length(unsigned char c); - std::string remove_tone(const std::string& pinyin); - - std::vector split_utf8_characters(const std::string& sentence); - -private: - dict_type pinyin_dict_; -}; - -ANYTHING_NAMESPACE_END - -#endif // ANYTHING_PINYIN_PROCESSOR_H_ \ No newline at end of file diff --git a/src/daemon/include/core/thread_pool.h b/src/daemon/include/core/thread_pool.h deleted file mode 100644 index 5c148be6..00000000 --- a/src/daemon/include/core/thread_pool.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef ANYTHING_THREAD_POOL_HPP_ -#define ANYTHING_THREAD_POOL_HPP_ - -#include -#include -#include -#include -#include -#include - -#include "common/anything_fwd.hpp" - -ANYTHING_NAMESPACE_BEGIN - -class thread_pool { - using job_type = std::function; -public: - thread_pool(unsigned int num = std::thread::hardware_concurrency()); - - void enqueue_detach(job_type job); - - void wait_for_tasks(); - - bool busy(); - -private: - void thread_loop(); - - bool stop_thread_; - std::mutex mtx_; - std::condition_variable cv_; - std::vector threads_; - std::queue jobs_; -}; - -ANYTHING_NAMESPACE_END - -#endif // ANYTHING_THREAD_POOL_HPP_ \ No newline at end of file diff --git a/src/daemon/include/utils/enum_helper.h b/src/daemon/include/utils/enum_helper.h deleted file mode 100644 index 5eb9c076..00000000 --- a/src/daemon/include/utils/enum_helper.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef ANYTHING_ENUM_HELPER_H_ -#define ANYTHING_ENUM_HELPER_H_ - -#include "common/anything_fwd.hpp" - -ANYTHING_NAMESPACE_BEGIN - -template -constexpr auto to_underlying(E e) noexcept { - return static_cast>(e); -} - -ANYTHING_NAMESPACE_END - -#endif // ANYTHING_ENUM_HELPER_H_ \ No newline at end of file diff --git a/src/daemon/include/utils/log.h b/src/daemon/include/utils/log.h deleted file mode 100644 index 04953136..00000000 --- a/src/daemon/include/utils/log.h +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef ANYTHING_LOG_H_ -#define ANYTHING_LOG_H_ - -// #include -// #include // std::put_time -// #include -// #include -// #include - -#include -#include - -// #include "common/anything_fwd.hpp" -// #include "utils/enum_helper.h" - -// ANYTHING_NAMESPACE_BEGIN - -// namespace log { - -// enum class level : uint8_t { -// debug = 1 << 0, -// info = 1 << 1, -// warning = 1 << 2, -// success = 1 << 3, -// error = 1 << 4, -// all = debug | info | warning | success | error -// }; - -// inline auto level_debug_enabled = false; -// inline auto level_info_enabled = false; -// inline auto level_warning_enabled = false; -// inline auto level_success_enabled = false; -// inline auto level_error_enabled = false; - -// inline auto set_level(level log_level, bool enabled = true) -> void { -// if (enabled) { -// level_debug_enabled |= to_underlying(log_level) & to_underlying(level::debug); -// level_info_enabled |= to_underlying(log_level) & to_underlying(level::info); -// level_warning_enabled |= to_underlying(log_level) & to_underlying(level::warning); -// level_success_enabled |= to_underlying(log_level) & to_underlying(level::success); -// level_error_enabled |= to_underlying(log_level) & to_underlying(level::error); -// } else { -// level_debug_enabled &= ~(to_underlying(log_level) & to_underlying(level::debug)); -// level_info_enabled &= ~(to_underlying(log_level) & to_underlying(level::info)); -// level_warning_enabled &= ~(to_underlying(log_level) & to_underlying(level::warning)); -// level_success_enabled &= ~(to_underlying(log_level) & to_underlying(level::success)); -// level_error_enabled &= ~(to_underlying(log_level) & to_underlying(level::error)); -// } -// } - -// inline auto operator|(level lhs, level rhs) -> level { -// return static_cast(to_underlying(lhs) | to_underlying(rhs)); -// } - -// struct null_buffer : ::std::streambuf { -// int overflow(int c) override { return c; } -// }; - -// class null_stream : public ::std::ostream { -// null_buffer null_buf; -// public: -// null_stream() : ::std::ostream(&null_buf) {} -// }; - -// inline ::std::ostream& log_stream = ::std::cout; -// inline ::std::ofstream log_file; -// inline ::std::string log_file_path; -// inline null_stream null_os; - -// namespace detail { - -// inline void print_pattern_info(std::string_view level_info) { -// auto now = std::chrono::system_clock::now(); -// std::time_t t = std::chrono::system_clock::to_time_t(now); -// std::tm tm = *std::localtime(&t); -// log_stream << "[" << std::put_time(&tm, "%Y-%m-%d %H:%M:%S") << "]" -// << " [" << level_info << "]" << " [Thread " << std::this_thread::get_id() << "] "; -// } - -// } // namespace detail - -// inline void set_output_stream(std::ostream& new_stream) { -// log_stream.rdbuf(new_stream.rdbuf()); -// } - -// inline void set_to_file(std::string path) { -// if (log_file.is_open()) { -// log_file.close(); -// } - -// log_file.open(path, std::ios::out | std::ios::app); -// if (!log_file.is_open()) { -// return; -// } - -// log_file_path = std::move(path); -// log_stream.rdbuf(log_file.rdbuf()); -// } - -// inline ::std::ostream& debug() { -// if (level_debug_enabled) { -// detail::print_pattern_info("DEBUG"); -// return log_stream; -// } - -// return null_os; -// } - -// inline ::std::ostream& info() { -// if (level_info_enabled) { -// detail::print_pattern_info("INFO"); -// return log_stream; -// } - -// return null_os; -// } - -// inline ::std::ostream& warning() { -// if (level_warning_enabled) { -// detail::print_pattern_info("WARNING"); -// return log_stream; -// } - -// return null_os; -// } - -// inline ::std::ostream& success() { -// if (level_success_enabled) { -// detail::print_pattern_info("SUCCESS"); -// return log_stream; -// } - -// return null_os; -// } - -// inline ::std::ostream& error() { -// if (level_error_enabled) { -// detail::print_pattern_info("ERROR"); -// return log_stream; -// } - -// return null_os; -// } - -// //////////////////////////////// -// void customLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg); - -// } // namespace log - -// ANYTHING_NAMESPACE_END - -#endif // ANYTHING_LOG_H_ \ No newline at end of file diff --git a/src/daemon/include/utils/running_flag.h b/src/daemon/include/utils/running_flag.h deleted file mode 100755 index 3a066699..00000000 --- a/src/daemon/include/utils/running_flag.h +++ /dev/null @@ -1,81 +0,0 @@ -// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef RUNNING_FLAG_H_ -#define RUNNING_FLAG_H_ - -/** - * @file running_flag.h - * @brief 守护进程运行状态标志管理模块 - * - * 本模块通过文件标志机制检测守护进程的上一次退出状态: - * - 正常退出:运行标志文件被移除 - * - 异常退出(崩溃/被终止):运行标志文件仍然存在 - * - * 设计原理: - * - 守护进程启动时调用 set_volatile_index_dir() 设置易失性索引目录路径 - * - 守护进程随后调用 detect_last_time_quit_status() 检测并上次的退出状态 - * - 守护进程然后调用 set_running_flag() 创建运行标志文件 - * - 守护进程运行中通过 is_last_time_normal_quit() 获取上次的退出状态 - * - 守护进程正常退出前调用 remove_running_flag() 移除运行标志文件 - */ - -#include - -/** - * @brief 设置易失性索引目录路径 - * @param volatile_index_dir 易失性索引目录的完整路径 - * - * 设置运行标志文件的目标目录。如果目录不存在,后续操作会自动创建。 - * - * @note 必须在其他任何函数之前调用 - * - * @param volatile_index_dir 目录路径,不能为空字符串 - */ -void set_volatile_index_dir(const std::string &volatile_index_dir); - -/** - * @brief 检测守护进程上一次退出的状态 - * - * 通过检查运行标志文件是否存在来判断上一次退出是否正常: - * - 标志文件存在:上一次异常退出(崩溃或被终止) - * - 标志文件不存在:上一次正常退出 - * - * 检测结果缓存到内部状态,可通过 is_last_time_normal_quit() 获取。 - * - * @note 必须先调用 set_volatile_index_dir() 设置目录路径 - */ -void detect_last_time_quit_status(void); - -/** - * @brief 设置运行标志文件 - * - * 在易失性索引目录中创建 "running" 文件,表示守护进程正在运行。 - * 如果目录不存在,会自动创建(包括父目录)。 - * - * @note 必须先调用 set_volatile_index_dir() 设置目录路径 - */ -void set_running_flag(void); - -/** - * @brief 获取上一次退出状态的检测结果 - * @return true 上一次正常退出,false 上一次异常退出 - * - * 返回 detect_last_time_quit_status() 的检测结果。 - * - * @note 必须先调用 detect_last_time_quit_status() 执行检测 - */ -bool is_last_time_normal_quit(void); - -/** - * @brief 移除运行标志文件 - * - * 删除 "running" 标志文件,表示守护进程正常退出。 - * 如果文件不存在,静默跳过不做任何操作。 - * - * @note 应在守护进程正常退出前调用,而不是在异常处理中调用 - */ -void remove_running_flag(void); - -#endif // RUNNING_FLAG_H_ diff --git a/src/daemon/include/utils/string_helper.h b/src/daemon/include/utils/string_helper.h deleted file mode 100644 index df17d479..00000000 --- a/src/daemon/include/utils/string_helper.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef ANYTHING_STRING_HELPER_H_ -#define ANYTHING_STRING_HELPER_H_ - -#include -#include -#include -#include - -#include "common/anything_fwd.hpp" - -#if defined(__cplusplus) && __cplusplus >= 202002L - #define ANYTHING_CONSTEXPR constexpr -#else - #define ANYTHING_CONSTEXPR -#endif - -ANYTHING_NAMESPACE_BEGIN - -namespace string_helper { - -ANYTHING_CONSTEXPR inline auto split(std::string s, const std::string& delimiter) { - std::vector tokens; - size_t pos = 0; - std::string token; - while ((pos = s.find(delimiter)) != std::string::npos) { - token = s.substr(0, pos); - tokens.push_back(token); - s.erase(0, pos + delimiter.length()); - } - - tokens.push_back(s); - return tokens; -} - -ANYTHING_CONSTEXPR inline auto starts_with(const std::string& str, const std::string& prefix) { - return str.rfind(prefix, 0) == 0; -} - -ANYTHING_CONSTEXPR inline auto ends_with(const std::string& path, const std::string& ending) { - if (path.length() >= ending.length()) - return 0 == path.compare(path.length() - ending.length(), ending.length(), ending); - - return false; -} - -ANYTHING_CONSTEXPR inline auto contains(const std::string& str, const std::string& substr) { - return str.find(substr) != std::string::npos; -} - -inline auto contains_invalid_chars(const std::string& path) { - // Set of characters that are not allowed in file paths - std::unordered_set invalid_chars = { ':', '[', ']', '{', '}' }; - return std::any_of(path.begin(), path.end(), [&invalid_chars](char c) { - return invalid_chars.count(c); - }); -} - - ANYTHING_CONSTEXPR inline std::string& trim(std::string& str) { - str.erase(str.find_last_not_of(' ') + 1); - str.erase(0, str.find_first_not_of(' ')); - return str; - } - -} // namespace string_helper - -ANYTHING_NAMESPACE_END - -#endif // ANYTHING_STRING_HELPER_H_ \ No newline at end of file diff --git a/src/daemon/src/analyzers/AnythingAnalyzer.cpp b/src/daemon/src/analyzers/AnythingAnalyzer.cpp deleted file mode 100644 index f9a5c1e9..00000000 --- a/src/daemon/src/analyzers/AnythingAnalyzer.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "analyzers/AnythingAnalyzer.h" - -#include "analyzers/AnythingFilter.h" -#include "analyzers/AnythingTokenizer.h" - -ANYTHING_NAMESPACE_BEGIN - -TokenStreamPtr AnythingAnalyzer::tokenStream( - const String&, const ReaderPtr& reader) { - TokenStreamPtr result = newLucene(reader); - result = newLucene(result); - return result; -} - -TokenStreamPtr AnythingAnalyzer::reusableTokenStream(const String&, const ReaderPtr& reader) { - auto streams(boost::dynamic_pointer_cast(getPreviousTokenStream())); - if (!streams) { - streams = newLucene(); - streams->source = newLucene(reader); - streams->result = newLucene(streams->source); - setPreviousTokenStream(streams); - } else { - streams->source->reset(reader); - } - - return streams->result; -} - -AnythingAnalyzerSavedStreams::~AnythingAnalyzerSavedStreams() {} - -ANYTHING_NAMESPACE_END \ No newline at end of file diff --git a/src/daemon/src/analyzers/AnythingFilter.cpp b/src/daemon/src/analyzers/AnythingFilter.cpp deleted file mode 100644 index dfdbc0d0..00000000 --- a/src/daemon/src/analyzers/AnythingFilter.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "analyzers/AnythingFilter.h" - -#include -#include - -#include "analyzers/AnythingTokenizer.h" - -ANYTHING_NAMESPACE_BEGIN - -const wchar_t* AnythingFilter::STOP_WORDS[] = { - L"and", L"are", L"as", L"at", L"be", L"but", L"by", - L"for", L"if", L"in", L"into", L"is", L"it", - L"no", L"not", L"of", L"on", L"or", L"such", - L"that", L"the", L"their", L"then", L"there", L"these", - L"they", L"this", L"to", L"was", L"will", L"with" -}; - -AnythingFilter::AnythingFilter(const TokenStreamPtr& input) - : TokenFilter(input) { - stopTable_ = HashSet::newInstance(STOP_WORDS, STOP_WORDS + SIZEOF_ARRAY(STOP_WORDS)); - termAtt_ = addAttribute(); -} - -bool AnythingFilter::incrementToken() { - while (input->incrementToken()) { - String text(termAtt_->term()); - - if (!stopTable_.contains(text)) { - if (UnicodeUtil::isLower(text[0]) || UnicodeUtil::isUpper(text[0])) { - // English word/token should be at least 1 character. - if (text.length() >= 1) { - return true; - } - } else if (UnicodeUtil::isOther(text[0]) || UnicodeUtil::isDigit(text[0])) { - // One Chinese character as one Chinese word. - // Chinese word extraction to be added later here. - return true; - } else if (AnythingTokenizer::isDot(text[0])) { - return true; - } else if (AnythingTokenizer::isPreservedSymbol(text[0]) && text.length() > 1) { - return true; - } - } - } - - return false; -} - -ANYTHING_NAMESPACE_END \ No newline at end of file diff --git a/src/daemon/src/analyzers/AnythingTokenizer.cpp b/src/daemon/src/analyzers/AnythingTokenizer.cpp deleted file mode 100755 index 7e725625..00000000 --- a/src/daemon/src/analyzers/AnythingTokenizer.cpp +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "analyzers/AnythingTokenizer.h" - -#include -#include -#include -#include - -#include "utils/log.h" - -#include - -ANYTHING_NAMESPACE_BEGIN - -constexpr int32_t max_word_len = 512; -constexpr int32_t io_buffer_size = 1024; - -AnythingTokenizer::AnythingTokenizer(const ReaderPtr& input) - : Tokenizer(input) { - // load_dictionary("config/dict.utf8", - // [this](std::wstring&& word) { - // words_.insert(word); - // }); -} - -void AnythingTokenizer::initialize() { - offset_ = 0; - bufferIndex_ = 0; - dataLen_ = 0; - buffer_ = CharArray::newInstance(max_word_len); - ioBuffer_ = CharArray::newInstance(io_buffer_size); - length_ = 0; - start_ = 0; - - termAtt_ = addAttribute(); - offsetAtt_ = addAttribute(); -} - -bool AnythingTokenizer::incrementToken() { - clearAttributes(); - - length_ = 0; - start_ = offset_; - bool last_is_en = false; - bool last_is_num = false; - bool last_is_sym = false; - - while (true) { - wchar_t c; - ++offset_; - - if (bufferIndex_ >= dataLen_) { - std::memset(ioBuffer_.get(), 0, ioBuffer_.size() * sizeof(wchar_t)); - dataLen_ = input->read(ioBuffer_.get(), 0, ioBuffer_.size()); - bufferIndex_ = 0; - - // if (dataLen_ != -1) { - // std::wcout << L"Buffer: " << ioBuffer_.get() << " dataLen: " << dataLen_ - // << " ioBuffer size: " << ioBuffer_.size() << L"\n"; - // } - } - - if (dataLen_ == -1) { - --offset_; - return flush(); - } else { - c = ioBuffer_[bufferIndex_++]; - } - - if (UnicodeUtil::isLower(c) || UnicodeUtil::isUpper(c)) { // 字母 - if (last_is_num || last_is_sym) { - --bufferIndex_; - --offset_; - return flush(); - } - - push(c); - if (length_ == max_word_len) { - return flush(); - } - // Read to the end - if (bufferIndex_ >= dataLen_ - 1 && length_ == 1) { - if (c == L'c' || c == L'r' || c == L'a') { - return flush(); - } - } - last_is_en = true; - } else if (UnicodeUtil::isDigit(c)) { // 数字 - if (last_is_en || last_is_sym) { - --bufferIndex_; - --offset_; - return flush(); - } - - push(c); - if (length_ == max_word_len) { - return flush(); - } - last_is_num = true; - } else if (isDot(c)) { - // Detect the version number, for example: v1.0.0 - if (last_is_num && bufferIndex_ < dataLen_ && - UnicodeUtil::isDigit(ioBuffer_[bufferIndex_])) { - push(c); - } else { - if (length_ > 0) { - return flush(); - } - } - } else if (isSymbol(c)) { - // Detect C++ or C#, etc... - if (last_is_en || last_is_sym) { - push(c); - last_is_sym = true; - } else { - if (length_ > 0) { - return flush(); - } - } - } else if (isPreservedSymbol(c)) { - if (length_ > 0) { - --bufferIndex_; - --offset_; - return flush(); - } - push(c); - // return flush(); - } else if (UnicodeUtil::isOther(c)) { - if (length_ > 0) { - --bufferIndex_; - --offset_; - return flush(); - } - push(c); - return flush(); - } else if (length_ > 0) { - return flush(); - } - } -} - -void AnythingTokenizer::end() { - // set final offset - int32_t finalOffset = correctOffset(offset_); - offsetAtt_->setOffset(finalOffset, finalOffset); -} - -void AnythingTokenizer::reset() { - // std::cout << __PRETTY_FUNCTION__ << "\n"; - Tokenizer::reset(); - // input->reset(); - offset_ = 0; - bufferIndex_ = 0; - dataLen_ = 0; -} - -void AnythingTokenizer::reset(const ReaderPtr& input) { - Tokenizer::reset(input); - reset(); -} - -void AnythingTokenizer::push(wchar_t c) { - if (length_ == 0) { - start_ = offset_ - 1; // start of token - } - - buffer_[length_++] = CharFolder::toLower(c); -} - -// 处理当前积累的 token -bool AnythingTokenizer::flush() { - if (length_ > 0) { - termAtt_->setTermBuffer(buffer_.get(), 0, length_); - offsetAtt_->setOffset(correctOffset(start_), correctOffset(start_ + length_)); - std::memset(buffer_.get(), 0, buffer_.size() * sizeof(wchar_t)); - return true; - } - - return false; -} - -bool AnythingTokenizer::isSymbol(wchar_t c) { - return c == L'+' || c == L'#'; -} - -bool AnythingTokenizer::isPreservedSymbol(wchar_t c) { - return c == L'@'; -} - -bool AnythingTokenizer::isDot(wchar_t c) { - return c == L'.'; -} - -bool AnythingTokenizer::isLastDot(wchar_t c, int32_t offset, std::wstring buf) { - if (isDot(c)) { - auto lastDotPosition = buf.find_last_of(L'.'); - if (lastDotPosition != buf.size() - 1) { - return static_cast(offset) == lastDotPosition; - } - } - - return false; -} - -bool AnythingTokenizer::is_word(wchar_t* buf, int32_t len) { - if (auto it = words_.find(std::wstring(buf, len)); it != words_.end()) { - return true; - } - - return false; -} - -ANYTHING_NAMESPACE_END diff --git a/src/daemon/src/analyzers/LowerCaseNGramAnalyzer.cpp b/src/daemon/src/analyzers/LowerCaseNGramAnalyzer.cpp deleted file mode 100644 index e8aedd9d..00000000 --- a/src/daemon/src/analyzers/LowerCaseNGramAnalyzer.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "analyzers/LowerCaseNGramAnalyzer.h" - -#include -#include -#include - -ANYTHING_NAMESPACE_BEGIN - -using namespace Lucene; - -LowerCaseNGramAnalyzer::LowerCaseNGramAnalyzer(int32_t minGram, int32_t maxGram) - : m_minGram(minGram), - m_maxGram(maxGram) -{ -} - -LowerCaseNGramAnalyzer::~LowerCaseNGramAnalyzer() = default; - -TokenStreamPtr LowerCaseNGramAnalyzer::tokenStream(const String &fieldName, - const ReaderPtr &reader) -{ - (void)fieldName; - return newLucene( - newLucene(reader, m_minGram, m_maxGram)); -} - -TokenStreamPtr LowerCaseNGramAnalyzer::reusableTokenStream(const String &fieldName, - const ReaderPtr &reader) -{ - (void)fieldName; - - boost::shared_ptr streams = - boost::dynamic_pointer_cast(getPreviousTokenStream()); - - if (!streams) { - streams = newLucene(reader, m_minGram, m_maxGram); - setPreviousTokenStream(streams); - } else { - streams->source->reset(reader); - } - - return streams->result; -} - -ANYTHING_NAMESPACE_END diff --git a/src/daemon/src/core/base_event_handler.cpp b/src/daemon/src/core/base_event_handler.cpp deleted file mode 100755 index c09b9989..00000000 --- a/src/daemon/src/core/base_event_handler.cpp +++ /dev/null @@ -1,486 +0,0 @@ -// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "core/base_event_handler.h" - -#include "core/disk_scanner.h" -#include "utils/log.h" -#include "utils/string_helper.h" -#include "utils/tools.h" -#include "utils/running_flag.h" - -#include -#include - -#define REFRESH_INDEX_FILE "refresh_index" -#define JOB_BATCH_COUNT_FOR_LIGHT_LOAD 4 - - -static std::string get_refresh_index_path(const std::string &volatile_index_dir) -{ - return volatile_index_dir + "/" + REFRESH_INDEX_FILE; -} - -static bool set_refresh_index_flag(const std::string &volatile_index_dir) -{ - std::string refresh_flag_path = get_refresh_index_path(volatile_index_dir); - - if (g_file_set_contents(refresh_flag_path.c_str(), "", -1, nullptr)) { - spdlog::info("Refresh index flag set successfully at {}", refresh_flag_path); - return true; - } else { - spdlog::warn("Failed to set refresh index flag at {}: {}", refresh_flag_path, - strerror(errno)); - return false; - } -} - -static bool have_refresh_index_flag(const std::string &volatile_index_dir) -{ - return g_file_test(get_refresh_index_path(volatile_index_dir).c_str(), G_FILE_TEST_EXISTS); -} - -static bool remove_refresh_index_flag(const std::string &volatile_index_dir) -{ - std::string refresh_flag_path = get_refresh_index_path(volatile_index_dir); - - if (g_file_test(refresh_flag_path.c_str(), G_FILE_TEST_EXISTS)) { - if (g_unlink(refresh_flag_path.c_str()) != 0) { - spdlog::warn("Failed to remove refresh index flag at {}: {}", refresh_flag_path, - strerror(errno)); - return false; - } else { - spdlog::info("Refresh index flag removed successfully from {}", refresh_flag_path); - return true; - } - } else { - spdlog::debug("Refresh index flag file does not exist at {}, skipping removal", - refresh_flag_path); - return true; - } -} - -base_event_handler::base_event_handler(const event_handler_config &config) - : config_(config), - index_manager_(config_.persistent_index_dir, config_.volatile_index_dir, config_.file_type_mapping), - batch_size_(200), - pool_(1), - cancellable_(g_cancellable_new()), - index_dirty_(false), - commit_volatile_index_timeout_(config_.commit_volatile_index_timeout), - index_status_(anything::index_status::loading), - stop_scan_directory_(false), - batch_count_(0), - wait_commit_persistent_index_(false) { - // 若发现索引数量为空或异常退出, 则设置 refresh_index 标志以触发扫盘逻辑 - // 索引版本号会保存为一条记录 - if (index_manager_.document_size(false) <= 1 || !is_last_time_normal_quit()) { - spdlog::info("Set refresh index flag for empty index or abnormal quit"); - set_refresh_index_flag(config_.volatile_index_dir); - } -} - -base_event_handler::~base_event_handler() { - g_object_unref(cancellable_); -} - -void base_event_handler::terminate_processing() { - g_cancellable_cancel(cancellable_); - stop_scan_directory_ = true; - - if (timer_.joinable()) { - auto thread_id = timer_.get_id(); - timer_.join(); - std::ostringstream oss; - oss << thread_id; - spdlog::info("Timer thread {} has exited", oss.str()); - } - - pool_.wait_for_tasks(); - if (!jobs_.empty()) { - // Eat all jobs - for (auto &&job : jobs_) { - eat_job(std::move(job)); - } - jobs_.clear(); - } -} - -void base_event_handler::set_index_invalid_and_restart() { - spdlog::info("Set index invalid and restart"); - - index_manager_.set_index_invalid(); - - set_app_restart(true); - qApp->quit(); -} - -bool base_event_handler::handle_config_change(const std::string &key, const event_handler_config &new_config) -{ - if (key == "blacklist_paths") { - set_blacklist_paths(new_config.blacklist_paths); - return true; - } else if (key == "pending_events_trigger_updating") { - // 简单数据类型更新不加锁 - spdlog::info("pending_events_trigger_updating updated: {} -> {}", - config_.pending_events_trigger_updating, - new_config.pending_events_trigger_updating); - config_.pending_events_trigger_updating = new_config.pending_events_trigger_updating; - return true; - } else { - spdlog::info("Dynamic updates of config are not supported: {}", key); - return false; - } -} - -gboolean base_event_handler::trigger_commit_persistent_index(base_event_handler *handler) -{ - // 不使用 jobs_push 避免将 index_dirty_ 置为 true - std::lock_guard lock(handler->jobs_mtx_); - spdlog::debug("Push job: commit_persistent_index"); - handler->jobs_.emplace_back("", anything::index_job_type::commit_persistent_index); - return FALSE; -} - -void base_event_handler::set_batch_size(std::size_t size) { - batch_size_ = size; -} - -void base_event_handler::add_index_delay(std::string path) { - jobs_push(std::move(path), anything::index_job_type::add); -} - -void base_event_handler::remove_index_delay(std::string path) { - jobs_push(std::move(path), anything::index_job_type::remove); -} - -void base_event_handler::update_index_delay(std::string src, std::string dst) { - jobs_push(std::move(src), anything::index_job_type::update, std::move(dst)); -} - -void base_event_handler::update_index_delay(std::string path) { - jobs_push(std::move(path), anything::index_job_type::update); -} - -void base_event_handler::scan_index_delay(std::string path) { - jobs_push(std::move(path), anything::index_job_type::scan); -} - -void base_event_handler::recursive_update_index_delay(std::string src, std::string dst) { - jobs_push(std::move(src), anything::index_job_type::recursive_update, std::move(dst)); -} - -void base_event_handler::init_scan_index_delay(std::string path) { - index_status_ = anything::index_status::scanning; - jobs_push(std::move(path), anything::index_job_type::init_scan); -} - -void base_event_handler::refresh_indexes() { - jobs_push("", anything::index_job_type::refresh); -} - -// 启动时按需扫盘 -// 若发现 refresh_index 文件存在, 则扫盘, 扫盘完成后会删除 refresh_index 文件 -// 若发现 refresh_index 文件不存在, 则不扫盘 -void base_event_handler::init_refresh_scan_indexes(std::vector& index_dirs) -{ - if (have_refresh_index_flag(config_.volatile_index_dir)) { - spdlog::info("Found refresh index flag, do index refresh and scan"); - - // init refresh indexes - index_dirty_ = index_manager_.refresh_indexes(get_blacklist_paths(), false, true); - - // add init scan event - for (auto& dir : index_dirs) { - add_index_delay(dir); - init_scan_index_delay(std::move(dir)); - } - // indicate init scan end - init_scan_index_delay(""); - } else { - spdlog::info("No found refresh index flag, skip index refresh and scan"); - - for (const auto& dir : index_dirs) { - start_handle_init_scan(dir); - } - - index_status_ = anything::index_status::monitoring; - - // trigger timer thead save index status - index_dirty_ = true; - } - - timer_ = std::thread(&base_event_handler::timer_worker, this, 1000); -} - -void base_event_handler::eat_jobs(std::vector& jobs, std::size_t number) { - std::vector processing_jobs; - - processing_jobs.insert( - processing_jobs.end(), - std::make_move_iterator(jobs.begin()), - std::make_move_iterator(jobs.begin() + number)); - jobs.erase(jobs.begin(), jobs.begin() + number); - - g_atomic_int_inc(&batch_count_); - pool_.enqueue_detach([this, processing_jobs = std::move(processing_jobs)]() { - for (const auto& job : processing_jobs) { - eat_job(job); - } - g_atomic_int_dec_and_test(&this->batch_count_); - check_jobs_load(); - }); - -} - -void base_event_handler::eat_job(const anything::index_job& job) { - bool ret = false; - - switch (job.type) { - case anything::index_job_type::add: - ret = index_manager_.add_index(job.src); - break; - case anything::index_job_type::remove: - ret = index_manager_.remove_index(job.src); - break; - case anything::index_job_type::update: - if (job.dst) { - ret = index_manager_.update_index(job.src, *job.dst); - } else { - ret = index_manager_.update_index(job.src); - } - break; - case anything::index_job_type::scan: - ret = scan_directory(job.src, [this](const std::string& path) { - return index_manager_.add_index(path); - }); - break; - case anything::index_job_type::recursive_update: - if (job.dst) { - auto src_subitems = index_manager_.traverse_directory(job.src, true, ret); - if (!ret) - break; - - src_subitems.emplace_back(job.src); - - if (job.dst->empty()) { - for (auto const& src : src_subitems) { - ret = index_manager_.remove_index(src); - if (!ret) - break; - } - } else { - size_t event_src_len = job.src.length(); - for (auto const& src : src_subitems) { - std::string dst = src; - dst.replace(0, event_src_len, *job.dst); - ret = index_manager_.update_index(src, dst); - if (!ret) - break; - } - } - } - break; - case anything::index_job_type::init_scan: - if (!job.src.empty()) { - start_handle_init_scan(job.src); - ret = scan_directory(job.src, [this](const std::string& path) { - if (!index_manager_.document_exists(path, true)) - return index_manager_.add_index(path); - else - return true; - }); - } else { - // init scan end - index_status_ = anything::index_status::monitoring; - if (stop_scan_directory_) { - spdlog::info("Not remove refresh index flag for interrupted scan"); - } else { - remove_refresh_index_flag(config_.volatile_index_dir); - } - spdlog::info("Index scan completed"); - // index commit will be triggered by timer - ret = true; - } - break; - case anything::index_job_type::refresh: - index_manager_.refresh_indexes(get_blacklist_paths(), true, false); - ret = true; - break; - case anything::index_job_type::commit_volatile_index: - spdlog::debug("Eat job: commit_volatile_index"); - if (g_atomic_int_get(&batch_count_) <= JOB_BATCH_COUNT_FOR_LIGHT_LOAD) { - // 现在线程池中待处理的任务较少 - if (index_status_ == anything::index_status::updating) - index_status_ = anything::index_status::monitoring; - ret = index_manager_.commit(index_status_); - if (ret) { - if (!wait_commit_persistent_index_) { - wait_commit_persistent_index_ = true; - g_timeout_add_seconds (config_.commit_persistent_index_timeout, - (GSourceFunc)trigger_commit_persistent_index, - this); - } - } else { - spdlog::error("Failed to commit index"); - } - } else { - ret = true; - spdlog::debug("Skip to commit volatile index due to a large number of pending events"); - } - break; - case anything::index_job_type::commit_persistent_index: - spdlog::debug("Eat job: commit_persistent_index"); - index_manager_.persist_index(); - wait_commit_persistent_index_ = false; - ret = true; - break; - default: - spdlog::error("Invalid job type: {}", static_cast(job.type)); - break; - } - - if (!ret) { - spdlog::info("Failed to process job"); - set_index_invalid_and_restart(); - } -} - -void base_event_handler::check_jobs_load() -{ - if ((g_atomic_int_get(&batch_count_)*(int)batch_size_) >= config_.pending_events_trigger_updating && - index_status_ == anything::index_status::monitoring) { - index_status_ = anything::index_status::updating; - index_manager_.set_index_updating(); - spdlog::info("Set index status to updating"); - } -} - -void base_event_handler::jobs_push(std::string src, - anything::index_job_type type, std::optional dst) { - - std::lock_guard lock(jobs_mtx_); - index_dirty_ = true; - jobs_.emplace_back(std::move(src), type, std::move(dst)); - if (jobs_.size() >= batch_size_) { - eat_jobs(jobs_, batch_size_); - } -} - -// Returns: TRUE if the cancellable was cancelled, FALSE if it timed out. -static gboolean -cancellable_wait(GCancellable *cancellable, int cancellable_fd, gint timeout_ms) -{ - if (g_cancellable_is_cancelled(cancellable)) { - return TRUE; - } - - if (cancellable_fd == -1) { - if (timeout_ms >= 0) { - g_usleep(timeout_ms * 1000); - } - return g_cancellable_is_cancelled(cancellable); - } - - GPollFD pfd; - pfd.fd = cancellable_fd; - pfd.events = G_IO_IN; - pfd.revents = 0; - - int ret = g_poll(&pfd, 1, timeout_ms); - - if (ret > 0) { - // cancel event - if (pfd.revents & G_IO_IN) { - return TRUE; - } - } else if (ret == 0) { - // timeout - ; - } else { - // error - spdlog::warn("g_poll() returned an error: %s", g_strerror(errno)); - if (timeout_ms >= 0) { - g_usleep(timeout_ms * 1000); - } - } - - return g_cancellable_is_cancelled(cancellable); -} - -void base_event_handler::timer_worker(int64_t interval) { - int cancellable_fd = g_cancellable_get_fd(cancellable_); - - while(!cancellable_wait(cancellable_, cancellable_fd, (gint)interval)) { - std::lock_guard lock(jobs_mtx_); - - // trigger commit volatile index - if (index_dirty_ && commit_volatile_index_timeout_ > 0) - --commit_volatile_index_timeout_; - if (commit_volatile_index_timeout_ == 0) { - spdlog::debug("Push job: commit_volatile_index"); - jobs_.emplace_back("", anything::index_job_type::commit_volatile_index); - commit_volatile_index_timeout_ = config_.commit_volatile_index_timeout; - index_dirty_ = false; - } - - if (!jobs_.empty()) - eat_jobs(jobs_, jobs_.size()); - } - - if (cancellable_fd != -1) { - g_cancellable_release_fd(cancellable_); - } -} - -bool base_event_handler::scan_directory(const std::string& dir_path, std::function handler) { - spdlog::info("Scanning directory {}", dir_path); - - std::error_code ec; - std::string path; - - try { - // By default, symlinks are not followed - std::filesystem::recursive_directory_iterator dirpos{ dir_path, std::filesystem::directory_options::skip_permission_denied }; - std::vector blacklist_paths = get_blacklist_paths(); - for (auto it = begin(dirpos); it != end(dirpos); ++it) { - path = std::move(it->path().string()); - if (is_path_in_blacklist(path, blacklist_paths) || - !std::filesystem::exists(it->path(), ec)) { - it.disable_recursion_pending(); - continue; - } - - if (!handler(path)) { - spdlog::error("Failed to handle path: {}", path); - return false; - } - - if (stop_scan_directory_) { - spdlog::info("Scanning interrupted"); - return true; - } - } - } catch (std::filesystem::filesystem_error const& e) { - spdlog::error("Failed to scan directory: {}, {}, {}, {}", - e.what(), e.path1().string(), e.path2().string(), e.code().value()); - } - - spdlog::info("Scanning directory {} completed", dir_path); - return true; -} - -std::vector base_event_handler::get_blacklist_paths() -{ - std::lock_guard lock(config_access_mtx_); - - return config_.blacklist_paths; -} - -void base_event_handler::set_blacklist_paths(const std::vector &paths) -{ - std::lock_guard lock(config_access_mtx_); - - config_.blacklist_paths = paths; -} diff --git a/src/daemon/src/core/config.cpp b/src/daemon/src/core/config.cpp deleted file mode 100755 index 17086ee2..00000000 --- a/src/daemon/src/core/config.cpp +++ /dev/null @@ -1,489 +0,0 @@ -// Copyright (C) 2025 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "core/config.h" -#include "spdlog/spdlog.h" -#include "utils/tools.h" -#include "utils/string_helper.h" - -#include -#include -#include -#include -#include - -#define COMMIT_VOLATILE_INDEX_TIMEOUT_DEFAULT 2 -#define COMMIT_VOLATILE_INDEX_TIMEOUT_MIN 1 -#define COMMIT_VOLATILE_INDEX_TIMEOUT_MAX 60 -#define COMMIT_PERSISTENT_INDEX_TIMEOUT_DEFAULT 600 -#define COMMIT_PERSISTENT_INDEX_TIMEOUT_MIN 60 -#define COMMIT_PERSISTENT_INDEX_TIMEOUT_MAX 3600 - -#define PENDING_EVENTS_TRIGGER_UPDATING_DEFAULT (5 * 1000) -#define PENDING_EVENTS_TRIGGER_UPDATING_MIN 200 -#define PENDING_EVENTS_TRIGGER_UPDATING_MAX (100 * 1000) - -void print_event_handler_config(const event_handler_config &config) { - spdlog::info("Persistent index dir: {}", config.persistent_index_dir); - spdlog::info("Volatile index dir: {}", config.volatile_index_dir); - spdlog::info("Blacklist paths:"); - for (const auto& path : config.blacklist_paths) { - spdlog::info(" {}", path); - } - spdlog::info("Indexing paths:"); - for (const auto& path : config.indexing_paths) { - spdlog::info(" {}", path); - } - spdlog::info("File type mapping:"); - for (const auto& [file_type, file_exts] : config.file_type_mapping_original) { - spdlog::info(" {} : {}", file_type, file_exts); - } - spdlog::info("Commit volatile index timeout: {}", config.commit_volatile_index_timeout); - spdlog::info("Commit persistent index timeout: {}", config.commit_persistent_index_timeout); - spdlog::info("Number of events that trigger updating: {}", config.pending_events_trigger_updating); -} - -// 获取dconfig资源路径 -std::string get_dconfig_resource_path(GDBusConnection *connection) { - GError *error = nullptr; - GVariant *result = nullptr; - std::string resource_path; - - // Call the D-Bus method - result = g_dbus_connection_call_sync( - connection, - "org.desktopspec.ConfigManager", // destination - "/", // object path - "org.desktopspec.ConfigManager", // interface - "acquireManager", // method - g_variant_new("(sss)", // parameters - "org.deepin.anything", - "org.deepin.anything", - ""), - G_VARIANT_TYPE("(o)"), // reply type - G_DBUS_CALL_FLAGS_NONE, - 1000, // timeout is 1s - nullptr, - &error - ); - - if (error) { - spdlog::error("D-Bus call failed: {}", error->message); - g_error_free(error); - } else if (result) { - gchar *path = nullptr; - g_variant_get(result, "(o)", &path); - if (path) { - resource_path = path; - g_free(path); - } - g_variant_unref(result); - } - - return resource_path; -} - -// 获取dconfig配置 -GVariant *get_config_value(GDBusConnection *connection, const std::string& resource_path, const std::string& key) { - GError *error = nullptr; - GVariant *result = nullptr; - - // Call the D-Bus method to get config value - result = g_dbus_connection_call_sync( - connection, - "org.desktopspec.ConfigManager", // destination - resource_path.c_str(), // object path - "org.desktopspec.ConfigManager.Manager", // interface - "value", // method - g_variant_new("(s)", key.c_str()), // parameters - G_VARIANT_TYPE("(v)"), // reply type - G_DBUS_CALL_FLAGS_NONE, - 1000, // timeout is 1s - nullptr, - &error - ); - - if (error) { - spdlog::error("D-Bus call failed: {}", error->message); - g_error_free(error); - } - - return result; -} - -std::vector get_config_string_list(GDBusConnection *connection, const std::string& resource_path, const std::string& key) { - GVariant *result = nullptr; - std::vector config_list; - - result = get_config_value(connection, resource_path, key); - if (result) { - GVariant *val = nullptr; - GVariantIter iter; - GVariant *item = nullptr; - gchar *str; - g_variant_get(result, "(v)", &val); - g_variant_iter_init(&iter, val); - while (g_variant_iter_loop(&iter, "v", &item)) { - g_variant_get(item, "s", &str); - config_list.push_back(str); - g_free(str); - } - g_variant_unref(val); - g_variant_unref(result); - } - - return config_list; -} - -std::string get_config_string(GDBusConnection *connection, const std::string& resource_path, const std::string& key) { - GVariant *result = nullptr; - std::string config_value; - - result = get_config_value(connection, resource_path, key); - if (result) { - GVariant *val = nullptr; - gchar *str; - g_variant_get(result, "(v)", &val); - g_variant_get(val, "s", &str); - if (str) { - config_value = str; - g_free(str); - } - g_variant_unref(val); - g_variant_unref(result); - } - - return config_value; -} - -int64_t get_config_int64(GDBusConnection *connection, const std::string& resource_path, const std::string& key) { - GVariant *result = nullptr; - int64_t config_value = 0; - int64_t config_value_int64 = 0; - double config_value_double = 0; - - result = get_config_value(connection, resource_path, key); - if (result) { - GVariant *val = nullptr; - g_variant_get(result, "(v)", &val); - if (g_variant_is_of_type(val, G_VARIANT_TYPE_INT64)) { - g_variant_get(val, "x", &config_value_int64); - config_value = config_value_int64; - } else if (g_variant_is_of_type(val, G_VARIANT_TYPE_DOUBLE)) { - g_variant_get(val, "d", &config_value_double); - config_value = static_cast(config_value_double); - } else { - spdlog::error("Invalid config value type for key: {}", key); - } - g_variant_unref(val); - g_variant_unref(result); - } - - return config_value; -} - - -bool replace_home_dir(std::string& path) { - auto home = g_get_home_dir(); - size_t pos = path.find("$HOME"); - if (pos != std::string::npos) { - path.replace(pos, strlen("$HOME"), home); - return true; - } - return false; -} - -void dconfig_changed (G_GNUC_UNUSED GDBusConnection *connection, - G_GNUC_UNUSED const gchar *sender_name, - G_GNUC_UNUSED const gchar *object_path, - G_GNUC_UNUSED const gchar *interface_name, - G_GNUC_UNUSED const gchar *signal_name, - GVariant *parameters, - gpointer user_data) { - gchar *str; - std::string key; - Config* config = (Config*)user_data; - - g_variant_get(parameters, "(s)", &str); - if (str) { - key = str; - g_free(str); - } - - if (!key.empty()) - config->notify_config_changed(key); -} - -Config::Config() -{ - // 获取dconfig配置 - dbus_connection_ = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, nullptr); - if (!dbus_connection_) { - spdlog::error("Failed to connect to system bus"); - exit(APP_QUIT_CODE); - } - - resource_path_ = get_dconfig_resource_path((GDBusConnection*)dbus_connection_); - if(resource_path_.empty()) { - spdlog::error("Failed to get dconfig resource path"); - exit(APP_QUIT_CODE); - } - - if (!update_config()) { - spdlog::error("Failed to get dconfig config"); - exit(APP_QUIT_CODE); - } - - subscription_id_ = g_dbus_connection_signal_subscribe((GDBusConnection*)dbus_connection_, - "org.desktopspec.ConfigManager", // sender - "org.desktopspec.ConfigManager.Manager", // interface - "valueChanged", // signal - resource_path_.c_str(), // object path - NULL, - G_DBUS_SIGNAL_FLAGS_NONE, - dconfig_changed, - this, - NULL); -} - -Config::~Config() { - g_dbus_connection_signal_unsubscribe((GDBusConnection*)dbus_connection_, subscription_id_); - g_object_unref(dbus_connection_); -} - -static void migrate_index_dir(const std::string& old_dir, const std::string& new_dir) { - std::error_code ec; - - // Skip if new directory already exists - if (std::filesystem::exists(new_dir, ec)) { - return; - } - - // Skip if old directory doesn't exist - if (!std::filesystem::exists(old_dir, ec)) { - return; - } - - spdlog::info("Migrating index from {} to {}", old_dir, new_dir); - - // Create parent directory for new location - auto parent_path = std::filesystem::path(new_dir).parent_path(); - if (!std::filesystem::exists(parent_path, ec)) { - std::filesystem::create_directories(parent_path, ec); - if (ec) { - spdlog::error("Failed to create parent directory {}: {}", parent_path.string(), ec.message()); - return; - } - } - - // Move the directory - std::filesystem::rename(old_dir, new_dir, ec); - if (ec) { - spdlog::error("Failed to migrate index directory: {}", ec.message()); - // If rename fails (e.g., cross-device), try copy and remove - ec.clear(); - std::filesystem::copy(old_dir, new_dir, std::filesystem::copy_options::recursive, ec); - if (ec) { - spdlog::error("Failed to copy index directory: {}", ec.message()); - return; - } - ec.clear(); - std::filesystem::remove_all(old_dir, ec); - if (ec) { - spdlog::warn("Failed to remove old index directory: {}", ec.message()); - } - } - - spdlog::info("Index migration completed successfully"); -} - -event_handler_config Config::make_event_handler_config() -{ - event_handler_config config; - - // Use XDG_DATA_HOME for persistent index storage (instead of XDG_CACHE_HOME) - // This ensures the index survives cache cleaning operations - std::string old_index_dir = std::string(g_get_user_cache_dir()) + "/deepin-anything-server"; - std::string new_index_dir = std::string(g_get_user_data_dir()) + "/deepin-anything-server"; - - // Migrate from old location to new location if needed - migrate_index_dir(old_index_dir, new_index_dir); - - config.persistent_index_dir = new_index_dir; - config.volatile_index_dir = config.persistent_index_dir; - config.blacklist_paths = blacklist_paths_; - config.indexing_paths = indexing_paths_; - config.file_type_mapping_original = file_type_mapping_; - for (const auto& [file_type, file_exts] : file_type_mapping_) { - std::stringstream ss(file_exts); - std::string item; - while (std::getline(ss, item, ';')) { - config.file_type_mapping[item] = file_type; - } - } - config.commit_volatile_index_timeout = commit_volatile_index_timeout_; - config.commit_persistent_index_timeout = commit_persistent_index_timeout_; - config.pending_events_trigger_updating = pending_events_trigger_updating_; - - return config; -} - -void Config::set_config_change_handler(std::function config_change_handler) -{ - config_change_handler_ = config_change_handler; -} - -void Config::notify_config_changed(const std::string &key) -{ - update_config(); - - if (config_change_handler_) - config_change_handler_(key); -} - -std::string Config::get_log_level() -{ - return log_level_; -} - -void process_blacklist_paths(std::vector& blacklist_paths) -{ - std::unordered_set unique_paths; - - for (auto& path : blacklist_paths) { - // remove empty string - if (path.empty()) continue; - - // replace $HOME - replace_home_dir(path); - - // remove empty string - if (path.empty()) continue; - - // If it starts with '/', then canonicalize it - if (path[0] == '/') { - g_autofree gchar *canonical = g_canonicalize_filename(path.c_str(), NULL); - if (!canonical) continue; - path = canonical; - } - - unique_paths.insert(path); - } - - // ensure deepin-anything-server is in blacklist to filter index update event - unique_paths.insert("deepin-anything-server"); - - // ensure .avfs is in blacklist to avoid loop scanning issues. - unique_paths.insert(".avfs"); - - blacklist_paths.assign(unique_paths.begin(), unique_paths.end()); -} - -bool Config::update_config() -{ - indexing_paths_ = get_config_string_list((GDBusConnection*)dbus_connection_, resource_path_, "indexing_paths"); - blacklist_paths_ = get_config_string_list((GDBusConnection*)dbus_connection_, resource_path_, "blacklist_paths"); - std::string app_file_suffix, archive_file_suffix, audio_file_suffix, doc_file_suffix, pic_file_suffix, video_file_suffix; - app_file_suffix = get_config_string((GDBusConnection*)dbus_connection_, resource_path_, "app_file_suffix"); - archive_file_suffix = get_config_string((GDBusConnection*)dbus_connection_, resource_path_, "archive_file_suffix"); - audio_file_suffix = get_config_string((GDBusConnection*)dbus_connection_, resource_path_, "audio_file_suffix"); - doc_file_suffix = get_config_string((GDBusConnection*)dbus_connection_, resource_path_, "doc_file_suffix"); - pic_file_suffix = get_config_string((GDBusConnection*)dbus_connection_, resource_path_, "pic_file_suffix"); - video_file_suffix = get_config_string((GDBusConnection*)dbus_connection_, resource_path_, "video_file_suffix"); - file_type_mapping_ = { - {"app", app_file_suffix}, - {"archive", archive_file_suffix}, - {"audio", audio_file_suffix}, - {"doc", doc_file_suffix}, - {"pic", pic_file_suffix}, - {"video", video_file_suffix}, - }; - if(indexing_paths_.empty() || - app_file_suffix.empty() || - archive_file_suffix.empty() || - audio_file_suffix.empty() || - doc_file_suffix.empty() || - pic_file_suffix.empty() || - video_file_suffix.empty()) { - return false; - } - - process_blacklist_paths(blacklist_paths_); - - for (auto it = indexing_paths_.begin(); it != indexing_paths_.end(); ) { - replace_home_dir(*it); - - // not allow relative path - if (!it->empty() && (*it)[0] != '/') { - it = indexing_paths_.erase(it); - continue; - } - - ++it; - } - - commit_volatile_index_timeout_ = get_config_int64((GDBusConnection*)dbus_connection_, resource_path_, "commit_volatile_index_timeout"); - commit_persistent_index_timeout_ = get_config_int64((GDBusConnection*)dbus_connection_, resource_path_, "commit_persistent_index_timeout"); - if (commit_volatile_index_timeout_ < COMMIT_VOLATILE_INDEX_TIMEOUT_MIN || - commit_volatile_index_timeout_ > COMMIT_VOLATILE_INDEX_TIMEOUT_MAX) { - commit_volatile_index_timeout_ = COMMIT_VOLATILE_INDEX_TIMEOUT_DEFAULT; - } - if (commit_persistent_index_timeout_ < COMMIT_PERSISTENT_INDEX_TIMEOUT_MIN || - commit_persistent_index_timeout_ > COMMIT_PERSISTENT_INDEX_TIMEOUT_MAX) { - commit_persistent_index_timeout_ = COMMIT_PERSISTENT_INDEX_TIMEOUT_DEFAULT; - } - - pending_events_trigger_updating_ = get_config_int64((GDBusConnection*)dbus_connection_, resource_path_, "pending_events_trigger_updating"); - if (pending_events_trigger_updating_ < PENDING_EVENTS_TRIGGER_UPDATING_MIN || - pending_events_trigger_updating_ > PENDING_EVENTS_TRIGGER_UPDATING_MAX) { - pending_events_trigger_updating_ = PENDING_EVENTS_TRIGGER_UPDATING_DEFAULT; - } - - log_level_ = get_config_string((GDBusConnection*)dbus_connection_, resource_path_, LOG_LEVEL_KEY); - - return true; -} - -bool is_path_in_blacklist(const std::string& path, const std::vector& blacklist_paths) -{ - for (const auto& blacklisted_path : blacklist_paths) { - // 检查 blacklisted_path 是否是 path 的一个组件 - size_t last_pos = 0; - while (true) { - size_t pos = path.find(blacklisted_path, last_pos); - if (pos != std::string::npos) { - // 检查前面是否是路径分隔符或开头 - bool is_start = (pos == 0); - bool has_separator_before = (pos > 0 && (path[pos - 1] == '/' || path[pos - 1] == '\\')); - - // 检查后面是否是路径分隔符或结尾 - size_t end_pos = pos + blacklisted_path.length(); - bool is_end = (end_pos == path.length()); - bool has_separator_after = (end_pos < path.length() && (path[end_pos] == '/' || path[end_pos] == '\\')); - - if ((is_start || has_separator_before) && (is_end || has_separator_after)) { - return true; - } - - last_pos = pos + 1; - } else { - break; - } - } - } - return false; -} - -static int app_ret_code = 0; - -void set_app_restart(bool restart) -{ - app_ret_code = restart ? APP_RESTART_CODE : APP_QUIT_CODE; -} - -int get_app_ret_code() -{ - return app_ret_code; -} diff --git a/src/daemon/src/core/default_event_handler.cpp b/src/daemon/src/core/default_event_handler.cpp deleted file mode 100755 index 4e79fe37..00000000 --- a/src/daemon/src/core/default_event_handler.cpp +++ /dev/null @@ -1,543 +0,0 @@ -// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "core/default_event_handler.h" - -#include // std::getenv -#include -#include -#include -#include - -#include "utils/log.h" -#include "utils/string_helper.h" -#include "vfs_change_consts.h" -#include "core/config.h" -#include "utils/tools.h" - -ANYTHING_NAMESPACE_BEGIN - -#define ACT_TERMINATE 100 - -#define ACT_BLACKLIST_ADD_ABSOLUTE_PATH 120 -#define ACT_BLACKLIST_DEL_ABSOLUTE_PATH 121 -#define ACT_BLACKLIST_ADD_OTHER 122 -#define ACT_CONFIG_EVENT_END 130 - - -static std::string determine_blacklist_path(MountInfo *mount_info, const char *path) -{ - std::string ret; - - // process_blacklist_paths ensure no empty path - if (path[0] != '/') { - ret = path; - } else { - if (g_file_test(path, G_FILE_TEST_EXISTS)) { - g_autofree char *event_path = get_full_path(mount_info, path); - if (event_path) { - ret = event_path; - } - } - } - - spdlog::info("Determine blacklist path: \"{}\" -> \"{}\"", path, ret); - - return ret; -} - -// 检查 event_path 与 indexing_items_ 中的 event_path 是否冲突 -bool is_event_path_conflict_with_indexing_items(const std::string& event_path, - const std::vector& indexing_items) { - for (auto& item : indexing_items) { - if (string_helper::starts_with(event_path, item.event_path) || - string_helper::starts_with(item.event_path, event_path)) { - return true; - } - } - return false; -} - -std::string get_event_path(MountInfo *mount_info, const std::string& origin_path, const std::vector& indexing_items) { - std::error_code ec; - if (!std::filesystem::exists(origin_path, ec)) { - spdlog::error("The origin path {} does not exist: {}", origin_path, ec.message()); - return ""; - } - - std::string event_path_str; - char *event_path = get_full_path(mount_info, origin_path.c_str()); - if (event_path == nullptr) { - spdlog::warn("Failed to get event path, use the origin path: {}", origin_path); - event_path_str = origin_path; - } else { - event_path_str = std::string(event_path); - g_free(event_path); - } - - // add "/" to the end of the event_path for simplify the comparison - std::string event_path_with_slash = event_path_str; - if (!string_helper::ends_with(event_path_with_slash, "/")) { - event_path_with_slash += "/"; - } - - if (is_event_path_conflict_with_indexing_items(event_path_with_slash, indexing_items)) { - spdlog::warn("Event path {} conflicts with already configured event paths, skip", event_path_with_slash); - return ""; - } - - return event_path_with_slash; -} - -// /data 和非 data 需要保持一致,最好有一种方式能够获取当前的状态 -default_event_handler::default_event_handler(const event_handler_config &config) - : base_event_handler(config), config_(config) { - event_queue_ = g_async_queue_new(); - event_filter_thread_ = g_thread_new("event_filter", event_filter_thread_func, this); - config_event_queue_ = g_async_queue_new(); - mount_info_ = mount_info_new(); - - // init indexing_items_ - spdlog::info("Processing indexing_paths..."); - for (auto& origin_path : config_.indexing_paths) { - std::string event_path_with_slash = get_event_path(mount_info_, origin_path, indexing_items_); - if (event_path_with_slash.empty()) { - continue; - } - - std::string origin_path_with_slash = origin_path; - if (!string_helper::ends_with(origin_path_with_slash, "/")) { - origin_path_with_slash += "/"; - } - indexing_item item = { - .origin_path = origin_path_with_slash, - .event_path = event_path_with_slash, - .different_path = origin_path_with_slash != event_path_with_slash, - .enable = false - }; - spdlog::info("Determine the event path: {} -> {}", item.origin_path, item.event_path); - - indexing_items_.emplace_back(item); - } - - // init event_path_blocked_list_ - spdlog::info("Processing blacklist_paths..."); - for (auto& path : config_.blacklist_paths) { - std::string event_path = determine_blacklist_path(mount_info_, path.c_str()); - if (event_path.empty()) - continue; - event_path_blocked_list_.emplace_back(event_path); - } - - // index refresh and scan - std::vector index_dirs; - for (const auto& item : indexing_items_) { - std::string scan_path_without_slash = item.origin_path; - if (scan_path_without_slash != "/") { - scan_path_without_slash.pop_back(); - } - index_dirs.push_back(std::move(scan_path_without_slash)); - } - init_refresh_scan_indexes(index_dirs); - - g_autofree gchar *dump = mount_info_dump(mount_info_); - // remove the last "\n" - dump[strlen(dump) - 1] = '\0'; - spdlog::info("{}", dump); -} - -default_event_handler::~default_event_handler() { - mount_info_free(mount_info_); -} - -bool default_event_handler::is_under_indexing_path(const std::string& path, indexing_item *&indexing_item) { - for (auto& item : indexing_items_) { - if (item.enable && string_helper::starts_with(path, item.event_path)) { - indexing_item = &item; - return true; - } - } - return false; -} - -// 将路径中的 /persistent/home/user 替换为 /home/user -void default_event_handler::convert_event_path_to_origin_path(std::string& path, const indexing_item& item) { - if (item.different_path) { - path.replace(0, item.event_path.length(), item.origin_path); - } -} - -bool default_event_handler::is_event_path_blocked(const std::string& path, indexing_item *&indexing_item) { - return !is_under_indexing_path(path, indexing_item) || is_path_in_blacklist(path, event_path_blocked_list_); -} - -void default_event_handler::handle(fs_event *event) { - g_async_queue_push(event_queue_, event); -} - -void default_event_handler::start_handle_init_scan(const std::string &path) { - for (auto& item : indexing_items_) { - if (item.enable) - continue; - - std::string origin_path_without_slash = item.origin_path; - if (origin_path_without_slash != "/") - origin_path_without_slash.pop_back(); - - if (origin_path_without_slash == path) { - item.enable = true; - break; - } - } -} - -bool default_event_handler::prepare_event(fs_event *fs_evt, - fs_event_with_full_path *out) { - out->device_id = 0; - - switch (fs_evt->act) { - case ACT_NEW_FILE: - case ACT_NEW_SYMLINK: - case ACT_NEW_LINK: - case ACT_NEW_FOLDER: - case ACT_DEL_FILE: - case ACT_DEL_FOLDER: - case ACT_CLOSE_WRITE_FILE: - out->act = fs_evt->act; - out->src = fs_evt->src; - out->dst = ""; - break; - case ACT_RENAME_FROM_FILE: - case ACT_RENAME_FROM_FOLDER: - if (!has_saved_from_) { - saved_from_ = *fs_evt; - has_saved_from_ = true; - return false; - } - out->act = (saved_from_.act == ACT_RENAME_FROM_FILE) - ? ACT_RENAME_FILE : ACT_RENAME_FOLDER; - out->src = saved_from_.src; - out->dst = ""; - saved_from_ = *fs_evt; - break; - case ACT_RENAME_TO_FILE: - case ACT_RENAME_TO_FOLDER: - if (!has_saved_from_) { - out->act = (fs_evt->act == ACT_RENAME_TO_FILE) - ? ACT_RENAME_FILE : ACT_RENAME_FOLDER; - out->src = ""; - out->dst = fs_evt->src; - } else if (saved_from_.cookie == fs_evt->cookie) { - out->act = (saved_from_.act == ACT_RENAME_FROM_FILE) - ? ACT_RENAME_FILE : ACT_RENAME_FOLDER; - out->src = saved_from_.src; - out->dst = fs_evt->src; - has_saved_from_ = false; - } else { - out->act = (saved_from_.act == ACT_RENAME_FROM_FILE) - ? ACT_RENAME_FILE : ACT_RENAME_FOLDER; - out->src = saved_from_.src; - out->dst = ""; - has_saved_from_ = false; - pending_event_ = *fs_evt; - has_pending_event_ = true; - } - break; - default: - spdlog::warn("Unknown file action: {}", +fs_evt->act); - return false; - } - - return true; -} - -void default_event_handler::filter_event(fs_event *fs_evt) { - [[maybe_unused]] const char* act_names[] = { - "file_created", "link_created", "symlink_created", "dir_created", - "file_deleted", "dir_deleted", - "file_renamed", "dir_renamed", "file_renamed_from", "file_renamed_to", "dir_renamed_from", "dir_renamed_to", - "mount", "unmount", - "file_close_write" }; - - fs_event_with_full_path event; - if (!prepare_event(fs_evt, &event)) - return; - - spdlog::debug("Received event: {} {} {}", act_names[event.act], event.src, event.dst); - - // Preparations are done, starting to process the event. - - indexing_item *src_indexing_item = nullptr; - indexing_item *dst_indexing_item = nullptr; - if (event.act != ACT_RENAME_FILE && - event.act != ACT_RENAME_FOLDER && - is_event_path_blocked(event.src, src_indexing_item)) { - return; - } - - if (event.act == ACT_NEW_FILE || event.act == ACT_NEW_SYMLINK || - event.act == ACT_NEW_LINK || event.act == ACT_NEW_FOLDER) { - // Do not check for the existence of files; we trust the kernel module. - convert_event_path_to_origin_path(event.src, *src_indexing_item); - add_index_delay(std::move(event.src)); - } else if (event.act == ACT_CLOSE_WRITE_FILE) { - convert_event_path_to_origin_path(event.src, *src_indexing_item); - update_index_delay(std::move(event.src)); - } else if (event.act == ACT_DEL_FILE || event.act == ACT_DEL_FOLDER) { - convert_event_path_to_origin_path(event.src, *src_indexing_item); - remove_index_delay(std::move(event.src)); - } else if (event.act == ACT_RENAME_FILE) { - bool isSrcBlocked = is_event_path_blocked(event.src, src_indexing_item); - bool isDstBlocked = is_event_path_blocked(event.dst, dst_indexing_item); - - if (isSrcBlocked && isDstBlocked) { - return; - } else if (isSrcBlocked) { - convert_event_path_to_origin_path(event.dst, *dst_indexing_item); - add_index_delay(std::move(event.dst)); - } else if (isDstBlocked) { - convert_event_path_to_origin_path(event.src, *src_indexing_item); - remove_index_delay(std::move(event.src)); - } else { - convert_event_path_to_origin_path(event.src, *src_indexing_item); - convert_event_path_to_origin_path(event.dst, *dst_indexing_item); - update_index_delay(std::move(event.src), std::move(event.dst)); - } - } else if (event.act == ACT_RENAME_FOLDER) { - // Rename all files/folders in this folder(including this folder) - bool isSrcBlocked = is_event_path_blocked(event.src, src_indexing_item); - bool isDstBlocked = is_event_path_blocked(event.dst, dst_indexing_item); - - if (isSrcBlocked && isDstBlocked) { - return; - } - - if (isSrcBlocked) { - convert_event_path_to_origin_path(event.dst, *dst_indexing_item); - add_index_delay(event.dst); - scan_index_delay(std::move(event.dst)); - return; - } - - convert_event_path_to_origin_path(event.src, *src_indexing_item); - if (!isDstBlocked) { - convert_event_path_to_origin_path(event.dst, *dst_indexing_item); - } else { - event.dst.clear(); - } - recursive_update_index_delay(std::move(event.src), std::move(event.dst)); - } -} - -void default_event_handler::terminate_filter() { - fs_event* event = g_slice_new(fs_event); - event->act = ACT_TERMINATE; - g_async_queue_push(event_queue_, event); - g_thread_join(event_filter_thread_); - spdlog::info("Event filter thread terminated"); - g_async_queue_unref(event_queue_); - g_async_queue_unref(config_event_queue_); -} - -void* default_event_handler::event_filter_thread_func(void* data) { - auto handler = static_cast(data); - while (true) { - // If no file event is processed within 3 seconds, check the config event. - fs_event* event = (fs_event*)g_async_queue_timeout_pop(handler->event_queue_, 3 * 1000 * 1000); - if (!event) { - handler->handle_config_event(); - continue; - } - if (event->act == ACT_TERMINATE) { - g_slice_free(fs_event, event); - break; - } - handler->filter_event(event); - g_slice_free(fs_event, event); - - while (handler->has_pending_event_) { - handler->has_pending_event_ = false; - handler->filter_event(&handler->pending_event_); - } - } - - return NULL; -} - -static void get_string_list_diff(const std::vector &olds, - const std::vector &news, - std::vector *adds, - std::vector *dels) -{ - if (adds) { - adds->clear(); - std::unordered_set old_set(olds.begin(), olds.end()); - for (const auto& s : news) { - if (old_set.find(s) == old_set.end()) { - adds->push_back(s); - } - } - } - - if (dels) { - dels->clear(); - std::unordered_set new_set(news.begin(), news.end()); - for (const auto& s : olds) { - if (new_set.find(s) == new_set.end()) { - dels->push_back(s); - } - } - } -} - -static bool is_all_absolute_path(const std::vector &paths) -{ - for (const auto& path : paths) { - // process_blacklist_paths ensure no empty path - if (path[0] != '/') { - return false; - } - } - return true; -} - -static void push_config_event(GAsyncQueue *queue, uint8_t act, const char* path) -{ - fs_event* event = g_slice_new(fs_event); - - event->act = act; - strncpy(event->src, path, MAX_PATH_LEN-1); - if (event->src[MAX_PATH_LEN-2] != '\0') { - spdlog::warn("File path is too long: {}", path); - g_slice_free(fs_event, event); - return; - } - - g_async_queue_push(queue, event); -} - -bool default_event_handler::handle_blacklist_paths_change(const event_handler_config &old_config, const event_handler_config &new_config) -{ - std::vector adds, dels; - get_string_list_diff(old_config.blacklist_paths, - new_config.blacklist_paths, - &adds, - &dels); - - if (!dels.empty() && !is_all_absolute_path(dels)) { - spdlog::info("Found non-absolute paths were removed from the blacklist"); - return false; - } - - if (!adds.empty()) { - uint8_t act = is_all_absolute_path(adds) ? ACT_BLACKLIST_ADD_ABSOLUTE_PATH : ACT_BLACKLIST_ADD_OTHER; - for (const auto& path : adds) { - push_config_event(config_event_queue_, act, path.c_str()); - } - } - - if (!dels.empty()) { - for (const auto& path : dels) { - push_config_event(config_event_queue_, ACT_BLACKLIST_DEL_ABSOLUTE_PATH, path.c_str()); - } - } - - // indicate the end of the events - if (!adds.empty() || !dels.empty()) { - push_config_event(config_event_queue_, ACT_CONFIG_EVENT_END, ""); - } else { - spdlog::info("No valid config updates found"); - } - - return true; -} - -bool default_event_handler::handle_config_change(const std::string &key, const event_handler_config &new_config) -{ - if (!base_event_handler::handle_config_change(key, new_config)) - return false; - - bool handled = (key == "blacklist_paths" && handle_blacklist_paths_change(config_, new_config)) || - key == "pending_events_trigger_updating"; // 不需额外处理 - - if (handled) - config_ = new_config; - - return handled; -} - -void default_event_handler::handle_config_event() -{ - bool do_refresh_index = false; - bool run = true; - - if (g_async_queue_length(config_event_queue_) <= 0) - return; - - spdlog::info("Handling config events..."); - - while (run) { - fs_event* event = (fs_event*)g_async_queue_pop(config_event_queue_); - - if (event->act == ACT_BLACKLIST_ADD_ABSOLUTE_PATH) { - // add black list path - std::string path = determine_blacklist_path(mount_info_, event->src); - if (!path.empty()) { - event_path_blocked_list_.emplace_back(path); - - // del index under the path - recursive_update_index_delay(event->src, ""); - spdlog::info("Handled config event: ACT_BLACKLIST_ADD_ABSOLUTE_PATH, {}", event->src); - } else { - spdlog::info("Skipped config event: ACT_BLACKLIST_ADD_ABSOLUTE_PATH, {}", event->src); - } - } else if (event->act == ACT_BLACKLIST_DEL_ABSOLUTE_PATH) { - // del black list path - std::string path = determine_blacklist_path(mount_info_, event->src); - if (!path.empty()) { - for (auto it = event_path_blocked_list_.begin(); it != event_path_blocked_list_.end(); ++it) { - if (*it == path) { - event_path_blocked_list_.erase(it); - break; - } - } - - // scan index under the path - add_index_delay(event->src); - scan_index_delay(event->src); - spdlog::info("Handled config event: ACT_BLACKLIST_DEL_ABSOLUTE_PATH, {}", event->src); - } else { - spdlog::info("Skipped config event: ACT_BLACKLIST_DEL_ABSOLUTE_PATH, {}", event->src); - } - - } else if (event->act == ACT_BLACKLIST_ADD_OTHER) { - // add black list path - std::string path = determine_blacklist_path(mount_info_, event->src); - if (!path.empty()) { - event_path_blocked_list_.emplace_back(path); - - // do refresh at last - do_refresh_index = true; - spdlog::info("Handled config event: ACT_BLACKLIST_ADD_OTHER, {}", event->src); - } else { - spdlog::info("Skipped config event: ACT_BLACKLIST_ADD_OTHER, {}", event->src); - } - } else { - // ACT_CONFIG_EVENT_END - run = false; - spdlog::info("Handled config event: ACT_CONFIG_EVENT_END"); - } - - g_slice_free(fs_event, event); - } - - if (do_refresh_index) { - refresh_indexes(); - spdlog::info("Refreshed indexes"); - } - - spdlog::info("Handled config events"); -} - -ANYTHING_NAMESPACE_END diff --git a/src/daemon/src/core/disk_scanner.cpp b/src/daemon/src/core/disk_scanner.cpp deleted file mode 100755 index 9c4a1eaa..00000000 --- a/src/daemon/src/core/disk_scanner.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "core/disk_scanner.h" - -#include - -#include - -#include "utils/log.h" -#include "core/config.h" - -ANYTHING_NAMESPACE_BEGIN - -std::vector disk_scanner::scan(const fs::path& root, const std::vector& blacklist_paths) { - spdlog::info("Scanning {}...", root.string()); - std::vector records; - // By default, symlinks are not followed - fs::recursive_directory_iterator dirpos{ root, fs::directory_options::skip_permission_denied }; - std::error_code ec; - for (auto it = begin(dirpos); it != end(dirpos); ++it) { - if (is_path_in_blacklist(it->path().string(), blacklist_paths) || - !std::filesystem::exists(it->path(), ec)) { - it.disable_recursion_pending(); - continue; - } - - records.push_back(it->path().string()); - - if (disk_scanner::stop_scanning) { - spdlog::info("Scanning interrupted"); - return records; - } - } - - spdlog::info("Scanning {} completed", root.string()); - return records; -} - -bool disk_scanner::is_hidden(const fs::path& p) { - auto filename = p.filename().string(); - return filename == ".." || filename == "." || filename[0] == '.'; -} - -ANYTHING_NAMESPACE_END diff --git a/src/daemon/src/core/event_listener.cpp b/src/daemon/src/core/event_listener.cpp deleted file mode 100644 index a2b642dc..00000000 --- a/src/daemon/src/core/event_listener.cpp +++ /dev/null @@ -1,397 +0,0 @@ -// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "core/event_listener.h" - -#include - -#include - -#include "event_dispatcher.h" -#include "utils/log.h" - -#define DISPATCHER_SOCKET_PATH "/run/deepin-anything/event-dispatcher.sock" -#define RECONNECT_DELAY_MS 10000 /* 10s delay to ride out event bursts */ -#define MAX_RECONNECT_ATTEMPTS 30 /* give up and quit after this many fails */ - -struct EventListener { - EventReceiver *receiver; - GMainLoop *loop; - GMainContext *context; - GThread *thread; - EventListenerCallback callback; - EventListenerQuitCallback quit_callback; - gpointer user_data; - guint fd_source_id; - guint reconnect_timer_id; - gint reconnect_attempts; - - GMutex startup_mutex; - GCond startup_cond; - volatile gint started; /* 0 = pending, 1 = success, -1 = failure */ -}; - -static void signal_startup(EventListener *listener, gboolean success) -{ - g_mutex_lock(&listener->startup_mutex); - g_atomic_int_set(&listener->started, success ? 1 : -1); - g_cond_signal(&listener->startup_cond); - g_mutex_unlock(&listener->startup_mutex); -} - -static void notify_quit(EventListener *listener) -{ - if (listener->quit_callback) - listener->quit_callback(listener->user_data); -} - -static gboolean on_fd_readable(gint fd, GIOCondition condition, gpointer data); - -/* - * Reconnect state machine — why one-shot timers instead of a single - * repeating GSource: - * - * A one-shot timer per attempt (create → fire → destroy → create next) - * trades a tiny per-10s allocation for three simplifications: - * - * 1. Success path needs no cleanup: returning G_SOURCE_REMOVE auto- - * destroys the timer, so reconnection back to fd-driven mode is a - * single return with no g_source_remove() branch. - * 2. Single reschedule point: the failure-count check, the new-timer - * creation, and the id storage all live in one place (schedule_retry - * below). A repeating source would split "keep going" (return value) - * from "hit the cap" (in-body check), scattering the state machine. - * 3. stop() is trivial: at most one pending source id - * (reconnect_timer_id) to remove in the cleanup block; the callback - * entry immediately clears it, so the state space is minimal. - * - * The allocation cost (g_timeout_source_new + attach + unref) is paid at - * most once per RECONNECT_DELAY_MS (10s) — negligible on this low-frequency - * path. - */ -static gboolean on_reconnect_attempt(gpointer data) -{ - EventListener *listener = (EventListener *)data; - - listener->reconnect_timer_id = 0; - - EventReceiver *new_receiver = event_receiver_new(DISPATCHER_SOCKET_PATH); - if (new_receiver != NULL) { - listener->receiver = new_receiver; - - int sock_fd = event_receiver_get_socket(listener->receiver); - if (sock_fd < 0) { - spdlog::error("Invalid receiver socket fd after reconnect"); - event_receiver_free(listener->receiver); - listener->receiver = NULL; - listener->reconnect_attempts++; - goto schedule_retry; - } - - GSource *fd_source = g_unix_fd_source_new(sock_fd, - (GIOCondition)(G_IO_IN | G_IO_HUP | G_IO_ERR)); - if (fd_source == NULL) { - spdlog::error("Failed to create fd watch source for receiver socket"); - event_receiver_free(listener->receiver); - listener->receiver = NULL; - listener->reconnect_attempts++; - goto schedule_retry; - } - g_source_set_priority(fd_source, G_PRIORITY_DEFAULT); - g_source_set_callback(fd_source, - (GSourceFunc)(void (*)(void))on_fd_readable, listener, NULL); - listener->fd_source_id = g_source_attach(fd_source, listener->context); - g_source_unref(fd_source); - if (listener->fd_source_id == 0) { - spdlog::error("Failed to attach fd watch to listener context"); - event_receiver_free(listener->receiver); - listener->receiver = NULL; - listener->reconnect_attempts++; - goto schedule_retry; - } - - spdlog::info("Reconnected to dispatcher: {}", DISPATCHER_SOCKET_PATH); - listener->reconnect_attempts = 0; - return G_SOURCE_REMOVE; - } - - listener->reconnect_attempts++; - spdlog::warn("Reconnect attempt {}/{} failed", - listener->reconnect_attempts, MAX_RECONNECT_ATTEMPTS); - -schedule_retry: - if (listener->reconnect_attempts >= MAX_RECONNECT_ATTEMPTS) { - spdlog::error("Giving up after {} reconnect attempts, requesting quit", - MAX_RECONNECT_ATTEMPTS); - notify_quit(listener); - return G_SOURCE_REMOVE; - } - - GSource *timer_source = g_timeout_source_new(RECONNECT_DELAY_MS); - if (timer_source == NULL) { - spdlog::warn("Failed to create reconnect timer, quitting immediately"); - notify_quit(listener); - return G_SOURCE_REMOVE; - } - g_source_set_callback(timer_source, on_reconnect_attempt, listener, NULL); - listener->reconnect_timer_id = g_source_attach(timer_source, listener->context); - g_source_unref(timer_source); - - if (listener->reconnect_timer_id == 0) { - spdlog::warn("Failed to attach reconnect timer, quitting immediately"); - notify_quit(listener); - } - - return G_SOURCE_REMOVE; -} - -static void start_reconnect(EventListener *listener) -{ - /* The old fd source has already returned G_SOURCE_REMOVE, so it is - * destroyed by the main loop. Free the stale receiver and schedule a - * delayed reconnect to avoid hammering the dispatcher during an event - * burst. */ - if (listener->receiver != NULL) { - event_receiver_free(listener->receiver); - listener->receiver = NULL; - } - - listener->reconnect_attempts = 0; - - GSource *timer_source = g_timeout_source_new(RECONNECT_DELAY_MS); - if (timer_source == NULL) { - spdlog::warn("Failed to create reconnect timer, quitting immediately"); - notify_quit(listener); - return; - } - g_source_set_callback(timer_source, on_reconnect_attempt, listener, NULL); - listener->reconnect_timer_id = g_source_attach(timer_source, listener->context); - g_source_unref(timer_source); - - if (listener->reconnect_timer_id == 0) { - spdlog::warn("Failed to attach reconnect timer, quitting immediately"); - notify_quit(listener); - } else { - spdlog::info("Connection lost, will reconnect in {}ms", - RECONNECT_DELAY_MS); - } -} - -static gboolean on_fd_readable(G_GNUC_UNUSED gint fd, - GIOCondition condition, - gpointer data) -{ - EventListener *listener = (EventListener *)data; - - if ((condition & (G_IO_HUP | G_IO_ERR)) != 0) { - spdlog::info("Dispatcher connection lost"); - listener->fd_source_id = 0; - start_reconnect(listener); - return G_SOURCE_REMOVE; - } - - /* Drain all pending events in one callback to avoid GMainContext - * re-dispatch overhead per event under high throughput. The fd source - * is level-triggered, so it will fire again if the kernel buffer still - * has data after we return. */ - for (;;) { - dispatch_event_t dispatch_evt; - memset(&dispatch_evt, 0, sizeof(dispatch_evt)); - - EventReceiveResult result = event_receiver_receive_nonblock( - listener->receiver, &dispatch_evt); - - switch (result) { - case EVENT_RECEIVE_OK: { - fs_event *evt = g_slice_new(fs_event); - evt->act = (uint8_t)dispatch_evt.event_action; - evt->cookie = dispatch_evt.cookie; - g_strlcpy(evt->src, dispatch_evt.event_path, MAX_PATH_LEN); - evt->dst[0] = '\0'; - - if (listener->callback) - listener->callback(listener->user_data, evt); - - continue; - } - case EVENT_RECEIVE_WOULD_BLOCK: - return G_SOURCE_CONTINUE; - case EVENT_RECEIVE_INTERRUPTED: - continue; - case EVENT_RECEIVE_DISCONNECTED: - spdlog::info("Dispatcher closed the connection"); - listener->fd_source_id = 0; - start_reconnect(listener); - return G_SOURCE_REMOVE; - case EVENT_RECEIVE_ERROR: - spdlog::warn("Failed to receive event"); - listener->fd_source_id = 0; - start_reconnect(listener); - return G_SOURCE_REMOVE; - default: - continue; - } - } -} - -static gpointer event_listener_thread_func(gpointer data) -{ - EventListener *listener = (EventListener *)data; - - listener->context = g_main_context_new(); - if (listener->context == NULL) { - spdlog::error("Failed to create event listener GMainContext"); - signal_startup(listener, FALSE); - return NULL; - } - - listener->loop = g_main_loop_new(listener->context, FALSE); - g_main_context_push_thread_default(listener->context); - - int sock_fd = -1; - - listener->receiver = event_receiver_new(DISPATCHER_SOCKET_PATH); - if (listener->receiver == NULL) { - spdlog::error("Failed to connect to dispatcher at {}", - DISPATCHER_SOCKET_PATH); - spdlog::info("Is deepin-anything-server running and reachable?"); - signal_startup(listener, FALSE); - goto cleanup; - } - - spdlog::info("Connected to dispatcher: {}", DISPATCHER_SOCKET_PATH); - - sock_fd = event_receiver_get_socket(listener->receiver); - if (sock_fd < 0) { - spdlog::error("Invalid receiver socket fd"); - signal_startup(listener, FALSE); - goto cleanup; - } - - { - GSource *fd_source = g_unix_fd_source_new(sock_fd, - (GIOCondition)(G_IO_IN | G_IO_HUP | G_IO_ERR)); - if (fd_source == NULL) { - spdlog::error("Failed to create fd watch source for receiver socket"); - signal_startup(listener, FALSE); - goto cleanup; - } - g_source_set_priority(fd_source, G_PRIORITY_DEFAULT); - g_source_set_callback(fd_source, - (GSourceFunc)(void (*)(void))on_fd_readable, listener, NULL); - listener->fd_source_id = g_source_attach(fd_source, listener->context); - g_source_unref(fd_source); - if (listener->fd_source_id == 0) { - spdlog::error("Failed to attach fd watch to listener context"); - signal_startup(listener, FALSE); - goto cleanup; - } - } - - spdlog::info("Event listener thread started"); - signal_startup(listener, TRUE); - g_main_loop_run(listener->loop); - -cleanup: - if (listener->fd_source_id > 0) { - g_source_remove(listener->fd_source_id); - listener->fd_source_id = 0; - } - if (listener->reconnect_timer_id > 0) { - g_source_remove(listener->reconnect_timer_id); - listener->reconnect_timer_id = 0; - } - if (listener->receiver != NULL) { - event_receiver_free(listener->receiver); - listener->receiver = NULL; - } - g_main_context_pop_thread_default(listener->context); - if (listener->loop != NULL) { - g_main_loop_unref(listener->loop); - listener->loop = NULL; - } - if (listener->context != NULL) { - g_main_context_unref(listener->context); - listener->context = NULL; - } - - spdlog::info("Event listener thread stopped"); - return NULL; -} - -EventListener *event_listener_new(EventListenerCallback callback, - EventListenerQuitCallback quit_callback, - gpointer user_data) -{ - g_return_val_if_fail(callback != NULL, NULL); - - EventListener *listener = g_new0(EventListener, 1); - listener->callback = callback; - listener->user_data = user_data; - listener->quit_callback = quit_callback; - listener->fd_source_id = 0; - listener->reconnect_timer_id = 0; - listener->reconnect_attempts = 0; - g_atomic_int_set(&listener->started, 0); - g_mutex_init(&listener->startup_mutex); - g_cond_init(&listener->startup_cond); - - return listener; -} - -gboolean event_listener_start(EventListener *listener) -{ - g_return_val_if_fail(listener != NULL, FALSE); - - if (listener->thread) { - spdlog::warn("Event listener is already started"); - return FALSE; - } - - listener->thread = g_thread_new("event_listener", - event_listener_thread_func, listener); - if (listener->thread == NULL) { - spdlog::error("Failed to create event listener thread"); - return FALSE; - } - - g_mutex_lock(&listener->startup_mutex); - while (g_atomic_int_get(&listener->started) == 0) - g_cond_wait(&listener->startup_cond, &listener->startup_mutex); - gboolean ok = (g_atomic_int_get(&listener->started) == 1); - g_mutex_unlock(&listener->startup_mutex); - - if (!ok) { - g_thread_join(listener->thread); - listener->thread = NULL; - spdlog::error("Event listener thread failed during startup"); - } - - return ok; -} - -void event_listener_stop(EventListener *listener) -{ - g_return_if_fail(listener != NULL); - - if (listener->loop != NULL) - g_main_loop_quit(listener->loop); - - if (listener->thread) { - g_thread_join(listener->thread); - listener->thread = NULL; - } -} - -void event_listener_free(EventListener *listener) -{ - if (listener == NULL) - return; - - event_listener_stop(listener); - - g_mutex_clear(&listener->startup_mutex); - g_cond_clear(&listener->startup_cond); - g_free(listener); -} diff --git a/src/daemon/src/core/file_index_manager.cpp b/src/daemon/src/core/file_index_manager.cpp deleted file mode 100755 index d687ecd3..00000000 --- a/src/daemon/src/core/file_index_manager.cpp +++ /dev/null @@ -1,772 +0,0 @@ -// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "core/file_index_manager.h" -#include "analyzers/AnythingAnalyzer.h" -#include "analyzers/LowerCaseNGramAnalyzer.h" -#include "core/config.h" -#include "utils/string_helper.h" - -#include -#include - -#include "lucene++/Highlighter.h" -#include "lucene++/FileUtils.h" -#include "lucene++/FuzzyQuery.h" -#include "lucene++/QueryScorer.h" -#include "lucene++/SimpleHTMLFormatter.h" - -#include "analyzers/AnythingAnalyzer.h" -#include "utils/log.h" -#include "utils/tools.h" -#include "core/config.h" - -#include -#include // For statx and struct statx -#include // For AT_FDCWD - -ANYTHING_NAMESPACE_BEGIN - -using namespace Lucene; - -// file_record - -struct file_record { - std::string file_name; - std::string file_name_pinyin; - std::string file_name_pinyin_acronym; - std::string full_path; - std::string file_type; - std::string file_ext; - int64_t birth_time; // seconds since epoch - int64_t modify_time; // seconds since epoch - int64_t file_size; - bool is_hidden; -}; - -void print_file_record(const file_record& record) { - spdlog::info("file_name: {} full_path: {} file_type: {} file_ext: {} birth_time: {} modify_time: {} file_size: {} is_hidden: {}", - record.file_name, record.full_path, record.file_type, record.file_ext, record.birth_time, record.modify_time, record.file_size, record.is_hidden); -} - -file_record make_file_record(const std::filesystem::path& p, - pinyin_processor& pinyin_processor, - const std::map &file_type_mapping) { - file_record ret = { - .file_name = std::move(p.filename().string()), - .file_name_pinyin = "", - .file_name_pinyin_acronym = "", - .full_path = std::move(p.string()), - .file_type = "other", - .file_ext = std::move(p.extension().string()), - .birth_time = 0, - .modify_time = 0, - .file_size = 0, - .is_hidden = false, - }; - pinyin_processor.convert_to_pinyin(ret.file_name, ret.file_name_pinyin, ret.file_name_pinyin_acronym); - - if (ret.file_ext.size() > 1) { - ret.file_ext = ret.file_ext.substr(1); - std::transform(ret.file_ext.begin(), ret.file_ext.end(), ret.file_ext.begin(), ::tolower); - } - ret.is_hidden = ret.full_path.find("/.") != std::string::npos; - - struct statx statxbuf; - if (statx(AT_FDCWD, ret.full_path.c_str(), AT_SYMLINK_NOFOLLOW, - STATX_BASIC_STATS | STATX_BTIME | STATX_MTIME, &statxbuf) != 0) { - auto err = errno; - // The error is usually that the file does not exist, mainly because the index is not updated in time. - spdlog::debug("statx fail: {} {}", ret.full_path, strerror(err)); - return ret; - } else { - if (statxbuf.stx_mask & STATX_BTIME) { - ret.birth_time = statxbuf.stx_btime.tv_sec; - } - if (statxbuf.stx_mask & STATX_MTIME) { - ret.modify_time = statxbuf.stx_mtime.tv_sec; - } - ret.file_size = statxbuf.stx_size; - - if (S_ISDIR(statxbuf.stx_mode)) { - ret.file_type = "dir"; - } else if (S_ISREG(statxbuf.stx_mode)) { - auto it = file_type_mapping.find(ret.file_ext); - if (it != file_type_mapping.end()) { - ret.file_type = it->second; - } - } - } - - return ret; -} - -#define FILE_NAME_FIELD L"file_name" -#define FILE_NAME_LOWER_FIELD L"file_name_lower" -#define FULL_PATH_FIELD L"full_path" -#define FILE_TYPE_FIELD L"file_type" -#define FILE_EXT_FIELD L"file_ext" -#define BIRTH_TIME_FIELD L"birth_time" -#define MODIFY_TIME_FIELD L"modify_time" -#define FILE_SIZE_FIELD L"file_size" -#define FILE_SIZE_STR_FIELD L"file_size_str" -#define PINYIN_FIELD L"pinyin" -#define PINYIN_ACRONYM_FIELD L"pinyin_acronym" -#define IS_HIDDEN_FIELD L"is_hidden" -#define ANCESTOR_PATHS_FIELD L"ancestor_paths" - -/** - * 辅助函数:解析文件路径,将所有父级目录作为 Term 添加到索引中。 - * - * 逻辑示例: - * 如果 full_path 是 "/home/user/project/main.cpp" - * 我们会添加以下 Term 到 ANCESTOR_PATHS_FIELD: - * 1. "/home/user/project" - * 2. "/home/user" - * 3. "/home" - * 4. "/" - */ -static void add_ancestor_paths(DocumentPtr doc, const std::string &full_path) -{ - if (full_path.empty() || full_path[0] != '/') - return; - - std::string current_path = full_path; - size_t last_slash = 1; - - while (last_slash != 0) { - last_slash = current_path.find_last_of('/'); - current_path.resize(last_slash == 0 ? 1 : last_slash); - - // 添加 Field - // 注意: - // 1. 使用 Field::STORE_NO,因为我们只需要搜索它,不需要把这些父路径取出来显示给用户,节省空间。 - // 2. 使用 Field::INDEX_NOT_ANALYZED,确保路径作为一个整体被索引,不要被分词器拆开。 - doc->add(newLucene(ANCESTOR_PATHS_FIELD, - StringUtils::toUnicode(current_path), - Field::STORE_NO, - Field::INDEX_NOT_ANALYZED)); - } -} - -DocumentPtr create_document(const file_record& record) { - DocumentPtr doc = newLucene(); - // File name with fuzzy match; parser is required for searching and deleting. - doc->add(newLucene(FILE_NAME_FIELD, - StringUtils::toLower(StringUtils::toUnicode(record.file_name)), - Field::STORE_YES, Field::INDEX_ANALYZED)); - doc->add(newLucene(FILE_NAME_LOWER_FIELD, - StringUtils::toLower(StringUtils::toUnicode(record.file_name)), - Field::STORE_YES, Field::INDEX_NOT_ANALYZED)); - // Full path with exact match; parser is not needed for deleting and exact searching, which improves perferemce. - doc->add(newLucene(FULL_PATH_FIELD, - StringUtils::toUnicode(record.full_path), - Field::STORE_YES, Field::INDEX_NOT_ANALYZED)); - doc->add(newLucene(FILE_TYPE_FIELD, - StringUtils::toUnicode(record.file_type), - Field::STORE_YES, Field::INDEX_NOT_ANALYZED)); - doc->add(newLucene(FILE_EXT_FIELD, - StringUtils::toUnicode(record.file_ext), - Field::STORE_YES, Field::INDEX_NOT_ANALYZED)); - - doc->add(newLucene(BIRTH_TIME_FIELD, Field::STORE_YES, true)->setLongValue(record.birth_time)); - doc->add(newLucene(MODIFY_TIME_FIELD, Field::STORE_YES, true)->setLongValue(record.modify_time)); - - char *formatted_size = format_size(record.file_size); - doc->add(newLucene(FILE_SIZE_STR_FIELD, - StringUtils::toUnicode(formatted_size), - Field::STORE_YES, Field::INDEX_NOT_ANALYZED)); - g_free(formatted_size); - doc->add(newLucene(FILE_SIZE_FIELD, Field::STORE_YES, true)->setLongValue(record.file_size)); - - doc->add(newLucene(PINYIN_FIELD, - StringUtils::toLower(StringUtils::toUnicode(record.file_name_pinyin)), - Field::STORE_YES, Field::INDEX_ANALYZED)); - doc->add(newLucene(PINYIN_ACRONYM_FIELD, - StringUtils::toLower(StringUtils::toUnicode(record.file_name_pinyin_acronym)), - Field::STORE_YES, Field::INDEX_ANALYZED)); - - doc->add(newLucene(IS_HIDDEN_FIELD, - (record.is_hidden ? L"Y" : L"N"), - Field::STORE_YES, Field::INDEX_NOT_ANALYZED)); - - add_ancestor_paths(doc, record.full_path); - - return doc; -} - - -#define INDEX_VERSION L"6" -#define INDEX_VERSION_FIELD L"index_version" - -file_index_manager::file_index_manager(const std::string& persistent_index_dir, - const std::string& volatile_index_dir, - const std::map& file_type_mapping) - : persistent_index_directory_(persistent_index_dir), - volatile_index_directory_(volatile_index_dir), - pinyin_processor_("/usr/share/deepin-anything-server/pinyin.txt"), - file_type_mapping_(file_type_mapping) { - try { - prepare_index(); - check_index_version(); - FSDirectoryPtr dir = FSDirectory::open(StringUtils::toUnicode(volatile_index_directory_)); - try { - auto create = !IndexReader::indexExists(dir); - writer_ = newLucene(dir, - newLucene(1, 2), - create, IndexWriter::MaxFieldLengthLIMITED); - reader_ = IndexReader::open(dir, true); - // check if index corrupted by same method - if (!commit(index_status::loading)) { - throw LuceneException(); - } - } catch (const LuceneException& e) { - spdlog::warn("The index is corrupted: {}", volatile_index_directory_); - std::error_code ec; - if (writer_) writer_->close(); - if (reader_) reader_->close(); - std::filesystem::remove_all(volatile_index_directory_, ec); - - writer_ = newLucene(dir, - newLucene(1, 2), - true, IndexWriter::MaxFieldLengthLIMITED); - reader_ = IndexReader::open(dir, true); - } - nrt_reader_ = writer_->getReader(); - searcher_ = newLucene(reader_); - nrt_searcher_ = newLucene(nrt_reader_); - } catch (const LuceneException& e) { - std::string error_msg = "Failed to initialize file_index_manager: " + StringUtils::toUTF8(e.getError()); - spdlog::critical(error_msg); - exit(APP_QUIT_CODE); - } -} - -file_index_manager::~file_index_manager() { - try { - if (writer_) { - commit(index_status::closed); - writer_->close(); - persist_index(); - } - - if (searcher_) searcher_->close(); - if (nrt_searcher_) nrt_searcher_->close(); - if (reader_) reader_->close(); - if (nrt_reader_) nrt_reader_->close(); - } catch (const LuceneException& e) { - spdlog::error("Failed to close file_index_manager: {}", StringUtils::toUTF8(e.getError())); - } -} - -bool file_index_manager::add_index(const std::string& path) { - bool ret = false; - - try { - auto doc = create_document(make_file_record(path, pinyin_processor_, file_type_mapping_)); - writer_->updateDocument(newLucene(FULL_PATH_FIELD, StringUtils::toUnicode(path)), doc); - spdlog::debug("Indexed {}", path); - ret = true; - } catch (const LuceneException& e) { - spdlog::error("Failed to index {}: {}", path, StringUtils::toUTF8(e.getError())); - } catch (const std::exception& e) { - spdlog::error("Failed to index {}: {}", path, e.what()); - } - - return ret; -} - -bool file_index_manager::remove_index(const std::string& path) { - bool ret = false; - - try { - TermPtr pterm = newLucene(FULL_PATH_FIELD, StringUtils::toUnicode(path)); - writer_->deleteDocuments(pterm); - spdlog::debug("Removed index: {}", path); - ret = true; - } catch (const LuceneException& e) { - spdlog::error("Failed to remove index {}: {}", path, StringUtils::toUTF8(e.getError())); - } catch (const std::exception& e) { - spdlog::error("Failed to remove index {}: {}", path, e.what()); - } - - return ret; -} - -bool file_index_manager::update_index(const std::string& old_path, const std::string& new_path) { - bool ret = false; - - try { - auto doc = create_document(make_file_record(new_path, pinyin_processor_, file_type_mapping_)); - writer_->updateDocument(newLucene(FULL_PATH_FIELD, StringUtils::toUnicode(old_path)), doc); - spdlog::debug("Renamed: {} --> {}", old_path, new_path); - ret = true; - } catch (const LuceneException& e) { - spdlog::error("Failed to rename index {} to {}: {}", old_path, new_path, StringUtils::toUTF8(e.getError())); - } catch (const std::exception& e) { - spdlog::error("Failed to rename index {} to {}: {}", old_path, new_path, e.what()); - } - - return ret; -} - -bool file_index_manager::update_index(const std::string& path) { - auto record = make_file_record(path, pinyin_processor_, file_type_mapping_); - if (record.modify_time == 0) { - spdlog::debug("Skip updating index for non-existent file: {}", path); - return true; - } - - bool ret = false; - - try { - auto doc = create_document(record); - writer_->updateDocument(newLucene(FULL_PATH_FIELD, StringUtils::toUnicode(path)), doc); - spdlog::debug("Updated index for {}", path); - ret = true; - } catch (const LuceneException& e) { - spdlog::error("Failed to update index for {}: {}", path, StringUtils::toUTF8(e.getError())); - } catch (const std::exception& e) { - spdlog::error("Failed to update index for {}: {}", path, e.what()); - } - - return ret; -} - -bool check_index_corrupted(const std::string& index_directory) { - try { - FSDirectoryPtr dir = FSDirectory::open(StringUtils::toUnicode(index_directory)); - Lucene::IndexReaderPtr reader = IndexReader::open(dir, true); - reader->close(); - return false; - } catch (const LuceneException& e) { - spdlog::error("The index is corrupted: {}, {}", index_directory, StringUtils::toUTF8(e.getError())); - return true; - } -} - -bool file_index_manager::commit(index_status status) { - try { - save_index_status(status); - set_index_version(); - writer_->commit(); - spdlog::debug("All changes are commited with version: {}", StringUtils::toUTF8(INDEX_VERSION)); - } catch (const LuceneException& e) { - spdlog::error("Failed to commit index: {}", StringUtils::toUTF8(e.getError())); - return false; - } - - return !check_index_corrupted(volatile_index_directory_); -} - -void file_index_manager::persist_index() { - std::error_code ec; - - if (persistent_index_directory_ == volatile_index_directory_) { - spdlog::debug("Persistent index directory is the same as volatile index directory, skip persist"); - return; - } - - std::filesystem::remove_all(persistent_index_directory_, ec); - if (ec) { - spdlog::error("Failed to remove persistent index directory: {}", ec.message()); - return; - } - - std::filesystem::copy(volatile_index_directory_, - persistent_index_directory_, - std::filesystem::copy_options::recursive, - ec); - if (ec) { - spdlog::error("Failed to copy index to persistent index directory: {}", ec.message()); - return; - } - - spdlog::debug("Persist index to {}", persistent_index_directory_); -} - -// bool file_index_manager::indexed() const { -// return document_size() > 0; -// } - -// void file_index_manager::test(const String& path) { -// spdlog::info("test path: {}", StringUtils::toUTF8(path)); -// // AnalyzerPtr analyzer = newLucene(LuceneVersion::LUCENE_CURRENT); -// AnalyzerPtr analyzer = newLucene(); - -// // Use a StringReader to simulate input -// TokenStreamPtr tokenStream = analyzer->tokenStream(L"", newLucene(path)); -// // TokenPtr token = newLucene(); - -// // Tokenize and print out the results -// while (tokenStream->incrementToken()) { -// spdlog::info("Token: {}", StringUtils::toUTF8(tokenStream->toString())); -// } -// } - -// void file_index_manager::pinyin_test(const std::string& path) { -// spdlog::info("pinyin test path: {}", path); -// auto pinyin_path = pinyin_processor_.convert_to_pinyin(path); -// test(StringUtils::toUnicode(pinyin_path)); -// } - -int32_t file_index_manager::document_size(bool nrt) { - try_refresh_reader(nrt); - - auto reader = nrt ? nrt_reader_ : reader_; - if (!reader) { - spdlog::error("document_size: reader is null (nrt={})", nrt); - return -1; - } - - return reader->numDocs(); -} - -std::string file_index_manager::index_directory() const { - return persistent_index_directory_; -} - -std::vector file_index_manager::traverse_directory(const std::string& path, bool nrt, bool &success) { - success = false; - - if (path.empty()) { - success = true; - return {}; - } - - std::string path_with_slash = path; - if (!string_helper::ends_with(path_with_slash, "/")) { - path_with_slash += "/"; - } - - String query_terms = StringUtils::toUnicode(path_with_slash); - - try { - SearcherPtr searcher; - int32_t max_results; - if (nrt) { - try_refresh_reader(true); - searcher = nrt_searcher_; - max_results = nrt_reader_->numDocs(); - } else { - try_refresh_reader(); - searcher = searcher_; - max_results = reader_->numDocs(); - } - - auto query = newLucene(newLucene(FULL_PATH_FIELD, query_terms)); - auto search_results = searcher->search(query, max_results); - - std::vector results; - results.reserve(search_results->scoreDocs.size()); - for (const auto& score_doc : search_results->scoreDocs) { - DocumentPtr doc = searcher->doc(score_doc->doc); - results.push_back(std::move(StringUtils::toUTF8(doc->get(FULL_PATH_FIELD)))); - } - - success = true; - return results; - } catch (const LuceneException& e) { - spdlog::error("Failed to traverse directory {}: {}", path, StringUtils::toUTF8(e.getError())); - success = false; - return {}; - } -} - -bool file_index_manager::document_exists(const std::string &path, bool only_check_initial_index) { - TermPtr term = newLucene(FULL_PATH_FIELD, StringUtils::toUnicode(path)); - TermDocsPtr termDocs; - if (only_check_initial_index) { - termDocs = reader_->termDocs(term); - } else { - try_refresh_reader(true); - termDocs = nrt_reader_->termDocs(term); - } - return termDocs->next(); -} - -bool file_index_manager::refresh_indexes(const std::vector& blacklist_paths, bool nrt, bool check_exist) { - bool index_changed = false; - try { - spdlog::info("Refreshing file indexes..."); - - SearcherPtr searcher; - int32_t num_docs; - if (nrt) { - try_refresh_reader(true); - searcher = nrt_searcher_; - num_docs = nrt_reader_->numDocs(); - } else { - try_refresh_reader(); - searcher = searcher_; - num_docs = reader_->numDocs(); - } - - if (num_docs > 0) { - auto query = newLucene(); - auto search_results = searcher->search(query, num_docs); - std::vector remove_list; - std::error_code ec; - for (const auto& score_doc : search_results->scoreDocs) { - DocumentPtr doc = searcher->doc(score_doc->doc); - std::filesystem::path full_path(doc->get(FULL_PATH_FIELD)); - if (full_path.empty()) { - // doc is metadata, not a file - continue; - } - if ((check_exist && !std::filesystem::exists(full_path, ec)) || - is_path_in_blacklist(full_path.string(), blacklist_paths)) { - remove_list.push_back(std::move(full_path.string())); - } - } - - for (const auto& path : remove_list) { - // Remove non-existent path from the indexes - remove_index(path); - index_changed = true; - } - } - } catch (const LuceneException& e) { - spdlog::error("Failed to refresh indexes: {}", StringUtils::toUTF8(e.getError())); - } catch (const std::exception& e) { - spdlog::error("Failed to refresh indexes: {}", e.what()); - } - - return index_changed; -} - -void file_index_manager::set_index_invalid() -{ - try { - std::ofstream invalid_index_file(volatile_index_directory_ + "/invalid_index"); - invalid_index_file.close(); - } catch (const std::exception& e) { - spdlog::error("Failed to set index invalid: {}", e.what()); - } -} - -void file_index_manager::set_index_updating() -{ - save_index_status(index_status::updating); -} - -void file_index_manager::try_refresh_reader(bool nrt) { - std::lock_guard lock(reader_mtx_); - if (nrt) { - if (!nrt_reader_->isCurrent()) { - IndexReaderPtr new_reader = writer_->getReader(); - if (new_reader != nrt_reader_) { - nrt_reader_->close(); - nrt_reader_ = new_reader; - nrt_searcher_ = newLucene(nrt_reader_); - } - } - } else { - if (!reader_->isCurrent()) { - IndexReaderPtr new_reader = reader_->reopen(); - if (new_reader != reader_) { - reader_->close(); - reader_ = new_reader; - searcher_ = newLucene(reader_); - } - } - } -} - -static void create_index_entry_point(const std::string &volatile_index_directory) { - std::error_code ec; - std::string index_entry_point = std::string(g_get_user_runtime_dir()) + "/deepin-anything-server"; - - if (volatile_index_directory == index_entry_point) - return; - - // remove index entry point if exists - // symlink is removed, not its target - std::filesystem::remove_all(index_entry_point, ec); - - // create volatile index directory if not exists - ec.clear(); - bool volatile_index_directory_exists = std::filesystem::exists(volatile_index_directory, ec); - if (ec) { - spdlog::error("Failed to check volatile index directory: {}, quit", ec.message()); - exit(APP_QUIT_CODE); - } - if (!volatile_index_directory_exists) { - ec.clear(); - std::filesystem::create_directory(volatile_index_directory, ec); - if (ec) { - spdlog::error("Failed to create volatile index directory: {}, quit", ec.message()); - exit(APP_QUIT_CODE); - } - } - - // create symbolic links for index entry point - ec.clear(); - std::filesystem::create_directory_symlink(volatile_index_directory, index_entry_point, ec); - if (ec) { - spdlog::error("Failed to create symbolic link from {} to {}: {}, quit", - index_entry_point, volatile_index_directory, ec.message()); - exit(APP_QUIT_CODE); - } -} - -void file_index_manager::prepare_index() { - spdlog::info("Preparing index..."); - std::error_code ec; - - create_index_entry_point(volatile_index_directory_); - - if (persistent_index_directory_ == volatile_index_directory_) { - spdlog::info("Persistent index directory is the same as volatile index directory, skip prepare"); - return; - } - - ec.clear(); - if (!std::filesystem::exists(volatile_index_directory_, ec)) { - if (ec) { - spdlog::error("Failed to check volatile index directory: {}", ec.message()); - exit(APP_RESTART_CODE); - } - - if (!std::filesystem::exists(persistent_index_directory_, ec)) { - spdlog::info("Persistent index directory does not exist: {}", persistent_index_directory_); - return; - } - - ec.clear(); - std::filesystem::copy(persistent_index_directory_, - volatile_index_directory_, - std::filesystem::copy_options::recursive, - ec); - if (ec) { - spdlog::error("Failed to copy index to volatile index directory: {}", ec.message()); - } else { - spdlog::info("Prepared index in {}", volatile_index_directory_); - } - } else { - spdlog::info("Index already exists in {}", volatile_index_directory_); - } -} - -void file_index_manager::check_index_version() { - spdlog::info("Checking index version..."); - Lucene::IndexReaderPtr reader; - - std::error_code ec; - if (!std::filesystem::exists(volatile_index_directory_, ec)) { - spdlog::info("Index directory does not exist: {}", volatile_index_directory_); - return; - } - - // 检查是否是无效索引 - if (std::filesystem::exists(volatile_index_directory_ + "/invalid_index", ec)) { - spdlog::warn("The index is invalid: {}, remove it", volatile_index_directory_); - std::filesystem::remove_all(volatile_index_directory_, ec); - return; - } - - // 打开索引 - try { - FSDirectoryPtr dir = FSDirectory::open(StringUtils::toUnicode(volatile_index_directory_)); - reader = IndexReader::open(dir, true); - } catch (const LuceneException& e) { - spdlog::warn("The index is corrupted: {}", volatile_index_directory_); - if (reader) reader->close(); - spdlog::warn("Removing the corrupted index..."); - std::filesystem::remove_all(volatile_index_directory_, ec); - return; - } - - // 查找数据库版本 - bool found = false; - try { - TermPtr term = newLucene(INDEX_VERSION_FIELD, INDEX_VERSION); - QueryPtr query = newLucene(term); - Lucene::SearcherPtr searcher = newLucene(reader); - Lucene::TopDocsPtr top_docs = searcher->search(query, 1); - found = top_docs->scoreDocs.size() == 1; - reader->close(); - } catch (const LuceneException& e) { - spdlog::error("Failed to check index version: {}", StringUtils::toUTF8(e.getError())); - } catch (const std::exception& e) { - spdlog::error("Failed to check index version: {}", e.what()); - } - if (found) { - spdlog::info("The index version is expected({}): {}", StringUtils::toUTF8(INDEX_VERSION), volatile_index_directory_); - } else { - spdlog::warn("The index version is mismatched: {}", volatile_index_directory_); - spdlog::warn("Removing the incompatible index..."); - std::filesystem::remove_all(volatile_index_directory_, ec); - } -} - -void file_index_manager::set_index_version() { - static std::once_flag flag; - std::call_once(flag, [this]() { - // 保存版本号到数据库 - try { - DocumentPtr doc = newLucene(); - doc->add(newLucene(INDEX_VERSION_FIELD, INDEX_VERSION, Field::STORE_YES, Field::INDEX_NOT_ANALYZED)); - writer_->updateDocument(newLucene(INDEX_VERSION_FIELD, INDEX_VERSION), doc); - } catch (const LuceneException& e) { - spdlog::error("Failed to set index version: {}", StringUtils::toUTF8(e.getError())); - } catch (const std::exception& e) { - spdlog::error("Failed to set index version: {}", e.what()); - } - }); -} - -static const char * const status_json_template = R"({ - "time": "%s", - "status": "%s", - "version": "%s" -} -)"; - -void file_index_manager::save_index_status(index_status status) { - g_autoptr(GDateTime) now = g_date_time_new_now_local(); - g_autofree char *time_str = g_date_time_format(now, "%Y-%m-%dT%H:%M:%S"); - - std::string status_str; - switch (status) { - case index_status::loading: - status_str = "loading"; - break; - case index_status::scanning: - status_str = "scanning"; - break; - case index_status::monitoring: - status_str = "monitoring"; - break; - case index_status::updating: - status_str = "updating"; - break; - case index_status::closed: - status_str = "closed"; - break; - default: - assert(false && "Invalid index status"); - break; - } - - char status_json[1024]; - int written = snprintf(status_json, sizeof(status_json), status_json_template, - time_str, - status_str.c_str(), - StringUtils::toUTF8(INDEX_VERSION).c_str()); - if (written < 0 || written >= (int)sizeof(status_json)) { - spdlog::error("Failed to format status json"); - return; - } - - try { - std::ofstream status_file(volatile_index_directory_ + "/status.json"); - status_file << status_json; - status_file.close(); - } catch (const std::exception& e) { - spdlog::error("Failed to save index status: {}", e.what()); - } -} - -ANYTHING_NAMESPACE_END diff --git a/src/daemon/src/core/mount_manager.cpp b/src/daemon/src/core/mount_manager.cpp deleted file mode 100644 index 2472a389..00000000 --- a/src/daemon/src/core/mount_manager.cpp +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "core/mount_manager.h" - -#include -#include -#include -#include -#include - -#include -#include // major(), minor() - -#include "utils/enum_helper.h" -#include "utils/string_helper.h" - -ANYTHING_NAMESPACE_BEGIN - -mount_manager::mount_manager() - : mountinfo_path_{"/proc/self/mountinfo"} { - update_mount_points(); -} - -bool mount_manager::update() { - std::ifstream file_mountinfo(mountinfo_path_); - if (!file_mountinfo.is_open()) { - std::cerr << "open file failed: " << mountinfo_path_ << "\n"; - return false; - } - - std::string line; - mounts_.clear(); - while (std::getline(file_mountinfo, line)) { - auto mountinfo = string_helper::split(line, " "); - auto major_minor = string_helper::split(mountinfo[to_underlying(mountinfo_field::major_minor)], ":"); - unsigned int major = std::stoul(major_minor[0]); - unsigned int minor = std::stoul(major_minor[1]); - - if (mountinfo[to_underlying(mountinfo_field::root)] == "/") { - // only record the first mount point of the device - if (mounts_.find(MKDEV(major, minor)) != mounts_.end()) - continue; - - mounts_[MKDEV(major, minor)] = mountinfo[to_underlying(mountinfo_field::mount_point)]; - } - } - - return true; -} - -bool mount_manager::contains_device(unsigned int key) const { - return mounts_.count(key); -} - -std::string mount_manager::get_mount_point(unsigned int device) const { - return mounts_.at(device); -} - -const std::vector& mount_manager::get_mount_points() { - std::cout << "mount_points: " << mount_points_.size() << " mounts: " << mounts_.size() << "\n"; - return mount_points_; -} - -bool mount_manager::update_mount_points() { - mnt_init_debug(0); - - using unique_table_t = std::unique_ptr; - unique_table_t tb(mnt_new_table(), &mnt_free_table); - if (!tb) - return false; - - mnt_table_set_parser_errcb(tb.get(), - [](libmnt_table *tb, const char *filename, int line) { - (void)tb; - std::cerr << filename << ": parse error at line " << line << " -- ignored\n"; - return 1; - }); - - // 使用 "/proc/self/mountinfo",否则导致NTFS挂载点被隐藏 - if (mnt_table_parse_mtab(tb.get(), "/proc/self/mountinfo") != 0) { - std::cerr << "Can't read /proc/self/mountinfo\n"; - return false; - } - - // 解析成功,清除之前的 mount 信息 - mount_points_.clear(); - - // 向前查找,保存信息与 "cat /proc/self/mountinfo" 得到信息一致 - libmnt_iter* iter = mnt_new_iter(MNT_ITER_FORWARD); - libmnt_fs* fs; - - while (mnt_table_next_fs(tb.get(), iter, &fs) == 0) { - mount_point info; - info.device_id = mnt_fs_get_devno(fs); - info.type = mnt_fs_get_fstype(fs); - if (!major(info.device_id) && info.type != "fuse.dlnfs") { - // std::cout << "ignore the virtual: " << info.type << "\n"; - continue; - } - info.source = mnt_fs_get_source(fs); - info.target = mnt_fs_get_target(fs); - info.root = mnt_fs_get_root(fs); - info.real_device = info.source; - - std::cout << "device_id: " << info.device_id << ", type: " << info.type - << ", source: " << info.source << ", target: " << info.target - << ", root: " << info.root << ", real_device: " << info.real_device << "\n"; - mount_points_.push_back(std::move(info)); - } - - mnt_free_iter(iter); - - std::cout << "-------------------------------\n"; - return true; -} - -std::string mount_manager::find_mount_point(const std::string& path, bool hardreal) { - std::string result; - std::string result_path = path; - - for (;;) { - char* mp = mnt_get_mountpoint(result_path.c_str()); - if (mp) { - result = std::string(mp); - free(mp); - if (hardreal) { - bool find_virtual = false; - for (const auto& info : mount_points_) { - // 找到挂载点相同,但是虚拟设备(major=0),向上一级找到真实设备挂载点 - if (result == info.target && !major(info.device_id)) { - // 赋值当前挂载点,进入向上一级目录 - result_path = result; - find_virtual = true; - break; - } - } - - if (!find_virtual) { - break; // 遍历完但是没有找到虚拟设备,返回当前挂载点 - } - } else { - break; // 不需要向上找到真实设备挂载,直接返回 - } - } - - // 已经向上找到根'/', 返回 - if (result_path == "/") { - result = result_path; - break; - } - - auto last_dir_split_pos = result_path.find_last_of('/'); - if (last_dir_split_pos == std::string::npos) - break; - - result_path = result_path.substr(0, last_dir_split_pos); - if (result_path.empty()) - result_path = "/"; - } - - return result; -} - -bool mount_manager::path_match_type(const std::string& path, const std::string& type) { - auto point = find_mount_point(path); - for (const auto& info : mount_points_) { - if (point == info.target && type == info.type) - return true; - } - - return false; -} - -bool mount_manager::write_vfs_unnamed_device(const std::string &str) { - std::ofstream file("/sys/kernel/vfs_monitor/vfs_unnamed_devices"); - if (!file.is_open()) { - std::cerr << "Failed to open file: /sys/kernel/vfs_monitor/vfs_unnamed_devices\n"; - return false; - } - - file << str; - return true; -} - -bool mount_manager::read_vfs_unnamed_device(std::unordered_set &devices) { - std::ifstream file("/sys/kernel/vfs_monitor/vfs_unnamed_devices"); - if (!file.is_open()) { - std::cerr << "Failed to open file: /sys/kernel/vfs_monitor/vfs_unnamed_devices\n"; - return false; - } - - std::string line; - if (std::getline(file, line)) { - // Only includes a whitespace in this line - if (line.find_first_not_of(' ') == std::string::npos) - return false; - - std::cout << "line(read_vfs_unnamed_device): " << line << "\n"; - auto minors = string_helper::split(line, ","); - for (auto&& minor : minors) - devices.insert(std::move(minor)); - } - - std::cout << "devices: " << devices.size() << " 1: " << *devices.begin() << "\n"; - return true; -} - -bool mount_manager::update_vfs_unnamed_device(const std::unordered_set& new_devices) { - std::unordered_set old_devices; - if (!read_vfs_unnamed_device(old_devices)) - return false; - - // Remove the old devices - std::vector removed_devices; - std::copy_if(old_devices.begin(), old_devices.end(), std::back_inserter(removed_devices), - [&new_devices](const std::string& device) { return new_devices.count(device) == 0; }); - for (const auto& minor : removed_devices) { - if (!write_vfs_unnamed_device("r" + minor)) - return false; - } - - // Add the new devices - std::vector added_devices; - std::copy_if(new_devices.begin(), new_devices.end(), std::back_inserter(added_devices), - [&old_devices](const std::string& device) { return old_devices.count(device) == 0; }); - for (const auto& minor : added_devices) { - if (!write_vfs_unnamed_device("a" + minor)) - return false; - } - - return true; -} - -ANYTHING_NAMESPACE_END \ No newline at end of file diff --git a/src/daemon/src/core/pinyin_processor.cpp b/src/daemon/src/core/pinyin_processor.cpp deleted file mode 100644 index 41801e63..00000000 --- a/src/daemon/src/core/pinyin_processor.cpp +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "core/pinyin_processor.h" - -#include -#include -#include - -#include "utils/string_helper.h" - -ANYTHING_NAMESPACE_BEGIN - -pinyin_processor::pinyin_processor(const std::string& filename) { - load_pinyin_dict(filename); -} - -void pinyin_processor::load_pinyin_dict(const std::string& filename) { - std::ifstream file(filename); - if (!file.is_open()) { - return; - } - - std::string line; - while (std::getline(file, line)) { - if (!line.empty() && string_helper::starts_with(line, "U+")) { - if (auto colon_pos = line.find_first_of(':'); - colon_pos != std::string::npos) { - auto unicode = line.substr(2, colon_pos - 2); // index, length - - // Convert hex string to decimal and then to wchar_t - wchar_t unicode_char = static_cast(hex_to_dec(unicode)); - std::wstring_convert> converter; - std::string hanzi = converter.to_bytes(unicode_char); - - if (auto hash_pos = line.find_first_of('#'); - hash_pos != std::string::npos) { - auto pinyin = line.substr(colon_pos + 1, hash_pos - colon_pos - 1); - pinyin_dict_.emplace(std::move(hanzi), - string_helper::split(string_helper::trim(pinyin), ",")); - } - } - } - } -} - -void pinyin_processor::convert_to_pinyin(const std::string& sentence, std::string& pinyin_full, std::string& pinyin_acronym) { - auto results = split_utf8_characters(sentence); - std::string new_sentence; - std::string pinyin_temp; - std::string pinyin_acronym_english; - std::string pinyin_english; - std::vector pinyin_phrase_groups; - bool last_is_utf8_character = false; - bool last_is_single_character = false; - for (auto const& character : results) { - if (auto it = pinyin_dict_.find(character); it != pinyin_dict_.end()) { - if (last_is_single_character || last_is_utf8_character) { - new_sentence += " "; - if (!pinyin_temp.empty()) - pinyin_temp += " "; - } - - auto pinyin = remove_tone(it->second[0]); - new_sentence += pinyin; - pinyin_temp += pinyin; - - size_t char_len = get_utf8_char_length(pinyin[0]); - pinyin_acronym_english += pinyin.substr(0, char_len); - - pinyin_english += pinyin; - - last_is_utf8_character = true; - last_is_single_character = false; - } else { - if (last_is_utf8_character) { - new_sentence += " "; - if (!pinyin_temp.empty()) { - pinyin_phrase_groups.push_back(std::move(pinyin_temp)); - } - } - - new_sentence += character; - pinyin_acronym_english += character; - pinyin_english += character; - last_is_utf8_character = false; - last_is_single_character = true; - } - } - - if (!pinyin_temp.empty()) { - pinyin_phrase_groups.push_back(std::move(pinyin_temp)); - } - - for (auto const& phrase : pinyin_phrase_groups) { - auto words = string_helper::split(phrase, " "); - std::string acronym; - for (auto const& word : words) { - if (acronym.empty()) new_sentence += " "; - size_t char_len = get_utf8_char_length(word[0]); - acronym += word.substr(0, char_len); - new_sentence += word; - } - new_sentence += " " + acronym; - } - - new_sentence += " " + pinyin_acronym_english; - new_sentence += " " + pinyin_english; - - pinyin_full = std::move(pinyin_english); - pinyin_acronym = std::move(pinyin_acronym_english); - - // remove space in pinyin_full and pinyin_acronym - pinyin_full.erase(std::remove_if(pinyin_full.begin(), pinyin_full.end(), [](unsigned char c) { - return std::isspace(c); - }), pinyin_full.end()); - pinyin_acronym.erase(std::remove_if(pinyin_acronym.begin(), pinyin_acronym.end(), [](unsigned char c) { - return std::isspace(c); - }), pinyin_acronym.end()); -} - -unsigned int pinyin_processor::hex_to_dec(const std::string& hex_str) { - unsigned int result = 0; - for (char c : hex_str) { - result *= 16; - if (c >= '0' && c <= '9') { - result += c - '0'; - } else if (c >= 'A' && c <= 'F') { - result += c - 'A' + 10; - } else if (c >= 'a' && c <= 'f') { - result += c - 'a' + 10; - } - } - - return result; -} - -int pinyin_processor::get_utf8_char_length(unsigned char c) { - if ((c & 0x80) == 0) return 1; - if ((c & 0xE0) == 0xC0) return 2; - if ((c & 0xF0) == 0xE0) return 3; - if ((c & 0xF8) == 0xF0) return 4; - return 1; -} - -std::string pinyin_processor::remove_tone(const std::string& pinyin) { - static const std::unordered_map tone_map = { - { "ā", "a" }, { "á", "a" }, { "ǎ", "a" }, { "à", "a" }, - { "ē", "e" }, { "é", "e" }, { "ě", "e" }, { "è", "e" }, - { "ī", "i" }, { "í", "i" }, { "ǐ", "i" }, { "ì", "i" }, - { "ō", "o" }, { "ó", "o" }, { "ǒ", "o" }, { "ò", "o" }, - { "ū", "u" }, { "ú", "u" }, { "ǔ", "u" }, { "ù", "u" }, - { "ǖ", "v" }, { "ǘ", "v" }, { "ǚ", "v" }, { "ǜ", "v" }, - { "ü", "v" } - }; - - std::string result; - for (size_t i = 0; i < pinyin.size();) { - size_t char_len = get_utf8_char_length(pinyin[i]); - std::string char_str = pinyin.substr(i, char_len); - if (auto it = tone_map.find(char_str); - it != tone_map.end()) { - result += it->second; // Replace with tone-free character - } else { - result += char_str; // Keep original character if no tone - } - - i += char_len; - } - - return result; -} - -std::vector pinyin_processor::split_utf8_characters( - const std::string& sentence) { - std::vector result; - std::size_t i = 0; - - while (i < sentence.length()) { - int char_len = get_utf8_char_length(sentence[i]); - result.push_back(sentence.substr(i, char_len)); - i += char_len; - } - - return result; -} - -ANYTHING_NAMESPACE_END \ No newline at end of file diff --git a/src/daemon/src/core/thread_pool.cpp b/src/daemon/src/core/thread_pool.cpp deleted file mode 100644 index 38159d29..00000000 --- a/src/daemon/src/core/thread_pool.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "core/thread_pool.h" - -#include - -#include "utils/log.h" - -ANYTHING_NAMESPACE_BEGIN - -thread_pool::thread_pool(unsigned int num) - : stop_thread_(false) { - for (unsigned int i = 0; i < num; ++i) { - threads_.emplace_back(std::thread(&thread_pool::thread_loop, this)); - } -} - -void thread_pool::enqueue_detach(job_type job) { - { - std::lock_guard lock(mtx_); - jobs_.push(std::move(job)); - } - cv_.notify_one(); -} - -void thread_pool::wait_for_tasks() { - { - std::lock_guard lock(mtx_); - stop_thread_ = true; - } - - cv_.notify_all(); - for (auto& t : threads_) { - auto thread_id = t.get_id(); - t.join(); - std::ostringstream oss; - oss << thread_id; - spdlog::info("Pool thread {} has exited.", oss.str()); - } - - threads_.clear(); -} - -bool thread_pool::busy() { - std::lock_guard lock(mtx_); - return !jobs_.empty(); -} - -void thread_pool::thread_loop() { - for (;;) { - job_type job; - { - std::unique_lock lock(mtx_); - cv_.wait(lock, [this]{ return !jobs_.empty() || stop_thread_; }); - - if (stop_thread_) - break; - - job = std::move(jobs_.front()); - jobs_.pop(); - } - - // do the job - job(); - } -} - -ANYTHING_NAMESPACE_END \ No newline at end of file diff --git a/src/daemon/src/main.cpp b/src/daemon/src/main.cpp deleted file mode 100644 index 41af88f2..00000000 --- a/src/daemon/src/main.cpp +++ /dev/null @@ -1,142 +0,0 @@ -// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include -#include - -#include "anything.hpp" -#include "core/config.h" -#include "utils/running_flag.h" - -#include -#include - -using namespace anything; - -extern "C" { -static void on_event_received(gpointer user_data, fs_event *event) { - auto handler = static_cast(user_data); - handler->handle(event); -} - -static void on_quit_requested(gpointer user_data) { - (void)user_data; - spdlog::info("Event listener disconnected after exhausting reconnects, exit"); - set_app_restart(false); - qApp->quit(); -} -} - -// 判断 uid 是否可登录 -bool can_user_login() { - struct passwd pwd, *result = NULL; - gchar buf[1024]; - uid_t uid = getuid(); - - if (getpwuid_r(uid, &pwd, buf, sizeof(buf), &result) != 0 || !result) { - spdlog::warn("User not found"); - return false; - } - - // 检查登录 Shell - if (g_strcmp0(pwd.pw_shell, "/sbin/nologin") == 0 || - g_strcmp0(pwd.pw_shell, "/bin/false") == 0) { - spdlog::warn("User can not login: {}", uid); - return false; - } - - return true; -} - -// 收到信号后调用, 运行在 Qt 事件循环中 -gboolean on_sigint_sigterm(gpointer user_data) { - spdlog::info("Interrupt signal ({}) received, quit", (const char *) user_data); - remove_running_flag(); - set_app_restart(false); - qApp->quit(); - - return TRUE; -} - -int main(int argc, char* argv[]) { - QCoreApplication app(argc, argv); - - if (!can_user_login()) - exit(APP_QUIT_CODE); - - spdlog::info("Anything daemon starting..."); - // 打印版本号(如果在编译时定义了的话) -#ifdef DEEPIN_ANYTHING_VERSION - spdlog::info("Deepin Anything version: {}", DEEPIN_ANYTHING_VERSION); -#endif - // 打印commit号(如果在编译时定义了的话) -#ifdef DEEPIN_ANYTHING_COMMIT_HASH - spdlog::info("Deepin Anything commit: {}", DEEPIN_ANYTHING_COMMIT_HASH); -#endif - spdlog::info("Qt version: {}", qVersion()); - - Config config; - event_handler_config event_handler_config = config.make_event_handler_config(); - - spdlog::set_level(spdlog::level::from_str(config.get_log_level())); - spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [thread %t] %v"); - - set_volatile_index_dir(event_handler_config.volatile_index_dir); - detect_last_time_quit_status(); - set_running_flag(); - - print_event_handler_config(event_handler_config); - default_event_handler handler(event_handler_config); - // default_event_handler 实例化时, 可能会清空索引目录, 这里重新设置 running 标志 - set_running_flag(); - EventListener *listener = event_listener_new(on_event_received, - on_quit_requested, - &handler); - config.set_config_change_handler([&handler, &config](std::string key) { - spdlog::info("Config changed: {}", key); - - if (key == LOG_LEVEL_KEY) { - spdlog::set_level(spdlog::level::from_str(config.get_log_level())); - return; - } - - auto new_config = config.make_event_handler_config(); - bool handled = handler.handle_config_change(key, new_config); - - if (handled) { - spdlog::info("Config changes have been processed."); - } else { - handler.set_index_invalid_and_restart(); - } - }); - - if (!event_listener_start(listener)) { - spdlog::error("Failed to start event listener"); - event_listener_free(listener); - handler.terminate_filter(); - handler.terminate_processing(); - return APP_QUIT_CODE; - } - - // Process the interrupt signal using g_unix_signal_add() - guint sigint_id = g_unix_signal_add(SIGINT, on_sigint_sigterm, (gpointer)"SIGINT"); - guint sigterm_id = g_unix_signal_add(SIGTERM, on_sigint_sigterm, (gpointer)"SIGTERM"); - - app.exec(); - - // Clean up signal handlers - if (sigint_id > 0) - g_source_remove(sigint_id); - if (sigterm_id > 0) - g_source_remove(sigterm_id); - - spdlog::info("Performing cleanup tasks..."); - event_listener_stop(listener); - event_listener_free(listener); - handler.terminate_filter(); - handler.terminate_processing(); - - spdlog::info("Anything daemon stopped."); - return get_app_ret_code(); -} diff --git a/src/daemon/src/utils/running_flag.cpp b/src/daemon/src/utils/running_flag.cpp deleted file mode 100755 index 43d2eed4..00000000 --- a/src/daemon/src/utils/running_flag.cpp +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -// 本模块实现运行标志文件管理,用于检测守护进程的退出状态 -// -// 工作流程: -// 1. 启动初始化:调用 set_volatile_index_dir() 设置目录 -// 2. 检测上次状态:调用 detect_last_time_quit_status() 检查标志文件 -// 3. 设置运行标志:调用 set_running_flag() 创建运行标志文件 -// 4. 获取上次状态:调用 is_last_time_normal_quit() 获取退出状态 -// 5. 正常退出前:调用 remove_running_flag() 移除运行标志文件 - -#include "utils/running_flag.h" - -#include -#include -#include -#include -#include - -static std::string volatile_index_dir_; -static bool is_last_time_normal_quit_ = false; -static std::mutex flag_mutex_; -static const char RUNNING_FLAG_FILE[] = "running"; - -static std::string get_running_flag_path() -{ - return volatile_index_dir_ + "/" + RUNNING_FLAG_FILE; -} - -static bool ensure_directory_exists() -{ - std::error_code ec; - if (!std::filesystem::exists(volatile_index_dir_, ec)) { - if (ec) { - spdlog::error("Failed to check directory existence {}: {}", - volatile_index_dir_, ec.message()); - return false; - } - - spdlog::info("Creating volatile index directory: {}", volatile_index_dir_); - - std::filesystem::create_directories(volatile_index_dir_, ec); - if (ec) { - spdlog::error("Failed to create directory {}: {}", volatile_index_dir_, - ec.message()); - return false; - } - - spdlog::info("Created directory: {}", volatile_index_dir_); - } - - return true; -} - -void set_volatile_index_dir(const std::string &volatile_index_dir) -{ - g_return_if_fail(!volatile_index_dir.empty()); - - std::lock_guard lock(flag_mutex_); - volatile_index_dir_ = volatile_index_dir; -} - -void detect_last_time_quit_status() -{ - std::lock_guard lock(flag_mutex_); - - if (!ensure_directory_exists()) { - spdlog::warn("Volatile index directory check failed, assuming abnormal exit"); - is_last_time_normal_quit_ = false; - return; - } - - std::string running_flag_path = get_running_flag_path(); - - if (g_file_test(running_flag_path.c_str(), G_FILE_TEST_EXISTS)) { - // 标志文件存在,说明上次异常退出(崩溃或被终止) - is_last_time_normal_quit_ = false; - spdlog::warn("Running flag exists, last quit was abnormal"); - } else { - // 标志文件不存在,说明上次正常退出 - is_last_time_normal_quit_ = true; - spdlog::info("Running flag does not exist, last quit was normal"); - } -} - -void set_running_flag(void) -{ - std::lock_guard lock(flag_mutex_); - - if (!ensure_directory_exists()) { - spdlog::error("Volatile index directory check failed, cannot set running flag"); - return; - } - - std::string running_flag_path = get_running_flag_path(); - - if (g_file_test(running_flag_path.c_str(), G_FILE_TEST_EXISTS)) { - spdlog::debug("Running flag already exists at {}, skipping", running_flag_path); - return; - } - - if (!g_file_set_contents(running_flag_path.c_str(), "", -1, nullptr)) { - spdlog::warn("Failed to set running flag at {}: {}", running_flag_path, - strerror(errno)); - } else { - spdlog::info("Running flag set successfully at {}", running_flag_path); - } -} - -bool is_last_time_normal_quit(void) -{ - std::lock_guard lock(flag_mutex_); - return is_last_time_normal_quit_; -} - -void remove_running_flag(void) -{ - std::lock_guard lock(flag_mutex_); - - std::string running_flag_path = get_running_flag_path(); - - if (g_file_test(running_flag_path.c_str(), G_FILE_TEST_EXISTS)) { - if (g_unlink(running_flag_path.c_str()) != 0) { - spdlog::warn("Failed to remove running flag at {}: {}", running_flag_path, - strerror(errno)); - } else { - spdlog::info("Running flag removed successfully from {}", running_flag_path); - } - } else { - spdlog::debug("Running flag file does not exist at {}, skipping removal", - running_flag_path); - } -} diff --git a/src/daemon/src/utils/string_helper.cpp b/src/daemon/src/utils/string_helper.cpp deleted file mode 100644 index 71315d3c..00000000 --- a/src/daemon/src/utils/string_helper.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (C) 2024 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "utils/string_helper.h" - -ANYTHING_NAMESPACE_BEGIN - -ANYTHING_NAMESPACE_END \ No newline at end of file diff --git a/src/searcher/CMakeLists.txt b/src/searcher/CMakeLists.txt deleted file mode 100644 index 48462079..00000000 --- a/src/searcher/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -cmake_minimum_required(VERSION 3.10) -project(deepin-anything-searcher) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -# Find required packages -find_package(PkgConfig REQUIRED) -pkg_check_modules(GLIB REQUIRED glib-2.0) -pkg_check_modules(LUCENE REQUIRED liblucene++) -find_package(Threads REQUIRED) -find_package(Boost REQUIRED) -if (Boost_VERSION_STRING VERSION_LESS "1.89.0") - message(STATUS "Boost < 1.89 → using Boost::system") - find_package(Boost REQUIRED COMPONENTS system) -endif() - -# Add executable -add_executable(deepin-anything-searcher - main.cpp - searcher.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../daemon/src/analyzers/LowerCaseNGramAnalyzer.cpp -) - -# Include directories -target_include_directories(deepin-anything-searcher PRIVATE - ${GLIB_INCLUDE_DIRS} - ${LUCENE_INCLUDE_DIRS} - ${CMAKE_CURRENT_SOURCE_DIR}/../daemon/include -) - -# Link libraries -target_link_libraries(deepin-anything-searcher - ${GLIB_LIBRARIES} - ${LUCENE_LIBRARIES} - Threads::Threads - ${Boost_LIBRARIES} - stdc++fs -) - -target_link_options(deepin-anything-searcher PRIVATE -pie) - -# Install -install(TARGETS deepin-anything-searcher - RUNTIME DESTINATION bin -) \ No newline at end of file diff --git a/src/searcher/main.cpp b/src/searcher/main.cpp deleted file mode 100644 index ea3718e0..00000000 --- a/src/searcher/main.cpp +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (C) 2025 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "searcher.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void printUsage(const char* programName) { - std::cout << "Usage: " << programName << " [-i index_path] [-w] [path] " << std::endl; - std::cout << "Options:" << std::endl; - std::cout << " -i index_path Specify the index path (default: " << std::string(g_get_user_runtime_dir()) << "/deepin-anything-server)" << std::endl; - std::cout << " -w Enable wildcard search" << std::endl; - std::cout << "Examples:" << std::endl; - std::cout << " " << programName << " -i /path/to/index /home \"txt\"" << std::endl; - std::cout << " " << programName << " -w /home \"*.txt\"" << std::endl; - std::cout << " " << programName << " /home \"txt\"" << std::endl; - std::cout << " " << programName << " \"txt\" (searches in /)" << std::endl; -} - -void search_by_index(const std::string &path, - const std::string &query, - int max_results, - bool wildcard_query, - const std::string &index_path, - std::vector &results) -{ - // 创建搜索器实例 - anything::Searcher searcher; - - // 初始化搜索器 - if (!searcher.initialize(index_path)) { - std::cerr << "Failed to initialize searcher" << std::endl; - return; - } - - // 执行搜索 - results = searcher.search(path, query, max_results, wildcard_query); -} - -void search_by_scan(const std::string &path, - const std::string &query, - std::vector &results) -{ - // 在目录 path 下, 查找包含 query 字符串的文件名和目录名, 将查找结果保存到 results - try { - // 检查路径是否存在且为目录 - if (!std::filesystem::exists(path) || !std::filesystem::is_directory(path)) { - std::cerr << "Path does not exist or is not a directory: " << path << std::endl; - return; - } - - // 递归遍历目录 - for (const auto& entry : std::filesystem::recursive_directory_iterator( - path, std::filesystem::directory_options::skip_permission_denied)) { - - // 获取文件名(不包含路径) - std::string filename = entry.path().filename().string(); - - if (filename.find(query) != std::string::npos) { - // 将完整路径添加到结果中 - results.push_back(entry.path().string()); - } - } - } catch (const std::filesystem::filesystem_error& ex) { - std::cerr << "Filesystem error while scanning: " << ex.what() << std::endl; - } catch (const std::exception& ex) { - std::cerr << "Error while scanning: " << ex.what() << std::endl; - } -} - -void search(const std::string &path, - const std::string &query, - int max_results, - bool wildcard_query, - const std::string &index_path, - std::vector &results) -{ - // 查看指定文件中是否包含 '"status": "updating"' 字符串 - std::string status_file = index_path + "/status.json"; - std::ifstream file(status_file); - if (!file.is_open()) { - std::cerr << "Fail to open status file: " << status_file << std::endl; - return; - } - - std::stringstream buffer; - buffer << file.rdbuf(); - std::string content = buffer.str(); - - bool found = content.find("\"status\": \"updating\"") != std::string::npos; - - // 决定搜索方式 - if (found) { - std::cout << "Index is updating, using scan search." << std::endl; - search_by_scan(path, query, results); - } else { - std::cout << "Index is ready, using index search." << std::endl; - search_by_index(path, query, max_results, wildcard_query, index_path, results); - } -} - -int main(int argc, char* argv[]) { - std::string default_index_path = std::string(g_get_user_runtime_dir()) + "/deepin-anything-server"; - const char* index_path = default_index_path.c_str(); - g_autofree char* search_path = nullptr; - const char* query = nullptr; - bool wildcard_query = false; - int opt; - - // 处理命令行选项 - while ((opt = getopt(argc, argv, "i:w")) != -1) { - switch (opt) { - case 'i': - index_path = optarg; - break; - case 'w': - wildcard_query = true; - break; - default: - printUsage(argv[0]); - return 1; - } - } - - // 检查剩余参数 - int remaining_args = argc - optind; - if (remaining_args < 1 || remaining_args > 2) { - printUsage(argv[0]); - return 1; - } - - // 获取搜索路径和查询 - if (remaining_args == 2) { - search_path = g_canonicalize_filename (argv[optind], NULL); - if (!search_path) { - std::cerr << "Fail to canonicalize search path: " << argv[optind] << std::endl; - return 1; - } - query = argv[optind + 1]; - } else { - search_path = g_strdup("/"); - query = argv[optind]; - } - - // 执行搜索 - std::vector results; - search(search_path, query, 0, wildcard_query, index_path, results); - - // 输出结果 - if (results.empty()) { - std::cout << "No results found." << std::endl; - } else { - std::cout << "Found " << results.size() << " results:" << std::endl; - for (const auto& result : results) { - std::cout << result << std::endl; - } - } - - return 0; -} \ No newline at end of file diff --git a/src/searcher/searcher.cpp b/src/searcher/searcher.cpp deleted file mode 100644 index 7097d430..00000000 --- a/src/searcher/searcher.cpp +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (C) 2025 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "searcher.h" -#include "analyzers/LowerCaseNGramAnalyzer.h" -#include "utils/string_helper.h" -#include -#include - -using namespace Lucene; - -namespace anything { - -Searcher::Searcher() { -} - -Searcher::~Searcher() { - // 清理 Lucene 资源 - if (reader) { - reader->close(); - } -} - -bool Searcher::initialize(const std::string& index_path) { - if (!checkIndexPath(index_path)) { - std::cerr << "Invalid index path: " << index_path << std::endl; - return false; - } - - try { - // 打开索引目录 - FSDirectoryPtr dir = FSDirectory::open(StringUtils::toUnicode(index_path.c_str())); - reader = IndexReader::open(dir, true); - searcher = newLucene(reader); - return true; - } catch (const LuceneException& e) { - std::cerr << "Failed to initialize searcher: " << StringUtils::toUTF8(e.getError()) << std::endl; - return false; - } -} - -std::vector Searcher::search(const std::string& path, - const std::string& query, - int max_results, - bool wildcard_query) { - std::vector results; - - if (!searcher) { - std::cerr << "Searcher not initialized" << std::endl; - return results; - } - - try { - BooleanQueryPtr finalQuery = newLucene(); - String query_string = StringUtils::toLower(StringUtils::toUnicode(query.c_str())); - - // 文件名搜索 - if (wildcard_query) { - TermPtr term = newLucene(L"file_name_lower", query_string); - QueryPtr wildcardQuery = newLucene(term); - finalQuery->add(wildcardQuery, BooleanClause::MUST); - } else { - // 创建查询解析器 - AnalyzerPtr analyzer = newLucene(1, 2); - QueryParserPtr parser = newLucene(LuceneVersion::LUCENE_CURRENT, L"file_name", analyzer); - - // 解析查询 - QueryPtr parserQuery = parser->parse(query_string); - finalQuery->add(parserQuery, BooleanClause::MUST); - } - - // 搜索路径前缀过滤 - { - g_autofree gchar *canonical = g_canonicalize_filename (path.c_str(), NULL); - TermPtr term = newLucene(L"ancestor_paths", StringUtils::toUnicode(canonical)); - QueryPtr prefixQuery = newLucene(term); - finalQuery->add(prefixQuery, BooleanClause::MUST); - } - - // 执行搜索 - if (max_results == 0) { - max_results = reader->numDocs(); - } - std::cout << "Doc num: " << reader->numDocs() << std::endl; - TopDocsPtr topDocs = searcher->search(finalQuery, max_results); - results.reserve(topDocs->totalHits); - - // 处理搜索结果 - for (int32_t i = 0; i < topDocs->totalHits; ++i) { - ScoreDocPtr scoreDoc = topDocs->scoreDocs[i]; - DocumentPtr doc = searcher->doc(scoreDoc->doc); - std::stringstream ss; - ss << StringUtils::toUTF8(doc->get(L"full_path")) - << "<\\>" << StringUtils::toUTF8(doc->get(L"file_type")) - << "<\\>" << StringUtils::toUTF8(doc->get(L"file_ext")) - << "<\\>" << StringUtils::toUTF8(doc->get(L"birth_time")) - << "<\\>" << StringUtils::toUTF8(doc->get(L"modify_time")) - << "<\\>" << StringUtils::toUTF8(doc->get(L"file_size_str")) - << "<\\>" << StringUtils::toUTF8(doc->get(L"pinyin")) - << "<\\>" << StringUtils::toUTF8(doc->get(L"pinyin_acronym")) - << "<\\>" << StringUtils::toUTF8(doc->get(L"is_hidden")); - std::string result = ss.str(); - results.push_back(result); - } - } catch (const LuceneException& e) { - std::cerr << "Search failed: " << StringUtils::toUTF8(e.getError()) << std::endl; - } - - return results; -} - -bool Searcher::checkIndexPath(const std::string& path) { - return g_file_test(path.c_str(), G_FILE_TEST_IS_DIR); -} - -} // namespace anything \ No newline at end of file diff --git a/src/searcher/searcher.h b/src/searcher/searcher.h deleted file mode 100644 index f9628ded..00000000 --- a/src/searcher/searcher.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (C) 2025 UOS Technology Co., Ltd. -// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef DEEPIN_ANYTHING_SEARCHER_H -#define DEEPIN_ANYTHING_SEARCHER_H - -#include -#include -#include -#include - -namespace anything { - -class Searcher { -public: - Searcher(); - ~Searcher(); - - // 初始化搜索器 - bool initialize(const std::string& index_path); - - // 执行搜索 - std::vector search(const std::string& path, const std::string& query, int max_results = 0, bool wildcard_query = false); - -private: - // Lucene 相关成员 - Lucene::IndexReaderPtr reader; - Lucene::SearcherPtr searcher; - - // 检查索引路径是否有效 - bool checkIndexPath(const std::string& path); -}; - -} // namespace anything - -#endif // DEEPIN_ANYTHING_SEARCHER_H \ No newline at end of file diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index 1b43a223..cc287e33 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -15,8 +15,8 @@ add_executable(${PROJECT_NAME} mount-monitor.c event-listener.c event-dispatcher.c - ${CMAKE_CURRENT_SOURCE_DIR}/../daemon/src/core/mount_info.c - ${CMAKE_CURRENT_SOURCE_DIR}/../daemon/src/utils/tools.c + mount_info.c + tools.c ) target_include_directories(${PROJECT_NAME} PRIVATE @@ -27,7 +27,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE ${LIBNL_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/../kernelmod ${CMAKE_CURRENT_SOURCE_DIR}/../dispatcher - ${CMAKE_CURRENT_SOURCE_DIR}/../daemon/include + ${CMAKE_CURRENT_SOURCE_DIR} ) target_link_libraries(${PROJECT_NAME} PRIVATE diff --git a/src/server/event-dispatcher.c b/src/server/event-dispatcher.c index dba90a52..b2b97ef7 100644 --- a/src/server/event-dispatcher.c +++ b/src/server/event-dispatcher.c @@ -14,8 +14,8 @@ #include "vfs_change_consts.h" #include "event_dispatcher.h" -#include "core/mount_info.h" -#include "utils/tools.h" +#include "mount_info.h" +#include "tools.h" #define ACT_TERMINATE 100 #define ACT_WAKEUP 101 diff --git a/src/daemon/src/core/mount_info.c b/src/server/mount_info.c similarity index 99% rename from src/daemon/src/core/mount_info.c rename to src/server/mount_info.c index 7803d236..28849123 100644 --- a/src/daemon/src/core/mount_info.c +++ b/src/server/mount_info.c @@ -3,7 +3,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -#include "core/mount_info.h" +#include "mount_info.h" #include #include diff --git a/src/daemon/include/core/mount_info.h b/src/server/mount_info.h similarity index 100% rename from src/daemon/include/core/mount_info.h rename to src/server/mount_info.h diff --git a/src/daemon/src/utils/tools.c b/src/server/tools.c similarity index 99% rename from src/daemon/src/utils/tools.c rename to src/server/tools.c index 388c05ba..7d3dc2b0 100755 --- a/src/daemon/src/utils/tools.c +++ b/src/server/tools.c @@ -4,7 +4,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #define _GNU_SOURCE -#include "utils/tools.h" +#include "tools.h" #include #include #include diff --git a/src/daemon/include/utils/tools.h b/src/server/tools.h similarity index 94% rename from src/daemon/include/utils/tools.h rename to src/server/tools.h index 330b7442..4e26dcb7 100755 --- a/src/daemon/include/utils/tools.h +++ b/src/server/tools.h @@ -7,7 +7,7 @@ #define ANYTHING_TOOLS_H_ #include -#include "core/mount_info.h" +#include "mount_info.h" #ifdef __cplusplus extern "C" { diff --git a/tests/stress_stop_start.sh b/tests/stress_stop_start.sh deleted file mode 100755 index fc98c8b2..00000000 --- a/tests/stress_stop_start.sh +++ /dev/null @@ -1,414 +0,0 @@ -#!/bin/bash -# SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# deepin-anything 服务停启压测脚本 -# -# 循环验证 server/daemon 的健康状态、正常关闭、恢复运行 -# 整体以 root 身份运行;daemon 作为用户级 systemd 服务, -# 通过 runuser 切换到目标用户身份执行 systemctl --user 操作。 -# -# 用法: -# sudo ./tests/stress_stop_start.sh # 无限循环,Ctrl+C 停止 -# sudo ./tests/stress_stop_start.sh 20 # 固定 20 轮 -# -# 中断行为: 收到 SIGINT/SIGTERM 后立即中断当前等待并退出,不等待 -# 当前阶段完成;服务可能停留在停止或中间状态 (这是预期的,用户要退出)。 -# -# 退出码: -# 0 正常完成 -# 1 参数/环境错误 -# 2 检查阶段失败 (server/daemon 未运行或状态非 monitoring) -# 3 停止阶段失败 (服务未在预期时间内退出) -# 4 恢复阶段失败 (daemon 未在预期时间内进入 monitoring) -# 5 压测结束但有失败轮次 -# 130 收到中断信号提前退出 -set -u -umask 0022 - -# ===================== 配置 ===================== - -SERVER_SERVICE="deepin-anything-server" # 系统服务 (root) -DAEMON_SERVICE="deepin-anything-daemon" # 用户服务 - -# 停止阶段: 先停 server,间隔 1s,再停 daemon;两者总等待上限 -STOP_INTERVAL_S=1 -STOP_WAIT_S=2 - -# 恢复阶段: 先启 server,间隔 1s,再启 daemon;等待 daemon 进入 monitoring 上限 -START_INTERVAL_S=1 -MONITOR_WAIT_S=600 # 10 min - -# 状态文件根目录,会按运行用户 uid 拼接: /run/user//deepin-anything-server/status.json -STATUS_FILE_DIR_PREFIX="/run/user" - -# 中断返回码 (收到 SIGINT/SIGTERM 时由各阶段返回,主循环据此跳过恢复直接退出) -RC_INTERRUPTED=130 - -# ===================== 日志 ===================== - -# 颜色 (非 tty 自动关闭) -if [ -t 1 ]; then - C_RED=$'\033[31m'; C_GRN=$'\033[32m'; C_YEL=$'\033[33m' - C_CYN=$'\033[36m'; C_RST=$'\033[0m' -else - C_RED=""; C_GRN=""; C_YEL=""; C_CYN=""; C_RST="" -fi - -ts() { date '+%Y-%m-%d %H:%M:%S'; } - -log_info() { printf '%s[%s INFO %s] %s%s\n' "${C_CYN}" "$(ts)" "${C_RST}" "$*" "${C_RST}"; } -log_ok() { printf '%s[%s OK %s] %s%s\n' "${C_GRN}" "$(ts)" "${C_RST}" "$*" "${C_RST}"; } -log_warn() { printf '%s[%s WARN %s] %s%s\n' "${C_YEL}" "$(ts)" "${C_RST}" "$*" "${C_RST}"; } -log_err() { printf '%s[%s ERROR%s] %s%s\n' "${C_RED}" "$(ts)" "${C_RST}" "$*" "${C_RST}" >&2; } - -# ===================== 环境 ===================== - -# 整体以 root 运行 (server 是系统服务需要 root) -if [ "$(id -u)" -ne 0 ]; then - log_err "本脚本需要以 root 身份运行 (server 为系统服务)" - exit 1 -fi - -# 自动检测当前登录用户: 取 tty/pts 上活跃会话对应的 uid,默认 1000 -# 优先取环境变量 SUDO_USER (sudo 运行),其次取一个有 /run/user 目录的登录用户 -detect_user() { - local uid - - # 1) sudo 透传的原始用户 - if [ -n "${SUDO_USER:-}" ] && [ "${SUDO_USER}" != "root" ]; then - uid="$(id -u "${SUDO_USER}" 2>/dev/null)" && [ -n "$uid" ] && { echo "$uid"; return; } - fi - - # 2) 查找当前有活跃 systemd 用户实例的登录用户 (有 /run/user//bus) - local best_uid="" best_time=0 - for d in /run/user/[0-9]*; do - [ -d "$d/bus" ] || continue - local u="${d##*/}" - # 该用户是否为活跃登录会话 - if loginctl show-user "$u" 2>/dev/null | grep -q '^State=active'; then - echo "$u" - return - fi - [ -z "$best_uid" ] && best_uid="$u" - done - - # 3) 回退: 取第一个存在的 /run/user/ - if [ -n "$best_uid" ]; then - echo "$best_uid" - return - fi - - # 4) 最终回退 1000 - echo 1000 -} - -RUN_UID="$(detect_user)" -RUN_USER="$(id -u "${RUN_UID}" >/dev/null 2>&1 && getent passwd "${RUN_UID}" | cut -d: -f1 || echo uos)" -RUN_DIR="/run/user/${RUN_UID}" -STATUS_FILE="${STATUS_FILE_DIR_PREFIX}/${RUN_UID}/deepin-anything-server/status.json" - -log_info "运行用户: ${RUN_USER} (uid=${RUN_UID}), 运行目录: ${RUN_DIR}" - -# 前置校验: 目标用户必须有活跃的 user-bus 才能操作其用户服务实例 -if [ ! -S "${RUN_DIR}/bus" ]; then - log_err "用户 ${RUN_USER} (uid=${RUN_UID}) 无 user-bus (${RUN_DIR}/bus)" - log_err "请确保该用户已活跃登录 (有 systemd 用户会话) 后再运行" - exit 1 -fi - -# ===================== 用户级 systemctl 包装 ===================== -# root 通过 runuser 切换到目标用户身份执行 systemctl --user。 -# 仅设置 XDG/DBUS 环境变量对 root 不够: systemd 拒绝非会话属主的 -# 总线连接 (报 "不允许的操作"),必须以目标用户身份运行。 - -user_systemctl() { - runuser -u "${RUN_USER}" -- env \ - XDG_RUNTIME_DIR="${RUN_DIR}" \ - DBUS_SESSION_BUS_ADDRESS="unix:path=${RUN_DIR}/bus" \ - systemctl --user "$@" -} - -server_systemctl() { - systemctl "$@" -} - -# ===================== 检查原语 ===================== - -check_server_running() { - server_systemctl is-active --quiet "$SERVER_SERVICE" -} - -check_daemon_running() { - user_systemctl is-active --quiet "$DAEMON_SERVICE" -} - -# daemon 监控状态: status.json 含 "monitoring" -check_daemon_monitoring() { - [ -f "$STATUS_FILE" ] || return 1 - grep -q '"monitoring"' "$STATUS_FILE" 2>/dev/null -} - -# daemon 监控状态 (新鲜度感知): status.json 含 monitoring 且 mtime 晚于基线时间戳 -# 基线由 MONITOR_BASELINE_NS 全局变量提供 (启动 daemon 前设置) -# 用于避免 daemon 停止后残留的旧 status.json 被误判为已进入 monitoring -MONITOR_BASELINE_S=0 -check_daemon_monitoring_fresh() { - [ -f "$STATUS_FILE" ] || return 1 - grep -q '"monitoring"' "$STATUS_FILE" 2>/dev/null || return 1 - # status.json 的 mtime (秒级) 必须严格晚于启动 daemon 前记录的基线 - local mtime_s - mtime_s=$(stat -c '%Y' "$STATUS_FILE" 2>/dev/null) || return 1 - [ "$mtime_s" -gt "$MONITOR_BASELINE_S" ] 2>/dev/null -} - -# 全局中断标志: SIGINT/SIGTERM 的 trap 置 1,各轮询循环据此立即退出 -INTERRUPTED=0 - -# 可中断 sleep: 收到中断信号立即返回,供阶段间停顿使用 -sleep_intr() { - local total="$1" - local slept=0 - while [ "$slept" -lt "$total" ]; do - [ "$INTERRUPTED" -ne 0 ] && return 1 - sleep 0.5 - slept=$((slept + 1)) - done - return 0 -} - -# 等待条件成立: 轮询直到条件满足或超时;收到中断信号立即退出 -# 用法: wait_for_condition <描述> <超时秒> <函数...> -wait_for_condition() { - local desc="$1"; shift - local timeout="$1"; shift - local start now elapsed - start=$(date +%s) - while true; do - [ "$INTERRUPTED" -ne 0 ] && { log_warn "等待中断: ${desc}"; return "$RC_INTERRUPTED"; } - if "$@"; then - return 0 - fi - now=$(date +%s); elapsed=$((now - start)) - if [ "$elapsed" -ge "$timeout" ]; then - log_err "等待超时 (${timeout}s): ${desc}" - return 1 - fi - sleep 0.5 - done -} - -# 反向等待: 等待条件不成立 (服务停止);收到中断信号立即退出 -# 用法: wait_for_not <描述> <超时秒> <函数...> -wait_for_not() { - local desc="$1"; shift - local timeout="$1"; shift - local start now elapsed - start=$(date +%s) - while true; do - [ "$INTERRUPTED" -ne 0 ] && { log_warn "等待中断: ${desc}"; return "$RC_INTERRUPTED"; } - if ! "$@"; then - return 0 - fi - now=$(date +%s); elapsed=$((now - start)) - if [ "$elapsed" -ge "$timeout" ]; then - log_err "等待超时 (${timeout}s): ${desc}" - return 1 - fi - sleep 0.5 - done -} - -# ===================== 压测三个阶段 ===================== - -# 阶段 1: 检查服务正常运行 -phase_check_health() { - log_info "[阶段1] 检查服务正常运行" - - if ! check_server_running; then - log_err "server (${SERVER_SERVICE}) 未运行" - server_systemctl status "$SERVER_SERVICE" --no-pager -l | log_err - return 2 - fi - log_ok "server 运行中" - - if ! check_daemon_running; then - log_err "daemon (${DAEMON_SERVICE}) 未运行" - user_systemctl status "$DAEMON_SERVICE" --no-pager -l | log_err - return 2 - fi - log_ok "daemon 运行中" - - if ! check_daemon_monitoring; then - log_err "daemon 未进入 monitoring 状态 (status.json 不含 monitoring)" - [ -f "$STATUS_FILE" ] && { log_err "当前 status.json:"; cat "$STATUS_FILE" >&2; } - return 2 - fi - log_ok "daemon 处于 monitoring 状态" - return 0 -} - -# 阶段 2: 测试服务正常关闭 -phase_stop_services() { - log_info "[阶段2] 测试服务正常关闭" - - # 2.1 先停 server,间隔 1s,再停 daemon - log_info "停止 server (${SERVER_SERVICE}) ..." - server_systemctl stop "$SERVER_SERVICE" || { - log_err "停止 server 失败" - return 3 - } - sleep_intr "$STOP_INTERVAL_S" - - log_info "停止 daemon (${DAEMON_SERVICE}) ..." - user_systemctl stop "$DAEMON_SERVICE" || { - log_warn "停止 daemon 返回非零 (可能已随 server 退出),继续等待" - } - - # 2.2 等待两者均停止,超时报错 - # 由于 server/daemon 间无依赖关系,并行等待 - log_info "等待 server 与 daemon 完全停止 (上限 ${STOP_WAIT_S}s) ..." - - local server_ok=0 daemon_ok=0 - local start now elapsed - start=$(date +%s) - while true; do - [ "$INTERRUPTED" -ne 0 ] && { log_warn "停止等待被中断"; return "$RC_INTERRUPTED"; } - check_server_running || server_ok=1 - check_daemon_running || daemon_ok=1 - if [ "$server_ok" -eq 1 ] && [ "$daemon_ok" -eq 1 ]; then - log_ok "server 与 daemon 均已停止" - return 0 - fi - now=$(date +%s); elapsed=$((now - start)) - if [ "$elapsed" -ge "$STOP_WAIT_S" ]; then - [ "$server_ok" -ne 1 ] && log_err "server 未在 ${STOP_WAIT_S}s 内停止" - [ "$daemon_ok" -ne 1 ] && log_err "daemon 未在 ${STOP_WAIT_S}s 内停止" - return 3 - fi - sleep 0.3 - done -} - -# 阶段 3: 恢复服务运行 -phase_start_services() { - log_info "[阶段3] 恢复服务运行" - - # 3.1 先启 server,间隔 1s,再启 daemon - log_info "启动 server (${SERVER_SERVICE}) ..." - server_systemctl start "$SERVER_SERVICE" || { - log_err "启动 server 失败" - server_systemctl status "$SERVER_SERVICE" --no-pager -l | log_err - return 4 - } - sleep_intr "$START_INTERVAL_S" - - # 在启动 daemon 前记录基线时间戳,用于区分 daemon 重写的新 status.json - # 与停止后残留的旧 status.json (后者 mtime 不会更新) - MONITOR_BASELINE_S=$(date +%s) - log_info "启动 daemon (${DAEMON_SERVICE}) ... (baseline ts=${MONITOR_BASELINE_S})" - user_systemctl start "$DAEMON_SERVICE" || { - log_err "启动 daemon 失败" - user_systemctl status "$DAEMON_SERVICE" --no-pager -l | log_err - return 4 - } - - # 3.2 等待 daemon 进入 monitoring 状态,超时 10min - # 使用新鲜度感知检查: 要求 status.json 的 mtime 晚于启动前的基线, - # 避免 daemon 停止时残留的旧 status.json (仍含 monitoring) 导致误判 - log_info "等待 daemon 进入 monitoring 状态 (上限 $((MONITOR_WAIT_S/60))min) ..." - wait_for_condition "daemon 进入 monitoring" "$MONITOR_WAIT_S" check_daemon_monitoring_fresh - local rc=$? - if [ "$rc" -eq "$RC_INTERRUPTED" ]; then - return "$RC_INTERRUPTED" - elif [ "$rc" -ne 0 ]; then - log_err "daemon 未在 ${MONITOR_WAIT_S}s 内进入 monitoring" - log_err "当前 daemon 状态:" - user_systemctl status "$DAEMON_SERVICE" --no-pager -l 2>&1 | log_err - [ -f "$STATUS_FILE" ] && { log_err "当前 status.json:"; cat "$STATUS_FILE" >&2; } - return 4 - fi - log_ok "daemon 已进入 monitoring 状态" - return 0 -} - -# ===================== 单轮压测 ===================== - -run_one_round() { - local round="$1" - local t0 t1 - printf '\n%s══════════════════════════════════════════════════\n' "${C_CYN}" - printf '%s 第 %s 轮压测开始 %s\n' "${C_CYN}" "$round" "${C_RST}" - printf '%s══════════════════════════════════════════════════%s\n' "${C_CYN}" "${C_RST}" - t0=$(date +%s) - - phase_check_health || return $? - phase_stop_services || return $? - phase_start_services || return $? - - t1=$(date +%s) - log_ok "第 ${round} 轮压测通过 (用时 $((t1 - t0))s)" - return 0 -} - -# ===================== 主流程 ===================== - -main() { - local max_rounds="${1:-0}" # 0 = 无限 - local round=0 - local pass=0 fail=0 - local start_ts end_ts - - start_ts=$(date +%s) - - if [ "$max_rounds" -gt 0 ]; then - log_info "压测计划: 固定 ${max_rounds} 轮" - else - log_info "压测计划: 无限循环,Ctrl+C 停止" - fi - - # 优雅处理 Ctrl+C: 置 INTERRUPTED,各轮询循环据此立即退出 - trap 'INTERRUPTED=1; log_warn "收到中断信号,立即退出当前等待..."' INT TERM - - while true; do - [ "$INTERRUPTED" -ne 0 ] && break - round=$((round + 1)) - - if [ "$max_rounds" -gt 0 ] && [ "$round" -gt "$max_rounds" ]; then - break - fi - - if run_one_round "$round"; then - pass=$((pass + 1)) - else - local rc=$? - # 中断导致的退出不计入失败,直接结束 - if [ "$rc" -eq "$RC_INTERRUPTED" ] || [ "$INTERRUPTED" -ne 0 ]; then - log_warn "第 ${round} 轮因中断信号提前结束,停止压测" - break - fi - fail=$((fail + 1)) - log_err "第 ${round} 轮压测失败 (退出码 ${rc})" - # 失败后尝试恢复到健康状态,避免下轮因环境残留失败 - log_warn "尝试恢复服务到健康状态 ..." - server_systemctl start "$SERVER_SERVICE" 2>/dev/null - sleep_intr "$START_INTERVAL_S" - user_systemctl start "$DAEMON_SERVICE" 2>/dev/null - MONITOR_BASELINE_S=$(date +%s) - wait_for_condition "daemon 进入 monitoring" "$MONITOR_WAIT_S" check_daemon_monitoring_fresh 2>/dev/null \ - && log_ok "已恢复到 monitoring 状态" \ - || log_warn "恢复失败,后续轮次可能受影响" - fi - done - - end_ts=$(date +%s) - printf '\n%s══════════════════════════════════════════════════%s\n' "${C_CYN}" "${C_RST}" - log_info "压测结束: 共 ${round} 轮, 通过 ${pass}, 失败 ${fail}, 总用时 $((end_ts - start_ts))s" - printf '%s══════════════════════════════════════════════════%s\n' "${C_CYN}" "${C_RST}" - - [ "$INTERRUPTED" -ne 0 ] && exit 130 - [ "$fail" -eq 0 ] && exit 0 || exit 5 -} - -main "$@"