Skip to content

feat: 将静态内容调整为embed嵌入,减少外部依赖文件 #325

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
tmp
logs
public/static/dist
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: build
name: build and push binary to release

on:
release:
Expand All @@ -16,11 +16,13 @@ jobs:
goos: windows
steps:
- uses: actions/checkout@v3
- run: |
release_url=$(curl -s https://api.github.com/repos/eryajf/go-ldap-admin-ui/releases/latest | grep "browser_download_url" | grep -v 'dist.zip.md5' | cut -d '"' -f 4); wget $release_url && unzip dist.zip && rm dist.zip && mv dist public/static
- uses: wangyoucao577/go-release-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }} # 一个默认的变量,用来实现往 Release 中添加文件
goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }}
goversion: 1.18 # 可以指定编译使用的 Golang 版本
binary_name: "go-ldap-admin" # 可以指定二进制文件的名称
extra_files: LICENSE config.yml go-ldap-admin-priv.pem go-ldap-admin-pub.pem rbac_model.conf README.md # 需要包含的额外文件
extra_files: LICENSE config.yml README.md # 需要包含的额外文件
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,20 @@ jobs:
with:
go-version: 1.18
- uses: actions/checkout@v3
- run: |
release_url=$(curl -s https://api.github.com/repos/eryajf/go-ldap-admin-ui/releases/latest | grep "browser_download_url" | grep -v 'dist.zip.md5' | cut -d '"' -f 4); wget $release_url && unzip dist.zip && rm dist.zip && mv dist public/static
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.47.3
version: v1.57.2
args: --timeout=5m --skip-files="public/client/feishu/feishu.go"
build:
name: go-build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: |
release_url=$(curl -s https://api.github.com/repos/eryajf/go-ldap-admin-ui/releases/latest | grep "browser_download_url" | grep -v 'dist.zip.md5' | cut -d '"' -f 4); wget $release_url && unzip dist.zip && rm dist.zip && mv dist public/static
- name: Set up Go
uses: actions/setup-go@v3
with:
Expand Down
File renamed without changes.
File renamed without changes.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ go-ldap-admin.db
# Dependency directories (remove the comment below to include it)
# vendor/
tmp
docs/docker-compose/data
docs/docker-compose/data
dist
36 changes: 13 additions & 23 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,39 +1,29 @@
FROM golang:1.18.10-alpine3.16 AS builder
FROM registry.cn-hangzhou.aliyuncs.com/ali_eryajf/golang:1.18.10-alpine3.17 AS builder

# ENV GOPROXY https://goproxy.io
WORKDIR /app

RUN mkdir /app && apk add --no-cache --virtual .build-deps \
ca-certificates \
gcc \
g++
RUN sed -i "s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g" /etc/apk/repositories \
&& apk upgrade && apk add --no-cache --virtual .build-deps \
ca-certificates gcc g++ curl

ADD . /app/
ADD . .

WORKDIR /app
RUN release_url=$(curl -s https://api.github.com/repos/eryajf/go-ldap-admin-ui/releases/latest | grep "browser_download_url" | grep -v 'dist.zip.md5' | cut -d '"' -f 4); wget $release_url && unzip dist.zip && rm dist.zip && mv dist public/static

RUN sed -i 's@localhost:389@openldap:389@g' /app/config.yml \
&& sed -i 's@host: localhost@host: mysql@g' /app/config.yml && go build -o go-ldap-admin .

### build final image
FROM alpine:3.16

# we set the timezone `Asia/Shanghai` by default, you can be modified
# by `docker build --build-arg="TZ=Other_Timezone ..."`
ARG TZ="Asia/Shanghai"
FROM registry.cn-hangzhou.aliyuncs.com/ali_eryajf/alpine:3.19

ENV TZ ${TZ}

RUN mkdir /app
LABEL maintainer [email protected]

WORKDIR /app

COPY --from=builder /app/ .


RUN apk upgrade \
&& apk add bash tzdata sqlite vim \
&& ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime \
&& echo ${TZ} > /etc/timezone
COPY --from=builder /app/wait .
COPY --from=builder /app/LICENSE .
COPY --from=builder /app/config.yml .
COPY --from=builder /app/go-ldap-admin .

RUN chmod +x wait go-ldap-admin

Expand Down
9 changes: 0 additions & 9 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ system:
port: 8888
# 是否初始化数据(没有初始数据时使用, 已发布正式版改为false)
init-data: true
# rsa公钥文件路径(config.yml相对路径, 也可以填绝对路径)
rsa-public-key: go-ldap-admin-pub.pem
# rsa私钥文件路径(config.yml相对路径, 也可以填绝对路径)
rsa-private-key: go-ldap-admin-priv.pem

logs:
# 日志等级(-1:Debug, 0:Info, 1:Warn, 2:Error, 3:DPanic, 4:Panic, 5:Fatal, -1<=level<=5, 参照zap.level源码)
Expand Down Expand Up @@ -55,11 +51,6 @@ mysql:
# 字符集(utf8mb4_general_ci速度比utf8mb4_unicode_ci快些)
collation: utf8mb4_general_ci

# casbin配置
casbin:
# 模型配置文件, config.yml相对路径
model-path: 'rbac_model.conf'

# jwt配置
jwt:
# jwt标识
Expand Down
51 changes: 19 additions & 32 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package config

import (
_ "embed"
"fmt"
"os"

Expand All @@ -15,12 +16,18 @@ import (
// 全局配置变量
var Conf = new(config)

//go:embed go-ldap-admin-priv.pem
var priv []byte

//go:embed go-ldap-admin-pub.pem
var pub []byte

type config struct {
System *SystemConfig `mapstructure:"system" json:"system"`
Logs *LogsConfig `mapstructure:"logs" json:"logs"`
Database *Database `mapstructure:"database" json:"database"`
Mysql *MysqlConfig `mapstructure:"mysql" json:"mysql"`
Casbin *CasbinConfig `mapstructure:"casbin" json:"casbin"`
System *SystemConfig `mapstructure:"system" json:"system"`
Logs *LogsConfig `mapstructure:"logs" json:"logs"`
Database *Database `mapstructure:"database" json:"database"`
Mysql *MysqlConfig `mapstructure:"mysql" json:"mysql"`
// Casbin *CasbinConfig `mapstructure:"casbin" json:"casbin"`
Jwt *JwtConfig `mapstructure:"jwt" json:"jwt"`
RateLimit *RateLimitConfig `mapstructure:"rate-limit" json:"rateLimit"`
Ldap *LdapConfig `mapstructure:"ldap" json:"ldap"`
Expand Down Expand Up @@ -50,8 +57,8 @@ func InitConfig() {
panic(fmt.Errorf("初始化配置文件失败:%s", err))
}
// 读取rsa key
Conf.System.RSAPublicBytes = RSAReadKeyFromFile(Conf.System.RSAPublicKey)
Conf.System.RSAPrivateBytes = RSAReadKeyFromFile(Conf.System.RSAPrivateKey)
Conf.System.RSAPublicBytes = pub
Conf.System.RSAPrivateBytes = priv
})

if err != nil {
Expand All @@ -62,36 +69,16 @@ func InitConfig() {
panic(fmt.Errorf("初始化配置文件失败:%s", err))
}
// 读取rsa key
Conf.System.RSAPublicBytes = RSAReadKeyFromFile(Conf.System.RSAPublicKey)
Conf.System.RSAPrivateBytes = RSAReadKeyFromFile(Conf.System.RSAPrivateKey)

}

// 从文件中读取RSA key
func RSAReadKeyFromFile(filename string) []byte {
f, err := os.Open(filename)
var b []byte
Conf.System.RSAPublicBytes = pub
Conf.System.RSAPrivateBytes = priv

if err != nil {
return b
}
defer f.Close()
fileInfo, _ := f.Stat()
b = make([]byte, fileInfo.Size())
_, err = f.Read(b)
if err != nil {
return b
}
return b
}

type SystemConfig struct {
Mode string `mapstructure:"mode" json:"mode"`
UrlPathPrefix string `mapstructure:"url-path-prefix" json:"urlPathPrefix"`
Port int `mapstructure:"port" json:"port"`
InitData bool `mapstructure:"init-data" json:"initData"`
RSAPublicKey string `mapstructure:"rsa-public-key" json:"rsaPublicKey"`
RSAPrivateKey string `mapstructure:"rsa-private-key" json:"rsaPrivateKey"`
RSAPublicBytes []byte `mapstructure:"-" json:"-"`
RSAPrivateBytes []byte `mapstructure:"-" json:"-"`
}
Expand Down Expand Up @@ -123,9 +110,9 @@ type MysqlConfig struct {
Collation string `mapstructure:"collation" json:"collation"`
}

type CasbinConfig struct {
ModelPath string `mapstructure:"model-path" json:"modelPath"`
}
// type CasbinConfig struct {
// ModelPath string `mapstructure:"model-path" json:"modelPath"`
// }

type JwtConfig struct {
Realm string `mapstructure:"realm" json:"realm"`
Expand Down
File renamed without changes.
File renamed without changes.
17 changes: 0 additions & 17 deletions docs/docker-compose/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ services:
hostname: go-ldap-admin-server
restart: always
environment:
TZ: Asia/Shanghai
WAIT_HOSTS: mysql:3306, openldap:389
ports:
- 8888:8888
Expand All @@ -86,19 +85,3 @@ services:
- openldap:go-ldap-admin-openldap # ldap容器的 service_name:container_name
networks:
- go-ldap-admin

go-ldap-admin-ui:
image: registry.cn-hangzhou.aliyuncs.com/ali_eryajf/go-ldap-admin-ui
container_name: go-ldap-admin-ui
hostname: go-ldap-admin-ui
restart: always
environment:
TZ: Asia/Shanghai
ports:
- 8090:80
depends_on:
- go-ldap-admin-server
links:
- go-ldap-admin-server:go-ldap-admin-server
networks:
- go-ldap-admin
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func main() {
// 启动定时任务
logic.InitCron()

common.Log.Info(fmt.Sprintf("Server is running at %s:%d/%s", host, port, config.Conf.System.UrlPathPrefix))
common.Log.Info(fmt.Sprintf("Server is running at http://%s:%d", host, port))

// Wait for interrupt signal to gracefully shutdown the server with
// a timeout of 5 seconds.
Expand Down
91 changes: 91 additions & 0 deletions middleware/EmbedMiddleware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package middleware

import (
"embed"
"io/fs"
"net/http"
"os"
"path"
"strings"

"github.com/gin-gonic/gin"
)

const INDEX = "index.html"

type ServeFileSystem interface {
http.FileSystem
Exists(prefix string, path string) bool
}

type localFileSystem struct {
http.FileSystem
root string
indexes bool
}

func LocalFile(root string, indexes bool) *localFileSystem {
return &localFileSystem{
FileSystem: gin.Dir(root, indexes),
root: root,
indexes: indexes,
}
}

func (l *localFileSystem) Exists(prefix string, filepath string) bool {
if p := strings.TrimPrefix(filepath, prefix); len(p) < len(filepath) {
name := path.Join(l.root, p)
stats, err := os.Stat(name)
if err != nil {
return false
}
if stats.IsDir() {
if !l.indexes {
index := path.Join(name, INDEX)
_, err := os.Stat(index)
if err != nil {
return false
}
}
}
return true
}
return false
}

func ServeRoot(urlPrefix, root string) gin.HandlerFunc {
return Serve(urlPrefix, LocalFile(root, false))
}

// Static returns a middleware handler that serves static files in the given directory.
func Serve(urlPrefix string, fs ServeFileSystem) gin.HandlerFunc {
fileserver := http.FileServer(fs)
if urlPrefix != "" {
fileserver = http.StripPrefix(urlPrefix, fileserver)
}
return func(c *gin.Context) {
if fs.Exists(urlPrefix, c.Request.URL.Path) {
fileserver.ServeHTTP(c.Writer, c.Request)
c.Abort()
}
}
}

type embedFileSystem struct {
http.FileSystem
}

func (e embedFileSystem) Exists(prefix string, path string) bool {
_, err := e.Open(path)
return err == nil
}

func EmbedFolder(fsEmbed embed.FS, targetPath string) ServeFileSystem {
fsys, err := fs.Sub(fsEmbed, targetPath)
if err != nil {
panic(err)
}
return embedFileSystem{
FileSystem: http.FS(fsys),
}
}
Loading