## 可擴展部分
- 配置解析器 (原生集成 json 解析器)
- 驅動構造器 (原生集成 mysql 構造器)
## 實現目標
- 新增 `toml` 配置解析器
## 配置解析器結構分析
我們查看官方源碼配置解析器目錄`~/gorose/parser/`, 找到已有的`json`解析器, 實現方式是:
1. 定義統一解析器接口 (`interface.go`)
```go
type IParser interface {
Parse(d string) (conf *across.DbConfigCluster, err error)
}
```
2. 實現該接口解析 json (`json_parser.go`)
```go
package parser
import (
"encoding/json"
"fmt"
"io/ioutil"
"reflect"
"strings"
)
type JsonConfigParser struct {
}
func init() {
// 檢查解析器是否實現了接口
var parserTmp IParser = &JsonConfigParser{}
// 注冊驅動
Register("json", parserTmp)
}
func (c *JsonConfigParser) Parse(file string, dbConfCluster interface{}) (err error) {
var fp []byte
fp, err = ioutil.ReadFile(file)
if err != nil {
return err
}
// 是否是主從格式
strFp := string(fp)
if strings.Contains(strFp, "Slave") &&
strings.Contains(strFp, "Master") {
err = json.Unmarshal(fp, dbConfCluster)
} else {
//err = json.Unmarshal([]byte(fp), &conf.Master)
err = jsonDecoder(fp, dbConfCluster)
}
return err
}
func jsonDecoder(str []byte, dbConfCluster interface{}) (err error) {
srcElem := reflect.Indirect(reflect.ValueOf(dbConfCluster))
fmt.Println(srcElem)
fieldType := srcElem.FieldByName("Master").Type().Elem()
fieldElem := reflect.New(fieldType)
err = json.Unmarshal(str, fieldElem.Interface())
srcElem.FieldByName("Master").Set(fieldElem)
return
}
```
`json_parser.go`分析:
- a. 定義 `type JsonConfigParser struct`
- b. 實現解析器接口 `func (c *JsonConfigParser) Parse(file string, dbConfCluster interface{}) (err error)`
- c. 在入口處`init()`方法中檢查并注冊解析器, 并定取名為 `json`
實現接口(b)的源碼分析:
- i. 獲取 `across.DbConfigCluster` 數據庫映射結構體對象
- ii: 讀取文件
- iii: 解析配置
通過如上的源碼分析, 我們不難發現, 只需要實現解析器接口, 并能夠解析到配置結構體中即可, 下面, 我們就是先一個toml解析器來練練手
## toml 解析器的實現
- 新增文件`~/gorose/parser/toml_parser.go`
- 定義結構體 `type TomlConfigParser struct`
- 實現方法 `func (c *TomlConfigParser) Parse(file string, dbConfCluster interface{}) (err error)`
- 注冊解析器
```go
func init() {
// 檢查解析器是否實現了接口
var parserTmp IParser = &TomlConfigParser{}
// 注冊解析器
Register("toml", parserTmp)
}
```
- 完整源碼
```go
package parser
import (
"github.com/BurntSushi/toml"
"io/ioutil"
"reflect"
"strings"
)
type TomlConfigParser struct {
}
func init() {
// 檢查解析器是否實現了接口
var parserTmp IParser = &TomlConfigParser{}
// 注冊驅動
Register("toml", parserTmp)
}
func (c *TomlConfigParser) Parse(file string, dbConfCluster interface{}) (err error) {
var fp []byte
fp, err = ioutil.ReadFile(file)
if err != nil {
return
}
// 是否是主從格式
strFp := string(fp)
if strings.Contains(strFp, "Slave") &&
strings.Contains(strFp, "Master") {
err = toml.Unmarshal(fp, dbConfCluster)
} else {
//err = json.Unmarshal([]byte(fp), &conf.Master)
err = tomlDecoder(fp, dbConfCluster)
}
return err
}
func tomlDecoder(str []byte, dbConfCluster interface{}) (err error) {
srcElem := reflect.Indirect(reflect.ValueOf(dbConfCluster))
fieldType := srcElem.FieldByName("Master").Type().Elem()
fieldPtr := reflect.New(fieldType)
//tmp := fieldPtr.Interface()
err = toml.Unmarshal(str, fieldPtr.Interface())
srcElem.FieldByName("Master").Set(fieldPtr)
return
}
```
這里引入了第三方包 `github.com/BurntSushi/toml` 作為toml解析器, 并賦值給 `across.DbConfigCluster` 即可
同理, 我們可以實現任何文件類型的解析器 , 只需要能夠最終返回 `across.DbConfigCluster` 的實現即可