欢迎关注「Keegan小钢」公众号获取更多文章
程序入口
我们要开始聊代码实现逻辑了,如果不记得之前讲的目录结构,请回去翻看前文。聊代码实现的第一步自然从程序入口开始,核心就两个函数:init() 和 main(),其代码如下:
package main
... //other codes
func init() {
initViper()
initLog()
engine.Init()
middleware.Init()
process.Init()
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/openMatching", handler.OpenMatching)
mux.HandleFunc("/closeMatching", handler.CloseMatching)
mux.HandleFunc("/handleOrder", handler.HandleOrder)
log.Printf("HTTP ListenAndServe at port %s", viper.GetString("server.port"))
if err := http.ListenAndServe(viper.GetString("server.port"), mux); err != nil {
panic(err)
}
}
init() 函数做了一些初始化的操作,我来简单介绍这几个初始化函数:
- initViper():配置文件初始化,使用了第三方配置库 viper,这是一个被广泛使用的配置库,其 github 地址为 https://github.com/spf13/viper。
- initLog():日志初始化,程序主要使用自己定义的日志包用来输出日志文件,该日志包的实现后续文章再单独讲。
- engine.Init():引擎包的初始化,只是初始化了一个 map,用来保存不同交易标的的订单 channel,作为各交易标的的定序队列来用。
- middleware.Init():中间件的初始化,我们用到的中间件就只有 Redis,所以这里其实就是初始化 Redis 连接。Redis 客户端库方面我选择的是 go-redis/redis。
- process.Init():这一步主要是从缓存加载和恢复各交易标的引擎的启动和所有订单数据。
viper 和 redis 的初始化都是参照官方 demo 写的,这里就不展开说明了。log 后续再单独讲。engine 包和 process 包的初始化就需要好好讲讲。
其中,引擎包的初始化虽然非常简单,但很关键,其代码写在 engine/init.go 文件中,完整代码如下:
package engine
var ChanMap map[string]chan Order
func Init() {
ChanMap = make(map[string]chan Order)
}
这个保存通道的 map,其 Key 是各交易标的的 symbol,即是说每个交易标的各有一个订单通道,这些订单通道将作为每个交易标的的定序队列。
process 包的初始化则如下:
func Init() {
symbols := cache.GetSymbols()
for _, symbol := range symbols {
price := cache.GetPrice(symbol)
NewEngine(symbol, price)
orderIds := cache.GetOrderIdsWithAction(symbol)
for _, orderId := range orderIds {
mapOrder := cache.GetOrder(symbol, orderId)
order := engine.Order{
}
order.FromMap(mapOrder)
engine.ChanMap[order.Symbol] <- order
}
}