明匣之境 - 技术
type: channel
link: https://www.0s.ink/category/Technical/
items: ChaCha20-Poly1305 加密算法详解
items: 自定义Linker与SO加固
items: omod模型制作与导入方法
items: JavaScript快速入门
items: 常用CSS样式
items: Vue3实现瀑布流布局
items: ClawCloud Run搭建图床
items: Restful-API设计风格
items: Navicat 17 破解教程
items: jetbrains 全家桶-免费试用
items: paopao-ce 部署教程

ChaCha20-Poly1305 加密算法详解
type: item
date: 2025-12-13T19:08:00+08:00
description: 前言ChaCha20-Poly1305是一种结合了流加密算法（ChaCha20）和消息认证码（Poly1305）的认证加密方案，由Daniel J. Bernstein教授设计。它提供了数据的机密性、完整性和身份验证，属于AEAD（Authenticated Encryption with Associated Data）加密模式。1 算法概述与发展历史1.1 发展背景与历史提出时间：ChaCha20-Poly1305于2014年正式提出。设计动机：Google为替代RC4和AES在某些平台上的性能问题而推动采用。在Android移动平台的Chrome浏览器中首次替代RC4使用。性能优势：在ARM等精简指令集架构的移动设备上（无AES硬件加速时），性能可达AES的4倍；但在支持AES-NI的x86平台上，AES性能更优。标准化进程：2013年Google在Chrome 31中启用，2014年扩展到iOS和Android平台。IETF于2016年6月完成标准化（RFC 7905），OpenSSL从1.1.0版本（2016年8月）开始支持1.2 应用场景该算法已被广泛用于多种安全协议和系统中：TLS 1.3：作为推荐加密套件之一（TLS_CHACHA20_POLY1305_SHA256）OpenSSH：自2013年起作为默认加密算法之一QUIC协议：Google开发的下一代网络传输协议WireGuard VPN协议：核心加密组件移动设备与物联网：因高效率和抗侧信道攻击而受青睐2 算法原理与技术细节2.1 ChaCha20流密码ChaCha20是一种流密码，通过生成伪随机密钥流与明文异或实现加密。2.1.1 初始矩阵结构ChaCha20的核心是一个4×4的32位字矩阵（共512位），初始结构如下：位置内容值/说明[0]常量0x61707865 ("expa")[1]常量0x3320646e ("nd 3")[2]常量0x79622d32 ("2-by")[3]常量0x6b206574 ("te k")[4]-[7]密钥256位密钥(8个32位字)[8]-[11]计数器32位块计数器(从0开始)[12]-[15]随机数96位Nonce(每次加密唯一)完整初始矩阵布局：0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 Key[0], Key[1], Key[2], Key[3] Key[4], Key[5], Key[6], Key[7] Counter[0], Counter[1], nonce[0], nonce[1]2.1.2 轮函数运算ChaCha20进行20轮加密计算（10次双轮操作），每轮包含列轮和对角轮。# Quarter Round函数定义（核心操作） def quarter_round(a, b, c, d): a = (a + b) & 0xFFFFFFFF d ^= a d = (d << 16) | (d >> 16) # 循环左移16位 c = (c + d) & 0xFFFFFFFF b ^= c b = (b << 12) | (b >> 20) # 循环左移12位 a = (a + b) & 0xFFFFFFFF d ^= a d = (d << 8) | (d >> 24) # 循环左移8位 c = (c + d) & 0xFFFFFFFF b ^= c b = (b << 7) | (b >> 25) # 循环左移7位 return a, b, c, d轮函数执行流程：列轮运算：对矩阵的每一列应用Quarter Round对角轮运算：对对角线元素应用Quarter Round重复10次：共进行10次双轮操作（20轮）矩阵相加：将结果与初始矩阵相加，生成最终密钥流2.1.3 加密与解密过程加密和解密都是通过将生成的密钥流与数据（明文或密文）进行异或操作实现的：加密：密文 = 明文 ⊕ 密钥流解密：明文 = 密文 ⊕ 密钥流由于计数器是32位，ChaCha20最多可生成2^32个密钥流块，每个块512位，总计约256GB数据。2.2 Poly1305消息认证码Poly1305负责生成认证标签，确保数据完整性。2.2.1 算法流程密钥处理：将32字节密钥分为两部分（r和s），并进行特定处理。消息分块：将消息划分为16字节块，不足的进行填充。累加计算：使用Horner法则在有限域上进行多项式求值。生成标签：结果与s相加，取模2^128，生成16字节认证标签。2.2.2 数学公式认证标签的计算公式为：2.3 ChaCha20-Poly1305组合模式在实际应用中，两者结合使用的工作流程如下：使用ChaCha20和相同的密钥生成密钥流将密钥流与明文异或产生密文使用Pol…

