From 27e0ed2994e56b9548b2d1a2ef3fe0cc5e45eb77 Mon Sep 17 00:00:00 2001 From: luorijun Date: Sat, 15 Mar 2025 16:07:45 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9B=E5=BB=BA=E7=AE=A1=E7=90=86=E5=90=8E?= =?UTF-8?q?=E7=AB=AF=E4=BB=93=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 8 + README.md | 25 ++ cmd/main.go | 58 +++ go.mod | 20 + go.sum | 29 ++ scripts/dev/docker-compose.yaml | 17 + scripts/sql/init.sql | 642 ++++++++++++++++++++++++++++++++ web/auth.go | 1 + web/router.go | 7 + web/web.go | 54 +++ 10 files changed, 861 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 cmd/main.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 scripts/dev/docker-compose.yaml create mode 100644 scripts/sql/init.sql create mode 100644 web/auth.go create mode 100644 web/router.go create mode 100644 web/web.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0b70e90 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.idea/ +.vscode/ + +.env +.env.* +!.env.example + +build/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7120c99 --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +## todo + +购买使用流程 + +- [ ] 注册 +- [ ] 登录 +- [ ] 实名认证 +- [ ] 充值余额 +- [ ] 选择套餐 +- [ ] 提取 IP +- [ ] 连接 + +确认登录方式,决定表结构 + +固有字段统一放在最开始 + +## 枚举字典 + +### 产品 + +| 代码 | 缩写 | 产品 | +|----------------------|-----|------| +| proxy/shared-static | pss | 动态代理 | +| proxy/shared-rotate | psr | 隧道代理 | +| proxy/private-static | pps | 独享代理 | diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..6360d98 --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,58 @@ +package main + +import ( + "log/slog" + "os" + "os/signal" + "platform/web" + "syscall" +) + +func main() { + logger := slog.Default() + + // 退出信号 + shutdown := make(chan os.Signal, 1) + signal.Notify(shutdown, syscall.SIGINT, syscall.SIGTERM) + + // web 服务 + app, err := web.New(&web.Config{ + Logger: logger, + Listen: ":8080", + }) + if err != nil { + logger.Error("Failed to create server", slog.Any("error", err)) + return + } + + errCh := make(chan error) + defer close(errCh) + go func() { + err = app.Run() + if err != nil { + logger.Error("Failed to run server", slog.Any("error", err)) + errCh <- err + } + errCh <- nil + }() + + // 关闭服务 + exit := false + select { + case <-shutdown: + logger.Info("Received shutdown signal") + app.Stop() + exit = true + case err := <-errCh: + if err != nil { + logger.Error("Server error", slog.Any("error", err)) + } + } + + if exit { + err := <-errCh + if err != nil { + logger.Error("Server error", slog.Any("error", err)) + } + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..73f47fd --- /dev/null +++ b/go.mod @@ -0,0 +1,20 @@ +module platform + +go 1.24.0 + +require github.com/gofiber/fiber/v2 v2.52.6 + +require ( + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/sys v0.28.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..7769a78 --- /dev/null +++ b/go.sum @@ -0,0 +1,29 @@ +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/gofiber/fiber/v2 v2.52.6 h1:Rfp+ILPiYSvvVuIPvxrBns+HJp8qGLDnLJawAu27XVI= +github.com/gofiber/fiber/v2 v2.52.6/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/scripts/dev/docker-compose.yaml b/scripts/dev/docker-compose.yaml new file mode 100644 index 0000000..0454a5f --- /dev/null +++ b/scripts/dev/docker-compose.yaml @@ -0,0 +1,17 @@ +name: server-dev + +services: + postgres: + image: postgres:17 + restart: always + environment: + POSTGRES_USER: test + POSTGRES_PASSWORD: test + POSTGRES_DB: app + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + +volumes: + postgres_data: diff --git a/scripts/sql/init.sql b/scripts/sql/init.sql new file mode 100644 index 0000000..1eff788 --- /dev/null +++ b/scripts/sql/init.sql @@ -0,0 +1,642 @@ +-- ==================== +-- region 管理员信息 +-- ==================== + +-- admin +drop table if exists admin cascade; +create table admin ( + id serial primary key, + username varchar(255) not null unique, + password varchar(255) not null, + name varchar(255), + avatar varchar(255), + phone varchar(255), + email varchar(255), + status int not null default 1, + last_login timestamp, + last_login_addr varchar(45), + last_login_agent varchar(255), + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); +create index admin_status_index on admin (status); + +-- admin表字段注释 +comment on table admin is '管理员表'; +comment on column admin.id is '管理员ID'; +comment on column admin.username is '用户名'; +comment on column admin.password is '密码'; +comment on column admin.name is '真实姓名'; +comment on column admin.avatar is '头像URL'; +comment on column admin.phone is '手机号码'; +comment on column admin.email is '邮箱'; +comment on column admin.status is '状态:1-正常,0-禁用'; +comment on column admin.last_login is '最后登录时间'; +comment on column admin.last_login_addr is '最后登录地址'; +comment on column admin.last_login_agent is '最后登录代理'; +comment on column admin.created_at is '创建时间'; +comment on column admin.updated_at is '更新时间'; +comment on column admin.deleted_at is '删除时间'; + +-- admin_role +drop table if exists admin_role cascade; +create table admin_role ( + id serial primary key, + name varchar(255) not null unique, + description varchar(255), + active bool default true, + sort int default 0, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); + +-- admin_role表字段注释 +comment on table admin_role is '管理员角色关联表'; +comment on column admin_role.id is '管理员角色ID'; +comment on column admin_role.name is '角色名称'; +comment on column admin_role.description is '角色描述'; +comment on column admin_role.active is '是否激活'; +comment on column admin_role.sort is '排序'; +comment on column admin_role.created_at is '创建时间'; +comment on column admin_role.updated_at is '更新时间'; +comment on column admin_role.deleted_at is '删除时间'; + +-- endregion + +-- ==================== +-- region 用户信息 +-- ==================== + +-- user +drop table if exists "user" cascade; +create table "user" ( + id serial primary key, + admin_id int references admin (id) -- + on update cascade -- + on delete set null, + password varchar(255) not null, + username varchar(255) not null unique, + phone varchar(255) not null unique, + email varchar(255) not null unique, + name varchar(255), + avatar varchar(255), + status int not null default 1, + balance decimal(12, 2) not null default 0, + id_type int not null default 0, + id_no varchar(255), + id_token varchar(255), + contact_qq varchar(255), + contact_wechat varchar(255), + last_login timestamp, + last_login_addr varchar(45), + last_login_agent varchar(255), + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); +create index user_status_index on "user" (status); + +-- user表字段注释 +comment on table "user" is '用户表'; +comment on column user.id is '用户ID'; +comment on column user.admin_id is '管理员ID'; +comment on column user.password is '用户密码'; +comment on column user.username is '用户名'; +comment on column user.phone is '手机号码'; +comment on column user.name is '真实姓名'; +comment on column user.avatar is '头像URL'; +comment on column user.status is '用户状态:1-正常,0-禁用'; +comment on column user.balance is '账户余额'; +comment on column user.id_type is '认证类型:0-未认证,1-个人认证,2-企业认证'; +comment on column user.id_no is '身份证号或营业执照号'; +comment on column user.id_token is '身份验证标识'; +comment on column user.contact_qq is 'QQ联系方式'; +comment on column user.contact_wechat is '微信联系方式'; +comment on column user.last_login is '最后登录时间'; +comment on column user.last_login_addr is '最后登录地址'; +comment on column user.last_login_agent is '最后登录代理'; +comment on column user.created_at is '创建时间'; +comment on column user.updated_at is '更新时间'; +comment on column user.deleted_at is '删除时间'; + +-- user_role +drop table if exists user_role cascade; +create table user_role ( + id serial primary key, + name varchar(255) not null unique, + description varchar(255), + active bool default true, + sort int default 0, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); + +-- user_role表字段注释 +comment on table user_role is '用户角色表'; +comment on column user_role.id is '角色ID'; +comment on column user_role.name is '角色名称'; +comment on column user_role.description is '角色描述'; +comment on column user_role.active is '是否激活'; +comment on column user_role.sort is '排序'; +comment on column user_role.created_at is '创建时间'; +comment on column user_role.updated_at is '更新时间'; +comment on column user_role.deleted_at is '删除时间'; + +-- endregion + +-- ==================== +-- region 权限信息 +-- ==================== + +-- permission +drop table if exists permission cascade; +create table permission ( + id serial primary key, + parent_id int references permission (id) + on update cascade + on delete cascade, + name varchar(255) not null unique, + description varchar(255), + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); +create index permission_parent_id_index on permission (parent_id); + +-- permission表字段注释 +comment on table permission is '权限表'; +comment on column permission.id is '权限ID'; +comment on column permission.parent_id is '父权限ID'; +comment on column permission.name is '权限名称'; +comment on column permission.description is '权限描述'; +comment on column permission.created_at is '创建时间'; +comment on column permission.updated_at is '更新时间'; +comment on column permission.deleted_at is '删除时间'; + +-- user_role_link +drop table if exists user_role_link cascade; +create table user_role_link ( + id serial primary key, + user_id int not null references "user" (id) + on update cascade + on delete cascade, + role_id int not null references user_role (id) + on update cascade + on delete cascade, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); +create index user_role_link_user_id_index on user_role_link (user_id); +create index user_role_link_role_id_index on user_role_link (role_id); + +-- user_role_link表字段注释 +comment on table user_role_link is '用户角色关联表'; +comment on column user_role_link.id is '关联ID'; +comment on column user_role_link.user_id is '用户ID'; +comment on column user_role_link.role_id is '角色ID'; +comment on column user_role_link.created_at is '创建时间'; +comment on column user_role_link.updated_at is '更新时间'; +comment on column user_role_link.deleted_at is '删除时间'; + +-- admin_role_link +drop table if exists admin_role_link cascade; +create table admin_role_link ( + id serial primary key, + admin_id int not null references admin (id) + on update cascade + on delete cascade, + role_id int not null references admin_role (id) + on update cascade + on delete cascade, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); +create index admin_role_link_admin_id_index on admin_role_link (admin_id); +create index admin_role_link_role_id_index on admin_role_link (role_id); + +-- admin_role_link表字段注释 +comment on table admin_role_link is '管理员角色关联表'; +comment on column admin_role_link.id is '关联ID'; +comment on column admin_role_link.admin_id is '管理员ID'; +comment on column admin_role_link.role_id is '角色ID'; +comment on column admin_role_link.created_at is '创建时间'; +comment on column admin_role_link.updated_at is '更新时间'; +comment on column admin_role_link.deleted_at is '删除时间'; + +-- user_role_permission_link +drop table if exists user_role_permission_link cascade; +create table user_role_permission_link ( + id serial primary key, + role_id int not null references user_role (id) + on update cascade + on delete cascade, + permission_id int not null references permission (id) + on update cascade + on delete cascade, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); +create index user_role_permission_link_role_id_index on user_role_permission_link (role_id); +create index user_role_permission_link_permission_id_index on user_role_permission_link (permission_id); + +-- user_role_permission_link表字段注释 +comment on table user_role_permission_link is '用户角色权限关联表'; +comment on column user_role_permission_link.id is '关联ID'; +comment on column user_role_permission_link.role_id is '角色ID'; +comment on column user_role_permission_link.permission_id is '权限ID'; +comment on column user_role_permission_link.created_at is '创建时间'; +comment on column user_role_permission_link.updated_at is '更新时间'; +comment on column user_role_permission_link.deleted_at is '删除时间'; + +-- admin_role_permission_link +drop table if exists admin_role_permission_link cascade; +create table admin_role_permission_link ( + id serial primary key, + role_id int not null references admin_role (id) + on update cascade + on delete cascade, + permission_id int not null references permission (id) + on update cascade + on delete cascade, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); +create index admin_role_permission_link_role_id_index on admin_role_permission_link (role_id); +create index admin_role_permission_link_permission_id_index on admin_role_permission_link (permission_id); + +-- admin_role_permission_link表字段注释 +comment on table admin_role_permission_link is '管理员角色权限关联表'; +comment on column admin_role_permission_link.id is '关联ID'; +comment on column admin_role_permission_link.role_id is '角色ID'; +comment on column admin_role_permission_link.permission_id is '权限ID'; +comment on column admin_role_permission_link.created_at is '创建时间'; +comment on column admin_role_permission_link.updated_at is '更新时间'; +comment on column admin_role_permission_link.deleted_at is '删除时间'; + +-- endregion + +-- ==================== +-- region 节点信息 +-- ==================== + +-- node +drop table if exists node cascade; +create table node ( + id serial primary key, + name varchar(255) not null unique, + version int not null, + fwd_port int not null, + provider varchar(255) not null, + location varchar(255) not null, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); +create index node_provider_index on node (provider); +create index node_location_index on node (location); + +-- node表字段注释 +comment on table node is '节点表'; +comment on column node.id is '节点ID'; +comment on column node.name is '节点名称'; +comment on column node.version is '节点版本'; +comment on column node.fwd_port is '转发端口'; +comment on column node.provider is '运营商'; +comment on column node.location is '位置'; +comment on column node.created_at is '创建时间'; +comment on column node.updated_at is '更新时间'; +comment on column node.deleted_at is '删除时间'; + +-- whitelist +drop table if exists whitelist cascade; +create table whitelist ( + id serial primary key, + user_id int not null references "user" (id) + on update cascade + on delete cascade, + address varchar(45) not null, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); +create index whitelist_user_id_index on whitelist (user_id); +create index whitelist_address_index on whitelist (address); + +-- whitelist表字段注释 +comment on table whitelist is '白名单表'; +comment on column whitelist.id is '白名单ID'; +comment on column whitelist.user_id is '用户ID'; +comment on column whitelist.address is 'IP地址'; +comment on column whitelist.created_at is '创建时间'; +comment on column whitelist.updated_at is '更新时间'; +comment on column whitelist.deleted_at is '删除时间'; + +-- channel +drop table if exists channel cascade; +create table channel ( + id serial primary key, + user_id int not null references "user" (id) + on update cascade + on delete cascade, + node_id int references node (id) -- + on update cascade -- + on delete set null, + user_addr varchar(255) not null, + node_port int, + auth_ip bool not null default false, + auth_pass bool not null default false, + protocol varchar(255), + username varchar(255) unique, + password varchar(255), + expiration timestamp not null, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); +create index channel_user_id_index on channel (user_id); +create index channel_node_id_index on channel (node_id); +create index channel_user_addr_index on channel (user_addr); +create index channel_node_port_index on channel (node_port); +create index channel_expiration_index on channel (expiration); + +-- channel表字段注释 +comment on table channel is '通道表'; +comment on column channel.id is '通道ID'; +comment on column channel.user_id is '用户ID'; +comment on column channel.node_id is '节点ID'; +comment on column channel.user_addr is '用户地址'; +comment on column channel.node_port is '节点端口'; +comment on column channel.auth_ip is 'IP认证'; +comment on column channel.auth_pass is '密码认证'; +comment on column channel.protocol is '协议'; +comment on column channel.username is '用户名'; +comment on column channel.password is '密码'; +comment on column channel.expiration is '过期时间'; +comment on column channel.created_at is '创建时间'; +comment on column channel.updated_at is '更新时间'; +comment on column channel.deleted_at is '删除时间'; + +-- endregion + +-- ==================== +-- region 产品信息 +-- ==================== + +-- product +drop table if exists product cascade; +create table product ( + id serial primary key, + code varchar(255) not null unique, + name varchar(255) not null, + description varchar(255), + sort int not null default 0, + status int not null default 1, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); + +-- product表字段注释 +comment on table product is '产品表'; +comment on column product.id is '产品ID'; +comment on column product.code is '产品代码'; +comment on column product.name is '产品名称'; +comment on column product.description is '产品描述'; +comment on column product.sort is '排序'; +comment on column product.status is '产品状态:1-正常,0-禁用'; +comment on column product.created_at is '创建时间'; +comment on column product.updated_at is '更新时间'; +comment on column product.deleted_at is '删除时间'; + +-- resource +drop table if exists resource cascade; +create table resource ( + id serial primary key, + user_id int not null references "user" (id) + on update cascade + on delete cascade, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); +create index resource_user_id_index on resource (user_id); + +-- resource表字段注释 +comment on table resource is '套餐表'; +comment on column resource.id is '套餐ID'; +comment on column resource.user_id is '用户ID'; +comment on column resource.created_at is '创建时间'; +comment on column resource.updated_at is '更新时间'; +comment on column resource.deleted_at is '删除时间'; + +-- resource_pss +drop table if exists resource_pss cascade; +create table resource_pss ( + id serial primary key, + resource_id int not null references resource (id) + on update cascade + on delete cascade, + active bool not null default false, + type int, + live int, + quota int, + used int, + expire timestamp, + limit_day int, + last_used timestamp, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); +create index resource_pss_resource_id_index on resource_pss (resource_id); + +-- resource_pss表字段注释 +comment on table resource_pss is '动态代理套餐表'; +comment on column resource_pss.id is 'ID'; +comment on column resource_pss.resource_id is '套餐ID'; +comment on column resource_pss.active is '是否启用'; +comment on column resource_pss.type is '套餐类型:1-包时,2-包量'; +comment on column resource_pss.live is '可用时长(秒)'; +comment on column resource_pss.quota is '配额数量'; +comment on column resource_pss.used is '已用数量'; +comment on column resource_pss.expire is '过期时间'; +comment on column resource_pss.limit_day is '每日限额'; +comment on column resource_pss.last_used is '最后提取时间'; +comment on column resource_pss.created_at is '创建时间'; +comment on column resource_pss.updated_at is '更新时间'; +comment on column resource_pss.deleted_at is '删除时间'; + +-- resource_psr +drop table if exists resource_psr cascade; +create table resource_psr ( + id serial primary key, + resource_id int not null references resource (id) + on update cascade + on delete cascade, + active bool not null default false, + live int, + conn int, + expire timestamp, + used bool, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); +create index resource_psr_resource_id_index on resource_psr (resource_id); + +-- resource_psr表字段注释 +comment on table resource_psr is '隧道代理套餐表'; +comment on column resource_psr.id is 'ID'; +comment on column resource_psr.resource_id is '套餐ID'; +comment on column resource_psr.active is '是否启用'; +comment on column resource_psr.live is '轮换周期(秒)'; +comment on column resource_psr.conn is '最大连接数'; +comment on column resource_psr.expire is '过期时间'; +comment on column resource_psr.used is '是否已使用'; +comment on column resource_psr.created_at is '创建时间'; +comment on column resource_psr.updated_at is '更新时间'; +comment on column resource_psr.deleted_at is '删除时间'; + +-- resource_pps +drop table if exists resource_pps cascade; +create table resource_pps ( + id serial primary key, + resource_id int not null references resource (id) + on update cascade + on delete cascade, + active bool not null default false, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); +create index resource_pps_resource_id_index on resource_pps (resource_id); + +-- resource_pps表字段注释 +comment on table resource_pps is '独享代理套餐表'; +comment on column resource_pps.id is 'ID'; +comment on column resource_pps.resource_id is '套餐ID'; +comment on column resource_pps.active is '是否启用'; +comment on column resource_pps.created_at is '创建时间'; +comment on column resource_pps.updated_at is '更新时间'; +comment on column resource_pps.deleted_at is '删除时间'; + +-- endregion + +-- ==================== +-- region 订单信息 +-- ==================== + +-- trade +drop table if exists trade cascade; +create table trade ( + id serial primary key, + user_id int not null references "user" (id) + on update cascade + on delete cascade, + inner_no varchar(255) not null unique, + outer_no varchar(255) not null unique, + subject varchar(255) not null, + remark varchar(255), + amount decimal(12, 2) not null default 0, + payment decimal(12, 2) not null default 0, + method int not null default 0, + status int not null default 0, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); +create index trade_user_id_index on trade (user_id); +create index trade_status_index on trade (status); + +-- trade表字段注释 +comment on table trade is '订单表'; +comment on column trade.id is '订单ID'; +comment on column trade.user_id is '用户ID'; +comment on column trade.inner_no is '内部订单号'; +comment on column trade.outer_no is '外部订单号'; +comment on column trade.subject is '订单主题'; +comment on column trade.remark is '订单备注'; +comment on column trade.amount is '订单总金额'; +comment on column trade.payment is '支付金额'; +comment on column trade.method is '支付方式:1-支付宝,2-微信'; +comment on column trade.status is '订单状态:0-待支付,1-已支付,2-已取消,3-已退款'; +comment on column trade.created_at is '创建时间'; +comment on column trade.updated_at is '更新时间'; +comment on column trade.deleted_at is '删除时间'; + +-- bill +drop table if exists bill cascade; +create table bill ( + id serial primary key, + order_id int not null references trade (id) + on update cascade + on delete cascade, + user_id int not null references "user" (id) + on update cascade + on delete cascade, + product_id int references product (id) -- + on update cascade -- + on delete set null, + info varchar(255), + count int default 0, + price decimal(12, 2) not null default 0, + amount decimal(12, 2) not null default 0, + payment decimal(12, 2) not null default 0, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); +create index bill_order_id_index on bill (order_id); +create index bill_product_id_index on bill (product_id); + +-- bill表字段注释 +comment on table bill is '账单表'; +comment on column bill.id is '账单ID'; +comment on column bill.order_id is '订单ID'; +comment on column bill.user_id is '用户ID'; +comment on column bill.product_id is '产品ID'; +comment on column bill.info is '产品可读信息'; +comment on column bill.count is '购买数量'; +comment on column bill.price is '单价'; +comment on column bill.amount is '总金额'; +comment on column bill.payment is '支付金额'; +comment on column bill.created_at is '创建时间'; +comment on column bill.updated_at is '更新时间'; +comment on column bill.deleted_at is '删除时间'; + +-- refund +drop table if exists refund cascade; +create table refund ( + id serial primary key, + order_id int not null references trade (id) + on update cascade + on delete cascade, + product_id int references product (id) -- + on update cascade -- + on delete set null, + amount decimal(12, 2) not null default 0, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + deleted_at timestamp +); +create index refund_order_id_index on refund (order_id); +create index refund_product_id_index on refund (product_id); + +-- refund表字段注释 +comment on table refund is '退款记录表'; +comment on column refund.id is '退款ID'; +comment on column refund.order_id is '订单ID'; +comment on column refund.product_id is '产品ID'; +comment on column refund.amount is '退款金额'; +comment on column refund.created_at is '创建时间'; +comment on column refund.updated_at is '更新时间'; +comment on column refund.deleted_at is '删除时间'; + +-- endregion \ No newline at end of file diff --git a/web/auth.go b/web/auth.go new file mode 100644 index 0000000..efb3895 --- /dev/null +++ b/web/auth.go @@ -0,0 +1 @@ +package web diff --git a/web/router.go b/web/router.go new file mode 100644 index 0000000..4a0a787 --- /dev/null +++ b/web/router.go @@ -0,0 +1,7 @@ +package web + +import "github.com/gofiber/fiber/v2" + +func UseRoute(app *fiber.App) { + +} diff --git a/web/web.go b/web/web.go new file mode 100644 index 0000000..a2893f1 --- /dev/null +++ b/web/web.go @@ -0,0 +1,54 @@ +package web + +import ( + "github.com/gofiber/fiber/v2" +) +import "log/slog" + +type Config struct { + Logger *slog.Logger + Listen string +} + +type Server struct { + config *Config + log *slog.Logger + fiber *fiber.App +} + +func New(config *Config) (*Server, error) { + _config := config + if config == nil { + _config = &Config{} + } + + if _config.Logger == nil { + _config.Logger = slog.Default() + } + + return &Server{ + config: _config, + log: _config.Logger, + }, nil +} + +func (s *Server) Run() error { + s.fiber = fiber.New(fiber.Config{}) + UseRoute(s.fiber) + + s.log.Info("Server started on :8080") + err := s.fiber.Listen(":8080") + if err != nil { + s.log.Error("Failed to start server", slog.Any("error", err)) + } + + s.log.Info("Server stopped") + return nil +} + +func (s *Server) Stop() { + err := s.fiber.Shutdown() + if err != nil { + s.log.Error("Failed to shutdown server", slog.Any("error", err)) + } +}