Ipv4地址段匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class IpMatcher {
public static boolean matchIPV4(String ip, String cidr) {
String[] ips = ip.split("\\.");
if (ips.length != 4) {
return false;
}
int ipAddr = (Integer.parseInt(ips[0]) << 24)
| (Integer.parseInt(ips[1]) << 16)
| (Integer.parseInt(ips[2]) << 8) | Integer.parseInt(ips[3]);
int type = Integer.parseInt(cidr.replaceAll(".*/", ""));
int mask = 0xFFFFFFFF << (32 - type);
String cidrIp = cidr.replaceAll("/.*", "");
String[] cidrIps = cidrIp.split("\\.");
int cidrIpAddr = (Integer.parseInt(cidrIps[0]) << 24)
| (Integer.parseInt(cidrIps[1]) << 16)
| (Integer.parseInt(cidrIps[2]) << 8)
| Integer.parseInt(cidrIps[3]);
return (ipAddr & mask) == (cidrIpAddr & mask);
}

public static void main(String[] args) {
System.out.println(matchIPV4("172.16.0.1", "172.16.0.0/20"));
}
}

使用certbot申请https证书

我的博客图片放在阿里云的oss,oss绑定域名的https证书过期很久了,之前一直懒得弄,周末抽时间弄一下,证书是使用certbot申请的,步骤如下:

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
➜  ~ sudo certbot certonly --manual --preferred-challenges=dns-01 --server=https://acme-v02.api.letsencrypt.org/directory

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Please enter the domain name(s) you would like on your certificate (comma and/or
space separated) (Enter 'c' to cancel): file.mspring.org
Requesting a certificate for file.mspring.org

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name:

_acme-challenge.file.mspring.org.

with the following value:

eyCcqOYGl7KWxr-mGpp7Y77j6iEV-rC0dXyq8-LnL3k

Before continuing, verify the TXT record has been deployed. Depending on the DNS
provider, this may take some time, from a few seconds to multiple minutes. You can
check if it has finished deploying with aid of online tools, such as the Google
Admin Toolbox: https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.file.mspring.org.
Look for one or more bolded line(s) below the line ';ANSWER'. It should show the
value(s) you've just added.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/file.mspring.org-0001/fullchain.pem
Key is saved at: /etc/letsencrypt/live/file.mspring.org-0001/privkey.pem
This certificate expires on 2022-06-24.
These files will be updated when the certificate renews.

NEXT STEPS:
- This certificate will not be renewed automatically. Autorenewal of --manual certificates requires the use of an authentication hook script (--manual-auth-hook) but one was not provided. To renew this certificate, repeat this same certbot command before the certificate's expiry date.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
* Donating to EFF: https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Golang文件流下载,边下载边计算MD5

当时是为了测试文件网卡问题,发现同样的文件,在一个很烂的网卡中不断的下载,计算的文件MD5会不一样的问题。代码记录下,留作参考。

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package main

import (
"crypto/md5"
"encoding/hex"
"flag"
"fmt"
"io"
"net/http"
"os"
"strconv"
"time"
)

var (
url = "被下载文件链接"
data = make(map[string]int)
logFile = flag.String("logFile", os.Getenv("HOME")+"/"+"network-card-test.log", "日志文件路径") // /Users/xxx/Downloads/fuck.log
)

func main() {
flag.Parse()
for {
handle()
}
}

func handle() {
md5Str, err := download(url)
if err != nil {
log(err.Error())
return
}

defer func() {
count := data[md5Str]
data[md5Str] = count + 1
}()

count, found := data[md5Str]
if !found && len(data) > 0 {
log("文件MD5异常:" + md5Str + ", count=" + strconv.Itoa(count))
} else {
log("文件MD5:" + md5Str + ", count=" + strconv.Itoa(count))
}
}

func download(url string) (string, error) {
var (
err error
resp *http.Response
contentLen int64
downloadLen int
)
if resp, err = http.Get(url); err != nil {
return "", err
}

if contentLen, err = strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 64); err != nil {
return "", err
}

defer func() {
_ = resp.Body.Close()
fmt.Print("\n")
}()

h := md5.New()
for {
buf := make([]byte, 1024)
c, e := resp.Body.Read(buf)
if e != nil && e != io.EOF {
return "", e
}
downloadLen += c

printProgress(downloadLen, contentLen)

h.Write(buf[0:c])

if e != nil && e == io.EOF {
break
}
}
return hex.EncodeToString(h.Sum(nil)), nil
}

func printProgress(downloadLen int, contentLen int64) {
fmt.Printf("\r")
fmt.Printf("Downloading... %d of %d", downloadLen, contentLen)
}

func log(content string) {
content = time.Now().Format("2006-01-02 15:04:05") + ": " + content

fmt.Println(content)

file, err := os.OpenFile(*logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
fmt.Println(err.Error())
return
}
defer func() {
_ = file.Close()
}()

_, err = file.WriteString(content + "\n")
if err != nil {
fmt.Println(err.Error())
}
}

