Help us shape the future of Go! Take the 2026 Go Developer Survey

install

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 26, 2026 License: AGPL-3.0 Imports: 17 Imported by: 0

Documentation

Overview

Package install 实现首次安装向导:连接测试、安装执行与状态查询。

站点还没有数据库连接信息时 serve 进入安装模式,只挂本包的路由与 Console 静态资源, 其余一律不装配。安装成功后会把连接串写进工作目录的 install.json(见 config 包), 服务随即重新初始化一次,这一次带着数据库,就是正常的站点。

本包不认识模块清单,也不认识设置模块:迁移、初始管理员与站点设置由调用方经 Provision 注入(见 cmd/lumo/install.go),安装包只负责编排顺序与守住安装的前置条件。

Index

Constants

This section is empty.

Variables

View Source
var ErrAlreadyInstalled = errors.New("站点已完成安装")

ErrAlreadyInstalled 表示站点已经装好了,安装入口一律拒绝。

Functions

func WrapBadRequest

func WrapBadRequest(err error) error

WrapBadRequest 把调用方(注入的 Provision)返回的错误标记成站长可自行修正的, 处理器据此原样回显而不是当成内部故障。

安装阶段的失败几乎都属于这一类:数据库权限不足、参数写错、口令不合规。

Types

type AdminInput

type AdminInput struct {
	Username string `` /* 126-byte string literal not displayed */
	Email    string `json:"email" format:"email" maxLength:"254"`
	Password string `json:"password" minLength:"8" maxLength:"128"`
}

AdminInput 是初始管理员账号。

用户名与口令的规则照抄数据库层的约束(migrations/00002_auth.sql 的 CHECK 与 auth/password 的长度限制):向导早一步拦住,比让站长在最后一步收到一条 「违反约束 users_username_format」要好得多。

type ApplyInput

type ApplyInput struct {
	Database DatabaseInput `json:"database"`
	Site     SiteInput     `json:"site"`
	Admin    AdminInput    `json:"admin"`
}

ApplyInput 是执行安装所需的全部输入。

type ApplyResult

type ApplyResult struct {
	Steps []Step `json:"steps"`
	// ExternalURL 是站长填的对外地址,可能为空。
	ExternalURL string `json:"externalUrl,omitempty"`
	// AdminCreated 为假表示库里已有用户,未创建新的管理员。
	AdminCreated bool `json:"adminCreated"`
}

ApplyResult 是安装执行的结果。

type BadRequestError

type BadRequestError struct {
	// contains filtered or unexported fields
}

BadRequestError 标记「按提示改输入就能解决」的错误。

处理器靠它把这些消息原样回给向导(400),而把其余错误当内部故障处理(500, 细节只进日志)——数据库口令写错和磁盘写不进去,对站长是两件完全不同的事。

func (*BadRequestError) Error

func (e *BadRequestError) Error() string

func (*BadRequestError) Unwrap

func (e *BadRequestError) Unwrap() error

type Check

type Check struct {
	Key    string `json:"key"`
	Label  string `json:"label"`
	OK     bool   `json:"ok"`
	Detail string `json:"detail"`
}

Check 是一项安装前置检查的结果。

type DatabaseInfo

type DatabaseInfo struct {
	ServerVersion string `json:"serverVersion"`
	Database      string `json:"database"`
	User          string `json:"user"`
	Encoding      string `json:"encoding"`
	LatencyMS     int64  `json:"latencyMs"`
	// ExistingUsers 是目标库里已有的用户数;-1 表示该库还没有 Lumo 的数据表。
	// 大于 0 时向导要提醒站长:继续下去是接管一个已有站点,不是新建。
	ExistingUsers int64 `json:"existingUsers"`
}

DatabaseInfo 是测试连接的结果。

type DatabaseInput

type DatabaseInput struct {
	DSN      string `json:"dsn,omitempty" doc:"完整连接串;填了就忽略下面各项"`
	Host     string `json:"host,omitempty" doc:"主机地址,例如 127.0.0.1"`
	Port     int    `json:"port,omitempty" doc:"端口,默认 5432" minimum:"1" maximum:"65535"`
	User     string `json:"user,omitempty" doc:"用户名"`
	Password string `json:"password,omitempty" doc:"口令"`
	Name     string `json:"name,omitempty" doc:"数据库名"`
	SSLMode  string `json:"sslMode,omitempty" doc:"TLS 模式" enum:"disable,prefer,require,verify-ca,verify-full"`
}

