Skip to content

Commit d9c7278

Browse files
committed
feat: enhance configuration loading from environment variables
- Added functionality to load ClickHouse configuration from environment variables, falling back to a config file if not set. - Introduced a helper function to retrieve environment variables with default values. - Updated error handling for config file reading and parsing. - Added .vercel to .gitignore to exclude Vercel deployment files.
1 parent 993635a commit d9c7278

File tree

4 files changed

+252
-8
lines changed

4 files changed

+252
-8
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
wb
1+
wb
2+
.vercel

api/entrypoint.go

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*
2+
* @Author: Vincent Yang
3+
* @Date: 2025-09-03 01:03:00
4+
* @LastEditors: Vincent Yang
5+
* @LastEditTime: 2025-09-04 01:10:22
6+
* @FilePath: /WeiboSearcher/api/entrypoint.go
7+
* @Telegram: https://t.me/missuo
8+
* @GitHub: https://github.com/missuo
9+
*
10+
* Copyright © 2025 by Vincent, All Rights Reserved.
11+
*/
12+
13+
package api
14+
15+
import (
16+
"fmt"
17+
"net/http"
18+
"os"
19+
"regexp"
20+
21+
"github.com/gin-contrib/cors"
22+
"github.com/gin-gonic/gin"
23+
"gopkg.in/yaml.v2"
24+
"gorm.io/driver/clickhouse"
25+
"gorm.io/gorm"
26+
)
27+
28+
type User struct {
29+
Uid string
30+
Mobile string
31+
}
32+
33+
type Set struct {
34+
ClickhouseConf ClickhouseConf `yaml:"clickhouse"`
35+
WeiboSearcherConf WeiboSearcherConf `yaml:"weiboSearcher"`
36+
}
37+
38+
type ClickhouseConf struct {
39+
Host string `yaml:"host"`
40+
Port string `yaml:"port"`
41+
Username string `yaml:"username"`
42+
Password string `yaml:"password"`
43+
Dbname string `yaml:"dbname"`
44+
}
45+
46+
type WeiboSearcherConf struct {
47+
ListenAddress string `yaml:"listenAddress"`
48+
ListenPort string `yaml:"listenPort"`
49+
}
50+
51+
func getConfigFromEnvOrFile() *Set {
52+
var set Set
53+
54+
// Try to get configuration from environment variables first
55+
if dbHost := os.Getenv("CLICKHOUSE_HOST"); dbHost != "" {
56+
set.ClickhouseConf.Host = dbHost
57+
set.ClickhouseConf.Port = getEnvOrDefault("CLICKHOUSE_PORT", "9000")
58+
set.ClickhouseConf.Username = getEnvOrDefault("CLICKHOUSE_USERNAME", "default")
59+
set.ClickhouseConf.Password = getEnvOrDefault("CLICKHOUSE_PASSWORD", "")
60+
set.ClickhouseConf.Dbname = getEnvOrDefault("CLICKHOUSE_DBNAME", "default")
61+
set.WeiboSearcherConf.ListenAddress = getEnvOrDefault("LISTEN_ADDRESS", "0.0.0.0")
62+
set.WeiboSearcherConf.ListenPort = getEnvOrDefault("LISTEN_PORT", "8080")
63+
return &set
64+
}
65+
66+
// Fall back to config file if environment variables are not set
67+
yamlFile, err := os.ReadFile("./config.yml")
68+
if err != nil {
69+
fmt.Println("Error reading config file:", err.Error())
70+
// Return default values if both env vars and config file fail
71+
set.ClickhouseConf.Host = "localhost"
72+
set.ClickhouseConf.Port = "9000"
73+
set.ClickhouseConf.Username = "default"
74+
set.ClickhouseConf.Password = ""
75+
set.ClickhouseConf.Dbname = "default"
76+
set.WeiboSearcherConf.ListenAddress = "0.0.0.0"
77+
set.WeiboSearcherConf.ListenPort = "8080"
78+
return &set
79+
}
80+
err = yaml.Unmarshal(yamlFile, &set)
81+
if err != nil {
82+
fmt.Println("Error parsing config file:", err.Error())
83+
}
84+
return &set
85+
}
86+
87+
func getEnvOrDefault(key, defaultValue string) string {
88+
if value := os.Getenv(key); value != "" {
89+
return value
90+
}
91+
return defaultValue
92+
}
93+
94+
var (
95+
app *gin.Engine
96+
)
97+
98+
func init() {
99+
// Get Configuration
100+
set := getConfigFromEnvOrFile()
101+
var clickhouseConf = set.ClickhouseConf
102+
dbHost := clickhouseConf.Host
103+
dbPort := clickhouseConf.Port
104+
dbUsername := clickhouseConf.Username
105+
dbPassword := clickhouseConf.Password
106+
dbName := clickhouseConf.Dbname
107+
108+
// Connect Clickhouse
109+
dsn := "clickhouse://" + dbUsername + ":" + dbPassword + "@" + dbHost + ":" + dbPort + "/" + dbName
110+
db, err := gorm.Open(clickhouse.Open(dsn), &gorm.Config{})
111+
if err != nil {
112+
panic("failed to connect database")
113+
}
114+
115+
gin.SetMode(gin.ReleaseMode)
116+
app = gin.Default()
117+
app.Use(cors.Default())
118+
119+
app.GET("/", func(c *gin.Context) {
120+
// Index Page
121+
c.JSON(http.StatusOK, gin.H{
122+
"code": http.StatusOK,
123+
"message": "This is Weibo SGK. Made by Vincent.",
124+
"usage": "GET/POST to /wb with parameter u",
125+
})
126+
})
127+
128+
app.Any("/wb", func(c *gin.Context) {
129+
re := regexp.MustCompile(`\d+`)
130+
u := c.Query("u")
131+
key := re.FindString(u)
132+
var result User
133+
if len(key) == 10 {
134+
// Input Weibo Uid
135+
db.Raw("SELECT * FROM wb WHERE uid = ? LIMIT 1", key).Scan(&result)
136+
} else if len(key) == 11 {
137+
// Input User Mobile Number
138+
db.Raw("SELECT * FROM wbm WHERE mobile = ? LIMIT 1", key).Scan(&result)
139+
} else {
140+
// Bad Parameters
141+
c.JSON(http.StatusBadRequest, gin.H{
142+
"code": http.StatusBadRequest,
143+
"message": "Bad Parameters",
144+
})
145+
return
146+
}
147+
// No Results
148+
if result.Uid == "" {
149+
c.JSON(http.StatusNotFound, gin.H{
150+
"code": http.StatusNotFound,
151+
"message": "Data Not Found",
152+
})
153+
154+
} else {
155+
c.JSON(http.StatusOK, gin.H{
156+
"code": http.StatusOK,
157+
"uid": result.Uid,
158+
"mobile": result.Mobile,
159+
})
160+
}
161+
})
162+
163+
// Catch-all route to handle undefined paths
164+
app.NoRoute(func(c *gin.Context) {
165+
c.JSON(http.StatusNotFound, gin.H{
166+
"code": http.StatusNotFound,
167+
"message": "Path not found",
168+
})
169+
})
170+
}
171+
172+
// Entrypoint is the serverless function handler for Vercel
173+
func Entrypoint(w http.ResponseWriter, r *http.Request) {
174+
app.ServeHTTP(w, r)
175+
}
176+
177+
// Type assertion to ensure our function matches http.HandlerFunc
178+
var _ http.HandlerFunc = Entrypoint

