唉,好忙,距我说要每周写周记已经过了2周,但我没找出合适的时间写

国庆开始看纪录片《但是还有书籍 第三季》,共6集,目前看了4集,我竟然还没看完,每集都很喜欢,待读书目数量暴增。

第3集 词语摆渡者介绍了几位译者,其中一位是《那不勒斯四部曲》译者陈英,于是我开始读《那不勒斯四部曲》,目前读了29%,用时11.5h,不过半天。我的时间规划真的一塌糊涂,我的作息依然混乱。我的初步规划是上午学习,下午调研,晚上自由时间。

虽然我对《那不勒斯四部曲》早有耳闻,但是过去一直没兴趣读。不是不读,时候未到。

...

读书是很私人的事,我无法将我的阅读体验写下来给别人看。

我又想到了那个问题,我创建这个博客的意义是什么?现实里我鲜少发朋友圈,这个博客的访客大概也只有我告知过的几个朋友。

今天给人写信发现我的博客荒废了2个月,网站没维护,证书已过期,忘记开启评论功能。

这些都已经解决了,顺便安装了一个目录插件PostToc,看了一下插件的代码, 学了一点前端的我能看懂了。我想换个博客主题,但是没找到理想的主题,默认主题用着还行。这个服务器明年11月应该就要到期了,之后怎样我还没想好。

看到一个有趣的博客SkyWt,竟然是校友大佬。写周记这个想法很好,我也要写周记,思考要不要新增一个周记分类,我只记得小学以及初中语文课要写周记,好多年没写周记😄。我现有分类里的随笔和周记挺像的,周记看起来更适合我,因为我大概不会高频更新,也没有要特地拿出来写的。

这2个月没做什么,schema2ddl按照我最初的思路做到现在,都要结束了,发现有结构化数据可以用,需要再做点调整,但在家懒得切换学校的vpn,还没搞。前端学了一点点,cs336还在起步阶段。二刷游戏入侵,成功把游戏入侵推荐给🦉。斥巨资购入俄罗斯方块效应和xbox手柄,提高游戏体验😊

ssl证书自动续期

我清楚的记得我设置了certbot自动续期。在ai的帮助下排查了一会儿,问题如下:ubuntu20的cerbot版本0.40太旧了,与openssl1.1.1f不兼容。

image-20251006233130542

解决方法是删除旧的certbot,用snap安装certbot

# 1. 移除旧版本
sudo apt remove certbot -y

# 2. 安装 snap 版本
sudo snap install --classic certbot

# 3. 建立命令链接(让系统能直接找到)
sudo ln -s /snap/bin/certbot /usr/bin/certbot
#apt 版 Certbot 太旧,兼容性差、依赖落后;
#snap 版是 Certbot 官方唯一推荐且长期维护的版本。
nginx -t # 测试nginx是否恢复正常

过程挺简单的,不过有一个坑是旧版本certbot申请证书的时候改了nginx配置/etc/nginx/sites-enabled/php-default,同时增加了一些配置文件, 直接remove certbot只会删除文件,对nginx配置的修改不会撤回。如下:

  1. 旧 Certbot 安装时:自动修改 Nginx 配置 → 引用 options-ssl-nginx.conf(该文件由 Certbot 生成)
  2. 卸载旧 Certbot 时:仅删除 Certbot 程序和 options-ssl-nginx.conf → 但 Nginx 配置中的引用残留
  3. 新 Certbot 运行时:Nginx 先执行配置检测 → 发现引用的文件不存在 → 报错并阻止 Certbot 继续操作

image-20251006234621486

所以需要把nginx里certbot修改的配置注释掉,然后创建 options-ssl-nginx.conf并写入:

# This file contains important security parameters. If you modify this file
# manually, Certbot will be unable to automatically provide future security
# updates. Instead, Certbot will print and log an error message with a path to
# the up-to-date file that you will need to refer to when manually updating
# this file. Contents are based on https://ssl-config.mozilla.org

ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;

ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";

之后重新申请证书