DatabaseInput 是数据库连接信息。填了 DSN 就忽略逐项字段。

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

Handler 提供安装向导的三个端点。

func NewHandler

func NewHandler(svc *Service, logger *slog.Logger) *Handler

NewHandler 构造 Handler。

func (*Handler) Register

func (h *Handler) Register(api huma.API)

Register 把安装端点挂到根 huma API(planes.API())上。

三平面都不合适:它们的解析凭据中间件要查库,而此刻库还不存在 —— 浏览器只要带着任何旧 Cookie 过来就会被挡成 401,向导第一步都走不到。

三个端点一律无条件注册,包括已经装好的站点:OpenAPI 规范要稳定。若按运行时状态 条件注册,`lumo openapi` 在不同库上会导出不同的规范,进而污染 Console 的生成类型。 「能不能装」放在处理器内部判断。

这些端点没有 CSRF 中间件。跨站表单发不出 application/json,而 huma 只解析 JSON 请求体,所以浏览器侧的跨站提交在这里自然失效;至于能直接访问服务器的攻击者, 他本来就能自己跑一遍安装向导,CSRF 拦不住也不增加风险。

type Options

type Options struct {
	// Config 是本次启动的配置(此时必然不含可用 DSN)。
	Config config.Config
	// DataDir 是已初始化的工作目录绝对路径。
	DataDir string
	Logger  *slog.Logger
	Version string
	// Provision 由调用方注入。
	Provision ProvisionFunc
}

Options 是构造 Service 的依赖。

type Params

type Params struct {
	DSN   string
	Site  SiteInput
	Admin AdminInput
}

Params 是交给调用方执行安装所需的全部输入。

type ProvisionFunc

type ProvisionFunc func(ctx context.Context, db *database.DB, cfg config.Config, in Params) (ProvisionResult, error)

ProvisionFunc 在目标库上完成安装的实质工作:迁移、内置角色、初始管理员、站点设置。

由 cmd/lumo 注入:它拿得到模块清单与设置模块,而本包刻意不认识它们。

type ProvisionResult

type ProvisionResult struct {
	// AdminCreated 为假表示目标库里已有用户,故未创建新的管理员。
	AdminCreated bool
}

ProvisionResult 是安装执行的结果。

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service 是安装向导的服务端逻辑。

func New

func New(opts Options) *Service

New 构造 Service。

func (*Service) Apply

func (s *Service) Apply(ctx context.Context, in ApplyInput) (*ApplyResult, error)

Apply 执行安装:连库、迁移、建管理员、写站点设置,最后落盘安装产物。

顺序是有意的:安装产物写在最后一步。中途任何一步失败都不会留下这个文件, 于是下次启动仍然进入安装模式,站长可以改完参数重来。

func (*Service) Done

func (s *Service) Done() <-chan struct{}

Done 在安装成功时关闭,供 serve 据此重启一轮。

func (*Service) Installed

func (s *Service) Installed() bool

Installed 报告本次进程内安装是否已经成功。

func (*Service) Status

func (s *Service) Status() StatusView

Status 汇总当前是否可安装与前置检查结果。

func (*Service) TestDatabase

func (s *Service) TestDatabase(ctx context.Context, in DatabaseInput) (*DatabaseInfo, error)

TestDatabase 试连目标库并回报它的身份。

type SiteInput

type SiteInput struct {
	Title string `json:"title,omitempty" maxLength:"100" doc:"站点名称"`
	URL   string `json:"url,omitempty" maxLength:"255" doc:"对外访问地址,例如 https://example.com"`
}

SiteInput 是站点信息。

type StatusView

type StatusView struct {
	// Installed 为真时向导应当自行退出:要么跳后台,要么按提示手动配置。
	Installed bool    `json:"installed"`
	Version   string  `json:"version"`
	DataDir   string  `json:"dataDir"`
	Checks    []Check `json:"checks"`
}

StatusView 是安装状态。

type Step

type Step struct {
	Key        string `json:"key"`
	Label      string `json:"label"`
	DurationMS int64  `json:"durationMs"`
	Detail     string `json:"detail,omitempty"`
}

Step 是安装过程中的一个阶段及其耗时。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL