Skip to content

Commit

Permalink
refactor: attachment upload functionality and update configuration (#22)
Browse files Browse the repository at this point in the history
* chore:update

* refactor: add URLPrefix field to Config and AttachmentUpload structs

* Update configuration file with absolute paths and URL prefix

* Commented out cron task for debugging purposes

* refactor: create default config if not found config file

* refactor: add debug mode and network IP exclusion

* docs: update README.md with instructions for running the application
  • Loading branch information
funnyzak authored Feb 22, 2024
1 parent 3f9f624 commit c14bf1c
Show file tree
Hide file tree
Showing 12 changed files with 214 additions and 151 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ jobs:
docker-compose.yml
Dockerfile
config.example.yaml
draft: true
draft: false
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
19 changes: 16 additions & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,43 @@
"type": "go",
"request": "launch",
"mode": "auto",
"cwd": "${workspaceFolder}",
"program": "cmd/main.go"
},
{
"name": "Development",
"type": "go",
"request": "launch",
"mode": "auto",
"args": ["-c", "dev"],
"cwd": "${workspaceFolder}",
"args": [
"-c",
"dev"
],
"program": "cmd/main.go"
},
{
"name": "Production",
"type": "go",
"request": "launch",
"mode": "auto",
"args": ["-c", "prod"],
"cwd": "${workspaceFolder}",
"args": [
"-c",
"prod"
],
"program": "cmd/main.go"
},
{
"name": "Test",
"type": "go",
"request": "launch",
"mode": "auto",
"args": ["-c", "test"],
"cwd": "${workspaceFolder}",
"args": [
"-c",
"test"
],
"program": "cmd/main.go"
}
]
Expand Down
93 changes: 4 additions & 89 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,17 @@ If you want to develop with this project, you can follow the steps below.
```bash
git clone [email protected]:funnyzak/go-gin.git && cd go-gin
```

2. Copy the `config.example.yaml` file to `config.yaml` and update the values.

```bash
cp config.example.yaml config.yaml
```

3. Run the application.
2. Run the application.

```bash
go run cmd/main.go

# or
make dev

# You also specify the config file, e.g. dev, prod, etc.
go run cmd/main.go -c dev
```

**Note:** The application will load the configuration from the `config.yaml` file in the root directory by default. If you want to use a different configuration file, you can copy `config.example.yaml` to `prod.yaml` and update the values. specify it using the `-c` parameter, for example: `go run cmd/main.go -c prod`, it will load the `prod.yaml` configuration file.

### CI/CD

