github.com/erda-project/erda-infra@v1.0.10-0.20240327085753-f3a249292aeb/providers/mysqlxorm/xorm.go (about)

     1  // Copyright (c) 2021 Terminus, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package mysqlxorm
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"reflect"
    21  	"time"
    22  
    23  	_ "github.com/go-sql-driver/mysql" // mysql client driver package
    24  	"xorm.io/xorm"
    25  	xormlog "xorm.io/xorm/log"
    26  	"xorm.io/xorm/names"
    27  
    28  	"github.com/erda-project/erda-infra/base/logs"
    29  	"github.com/erda-project/erda-infra/base/servicehub"
    30  	"github.com/erda-project/erda-infra/pkg/mysqldriver"
    31  )
    32  
    33  // Interface .
    34  type Interface interface {
    35  	DB() *xorm.Engine
    36  	NewSession(ops ...SessionOption) *Session
    37  	Close() error
    38  	DataSourceName() string
    39  }
    40  
    41  var (
    42  	interfaceType = reflect.TypeOf((*Interface)(nil)).Elem()
    43  	xormType      = reflect.TypeOf((*xorm.Engine)(nil))
    44  )
    45  
    46  type config struct {
    47  	MySQLURL            string        `file:"url" env:"MYSQL_URL"`
    48  	MySQLHost           string        `file:"host" env:"MYSQL_HOST" default:"localhost"`
    49  	MySQLPort           string        `file:"port" env:"MYSQL_PORT" default:"3306"`
    50  	MySQLUsername       string        `file:"username" env:"MYSQL_USERNAME" default:"root"`
    51  	MySQLPassword       string        `file:"password" env:"MYSQL_PASSWORD" default:""`
    52  	MySQLDatabase       string        `file:"database" env:"MYSQL_DATABASE"`
    53  	MySQLMaxIdleConns   uint64        `file:"max_idle_conns" env:"MYSQL_MAXIDLECONNS" default:"10"`
    54  	MySQLMaxOpenConns   uint64        `file:"max_open_conns" env:"MYSQL_MAXOPENCONNS" default:"20"`
    55  	MySQLMaxLifeTime    time.Duration `file:"max_lifetime" env:"MYSQL_MAXLIFETIME" default:"30m"`
    56  	MySQLShowSQL        bool          `file:"show_sql" env:"MYSQL_SHOW_SQL" default:"false"`
    57  	MySQLProperties     string        `file:"properties" env:"MYSQL_PROPERTIES" default:"charset=utf8mb4&collation=utf8mb4_unicode_ci&parseTime=True&loc=Local"`
    58  	MySQLTLS            string        `file:"tls" env:"MYSQL_TLS"`
    59  	MySQLCaCertPath     string        `file:"ca_cert_path" env:"MYSQL_CACERTPATH"`
    60  	MySQLClientCertPath string        `file:"client_cert_path" env:"MYSQL_CLIENTCERTPATH"`
    61  	MySQLClientKeyPath  string        `file:"client_key_path" env:"MYSQL_CLIENTKEYPATH"`
    62  
    63  	MySQLPingWhenInit   bool   `file:"ping_when_init" env:"MYSQL_PING_WHEN_INIT" default:"true"`
    64  	MySQLPingTimeoutSec uint64 `file:"ping_timeout_sec" env:"MYSQL_PING_TIMEOUT_SEC" default:"10"`
    65  }
    66  
    67  func (c *config) url() string {
    68  	if c.MySQLURL != "" {
    69  		return c.MySQLURL
    70  	}
    71  
    72  	url := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?%s",
    73  		c.MySQLUsername, c.MySQLPassword, c.MySQLHost, c.MySQLPort, c.MySQLDatabase, c.MySQLProperties)
    74  	if c.MySQLTLS != "" {
    75  		url = fmt.Sprintf("%v&tls=%s", url, c.MySQLTLS)
    76  	}
    77  	return url
    78  }
    79  
    80  // provider .
    81  type provider struct {
    82  	Cfg *config
    83  	Log logs.Logger
    84  	db  *xorm.Engine
    85  }
    86  
    87  // Init .
    88  func (p *provider) Init(ctx servicehub.Context) error {
    89  	err := mysqldriver.OpenTLS(p.Cfg.MySQLTLS, p.Cfg.MySQLCaCertPath, p.Cfg.MySQLClientCertPath, p.Cfg.MySQLClientKeyPath)
    90  	if err != nil {
    91  		return err
    92  	}
    93  
    94  	db, err := xorm.NewEngine("mysql", p.Cfg.url())
    95  	if err != nil {
    96  		return fmt.Errorf("failed to connect to mysql server, err: %v", err)
    97  	}
    98  
    99  	db.SetMapper(names.GonicMapper{})
   100  	if p.Cfg.MySQLShowSQL {
   101  		db.ShowSQL(true)
   102  		db.SetLogLevel(xormlog.LOG_DEBUG)
   103  	}
   104  
   105  	// connection pool
   106  	db.SetMaxIdleConns(int(p.Cfg.MySQLMaxIdleConns))
   107  	db.SetMaxOpenConns(int(p.Cfg.MySQLMaxOpenConns))
   108  	db.SetConnMaxLifetime(p.Cfg.MySQLMaxLifeTime)
   109  	db.SetDisableGlobalCache(true)
   110  
   111  	// ping when init
   112  	if p.Cfg.MySQLPingWhenInit {
   113  		ctxForPing, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(p.Cfg.MySQLPingTimeoutSec))
   114  		defer cancel()
   115  		if err := db.PingContext(ctxForPing); err != nil {
   116  			return err
   117  		}
   118  	}
   119  
   120  	p.db = db
   121  	return nil
   122  }
   123  
   124  func (p *provider) DB() *xorm.Engine { return p.db }
   125  
   126  func (p *provider) Provide(ctx servicehub.DependencyContext, args ...interface{}) interface{} {
   127  	if ctx.Service() == "mysql-xorm-client" || ctx.Type() == xormType {
   128  		return p.db
   129  	}
   130  	return p
   131  }
   132  
   133  func (p *provider) DataSourceName() string {
   134  	return p.DB().DataSourceName()
   135  }
   136  
   137  func (p *provider) Close() error {
   138  	return p.DB().Close()
   139  }
   140  
   141  func init() {
   142  	servicehub.Register("mysql-xorm", &servicehub.Spec{
   143  		Services: []string{"mysql-xorm", "mysql-xorm-client"},
   144  		Types: []reflect.Type{
   145  			interfaceType, xormType,
   146  		},
   147  		Description: "mysql-xorm",
   148  		ConfigFunc:  func() interface{} { return &config{} },
   149  		Creator: func() servicehub.Provider {
   150  			return &provider{}
   151  		},
   152  	})
   153  }