Akawa

ETY001的博客

起因

因为最近要开发 AuthSteem(一个 SteemConnectPHP 版本的复制品),其中需要到生成私钥,验证私钥之类的操作,而目前没有找到一款包含这个功能的 PHP SDK,所以要自己来实现。

代码

虽然过程很艰辛,但是代码还是很简短的,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use BitWasp\Bitcoin\Key\Factory\PrivateKeyFactory;
function generatePrivateKeysFromMainPassword($username, $mainPassword) {
$roles = ['owner', 'active', 'posting', 'memo'];
$result = [];
$factory = new PrivateKeyFactory();
foreach ($roles as $role) {
$seed = $username.$role.$mainPassword;
$brainKey = implode(" ", explode("/[\t\n\v\f\r ]+/", trim($seed)));
$hashSha256 = hash('sha256', $brainKey);
$privKey = $factory->fromHexUncompressed($hashSha256);
$result[$role] = $privKey->toWif();
}
return $result;
}
$result = generatePrivateKeysFromMainPassword('ety001', '123456');

探索过程

过程真的是很艰辛,主要时间就是在读 steem-js 的源代码中度过的。另外有一篇关于比特币地址的文章也有指导意义,地址是:https://www.cnblogs.com/kumata/p/10477369.html

总结下,生成过程是 $username, $role, $mainPassword,三者连接后的字符串做 sha256 哈希,哈希的这一步的目的是产生一个 32-bytehex 字符串,这个字符串也就是你的私钥了,只不过这个私钥还需要经过一步处理,才是我们平时看到的样子。这个过程就是 Base58

Base58 的目的就是要把 256-bit 的二进制串(也就是 32-bytehex 字符串)转换为人类可读的、相对较短、不易写错的字符串。详细的内容在上面我给出的那个文章里有。

经过 Base58 处理后,就能得到我们平时看到的私钥字符串了。

这里我找到了一个库 bitwasp/bitcoin,可以帮助我更好的完成这个过程。通过使用这个库的 BitWasp\Bitcoin\Key\Factory\PrivateKeyFactory::fromHexUncompressed() 方法,可以快速的完成这个工作。

下一步

本计划等研究出如何把私钥转成公钥后再发文,但无奈花了一个下午,还是没有弄成功,于是下一步的工作就是需要能用 bitwasp/bitcoin 库已有的方法,实现通过私钥得到公钥。

目前尝试了 bitwasp/bitcoin 库里面自带的 BitWasp\Bitcoin\Address\PayToPubKeyHashAddress 类继承的 getAddress 方法,但是得到的地址并不是 Steem 格式的公钥地址。问题应该是 Steem 得到公钥的过程跟 BTC 还是有区别的。

另外仿照 Steem-js 的这段代码https://github.com/steemit/steem-js/blob/master/src/auth/ecc/src/key_public.js#L110 改写了一段 PHP 的版本,仿写的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use BitWasp\Bitcoin\Key\Factory\PrivateKeyFactory;
use BitWasp\Buffertools\Buffertools;
use BitWasp\Bitcoin\Crypto\Hash;
use BitWasp\Bitcoin\Base58;
function getPubKeyFromPrivKeyWif($wif) {
$factory = new PrivateKeyFactory();
$privKey = $factory->fromWif($wif);
$pubKeyBuff = $privKey->getBuffer();
$checkSum = Hash::ripemd160($pubKeyBuff);
$addy = Buffertools::concat($pubKeyBuff, $checkSum->slice(0, 4));
$pubdata = Base58::encode($addy);
$pubKeyStr = 'STM'.$pubdata;
return $pubKeyStr;
}

但是,结果依旧不对。

所以还得继续折腾。。。

起因

最近一个项目用到了 Laravel 框架的 Task Schedule 功能。

这个功能其实就是把 Laravel 的一个 Command 加到 Crontab 中,即

1
* * * * *  php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1