You can fork this repository and add Secrets Keys: `DOCKER_USERNAME` and `DOCKER_PASSWORD` in the repository settings. And when you push the code, it will automatically build binary and docker image and push to the Docker Hub.
Expand Down Expand Up @@ -79,84 +71,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.example.yaml` file to `config.yaml` and update the values, the configuration file is as follows:

```yaml
server:
port: 8080 # Server port
site:
brand: Go-Gin # Site brand
description: A simple web application using Go and Gin # Site description
base_url: http://localhost:8080 # Site base URL, used for generating absolute URLs
debug: false # Debug mode, if true, the server will print detailed error messages
log:
level: debug # debug, info, warn, error, fatal, panic
path: logs/go-gin.log # Log file path
db_path: db/go-gin.sqlite # Database path
rate_limit:
max: 100 # requests per minute, 0 means no limit
enable_cors: false # Enable CORS
enable_user_registration: true # Enable user registration
upload:
virtual_path: /upload # Virtual path, used for generating absolute URLs, must start with /
dir: upload # Upload directory, relative to the project root directory. Or you can use an absolute path, such as /var/www/upload
max_size: 10485760 # 10MB, unit: byte
keep_original_name: false # Keep original file name, if false, the server will generate a random file name
create_date_dir: true # Create date directory, such as /upload/2021/01/01
allow_types: # Allowed file types, if empty, all types are allowed
- image/jpeg
- image/jpg
- image/png
- image/gif
- image/bmp
jwt: # JWT settings
access_secret: qhkxjrRmYcVYKSEobqsvhxhtPVeTWquu # Access token secret
refresh_secret: qhkxjrRmYcVYKSEobqsvhxhtPV3TWquu # Refresh token secret
access_token_expiration: 60 # minutes
refresh_token_expiration: 720 # minutes
access_token_cookie_name: go-gin-access # Access token cookie name
refresh_token_cookie_name: go-gin-refresh # Refresh token cookie name
location: Asia/Chongqing # Timezone
notifications: # Notification settings
- type: apprise # You must install apprise first, more details: https://github.com/caronc/apprise
instances:
- url: "apprise-url-1"
- url: "apprise-url-2"
- type: dingtalk
instances:
- webhook: "dingtalk-webhook-1"
- webhook: "dingtalk-webhook-2"
- type: ifttt
instances:
- key: "ifttt-key-1"
event: "event-1"
- key: "ifttt-key-2"
event: "event-2"
- type: smtp
instances:
- host: "smtp-host-1"
port: 587
username: "user-1"
password: "password-1"
from: "from-1"
to: "to-1"
- host: "smtp-host-2"
port: 587
username: "user-2"
password: "password-2"
from: "from-2"
to: "to-2"
- type: telegram
instances:
- botToken: "telegram-bot-token-1"
chatID: "chat-id-1"
- botToken: "telegram-bot-token-2"
chatID: "chat-id-2"
- type: wecom
instances:
- key: "wecom-key-1"
- key: "wecom-key-2"
```
Service configuration via `yaml` format. The configuration file is located in the root directory of the project and is named `config.example.yaml`. You can copy this file to `config.yaml` and update the values. More details can be found in the [config.example.yaml](https://github.com/funnyzak/go-gin/blob/main/config.example.yaml) file.

## Build

Expand Down
98 changes: 55 additions & 43 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"context"
"fmt"
"net/http"

"github.com/gin-gonic/gin"
"github.com/ory/graceful"
Expand All @@ -15,89 +16,100 @@ import (
"go-gin/service/singleton"
)

type CliParam struct {
type ClIParam struct {
Version bool // Show version
ConfigName string // Config file name
Port uint // Server port
Debug bool // Debug mode
}

var (
cliParam CliParam
)
var cliParam ClIParam

func init() {
func parseCommandLineParams() (cliParam ClIParam) {
flag.CommandLine.ParseErrorsWhitelist.UnknownFlags = true
flag.BoolVarP(&cliParam.Version, "version", "v", false, "show version")
flag.StringVarP(&cliParam.ConfigName, "config", "c", "config", "config file name")
flag.UintVarP(&cliParam.Port, "port", "p", 0, "server port")
flag.BoolVarP(&cliParam.Debug, "debug", "d", false, "debug mode")
flag.Parse()
flag.Lookup("config").NoOptDefVal = "config"
singleton.InitConfig(cliParam.ConfigName)
singleton.InitLog(singleton.Conf)
singleton.InitTimezoneAndCache()
singleton.InitDBFromPath(singleton.Conf.DBPath)
initService()
return cliParam
}

func main() {
if cliParam.Version {
fmt.Println(singleton.Version)
return
}
func loadConfig() {
cliParam = parseCommandLineParams()

port := singleton.Conf.Server.Port
if cliParam.Port != 0 {
port = cliParam.Port
singleton.InitConfig(cliParam.ConfigName)
if cliParam.Port > 0 && cliParam.Port < 65536 {
singleton.Conf.Server.Port = cliParam.Port
}
if cliParam.Debug {
singleton.Conf.Debug = cliParam.Debug
}
}

srv := controller.ServerWeb(port)

startOutput := func() {
func startupOutput(httpserver *http.Server) {
if singleton.Conf.Debug {
fmt.Println()
fmt.Printf("Service version: %s\n", utils.Colorize(utils.ColorGreen, singleton.Version))

fmt.Println()
fmt.Println("Server available routes:")
mygin.PrintRoute(srv.Handler.(*gin.Engine))
mygin.PrintRoute(httpserver.Handler.(*gin.Engine))

fmt.Println()
fmt.Println("Server is running with config:")
fmt.Println("Server running with config:")
utils.PrintStructFieldsAndValues(singleton.Conf, "")
}

fmt.Println()
ipv4s, err := ip.GetIPv4NetworkIPs()
if ipv4s != nil && err == nil {
fmt.Println("Server is running at:")
for _, ip := range ipv4s {
fmt.Printf(" - %-7s: %s\n", "Network", utils.Colorize(utils.ColorGreen, fmt.Sprintf("http://%s:%d", ip, port)))
}
fmt.Println()
fmt.Println("Server is running at:")
fmt.Printf(" - %-7s: %s\n", "Local", utils.Colorize(utils.ColorGreen, fmt.Sprintf("http://127.0.0.1:%d", singleton.Conf.Server.Port)))
ipv4s, err := ip.GetIPv4NetworkIPs()
if ipv4s != nil && err == nil {
for _, ip := range ipv4s {
fmt.Printf(" - %-7s: %s\n", "Network", utils.Colorize(utils.ColorGreen, fmt.Sprintf("http://%s:%d", ip, singleton.Conf.Server.Port)))
}
fmt.Println()
}
fmt.Println()
}

fmt.Printf("Current service version: %s\n", utils.Colorize(utils.ColorGreen, singleton.Version))
fmt.Println()
func init() {
loadConfig()
singleton.InitLog(singleton.Conf)
singleton.InitTimezoneAndCache()
singleton.InitDBFromPath(singleton.Conf.DBPath)
initService()
}

func main() {
if cliParam.Version {
fmt.Println(singleton.Version)
return
}

srv := controller.ServerWeb(singleton.Conf.Server.Port)
if err := graceful.Graceful(func() error {
startOutput()
startupOutput(srv)
return srv.ListenAndServe()
}, func(c context.Context) error {
fmt.Print(utils.Colorize("Server is shutting down", utils.ColorRed))
srv.Shutdown(c)
return nil
}); err != nil {
fmt.Println(utils.Colorize("Server is shutting down with error: %s", utils.ColorRed), err)
fmt.Printf("Server is shutting down with error: %s", utils.Colorize(utils.ColorRed, err.Error()))
}
}

func initService() {
// Load all services in the singleton package
singleton.LoadSingleton()

if _, err := singleton.Cron.AddFunc("0 * * * * *", sayHello); err != nil {
panic(err)
}
// if _, err := singleton.Cron.AddFunc("0 * * * * *", sayHello); err != nil {
// panic(err)
// }
}

func sayHello() {
singleton.Log.Info().Msg("Hello world, I am a cron task")
// singleton.SendNotificationByType("wecom", "Hello world", "I am a cron task")
}
// func sayHello() {
// singleton.Log.Info().Msg("Hello world, I am a cron task")
// // singleton.SendNotificationByType("wecom", "Hello world", "I am a cron task")
// }
2 changes: 1 addition & 1 deletion cmd/srv/controller/api_v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func (v *apiV1) serve() {
var authModel = model.Auth{}

func (v *apiV1) upload(c *gin.Context) {
attachment, err := gogin.AttachmentUpload(c)
attachment, err := gogin.AttachmentUpload(c, c.Query("sub_dir"))
if err != nil {
mygin.ResponseJSON(c, 400, gin.H{}, err.Error())
return
Expand Down
9 changes: 5 additions & 4 deletions config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@ server:
site:
brand: Go-Gin # Site brand
description: A simple web application using Go and Gin # Site description
base_url: http://localhost:8080 # Site base URL, used for generating absolute URLs
base_url: http://localhost:8080 # Site base URL, used for generating absolute URLs, cant end with /
debug: false # Debug mode, if true, the server will print detailed error messages
log:
level: debug # debug, info, warn, error, fatal, panic
path: logs/go-gin.log # Log file path
db_path: db/go-gin.sqlite # Database path
path: logs/go-gin.log # Log file path, relative to the project root directory. Or you can use an absolute path, such as /var/www/go-gin.log
db_path: db/go-gin.sqlite # Database path, relative to the project root directory. Or you can use an absolute path, such as /var/www/go-gin.sqlite
rate_limit:
max: 100 # requests per minute, 0 means no limit
enable_cors: false # Enable CORS
enable_user_registration: true # Enable user registration
upload:
virtual_path: /upload # Virtual path, used for generating absolute URLs, must start with /
virtual_path: /upload # Virtual path, used for generating absolute URLs, must start with /, cant end with /
url_prefix: http://localhost:8080/upload # URL prefix, used for generating absolute URLs, must start with http:// or https:// or /, cant end with /
dir: upload # Upload directory, relative to the project root directory. Or you can use an absolute path, such as /var/www/upload
max_size: 10485760 # 10MB, unit: byte
keep_original_name: false # Keep original file name, if false, the server will generate a random file name
Expand Down
Loading

0 comments on commit c14bf1c

Please sign in to comment.