0%

记录一下 shell 脚本模板。

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/usr/bin/env bash

args_num=$#
action="${1}"

ALLOWED_ACTION_ARGS=("set" "unset" "test")


function print_ok() {
local msg="${1}"
echo "${msg}"
}

function print_err() {
local msg="${1}"
echo "${msg}" > /dev/stderr
}

function contain() {
local list="${1}"
local ele="${2}"
for i in ${list[*]};
do
if [ "${ele}" == "${i}" ]; then
return 0
fi
done
return 1
}

function check_args_num() {
if [ ${args_num} != 1 ]; then
print_err "Wrong args num"
return 1
fi
}

function check_action_arg() {
if ! contain "${ALLOWED_ACTION_ARGS[*]}" "${action}"; then
print_err "Action arg must be [ set || unset || test ]"
return 1
fi
}

function set_proxy () {
export ALL_PROXY=http://www.vksir.zone
print_ok "Set proxy success"
}

function unset_proxy() {
unset ALL_PROXY
print_ok "Unset proxy success"
}

function test_proxy() {
if curl -k https://www.google.com --connect-timeout 3 >/dev/null 2>&1; then
print_ok "Proxy is available"
else
print_err "Proxy is not available"
fi
}


if ! check_args_num; then
return 1
fi
if ! check_action_arg; then
return 1
fi

if [ "${action}" == "set" ]; then
set_proxy
elif [ "${action}" == "unset" ]; then
unset_proxy
elif [ "${action}" == "test" ]; then
test_proxy
fi

return $?
阅读全文 »

部署简单进程

编辑文件 /etc/systemd/system/supernode.service 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
[Unit]
Description=Supernode
After=network-online.target syslog.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/sbin/supernode /etc/n2n/supernode.conf -f
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
阅读全文 »

最近开我的世界服,发生了好几次内存占满服务器卡死、导致不得不重启服务器的事情,遂而想新建一个交换分区,以免内存占满服务器直接卡死。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 新建交换分区文件
dd if=/dev/zero of=/var/swap bs=1M count=4096
# 格式化交换分区
mkswap /var/swap
# 设置为交换分区
swapon /var/swap
# 设置开机自动挂载交换分区
echo "/var/swap swap swap defaults 0 0" >> /etc/fstab

# 查看交换分区是否生效
free -m

# 关闭交换分区
swapoff -a

10995316573765522

​ 看完,脑海中只剩下大哥。

​ ——近乎完美的人。

​ 强大,自信,善良,勤奋,阳光,谦逊,细心……你可以在大哥身上找到几乎所有、能想到的、为人所能拥有的优秀品质。没有比他更优秀的人了,堪称完美。

​ 像太阳,永远在发光、发热,让人想靠近,给予人温暖。——是我期望中的形象。

阅读全文 »

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
package main

import (
"context"
"fmt"
"os"
"os/signal"
"sync"
"time"
)

var wg sync.WaitGroup

func worker(name string, ctx context.Context, t time.Duration) {
fmt.Println(name, ": enter worker")
select {
case <-ctx.Done():
fmt.Println(name, ": worker context cancel, exit")
case <-time.After(t):
fmt.Println(name, ": worker process complete, exit")
}
wg.Done()
}

func main() {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()

wg.Add(2)
go worker("worker1", ctx, time.Second*2)
go worker("worker2", ctx, time.Second*4)

wg.Wait()
fmt.Println("exit main")
}

【背景】

  • 如 Wireguard 等工作在三层的 VPN,不会主动转发 UDP 广播报文,但能转发指定 IP 的 UDP 报文。

  • 现有一程序,仅在 PC 主网卡(192.168.1.106)上发送从 14001 端口到 14001 端口的 UDP 广播报文。这种报文一是不会使用虚拟网卡(10.0.0.3)发送,二是就算使用虚拟网卡发送,该种虚拟网卡(Wireguard)也无法发送 UDP 广播报文。

  • 想将报文捕获,使用虚拟网卡(10.0.0.3)指定目的 IP (10.0.0.2)进行转发。

