木头的博客

我是木头 有些想法 有点精力

在上一篇文章 在 NAS 上部署 Gitea 中,我教大家如何在内网中部署 Gitea 服务。但是,我们在内网中访问 Gitea 时,需要使用 http://192.168.5.5:4000 这样的地址,这样的地址不仅不美观,而且还需要记住端口号,不方便,甚至它还不是 HTTPS 的,也不安全。

那有没有什么办法可以让我们在内网中访问 Gitea 时,使用 https://gitea.lan 这样的地址呢?答案是肯定的,我们可以使用 DNS 和反向代理来实现这个功能。

1. 什么是 DNS

DNS 是 Domain Name System 的缩写,即域名系统。它的作用是将域名解析为 IP 地址,这样我们就可以通过域名访问网站了。

我们首先要做的一件事就是在 DNS 服务器中添加一条记录,将 gitea.lan 解析到 192.168.5.5 这个 IP 地址上。这样当我们访问这个域名时,就会将请求转发到我们的 NAS 服务器上对应的端口了。

DNS 服务器是一个树形结构,当你输入一个域名时,DNS 服务器会从最底层的节点向上查找,直到根节点,然后返回对应的 IP 地址。每个节点都缓存有一堆域名和与其对应的 IP 地址。

例如,当我们访问 https://gitea.lan 时,DNS 服务器会:

  1. 先从浏览器中尝试获取缓存的 IP 地址
  2. 如果没有缓存,就会向本机的 DNS 服务器发起请求尝试获取缓存的 IP 地址
  3. 如果本机的 DNS 服务器没有缓存,就会尝试向路由器发起请求尝试获取缓存的 IP 地址
  4. 如果路由器没有缓存,就会向上级 DNS 服务器(通常是运营商,如中国电信)发起请求尝试获取缓存的 IP 地址
  5. … 以此类推,直到根 DNS 节点
阅读全文 »

处于某种原因,需要自己部署一个 Git 仓库管理工具来管理和部署一些奇怪的家庭服务,虽然 GitHub private repository 也可以用,但因为这些平台都中心化的,会受制于人,速度可可靠性也不太理想,在外网做家庭服务的持续部署也比较麻烦,所以就想到了自己部署一个 Git 仓库管理工具,想怎么玩就怎么玩。

为什么不选择装 GitLab 而是 Gitea,因为 GitLab 的硬件要求太高了,而且我只是想要一个简单的 Git 仓库管理工具,不需要多人协作也不需要很多复杂的功能,Gitea 足够了,最低只需要 1 核和 2G 内存,所以选择了 Gitea。

虽然群辉 NAS 自带了 Gitea 的社区套件,之前也一直在用。但是它的版本已经落后于官方好几个版本了,所以这里选择自己用 Docker 部署一个最新版的 Gitea,也方便后续升级和折腾。

注:以下教程图示是群辉 NAS 的安装界面。如果你是其他 NAS 品牌的用户,可以参考自己对应品牌的 Docker 安装界面或是直接使用命令行或 使用 Gitea 的官方 docker compose 进行安装,也可以参考我安装的思路。

阅读全文 »

注:本文不会涉及任何算法,只通俗地分享自己的感悟,若有事实错误请直接批评指正,感谢大家。

0. 序

最近深度体验了 AI 绘图 Stable Diffusion,结合正在发生的经济危机/裁员/通缩,我产生了一些思考:AI 大模型时代的到来,到底会淘汰哪些人?哪些领域会受到影响?AI 带来哪些隐私、道德和安全问题?作为受到直接影响的底层程序员/设计师/画师/写手,我们真的只能坐以待毙吗?

我的结论是:第三产业大部分领域都会受到影响 (实体产业影响较小)。

第一产业是指农、林、牧、渔业。

第二产业是指采矿业,制造业,电力、燃气及水的生产和供应业,建筑业。

第三产业是指除第一、二产业以外的其他行业。第三产业包括:交通运输、仓储和邮政业,信息传输、计算机服务和软件业,批发和零售业,住宿和餐饮业,金融业,房地产业,租赁和商务服务业,科学研究、技术服务和地质勘查业,水利、环境和公共设施管理业,居民服务和其他服务业,教育,卫生、社会保障和社会福利业,文化、体育和娱乐业,公共管理和社会组织,国际组织。

1. AI 绘图现在发展到什么程度了?

其实半年前(2023年3月左右)我就接触了 Stable Diffusion (一个开源的 AI 绘图项目),那时候基于扩散模型的 AI 绘图才刚发展起来,对我有一定的冲击,毕竟这种通过文字转化为图像的方式是革命性的。 但受限于显卡,只画了一些简单的内容,画出来的人也是比较挫。

