畅想更大的一整套博客写作解决方案

2020-06-16

前言

在最近这几天的日子里,我连续写就了两个项目的雏形,分别是作为流量统计和分析系统的explorebeyondthestars/onlineServices,和作为友情链接自助提交管理系统的explorebeyondthestars/links(事实上该系统可很容易地被改变为评论及评论管理系统),而我现有的静态网站生成器(SSG)是Hugo,博客的静态网页服务器是Nginx,静态资源的存储是通过操作系统的文件系统来实现的,动态服务(links和onlineServices)的网页服务器是Caddy,我尝试着想,能否将这些模块互相打通,组合起来,组合成一个更大的系统,已取得工程上的成就,并且为自己带来更好的博客写作体验呢?

使用情景想象

用户在自己的电脑上用VS Code/Sublime Text或者自己喜爱的文本编辑工具撰写文档,用户保存文档时,会触发文件变动监控程序的响应脚本,该脚本进而调用本地的SSG(静态网站生成器)对用户所写文档进行「编译」操作,得到可直接发布至网页服务器的HTML文件集,然后,这些HTML文件被自动地上传至网页服务器,同时,用户所写的文档(一般是Markdown文档)被跟踪进Git仓库被推送至远端Git仓.服务器接收到来自用户本地电脑上传的新文件后,将这些文件存储进「静态服务」(Static Service),而后这个「静态服务」又负责将用户上传的文件存储到「对象存储服务」(Object Storage Service),静态服务和对象存储服务之间的相互通信是通过「对象存储服务访问接口」(OSS Interface)来进行的,而对象存储服务具体又可以是由不同的「对象存储服务驱动」(OSS Driver)来实现,例如说,我们可能会有以文件系统来实现对象存储的FileOSSDriver,还可以有由AmazonS3来实现对象存储的S3OSSDriver等等,而后当网页服务器收到文件请求时,会将请求转发到静态服务而不是操作系统的文件系统,同时立刻返回现有的缓存,待收到后端的静态服务返回的响应后,拿这个响应来更新自身的缓存.

博客的动态服务是通过HTML网页头部的<link>标签来实现的,一个或者多个<link>标签会在浏览器加载网页的时候就向远端服务器发起脚本文件的请求,收到脚本文件后,再执行脚本文件中的内容,而这些脚本文件则会调用动态服务(例如评论和评论管理服务,流量统计服务)所提供的API来和动态服务的后端服务器进行通.这样,即使动态服务陷入故障,亦不会影响博客的静态内容的提供,最多就是流量统计功能暂时不可用,或者是无法进行评论,但是博客的文章还是可以正常阅读的.

里程碑以及行动路线

不难想象,这么大的一个工程,其工作量一定是非常大的,或许需要上万行高质量的代码来实现,正如同在撰写第$n$行代码之前,必须撰写第$n-1$行代码,在到达第$m$个小里程碑之前,也需要先到达第$m-1$个小里程碑,我相信,对整个项目的各个模块的重要性和替换顺序做到心中有数,对任务安排的轻重缓急做到心中有数,对于最终能够成功实现整个项目,无疑是非常有帮助的.

在第$0$步,我们畅想未来,从自我满足中获得成就,仅仅确保自己知道自己将要在不久的将来就开始实现这个项目,同时克服任何畏难的情绪和生物生来就有的惰性和拖.很显然,在撰写这一篇文章之时,第$0$步已经是正在进行,并且是完成得差不多.同时还有确保,接下来的任何步骤的进行都不能够中断已经在工作的系统,例如,不能使beyondstars.xyz停.最理想地情况是整个实现过程是一系列微小改进的叠加.