【语言】Go

阅读全文 »

【Go】利用 reflect 实现结构体设置默认值

写 API 时经常会需要结构体中某个参数拥有默认值。但如 Gin 只有 ShouldBindQuery 这种 form 类型支持设置默认值,常用的 ShouldBindJSON 这种 json 类型却不支持,很奇怪。

Gin 中 bind 结构体设置默认值

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
package main

import (
"fmt"
"github.com/gin-gonic/gin"
)

type FormData struct {
Name string `form:"name,default=vksir"`
Age int `form:"age,default=18"`
}

type JsonData struct {
Name string `json:"name,default=vksir"`
Age int `json:"age,default=18"`
}

func main() {
e := gin.Default()
e.GET("/", func(c *gin.Context) {
var fd FormData
c.ShouldBindQuery(&fd)
var jd JsonData
c.ShouldBindJSON(&jd)
fmt.Printf("FormData: %+v\n", fd)
fmt.Printf("JsonData:%+v\n", jd)
})
e.Run()
}
阅读全文 »

话不多说直接上代码:

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package log

import (
"errors"
"fmt"
"log"
"os"
)

const (
LevelDebug = (1 + iota) * 10
LevelInfo
LevelWaring
LevelError
LevelCritical
)

var debugLogger *log.Logger
var debugFileLogger *log.Logger
var infoLogger *log.Logger
var infoFileLogger *log.Logger
var warningLogger *log.Logger
var warningFileLogger *log.Logger
var errorLogger *log.Logger
var errorFileLogger *log.Logger
var criticalLogger *log.Logger
var criticalFileLogger *log.Logger
var flag = log.Ldate | log.Ltime | log.Lshortfile | log.Lmsgprefix
var logLevel = LevelInfo

func SetLevel(level int) error {
if level != LevelDebug && level != LevelInfo && level != LevelWaring && level != LevelError && level != LevelCritical {
return errors.New(fmt.Sprintf("invalid level: %d", level))
} else {
logLevel = level
return nil
}
}

func AddFileOutput(filePath string) error {
logWriter, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0655)
if err != nil {
return err
} else {
debugFileLogger = log.New(logWriter, "[DEBUG] ", flag)
infoFileLogger = log.New(logWriter, "[INFO] ", flag)
warningFileLogger = log.New(logWriter, "[WARNING] ", flag)
errorFileLogger = log.New(logWriter, "[ERROR] ", flag)
criticalFileLogger = log.New(logWriter, "[CRITICAL] ", flag)
return nil
}
}

func Debug(format string, v ...any) {
logWithLevel(debugLogger, LevelDebug, format, v)
logWithLevel(debugFileLogger, LevelDebug, format, v)
}

func Info(format string, v ...any) {
logWithLevel(infoLogger, LevelDebug, format, v)
logWithLevel(infoFileLogger, LevelDebug, format, v)
}

func Waring(format string, v ...any) {
logWithLevel(warningLogger, LevelDebug, format, v)
logWithLevel(warningFileLogger, LevelDebug, format, v)
}

func Error(format string, v ...any) {
logWithLevel(errorLogger, LevelDebug, format, v)
logWithLevel(errorFileLogger, LevelDebug, format, v)
}

func Critical(format string, v ...any) {
logWithLevel(criticalLogger, LevelDebug, format, v)
logWithLevel(criticalFileLogger, LevelDebug, format, v)
}

func init() {
debugLogger = log.New(os.Stderr, "[DEBUG] ", flag)
infoLogger = log.New(os.Stderr, "[INFO] ", flag)
warningLogger = log.New(os.Stderr, "[WARNING] ", flag)
errorLogger = log.New(os.Stderr, "[ERROR] ", flag)
criticalLogger = log.New(os.Stderr, "[CRITICAL] ", flag)
}

func logWithLevel(logger *log.Logger, level int, format string, v []any) {
if logger != nil && logLevel >= level {
logger.Printf(format, v...)
}
}
阅读全文 »