## 可扩展部分
- 配置解析器 (原生集成 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` 的实现即可