自定义Linker与SO加固
type: item
date: 2025-12-09T19:52:00+08:00
description: 0x01 前言在研究360加固方案时，我发现其采用了一种独特的保护机制：在主SO文件内部嵌套了另一个SO文件，相当于为主SO添加了一层保护壳。这种技术实现引起了我的兴趣，经过深入研究，整理出本文，分享自定义Linker的实现原理及SO加固技术0x02 Linker源码分析PS：这部分有点长，如果你只想看怎么实现的，可以直接跳到总结核心代码解析（只贴关键部分，不然太长了）do_dlopen - 一切的起点soinfo* si = find_library(name); // 查找并加载SO到内存 if (si != NULL) { si->CallConstructors(); // 调用SO的初始化函数 }看起来很简单对吧，让我们深入看看这两个函数都干了啥find_library - 负责找SO的函数static soinfo* find_library(const char* name) { soinfo* si = find_library_internal(name); // 寻找相应的SO信息 if (si != NULL) { si->ref_count++; // 这个计数很重要，用来判断SO是否已经加载过 } return si; }CallConstructors - 调用构造函数// 直接看重点 if (dynamic != NULL) { for (Elf32_Dyn* d = dynamic; d->d_tag != DT_NULL; ++d) { if (d->d_tag == DT_NEEDED) { // 先调用依赖库的构造函数 const char* library_name = strtab + d->d_un.d_val; TRACE("\"%s\": calling constructors in DT_NEEDED \"%s\"", name, library_name); find_loaded_library(library_name)->CallConstructors(); } } } // DT_INIT要在DT_INIT_ARRAY之前调用 TRACE("\"%s\": calling constructors", name); CallFunction("DT_INIT", init_func); // SO文件加壳的脱壳点！划重点！ CallArray("DT_INIT_ARRAY", init_array, init_array_count, false);这里有个有趣的地方：DT_INIT和DT_INIT_ARRAY是很多加固方案的脱壳点，因为这是SO被加载后最早执行的地方之一find_library_internal - 真正干活的函数static soinfo* find_library_internal(const char* name) { if (name == NULL) { return somain; } soinfo* si = find_loaded_library(name); if (si != NULL) { if (si->flags & FLAG_LINKED) { return si; // 已经加载过了，直接返回 } DL_ERR("OOPS: recursive link to \"%s\"", si->name); return NULL; } TRACE("[ '%s' has not been loaded yet. Locating...]", name); si = load_library(name); // 真正加载SO文件的地方 if (si == NULL) { return NULL; } TRACE("[ init_library base=0x%08x sz=0x%08x name='%s' ]", si->base, si->size, si->name); if (!soinfo_link_image(si)) { // 执行重定位（会用mmap，所以在/proc/pid/maps能看到） munmap(reinterpret_cast<void*>(si->base), si->size); soinfo_free(si); return NULL; } return si; }关于重定位：想象一下，你的SO文件里调用了printf函数，但编译的时候并不知道printf在内存的哪个位置，所以先用个占位符（比如call 0x1234）。重定位就是把这个占位符改成真实的地址基本流程梳理：find_loaded_library()：先看看是不是已经加载过了load_library()：没加载过，那就加载soin…

