init: 0.1.2
feat: login page && auth required todo: file dir cleanup
This commit is contained in:
@ -4,10 +4,14 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/loveuer/nf/nft/log"
|
||||
"github.com/loveuer/ushare/internal/model"
|
||||
"github.com/loveuer/ushare/internal/opt"
|
||||
gonanoid "github.com/matoous/go-nanoid/v2"
|
||||
"github.com/spf13/viper"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@ -19,12 +23,12 @@ type metaInfo struct {
|
||||
last time.Time
|
||||
size int64
|
||||
cursor int64
|
||||
ip string
|
||||
user string
|
||||
}
|
||||
|
||||
func (m *metaInfo) generateMeta(code string) error {
|
||||
content := fmt.Sprintf("filename=%s\ncreated_at=%d\nsize=%d\nuploader_ip=%s",
|
||||
m.name, m.create.UnixMilli(), m.size, m.ip,
|
||||
content := fmt.Sprintf("filename=%s\ncreated_at=%d\nsize=%d\nuploader=%s",
|
||||
m.name, m.create.UnixMilli(), m.size, m.user,
|
||||
)
|
||||
|
||||
return os.WriteFile(opt.MetaPath(code), []byte(content), 0644)
|
||||
@ -62,7 +66,7 @@ func (m *meta) New(size int64, filename, ip string) (string, error) {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
m.m[code] = &metaInfo{f: f, name: filename, last: now, size: size, cursor: 0, create: now, ip: ip}
|
||||
m.m[code] = &metaInfo{f: f, name: filename, last: now, size: size, cursor: 0, create: now, user: ip}
|
||||
|
||||
return code, nil
|
||||
}
|
||||
@ -100,6 +104,7 @@ func (m *meta) Start(ctx context.Context) {
|
||||
ticker := time.NewTicker(time.Minute)
|
||||
m.ctx = ctx
|
||||
|
||||
// 清理 2 分钟内没有继续上传的 part
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
@ -107,7 +112,7 @@ func (m *meta) Start(ctx context.Context) {
|
||||
return
|
||||
case now := <-ticker.C:
|
||||
for code, info := range m.m {
|
||||
if now.Sub(info.last) > 1*time.Minute {
|
||||
if now.Sub(info.last) > 2*time.Minute {
|
||||
m.Lock()
|
||||
if err := info.f.Close(); err != nil {
|
||||
log.Warn("handler.Meta: [timer] close file failed, file = %s, err = %s", opt.FilePath(code), err.Error())
|
||||
@ -123,4 +128,57 @@ func (m *meta) Start(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// 清理一天前的文件
|
||||
go func() {
|
||||
ticker := time.NewTicker(5 * time.Minute)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case now := <-ticker.C:
|
||||
_ = filepath.Walk(opt.Cfg.DataPath, func(path string, info os.FileInfo, err error) error {
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
name := filepath.Base(info.Name())
|
||||
if !strings.HasPrefix(name, ".meta.") {
|
||||
return nil
|
||||
}
|
||||
|
||||
viper.SetConfigFile(path)
|
||||
viper.SetConfigType("env")
|
||||
if err = viper.ReadInConfig(); err != nil {
|
||||
// todo log
|
||||
return nil
|
||||
}
|
||||
|
||||
mi := new(model.Meta)
|
||||
|
||||
if err = viper.Unmarshal(mi); err != nil {
|
||||
// todo log
|
||||
return nil
|
||||
}
|
||||
|
||||
code := strings.TrimPrefix(name, ".meta.")
|
||||
|
||||
if now.Sub(time.UnixMilli(mi.CreatedAt)) > 24*time.Hour {
|
||||
|
||||
log.Debug("controller.meta: file out of date, code = %s, user_key = %s", code, mi.Uploader)
|
||||
|
||||
os.RemoveAll(opt.FilePath(code))
|
||||
os.RemoveAll(path)
|
||||
|
||||
m.Lock()
|
||||
delete(m.m, code)
|
||||
m.Unlock()
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
86
internal/controller/user.go
Normal file
86
internal/controller/user.go
Normal file
@ -0,0 +1,86 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/loveuer/ushare/internal/model"
|
||||
"github.com/loveuer/ushare/internal/opt"
|
||||
"github.com/loveuer/ushare/internal/pkg/tool"
|
||||
"github.com/pkg/errors"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type userManager struct {
|
||||
sync.Mutex
|
||||
ctx context.Context
|
||||
um map[string]*model.User
|
||||
}
|
||||
|
||||
func (um *userManager) Login(username string, password string) (*model.User, error) {
|
||||
var (
|
||||
now = time.Now()
|
||||
)
|
||||
|
||||
if username != "admin" {
|
||||
return nil, errors.New("账号或密码错误")
|
||||
}
|
||||
|
||||
if !tool.ComparePassword(password, opt.Cfg.Auth) {
|
||||
return nil, errors.New("账号或密码错误")
|
||||
}
|
||||
|
||||
op := &model.User{
|
||||
Id: 1,
|
||||
Username: username,
|
||||
LoginAt: now.Unix(),
|
||||
Token: tool.RandomString(32),
|
||||
}
|
||||
|
||||
um.Lock()
|
||||
defer um.Unlock()
|
||||
um.um[op.Token] = op
|
||||
|
||||
return op, nil
|
||||
}
|
||||
|
||||
func (um *userManager) Verify(token string) (*model.User, error) {
|
||||
um.Lock()
|
||||
defer um.Unlock()
|
||||
|
||||
op, ok := um.um[token]
|
||||
if !ok {
|
||||
return nil, errors.New("未登录或凭证已失效, 请重新登录")
|
||||
}
|
||||
|
||||
return op, nil
|
||||
}
|
||||
|
||||
func (um *userManager) Start(ctx context.Context) {
|
||||
um.ctx = ctx
|
||||
|
||||
go func() {
|
||||
|
||||
ticker := time.NewTicker(time.Minute)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-um.ctx.Done():
|
||||
return
|
||||
case now := <-ticker.C:
|
||||
um.Lock()
|
||||
for _, op := range um.um {
|
||||
if now.Sub(time.UnixMilli(op.LoginAt)) > 8*time.Hour {
|
||||
delete(um.um, op.Token)
|
||||
}
|
||||
}
|
||||
um.Unlock()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
var (
|
||||
UserManager = &userManager{
|
||||
um: make(map[string]*model.User),
|
||||
}
|
||||
)
|
Reference in New Issue
Block a user