certbot --nginx -d strangeloop.fun -d blog.strangeloop.fun --non-interactive --agree-tos --email szh-nine@outlook.com --redirect

snap会自动配置续期,但没有reload nginx,所以要增加一个post-hook,续期成功后会自动执行 reload-nginx.sh 钩子脚本

vim /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh
#!/bin/bash
systemctl reload nginx

评论开启

还好当时关闭评论的时候我记录了修改代码的位置

  • post.php 27line
<?php //$this->need('comments.php'); ?>
  • archive.php
<!-- <li itemprop="interactionCount"><a
                            href="<?php $this->permalink() ?>#comments"><?php $this->commentsNum('评论', '1 条评论', '%d 条评论'); ?></a>
                    </li> -->
  • comments.php

​ 注释全部

  • 已有评论更改为待审核

两周多没更新了,这不代表我没有写,只是没写完。这两周每周末我都有计划写周记。但如果当前周已经度过,而我还没写完,我就会觉得没有写完的意义。
上上周离校出发去天津,和🐿️告别,当时想写一下离别,感慨人生常在别离中,当然没写完。但是人生何处不相逢,过了一周,我就又见到🐿️了。然后又经历了离别。
数据库暑期学校好难,代码好难写,debug了一天发现题目理解错了真的令人崩溃,然后宽恕了自己。最后2天🦉和👻到天津找我玩,天津也没有很多好玩的,这个貌似是因为我没有大块时间出去玩。天津的饭也不合我胃口,不如长沙,也不如合肥。安徽的臭鳜鱼好吃,其他的(外卖)也不错,大概是安徽与河南相邻,口味也相近。
思考,天津不好吃也不好玩,可能因为我不是出于游玩的目的去那里,也就没有投入时间去做攻略找好吃的好玩的。
之后在合肥基本上一直都待在酒店里,十分快乐。可恶的就是,sunsetbot预测火烧云鲜艳度0.9,难得出去走走,去北雁湖追日落,最后被鸽了,云层厚到连落日都被遮住了。更可恶的是,第二天朝霞预测鲜艳度0.8,我太困了,没起床,火烧云却如约而至。
在家我打算刷一下leedcode,追赶🐿️的步伐,研究一下毕设(把rag框架搭起来),有空做一下datawhale的happyllm。
前几天收到短信说我的网站备案主体信息需要更新,于是做了一些小改动以度过审查🐿️。

引言

typecho网站后台里可以撰写并发布markdown格式的文章,但是我大部分笔记是在本地typora里写的。直接复制到后台里发布是一种可行的方式,但是markdown里的图片比较难处理,要手动上传为附件,还要替换链接。我检索了typecho上传文章的方式,其中搞定 Obsidian 笔记一键发布到 Typecho 博客的方案是MetaWeblog API(基于 XML-RPC 的标准化接口规范,定义了文章、分类、标签等核心资源的 CRUD(增删改查)方法,使外部工具能以统一方式管理多平台博客)。我没有选择MetaWeblog API,因为在我实现我的思路模拟登录+post并写这篇博客之前还没有详细了解它,稍微了解它之后我认为MetaWeblog API应该比我的方案容易实现。相比之下,我的方案像是钻木取火。

目前我的方案成效差强人意,有空再尝试MetaWeblog API

我的方案主要分为两部分,首先是对文章里图片的处理,一般是托管到图床上,但是找价格合适的图床有点浪费时间,我决定直接将提取文章里的图片路径,然后上传到服务器上,上传文章前替换图片路径,上传图片时,我顺便把markdown原文也上传了,作为备份,同步到github仓库。

第二部分是如何登录并发布,我发现原来在浏览器里登录的链接并不是实际post的目标链接,这一点困住我好久,以及post以后链接的重定向,我在查看服务器nginx日志时才意识到链接重定向,需要在post时允许重定向。

上传图片

测试路径

首先用scp测试一下 ssh免密登录以及读写权限有没有配置好

