## 前言

因为个人爱好，购买了云服务器，上面部署了静态博客网站，科学上网服务，内网穿透服务。

上述条件弄完之后，还剩下很多性能。所以决定自己实现一个服务器应用程序，代码比较简单，也可以说就是练练手。

## 访问统计

`/api/v1/visit_analysis`

`/api/v1/most_viewed_urls`

`/api/v1/latest_viewed_urls`

表名：visit_analysis

| 字段名          | 数据类型 | 约束条件              | 解释 |
| --------------- | -------- | --------------------- | ---- |
| id              | INTEGER  | NOT NULL，PRIMARY KEY | 主键 |
| url             | TEXT     | NOT NULL              |      |
| visitor_uuid    | TEXT     | NOT NULL              |      |
| last_user_agent | TEXT     | NOT NULL              |      |
| last_view_time  | INTEGER  | NOT NULL              |      |
| page_view_count | INTEGER  | NOT NULL              |      |

1. 创建table visit_analysis。
2. 插入 url，visitor_uuid，last_user_agent ，last_view_time至表中，如果表中已存在url，visitor_uuid 相同的item，则更新last_user_agent ，last_view_time，并将page_view_count加1，否则创建新的item，并将page_view_count赋值为1。
3. 根据url 获取 不同的visitor_uuid的个数作为访客数量统计，将所有 page_view_count 累加作为访问次数统计。
4. 将 url 的 所有 page_view_count 累加，统计出 n 个最大的记录。
5. 将 url 的 last_view_time进行排序，统计出最新的 n 个记录。
6. 将所有记录的不同 visitor_uuid 相加作为网站总访客数，将所有page_view_count相加作为网站总访问次数。

### 问题

sqlite3 如何将所有记录的 url 字段（TEXT类型） 中的 工作笔记 替换为 漫步闲谈？例如 /工作笔记/abc 替换为 /漫步闲谈/abc

```sqlite
sqlite3 ./database.sqlite

DELETE FROM visit_analysis WHERE rowid IN (
  SELECT t1.rowid 
  FROM visit_analysis t1
  JOIN visit_analysis t2 
    ON t1.visitor_uuid = t2.visitor_uuid
    AND REPLACE(t1.url, '工作笔记', '漫步闲谈') = t2.url
    AND t1.rowid != t2.rowid
  WHERE t1.url LIKE '%工作笔记%'
);

UPDATE visit_analysis SET url = REPLACE(url, '工作笔记', '漫步闲谈') WHERE url LIKE '%工作笔记%';

.quit
```

## 注册/登录

```json
//接口: /api/v1/user/register

//POST Body
{
  "username": "string(6-20位字母数字组合)",
  "password": "string(8-20位，需包含大小写和数字)",
  "email": "string(有效邮箱格式)"
}

// 回复
{
  "code": 200,
  "message": "注册成功",
  "data": {
    "user_id": 256
  }
}

curl -X POST \
  http://192.168.3.5:8081/api/v1/user/register \
  -H "Content-Type: application/json" \
  -d '{
    "username": "amass",
    "password": "123456",
    "email": "12345678@qq.com"
  }'
```



```json
//接口: /api/v1/user/login

// POST Body
{
  "username": "string",
  "password": "string",
}

curl -v -X POST \
  http://192.168.3.5:8081/api/v1/user/login \
  -H "Content-Type: application/json" \
  -d '{
    "username": "amass",
    "password": "123456",
	"remember_me": true
  }'


{
  "code": 200,
  "message": "login success",
  "data": {
    "user_id": "U123456789"
  }
}
```



```json
//接口: /api/v1/user/logout

{
  "code": 200,
  "message": "logout success",
}
```





```json
//接口: /api/v1/user/verify
// Cookie: auth=<jwt_token>

{
  "code": 200,
  "message": "会话有效",
  "data": {
    "user_id": "U123456789",
    "session_expire": 1669987200
  }
}
```



一般在Web应用前后端实现中,如何传输账号密码以及保存和后续验证？请给出经典应用方案。

用户注册的时候，前端需要把账号密码发送到后端。这里的关键是传输过程的安全，所以必须用HTTPS，不能是明文传输。

后端收到密码后，不能直接存明文，得做哈希处理，并且加盐。比如用bcrypt这样的算法，因为它是专门为密码存储设计的，速度慢，可以抵御暴力破解。盐值要每个用户独立生成，这样即使两个用户密码相同，哈希值也不同。