在第$1$步,我们尝试对现有系统做一些微小的改进,同时确保这些微小的改进的开发、调试和运行出错不能够影响现有的正在运行的系.首先,作为微小的改进,我们希望,当我们在VS Code编辑器中按下了Command+S组合键之后,文件的保存事件能够触发文件变动监视程序的自动响应脚本,该脚本做两件事:1)使新创建的文件被版本管理系统跟踪,同时提交已产生的变动,并自动将新的提交推送到远端的Git服务器上,即是作为备份,又是作为潜在版本回溯需求的基础;2)运行静态网站生成器例如Hugo,如果网站生成成功,那么,就将目标文件目录也就是public目录同步到服务器上,暂时先无需着急前面说过的「静态服务」,现阶段文件仍然是由操作系统的文件系统和网页服务器来向客户端提.做完了这一步,会发现接下来的任务量又少了一些了,这是好事,同时,鉴于在每一个步骤的完成时,整个系统的状态都是一致的(尽管可能在步骤的实现过程中不一致),因此我们可以不用着急立刻进行下一步,甚至可以就此宣告整个系统改进工程的完成,并且满足于已得到的改进带来的便利.

在第$2$步呢,我们主要是打算做一个静态文件服务系统简称静态服务(Static Service),它最基本的功能,就是存取图片,音频和视频,大的附件压缩包,以及非纯文本文档这类的静态文件,你也可以说这是一个网盘,因为我们不想让静态文件被编入博客的Git仓库中被追踪,因为静态文件体积很大,而且不可Git,所以呢,我们希望静态文件能被单独地管理和备.我们希望这个静态服务能够提供一个网页界面,允许我们通过拖拽图片完成图片的上传,单击图片可以复制URL,同时,在每次撰写博客进行保存操作时,本地的文件改变响应脚本还应该将本地的静态文件目录static目录同步至静态服.在最初的阶段,这个静态服务仅仅是简单地将收到的文件存在硬盘中,文件的目录简单地和请求目录对应,而在后面的阶段,我们希望这个静态服务自己实现一个虚拟的文件系统,而不再是把文件简单地存放在硬盘中,并且引入对象存储作为后端和文件的版本管理功能,以此实现静态资源的可靠存.同时,这样做,还能一举解决VPS存储空间不足的问.实现好这个静态服务系统后,我们在Caddy中进行配置,将静态文件请求全部转到这个静态服务系统,而不是直接从硬盘中直接读取文.在这个系统内部,我想初步地认为,文件名到文件的实际内容应该是分离的,文件的实际内容分散地存储在后端的对象存储服务中,而文件名到文件实际内容的映射应该是明文的,例如,在对象存储服务中可以有下列对象:

[
    "56f627b1-82a0-411f-be38-17858f18396c",
    "e481a5c3-2d5d-4c9d-94da-3868e82e1f0f",
    "47f3950f-3d5d-43b7-8c8a-2b59e8fec76e",
    "50181746-9246-4308-8571-5ff4341b7f09",
    "ef14df3d-50ba-40cb-848a-3d70bc497e0f",
    "eb61468f-1dc2-4e85-b25e-3bad0525bf2f"
]

而每一个文件可以分成一个或多个对象来存储,例如

[
    {
        "fileName": "message.txt",
        "blobs": [
            "56f627b1-82a0-411f-be38-17858f18396c",
            "e481a5c3-2d5d-4c9d-94da-3868e82e1f0f"
        ]
    },
    {
        "fileName": "landscape.png",
        "blobs": [
            "47f3950f-3d5d-43b7-8c8a-2b59e8fec76e",
            "50181746-9246-4308-8571-5ff4341b7f09",
            "ef14df3d-50ba-40cb-848a-3d70bc497e0f"
        ]
    },
    {
        "fileName": "design.pdf",
        "blobs": [
            "eb61468f-1dc2-4e85-b25e-3bad0525bf2f"
        ]
    }
]

当对象存储服务中的一个blob在我们的文件映射表中找不到任何一个文件指向它的时候,就可以把这个blob删除,这借鉴的其实是Linux操作系统中inode的思想,通过在版本管理系统中跟踪这个明文的文件映射表文件,我们可以实现一般二进制文件的版本管.我们只有完成第$2$步之后,才能开始制定第$3$步的计划,因为现在我们对该项目的了解仍然非常少,关于该项目的许多知识,不能仅靠空想得到,具体的实践得来的知识才是有效的.

探讨可能blog

近期项目进展

展示一下我自己做的友链自助提交系统!