早期的 AI 绘图模型 (来自 Stable Diffusion 1.5 大模型)

随着时间推移,各种 Chat 类应用,Code 补全类的 AI 工具层出不穷,我意识到 AI 时代已经来临,于是向老婆申请购买了一张二手的 3090 显卡,这张卡的优势在于有 24G 大显存,玩过 AI 绘图的小伙伴应该知道,显存越大,能画出来的原始图像分辨率就越高,训练时每一次迭代也可以同时训练更多图像。

拿到显卡后,我就陆续开始了对 AI 绘图的探索,先是沉溺与画各种漂亮妹子,然后绘制各种风格的图像,比如幻想风格、像素画风、游戏素材等图像。

真实系漂亮妹子
真实系风格 (来自 majicmix realistic 大模型)
奇幻风格 (来自 majicmix lux 大模型)
像素风格 (来自 Pixel Art LoRa 模型)
游戏素材 (左:Game Icon Research LoRa 模型 / 右:Character Design Sheet LoRa 模型)

后来不满足于画各种乱七八糟的东西,开始去各大网站搜罗 SD 应用方面的教程,陆续学习了照片高清放大、照片动漫化、AI 艺术字、光影重绘、换脸换装等各种应用。

AI 高清放大 (SD 高清重绘)
真人转动漫风格 (Disney 大模型重绘)
AI 艺术字 (ControlNet Depth 模型)
创意二维码 (ControlNet QRCodeMonster 模型)
光影重绘 (ControlNet Tile 模型)

再后来又用爱人的照片做数据集,训练她自己的真人模型,效果也相当不错,她本人看到都惊叹于其相似度。

阅读全文 »

标题党,勿全信;
这是一篇关于前端单元测试的优化心得,讲述了一个中型团队坎坷的痛与泪的故事;
长文预警,建议当短篇小说看;
干货在末尾。

就在前几天,我拿到了心心念念的 MacBook M1 Pro,上手第一件事就是跑一下项目上的前端测试,期待着久仰大名的 M1 处理器一显神威。

为什么这么着急用 M1 跑测试?这个故事要从半年前说起。

1. 越来越痛的测试

小半年前,项目规模越来越大,随着十几轮冲刺后,我们有两个前端库的代码量和测试也越来越多,于是出现了上面的对话

不知从什么时候开始,项目代码里的测试成了我们的痛点,推代码时会触发全量的测试,而在这推代码的10多分钟里,我是什么都做不了的,电脑卡的要命,不得不站起来去接杯水或上个厕所。

从某种角度来说,也挺好,能时不时的提醒我站起来活动活动,放松一下肩颈和眼睛,看看博客摸摸鱼(不是)。

但问题是 Pipeline 上的速度也是稳定慢,从开始 Build 到 Deploy to Dev,更是达到了离谱的 30 分钟左右,Pipeline 甚至还触发了客户设定的 300 小时/月的限流。

2. 法外狂徒

git push --no-verify 成了我们项目的常态。

阅读全文 »

最近把家里的网络折腾了一下,整体用下来感觉还不错,这里记录下来分享给大家,大家一起学习交流~

Infrastructure

痛点:

  • 科学上网。现在家里的网络总是觉得有些不尽人意,本人最大的爱好就是周末宅在家里搞搞开源、打打游戏。遇到问题了 Google / StackOverflow 效率是比 Baidu 高,而每个设备自己科学上网比较繁琐,需要各自管理白名单,太麻烦…
  • NAS 访问慢。和爱人出去玩偶尔会拍一些照片和 Vlog,这些都是美好珍贵的记忆,目前存在自己的私有云上,想看了拿出来看看,照片列表加载缓慢,视频进度拖拉卡顿…
  • WIFI 信号。之前路由器是放在客厅,信号到卧室床头比较曲折,有时关门后甚至断网,网络体验极差…

折腾后:

  • 全屋设备科学上网。在软路由里根据 IP 地址分流,国外 IP 走代理,国内直连。终端无需单独开软件,无需在意是否国内外网站。
  • 广告过滤。同上。
  • 内网全千兆访问。访问 NAS 资源、各设备之间文件互传速度大幅提升,堪比本地访问。
  • Docker。开发时如果需要容器资源,内外网都可使用路由器的 Docker,节约开发机资源,目前资源是 4C8G。
  • 数据安全。之前 NAS 是直接暴露在公网的,且没有开启 HTTP,现在公网访问内网设备需要 VPN,访问 NAS 强制 HTTPS。
  • 扩大 WIFI 信号覆盖。未来搬去新家后智能设备增多,WIFI6 是必不可少的。出于成本考虑,WIFI6 AP 放在客厅,现有垃圾 AP 放在卧室。

