默默呆,继续做搜索系统啊
打开 frontend/src/components/search/search.js
,找到了一些代码片段:
...
getSearchResult(queryData) {
......
this.source = seafileAPI.getSource();
......
}
......
sendRequest(queryData, cancelToken) {
var _this = this;
let isPublic = this.props.isPublic;
if (isPublic) {
seafileAPI.searchFilesInPublishedRepo(queryData.search_repo, queryData.q).then(res => {
......
} else {
seafileAPI.searchFiles(queryData,cancelToken).then(res => {
......
}
}
......
使用 IDEA 的查找,找到 SeafileAPI 的定义类,发现他是使用了一个 node module,当然是他自己提供的,名字叫 seafile-js。
精确查找一下刚才找到的 getSource
, searchFilesInPublishedRepo
, searchFiles
这几个函数,可以找到:
......
}, {
key: 'getSource',
value: function getSource() {
// for search
var CancelToken = axios.CancelToken;
var source = CancelToken.source();
return source;
}
}, {
key: 'searchFilesInPublishedRepo',
value: function searchFilesInPublishedRepo(repoID, q, page, perPage) {
var url = this.server + '/api/v2.1/published-repo-search/';
......
}
}, {
key: 'searchFiles',
value: function searchFiles(searchParams, cancelToken) {
var url = this.server + '/api2/search/';
......
}
}, {
key: 'searchFileInRepo',
value: function searchFileInRepo(repoID, q) {
var url = this.server + '/api/v2.1/search-file/';
......
}
}
可以看到,在 JS 代码中的这些 API 本质上是直接通过 get 方法,向 django 服务器发送请求,然后再由 django 端完成对后端的调用。
那么,我们到 django 的 router 看看(seahub/urls.py
):
......
# search file by name
url(r'^api/v2.1/search-file/$', SearchFile.as_view(), name='api-v2.1-search-file'),
......
# public repos search
url(r'^api/v2.1/published-repo-search/$', PublishedRepoSearchView.as_view(), name='api-v2.1-published-repo-search'),
还有一个,从 API 地址来看,是 /api2/search/
,因为有如下语句:
### Apps ###
url(r'^api2/', include('seahub.api2.urls')),
所以我们到 seahub/api2/urls.py
里面去找:
......
url(r'^search/$', Search.as_view(), name='api_search'),
......
(这里想吐槽一下,为啥还用了两套 API 的系统?而且还是用不同风格去写的。。。感觉 API v2.1 是匆忙之下要求尽快上线所以牺牲了一些代码美观程度?
总之,我们先打开了位于 /api2/search/
中的 Search view,看到了这样的代码:
class Search(APIView):
""" Search all the repos
"""
authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsAuthenticated,)
throttle_classes = (UserRateThrottle, )
def get(self, request, format=None):
if not HAS_FILE_SEARCH:
error_msg = 'Search not supported.'
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
# argument check
keyword = request.GET.get('q', None)
if not keyword:
error_msg = 'q invalid.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
try:
current_page = int(request.GET.get('page', '1'))
per_page = int(request.GET.get('per_page', '10'))
if per_page > 100:
per_page = 100
except ValueError:
current_page = 1
per_page = 10
......
return Response({"total":total, "results":results, "has_more":has_more})
我们一层一层剥开其中的东西。
首先就是在前面,用 HAS_FILE_SEARCH
判断的,那我们去翻翻:
# search realted
HAS_FILE_SEARCH = False
if EVENTS_CONFIG_FILE:
def check_search_enabled():
enabled = False
if hasattr(seafevents, 'is_search_enabled'):
enabled = seafevents.is_search_enabled(parsed_events_conf)
if enabled:
logging.debug('search: enabled')
else:
logging.debug('search: not enabled')
return enabled
HAS_FILE_SEARCH = check_search_enabled()
这里开始犯难了,采用了一个 seafevents 来去判断 is_search_enabled,这。。。
这里对 seafevents 可以说。。。是一点也不了解,也没有任何相关字段。我尝试在整个项目中全局搜索 seafevents,找到了这样的线索:
seahub/utils/__init__.py
:
if EVENTS_CONFIG_FILE:
parsed_events_conf = configparser.ConfigParser()
parsed_events_conf.read(EVENTS_CONFIG_FILE)
try:
import seafevents
EVENTS_ENABLED = True
SeafEventsSession = seafevents.init_db_session_class(EVENTS_CONFIG_FILE)
except ImportError:
logging.exception('Failed to import seafevents package.')
seafevents = None
EVENTS_ENABLED = False
......
这里可以看到,以 EVENTS_CONFIG_FILE
为判断标准,来导入 seafevents 包。那么,这个 EVENTS_CONFIG_FILE
又是怎么得到的?
在这里,seahub/settings.py
:
d = os.path.dirname
EVENTS_CONFIG_FILE = os.environ.get(
'EVENTS_CONFIG_FILE',
os.path.join(
d(d(d(d(os.path.abspath(__file__))))), 'conf', 'seafevents.conf'
)
)
啊,原来是直接检查文件是否存在吗。。。根据网上的资料:
那目前了解到的情况是:seafevents 是一个 Pro 版本特有的东西,与数据库有关,这东西通过一个配置文件来获得信息。
这样一来,我们没有办法通过 seafevents 来直接判断是否开启搜索了。不过其实。。。还好吧?那么大不了我们添加一个新的接口,通过 seafile API 来直接判断是否支持搜索系统好了。不过这里我们先不动这个代码了,因为后面 pro 的文件里找到了不少咱们需要的东西。
接着看 search 里面的东西。我们知道,主要就是 api2/views.py
中的 Search,api2/endpoints/search_file.py
中的 SearchFile,api2/endpoints/public_repos_search.py
中的 PublishedRepoSearchView,这三个 View。
那么,这些逻辑其实还好啦,主要就是把里面对 SeafileAPI 的调用找出来。
经过查找,找到了这些方法:
这里就发现问题了,seahub_extra。这个是只有 Pro 版本才有的东西,这个就比较麻烦了,连里面有什么都不清楚。不过本着能拿绝不写的原则,我们先去隔壁 pro 版文件里面,看看有没有什么有用的东西。
下载到的 pro 包:
哦吼?颤抖的心,点开看看!
舒服了,基本上一个也没少!好家伙!
当机立断,直接把这堆东西全部复制到咱的项目目录去。首先,把 seahub_extra 文件夹放到 seahub 文件夹的同级位置。
咱们的 PyCharm 编辑器没有识别到,正好介绍一下怎么把其他目录放上去。
打开 PyCharm - Preferences:
选择 project: seahub - project structure:
右边的 Add Content Root,把 seahub_extra 文件夹也加进去就好啦。
加进去以后简单先浏览一下,发现又有一个叫 seafes 的东西缺失了,而且。。。居然又是套了一层壳。。。
seahub_extra/search/utils.py
:
os.environ['EVENTS_CONFIG_FILE'] = EVENTS_CONFIG_FILE
from seafes import es_search
# Get an instance of a logger
logger = logging.getLogger(__name__)
# Decoupled from saehub's variable
SEARCH_FILEEXT = {
TEXT: ('ac', 'am', 'bat', 'c', 'cc', 'cmake', 'cpp', 'cs', 'css', 'diff', 'el', 'h', 'html', 'htm', 'java', 'js', 'json', 'less', 'make', 'org', 'php', 'pl', 'properties', 'py', 'rb', 'scala', 'script', 'sh', 'sql', 'txt', 'text', 'tex', 'vi', 'vim', 'xhtml', 'xml', 'log', 'csv', 'groovy', 'rst', 'patch', 'go'),
IMAGE: ('gif', 'jpeg', 'jpg', 'png', 'ico', 'bmp', 'tif', 'tiff', 'eps'),
DOCUMENT: ('doc', 'docx', 'ppt', 'pptx', 'odt', 'fodt', 'odp', 'fodp'),
SPREADSHEET: ('xls', 'xlsx', 'ods', 'fods'),
SVG: ('svg',),
PDF: ('pdf',),
MARKDOWN: ('markdown', 'md'),
VIDEO: ('mp4', 'ogv', 'webm', 'mov'),
AUDIO: ('mp3', 'oga', 'ogg'),
'3D': ('stl', 'obj'),
}
def get_owned_repos(username, org_id=None):
......
return shared_repos
def get_group_repos(username, org_id=None):
......
return groups_repos
def get_public_repos(username, org_id=None):
......
return public_repos
def get_search_repos_map(search_repo, username, org_id, shared_from, not_shared_from):
......
return repo_id_map, repo_type_map
def search_files(repos_map, search_path, keyword, obj_desc, start, size, org_id=None):
# search file
if len(repos_map) > 1:
search_path = None
files_found, total = es_search(repos_map, search_path, keyword, obj_desc, start, size)
......
return result, total
......
看,在 search_file 里面,又用了 es_search。这应该是 Elastic Search 相关的东西吧?
继续发挥传统艺能:
打开发现,哇,收获很大啊!甚至连文档都在!
这个详细程度,堪比保姆级手把手教学了吧?就差把 Elastic Search 也给我讲一遍了!
不过有一点,它这里用的 Elactic Search 并不是公共的 Elastic Search,而是他们自己的版本。而且,他们提供的这个 Github 地址明显存放的是二进制版内容,而打开以后。。。
这 Git 仓库已经失效了啊。。。不过我在文件夹里发现了它原本让咱们下载的东西:
打开一看,好家伙,这不就是 17 版的 Elastic Search 原版嘛。。。。。。
没想到啊没想到,你这浓眉大眼的 Seafile,也是个拿来党(
基本分析完毕,用手上这堆东西把 Elastic Search 系统恢复出来。
对了,seafevents 也在 pro 里面找到了。
刚刚搞到一半才想起来,如果只是把东西放在同目录底下应该是不行哒,得在 $PYTHONPATH 里面也要出现才行。那么,就需要稍微修改一下咱们的启动脚本了。
原本是:
cd ~/dev/source-code/seahub/
export PYTHONPATH=/usr/local/lib/python3.6/site-packages/:/root/dev/source-code/seahub/thirdpart:$PYTHONPATH
export CCNET_CONF_DIR=/root/dev/conf
export SEAFILE_CONF_DIR=/root/dev/seafile-data
export SEAFILE_CENTRAL_CONF_DIR=/root/dev/conf
现在得多加点东西:
export PYTHONPATH=/root/dev/source-code:/root/dev/source-code/pro/python:$PYTHONPATH
总之先把拿到的各种资源整合一下,说不定直接就能用呢(
在网上找到一份 seafevents.conf 的内容,将其放到 /root/dev/conf 下(英文注释是我补的,不知道为啥我那个 vim 无法输入中文,全乱码):
[AUDIT]
enabled = false
[INDEX FILES]
enabled = true
# Update interval for search index. could be s(seconds), m(minutes), d(days)
interval = 10m
# If "true", search index will also handle pdf file content.
# Notice: If you change this option from "false" to "true", you need to clear the search index and index again. For more info, please refer to FAQ.
index_office_pdf = true
[OFFICE CONVERTER]
# To enable pdf and office preview, you must set this settings to "true".
enabled = false
# Libreoffice worker threads.
workers = 1
# The converted pdf and office file storage location.
outputdir = /tmp/
# Maximum preview pages. Default is 50.
max-pages = 50
# Maximum preview file size, in MB. Default is 2 MB.
max-size = 2
[SEAHUB EMAIL]
# To enable mail notification system, you need to set this to "true"
enabled = false
# Email send interval. Could be s(seconds), m(minutes), d(days)
interval = 30m
OK,我们把环境变量配置好,配置文件也弄好了,现在开始运行。界面一切正常,但是搜索似乎会卡住:
打开网络控制台,发现是报了 404 错误:
这个根据咱们的代码段判断,应该是 seafevents 没有加载成功。后来翻开日志,发现果然:
2021-05-27 07:13:31,294 [ERROR] root:69 Failed to import seafevents package.
Traceback (most recent call last):
File "/root/dev/source-code/seahub/seahub/utils/__init__.py", line 66, in
from seafevents import seafevents_api
File "/root/dev/source-code/pro/python/seafevents/__init__.py", line 43, in
from .virus_scanner import get_virus_files, delete_virus_file, operate_virus_file, \
File "/root/dev/source-code/pro/python/seafevents/virus_scanner/__init__.py", line 2, in
from .virus_scan import VirusScan
File "/root/dev/source-code/pro/python/seafevents/virus_scanner/virus_scan.py", line 6, in
from seafobj import commit_mgr, fs_mgr, block_mgr
ModuleNotFoundError: No module named 'seafobj'
2021-05-27 07:13:31,317 [ERROR] root:562 Failed to import seafevents package.
Traceback (most recent call last):
File "/root/dev/source-code/seahub/seahub/utils/__init__.py", line 558, in
import seafevents
File "/root/dev/source-code/pro/python/seafevents/__init__.py", line 43, in
from .virus_scanner import get_virus_files, delete_virus_file, operate_virus_file, \
File "/root/dev/source-code/pro/python/seafevents/virus_scanner/__init__.py", line 2, in
from .virus_scan import VirusScan
File "/root/dev/source-code/pro/python/seafevents/virus_scanner/virus_scan.py", line 6, in
from seafobj import commit_mgr, fs_mgr, block_mgr
看起来,seafevents 是成功加载了,但是没有完全加载。由于 seafobj 没有找到,这玩意炸掉了。
啊,这好说,我们的项目组正好 fork 了一份 seafboj 的库,我们把它 clone 下来,然后把里面的 seafobj 子文件夹添加在 seahub/thirdpart 文件夹中。
然后就又愉快的报错了。
Traceback (most recent call last):
File "/root/dev/source-code/pro/python/seafevents/db.py", line 112, in init_db_session_class
engine = create_engine_from_conf(config_file, db)
File "/root/dev/source-code/pro/python/seafevents/db.py", line 52, in create_engine_from_conf
backend = config.get(db_sec, 'type')
File "/usr/lib/python3.6/configparser.py", line 781, in get
d = self._unify_values(section, vars)
File "/usr/lib/python3.6/configparser.py", line 1141, in _unify_values
raise NoSectionError(section)
configparser.NoSectionError: No section: 'DATABASE'
数据库嘛。。。看来提供的配置文件里还少了一内内东西,我们再找点资料来。对不起,我是憨憨,明明在 pro 里面就有现成的 conf 文件,我非要去网上找。。。
[DATABASE]
type = mysql
host = db
port = 3306
username = seafile
password = 7e8ed7e1-c4e8-4bc1-97ae-42a83fff9761
name = seahub_db
[AUDIT]
enabled = false
[INDEX FILES]
external_es_server = true
es_host = elasticsearch
es_port = 9200
enabled = true
interval = 10m
highlight = fvh
## If true, indexes the contents of office/pdf files while updating search index
## Note: If you change this option from "false" to "true", then you need to clear the search index and update the index again. See the FAQ for details.
index_office_pdf = true
[OFFICE CONVERTER]
port = 6000
host = 127.0.0.1
enabled = false
workers = 1
[SEAHUB EMAIL]
enabled = false
## interval of sending Seahub email. Can be s(seconds), m(minutes), h(hours), d(days)
interval = 30m
# Enable statistics
[STATISTICS]
enabled=false
注意需要把上面的数据库选项改成咱们自己的。
然后又启动,又报错了。
RuntimeError: ('invalid config file %s', '/root/dev/conf/seafile.conf')
结果一看,奇怪,这个配置文件有点眼熟啊。。。
看,社区版当时做的时候,把这个文件放在了 seafile-data 里面。我们给他纠正一下,也放到 conf 里面。不过 Seafile-Server 要想运行还是需要它在 seafile-data 里面(别问我为什么,这句话是我后面报错以后又回来加的,弄得我很恼火),那么我打算把原件放在 conf 中,然后一个软链接链到 seafile-data 里面。
mv seafile.conf ../conf
ln -s ../conf/seafile.conf ./
改动完了啦,结果又出了问题:
sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (1698, "Access denied for user 'root'@'localhost'")
连不上数据库???但是咱们用相同配置文件都能让 seafile-server 运行起来啊???怎么到了你 python 这里就萎了?
这里考虑到 root 用户有些特殊性,因此在数据库内创建了一个 master 账户,并赋予权限,之后把配置文件也改了。
现在,再试一次,错误终于换了啦。
RuntimeError: seafesdir is not set
看来是 Elastic Search 的文件夹没有被设置好。找到提示的对应代码:
# [ seafesdir ]
seafesdir = get_opt_from_conf_or_env(config, section_name, key_seafesdir, 'SEAFES_DIR', None)
看来既可以在环境变量中设置,也可以在配置文件中设置。那么为了方便起见,我们直接在环境变量中设置。他要的这个 seafes,应该就是 pro/python/seafes,当时咱们看里面内容的时候,还有一些脚本和文档,应该就是那个。使用以下命令添加环境变量:
export SEAFES_DIR=/root/dev/source-code/pro/python/seafes
再运行,终于,看到了久违的运行成功提示。现在我们来到高级搜索界面,然后输入内容查找,看到了 Internal Server Error。打开日志,发现新错误:
urllib3.exceptions.NewConnectionError: : Failed to establish a new connection: [Errno -2] Name or service not known
2021-05-27 09:54:03,560 [WARNING] elasticsearch:97 log_request_fail HEAD http://elasticsearch:9200/repofiles [status:N/A request:0.008s]
看来,是 Elastic Search 的服务器找不到。意料之中,因为。。。。。。我确实没开 Elastic Search(
那也就是说,基本上 Django 这边没啥问题了。那么,下一阶段我们把 Elastic Search 整出来。