添加一些新指令

This commit is contained in:
dandan 2024-10-27 17:54:21 +08:00
parent 167a6439ed
commit 6613151288
15 changed files with 486 additions and 65 deletions

1
app/config/config.go Normal file
View File

@ -0,0 +1 @@
package config

View File

@ -1,6 +1,7 @@
package http package http
import ( import (
"github.com/Superdanda/hade/app/provider/database_connect"
"github.com/Superdanda/hade/framework" "github.com/Superdanda/hade/framework"
"github.com/Superdanda/hade/framework/gin" "github.com/Superdanda/hade/framework/gin"
) )
@ -15,5 +16,12 @@ func NewHttpEngine(container *framework.HadeContainer) (*gin.Engine, error) {
// 业务绑定路由操作 // 业务绑定路由操作
Routes(r) Routes(r)
// 返回绑定路由后的Web引擎 // 返回绑定路由后的Web引擎
// 对业务模型进行注册,通过注册名获取业务模型类型信息
TypeRegister(container)
//绑定服务
container.Bind(&database_connect.DatabaseConnectProvider{})
return r, nil return r, nil
} }

View File

@ -2,9 +2,19 @@ package demo
import ( import (
"database/sql" "database/sql"
"github.com/Superdanda/hade/app/provider/demo"
"github.com/Superdanda/hade/framework/contract"
"time" "time"
) )
func init() {
}
func TypeRegister(typeRegister contract.TypeRegisterService) {
typeRegister.Register("UserThree", demo.UserThree{})
typeRegister.Register("UserTwo", demo.UserTwo{})
}
type UserModel struct { type UserModel struct {
UserId int UserId int
Name string Name string

12
app/http/register.go Normal file
View File

@ -0,0 +1,12 @@
package http
import (
"github.com/Superdanda/hade/app/http/module/demo"
"github.com/Superdanda/hade/framework"
"github.com/Superdanda/hade/framework/contract"
)
func TypeRegister(container framework.Container) {
typeRegister := container.MustMake(contract.TypeRegisterKey).(contract.TypeRegisterService)
demo.TypeRegister(typeRegister)
}

View File

@ -22,6 +22,7 @@ func Routes(core *gin.Engine) {
core.Use(static.Serve("/", static.LocalFile("./dist", false))) core.Use(static.Serve("/", static.LocalFile("./dist", false)))
err := demo.Register(core) err := demo.Register(core)
if err != nil { if err != nil {
return return
} }

View File

@ -1 +1,32 @@
package demo package demo
import (
"database/sql"
"time"
)
// User is gorm model
type UserTwo struct {
ID uint
Name string
Email *string
Age uint8
Birthday *time.Time
MemberNumber sql.NullString
ActivatedAt sql.NullTime
CreatedAt time.Time
UpdatedAt time.Time
}
// User is gorm model
type UserThree struct {
ID uint
Name string
Email *string
Age uint8
Birthday *time.Time
MemberNumber sql.NullString
ActivatedAt sql.NullTime
CreatedAt time.Time
UpdatedAt time.Time
}

View File

@ -4,12 +4,27 @@ conn_max_lifetime: 1h # 通用配置,连接数最大生命周期
protocol: tcp # 通用配置,传输协议 protocol: tcp # 通用配置,传输协议
loc: Local # 通用配置,时区 loc: Local # 通用配置,时区
default: local:
driver: mysql # 连接驱动
dsn: "" # dsn如果设置了dsn, 以下的所有设置都不生效
host: 127.0.0.1 # ip地址
port: 3306 # 端口
database: bbs # 数据库
username: root # 用户名
password: "123456" # 密码
charset: utf8mb4 # 字符集
collation: utf8mb4_unicode_ci # 字符序
timeout: 10s # 连接超时
read_timeout: 2s # 读超时
write_timeout: 2s # 写超时
parse_time: true # 是否解析时间
ali:
driver: mysql # 连接驱动 driver: mysql # 连接驱动
dsn: "" # dsn如果设置了dsn, 以下的所有设置都不生效 dsn: "" # dsn如果设置了dsn, 以下的所有设置都不生效
host: 47.97.21.20 # ip地址 host: 47.97.21.20 # ip地址
port: 3306 # 端口 port: 3306 # 端口
database: questionnaire # 数据库 database: bbs # 数据库
username: root # 用户名 username: root # 用户名
password: "kerowsqw34" # 密码 password: "kerowsqw34" # 密码
charset: utf8mb4 # 字符集 charset: utf8mb4 # 字符集
@ -18,6 +33,7 @@ default:
read_timeout: 2s # 读超时 read_timeout: 2s # 读超时
write_timeout: 2s # 写超时 write_timeout: 2s # 写超时
parse_time: true # 是否解析时间 parse_time: true # 是否解析时间
protocol: tcp # 传输协议
loc: Local # 时区
sync:
filePath: /app/provider

View File

@ -35,7 +35,7 @@ var cronCommand = &cobra.Command{
Short: "定时任务控制命令", Short: "定时任务控制命令",
Long: "定时任务控制命令,包含展示、重启、启动、常驻状态、停止等命令", Long: "定时任务控制命令,包含展示、重启、启动、常驻状态、停止等命令",
RunE: func(c *cobra.Command, args []string) error { RunE: func(c *cobra.Command, args []string) error {
if len(args) != 0 { if len(args) == 0 {
c.Help() c.Help()
} }
return nil return nil

View File

@ -0,0 +1,144 @@
package command
import (
"errors"
"fmt"
"github.com/Superdanda/hade/framework"
"github.com/Superdanda/hade/framework/cobra"
"github.com/Superdanda/hade/framework/contract"
"github.com/Superdanda/hade/framework/provider/orm"
"go/ast"
"go/parser"
"go/token"
"gorm.io/gorm"
"os"
"path/filepath"
"reflect"
)
func initDatabaseCommand() *cobra.Command {
databaseCommand.AddCommand(databaseModelSyncCommand)
return databaseCommand
}
var databaseCommand = &cobra.Command{
Use: "database",
Short: "数据库相关命令",
Long: "操控数据库相关命令,同步数据模型到数据库",
RunE: func(c *cobra.Command, args []string) error {
if len(args) == 0 {
c.Help()
}
return nil
},
}
var databaseModelSyncCommand = &cobra.Command{
Use: "modelSync",
Short: "同步数据模型到数据库",
RunE: func(c *cobra.Command, args []string) error {
if len(args) != 1 {
fmt.Println("请输入数据库连接名称")
}
container := c.GetContainer()
appService := container.MustMake(contract.AppKey).(contract.App)
configService := container.MustMake(contract.ConfigKey).(contract.Config)
syncPathFolder := filepath.Join(appService.BaseFolder(), configService.GetString("database.sync.filePath"))
ormService := container.MustMake(contract.ORMKey).(contract.ORMService)
db, err := ormService.GetDB(orm.WithConfigPath("database." + args[0]))
if err != nil {
return err
}
err = AutoMigrateStructs(db, syncPathFolder, container)
if err != nil {
return err
}
return nil
},
}
// ScanStructsInPackage 扫描给定包路径下的所有结构体
func ScanStructsInPackage(pkgPath string, container framework.Container) ([]interface{}, error) {
var structs []interface{}
// 遍历包路径下的所有 Go 文件
err := filepath.Walk(pkgPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 只处理 .go 文件
if filepath.Ext(path) != ".go" {
return nil
}
// 解析 Go 文件,构建 AST
fset := token.NewFileSet()
node, err := parser.ParseFile(fset, path, nil, parser.AllErrors)
if err != nil {
return err
}
// 遍历 AST找到所有类型声明
for _, decl := range node.Decls {
genDecl, ok := decl.(*ast.GenDecl)
if !ok || genDecl.Tok != token.TYPE {
continue
}
// 遍历所有类型声明,找到结构体类型
for _, spec := range genDecl.Specs {
typeSpec, ok := spec.(*ast.TypeSpec)
if !ok {
continue
}
// 检查是否为结构体类型
_, ok = typeSpec.Type.(*ast.StructType)
if ok {
// 创建结构体的零值并添加到结果中
structName := typeSpec.Name.Name
instance, err := createStructInstance(structName, container)
if err != nil {
fmt.Println(err.Error())
}
if instance != nil {
structs = append(structs, instance)
}
}
}
}
return nil
})
return structs, err
}
// createStructInstance 使用反射创建结构体的实例
func createStructInstance(structName string, container framework.Container) (interface{}, error) {
typeRegister := container.MustMake(contract.TypeRegisterKey).(contract.TypeRegisterService)
// 假设结构体已导入,使用反射获取类型
structType, b := typeRegister.GetType(structName)
if b {
instance := reflect.New(structType).Interface()
return instance, nil
}
return nil, errors.New(structName + "类型没有注册")
}
func AutoMigrateStructs(db *gorm.DB, pkgPath string, container framework.Container) error {
// 扫描包路径下的所有结构体
structs, err := ScanStructsInPackage(pkgPath, container)
if err != nil {
return err
}
// 使用 GORM 进行自动迁移
for _, model := range structs {
if err := db.AutoMigrate(model); err != nil {
return fmt.Errorf("自动迁移失败: %v", err)
}
fmt.Printf("成功迁移模型:%T\n", model)
}
return nil
}

View File

@ -20,6 +20,7 @@ func AddKernelCommands(root *cobra.Command) {
root.AddCommand(initNewCommand()) root.AddCommand(initNewCommand())
root.AddCommand(initSwaggerCommand()) root.AddCommand(initSwaggerCommand())
root.AddCommand(initDeployCommand()) root.AddCommand(initDeployCommand())
root.AddCommand(initDatabaseCommand())
} }
// 封装通用的命令执行器 // 封装通用的命令执行器

View File

@ -3,15 +3,15 @@ package command
import ( import (
"fmt" "fmt"
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
"os"
"path/filepath"
"strings"
"text/template"
"github.com/Superdanda/hade/framework" "github.com/Superdanda/hade/framework"
"github.com/Superdanda/hade/framework/cobra" "github.com/Superdanda/hade/framework/cobra"
"github.com/Superdanda/hade/framework/contract" "github.com/Superdanda/hade/framework/contract"
"github.com/Superdanda/hade/framework/util" "github.com/Superdanda/hade/framework/util"
"os"
"path/filepath"
"reflect"
"strings"
"text/template"
"github.com/jianfengye/collection" "github.com/jianfengye/collection"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -56,7 +56,7 @@ var providerCreateCommand = &cobra.Command{
container := c.GetContainer() container := c.GetContainer()
fmt.Println("创建一个服务") fmt.Println("创建一个服务")
var name, folder string var name, folder string
var interfaceNames []string interfaceNames := &RouteNode{}
{ {
prompt := &survey.Input{ prompt := &survey.Input{
Message: "请输入服务名称(服务凭证)", Message: "请输入服务名称(服务凭证)",
@ -101,10 +101,10 @@ var providerCreateCommand = &cobra.Command{
return nil return nil
} }
// Keep asking for interface names until the user presses Enter to stop // 收集用户输入并填充嵌套映射
for { for {
prompt := &survey.Input{ prompt := &survey.Input{
Message: "请输入接口名称(直接按回车结束输入):", Message: "请输入接口路径(格式:/user/login直接按回车结束输入):",
} }
var input string var input string
@ -113,23 +113,27 @@ var providerCreateCommand = &cobra.Command{
return err return err
} }
// If the user presses Enter without input, break the loop // 如果用户直接按回车,结束输入
if strings.TrimSpace(input) == "" { if strings.TrimSpace(input) == "" {
fmt.Println("接口输入结束") fmt.Println("接口输入结束")
break break
} }
// Add the valid interface name to the slice // 解析输入的路径为路径部分
interfaceNames = append(interfaceNames, input) pathParts := strings.Split(strings.TrimPrefix(input, "/"), "/")
if len(pathParts) == 0 {
fmt.Println("路径格式错误,请输入正确格式:/节点/接口")
continue
}
// 将路径部分插入到路由树中
insertIntoRouteTree(pathParts, []string{}, interfaceNames)
fmt.Printf("已添加接口:%s\n", input) fmt.Printf("已添加接口:%s\n", input)
} }
interfaceNames.NeedExtra = false
// Print all the interface names added by the user // 打印所有添加的接口(测试用)
if len(interfaceNames) > 0 { printRouteTree(interfaceNames, 0)
fmt.Println("已添加的接口名称:", interfaceNames)
} else {
fmt.Println("未添加任何接口")
}
// 开始创建文件 // 开始创建文件
if err := os.Mkdir(filepath.Join(pFolder, folder), 0700); err != nil { if err := os.Mkdir(filepath.Join(pFolder, folder), 0700); err != nil {
@ -141,9 +145,30 @@ var providerCreateCommand = &cobra.Command{
"appName": config.GetAppName(), "appName": config.GetAppName(),
"packageName": name, "packageName": name,
"interfaces": interfaceNames, "interfaces": interfaceNames,
"structName": name,
} }
// 创建title这个模版方法 // 创建title这个模版方法
funcs := template.FuncMap{"title": strings.Title} funcs := template.FuncMap{
"title": strings.Title,
"dict": func(values ...interface{}) (map[string]interface{}, error) {
if len(values)%2 != 0 {
return nil, fmt.Errorf("invalid dict call: missing key or value")
}
dict := make(map[string]interface{}, len(values)/2)
for i := 0; i < len(values); i += 2 {
key, ok := values[i].(string)
if !ok {
return nil, fmt.Errorf("dict keys must be strings")
}
dict[key] = values[i+1]
}
return dict, nil
},
"len": func(v interface{}) int {
return reflect.ValueOf(v).Len()
},
}
{ {
// 创建contract.go // 创建contract.go
file := filepath.Join(pFolder, folder, "contract.go") file := filepath.Join(pFolder, folder, "contract.go")
@ -184,6 +209,10 @@ var providerCreateCommand = &cobra.Command{
} }
} }
if interfaceNames.Children == nil || len(interfaceNames.Children) == 0 {
return nil
}
moduleFolder := app.HttpModuleFolder() moduleFolder := app.HttpModuleFolder()
pModuleFolder := filepath.Join(moduleFolder, name) pModuleFolder := filepath.Join(moduleFolder, name)
util.EnsureDir(pModuleFolder) util.EnsureDir(pModuleFolder)
@ -192,12 +221,13 @@ var providerCreateCommand = &cobra.Command{
// 创建api 我呢见 // 创建api 我呢见
{ {
// 创建api.go // 创建 api.go
file := filepath.Join(pModuleFolder, "api.go") file := filepath.Join(pModuleFolder, "api.go")
f, err := os.Create(file) f, err := os.Create(file)
if err != nil { if err != nil {
return err return err
} }
data["interfaces"] = interfaceNames // 传递嵌套的接口名称映射
t := template.Must(template.New("api").Funcs(funcs).Parse(apiTmp)) t := template.Must(template.New("api").Funcs(funcs).Parse(apiTmp))
if err := t.Execute(f, data); err != nil { if err := t.Execute(f, data); err != nil {
return err return err
@ -206,35 +236,15 @@ var providerCreateCommand = &cobra.Command{
// 创建api_controller文件 // 创建api_controller文件
{ {
tmpl, err := template.New("controller").Funcs(funcs).Parse(apiControllerTmp) tmpl := template.Must(template.New("controller").Funcs(funcs).Parse(apiControllerTmp))
if err != nil { data["packageName"] = name
fmt.Println("Failed to parse template:", err) data["structName"] = name
// 递归生成控制器文件
if err := generateControllers(interfaceNames, []string{}, tmpl, data, pModuleFolder); err != nil {
fmt.Println("生成控制器失败:", err)
return err return err
} }
// Generate a file for each interface
for _, interfaceName := range interfaceNames {
data := map[string]interface{}{
"packageName": name,
"appName": config.GetAppName(),
"interfaceName": interfaceName,
}
// Create the output file
filePath := filepath.Join(pModuleFolder, "api_"+interfaceName+".go")
file, err := os.Create(filePath)
if err != nil {
fmt.Println("Failed to create file:", err)
return errors.New("Failed to create file: " + filePath)
}
defer file.Close()
// Execute the template with the data
if err := tmpl.Execute(file, data); err != nil {
fmt.Println("Failed to execute template:", err)
return errors.New("Failed to execute template: " + filePath)
}
fmt.Printf("Generated file: %s\n", filePath)
}
} }
//创建 dto 文件 //创建 dto 文件
@ -271,6 +281,93 @@ var providerCreateCommand = &cobra.Command{
}, },
} }
func generateControllers(node *RouteNode, pathParts []string, tmpl *template.Template, data map[string]interface{}, moduleFolder string) error {
// 更新路径部分
newPathParts := append(pathParts, node.Path)
// 如果当前节点需要生成处理函数
if node.NeedExtra {
data["interfaceName"] = strings.Join(newPathParts, "_")
data["methodName"] = node.HandlerName
// 生成文件名,例如 api_user_edit_auto.go
fileName := "api" + strings.Join(newPathParts, "_") + ".go"
filePath := filepath.Join(moduleFolder, fileName)
// 创建控制器文件
file, err := os.Create(filePath)
if err != nil {
return fmt.Errorf("创建文件失败: %s", filePath)
}
defer file.Close()
// 渲染模板
if err := tmpl.Execute(file, data); err != nil {
return fmt.Errorf("渲染模板失败: %s", filePath)
}
fmt.Printf("生成接口控制器文件: %s\n", filePath)
}
// 递归处理子节点
for _, child := range node.Children {
if err := generateControllers(child, newPathParts, tmpl, data, moduleFolder); err != nil {
return err
}
}
return nil
}
func insertIntoRouteTree(pathParts []string, fullPathParts []string, currentNode *RouteNode) {
if len(pathParts) == 0 {
currentNode.NeedExtra = true
return
}
// 获取当前路径部分
part := pathParts[0]
fullPathParts = append(fullPathParts, part)
// 查找是否已存在该路径部分的子节点
var child *RouteNode
for _, node := range currentNode.Children {
if node.Path == part {
child = node
break
}
}
// 如果子节点不存在,则创建新的子节点
if child == nil {
handlerName := ""
for _, v := range fullPathParts {
handlerName += strings.Title(v)
}
child = &RouteNode{
Path: part,
HandlerName: handlerName,
}
currentNode.Children = append(currentNode.Children, child)
}
// 递归处理剩余路径部分
insertIntoRouteTree(pathParts[1:], fullPathParts, child)
}
func printRouteTree(node *RouteNode, level int) {
indent := strings.Repeat(" ", level)
fmt.Printf("%s- %s\n", indent, node.Path)
for _, child := range node.Children {
printRouteTree(child, level+1)
}
}
type RouteNode struct {
Path string // 路由路径
Children []*RouteNode // 子路由节点列表
NeedExtra bool // 是否需要额外生成接口
HandlerName string
}
var contractTmp = `package {{.packageName}} var contractTmp = `package {{.packageName}}
const {{.packageName | title}}Key = "{{.appName}}:{{.packageName}}" const {{.packageName | title}}Key = "{{.appName}}:{{.packageName}}"
@ -279,6 +376,8 @@ type Service interface {
// 请在这里定义你的方法 // 请在这里定义你的方法
Foo() string Foo() string
} }
type {{.packageName | title}} struct {}
` `
var providerTmp = `package {{.packageName}} var providerTmp = `package {{.packageName}}
@ -335,37 +434,64 @@ func (s *{{.packageName | title}}Service) Foo() string {
var apiTmp = `package {{.packageName}} var apiTmp = `package {{.packageName}}
import ( import (
"github.com/Superdanda/hade/framework/gin" "github.com/Superdanda/hade/framework/gin"
) )
type {{.packageName | title}}Api struct{} type {{.packageName | title}}Api struct{}
// 注册路由
func RegisterRoutes(r *gin.Engine) error { func RegisterRoutes(r *gin.Engine) error {
api := {{.packageName | title}}Api{}
api := {{.packageName | title}}Api{}
if !r.IsBind({{.packageName}}.{{.packageName | title}}Key) { if !r.IsBind({{.packageName}}.{{.packageName | title}}Key) {
r.Bind(&{{.packageName}}.{{.packageName | title}}Provider{}) r.Bind(&{{.packageName}}.{{.packageName | title}}Provider{})
} }
{{.packageName}}Group := r.Group("/{{.packageName}}") {{template "registerRoutes" dict "node" .interfaces "groupVar" "r" "apiVar" "api"}}
{
{{range .interfaces}} return nil
// {{.}} route
{{$.packageName}}Group.POST("/{{.}}", api.{{. | title}})
{{end}}
}
return nil
} }
{{- define "registerRoutes"}}
{{- $node := .node -}}
{{- $groupVar := .groupVar -}}
{{- $apiVar := .apiVar -}}
{{- if ne $node.Path "root" -}}
{{- $hasChildren := gt (len $node.Children) 0 -}}
{{- $groupName := (printf "%sGroup" $node.Path) -}}
{{- if $hasChildren -}}
{{$groupName}} := {{$groupVar}}.Group("/{{$node.Path}}")
{
{{- if $node.NeedExtra -}}
{{$groupName}}.POST("/", {{$apiVar}}.{{ $node.HandlerName }})
{{- end}}
{{range $child := $node.Children}}
{{template "registerRoutes" dict "node" $child "groupVar" $groupName "apiVar" $apiVar}}
{{- end}}
}
{{- else}}
{{- if $node.NeedExtra}}
{{$groupVar}}.POST("/{{$node.Path}}", {{$apiVar}}.{{ $node.HandlerName }})
{{- end}}
{{end}}
{{- else}}
{{range $child := $node.Children}}
{{template "registerRoutes" dict "node" $child "groupVar" $groupVar "apiVar" $apiVar}}
{{- end}}
{{- end}}
{{- end}}
` `
var apiControllerTmp = `package {{.packageName}} var apiControllerTmp = `package {{.packageName}}
import ( import (
"github.com/Superdanda/hade/framework/gin" "github.com/Superdanda/hade/framework/gin"
) )
// {{.interfaceName | title}} handler // {{.methodName}} handler
func (api *{{.packageName | title}}Api) {{.interfaceName | title}}(c *gin.Context) { func (api *{{.structName | title}}Api) {{.methodName}}(c *gin.Context) {
// TODO: Add logic for {{.interfaceName}} // TODO: Implement {{.methodName}}
} }
` `

View File

@ -0,0 +1,10 @@
package contract
import "reflect"
const TypeRegisterKey = "hade:typeRegister"
type TypeRegisterService interface {
Register(typeName string, instance interface{})
GetType(typeName string) (reflect.Type, bool)
}

View File

@ -0,0 +1,29 @@
package type_register
import (
"github.com/Superdanda/hade/framework"
"github.com/Superdanda/hade/framework/contract"
)
type TypeRegisterProvider struct {
}
func (t TypeRegisterProvider) Register(container framework.Container) framework.NewInstance {
return NewHadeTypeRegisterService
}
func (t TypeRegisterProvider) Boot(container framework.Container) error {
return nil
}
func (t TypeRegisterProvider) IsDefer() bool {
return false
}
func (t TypeRegisterProvider) Params(container framework.Container) []interface{} {
return []interface{}{container}
}
func (t TypeRegisterProvider) Name() string {
return contract.TypeRegisterKey
}

View File

@ -0,0 +1,30 @@
package type_register
import (
"reflect"
"sync"
)
type HadeTypeRegisterService struct {
mu sync.RWMutex
types map[string]reflect.Type
}
func NewHadeTypeRegisterService(params ...interface{}) (interface{}, error) {
return &HadeTypeRegisterService{
types: make(map[string]reflect.Type),
}, nil
}
func (r *HadeTypeRegisterService) Register(typeName string, instance interface{}) {
r.mu.Lock()
defer r.mu.Unlock()
r.types[typeName] = reflect.TypeOf(instance)
}
func (r *HadeTypeRegisterService) GetType(typeName string) (reflect.Type, bool) {
r.mu.RLock()
defer r.mu.RUnlock()
typ, exists := r.types[typeName]
return typ, exists
}

View File

@ -14,6 +14,7 @@ import (
"github.com/Superdanda/hade/framework/provider/orm" "github.com/Superdanda/hade/framework/provider/orm"
"github.com/Superdanda/hade/framework/provider/redis" "github.com/Superdanda/hade/framework/provider/redis"
"github.com/Superdanda/hade/framework/provider/ssh" "github.com/Superdanda/hade/framework/provider/ssh"
"github.com/Superdanda/hade/framework/provider/type_register"
) )
func main() { func main() {
@ -32,6 +33,7 @@ func main() {
container.Bind(&redis.RedisProvider{}) container.Bind(&redis.RedisProvider{})
container.Bind(&cache.HadeCacheProvider{}) container.Bind(&cache.HadeCacheProvider{})
container.Bind(&ssh.SSHProvider{}) container.Bind(&ssh.SSHProvider{})
container.Bind(&type_register.TypeRegisterProvider{})
// 将HTTP引擎初始化,并且作为服务提供者绑定到服务容器中 // 将HTTP引擎初始化,并且作为服务提供者绑定到服务容器中
if engine, err := http.NewHttpEngine(container); err == nil { if engine, err := http.NewHttpEngine(container); err == nil {