然后你可以在 Laravel 中配置更多的详细的计划任务。

问题

由于当前生产环境,我使用的是 Docker 来部署的。

我的 Docker 部署方案思路是用 Docker 的容器来作为运行环境,所有的网站代码通过挂载的方式,让容器读取到。具体的配置方案可以参考我之前的一篇文章 《命令行版的docker化lnmp搭建》。

这样的生产环境部署 Crontab 就有些棘手了。因为容器最好是只跑一个进程,如果用 docker execPHP 容器里执行 php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1,那就违背了这个最佳实践。而在宿主机部署计划任务,宿主机又没有 PHP 执行环境。

解决

最终我想到的方案是,按照当前 PHP 容器的配置参数,再启动一个临时容器来执行 php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1

比如说当前我的 PHP 容器的启动命令是:

1
2
3
4
5
6
7
8
9
docker run -itd --name php7 \
-v /etc/php7:/etc/php7 \
-v /data/wwwroot:/data/wwwroot \
-v /tmp:/tmp \
-v /data/logs/php7:/var/log/php7 \
--restart always \
--network lnmp \
--ip "172.20.0.4" \
ety001/php:7.2.14

那么我在宿主机创建一个脚本 schedule.sh,内容如下:

1
2
3
4
5
6
7
8
9
10
docker run -i \
--user 65534:65534 \
--rm \
-v /etc/php7:/etc/php7 \
-v /data/wwwroot:/data/wwwroot \
-v /tmp:/tmp \
-v /data/logs/php7:/var/log/php7 \
--network lnmp \
ety001/php:7.2.14 \
php /data/wwwroot/xiaoyugan-server/artisan schedule:run

然后在宿主机的计划任务中添加

1
* * * * * /your-project-path/schedule.sh

这里需要注意的是,去掉了 -t 参数,否则把 schedule.sh 加入到计划任务后,会执行失败,报 The input device is not a TTY
另外需要增加 --user 参数来指定你的计划任务的执行用户。这个配置很重要!!!由于我的网站运行在 nobody 用户下,如果不增加这个配置,那么计划任务里的写日志操作,很可能在每天0点的时候触发,进而导致日志文件的属主是 root 用户,进而网站再有写日志操作就会没有权限写入了,很尴尬!
--rm 参数可以使容器里的主进程执行结束后,自动删除该容器

总结

目前看,这个方案应该是优雅的吧。不过配置起来还是很复杂,且很多点有时候想不到。就像这个 --user 参数,也是在偶然的跨天测试中发现的。像这种跨天的bug真的是很坑。。。

起因

由于目前手头所有的本不是 MacOSX 就是LInux,再或者是ChromeOS系统。有时候想找个 Windows 系统测试东西,都找不到。老想着在淘一台性价比高的 Windows 的 VPS 用,今天才反应过来,我特么的见证人服务器那么多闲置资源为啥不拿来用?!!!轻轻松松 8 核 16G,硬盘任意用啊!!!

开工

安装KVM

我的宿主机是 Ubuntu16.04 不带桌面,安装很简单,只需要一条命令:

1
apt-get install qemu-kvm libvirt-bin virtinst bridge-utils cpu-checker

安装好以后,下载 Windows10 的 ISO 镜像。

启动

下载好以后,只需要两条命令就可以启动 KVM VPS 了。

先去创建虚拟盘

1
qemu-img create -f qcow2 /data/vm_images/win10/sys.img 50G

路径和大小根据自己的情况设定就好了。

然后一条命令创建并启动 VPS

1
virt-install --name win10 --ram 16384 --file /data/vm_images/win10/sys.img --cdrom /home/ety001/win10prox64.iso --os-type windows --vnc --vncport 5900 --vnclisten 0.0.0.0 --vcpus 8

里面的参数应该都看得懂,记得加上 –vnc 参数和配置,这样才能通过 VNC 远程来操作 VPS