scp -i D:\.ssh\id_rsa E:\2025\暑期学校报名\assets\image-20250630175256175.png hh@strangeloop.fun:/var/www/typecho/assets/test3.png  # hh用户对该目录没有权限
ssh -i D:\.ssh\id_rsa hh@strangeloop.fun

原本打算直接将图片上传到网站根目录,但是我用来上传图片的用户没有读写该位置的权限。安全起见,我不想直接用root用户上传或者修改目录权限,我选择将图片上传到当前用户(hh)有权限的目录,然后再通过软链接(symbolic link)暴露到网页服务目录中。如下:

mkdir /home/hh/blog && cd blog
mkdir assets
ln -s /home/hh/blog/assets /var/www/typecho/assets  # 软链接
scp -i D:\.ssh\id_rsa E:\2025\暑期学校报名\assets\image-20250630175256175.png hh@strangeloop.fun:/home/hh/blog/assets/test.png
#  blog用来备份博客
# strangeloop.fun/assets/test.png

image-20250706145859046

链接成功,访问网址,能访问图片,配置成功。正常情况下链接应该是绿色与蓝色,如果链接显示为红色,大概率是目标地址不存在,链接失败。

图片提取

这里直接用正则表达式匹配![图片描述](路径),typora里我设置图片存储路径为./assets/xxx.jpg,提取图片路径的正则表达式:

pattern =r'!\[.*?\]\(\.\/(assets/.*?)\)|<img\s+[^>]*src="\.\/(assets[^"]+)"'  
# 匹配 ![图片描述](https://strangeloop.fun/assets/图片路径) 的正则表达式  输出 assets/2023-10-01-1.png 这种格式

AI写的正则表达式总是离需求差一点点,所以我不得不回忆一下正则表达式。🐿️😑

最初我只提取了markdown语法的图片格式,但是后来我发现typora里的图片插入有两种语法:md和html

![alt](src)
<img src="src" alt="alt" style="zoom:xx%; float:left;"/>

html图片语法支持更多的图片操作,如缩放、调整位置。所以在代码里加入了对html语法图片的提取。

  • re.findall(pattern, string, flags=0):在字符串中查找所有与正则表达式匹配的非重叠子串,返回列表
  • re.sub(pattern, repl, string, count=0, flags=0):查找匹配正则表达式的子串,用指定内容替换

上传图片与文件

paramiko库,创建ssh连接

ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(REMOTE_HOST, username=REMOTE_USER, key_filename=os.path.expanduser(SSH_KEY_PATH))
    sftp = ssh.open_sftp()

这一部分比较令人头疼的是文件路径处理,程序在windows上运行,上传图片到linux服务器上,但也就是调不同的库

# 文件路径
file_name = Path(local_md).name
remote_md_path = posixpath.join(REMOTE_BLOG_PATH, file_name)

图片链接替换

这里主要也是正则表达式,替换图片路径之后的md用于后续的上传

    content = re.sub(html_pattern, replace_html, md_content)
    content = re.sub(markdown_pattern, replace_markdown, content)

模拟登录

这里和后面的发布差不多,get登录时浏览器显示的链接,提取实际的登录链接,然后post

发布文章

image-20250705214442228

提取该链接

def extract_post_action_url(html):
    soup = BeautifulSoup(html, "html.parser")
    form = soup.find("form", {"name": "write_post"})
    if not form:
        raise Exception("❌ 未找到登录表单")
    return form.get("action")

测试

python .\publish2typecho.py --md E:\2025\博客\typecho设置.md --tags xx,xx,xx --category 折腾

image-20250707000702247

发布成功

思考

typecho里的markdown不支持文章目录,我尝试了加入tocbot ,效果一般而且难看,我不太了解前端。然后我发现两点:

  • typora能带格式导出html,并且支持目录和侧边栏
  • typora导出里可以设置运行自定义命令

所以显然我可以设置自定义命令为运行typecho自动发布的程序,这样导出的同时可以直接发布,甚至不用我手动执行脚本。实现这一点我需要做的是:读取html,上传图片,更换图片路径,发布(通过MetaWeblog API 实现)。等我有空再做。🐿️🤖