omod模型制作与导入方法
type: item
date: 2025-05-24T16:57:00+08:00
description: 以下用3D MAX 2014版本作为示例带有动画的模型需要以omod文件格式导入到迷你世界中。1.解压“2014max插件”，将插件里的文件复制到3DMax2014安装目录中。2.在Max中运行脚本MiniAnimationExporter.ms（文件存在于3DMax2014安装目录下Scripts\OgreMaxScripts）3.将插件添加到工具栏。打开“自定义用户界面”，选择“工具栏”，在类别中找到Mini Animation Tools，在下面会显示Mini Animation Manager，用鼠标选择并把它拖拽至工具栏任意位置即可，点击即可打开插件工具。4.注意：如果步骤3中找不到Mini Animation Tools，可以将“mini_tools_enc.ms”文件直接拖入Max中，该脚本运行后会弹出“Mini工具”的窗口，在窗口中选择MiniAnimationManager即可。5.成功打开插件后，你已离成功不远了。你可以开始在3DMax里面制作模型、动画和贴图了。6.注意：模型对象的名称要与贴图名称一致，且要命名为body0。7.如果你的模型中有子模型，那则需要依次命名为body0、body1。注意：名称中的数字一定要按顺序，不可以跳过，比如body0、body5是错误的。8.在模型旁边添加一个命名为“aabb”的模型，并将“aabb”尽量完全包裹模型，随后将其隐藏即可。9.导出omod文件。首先你需要在桌面创建两个文件夹(数字或英文命名)，这里以创建A文件夹和B文件夹为例。A文件夹用于存放Max源文件和贴图源文件，B文件夹用于存放导出的omod文件和贴图文件。10.打开MiniAnimationManager工具。（1)选择要导出的对象。如果有多个骨骼组合，则需要选择骨骼的父节点。（2)设置Start frame和end frame，控制动画的帧数。注意结束帧要大于开始帧。（3)填写动作的ID，这里填写的ID对应迷你世界动作ID。（4)如果有多个动作需要添加，点击Append New Sequence按钮添加新设置新动作的帧数，重复（2)、（3)步。11.完成MiniAnimationManager的设置后，退出插件工具，点击MAX菜单->导出omod文件。注意：omod导出的位置是步骤8中创建的B文件夹，文件的命名一定是body（不是body0）。12.导出配置。（1)选择动画模型（2)动画帧的开始到结束设置必须覆盖整个动作时间段（3)源文件根目录和目标文件根目录分别选择，步骤8中创建的A和B文件夹。（4)点击OK完成导出13.打包。打开B文件夹，将动画集omod和贴图文件进行打包，压缩包的名字可以随意。打包后注意删除本地对应的文件，避免导出下一次导出模型时，因为重命名而导出失败。

JavaScript快速入门
type: item
date: 2025-04-18T21:46:00+08:00
description: 1.什么是javaScriptjavaScript是一门世界上最流行的脚本语言!JavaScript（简称“JS”）是一种具有函数优先的轻量级，解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名，但是它也被用到了很多非浏览器环境中，JavaScript基于原型编程、多范式的动态脚本语言，并且支持面向对象、命令式、声明式、函数式编程范式。javaScript的历史故事:值得一提的是:javaScript脚本语言是Brendan Eich只花了10天时间制作而成的! web history-----JavaScript 的起源故事_weixin_30883271的博客-CSDN博客ECMAScript可以理解为javaScript的一种标准! javaScript的最新版本已经到9了2.javaScript的引入方式html内部标签