使用

这里不得不吐槽苹果自带的 VNC 客户端,千万不要用这个去连,因为根本连不上!!!!一开始我还在怀疑是我的 frp 端口映射软件出了问题,折腾了一天,也不行,每次连接就是在那里转菊花。。。

今天才想到为什么我不换一个 VNC 客户端呢?!正好手机上有 VNC Viewer,赶快连一下服务器所在网络的 VPN,接入后,打开 VNC Viewer,连接服务器,瞬间登陆进去,画面早已经在安装界面等待,赶紧的安装了一下,快的飞起~~~

安装后进入系统

设置开机自启动

首先需要关闭虚拟机,然后执行下面的命令

1
virsh autostart win10

win10就是你的虚拟机的名字了

增加声卡

1
2
3
<sound model='ich6'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
</sound>

列出所有主机

1
virsh list

关机

1
virsh shutdown win10

强制关机

1
virsh destroy win10

删除主机

1
virsh undefined win10

总结

最近忙到脑子经常秀逗,思路跳跃比以前差了好多。总结一下就是身边自己的资源不要忘了,苹果自家的远程还是只跟自家的配套。


2021-05-28 补充

增加声卡支持

1
2
3
<sound model='ich6'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
</sound>

注意 slot 位不要冲突。

如何删除sasl用户

1
2
3
4
5
db_dump -p /etc/sasldb2 > /tmp/sasldb2.dump
vim /tmp/sasldb2.dump # 找到你要删除的用户,删掉用户和密码即可,也可以修改密码
mv /etc/sasldb2 /etc/sasldb2.bak
db_load -f /tmp/sasldb2.dump /etc/sasldb2
rm -rf /tmp/sasldb2.dump

如何让postfix以TLS方式连接远端服务器发信

/etc/postfix/main.cf 最后增加下面的配置。配置后再给 Gmail 发信,就不会提示不安全连接了。

1
2
smtpd_tls_security_level = may
smtp_tls_security_level = may

另外推一下之前写的《如何快速搭建邮件服务器用来发邮件》https://akawa.ink/2018/01/08/create-a-simple-smtp-server-by-postfix-and-sasl.html

引子

最近真的是跟 Webpack 作上了,又在 Webpack 上花费了宝贵的两天的工作时间。

上次好不容易把 iview-admin 集成进 Laravel,本来以为可以开开心心的开发了,结果在收尾的功能中需要加入富文本编辑器。由于 iview-admin 中集成了一个富文本编辑器,于是就把集成的这个 wangeditor 引入过来使用了。

结果,webpack 对于文件的编译速度瞬间从几秒变成了一分半钟。

WTF!

找原因

Laravel Mix默认的开发环境的编译命令如下:

1
cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js

但是这个坑爹的配置,根本看不出来编译慢的问题出在哪里好吗?!(如下图,加入 wangedit 编辑器后,每次在70%位置就会卡主大约70多秒,甚至更多)

怎么才能找到是具体哪个文件编译慢呢?

最先想到的是看看 webpack.js 的可用参数,最终找到了一个 --profile 参数,加上这个参数后,稍微多了点信息,但是完全不够啊。。。还是没法确认问题在哪啊。。。

接下来的大部分时间都花在了搜索引擎上,主要围绕的搜索关键词是 webpack build slow 之类的。但是完全没有什么用。

又切换了个思路,看看有没有什么好的调试工具。群里有人推荐我 speed-measure-webpack-plugin

看了下说明,是个好插件,可惜我这个项目的 webpack 套在 laravel-mix 里面,我只能通过 laravel-mix 提供的方法来配置 webpack 的参数,而 speed-measure-webpack-plugin 的使用方法是下面这个样子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
把原来的
const webpackConfig = {
plugins: [
new MyPlugin(),
new MyOtherPlugin()
]
}
改为
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
const webpackConfig = smp.wrap({
plugins: [
new MyPlugin(),
new MyOtherPlugin()
]
});