Go语言http请求计算文件md5

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

import (
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"net/http"
"strconv"
)

func main() {
ret, err := download("http://....")
if err != nil {
fmt.Println(err)
}
fmt.Println(ret)
}

func download(url string) (string, error) {
var (
err error
resp *http.Response
contentLen int64
downloadLen int
)
if resp, err = http.Get(url); err != nil {
return "", err
}

if contentLen, err = strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 64); err != nil {
return "", err
}

defer func() {
_ = resp.Body.Close()
fmt.Print("\n")
}()

h := md5.New()
for {
buf := make([]byte, 1024)
c, e := resp.Body.Read(buf)
if e != nil && e != io.EOF {
return "", e
}
downloadLen += c

printProgress(downloadLen, contentLen)

h.Write(buf[0:c])

if e != nil && e == io.EOF {
break
}
}
return hex.EncodeToString(h.Sum(nil)), nil
}

func printProgress(downloadLen int, contentLen int64) {
fmt.Printf("\r")
fmt.Printf("Downloading... %d of %d", downloadLen, contentLen)
}

使用PM2运行springboot项目

新建文件:pm2.json

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"name": "test",
"script": "java",
"args": [
"-jar",
"/home/test/test.jar",
"--spring.profiles.active=prod"
],
"exec_interpreter": "",
"exec_mode": "fork",
"error_file" : "/data/logs/error.log",
"out_file" : "/data/logs/out.log"
}

然后执行命令:pm2 start pm2.json启动服务。

解决nvm导致terminal打开慢的问题

电脑上是使用nvm安装的node,安装之后每次打开一个新的terminal都比较慢,运营是因为termainl在打开的时候会加载nvm相关内容,如下:

1
2
3
4
# nvm
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion

可以按照下面方式来修改,只有在需要用到nvm的时候才去加载:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# nvm
export NVM_DIR="$HOME/.nvm"
#[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
#[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
function _install_nvm() {
unset -f nvm
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This sets up nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # load nvm bash_completion
nvm "$@"
}

function nvm() {
_install_nvm "$@"
}

同时安装多个版本JDK,快速切换JDK版本

推荐一个工具:https://github.com/jenv/jenv

1. Getting Started

Follow the steps below to get a working jenv installation with knowledge of your java environment. Read all the code you execute carefully: a $ symbol at the beginning of a line should be omitted, since it’s meant to show you entering a command into your terminal and observing the response after the command.

1.1 Installing jenv

On OSX, the simpler way to install jEnv is using Homebrew

position-relative
1
brew install jenv

Alternatively, and on Linux, you can install it from source :

position-relative
1
2
3
4
5
6
7
git clone https://github.com/jenv/jenv.git ~/.jenv
# Shell: bash
echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(jenv init -)"' >> ~/.bash_profile
# Shell: zsh
echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(jenv init -)"' >> ~/.zshrc

Restart your shell by closing and reopening your terminal window or running exec $SHELL -l in the current session for the changes to take effect.

To verify jenv was installed, run jenv doctor. On a macOS machine, you’ll observe the following output:

position-relative
1
2
3
4
5
6
$ jenv doctor
[OK] No JAVA_HOME set
[ERROR] Java binary in path is not in the jenv shims.
[ERROR] Please check your path, or try using /path/to/java/home is not a valid path to java installation.
PATH : /Users/user/.jenv/libexec:/Users/user/.jenv/shims:/Users/user/.jenv/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
[OK] Jenv is correctly loaded

Observe that jenv is correctly loaded but Java is not yet installed.

To make sure JAVA_HOME is set, make sure to enable the export plugin:

position-relative
1
2
jenv enable-plugin export
exec $SHELL -l

Problem? Please visit the Trouble Shooting Wiki page.

Continue to the next section to install java.

Untested: While this fork has improved fish shell support, it has not been tested by this maintainer. To install jenv for Fish according to the contributor’s instructions:

position-relative
1
2
3
4
echo 'set PATH $HOME/.jenv/bin $PATH' >> ~/.config/fish/config.fish
echo 'status --is-interactive; and source (jenv init -|psub)' >> ~/.config/fish/config.fish
cp ~/.jenv/fish/jenv.fish ~/.config/fish/functions/jenv.fish
cp ~/.jenv/fish/export.fish ~/.config/fish/functions/export.fish

1.2 Adding Your Java Environment

Use jenv add to inform jenv where your Java environment is located. jenv does not, by itself, install Java.

For example, on macOS, use brew to install the latest Java (OpenJDK 11) followed by the appropriate jenv add PATH_TO_JVM_HOME command to recognize it.

position-relative
1
2
brew install --cask java
jenv add $(/usr/libexec/java_home)

