<commit_before>// Copyright 2018 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package app

import (
	"errors"
	"net/http"
	"plugin"

	"github.com/issue9/web/dependency"
)

// PluginModuleName 插件中必须提供的变量名称。
// 根据此变量提供的数据进行初始化。
const PluginModuleName = "Module"

// 表示模块的类型。
const (
	ModuleTypeAll    ModuleType = iota
	ModuleTypeModule            // 默认的方式，即和代码一起编译
	ModuleTypePlugin            // 加载以 buildmode=plugin 方式编译的模块
)

// ModuleFunc 每个模块必须提供的注册函数
//
// 如果让模块直接以变量的形式直接提供，则需要保证每个 *Module
// 需要使用的数据都会在加载模块时初始化，这无法做到；
//
// 而返回 *Module 而不是直接在 ModuleFunc 内进行注册，
// 是因为这样可以控制 Module.Type 的值。
type ModuleFunc func() *Module

// ModuleType 用以指定模块的类型。
type ModuleType int8

// Module 表示模块信息
type Module struct {
	Name        string
	Deps        []string
	Description string
	Routes      []*Route
	Type        ModuleType

	inits        []dependency.InitFunc
	buildHandler BuildHandler
}

// Route 表示模块信息中的路由信息
type Route struct {
	Path    string
	Handler http.Handler
	Methods []string
}

// Prefix 可以将具有统一前缀的路由项集中在一起操作。
//  p := srv.Prefix("/api")
//  p.Get("/users")  // 相当于 srv.Get("/api/users")
//  p.Get("/user/1") // 相当于 srv.Get("/api/user/1")
type Prefix struct {
	module *Module
	prefix string
}

// Modules 获取当前的所有模块信息
func (app *App) Modules() []*Module {
	return app.modules
}

// AddModule 注册一个新的模块。
func (app *App) AddModule(m *Module) *App {
	m.Type = ModuleTypeModule
	app.addModule(m)
	return app
}

func (app *App) addModule(m *Module) {
	app.modules = append(app.modules, m)
}

// 加载配置文件中指定的所有插件
func (app *App) loadPlugins() error {
	for _, p := range app.config.Plugins {
		if err := app.loadPlugin(p); err != nil {
			return err
		}
	}

	return nil
}

func (app *App) loadPlugin(path string) error {
	p, err := plugin.Open(path)
	if err != nil {
		return err
	}

	symbol, err := p.Lookup(PluginModuleName)
	if err != nil {
		return err
	}

	f, ok := symbol.(ModuleFunc)
	if !ok {
		return errors.New("无法转换成 ModuleFunc")
	}

	module := f()
	module.Type = ModuleTypePlugin
	app.addModule(module)

	return nil
}

func (app *App) initDependency() error {
	dep := dependency.New()

	for _, module := range app.modules {
		dep.Add(module.Name, app.getInit(module), module.Deps...)
	}

	return dep.Init()
}

// 当 Module 的内容生成一个 dependency.InitFunc 函数
func (app *App) getInit(m *Module) dependency.InitFunc {
	return func() error {
		for _, init := range m.inits {
			if err := init(); err != nil {
				return err
			}
		}

		for _, r := range m.Routes {
			h := r.Handler
			if m.buildHandler != nil {
				h = m.buildHandler(h)
			}

			if err := app.router.Handle(r.Path, h, r.Methods...); err != nil {
				return err
			}
		}

		return nil
	}
}

// NewModule 声明一个新的模块
//
// 仅作声明，并不会添加到系统中，需要通过 AddModule 时行添加。
//
// name 模块名称，需要全局唯一；
// desc 模块的详细信息；
// deps 表示当前模块的依赖模块名称，可以是插件中的模块名称。
func NewModule(name, desc string, deps ...string) *Module {
	return &Module{
		Name:        name,
		Deps:        deps,
		Description: desc,
		Type:        ModuleTypeModule,
		Routes:      make([]*Route, 0, 10),
		inits:       make([]dependency.InitFunc, 0, 5),
	}
}

// Prefix 声明一个 Prefix 实例。
func (m *Module) Prefix(prefix string) *Prefix {
	return &Prefix{
		module: m,
		prefix: prefix,
	}
}

// Module 返回关联的 Module 实全
func (p *Prefix) Module() *Module {
	return p.module
}

// SetHandler 为当前模块的所有路由添加的中间件。
//
// 多次调用，最后一次为准。
func (m *Module) SetHandler(f BuildHandler) {
	m.buildHandler = f
}

// AddInit 添加一个初始化函数<commit_msg>去掉不必要的成员初始化<commit_after>// Copyright 2018 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package app