如果我想要用 speed-measure-webpack-plugin 的话,需要在 node_modules 目录下找到 laravel-mix 包,然后修改里面的代码,让 laravel-mixmerge 完用户自定义的配置后,调用 speed-measure-webpack-plugin ,再传给 webpack

我看了下 laravel-mix 的代码,感觉就目前我的水平要想实现的话,需要耗费不止两天的时间吧,这样方向也有点偏。于是这个方案也抛弃了。

柳暗花明

虽然 speed-measure-webpack-plugin 不能用,但是给了我一个启发,那就是有没有可以直接写在 webpackplugins 配置中调用的调试插件呢?

功夫不负有心人,在大半天之后,偶然在 Stack Overflow 的一个问题的回复中看到了 simple-progress-webpack-plugin 这个插件。不过当时心是灰的,因为找了很久没找到,打开这个插件的文档,里面也没有个截图啥的,完全就是死马当活马医,试了试。按照文档提示,先安装 npm install simple-progress-webpack-plugin --save-dev,然后修改 laravel-mix 的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const SimpleProgressWebpackPlugin = require( 'simple-progress-webpack-plugin' ); // 这是新增的配置

mix.js('resources/js/admin.js', 'public/static')
.sass('resources/sass/admin.scss', 'public/static')
.webpackConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, 'resources/js/'),
'_c': path.resolve(__dirname, 'resources/js/components'),
},
},
output: {
chunkFilename: 'static/chunks/[name].js',
},
plugins: [
new SimpleProgressWebpackPlugin() // 这是新增的配置
],
})
.babelConfig({
persets: ['@vue/app']
})
.version();

这次打印出来的信息有些用处了,如下图所示

这次知道是在 Optimize modules 阶段速度慢了,具体是在 Module and chunk tree optimization 这里。于是以 webpack optimize modules slow 为关键词搜索,结果第一条就解决了问题:

妈蛋的原来是在异步加载优化这里慢啊。按照 issue 里提到的 babel-plugin-dynamic-import-node 插件,搜索了下,找到安装部署方法 npm install babel-plugin-dynamic-import-node --save-dev,然后配置下 laravel-mix

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const SimpleProgressWebpackPlugin = require( 'simple-progress-webpack-plugin' );

mix.js('resources/js/admin.js', 'public/static')
.sass('resources/sass/admin.scss', 'public/static')
.webpackConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, 'resources/js/'),
'_c': path.resolve(__dirname, 'resources/js/components'),
},
},
output: {
chunkFilename: 'static/chunks/[name].js',
},
plugins: [
new SimpleProgressWebpackPlugin()
],
})
.babelConfig({
plugins: ['dynamic-import-node'], // 新增配置
})
.version();

再次编译,瞬间完成!!撒花!!

区别

但是看到有提到是在 dev 环境使用 babel-plugin-dynamic-import-node 插件,这是为啥呢?用 requireimport() 有啥区别呢?

初步探索了下发现使用 babel-plugin-dynamic-import-nodeimport() 替换成 require 编译的话,就没有 chunk files 了,相当于是跳过了 code split 之类的阶段吧(我猜是这样)。

可以看下下面的两个截图,第一个是不使用 babel-plugin-dynamic-import-node 进行生产环境 build,第二个是使用的情况进行 build

从最终的文件大小和编译所需要的时间来看,目前不用 chunk 功能,并没有什么问题,于是最终选择使用 babel-plugin-dynamic-import-node 以此来解决编译时间过长的原因。

具体深入进去还有什么区别没时间探索了,目前编译后,使用正常,那就先这样吧。。。

最近需要开发一套后台,挑来挑去,觉得 iview-admin 不错,决定要使用这个后台前端框架。上面就是最终的效果图。