https://www.oceanbase.com/docs/community-developer-quickstart-10000000000627365

https://oceanbase.github.io/miniob/how_to_build/

环境配置

  • CMake:3.10 版本以上。
  • GCC/Clang:GCC 建议 8.3 版本以上,编译器需要支持 C++20 等新标准

gcc 9.4 cmake 3.16

sudo apt install cmake git
gitee 配置ssh
ssh-keygen -t rsa -C "szh-nine@outlook.com" 
# 将~/.ssh/id_rsa.pub 里的公钥添加到gitee里
ssh -T git@gitee.com  # 连接
git remote add origin git@gitee.com:si-zihui/MiniOb.git
git remote set-url origin git@gitee.com:si-zihui/MiniOb.git
git remote -v # 检查远程仓库url设置,若为https,则即便设置了ssh也要输入密码,必须为git
git init
git add .
git commit -m "init"
git branch -m main master # 将main分支重命名为master
git push -u origin master # 提交代码

构建miniob

https://github.com/skyitachi/miniob/blob/main/docs/how_to_build.md

下载代码

git clone 连接断开,直接到github下载,上传到服务器

git clone https://github.com/oceanbase/miniob.git
git clone git@github.com:oceanbase/miniob.git

过了一段时间又连接上了

安装依赖库
bash ./build.sh init

这会安装几个依赖库,在github上,总之绕不过github,换成ssh协议链接正常一点

# git submodule foreach 'git config submodule.$name.url git@github.com:$name'
git submodule sync # 同步gitmodule信息
git submodule deinit -f . # 清理缓存
git submodule update --init --recursive --force  # 自动下载子模块,还需要编译

image-20250630180000665

image-20250630175256175

编译
bash ./build.sh

image-20250630175704703

GCC 9.4 支持 C++20 的部分特性(如概念、协程的实验性支持),但 <span> 头文件(标准库中的 std::span)在 GCC 9.4 中尚未完全实现

编译gcc11
sudo apt install gcc-11 g++-11  #升级

软件源里没有高版本的gcc,所以下载源码编译

gnu 镜像站列表 https://www.gnu.org/prep/ftp.html

选择中科大镜像 https://mirrors.ustc.edu.cn/gnu/gcc/gcc-11.3.0/gcc-11.3.0.tar.gz

安装在默认路径/usr/local

wget https://mirrors.ustc.edu.cn/gnu/gcc/gcc-11.3.0/gcc-11.3.0.tar.gz
tar xzvf gcc-11.3.0.tar.gz
cd gcc-11.3.0

# 下载依赖
./contrib/download_prerequisites

# 配置。可以通过prefix参数设置编译完成的GCC的安装目录,如果不指定,会安装在/usr/local下
# 可以配置为当前用户的某个目录
./configure --prefix=/your/new/gcc/path --enable-threads=posix --disable-checking \
    --disable-multilib --enable--long-long --with-system-zlib --enable-languages=c,c++

# 开始编译
make -j

# 安装
# 编译产生物会安装到 configure --prefix指定的目录中,或系统默认目录下
make install

# 修改环境变量
# 可以将下面的配置写到 .bashrc 或 .bash_profile 中,这样每次登录都会自动生效
export PATH=/your/new/gcc/path/bin:$PATH
export LD_LIBRARY_PATH=/your/new/gcc/path/lib64:$LD_LIBRARY_PATH
export CC=/your/new/gcc/path/bin/gcc
export CXX=/your/new/gcc/path/bin/g++

# NOTE: 上面的环境变量CC和CXX是告诉CMake能够找到我们的编译器。cmake优先查找的
#       编译器是cc而不是gcc,而一般系统中会默认带cc,所以使用环境变量告诉cmake。
#       也可以使用 cmake 参数 
#       `-DCMAKE_C_COMPILER=/your/new/gcc/path/bin/gcc -DCMAKE_CXX_COMPILER=/your/new/gcc/path/bin/g++`
#       来指定编译器