硬件改造成本共 1135 元

  • 软路由: J4105,8G DDR4 + 64G SATA固态 咸鱼 750 元
  • 交换机: 水星SG108C 塑料8口 JD 69元
  • AP: 华为AX3Pro 咸鱼 295 元
  • 网线: 绿联6类线 0.5m x3 JD 21元

哭,现在设备各种涨价, ax3pro 暴涨 150 元,蹲了二周才蹲到低于 300 元的 AP,J4105 也涨了 100 多,不知道是不是受了这一波矿潮影响…

总之,想把网络环境做好,最大的变化就是没有变化,让用户感觉不到就成功了,只需要默默地提供稳定的服务就好~

阅读全文 »

Vite2 发布有一段时间了,其内部使用了 ESBuild 进行打包,ESBuild 有着相对 Webpack 惊人的打包速度。

esbuild benchmark 数据来自 github.com/evanw/esbuild

React 用户表示令人羡慕,不过 Vite 野心比较大,不止可以用来开发 Vue 项目,类似 Rollup,Vite2 可以使用插件来支持 React 项目。

这就巧了,手上刚好有一个 React 练习项目,使用 Create React App 创建并且进行过 Eject。接下来我们就用这个 React 项目来练练手吧,享受一下飞一般的构建速度!

阅读全文 »

第二章我们简单的介绍了下如何连接测试数据库,这篇我们将结合 TDD 来完整的实现注册和登录功能。(如果接下来我写的内容你已经做过,可以跳过该步)

1. 编写第一个集成测试

按照 Nest 提供的示例 E2E 测试, 位于 test/app.e2e-spec.ts 应该长这样

test/app.e2e-spec.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { Test, TestingModule } from '@nestjs/testing'
import * as request from 'supertest'
import { AppModule } from './../src/app.module'

describe('AppController (e2e)', () => {
let app

beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile()

app = moduleFixture.createNestApplication()
await app.init()
})

it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(200)
.expect('Hello World!')
})
})

现在是运行不了的,不过没关系,我们稍稍改造一下

首先我们测试一个用于检查健康的接口 /hello, 无需导入整个 AppModule, 只需导入 AppController ,改造为下列的样子

app.e2e-spec.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { Test, TestingModule } from '@nestjs/testing'
import { AppController } from 'app.controller'
import * as request from 'supertest'

describe('app module', () => {
let app

beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
controllers: [AppController],
}).compile()

app = moduleFixture.createNestApplication()
await app.init()
})

afterAll(async () => {
await app.close()
})

it('/hello (GET)', () => {
return request(app.getHttpServer())
.get('/hello?name=world')
.expect(200)
.expect('Hello world!')
})
})

然后执行

1
yarn test:e2e

yarn e2e test

阅读全文 »

这一节, 我们引入 Swagger 来自动根据代码里的注脚来生成接口文档。

Nest 为我们提供了一个专用的模块来搭配 Swagger 来使用

1. 安装依赖

1
yarn add @nestjs/swagger swagger-ui-express

2. 初始化 Swagger 模块

在我们的应用入口文件 main.ts 中添加一个 createSwagger 方法, 并在 bootstrap 方法中初始化它

main.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import { INestApplication, ValidationPipe } from '@nestjs/common'
import { NestFactory } from '@nestjs/core'
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'
import { AppModule } from 'app.module'

function createSwagger(app: INestApplication) {
const version = require('../package.json').version || ''

const options = new DocumentBuilder()
.setTitle('Nestjs Realworld Example App')
.setVersion(version)
.addBearerAuth()
.build()

const document = SwaggerModule.createDocument(app, options)
SwaggerModule.setup('/docs', app, document)
}

async function bootstrap() {
const app = await NestFactory.create(AppModule)
app.useGlobalPipes(new ValidationPipe())

if (process.env.SWAGGER_ENABLE && process.env.SWAGGER_ENABLE === 'true') {
createSwagger(app)
}

await app.listen(3000)
}

bootstrap().catch((err) => console.error(err))

createSwagger 中, 我们首先读取了来自 package.json 中的版本号来作为接口的版本

然后我们设置了 Title 和 Bearer 鉴权认证入口, 我们还设置了 /docs 为我们文档的入口

最后,我们判断环境变量中的 SWAGGER_ENABLE 是否打开, 如果打开我们就初始化 Swagger 文档系统。

.env.env.template 中增加 SWAGGER_ENABLE=true, 然后启动服务器

访问 http://localhost:3000/docs 就能看见我们的接口文档创建好啦!

swagger preview

阅读全文 »
0%