diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7c740bb..9e5831f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,7 @@ on: - '.github/**' - '.gitignore' - 'makefile' - - 'config.yaml.example' + - 'config.example.yaml' - 'script/**' - '.vscode/**' pull_request: @@ -20,7 +20,7 @@ on: - '.github/**' - '.gitignore' - 'makefile' - - 'config.yaml.example' + - 'config.example.yaml' - 'script/**' - '.vscode/**' workflow_dispatch: diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index d371e7c..c0ac3a5 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -8,7 +8,7 @@ on: - '.github/**' - '.gitignore' - 'makefile' - - 'config.yaml.example' + - 'config.example.yaml' - 'script/**' - '.vscode/**' workflow_call: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 824f329..ce8a58f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -86,7 +86,7 @@ jobs: ${{ needs.setup.outputs.REPO_NAME }}-${{ needs.setup.outputs.TAG_NAME }}-sha256sum.txt docker-compose.yml Dockerfile - config.yaml.example + config.example.yaml draft: true generate_release_notes: true env: diff --git a/.gitignore b/.gitignore index 4466569..fdda5b8 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,6 @@ db/ logs/ logs/*.log -config.env .env .venv env/ @@ -17,8 +16,8 @@ __debug** node_modules/ robots.txt -/*.yaml - +*.yaml +!*.example.yaml build/ dist/ diff --git a/Dockerfile b/Dockerfile index ac9bec4..3055d34 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,7 +35,7 @@ COPY --from=builder /app/gogin . COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ -COPY ./config.yaml.example /app/config.yaml +COPY ./config.example.yaml /app/config.yaml EXPOSE 8080 diff --git a/README.md b/README.md index f69a272..c3f48c2 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,10 @@ If you want to develop with this project, you can follow the steps below. git clone git@github.com:funnyzak/go-gin.git && cd go-gin ``` -2. Copy the `config.yaml.example` file to `config.yaml` and update the values. +2. Copy the `config.example.yaml` file to `config.yaml` and update the values. ```bash - cp config.yaml.example config.yaml + cp config.example.yaml config.yaml ``` 3. Run the application. @@ -48,7 +48,7 @@ You can fork this repository and add Secrets Keys: `DOCKER_USERNAME` and `DOCKER ├── cmd │ ├── main.go // The main entry point for the application │ └── srv // Server controller -├── config.yaml.example // An example configuration file for the project +├── config.example.yaml // An example configuration file for the project ├── docker-compose.yml // Defines services, networks and volumes for docker-compose ├── internal │ ├── gconfig // Internal package for configuration @@ -77,7 +77,7 @@ You can fork this repository and add Secrets Keys: `DOCKER_USERNAME` and `DOCKER ## Configuration -The configuration file is in the `config.yaml` file, you can copy the `config.yaml.example` file to `config.yaml` and update the values, the configuration file is as follows: +The configuration file is in the `config.yaml` file, you can copy the `config.example.yaml` file to `config.yaml` and update the values, the configuration file is as follows: ```yaml server: diff --git a/config.yaml.example b/config.example.yaml similarity index 100% rename from config.yaml.example rename to config.example.yaml diff --git a/go.mod b/go.mod index 3118dab..275ba81 100644 --- a/go.mod +++ b/go.mod @@ -6,27 +6,34 @@ require ( code.cloudfoundry.org/bytefmt v0.0.0-20231017140541-3b893ed0421b github.com/gin-contrib/pprof v1.4.0 github.com/gin-gonic/gin v1.9.1 + github.com/glebarez/sqlite v1.10.0 github.com/golang-jwt/jwt/v5 v5.2.0 + github.com/ory/graceful v0.1.3 + github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/robfig/cron/v3 v3.0.0 github.com/rs/zerolog v1.32.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.18.2 github.com/twinj/uuid v1.0.0 + golang.org/x/crypto v0.16.0 golang.org/x/time v0.5.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 - gorm.io/driver/sqlite v1.5.5 gorm.io/gorm v1.25.7 ) require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect + github.com/glebarez/go-sqlite v1.21.2 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/goccy/go-json v0.10.2 // indirect + github.com/google/uuid v1.4.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect @@ -36,16 +43,13 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect - github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/myesui/uuid v1.0.0 // indirect - github.com/ory/graceful v0.1.3 // indirect - github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/robfig/cron/v3 v3.0.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect @@ -57,7 +61,6 @@ require ( go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.16.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect golang.org/x/net v0.19.0 // indirect golang.org/x/sys v0.15.0 // indirect @@ -66,4 +69,8 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/stretchr/testify.v1 v1.2.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + modernc.org/libc v1.22.5 // indirect + modernc.org/mathutil v1.5.0 // indirect + modernc.org/memory v1.5.0 // indirect + modernc.org/sqlite v1.23.1 // indirect ) diff --git a/go.sum b/go.sum index 0efe74b..64200db 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= @@ -25,6 +27,10 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo= +github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= +github.com/glebarez/sqlite v1.10.0 h1:u4gt8y7OND/cCei/NMHmfbLxF6xP2wgKcT/BJf2pYkc= +github.com/glebarez/sqlite v1.10.0/go.mod h1:IJ+lfSOmiekhQsFTJRx/lHtGYmCdtAiTaf5wI9u5uHA= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= @@ -52,8 +58,10 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -85,8 +93,6 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= -github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -113,6 +119,9 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E= github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= @@ -216,8 +225,14 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/sqlite v1.5.5 h1:7MDMtUZhV065SilG62E0MquljeArQZNfJnjd9i9gx3E= -gorm.io/driver/sqlite v1.5.5/go.mod h1:6NgQ7sQWAIFsPrJJl1lSNSu2TABh0ZZ/zm5fosATavE= gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A= gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= +modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= +modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM= +modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/script/go-gin.plist b/script/go-gin.plist new file mode 100644 index 0000000..012dceb --- /dev/null +++ b/script/go-gin.plist @@ -0,0 +1,21 @@ + + + + + Label + go-gin + ProgramArguments + + /opt/go-gin/go-gin + -c + /opt/go-gin/config.yaml + + KeepAlive + + RunAtLoad + + WorkingDirectory + /opt/go-gin + + diff --git a/script/go-gin.service b/script/go-gin.service new file mode 100644 index 0000000..88199b6 --- /dev/null +++ b/script/go-gin.service @@ -0,0 +1,15 @@ +[Unit] +Description=go-gin service +After=syslog.target + +[Service] +Type=simple +User=nobody +Group=nogroup +Restart=on-failure +RestartSec=30s +WorkingDirectory=/opt/go-gin +ExecStart=/opt/go-gin/go-gin -c go-gin + +[Install] +WantedBy=multi-user.target diff --git a/script/install.ps1 b/script/install.ps1 new file mode 100644 index 0000000..a183f88 --- /dev/null +++ b/script/install.ps1 @@ -0,0 +1,90 @@ +$taskName = "go-gin" +$programPath = Join-Path $PSScriptRoot "go-gin.exe" +$workingDir = $PSScriptRoot + +# check if Administrator +$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") +if (-not $isAdmin) { + Write-Host "Please run this script as Administrator." + exit +} + +if ($args[0] -eq "enable") { + # first check if the task exists + $task = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue + if ($task -ne $null) { + Write-Host "Task $taskName already exists." + $status = Get-ScheduledTask -TaskName $taskName | Select-Object State + if ($status.State -eq "Running") { + Write-Host "Task $taskName is already running." + } else { + Start-ScheduledTask -TaskName $taskName + Write-Host "Task $taskName started." + } + } else { + Write-Host "Creating task $taskName..." + $action = New-ScheduledTaskAction -Execute $programPath -WorkingDirectory $workingDir + $trigger = New-ScheduledTaskTrigger -AtStartup + $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -DontStopOnIdleEnd + $principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount + Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Settings $settings -Principal $principal + Start-ScheduledTask -TaskName $taskName + Write-Host "Task $taskName created." + } +} elseif ($args[0] -eq "disable") { + # first check if the task exists + $task = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue + if ($task -eq $null) { + Write-Host "Task $taskName does not exist." + } else { + Write-Host "Deleting task $taskName..." + Stop-ScheduledTask -TaskName $taskName + Unregister-ScheduledTask -TaskName $taskName -Confirm:$false + Write-Host "Task $taskName deleted." + } +} elseif ($args[0] -eq "start") { + # first check if the task exists + $task = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue + if ($task -eq $null) { + Write-Host "Task $taskName does not exist. Please enable it first." + } else { + Write-Host "Starting task $taskName..." + Start-ScheduledTask -TaskName $taskName + Write-Host "Task $taskName started." + } +} elseif ($args[0] -eq "stop") { + # first check if the task exists + $task = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue + if ($task -eq $null) { + Write-Host "Task $taskName does not exist. Please enable it first." + } else { + Write-Host "Stopping task $taskName..." + Stop-ScheduledTask -TaskName $taskName + Write-Host "Task $taskName stopped." + } +} elseif ($args[0] -eq "restart") { + # first check if the task exists + $task = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue + if ($task -eq $null) { + Write-Host "Task $taskName does not exist. Please enable it first." + } else { + Write-Host "Restarting task $taskName..." + Restart-ScheduledTask -TaskName $taskName + Write-Host "Task $taskName restarted." + } +} elseif ($args[0] -eq "status") { + # first check if the task exists + $task = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue + if ($task -eq $null) { + Write-Host "Task $taskName does not exist. Please enable it first." + } else { + $status = Get-ScheduledTask -TaskName $taskName | Select-Object State + if ($status.State -eq "Running") { + Write-Host "Task $taskName is running." + } else { + Write-Host "Task $taskName is not running." + } + } +} else { + Write-Host "Please specify 'enable' or 'disable'." +} diff --git a/script/install.sh b/script/install.sh new file mode 100644 index 0000000..1496ec9 --- /dev/null +++ b/script/install.sh @@ -0,0 +1,485 @@ +#!/bin/bash + +#======================================================== +# System Required: Debian 8+ / Ubuntu 16.04+ / Centos 7+ / +# Description: GO-GIN Management script +# Github: https://github.com/funnyzak/go-gin +#======================================================== + +red='\033[0;31m' +green='\033[0;32m' +yellow='\033[0;33m' +plain='\033[0m' +export PATH=$PATH:/usr/local/bin + +SCRIPT_VERSION="0.0.1" # script version +SCRIPT_NAME="GO-GIN Management Script" # script name +GG_DESCRIPTION="Go-Gin is a web service based on Golang and Gin framework." # service description + +GG_NAME="go-gin" # service name +GG_REPO_NAME="funnyzak/${GG_NAME}" # service repo name +GG_REPO_BRANCH="installsrcipt" # service repo branch + +GG_SERVICE_NAME="${GG_NAME}" # service system name +GG_WORK_PATH="/opt/${GG_SERVICE_NAME}" # service workdir path +GG_SERVICE_PATH="${GG_WORK_PATH}/${GG_SERVICE_NAME}" # service app path +GG_CONFIG_PATH="${GG_WORK_PATH}/${GG_SERVICE_NAME}.yaml" # service config path +GG_SYSTEMD_PATH="/etc/systemd/system/${GG_SERVICE_NAME}.service" # service path in systemd +GG_RELEASES_DATA_URL="https://api.github.com/repos/${GG_REPO_NAME}/releases" # service releases data url for get latest version + +GG_LATEST_VERSION="" # service latest version +GG_LATEST_VERSION_ZIP_NAME="" # service latest version zip name +GG_LATEST_VERSION_DOWNLOAD_URL="" # service latest version download url + +GG_RAW_URL="https://raw.githubusercontent.com/${GG_REPO_NAME}/${GG_REPO_BRANCH}" # service attachment prefix url +GG_CONFIG_SAMPLE_URL="${GG_RAW_URL}/config.example.yaml" # service sample config download url + +os_arch="" # system arch + +[ -e /etc/os-release ] && cat /etc/os-release | grep -i "PRETTY_NAME" | grep -qi "alpine" && os_alpine='1' + +start_check() { + [ "$os_alpine" != 1 ] && ! command -v systemctl >/dev/null 2>&1 && echo "This system is not supported: systemctl not found" && exit 1 + + # check root + [[ $EUID -ne 0 ]] && echo -e "${red}ERROR: ${plain} This script must be run with the root user!\n" && exit 1 + + # check arch, only support amd64, arm64, arm + if [[ $(uname -m | grep 'x86_64') != "" ]]; then + os_arch="amd64" + elif [[ $(uname -m | grep 'aarch64\|armv8b\|armv8l') != "" ]]; then + os_arch="arm64" + elif [[ $(uname -m | grep 'arm') != "" ]]; then + os_arch="arm" + fi + + if [[ -z ${os_arch} ]]; then + echo -e "${red}ERROR: ${plain} This system is not supported: ${os_arch}\n" && exit 1 + fi + + ping_check + + GG_LATEST_VERSION=$(get_service_version) + if [ -z "${GG_LATEST_VERSION}" ]; then + echo -e "${red}ERROR${plain}: Get ${GG_SERVICE_NAME} latest version failed." + exit 1 + fi + + GG_LATEST_VERSION_ZIP_NAME="${GG_SERVICE_NAME}-linux-${os_arch}-${GG_LATEST_VERSION}.zip" + GG_LATEST_VERSION_DOWNLOAD_URL="https://github.com/${GG_REPO_NAME}/releases/download/${GG_LATEST_VERSION}/${GG_LATEST_VERSION_ZIP_NAME}" + +} + +ping_check() { + ping -c 1 github.com > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo -e "${red}ERROR${plain}: ping github.com failed. Please check your network." + exit 1 + fi +} + +confirm() { + if [[ $# > 1 ]]; then + echo && read -e -p "$1 [y/n]: " temp + if [[ x"${temp}" == x"" ]]; then + temp=$2 + fi + else + read -e -p "$1 [y/n]: " temp + fi + if [[ x"${temp}" == x"y" || x"${temp}" == x"Y" ]]; then + return 0 + else + return 1 + fi +} + +execute_funcs() { + for one_func in "$@"; do + echo -e "Execute function: ${green}${one_func}${plain}" + if [[ $one_func == *' '* ]]; then + eval $one_func + else + $one_func + fi + if [ $? -ne 0 ]; then + echo -e "${red}ERROR${plain}: execute function list ${@} failed, failed function is ${yellow}${one_func}${plain}." + return 1 + fi + done +} + +install_service() { + echo -e "Install ${green}${GG_SERVICE_NAME}${plain} service..." + if service_exists; then + echo -e "${red}ERROR${plain}: ${GG_SERVICE_NAME} service is already installed." + return 1 + fi + + execute_funcs "download_service_app" "download_service_template" "download_service_config" "enable_service 0" "start_service 0" + if [ $? -ne 0 ]; then + echo -e "${red}ERROR${plain}: ${GG_SERVICE_NAME} service install failed." + return 1 + fi + + echo -e "${green}${GG_SERVICE_NAME}${plain} service for ${os_arch} install success. the latest version is ${GG_LATEST_VERSION}. Enjoy it!" + + if [[ $# == 0 ]]; then + before_show_menu + fi +} + +get_service_log_path() { + local log_path="" + local log_paths=$(grep -i "path" ${GG_CONFIG_PATH} | awk '{print $2}') + if [ -n "${log_paths}" ]; then + for i in ${log_paths}; do + if [[ $i == *log* ]]; then + log_path=$i + fi + done + else + echo "" + fi + if [ -n "${log_path}" ]; then + if [[ ${log_path} != /* ]]; then + log_path=$(dirname ${GG_SERVICE_PATH})/${log_path} + echo ${log_path} + fi + else + echo "" + fi + +} + +service_exists() { + if systemctl --all --type=service | grep -Fq "${GG_SERVICE_NAME}.service"; then + return 0 + else + return 1 + fi +} + +service_active() { + if systemctl is-active --quiet ${GG_SERVICE_NAME}; then + return 0 + else + return 1 + fi +} + +service_action() { + local action=$1 + shift + + echo -e "${action} ${green}${GG_SERVICE_NAME}${plain} service..." + + systemctl ${action} ${GG_SERVICE_NAME} + + if [[ $? -ne 0 ]]; then + echo -e "${red}ERROR${plain}: ${GG_SERVICE_NAME} ${action} failed." + return 1 + fi + + echo -e "${green}${GG_SERVICE_NAME}${plain} service ${action} success." + + if [[ $# == 0 ]]; then + before_show_menu + fi +} + +create_service_workdir() { + if [ ! -d "${GG_WORK_PATH}" ]; then + mkdir -p ${GG_WORK_PATH} + fi +} + +enable_service() { + echo -e "Enable ${green}${GG_SERVICE_NAME}${plain} service..." + systemctl enable ${GG_SERVICE_NAME} + if [ $? -ne 0 ]; then + echo -e "${red}ERROR${plain}: Enable ${GG_SERVICE_NAME} service failed." + return 1 + fi + echo -e "${green}${GG_SERVICE_NAME}${plain} service enable success." + if [[ $# == 0 ]]; then + before_show_menu + fi +} + +start_service() { + service_action start $1 +} + +stop_service() { + service_action stop $1 +} + +disable_service() { + service_action disable $1 +} + +restart_service() { + service_action restart $1 +} + +show_service_status() { + service_action status $1 +} + +upgrade_service() { + echo -e "Upgrade ${green}${GG_SERVICE_NAME}${plain} service..." + + if service_exists && confirm "Do you want to upgrade ${GG_SERVICE_NAME} service?"; then + execute_funcs "download_service_app" "service_action restart" + if [ $? -ne 0 ]; then + echo -e "${red}ERROR${plain}: ${GG_SERVICE_NAME} service upgrade failed." + return 1 + fi + echo -e "${green}${GG_SERVICE_NAME}${plain} service for ${os_arch} upgrade success. the latest version is ${GG_LATEST_VERSION}. Enjoy it!" + else + echo -e "${red}ERROR${plain}: ${GG_SERVICE_NAME} service not installed or upgrade failed." + return 1 + fi + + if [[ $# == 0 ]]; then + before_show_menu + fi +} + +uninstall_service() { + echo -e "Uninstall ${green}${GG_SERVICE_NAME}${plain} service..." + + if service_exists; then + execute_funcs "stop_service 0" "disable_service 0" + systemctl daemon-reload + rm -f ${GG_SYSTEMD_PATH} + rm -f ${GG_SERVICE_PATH} + rm -f ${GG_CONFIG_PATH} + rm -rf ${GG_WORK_PATH} + systemctl daemon-reload + systemctl reset-failed + echo -e "${green}${GG_SERVICE_NAME}${plain} service uninstall success. Goodbye!" + else + echo -e "${red}ERROR${plain}: ${GG_SERVICE_NAME} service uninstall failed. Please check ${GG_SERVICE_NAME} service is installed." + return 1 + fi + + if [[ $# == 0 ]]; then + before_show_menu + fi +} + +show_service_log() { + echo -e "Show ${green}${GG_SERVICE_NAME}${plain} service log..." + + if ! service_exists || [ -z "$(get_service_log_path)" ] || [ ! -f "$(get_service_log_path)" ]; then + echo -e "${red}ERROR${plain}: ${GG_SERVICE_NAME} service log not found." + return 1 + fi + + echo -e "Press ${red}Ctrl+C${plain} to exit." + watch -n 1 tail -n 20 “$(get_service_log_path)” + + if [[ $# == 0 ]]; then + before_show_menu + fi +} + +edit_service_config() { + echo -e "Edit ${green}${GG_SERVICE_NAME}${plain} service config..." + + if ! service_exists; then + echo -e "${red}ERROR${plain}: ${GG_SERVICE_NAME} service not installed. Please install it first." + return 1 + fi + + if [ ! -f "${GG_CONFIG_PATH}" ]; then + echo -e "${red}ERROR${plain}: ${GG_SERVICE_NAME} config file not found." + return 1 + fi + + if command -v vim >/dev/null 2>&1; then + vim ${GG_CONFIG_PATH} + elif command -v nano >/dev/null 2>&1; then + nano ${GG_CONFIG_PATH} + elif command -v vi >/dev/null 2>&1; then + vi ${GG_CONFIG_PATH} + else + echo -e "${red}ERROR${plain}: No editor found." + return 1 + fi + + if [[ $# == 0 ]]; then + before_show_menu + fi +} + +download_service_config() { + create_service_workdir + download_file "${GG_CONFIG_SAMPLE_URL}" "${GG_CONFIG_PATH}" + if [ $? -ne 0 ]; then + return 1 + fi +} + +download_service_template() { + create_service_workdir + download_file "${GG_RAW_URL}/script/${GG_SERVICE_NAME}.service" "${GG_SYSTEMD_PATH}" + if [ $? -ne 0 ]; then + return 1 + fi +} + +download_service_app() { + create_service_workdir + download_file "${GG_LATEST_VERSION_DOWNLOAD_URL}" "/tmp/${GG_LATEST_VERSION_ZIP_NAME}" + if [ $? -ne 0 ]; then + return 1 + fi + if [ -f "${GG_SERVICE_PATH}" ]; then + rm -f ${GG_SERVICE_PATH} + fi + echo -e "Unzip ${GG_LATEST_VERSION_ZIP_NAME} to ${GG_WORK_PATH}..." + unzip -o /tmp/${GG_LATEST_VERSION_ZIP_NAME} -d ${GG_WORK_PATH} > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo -e "${red}ERROR${plain}: Unzip ${GG_LATEST_VERSION_ZIP_NAME} failed." + return 1 + fi + chmod +x ${GG_SERVICE_PATH} +} + +get_service_version() { + local latest_version=$(curl -s ${GG_RELEASES_DATA_URL} | grep "tag_name" | head -n 1 | awk -F '"' '{print $4}') + if [ -n "${latest_version}" ]; then + echo "${latest_version}" + else + echo "" + fi +} + +download_file() { + local url=$1 + local file=$2 + echo -e "Download ${url} to ${file}..." + wget -t 3 -T 15 -O ${file} ${url} > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo -e "${red}ERROR${plain}: Download ${url} failed." + return 1 + fi +} + +show_usage() { + echo -e "\nUsage: ${green}go-gin${plain} [option]" + echo "Options:" + echo -e " ${green}install${plain} Install service" + echo -e " ${green}start${plain} Start service" + echo -e " ${green}stop${plain} Stop service" + echo -e " ${green}restart${plain} Restart service" + echo -e " ${green}upgrade${plain} Upgrade service" + echo -e " ${green}uninstall${plain} Uninstall service" + echo -e " ${green}status${plain} Show service status" + echo -o " ${green}log${plain} Show service log" + echo -e " ${green}edit${plain} Edit service config" +} + +show_menu() { + echo -e "> + ${green}${SCRIPT_NAME} ${plain}${red}v${SCRIPT_VERSION}${plain} + Latest release version: ${green}${GG_LATEST_VERSION}${plain} + ———————————————— + ${green}1.${plain} Install service + ${green}2.${plain} Start service + ${green}3.${plain} Stop service + ${green}4.${plain} Restart service + ${green}5.${plain} Upgrade service + ${green}6.${plain} Uninstall service + ${green}7.${plain} Show service status + ${green}8.${plain} Show service log + ${green}9.${plain} Edit service config + ———————————————— + ${green}0.${plain} Exit + " + echo && read -ep "Please enter a number [0-9]: " num + + case "${num}" in + 0) + exit 0 + ;; + 1) + install_service + ;; + 2) + start_service + ;; + 3) + stop_service + ;; + 4) + restart_service + ;; + 5) + upgrade_service + ;; + 6) + uninstall_service + ;; + 7) + show_service_status + ;; + 8) + show_service_log + ;; + 9) + edit_service_config + ;; + *) + echo -e "${red}Please enter the correct number [0-9]${plain}" + ;; + esac +} + +before_show_menu() { + echo && echo -n -e "${yellow}* Press Enter to return to the main menu. *${plain}" && read temp + show_menu +} + +start_check + +if [ $# -gt 0 ] && [ -n "$1" ]; then + case $1 in + "install") + install_service 0 + ;; + "start") + start_service 0 + ;; + "stop") + stop_service 0 + ;; + "restart") + restart_service 0 + ;; + "upgrade") + upgrade_service 0 + ;; + "uninstall") + uninstall_service 0 + ;; + "status") + show_service_status 0 + ;; + "log") + show_service_log 0 + ;; + "edit") + edit_service_config 0 + ;; + *) + $@ || show_usage 0 + ;; + esac +else + show_menu +fi + diff --git a/service/singleton/singleton.go b/service/singleton/singleton.go index e9a1754..e126d3b 100644 --- a/service/singleton/singleton.go +++ b/service/singleton/singleton.go @@ -5,10 +5,10 @@ import ( "os" "time" + "github.com/glebarez/sqlite" "github.com/patrickmn/go-cache" "github.com/rs/zerolog" "github.com/spf13/viper" - "gorm.io/driver/sqlite" "gorm.io/gorm" "go-gin/internal/gconfig"