With macOS OpenJDK 11.0.2 installed, for example, either of these commands will add /Library/Java/JavaVirtualMachines/openjdk-11.0.2.jdk/Contents/Home as a valid JVM. Your JVM directory may vary!

Observe now that this version of Java is added to your java versions command:

position-relative
1
2
3
4
5
$ jenv versions
* system (set by /Users/user/.jenv/version)
11.0
11.0.2
openjdk64-11.0.2

By default, the latest version of Java is your system Java on macOS.

We’ll now set a jenv local VERSION local Java version for the current working directory. This will create a .java-version file we can check into Git for our projects, and jenv will load it correctly when a shell is started from this directory.

position-relative
1
2
3
4
$ jenv local 11.0.2
$ exec $SHELL -l
$ cat .java-version
11.0.2

Is JAVA_HOME set?

position-relative
1
2
$ echo ${JAVA_HOME}
/Users/bberman/.jenv/versions/11.0.2

Yes! Observe that JAVA_HOME is set to a valid shim directory. Unlike the main repository’s documentation we helpfully installed the export plugin, and we now have the most important jenv features covered.

If you executed this commands inside your $HOME directory, you can now delete .java-version:

position-relative
1
rm .java-version

1.3 Setting a Global Java Version

Use jenv global VERSION to set a global Java version:

position-relative
1
jenv global 11.0.2

When you next open a shell or terminal window, this version of Java will be the default.

On macOS, this sets JAVA_HOME for GUI applications on macOS using jenv macos-javahome. Integrates this tutorial to create a file that does not update dynamically depending on what local or shell version of Java is set, only global.

1.4 Setting a Shell Java Version

Use jenv shell VERSION to set the Java used in this particular shell session:

position-relative
1
jenv shell 11.0.2

2 Common Workflows

These common workflows demonstrate how to use jenv to solve common problems.

2.1 Using Two JVMs on macOS

Our goal is to have both the latest version of Java and JDK 8 installed at the same time. This is helpful for developing Android applications, whose build tools are sensitive to using an exact Java version.

We’ll resume where we left off with Java 11.0.2 installed. Let’s install Java 8 now:

position-relative
1
2
brew install --cask adoptopenjdk8
brew install --cask caskroom/versions/adoptopenjdk8

This will install the latest version of Java 8 to a special directory in macOS. Let’s see which directory that is:

position-relative
1
2
3
$ ls -1 /Library/Java/JavaVirtualMachines 
adoptopenjdk-8.jdk
openjdk-11.0.2.jdk

Observe the adoptopenjdk-8.jdk directory. Your exact version may vary. We cannot retrieve this using /usr/libexec/java_home, unfortunately. We’ll add the Java home directory using jenv so that it shows up in our jenv versions command:

position-relative
1
2
3
4
5
6
7
8
9
10
11
12
13
$ jenv add /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/
openjdk64-1.8.0.222 added
1.8.0.222 added
1.8 added
$ jenv versions
* system
1.8
1.8.0.222
openjdk64-1.8.0.222
11.0
11.0.2
openjdk64-11.0.2
oracle64-1.8.0.202-ea

批量拉取代码

场景:目录中有多个git项目,想要更新批量拉取一下这些项目的最新代码。

实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/sh
for dir in $(ls -d */); do
cd $dir
if [ -d ".git" ]; then
branch=$(git symbolic-ref --short -q HEAD)
if [ "$branch" != "master" ]; then
echo "skip $dir branch: $branch"
else
echo "dir:$dir branch: $branch"
git pull origin $branch
fi
fi
cd ..
done

扫码目录下的所有项目,如果发现当前项目在master分支,那么pull一下代码。

MacOS安装PHP

偶然的机会需要用一下PHP,记录下安装方式。本身mac系统是自带php的,但是自带的修改起来及其不方便,不好安装扩展。所以直接使用brew安装。

brew安装php

1
2
3
4
brew search php  使用此命令搜索可用的PHP版本
brew install php@7.3.21 使用此命令安装指定版本的php
brew install brew-php-switcher 安装php多版本切换工具
brew-php-switcher 7.3.21 切换PHP版本到7.3.21(需要brew安装多个版本)

安装PHP扩展

1
2
3
4
5
pecl version 查看版本信息
pecl help 可以查看命令帮助
pecl search redis 搜索可以安装的扩展信息
pecl install redis 安装扩展
pecl install http://pecl.php.net/get/redis-4.2.0.tgz 安装指定版本扩展

群辉QNAP使用备忘

记录家里的群辉NAS使用备忘,防止忘记了。

IP

192.168.1.13

文件目录

实际文件目录在:/share/…

备忘

很多图片传重复了,抽空写个脚本判断下是否是重复文件,如果是重复的只保留一份就够了,节省磁盘空间,就判断文件的md5即可。