import (
	"errors"
	"net/http"
	"plugin"

	"github.com/issue9/web/dependency"
)

// PluginModuleName 插件中必须提供的变量名称。
// 根据此变量提供的数据进行初始化。
const PluginModuleName = "Module"

// 表示模块的类型。
const (
	ModuleTypeAll    ModuleType = iota
	ModuleTypeModule            // 默认的方式，即和代码一起编译
	ModuleTypePlugin            // 加载以 buildmode=plugin 方式编译的模块
)

// ModuleFunc 每个模块必须提供的注册函数
//
// 如果让模块直接以变量的形式直接提供，则需要保证每个 *Module
// 需要使用的数据都会在加载模块时初始化，这无法做到；
//
// 而返回 *Module 而不是直接在 ModuleFunc 内进行注册，
// 是因为这样可以控制 Module.Type 的值。
type ModuleFunc func() *Module

// ModuleType 用以指定模块的类型。
type ModuleType int8

// Module 表示模块信息
type Module struct {
	Name        string
	Deps        []string
	Description string
	Routes      []*Route
	Type        ModuleType

	inits        []dependency.InitFunc
	buildHandler BuildHandler
}

// Route 表示模块信息中的路由信息
type Route struct {
	Path    string
	Handler http.Handler
	Methods []string
}

// Prefix 可以将具有统一前缀的路由项集中在一起操作。
//  p := srv.Prefix("/api")
//  p.Get("/users")  // 相当于 srv.Get("/api/users")
//  p.Get("/user/1") // 相当于 srv.Get("/api/user/1")
type Prefix struct {
	module *Module
	prefix string
}

// Modules 获取当前的所有模块信息
func (app *App) Modules() []*Module {
	return app.modules
}

// AddModule 注册一个新的模块。
func (app *App) AddModule(m *Module) *App {
	m.Type = ModuleTypeModule
	app.addModule(m)
	return app
}

func (app *App) addModule(m *Module) {
	app.modules = append(app.modules, m)
}

// 加载配置文件中指定的所有插件
func (app *App) loadPlugins() error {
	for _, p := range app.config.Plugins {
		if err := app.loadPlugin(p); err != nil {
			return err
		}
	}

	return nil
}

func (app *App) loadPlugin(path string) error {
	p, err := plugin.Open(path)
	if err != nil {
		return err
	}

	symbol, err := p.Lookup(PluginModuleName)
	if err != nil {
		return err
	}

	f, ok := symbol.(ModuleFunc)
	if !ok {
		return errors.New("无法转换成 ModuleFunc")
	}

	module := f()
	module.Type = ModuleTypePlugin
	app.addModule(module)

	return nil
}

func (app *App) initDependency() error {
	dep := dependency.New()

	for _, module := range app.modules {
		dep.Add(module.Name, app.getInit(module), module.Deps...)
	}

	return dep.Init()
}

// 当 Module 的内容生成一个 dependency.InitFunc 函数
func (app *App) getInit(m *Module) dependency.InitFunc {
	return func() error {
		for _, init := range m.inits {
			if err := init(); err != nil {
				return err
			}
		}

		for _, r := range m.Routes {
			h := r.Handler
			if m.buildHandler != nil {
				h = m.buildHandler(h)
			}

			if err := app.router.Handle(r.Path, h, r.Methods...); err != nil {
				return err
			}
		}

		return nil
	}
}

// NewModule 声明一个新的模块
//
// 仅作声明，并不会添加到系统中，需要通过 AddModule 时行添加。
//
// name 模块名称，需要全局唯一；
// desc 模块的详细信息；
// deps 表示当前模块的依赖模块名称，可以是插件中的模块名称。
func NewModule(name, desc string, deps ...string) *Module {
	return &Module{
		Name:        name,
		Deps:        deps,
		Description: desc,
		Routes:      make([]*Route, 0, 10),
		inits:       make([]dependency.InitFunc, 0, 5),
	}
}

// Prefix 声明一个 Prefix 实例。
func (m *Module) Prefix(prefix string) *Prefix {
	return &Prefix{
		module: m,
		prefix: prefix,
	}
}

// Module 返回关联的 Module 实全
func (p *Prefix) Module() *Module {
	return p.module
}

// SetHandler 为当前模块的所有路由添加的中间件。
//
// 多次调用，最后一次为准。
func (m *Module) SetHandler(f BuildHandler) {
	m.buildHandler = f
}

// AddInit 添加一个初始化函数
{'fraction_non_alphanumeric': 0.13626624767890302, 'fraction_numerical': 0.0037137551778317385, 'mean_word_length': 3.0103092783505154, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1818529', 'n_tokens_mistral': 3149, 'n_tokens_neox': 3155, 'n_words': 685}