服务器内存占用过多,崩了

  • 清理残留编译文件

    make clean    # 删除大多数生成的文件
    make distclean # 彻底清理(若配置错误需重新配置时使用)
    # 无效

    直接删除build文件

    rm -rf build-x86_64-pc-linux-gnu/
  • 重新编译

    make -j # 自动使用当前 CPU 核心数(线程数)个并发任务来编译,服务器内存小多线程容易崩,建议使用较小的线程数
    make -j1 

    image-20250701042041073

    单线程执行了五六个小时,然后安装

    sudo make install 

    添加环境变量 至~/.bashrc或者/etc/profile

    维度~/.bashrc/etc/profile
    范围用户级系统级
    时机每次非登录 Shell 启动用户登录时
    用途个性化终端配置全局环境与系统配置
    # /usr/local/
    export PATH=/usr/local/bin:$PATH
    export LD_LIBRARY_PATH=/usr/local/lib64:$LD_LIBRARY_PATH
    export CC=/usr/local/bin/gcc
    export CXX=/usr/local/bin/g++
重新编译miniob

gcc升级后,之前安装的依赖库可能不兼容,所以重新下载

./build.sh

出现同样的错误,查看日志,发现使用的仍为旧版本

bash ./build.sh 
THIRD_PARTY_INSTALL_PREFIX is /home/hh/miniob/deps/3rd/usr/local
./build.sh 
Build type: debug
create soft link for build_debug, linked by directory named build
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 --log-level=STATUS /home/hh/miniob -DCMAKE_BUILD_TYPE=debug
-- The C compiler identification is GNU 9.4.0
-- The CXX compiler identification is GNU 9.4.0

修改build.sh,指定编译时的gcc和g++

CMAKE_COMMAND='cmake \
  -DCMAKE_EXPORT_COMPILE_COMMANDS=1 \
  -DCMAKE_C_COMPILER=/usr/local/bin/gcc \
  -DCMAKE_CXX_COMPILER=/usr/local/bin/g++ \
  -DCMAKE_CXX_STANDARD=20 \
  -DCMAKE_EXE_LINKER_FLAGS=-Wl,-rpath=/usr/local/lib64 \
  --log-level=STATUS'

再次编译

image-20250701155649901

系统缺少 flexbison 工具,它们是用于生成词法分析器(.l 文件)和语法分析器(.y 文件)代码的工具

sudo apt install flex bison

再次编译,编译成功!

image-20250701162133123

运行

以直接执行命令的方式启动服务端程序

sudo ./bin/observer -f ../etc/observer.ini -P cli

若启动失败,如下图

image-20250703154638028

创建目录需要sudo权限

image-20250701180313721

开发环境搭建

安装插件

cmake c++

[submodule "deps/3rd/libevent"]
    path = deps/3rd/libevent
    url = git@github.com:libevent/libevent.git
[submodule "deps/3rd/jsoncpp"]
    path = deps/3rd/jsoncpp
    url = git@github.com:open-source-parsers/jsoncpp.git
[submodule "deps/3rd/googletest"]
    path = deps/3rd/googletest
    url = git@github.com:google/googletest.git
[submodule "deps/3rd/benchmark"]
    path = deps/3rd/benchmark
    url = git@github.com:google/benchmark.git
[submodule "deps/3rd/replxx"]
    path = deps/3rd/replxx
    url = git@github.com:AmokHuginnsson/replxx.git

手动编译gdb

gcc11.3 适配的gdb版本为11.1 10.2

https://mirrors.ustc.edu.cn/gnu/gdb/gdb-11.1.tar.gz

wget https://mirrors.ustc.edu.cn/gnu/gdb/gdb-11.1.tar.gz
tar xavf gdb-11.1.tar.gz
cd gdb-11.1
sudo apt install expect dejagnu gawk texinfo
# 忘记创建build目录了
mkdir build
cd build

../configure
make -j1
sudo make install