paopao-ce 是使用Golang技术栈打造的一个清新文艺的微社区,编译后的可执行文件外加一个配置文件conf.yml
就可以简单部署一个节点实例提供类似Twitter的推文服务。
paopao-ce的配置文件中有一个功能项的配置用于自定义节点实例运行时提供哪些服务,对部署运维非常友好。本文简单解析conf.yml
中功能项配置的设计,了解其背后的实现细节。
conf.yml
的功能项配置机制是参考Rust包管理工具Cargo的 Cargo.toml
中 [features]
配置而设计的。如下示例:
[package]
name = "poem"
version = "1.3.50"
authors = ["sunli <scott_s829@163.com>"]
edition = "2021"
description = "Poem is a full-featured and easy-to-use web framework with the Rust programming language."
[features]
default = ["server"]
server = ["tokio/rt", "tokio/net", "hyper/server", "hyper/runtime"]
websocket = ["tokio/rt", "tokio-tungstenite", "base64"]
multipart = ["multer"]
rustls = ["server", "tokio-rustls", "rustls-pemfile"]
native-tls = ["server", "tokio-native-tls"]
openssl-tls = ["server", "tokio-openssl", "openssl"]
static-files = ["httpdate", "mime_guess", "tokio/io-util", "tokio/fs"]
cookie = ["libcookie", "chrono", "time"]
session = ["tokio/rt", "cookie", "rand", "priority-queue", "base64"]
embed = ["rust-embed", "hex", "mime_guess"]
xml = ["quick-xml"]
i18n = [
"fluent",
"fluent-langneg",
"fluent-syntax",
"unic-langid",
"intl-memoizer",
]
在Rust中,使用features
的方式
pub mod endpoint;
pub mod error;
#[cfg(feature = "i18n")]
#[cfg_attr(docsrs, doc(cfg(feature = "i18n")))]
pub mod i18n;
#[cfg(feature = "server")]
#[cfg_attr(docsrs, doc(cfg(feature = "server")))]
pub mod listener;
pub mod middleware;
#[cfg(feature = "session")]
#[cfg_attr(docsrs, doc(cfg(feature = "session")))]
pub mod session;
#[cfg(feature = "test")]
#[cfg_attr(docsrs, doc(cfg(feature = "test")))]
pub mod test;
pub mod web;
#[doc(inline)]
pub use http;
没错,很简单,只要在需要feature时使用#[cfg(feature = "some-feature")]
注解即可,Rust编译器会做相应处理。
paopao-ce使用YAML格式的配置文件conf.yml
,在[Features]小节中声明运行时开启哪些功能项/服务:
...
Features:
Default: ["Base", "MySQL", "Option", "LocalOSS", "LoggerFile"]
Develop: ["Base", "MySQL", "Option", "Sms", "AliOSS", "LoggerZinc"]
Demo: ["Base", "MySQL", "Option", "Sms", "MinIO", "LoggerZinc"]
Slim: ["Base", "Sqlite3", "LocalOSS", "LoggerFile"]
Base: ["Zinc", "Redis", "Alipay"]
Docs: ["Docs:OpenAPI"]
Service: ["Admin", "SpaceX", "Bot", "LocalOSS"]
Deprecated: ["Deprecated:OldWeb"]
Option: ["SimpleCacheIndex"]
Sms: "SmsJuhe"
...
如上: Default/Develop/Demo/Slim 是不同 功能集套件(Features Suite), Base/Option 是子功能套件, Sms是关于短信验证码功能的参数选项。
这里 Default
套件 代表的意思是: 使用Base/Option
中的功能,外加 MySQL/LocalOSS/LoggerFile
功能,也就是说开启了Zinc/Redis/Alipay/SimpleCacheIndex/MySQL/LocalOSS/LoggerFile
7项功能;
Develop
套件依例类推。
使用Features:
release/paopao-ce --help
Usage of release/paopao-ce:
-features value
use special features
-no-default-features
whether use default features
# 默认使用 Default 功能套件
release/paopao-ce
# 不包含 default 中的功能集,仅仅使用 develop 中声明的功能集
release/paopao-ce --no-default-features --features develop
# 使用 default 中的功能集,外加 sms 功能
release/paopao-ce --features sms
# 手动指定需要开启的功能集
release/paopao-ce --no-default-features --features sqlite3,localoss,loggerfile,redis
paopao-ce在代码实现中是通过github.com/alimy/cfg解析Features配置:
初始化cfg
// file: internal/conf/conf.go
package conf
import (
"log"
"sync"
"time"
"github.com/alimy/cfg"
)
func setupSetting(suite []string, noDefault bool) error {
...
// initialize features configure
ss, kv := setting.featuresInfoFrom("Features")
cfg.Initial(ss, kv)
if len(suite) > 0 {
cfg.Use(suite, noDefault)
}
...
}
cfg的参考使用
// file: internal/service/service.go
package service
import (
"log"
"github.com/alimy/cfg"
"github.com/rocboss/paopao-ce/pkg/types"
)
func newService() (ss []Service) {
ss = append(ss, newWebService())
// add oldWebService if not depredcated OldWebService
cfg.Not("Deprecated:OldWeb", func() {
ss = append(ss, newOldWebService())
})
cfg.In(cfg.Actions{
"Admin": func() {
ss = append(ss, newAdminService())
},
"SpaceX": func() {
ss = append(ss, newSpaceXService())
},
"Bot": func() {
ss = append(ss, newBotService())
},
"LocalOSS": func() {
ss = append(ss, newLocalossService())
},
})
return
}
// file: internal/dao/dao.go
package dao
import (
"sync"
"github.com/alimy/cfg"
"github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/dao/jinzhu"
"github.com/rocboss/paopao-ce/internal/dao/sakila"
"github.com/rocboss/paopao-ce/internal/dao/search"
"github.com/rocboss/paopao-ce/internal/dao/slonik"
"github.com/rocboss/paopao-ce/internal/dao/storage"
"github.com/sirupsen/logrus"
)
func newAuthorizationManageService() (s core.AuthorizationManageService) {
if cfg.If("Gorm") {
s = jinzhu.NewAuthorizationManageService()
} else if cfg.If("Sqlx") && cfg.If("MySQL") {
s = sakila.NewAuthorizationManageService()
} else if cfg.If("Sqlx") && (cfg.If("Postgres") || cfg.If("PostgreSQL")) {
s = slonik.NewAuthorizationManageService()
} else {
s = jinzhu.NewAuthorizationManageService()
}
return
}
github.com/alimy/cfg的API文档请参考