github.com/erda-project/erda-infra@v1.0.9/providers/mysql/v2/mysql.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 v2
    16  
    17  import (
    18  	"fmt"
    19  	"reflect"
    20  	"time"
    21  
    22  	"github.com/sirupsen/logrus"
    23  	"gorm.io/driver/mysql" // mysql client driver package
    24  	"gorm.io/gorm"
    25  
    26  	"github.com/erda-project/erda-infra/base/servicehub"
    27  	"github.com/erda-project/erda-infra/pkg/mysqldriver"
    28  )
    29  
    30  var (
    31  	interfaceType = reflect.TypeOf((*Interface)(nil)).Elem()
    32  	gormType      = reflect.TypeOf((*gorm.DB)(nil))
    33  	txType        = reflect.TypeOf((*TX)(nil))
    34  	name          = "gorm.v2"
    35  	spec          = servicehub.Spec{
    36  		Services: []string{"mysql-gorm.v2", "mysql-gorm.v2-client"},
    37  		Types: []reflect.Type{
    38  			interfaceType, gormType,
    39  		},
    40  		Description: "mysql-gorm.v2",
    41  		ConfigFunc:  func() interface{} { return &config{} },
    42  		Creator: func() servicehub.Provider {
    43  			return &provider{}
    44  		},
    45  	}
    46  )
    47  
    48  func init() {
    49  	servicehub.Register(name, &spec)
    50  }
    51  
    52  // Interface .
    53  type Interface interface {
    54  	// DB returns the raw *gorm.DB.
    55  	DB() *gorm.DB
    56  	// Q returns the CRUD APIs without a transaction.
    57  	Q() *TX
    58  	// Begin returns the CRUD APIs with a transaction.
    59  	Begin() *TX
    60  }
    61  
    62  type config struct {
    63  	MySQLURL            string        `file:"url" env:"MYSQL_URL"`
    64  	MySQLHost           string        `file:"host" env:"MYSQL_HOST" default:"localhost"`
    65  	MySQLPort           string        `file:"port" env:"MYSQL_PORT" default:"3306"`
    66  	MySQLUsername       string        `file:"username" env:"MYSQL_USERNAME" default:"root"`
    67  	MySQLPassword       string        `file:"password" env:"MYSQL_PASSWORD" default:""`
    68  	MySQLDatabase       string        `file:"database" env:"MYSQL_DATABASE"`
    69  	MySQLMaxIdleConns   uint64        `file:"max_idle_conns" env:"MYSQL_MAXIDLECONNS" default:"10"`
    70  	MySQLMaxOpenConns   uint64        `file:"max_open_conns" env:"MYSQL_MAXOPENCONNS" default:"20"`
    71  	MySQLMaxLifeTime    time.Duration `file:"max_lifetime" env:"MYSQL_MAXLIFETIME" default:"30m"`
    72  	MySQLDebug          bool          `file:"debug" env:"MYSQL_DEBUG" default:"false"`
    73  	MySQLCharset        string        `file:"charset" env:"MYSQL_CHARSET" default:"utf8mb4"`
    74  	MySQLTLS            string        `file:"tls" env:"MYSQL_TLS"`
    75  	MySQLCaCertPath     string        `file:"ca_cert_path" env:"MYSQL_CACERTPATH"`
    76  	MySQLClientCertPath string        `file:"client_cert_path" env:"MYSQL_CLIENTCERTPATH"`
    77  	MySQLClientKeyPath  string        `file:"client_key_path" env:"MYSQL_CLIENTKEYPATH"`
    78  }
    79  
    80  func (c *config) url() string {
    81  	if c.MySQLURL != "" {
    82  		return c.MySQLURL
    83  	}
    84  
    85  	url := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=True&loc=Local",
    86  		c.MySQLUsername, c.MySQLPassword, c.MySQLHost, c.MySQLPort, c.MySQLDatabase, c.MySQLCharset)
    87  	if c.MySQLTLS != "" {
    88  		url = fmt.Sprintf("%v&tls=%s", url, c.MySQLTLS)
    89  	}
    90  	return url
    91  }
    92  
    93  // provider .
    94  type provider struct {
    95  	Cfg *config
    96  	db  *gorm.DB
    97  	tx  *TX
    98  }
    99  
   100  // Init implements servicehub.ProviderInitializer
   101  func (p *provider) Init(ctx servicehub.Context) error {
   102  	err := mysqldriver.OpenTLS(p.Cfg.MySQLTLS, p.Cfg.MySQLCaCertPath, p.Cfg.MySQLClientCertPath, p.Cfg.MySQLClientKeyPath)
   103  	if err != nil {
   104  		return err
   105  	}
   106  
   107  	logrus.WithField("provider", name).Infoln("init")
   108  	db, err := gorm.Open(mysql.Open(p.Cfg.url()))
   109  	if err != nil {
   110  		return fmt.Errorf("fail to connect mysql: %s", err)
   111  	}
   112  
   113  	s, err := db.DB()
   114  	if err != nil {
   115  		return fmt.Errorf("failed to get a conn pool")
   116  	}
   117  
   118  	// connection pool
   119  	s.SetMaxIdleConns(int(p.Cfg.MySQLMaxIdleConns))
   120  	s.SetMaxOpenConns(int(p.Cfg.MySQLMaxOpenConns))
   121  	s.SetConnMaxLifetime(p.Cfg.MySQLMaxLifeTime)
   122  	p.db = db
   123  	if p.Cfg.MySQLDebug {
   124  		p.db = p.db.Debug()
   125  	}
   126  
   127  	return nil
   128  }
   129  
   130  // DB implements Interface.DB
   131  func (p *provider) DB() *gorm.DB { return p.db }
   132  
   133  // Q implements Interface.Q
   134  func (p *provider) Q() *TX {
   135  	return &TX{
   136  		db:    p.db,
   137  		valid: true,
   138  	}
   139  }
   140  
   141  // Begin implements Interface.Begin
   142  func (p *provider) Begin() *TX {
   143  	return &TX{
   144  		db:    p.db,
   145  		valid: true,
   146  		inTx:  true,
   147  	}
   148  }
   149  
   150  // Provide implements servicehub.DependencyProvider
   151  func (p *provider) Provide(ctx servicehub.DependencyContext, args ...interface{}) interface{} {
   152  	if ctx.Service() == "mysql-gorm.v2-client" || ctx.Type() == gormType {
   153  		return p.db
   154  	}
   155  	return p
   156  }