起因
最近还是有一些小伙伴反馈加载速度有点慢,那行吧,部署一个距离中国近一点的节点,且关闭 cf 保护来提速好了。
那么涉及到一个问题就是怎么部署比较方便,考虑了 rsync 等等后来还是决定写一个小工具来当作 webhook 部署。
部署流程
流程很简单就不画图了:
- github 完成构建
- 打包
- 使用 webhook 上传到服务器
- 服务器上解压缩,并部署到指定目录
部署工具
先讲部署工具,因为要跑到服务器上用,我希望打包完小一点,同时可以理解执行,考虑了一下用 go 是个不错的选择,估计 100 行内就可以解决。
package main
import (
"archive/zip"
"flag" "fmt" "github.com/google/uuid" "io" "net/http" "os" "path/filepath" "strings")
var (
uploadPath string
extractPath string
password string
uploadUrl string
port string
maxSize int64 = 30 // 30 MB
)
func main() {
flag.StringVar(&uploadPath, "uploadPath", "./uploads", "Directory to save uploaded files")
flag.StringVar(&extractPath, "extractPath", "./extracted", "Directory to extract files")
flag.StringVar(&password, "password", "123456", "Password to upload")
flag.StringVar(&uploadUrl, "uploadUrl", "/upload-url", "URL to upload file")
flag.StringVar(&port, "port", "1234", "Port to listen")
flag.Parse()
http.HandleFunc(uploadUrl, uploadHandler)
fmt.Println("Server started at :" + port + " and listening...")
err := http.ListenAndServe(":"+port, nil)
if err != nil {
return
}
}
func uploadHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
return
}
// 解析表单数据
// 验证密码
if r.FormValue("password") != password {
http.Error(w, "Invalid password", http.StatusUnauthorized)
return
}
err := r.ParseMultipartForm(maxSize << 20) // 30 MB
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// 获取上传文件
file, _, err := r.FormFile("file")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer file.Close()
// 创建上传目录
err = os.MkdirAll(uploadPath, os.ModePerm)
// 文件名需要保证唯一性
id := uuid.New().String()
tempFilePath := filepath.Join(uploadPath, id+".zip")
tempFile, err := os.Create(tempFilePath)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer tempFile.Close()
// 保存上传文件到临时文件
_, err = io.Copy(tempFile, file)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// 解压文件
err = unzip(tempFilePath, extractPath)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Write([]byte("File uploaded and extracted successfully"))
// 完成后删除上传文件
err = os.Remove(tempFilePath)
if err != nil {
return
}
}
func unzip(src, dest string) error {
r, err := zip.OpenReader(src)
if err != nil {
return err
}
defer r.Close()
for _, f := range r.File {
fpath := filepath.Join(dest, f.Name)
if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) {
return fmt.Errorf("illegal file path: %s", fpath)
}
if f.FileInfo().IsDir() {
os.MkdirAll(fpath, os.ModePerm)
continue
}
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
return err
}
outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
rc, err := f.Open()
if err != nil {
return err
}
_, err = io.Copy(outFile, rc)
outFile.Close()
rc.Close()
if err != nil {
return err
}
} return nil
}
在构建一下
GOOS=linux GOARCH=amd64 go build node-static-server-linux-amd64 ./cmd/server.go
随后拷贝到服务器用 screen 运行即可
node-static-server-linux-amd64 -port=123 -password=123 -uploadUrl=123456
本文标题:静态部署工具
永久链接:https://iceprosurface.com/2024/static-deploy-tool/
作者授权:本文由 icepro 原创编译并授权刊载发布。
版权声明:本文使用「署名-非商业性使用-相同方式共享 4.0 国际」创作共享协议,转载或使用请遵守署名协议。