但是由于我们的后台是 Laravel 框架用的 Laravel Mix, 与 iview-admin 用的 vue-cli-service 不一样,于是整合起来有些麻烦,虽然最简单的方法是开两个库独立开来,但是这会让部署什么的增加一些环节,毕竟这个项目开发就我自己,没必要折腾那么多,于是就想要整合。

从周二开始折腾,折腾来折腾去,将近一周过去了,终于搞定了(虽然解决了最后一个问题,但是原理是啥我也不知道),现在已经可以使用 Laravel Mix 来直接替代 vue-cli-service 编译啦。

为了方便自己以后再次使用,所以记录下关键的几个环节。

首先需要的就是调整下 package.json,我的代码最终版如下:

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch": "npm run development -- --watch",
"watch-poll": "npm run watch -- --watch-poll",
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
"prod": "npm run production",
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
},
"devDependencies": {
"@vue/babel-preset-app": "^3.5.0",
"axios": "^0.18",
"bootstrap": "^4.0.0",
"chai": "^4.1.2",
"clipboard": "^2.0.0",
"codemirror": "^5.38.0",
"countup": "^1.8.2",
"cropperjs": "^1.2.2",
"cross-env": "^5.1",
"dayjs": "^1.7.7",
"echarts": "^4.0.4",
"html2canvas": "^1.0.0-alpha.12",
"iview": "^3.3.0",
"iview-area": "^1.5.17",
"jquery": "^3.2",
"js-cookie": "^2.2.0",
"laravel-mix": "^4.0.14",
"less": "^2.7.3",
"less-loader": "^4.0.5",
"lodash": "^4.17.5",
"mockjs": "^1.0.1-beta3",
"popper.js": "^1.12",
"resolve-url-loader": "2.3.1",
"sass": "^1.17.2",
"sass-loader": "7.*",
"simplemde": "^1.11.2",
"sortablejs": "^1.7.0",
"tree-table-vue": "^1.1.0",
"v-org-tree": "^1.0.6",
"vue": "^2.5.17",
"vue-i18n": "^7.8.0",
"vue-router": "^3.0.2",
"vue-template-compiler": "^2.5.13",
"vuedraggable": "^2.16.0",
"vuex": "^3.0.1",
"wangeditor": "^3.1.1",
"xlsx": "^0.13.3"
}
}

这里是在 Laravel 原有的 package.json 基础上,把 iview-admin 需要的 依赖 一一手动添加进去的。

其中命令中的 node_modules/webpack/bin/webpack.js 应该是调用的 laravel-mix 包中的依赖。

完成 package.json 之后,我们使用 npm install 安装一下所有的依赖,然后把 iview-admin 项目克隆到本地,把其中的 src 目录下的所有文件复制到 Laravel 项目的 resources/js 目录下。如果你想变更入口名称,可以把 main.js 改成你自己想要的名字,这里我改为了 admin.js

之后修改一下 Laravel 项目根目录下的 webpack.mix.js 文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const mix = require('laravel-mix');

mix.js('resources/js/admin.js', 'public/static')
.sass('resources/sass/admin.scss', 'public/static')
.webpackConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, 'resources/js/'),
'_c': path.resolve(__dirname, 'resources/js/components'),
},
},
output: {
chunkFilename: 'static/chunks/[name].js',
},
})
.babelConfig({
"presets": [
"@vue/app",
],
})
.version();

在原有的基础上增加了 resolve 配置,为了能够正确解析 @_c 开头的引入包路径。增加了 output 配置,让所有的 chunk 文件与主文件同目录(这条配置可不加)。增加了 babelConfig 配置,为了解决 动态import 语法解析的问题(这个就是目前还没有弄明白的那个地方)。

完成上面的步骤后,就完成了大半了。

之后,在 Laravel 项目中增加一个后台的路由,我是直接加在 routers/web.php 中的,如下

1
Route::get('admin', 'AdminController@index');

创建 AdminController,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class AdminController extends Controller
{
public function index(Request $request) {
return view('admin/index');
}
}