main.go

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"fmt"
1616
"io/ioutil"
1717
"net/http"
18+
"os"
1819
"regexp"
1920

2021
"github.com/gin-contrib/cors"
@@ -47,22 +48,52 @@ type WeiboSearcherConf struct {
4748
ListenPort string `yaml:"listenPort"`
4849
}
4950

50-
func (conf *Set) getConf() *Set {
51+
func getConfigFromEnvOrFile() *Set {
52+
var set Set
53+
54+
// Try to get configuration from environment variables first
55+
if dbHost := os.Getenv("CLICKHOUSE_HOST"); dbHost != "" {
56+
set.ClickhouseConf.Host = dbHost
57+
set.ClickhouseConf.Port = getEnvOrDefault("CLICKHOUSE_PORT", "9000")
58+
set.ClickhouseConf.Username = getEnvOrDefault("CLICKHOUSE_USERNAME", "default")
59+
set.ClickhouseConf.Password = getEnvOrDefault("CLICKHOUSE_PASSWORD", "")
60+
set.ClickhouseConf.Dbname = getEnvOrDefault("CLICKHOUSE_DBNAME", "default")
61+
set.WeiboSearcherConf.ListenAddress = getEnvOrDefault("LISTEN_ADDRESS", "0.0.0.0")
62+
set.WeiboSearcherConf.ListenPort = getEnvOrDefault("LISTEN_PORT", "8080")
63+
return &set
64+
}
65+
66+
// Fall back to config file if environment variables are not set
5167
yamlFile, err := ioutil.ReadFile("./config.yml")
5268
if err != nil {
53-
fmt.Println(err.Error())
69+
fmt.Println("Error reading config file:", err.Error())
70+
// Return default values if both env vars and config file fail
71+
set.ClickhouseConf.Host = "localhost"
72+
set.ClickhouseConf.Port = "9000"
73+
set.ClickhouseConf.Username = "default"
74+
set.ClickhouseConf.Password = ""
75+
set.ClickhouseConf.Dbname = "default"
76+
set.WeiboSearcherConf.ListenAddress = "0.0.0.0"
77+
set.WeiboSearcherConf.ListenPort = "8080"
78+
return &set
5479
}
55-
err = yaml.Unmarshal(yamlFile, conf)
80+
err = yaml.Unmarshal(yamlFile, &set)
5681
if err != nil {
57-
fmt.Println(err.Error())
82+
fmt.Println("Error parsing config file:", err.Error())
83+
}
84+
return &set
85+
}
86+
87+
func getEnvOrDefault(key, defaultValue string) string {
88+
if value := os.Getenv(key); value != "" {
89+
return value
5890
}
59-
return conf
91+
return defaultValue
6092
}
6193

6294
func main() {
6395
// Get Configuration
64-
var set Set
65-
set.getConf()
96+
set := getConfigFromEnvOrFile()
6697
var clickhouseConf = set.ClickhouseConf
6798
var appConf = set.WeiboSearcherConf
6899
dbHost := clickhouseConf.Host

vercel.json

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"version": 2,
3+
"builds": [
4+
{
5+
"src": "api/entrypoint.go",
6+
"use": "@vercel/go"
7+
}
8+
],
9+
"routes": [
10+
{
11+
"src": "/(.*)",
12+
"dest": "/api/entrypoint.go"
13+
}
14+
],
15+
"headers": [
16+
{
17+
"source": "/(.*)",
18+
"headers": [
19+
{
20+
"key": "Access-Control-Allow-Origin",
21+
"value": "*"
22+
},
23+
{
24+
"key": "Access-Control-Allow-Methods",
25+
"value": "GET, POST, PUT, DELETE, OPTIONS"
26+
},
27+
{
28+
"key": "Access-Control-Allow-Headers",
29+
"value": "Content-Type, Authorization"
30+
}
31+
]
32+
}
33+
]
34+
}

0 commit comments

Comments
 (0)