然后是登录时的验证。用户输入账号密码后，前端同样通过HTTPS发送到后端。后端根据用户名找到对应的用户记录，取出盐值和哈希后的密码，然后用相同的算法对用户输入的密码进行哈希，比较两者是否一致。如果一致，就生成一个会话或者Token返回给前端，比如JWT。之后的前端请求可以带着这个Token，后端验证Token的有效性来处理后续请求。

表名：users

| 字段名        | 数据类型 | 约束条件                            | 解释 |
| ------------- | -------- | ----------------------------------- | ----|
| id            | INTEGER  | NOT NULL,PRIMARY KEY,AUTO_INCREMENT | 主键 |
| username      | TEXT     | UNIQUE,NOT NULL                     |     |
| password_hash | BLOB     | NOT NULL                            |     |
| salt          | BLOB     | NOT NULL                            |     |
| created_at    | INTEGER  | NOT NULL                            |     |



## Live2D 模型添加

在 XML 配置文件定义`Live2dModelsRoot` 字段，值默认为 `resources/live2d`。

模型相关文件放置在 DocumentRoot/resources/live2d下。

## Wake On Lan

1. 实现一个客户端，上线之后向服务器发送自己的状态，服务器将其作为上下线状态判断。客户端提供了
2. Web前端可以通过 Http api 获取 上线的客户端提供了哪些 Wake on lan 服务 ，可以显示在页面上。
3. 当web点击对应的按钮时，服务器通知服务对应的客户端
4. 客户端接收到指令后，开始向该服务对应的mac进行广播。


## 任务清单

| 字段名        | 数据类型     | 约束条件              | 解释 |
| ------------- | ------------ | --------------------- | ---- |
| id            | INTEGER      | NOT NULL，PRIMARY KEY |      |
| create_time   | INTEGER      | NOT NULL              |      |
| parent_id     | INTEGER      |                       |      |
| content       | VARCHAR(512) | NOT NULL              |      |
| finished      | BOOL         |                       |      |
| finished_time | INTEGER      |                       |      |



## Core Dump

通过命令`ulimit -a`查看：

```
real-time non-blocking time  (microseconds, -R) unlimited
core file size              (blocks, -c) 0
data seg size               (kbytes, -d) unlimited
scheduling priority                 (-e) 0
file size                   (blocks, -f) unlimited
pending signals                     (-i) 6846
max locked memory           (kbytes, -l) 228312
max memory size             (kbytes, -m) unlimited
open files                          (-n) 65535
pipe size                (512 bytes, -p) 8
POSIX message queues         (bytes, -q) 819200
real-time priority                  (-r) 0
stack size                  (kbytes, -s) 8192
cpu time                   (seconds, -t) unlimited
max user processes                  (-u) 6846
virtual memory              (kbytes, -v) unlimited
file locks                          (-x) unlimited
```

core file size这一项为0，说明不生成core dump文件。

在`/etc/profile`里面加入

```
ulimit -c unlimited
sysctl -w kernel.core_pattern=core_%t_%s_%d_%e
```

查看帮助`man 5 core`。

## 企业微信

```xml
<xml>
  <ToUserName><![CDATA[ww1a786851749bdadc]]></ToUserName>
  <FromUserName><![CDATA[LuoCai]]></FromUserName>
  <CreateTime>1749032507</CreateTime>
  <MsgType><![CDATA[text]]></MsgType>
  <Content><![CDATA[今天去哪里？]]></Content>
  <MsgId>7512037417818888268</MsgId>
  <AgentID>1000003</AgentID>
</xml>
```

## 微信公众号对接

1. 公众号管理网页：设置与开发→基本配置→服务器配置。
2. 由于使用的是测试公众号，因此只能够接受消息，微信服务器会将该信息发送至我们的服务器，然后我们可以对该消息进行回复，随后该连接将被关闭。



```mermaid
stateDiagram-v2
[*] --> Idle

Idle --> WaitSetAlarmClock : input 1
WaitSetAlarmClock --> Idle : process input

Idle --> WaitSetText : input 2
WaitSetText --> Idle : process input

Idle --> Idle : not found
```

## 修改历史

### 2025/02/28

1. 重新新建项目，只存放服务器业务相关代码和文件。
2. 去除Web Toolkit，以后不再使用它了。

### 2021/09/03

1. 通过阿里云申请免费SSL证书放置cert目录中。
2. 修改`conf/nginx.conf`文件，使http全部重定向至https。