创建视图 resources/view/admin/index.blade.php,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>BACC</title>
<meta name="csrf-token" content="{{ csrf_token() }}" api_token="{{ \Auth::check() ? 'Bearer ' . \Auth::user()->api_token : 'Bearer ' }}">
<link rel="stylesheet" href="{{ mix('static/admin.css') }}">
<!-- <script src="{{ asset('/js/tinymce.min.js') }}"></script> -->
</head>
<body>
<div id="app"></div>

<script src="{{ mix('static/admin.js') }}"></script>
</body>
</html>

最后要修改的就是 iview-admin 的路由模式了。iview-admin 默认使用的是 history,而这个配置将会让 iview-admin 的路由与 Laravel 的路由冲突,因此需要去掉这个配置。这个配置项在 resources/js/router/index.js 中,把下面的代码中的 mode: 'history'去掉即可。

1
2
3
4
const router = new Router({
routes,
mode: 'history'
})

所有配置完成,执行 npm run watch,如果一切顺利的话,所有的前端文件会编译完成,直接访问 http://localhost:8000/admin 就能看到 iview-admin 已经成功整合完成了!

撒花!

最近新开了一个钱包的App项目,直接把之前的代码从 Github 上拖回来,但是执行 cordova prepare -d 一直不成功,显示 current working directory is not a cordova-based project.

经过查看源码,发现在 https://github.com/apache/cordova-lib/blob/master/src/cordova/util.js#L102 这个地方的代码有问题。

正常情况下,这个函数返回 2 就可以了,由于我的 .gitignore 中把 wwwplatforms 两个目录都给忽略了,这就导致了一直返回 0,进而导致另外一个位置获取到的项目目录一直是 /,这显示不是项目根目录。。。

于是手动创建了 wwwplatforms 两个空目录后,一切就正常了。。。。。坑爹。。。。。。

在开发 SteemTools 服务号的文章单独页面的时候,遇到的一个问题就是有些人的图片存放在了被墙的服务器上了,导致文章中的图片无法正常显示。

从网上搜索了下,找到了一个用 node 写的图片代理,我已经 fork 到了自己的库中,https://github.com/ety001/node-image-proxy

为了方便部署和管理,把这个服务封装进了 Docker 中。

运行命令如下:

1
docker run -itd --name node-image-proxy -p 9091:9091 -v /data/node-image-cache:/app/cache --restart always ety001/node-image-proxy

其中 /data/node-image-cache 目录是用来存储缓存的,自己手动建立一个目录就好了。

启动成功后,可以用 nginx 的反向代理来实现 https,也可以直接使用,只需要把要代理的图片地址放到 url 后面就好了,例如这样:

1
https://img.steemtools.top/http://newappaz.oss-cn-hongkong.aliyuncs.com/wherein_images/post/20190224/89a2802d622c4940b2ece51eea04aecd.jpg

这样只需要把服务部署在国外服务器上,然后在解析 markdown 的时候把原来的图片地址加上代理地址后,就可以正常的访问文章中的图片了。

起因

由于最近在开发恒星币的钱包,其中有部分数据,如果直接通过恒星的 API 获取则效率太低,影响页面展示体验。
于是用 hapijs 来开发一些定制的接口,批量获取并缓存数据,来提升页面访问效果。

之前在 《使用 hapijs 快速构建自己的 api 服务》 这篇文章中有写到 hapijs 默认使用 catboxcatbox-memory 组件来缓存数据。

我这次还是按照上次的方法来使用缓存,但是却没有成功,每次提交请求,都是重新去获取数据,而没有走缓存。

祸起文档和配置

翻了好几遍 hapijs 的文档,也使用搜索引擎查了,折腾了3个多小时无果,最终决定一边读源码一边在代码加标记输出。

