增加数据库配置:默认 sqlite3、支持 mysql,启动时连接校验
This commit is contained in:
@@ -4,16 +4,27 @@ go 1.26.4
|
||||
|
||||
require (
|
||||
github.com/expr-lang/expr v1.17.8
|
||||
github.com/go-sql-driver/mysql v1.10.0
|
||||
github.com/openai/openai-go v1.12.0
|
||||
github.com/peterh/liner v1.2.2
|
||||
github.com/tidwall/gjson v1.14.4
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
modernc.org/sqlite v1.56.0
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.2.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.24 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.3 // indirect
|
||||
github.com/ncruces/go-strftime v1.0.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tidwall/sjson v1.2.5 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/sys v0.47.0 // indirect
|
||||
modernc.org/libc v1.74.4 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
)
|
||||
@@ -1,11 +1,29 @@
|
||||
filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo=
|
||||
filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc=
|
||||
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/expr-lang/expr v1.17.8 h1:W1loDTT+0PQf5YteHSTpju2qfUfNoBt4yw9+wOEU9VM=
|
||||
github.com/expr-lang/expr v1.17.8/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
|
||||
github.com/go-sql-driver/mysql v1.10.0 h1:Q+1LV8DkHJvSYAdR83XzuhDaTykuDx0l6fkXxoWCWfw=
|
||||
github.com/go-sql-driver/mysql v1.10.0/go.mod h1:M+cqaI7+xxXGG9swrdeUIoPG3Y3KCkF0pZej+SK+nWk=
|
||||
github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3 h1:LMLX+LgTNWpfvCBdFebv6EsYotImrt/Ppc5cXIriCSo=
|
||||
github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3/go.mod h1:jl5iWTm0/hd5PjEYEOuwAJ57L/CibdZfrqZ5XA5GrCk=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI=
|
||||
github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A=
|
||||
github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4=
|
||||
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
|
||||
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/openai/openai-go v1.12.0 h1:NBQCnXzqOTv5wsgNC36PrFEiskGfO5wccfCWDo9S1U0=
|
||||
github.com/openai/openai-go v1.12.0/go.mod h1:g461MYGXEXBVdV5SaR/5tNzNbSfwTBBefwc+LlDCK0Y=
|
||||
github.com/peterh/liner v1.2.2 h1:aJ4AOodmL+JxOZZEL2u9iJf8omNRpqHc/EbrK+3mAXw=
|
||||
github.com/peterh/liner v1.2.2/go.mod h1:xFwJyiKIXJZUKItq5dGHZSTBRAuG/CpeNpWLyiNRNwI=
|
||||
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/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
||||
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
@@ -16,10 +34,44 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
|
||||
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
|
||||
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
|
||||
golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
|
||||
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q=
|
||||
golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
modernc.org/cc/v4 v4.29.1 h1:MKgdCV3WykTSPqpVrnxdEDS0HEd2FHpKZDzxzU5LyeI=
|
||||
modernc.org/cc/v4 v4.29.1/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI=
|
||||
modernc.org/ccgo/v4 v4.34.6 h1:sBgfIwyN0TQ9C5hwIeuqyeAKyMWnbvj2fvpF4L11uzU=
|
||||
modernc.org/ccgo/v4 v4.34.6/go.mod h1:SZ8YcN9NG7XVsQYdm6jYBvi8PQP1qi+kqB6OhjqI3Fk=
|
||||
modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM=
|
||||
modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU=
|
||||
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
||||
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/gc/v3 v3.1.4 h1:2g65LGVSmFQrXeITAw97x7hCRvZFcyE1uDP+7Vng7JI=
|
||||
modernc.org/gc/v3 v3.1.4/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
|
||||
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
|
||||
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
|
||||
modernc.org/libc v1.74.4 h1:fX1Omw4o2/1C2iRkkIsrQTasJQldLhRmuPreXLoWs9k=
|
||||
modernc.org/libc v1.74.4/go.mod h1:eeQAS9W3sZeKYMFubydxJpII9ybHWshk+7or7bLG9co=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
||||
modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg=
|
||||
modernc.org/opt v0.2.0/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||
modernc.org/sqlite v1.56.0 h1:/D8e2RfFqoy/Zc6PuC76U28zFwmI/sYx1Kjm4yEn9e0=
|
||||
modernc.org/sqlite v1.56.0/go.mod h1:yCJ2cmAaIkHQ25oXWrF8H4O1lIfPYPR26yCEDj2P3pQ=
|
||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
@@ -35,6 +35,17 @@ type Config struct {
|
||||
DefaultModel string `yaml:"default_model"`
|
||||
ToolModel string `yaml:"tool_model"`
|
||||
VisionModel string `yaml:"vision_model"`
|
||||
Database DatabaseConfig `yaml:"database"`
|
||||
}
|
||||
|
||||
type DatabaseConfig struct {
|
||||
Driver string `yaml:"driver"`
|
||||
File string `yaml:"file"`
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
User string `yaml:"user"`
|
||||
Password string `yaml:"password"`
|
||||
Name string `yaml:"name"`
|
||||
}
|
||||
|
||||
type legacyConfig struct {
|
||||
@@ -124,6 +135,20 @@ func applyDefaults(c *Config) {
|
||||
if c.DefaultProvider == "" && len(c.Providers) > 0 {
|
||||
c.DefaultProvider = c.Providers[0].Name
|
||||
}
|
||||
if c.Database.Driver == "" {
|
||||
c.Database.Driver = "sqlite3"
|
||||
}
|
||||
if c.Database.File == "" {
|
||||
c.Database.File = "data/memory.db"
|
||||
}
|
||||
if c.Database.Driver == "mysql" {
|
||||
if c.Database.Host == "" {
|
||||
c.Database.Host = "127.0.0.1"
|
||||
}
|
||||
if c.Database.Port == 0 {
|
||||
c.Database.Port = 3306
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func validate(c *Config) error {
|
||||
@@ -174,6 +199,13 @@ func validate(c *Config) error {
|
||||
return fmt.Errorf("vision_model 无效: %w", err)
|
||||
}
|
||||
}
|
||||
d := c.Database
|
||||
if !contains([]string{"sqlite3", "mysql"}, d.Driver) {
|
||||
return fmt.Errorf("database.driver 无效: %q(可选 sqlite3/mysql)", d.Driver)
|
||||
}
|
||||
if d.Driver == "mysql" && d.Name == "" {
|
||||
return errors.New("mysql 需要配置 database.name")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -257,6 +289,14 @@ func writeDefault(path string) error {
|
||||
},
|
||||
DefaultProvider: "openai",
|
||||
DefaultModel: "gpt-4o-mini",
|
||||
Database: DatabaseConfig{
|
||||
Driver: "sqlite3",
|
||||
File: "data/memory.db",
|
||||
Host: "127.0.0.1",
|
||||
Port: 3306,
|
||||
User: "root",
|
||||
Name: "memory",
|
||||
},
|
||||
}
|
||||
if err := validate(cfg); err != nil {
|
||||
return err
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package config
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestApplyDatabaseDefaults(t *testing.T) {
|
||||
c := &Config{Providers: []Provider{{Name: "p", BaseURL: "x", Models: []string{"m"}}}}
|
||||
applyDefaults(c)
|
||||
if c.Database.Driver != "sqlite3" {
|
||||
t.Errorf("默认 driver = %q, want sqlite3", c.Database.Driver)
|
||||
}
|
||||
if c.Database.File != "data/memory.db" {
|
||||
t.Errorf("默认 file = %q, want data/memory.db", c.Database.File)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyMySQLDefaults(t *testing.T) {
|
||||
c := &Config{
|
||||
Providers: []Provider{{Name: "p", BaseURL: "x", Models: []string{"m"}}},
|
||||
Database: DatabaseConfig{Driver: "mysql", Name: "memory"},
|
||||
}
|
||||
applyDefaults(c)
|
||||
if c.Database.Host != "127.0.0.1" {
|
||||
t.Errorf("默认 host = %q, want 127.0.0.1", c.Database.Host)
|
||||
}
|
||||
if c.Database.Port != 3306 {
|
||||
t.Errorf("默认 port = %d, want 3306", c.Database.Port)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateDatabase(t *testing.T) {
|
||||
c := &Config{
|
||||
DefaultProvider: "p",
|
||||
DefaultModel: "m",
|
||||
Providers: []Provider{{Name: "p", BaseURL: "x", Models: []string{"m"}}},
|
||||
Database: DatabaseConfig{Driver: "oracle"},
|
||||
}
|
||||
cfg = c
|
||||
if err := validate(c); err == nil {
|
||||
t.Error("非法驱动应报错")
|
||||
}
|
||||
c.Database = DatabaseConfig{Driver: "mysql"}
|
||||
if err := validate(c); err == nil {
|
||||
t.Error("mysql 缺 name 应报错")
|
||||
}
|
||||
c.Database = DatabaseConfig{Driver: "mysql", Name: "memory"}
|
||||
if err := validate(c); err != nil {
|
||||
t.Errorf("合法 mysql 配置不应报错: %v", err)
|
||||
}
|
||||
c.Database = DatabaseConfig{Driver: "sqlite3"}
|
||||
if err := validate(c); err != nil {
|
||||
t.Errorf("合法 sqlite3 配置不应报错: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "modernc.org/sqlite"
|
||||
|
||||
"myaibot/internal/config"
|
||||
)
|
||||
|
||||
func Open(cfg *config.DatabaseConfig) (*sql.DB, error) {
|
||||
driver, dsn, err := resolve(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db, err := sql.Open(driver, dsn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("打开数据库失败: %w", err)
|
||||
}
|
||||
db.SetMaxOpenConns(10)
|
||||
db.SetMaxIdleConns(5)
|
||||
db.SetConnMaxLifetime(30 * time.Minute)
|
||||
if err := db.Ping(); err != nil {
|
||||
db.Close()
|
||||
return nil, fmt.Errorf("数据库连接失败: %w", err)
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func Close(db *sql.DB) {
|
||||
if db != nil {
|
||||
db.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func resolve(cfg *config.DatabaseConfig) (driver, dsn string, err error) {
|
||||
switch cfg.Driver {
|
||||
case "sqlite3":
|
||||
return "sqlite", cfg.File, nil
|
||||
case "mysql":
|
||||
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
||||
cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.Name)
|
||||
return "mysql", dsn, nil
|
||||
default:
|
||||
return "", "", fmt.Errorf("不支持的数据库驱动: %s", cfg.Driver)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"myaibot/internal/config"
|
||||
)
|
||||
|
||||
func TestOpenSQLite(t *testing.T) {
|
||||
cfg := &config.DatabaseConfig{
|
||||
Driver: "sqlite3",
|
||||
File: filepath.Join(t.TempDir(), "memory.db"),
|
||||
}
|
||||
db, err := Open(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("Open 出错: %v", err)
|
||||
}
|
||||
defer Close(db)
|
||||
if err := db.Ping(); err != nil {
|
||||
t.Fatalf("Ping 出错: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenUnsupportedDriver(t *testing.T) {
|
||||
if _, err := Open(&config.DatabaseConfig{Driver: "oracle"}); err == nil {
|
||||
t.Error("不支持的驱动应报错")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveMySQL(t *testing.T) {
|
||||
cfg := &config.DatabaseConfig{
|
||||
Driver: "mysql",
|
||||
Host: "127.0.0.1",
|
||||
Port: 3306,
|
||||
User: "root",
|
||||
Password: "secret",
|
||||
Name: "memory",
|
||||
}
|
||||
driver, dsn, err := resolve(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("resolve 出错: %v", err)
|
||||
}
|
||||
if driver != "mysql" {
|
||||
t.Errorf("driver = %q, want mysql", driver)
|
||||
}
|
||||
want := "root:secret@tcp(127.0.0.1:3306)/memory?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
if dsn != want {
|
||||
t.Errorf("dsn = %q, want %q", dsn, want)
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"myaibot/internal/bot"
|
||||
"myaibot/internal/cli"
|
||||
"myaibot/internal/config"
|
||||
"myaibot/internal/store"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -21,6 +22,13 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatalf("加载配置失败: %v", err)
|
||||
}
|
||||
db, err := store.Open(&cfg.Database)
|
||||
if err != nil {
|
||||
log.Fatalf("数据库连接失败: %v", err)
|
||||
}
|
||||
defer store.Close(db)
|
||||
fmt.Printf("💾 数据库已连接 (%s)\n", cfg.Database.Driver)
|
||||
|
||||
b, err := bot.New(cfg)
|
||||
if err != nil {
|
||||
fmt.Printf("⚠️ %v\n", err)
|
||||
|
||||
Reference in New Issue
Block a user