常用CSS样式
type: item
date: 2025-04-15T11:28:00+08:00
description: 前言对于大佬们来说，CSS一点都不难，轻轻松松的就记了下来；但对于新手小白来说，CSS太多了，真的是太难了。于是就整理了一些CSS样式方便使用😇。CSS字体属性：(font)大小 {font-size: x-large;}(特大) xx-small;(极小) 一般中文用不到，只要用数值就可以，单位：PX、PD样式 {font-style: oblique;}(偏斜体) italic;(斜体) normal;(正常)行高 {line-height: normal;}(正常) 单位：PX、PD、EM粗细 {font-weight: bold;}(粗体) lighter;(细体) normal;(正常)变体 {font-variant: small-caps;}(小型大写字母) normal;(正常)大小写 {text-transform: capitalize;}(首字母大写) uppercase;(大写) lowercase;(小写) none;(无)修饰 {text-decoration: underline;}(下划线) overline;(上划线) line-through;(删除线) blink;(闪烁)常用字体： (font-family)“Courier New”, Courier, monospace, “Times New Roman”, Times, serif, Arial, Helvetica, sans-serif, Verdana背景属性： (background)色彩 {background-color: #FFFFFF;}图片 {background-image: url();}重复 {background-repeat: no-repeat;}滚动 {background-attachment: fixed;}(固定) scroll;(滚动)位置 {background-position: left;}(水平) top(垂直);简写方法 {background:#000 url(..) repeat fixed left top;} /简写·这个在阅读代码中经常出现，要认真的研究/区块属性： (Block)字间距 {letter-spacing: normal;} 数值 /这个属性似乎有用，多实践下/对齐 {text-align: justify;}(两端对齐) left;(左对齐) right;(右对齐) center;(居中)缩进 {text-indent: 数值px;}垂直对齐 {vertical-align: baseline;}(基线) sub;(下标) super;(下标) top; text-top; middle; bottom; text-bottom;词间距word-spacing: normal; 数值空格white-space: pre;(保留) nowrap;(不换行)显示 {display:block;}(块) inline;(内嵌) list-item;(列表项) run-in;(追加部分) compact;(紧凑) marker;(标记) table; inline-table; table-raw-group; table-header-group; table-footer-group; table-raw; table-column-group; table-column; table-cell; table-caption;(表格标题) /display 属性的了解很模糊/方框属性： (Box)width:; height:; float:; clear:both; margin:; padding:; 顺序：上右下左边框属性： (Border)border-style: dotted;(点线) dashed;(虚线) solid; double;(双线) groove;(槽线) ridge;(脊状) inset;(凹陷) outset;border-width:; 边框宽度border-color:#;简写方法border：width style color; /简写/列表属性： (List-style)类型list-style-type: disc;(圆点) circle;(圆圈) square;(方块) decimal;(数字) lower-roman;(小罗码数字) upper-roman; lower-alpha; upper-alpha;位置list-style-position: outside;(外) inside;图像list-style-image: url(..);定位属性： (Position)Position: absolute; …

Vue3实现瀑布流布局
type: item
date: 2025-04-15T09:58:00+08:00
description: 思路❶首先定义一个瀑布流容器，它的高度暂定（后面会更新）。把需要布局的组件（这里叫做waterfall-item）放在瀑布流容器里面渲染出来。使用绝对定位（position: absolute），把它移到屏幕外面，不要占用页面高度，并且设置不可见（visibility:hidden）。 <PostCard :title="post.title" :content="post.excerpt" :time="new Date(post.date).toLocaleDateString()" :tag="post.tags ? post.tags.join(', ') : '未分类'" :img="post.img" :path="`/post/${post.file}`" :id="post.title" @imageLoaded="onImageLoaded" /> .waterfall-item { position: absolute; left: 0; top: 0; transform: translate3d(0, 3000px, 0); visibility: hidden; /* 让容器不被空白占位的 trick */ }❷渲染出来之后才能计算高度。获取.waterfall-item的dom元素，遍历这些元素，使用getBoundingClientRect()获取高度。❸开始布局。以2列为例，新建两个变量分别表示2列的高度。遍历第2步获取的dom元素的高度，把dom元素的高度加到最小的高度上。这个过程还可以考虑在组件之间加上留白（gutter）。❹使用transform样式将waterfall-item移动到对应高度所在的位置。transform将组件移动到指定坐标，横坐标跟列有关，纵坐标跟高度有关。❺更新瀑布流容器的高度为两列高度中最大者。// 瀑布流容器引用 const waterfallWrapper = ref<HTMLElement | null>(null); // 瀑布流容器高度 const wrapperHeight = ref(0); // 一些瀑布流配置属性 const gutter = 20; // 卡片之间的间距，单位px const cols = ref(2); // 列数（可根据响应式需求调整） const colWidth = ref(0); // 每列宽度，或你可以动态计算 const hasAroundGutter = ref(true); const animationCancel = ref(false); // 是否取消动画 const posDuration = ref(300); // 位置动画时长 (ms) /** 2、3、4、5步的布局函数 */ const layoutHandle = async (): Promise<boolean> => { return new Promise((resolve) => { // 初始化 posY initY(); // 获取 .waterfall-item DOM 列表 const items: HTMLElement[] = []; if (waterfallWrapper.value) { waterfallWrapper.value.childNodes.forEach((el: any) => { if (el.className === 'waterfall-item') items.push(el); }); } if (!items.length) return false; // 遍历每个卡片 for (let i = 0; i < items.length; i++) { const curItem = items[i] as HTMLElement; const style = curItem.style; // 最小列 const minY = Math.min(...posY.value); const minYIndex = posY.value.indexOf(minY); // 计算 X const curX = getX(minYIndex); // 设置 transform style.transform = `translate3d(${Math.floor(curX)}px, ${Math.floor(minY)}px, 0)`; style.width = `${colWidth.value}px`; style.visibility = 'visible'; // 测量高度 const { height } = curItem.getBoundingClientRect(); /…

ClawCloud Run搭建图床
type: item
date: 2025-04-13T19:46:00+08:00
description: 简介 ClawCloud Run 是一个集成在线开发、测试和生产环境的云开发平台。只需单击几下，即可设置开发环境和数据库依赖项，从而显著降低复杂性。Free Plan 免费计划 对于每一个新注册的用户，ClawCloud Run 将提供 5 美元的优惠。此赠品的有效期为一个月。如果您在注册后一个月内绑定 GitHub 账户，则此后每个月都会额外获得 5 美元，而这份后续礼物的有效期也是一个月。如果你的 GitHub 账户超过 180 天，建议直接使用 GitHub 注册，免去绑定的步骤。免费的有Up to 4 vCPU / 8GiB RAM / 10GiB disk per region/10G traffic，个人使用基本差不多够了。注册地址：https://console.run.claw.cloud/signin?link=PVG759MZBNEN也就是说，可以实现永久免费，我这里搭建一个图床试试。另外我搜索了一下，WordPress网站可以直接创建，Typecho也可以去试试。创建容器点击App Launchpad，然后Creat APP，打开如下界面。容器设置我这里设置的是easyimage的图床，在Image Name这里输入ddsderek/easyimage:latest即可，接着设置自己需要的CPU和内存。自定义域名最后，还可以设置自己的域名，选择https的方式，自定义域名在创建容器的时候就先设置好。提交部署即可，一会儿图床就搭建好了，用你的自定义域名访问，安装图床即可。重要说明:使用自定义域名，一定要创建容器的时候就用自定义域名，不然他给的随机域名再修改是会变。注册地址https://console.run.claw.cloud/signin?link=PVG759MZBNEN搭建演示我用这个搭建了一个图床 大家可以免费使用图床连接:http://iii.0s.ink

Restful-API设计风格
type: item
date: 2025-03-22T20:44:00+08:00
description: API请求HTTP动词GET: 读取（READ） POST: 新建（CREATE） PUT: 更新（UPDATE） DELETE: 删除（DELETE）[card title="" color="primary"]PATCH 部分更新[/card]URL宾语宾语 顾名思义，是一个名词， URL 作为 API 的宾语是作用 HTTP 的对象，普遍以复数形式存在. 以下为错误示例：/getAllCars /createNewCar /deleteAllRedCars正确示例：/aticles /users /cars煮个栗子GET /zoos：列出所有动物园 POST /zoos：新建一个动物园 GET /zoos/ID：获取某个指定动物园的信息 PUT /zoos/ID：更新某个指定动物园的信息（提供该动物园的全部信息） PATCH /zoos/ID：更新某个指定动物园的信息（提供该动物园的部分信息） DELETE /zoos/ID：删除某个动物园 GET /zoos/ID/animals：列出某个指定动物园的所有动物 DELETE /zoos/ID/animals/ID：删除某个指定动物园的指定动物过滤（filter）通常在数据库中存储着许多数据，我们不可能将所有数据返回给用户，而是选择性的将一些数据返回给用户，而 API 就应该提供一些参数，过滤返回的结果。下面是一些常见的参数。?limit=10：指定返回记录的数量 ?offset=10：指定返回记录的开始位置。 ?page=2&per_page=100：指定第几页，以及每页的记录数。 ?sortby=name&order=asc：指定返回结果按照哪个属性排序，以及排序顺序。 ?animal_type_id=1：指定筛选条件参数的设计允许存在冗余，即允许API路径和URL参数偶尔有重复。比如， GET /zoo/ID/animals 与 GET /animals?zoo_id=ID 的含义是相同的。不符合 CRUD 情况的 RESTful API在实际资源操作中，总会有一些不符合 CRUD 的情况，一般有几种处理方法。1、使用 POST，为需要的动作增加一个 endpoint，使用 POST 来执行动作，比如: POST /resend 重新发送邮件。2、增加控制参数，添加动作相关的参数，通过修改参数来控制动作。比如一个博客网站，会有把写好的文章“发布”的功能，可以用上面的 POST /articles/{:id}/publish 方法，也可以在文章中增加 published:boolean 字段，发布的时候就是更新该字段 PUT /articles/{:id}?published=true3、把动作转换成资源，把动作转换成可以执行 CRUD 操作的资源， github 就是用了这种方法。比如“喜欢”一个 gist，就增加一个 /gists/:id/star 子资源，然后对其进行操作：“喜欢”使用 PUT /gists/:id/star ，“取消喜欢”使用 DELETE /gists/:id/star 。另外一个例子是 Fork，这也是一个动作，但是在 gist 下面增加 forks资源，就能把动作变成 CRUD 兼容的： POST /gists/:id/fork s 可以执行用户 fork 的动作。动词覆盖，应对服务器不完全支持 HTTP 的情况有些客户端只能使用GET和POST这两种方法。服务器必须接受POST模拟其他三个方法（PUT、PATCH、DELETE）。这时，客户端发出的 HTTP 请求，要加上X-HTTP-Method-Override属性，告诉服务器应该使用哪一个动词，覆盖POST方法。API响应状态码2xx 状态码200 状态码也称成功状态码，但是对于不同的方法又有不同的状态码GET --> 200 OKPOST–> 201 Created（表示生成新的资源）PUT --> 200 OKPATCH --> 200 OKDELETE --> 204 No Content（表示该资源已不存在）3xx 状态码在 Restful API 中用不上，永久重定向（ 301 ）、暂时重定向（ 302 、 307 ）可由应用级别返回，浏览器直接跳转。主要使用 303 see other，以表示参考另一个URL，它与 302 和 307 的含义一样，也是”暂时重定向”，区别在于 302 和 307 用于GET请求，而 303 用于POST、PUT和DELETE请求。收到 303 以后，浏览器不会自动跳转，而会让用户自己决定下一步怎么办。4xx 状态码4xx 状态码表示客户端错误，主要有下面几种：400 --> Bad Request：服务器不理解客户端的请求，未做任何处理…

Navicat 17 破解教程
type: item
date: 2025-03-20T14:14:00+08:00
description: 下载Navicat1.官网下载: 官网下载 2.百度云下载: 百度云下载 3.未安装过的用户可直接跳过该步骤，如果已安装Navicat，记得先卸载干净，防止破解失效，卸载完成后执行补丁压缩包中的 Navicat.bat 脚本（一闪而过表示正常，已成功删除Navicat的注册信息和相关的注册表数据）4.安装Navicat17(安装完成不要打开！！！) 4.1点击运行navicat170_premium_cs_x64.exe 4.2开始安装 4.3选择安装路径，最好不要放在系统盘C盘，后面两个步骤默认 4.4安装中，耐心等待1-2分钟 4.5安装完成，点击【完成】，先不要启动软件 4.6返回我们下载好的破解补丁文件夹内，文件夹下的 winmm.dll 文件覆盖到Navicat Premium的安装位置即可激活 下载破解补丁： 破解补丁

jetbrains 全家桶-免费试用
type: item
date: 2025-03-19T23:41:00+08:00
description: 打开网站点我前往打开网址寻找到一个 cors 标记为*号的网站并打开它下载工具包点击 jetbra.zip 即可下载工具包解压工具包把下载下来的jetbra.zip解压解压到一个稳定的位置注意：在执行完毕后本目录下的文件不能移动和删除执行脚本执行前请关闭 IDEA 软件在“许可证”窗口中注销 jb 帐户执行脚本执行成功后会出现相关提示文字注意确认是否有错误提示macOS 或 Linux执行“scripts/install.sh”Windows双击执行“scripts\install-current-user”。vbs”(针对当前用户)双击执行“scripts\install-all-users。vbs”(所有用户)复制许可证我这里用的是 IDEA 就复制 IDEA 的许可证信息打开IDEA使用激活码激活填入复制的许可证注意如果提示许可证无效，可能是执行脚本步骤存在问题,需要重试执行脚本步骤完成不用在意这个过期时间，他只是一个标志 过期后软件还可以正常使用

paopao-ce 部署教程
type: item
date: 2025-01-05T00:12:00+08:00
description: 前言本人文笔不太行，希望各位能看懂。不会的可以在下面评论留言。环境服务器环境Nginx v1.24.0Mysql v5.7.44Redis v7.4.1Meilisearch v1.12.1本地环境Node v22.12.0Git v2.43.0Go v1.23.4安装环境安装Node点击 这里 安装最新版Node即可 目前最新v22.12.0安装Go点击 这里 安装最新版Go即可 目前最新v1.23.4安装Git点击 这里 安装最新版Git即可 目前最新 v2.47.1获取源代码首先你可以在桌面或者任意位置新建一个文件夹或者直接在桌面打开cmd执行git clone https://github.com/rocboss/paopao-ce.git执行完之后你会发现桌面多了一个paopao-ce文件夹 我们cd进去cd paopao-ce然后进入这个页面你可以看到以下目录核心源码目录 internal/ - 项目内部代码,包含核心业务逻辑实现 pkg/ - 可复用的工具包代码 cmd/ - 命令行入口代码 auto/ - 自动生成的代码 mirc/ - RESTful API 接口定义 proto/ - gRPC 接口定义 Web前端相关 web/ - Web前端代码 部署和构建相关 docker/ - Docker相关配置和脚本 scripts/ - 各类脚本文件 build-image.sh - 构建Docker镜像脚本 build-allinone.sh - 构建all-in-one Docker镜像脚本 build-release.sh - 构建发布版本脚本 docker-compose.yaml - Docker Compose配置文件 Dockerfile - Docker构建文件 Dockerfile.allinone - All-in-one Docker构建文件 配置文件 .dockerignore - Docker构建忽略文件 .gitattributes - Git属性配置 .gitignore - Git忽略文件配置 .golangci.yml - golangci-lint配置 buf.gen.yaml - buf生成代码配置 buf.work.yaml - buf工作空间配置 config.yaml.sample - 示例配置文件 IDE配置 .vscode/ - VS Code配置文件 .github/ - GitHub Actions等配置 文档 docs/ - 项目文档 CHANGELOG.md - 版本变更记录 deployed-sites.md - 已部署站点列表 features-status.md - 功能特性状态 LICENSE - 开源协议 README.md - 项目说明 ROADMAP.md - 开发路线图 其他 main.go - 程序入口文件 Makefile - Make构建配置 go.mod/go.sum - Go模块依赖配置 run.sh - 运行脚本首先配置一下Go的源 默认是官方源 我们换一下国内源打开cmd输入以下命令go env -w GO111MODULE=on go env -w GOPROXY=https://goproxy.cn然后配置一下Go的编译设置 因为我们要在服务器上部署 我这边用的是Ubuntu系统 部署在宝塔面板上 所以我们得编译Linux可执行的二进制文件set GOARCH=amd64 go env -w GOARCH=amd64 set GOOS=linux go env -w GOOS=linux这样就设置成了编译Linux可执行的二进制文件了然后我们来配置一下config.yaml.sample文件首先复制一份config.yaml.sample文件更名为config.yaml然后在config.yaml中配置我们需要的这里我简单的配置一下我的App: # APP基础设置项 RunMode: debug AttachmentIncomeRate: 0.8 #这个是里面付费作者的提成比例 这个0.8 就是80% 设置1.0 就是100%收益 如果你不启用钱包或者付费 请忽视这条 MaxCommentCount: 10 DefaultContextTimeout: 60 DefaultPageSize: 10 MaxPageSize: 100 Server: # 服务设置 RunMode: debug HttpIp: 0.0.0.0 HttpPort: 8010 ReadTimeout: 60 WriteTimeout: 60 Features: Default: ["Web", "Frontend:EmbedWeb", "Meili…