在每个关键位置都打了输出,但是没有看到任何报错和问题。无意中看到了 hapijs 文档中的一个配置参数 generateOnReadError,作用是当在读取缓存时遇到错误时是否报错,而默认则是关掉的!!!WTF!!!!

配置这个参数为 false 后,得再配合 try {} catch () {} 才显示了错误信息,原来是缓存的 key 非法。

比较这次和上次使用 cache 功能的代码,找到了一个不同点,就是上次是使用的 string 作为 key,而这次使用的是 object 作为 key

不过在 hapijs 关于 cache文档 中,关于 generateFunc 参数的解释里有一句 the \'id\' string or object provided to the \'get()\' method.,看上去 idobject 也没有问题啊。

于是我又去读了 catbox 的源码,最终看到 catbox 的一段关于获取缓存信息的 代码

在第88行,原来特么的只接受 {id: id} 这种样子的对象啊?!!!!并且上面82行的注释也列出来了。。。

又去看了下 catbox 的文档中关于 get() 方法的介绍,有这么一句 id - the unique item identifier (within the policy segment). Can be a string or an object with the required 'id' key.

这就恍然大悟了。。。。。。。。。

原来对象中必须包含 id 这个字段啊,原来要是提交对象的话,需要自己来定义索引啊?!!!

修改下代码,这个坑过了。

不容易不容易啊。。

虽然平时主要用 Shadowsocks,但是架不住有时候没法安装 Shadowsocks 的客户端,那么就还是需要 PPTP VPN 或者 L2TP VPN

最早的时候,是使用的各种一键安装脚本,但是由于系统版本差异,每次需要安装的时候,都要现找可用的一键脚本,太费劲了。于是从网上找了别人封装好的 Docker 镜像,这篇文章总结下,基本上就是一条语句就搞定了。

PPTP VPN

使用的镜像是 mobtitude/vpn-pptp,首先需要把用户名和密码配置一下,打开 /etc/ppp/chap-secrets

1
2
3
# Secrets for authentication using CHAP
# client server secret IP addresses
ety001 * 123456 *

上面的就是配置了一个用户名 ety001 和 密码 123456 的用户,然后执行下面的命令就可以了,

1
docker run -d --name pptp --restart always  --privileged -p 1723:1723 -v /etc/ppp/chap-secrets:/etc/ppp/chap-secrets mobtitude/vpn-pptp

最后检查下 tcp 1723 端口在防火墙上是否打开就可以了。

L2TP + IPSEC VPN

使用的镜像是 hwdsl2/ipsec-vpn-server,需要先配置下用户名、密码和PSK,新建一个环境变量的文件 /etc/l2tp-env,内容如下

1
2
3
VPN_IPSEC_PSK=abcdef
VPN_USER=ety001
VPN_PASSWORD=123456

上面的就是配置了一个用户名 ety001,密码 123456,PSK 为 abcdef 的用户,然后执行下面的命令就可以了,

1
2
3
4
5
6
7
8
9
docker run --name ipsec-vpn-server \
--env-file /etc/l2tp-env \
--restart=always \
-p 500:500/udp \
-p 4500:4500/udp \
-p 1701:1701/udp \
-v /lib/modules:/lib/modules:ro \
-d --privileged \
hwdsl2/ipsec-vpn-server

最后检查下 udp 500udp 4500 端口在防火墙上是否打开就可以了。

Shadowsocks

最后再附带上一个一句话部署 Shadowsocks 的命令,先创建个配置文件 /etc/shadowsocks.json,内容如下

1
2
3
4
5
6
7
8
9
{
"server":"0.0.0.0",
"server_port": 10000,
"local_address":"127.0.0.1",
"local_port":1080,
"password":"ety001",
"timeout":60,
"method":"aes-256-cfb"
}

然后执行下面的命令部署

1
$ docker run -d -p 10000:10000 -v /etc/shadowsocks.json:/conf/shadowsocks.json --restart=always --name ss ety001/ss
0%