fix(fe/be): clean up and enable quota in ui
This commit is contained in:
parent
cdd15be4aa
commit
f986015c0b
11 changed files with 41 additions and 159 deletions
|
@ -15,6 +15,11 @@ server:
|
||||||
captchaWidth: 256
|
captchaWidth: 256
|
||||||
captchaHeight: 60
|
captchaHeight: 60
|
||||||
captchaEnabled: true
|
captchaEnabled: true
|
||||||
|
uploadSpeedLimit: 409600 # 400KB/limiterCyc
|
||||||
|
downloadSpeedLimit: 409600 # 400KB/limiterCyc
|
||||||
|
spaceLimit: 1024 # 1GB
|
||||||
|
limiterCapacity: 1000
|
||||||
|
limiterCyc: 1000 # 1s
|
||||||
users:
|
users:
|
||||||
enableAuth: true
|
enableAuth: true
|
||||||
defaultAdmin: ""
|
defaultAdmin: ""
|
||||||
|
|
|
@ -15,6 +15,11 @@ server:
|
||||||
captchaWidth: 256
|
captchaWidth: 256
|
||||||
captchaHeight: 60
|
captchaHeight: 60
|
||||||
captchaEnabled: true
|
captchaEnabled: true
|
||||||
|
uploadSpeedLimit: 102400 # 100k/limiterCyc
|
||||||
|
downloadSpeedLimit: 102400 # 100k/limiterCyc
|
||||||
|
spaceLimit: 1024 # 1GB
|
||||||
|
limiterCapacity: 1000
|
||||||
|
limiterCyc: 1000 # 1s
|
||||||
users:
|
users:
|
||||||
enableAuth: true
|
enableAuth: true
|
||||||
defaultAdmin: ""
|
defaultAdmin: ""
|
||||||
|
|
|
@ -3,11 +3,18 @@ import axios, { AxiosRequestConfig } from "axios";
|
||||||
export const defaultTimeout = 10000;
|
export const defaultTimeout = 10000;
|
||||||
export const userIDParam = "uid";
|
export const userIDParam = "uid";
|
||||||
|
|
||||||
|
export interface Quota {
|
||||||
|
spaceLimit: number;
|
||||||
|
uploadSpeedLimit: number;
|
||||||
|
downloadSpeedLimit: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface User {
|
export interface User {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
pwd: string;
|
pwd: string;
|
||||||
role: string;
|
role: string;
|
||||||
|
quota: Quota;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ListUsersResp {
|
export interface ListUsersResp {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import * as React from "react";
|
||||||
import { Map, Set } from "immutable";
|
import { Map, Set } from "immutable";
|
||||||
|
|
||||||
import { ICoreState } from "./core_state";
|
import { ICoreState } from "./core_state";
|
||||||
import { User } from "../client";
|
import { User, Quota } from "../client";
|
||||||
import { Updater as PanesUpdater } from "./panes";
|
import { Updater as PanesUpdater } from "./panes";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
@ -16,6 +16,7 @@ export interface UserFormProps {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
role: string;
|
role: string;
|
||||||
|
quota: Quota;
|
||||||
roles: Set<string>;
|
roles: Set<string>;
|
||||||
update?: (updater: (prevState: ICoreState) => ICoreState) => void;
|
update?: (updater: (prevState: ICoreState) => ICoreState) => void;
|
||||||
}
|
}
|
||||||
|
@ -102,9 +103,14 @@ export class UserForm extends React.Component<
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="bold item-name">Name: {this.props.name}</div>
|
<div className="bold item-name">
|
||||||
|
Name: {this.props.name} / ID: {this.props.id} / Role:{" "}
|
||||||
|
{this.props.role}
|
||||||
|
</div>
|
||||||
<div className="grey1-font item-name">
|
<div className="grey1-font item-name">
|
||||||
ID: {this.props.id} / Role: {this.props.role}
|
SpaceLimit: {this.props.quota.spaceLimit} / UploadSpeedLimit:{" "}
|
||||||
|
{this.props.quota.uploadSpeedLimit} / DownloadSpeedLimit:{" "}
|
||||||
|
{this.props.quota.downloadSpeedLimit}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -169,7 +175,6 @@ export class UserForm extends React.Component<
|
||||||
Update
|
Update
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -255,6 +260,7 @@ export class AdminPane extends React.Component<Props, State, {}> {
|
||||||
name: this.state.newUserName,
|
name: this.state.newUserName,
|
||||||
pwd: this.state.newUserPwd1,
|
pwd: this.state.newUserPwd1,
|
||||||
role: this.state.newUserRole,
|
role: this.state.newUserRole,
|
||||||
|
quota: undefined,
|
||||||
})
|
})
|
||||||
.then((ok: boolean) => {
|
.then((ok: boolean) => {
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
|
@ -282,6 +288,7 @@ export class AdminPane extends React.Component<Props, State, {}> {
|
||||||
id={user.id}
|
id={user.id}
|
||||||
name={user.name}
|
name={user.name}
|
||||||
role={user.role}
|
role={user.role}
|
||||||
|
quota={user.quota}
|
||||||
roles={this.props.roles}
|
roles={this.props.roles}
|
||||||
update={this.props.update}
|
update={this.props.update}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -2,7 +2,6 @@ package golimiter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
// "math"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -36,7 +35,6 @@ func (b *Bucket) Access(cyc, incr, decr int) bool {
|
||||||
After(now) {
|
After(now) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
fmt.Println(4)
|
|
||||||
b.token = incr - decr
|
b.token = incr - decr
|
||||||
b.refreshedAt = now
|
b.refreshedAt = now
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -42,144 +42,3 @@ func TestLimiter(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// var rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
||||||
|
|
||||||
// const rndCap = 10000
|
|
||||||
// const addCap = 1
|
|
||||||
|
|
||||||
// // how to set time
|
|
||||||
// // extend: wait can be greater than ttl/2
|
|
||||||
// // cyc is smaller than ttl and wait, then it can be clean in time
|
|
||||||
// const cap = 40
|
|
||||||
// const ttl = 3
|
|
||||||
// const cyc = 1
|
|
||||||
// const bucketCap = 2
|
|
||||||
// const id1 = "id1"
|
|
||||||
// const id2 = "id2"
|
|
||||||
// const op1 int16 = 0
|
|
||||||
// const op2 int16 = 1
|
|
||||||
|
|
||||||
// var customCaps = map[int16]int16{
|
|
||||||
// op2: 1000,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const wait = 1
|
|
||||||
|
|
||||||
// var limiter = New(cap, cyc, bucketCap)
|
|
||||||
|
|
||||||
// var idSeed = 0
|
|
||||||
|
|
||||||
// func randId() string {
|
|
||||||
// idSeed++
|
|
||||||
// return fmt.Sprintf("%d", idSeed)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func TestAccess(t *testing.T) {
|
|
||||||
// func(t *testing.T) {
|
|
||||||
// canAccess := limiter.Access(id1)
|
|
||||||
// if !canAccess {
|
|
||||||
// t.Fatal("access: fail")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for i := 0; i < bucketCap; i++ {
|
|
||||||
// canAccess = limiter.Access(id1)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if canAccess {
|
|
||||||
// t.Fatal("access: fail to deny access")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// time.Sleep(time.Duration(limiter.GetCyc()) * time.Second)
|
|
||||||
|
|
||||||
// canAccess = limiter.Access(id1)
|
|
||||||
// if !canAccess {
|
|
||||||
// t.Fatal("access: fail to refresh tokens")
|
|
||||||
// }
|
|
||||||
// }(t)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func TestCap(t *testing.T) {
|
|
||||||
// originalCap := limiter.GetCap()
|
|
||||||
// fmt.Printf("cap:info: %d\n", originalCap)
|
|
||||||
|
|
||||||
// ok := limiter.ExpandCap(originalCap + addCap)
|
|
||||||
|
|
||||||
// if !ok || limiter.GetCap() != originalCap+addCap {
|
|
||||||
// t.Fatal("cap: fail to expand")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// ok = limiter.ExpandCap(limiter.GetSize() - addCap)
|
|
||||||
// if ok {
|
|
||||||
// t.Fatal("cap: shrink cap")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// ids := []string{}
|
|
||||||
// for limiter.GetSize() < limiter.GetCap() {
|
|
||||||
// id := randId()
|
|
||||||
// ids = append(ids, id)
|
|
||||||
|
|
||||||
// ok := limiter.Access(id, 0)
|
|
||||||
// if !ok {
|
|
||||||
// t.Fatal("cap: not full")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if limiter.GetSize() != limiter.GetCap() {
|
|
||||||
// t.Fatal("cap: incorrect size")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if limiter.Access(randId(), 0) {
|
|
||||||
// t.Fatal("cap: more than cap")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// limiter.truncate()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func TestTtl(t *testing.T) {
|
|
||||||
// var addTtl int32 = 1
|
|
||||||
// originalTTL := limiter.GetTTL()
|
|
||||||
// fmt.Printf("ttl:info: %d\n", originalTTL)
|
|
||||||
|
|
||||||
// limiter.UpdateTTL(originalTTL + addTtl)
|
|
||||||
// if limiter.GetTTL() != originalTTL+addTtl {
|
|
||||||
// t.Fatal("ttl: update fail")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func cycTest(t *testing.T) {
|
|
||||||
// var addCyc int32 = 1
|
|
||||||
// originalCyc := limiter.GetCyc()
|
|
||||||
// fmt.Printf("cyc:info: %d\n", originalCyc)
|
|
||||||
|
|
||||||
// limiter.UpdateCyc(originalCyc + addCyc)
|
|
||||||
// if limiter.GetCyc() != originalCyc+addCyc {
|
|
||||||
// t.Fatal("cyc: update fail")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func autoCleanTest(t *testing.T) {
|
|
||||||
// ids := []string{
|
|
||||||
// randId(),
|
|
||||||
// randId(),
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for _, id := range ids {
|
|
||||||
// ok := limiter.Access(id, 0)
|
|
||||||
// if ok {
|
|
||||||
// t.Fatal("autoClean: warning: add fail")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// time.Sleep(time.Duration(limiter.GetTTL()+wait) * time.Second)
|
|
||||||
|
|
||||||
// for _, id := range ids {
|
|
||||||
// _, exist := limiter.get(id)
|
|
||||||
// if exist {
|
|
||||||
// t.Fatal("autoClean: item still exist")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func snapshotTest(t *testing.T) {
|
|
||||||
// }
|
|
||||||
|
|
|
@ -301,7 +301,7 @@ func (h *FileHandlers) UploadChunk(c *gin.Context) {
|
||||||
c.JSON(q.ErrResp(c, 500, err))
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
return
|
return
|
||||||
} else if !ok {
|
} else if !ok {
|
||||||
c.JSON(q.ErrResp(c, 503, errors.New("retry later")))
|
c.JSON(q.ErrResp(c, 429, errors.New("retry later")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -354,18 +354,15 @@ func (h *MultiUsersSvc) AddUser(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
spaceLimit := h.cfg.IntOr("Users.SpaceLimit", 1024)
|
|
||||||
uploadSpeedLimit := h.cfg.IntOr("Users.UploadSpeedLimit", 100*1024)
|
|
||||||
downloadSpeedLimit := h.cfg.IntOr("Users.DownloadSpeedLimit", 100*1024)
|
|
||||||
err = h.deps.Users().AddUser(&userstore.User{
|
err = h.deps.Users().AddUser(&userstore.User{
|
||||||
ID: uid,
|
ID: uid,
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Pwd: string(pwdHash),
|
Pwd: string(pwdHash),
|
||||||
Role: req.Role,
|
Role: req.Role,
|
||||||
Quota: &userstore.Quota{
|
Quota: &userstore.Quota{
|
||||||
SpaceLimit: spaceLimit,
|
SpaceLimit: h.cfg.IntOr("Users.SpaceLimit", 1024),
|
||||||
UploadSpeedLimit: uploadSpeedLimit,
|
UploadSpeedLimit: h.cfg.IntOr("Users.UploadSpeedLimit", 100*1024),
|
||||||
DownloadSpeedLimit: downloadSpeedLimit,
|
DownloadSpeedLimit: h.cfg.IntOr("Users.DownloadSpeedLimit", 100*1024),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -23,6 +23,8 @@ type UsersCfg struct {
|
||||||
UploadSpeedLimit int `json:"uploadSpeedLimit" yaml:"uploadSpeedLimit"`
|
UploadSpeedLimit int `json:"uploadSpeedLimit" yaml:"uploadSpeedLimit"`
|
||||||
DownloadSpeedLimit int `json:"downloadSpeedLimit" yaml:"downloadSpeedLimit"`
|
DownloadSpeedLimit int `json:"downloadSpeedLimit" yaml:"downloadSpeedLimit"`
|
||||||
SpaceLimit int `json:"spaceLimit" yaml:"spaceLimit"`
|
SpaceLimit int `json:"spaceLimit" yaml:"spaceLimit"`
|
||||||
|
LimiterCapacity int `json:"limiterCapacity" yaml:"limiterCapacity"`
|
||||||
|
LimiterCyc int `json:"limiterCyc" yaml:"limiterCyc"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Secrets struct {
|
type Secrets struct {
|
||||||
|
@ -72,6 +74,8 @@ func DefaultConfig() (string, error) {
|
||||||
UploadSpeedLimit: 100 * 1024, // B
|
UploadSpeedLimit: 100 * 1024, // B
|
||||||
DownloadSpeedLimit: 100 * 1024, // B
|
DownloadSpeedLimit: 100 * 1024, // B
|
||||||
SpaceLimit: 1024, // GB
|
SpaceLimit: 1024, // GB
|
||||||
|
LimiterCapacity: 1000,
|
||||||
|
LimiterCyc: 1000, // 1s
|
||||||
},
|
},
|
||||||
Secrets: &Secrets{
|
Secrets: &Secrets{
|
||||||
TokenSecret: "",
|
TokenSecret: "",
|
||||||
|
|
|
@ -105,8 +105,8 @@ func initDeps(cfg gocfg.ICfg) *depidx.Deps {
|
||||||
panic(fmt.Sprintf("fail to init user store: %s", err))
|
panic(fmt.Sprintf("fail to init user store: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
limiterCap := cfg.IntOr("Users.LimiterCapacity", 4096)
|
limiterCap := cfg.IntOr("Users.LimiterCapacity", 10000)
|
||||||
limiterCyc := cfg.IntOr("Users.LimiterCyc", 3000)
|
limiterCyc := cfg.IntOr("Users.LimiterCyc", 1000)
|
||||||
limiter := iolimiter.NewIOLimiter(limiterCap, limiterCyc, users)
|
limiter := iolimiter.NewIOLimiter(limiterCap, limiterCyc, users)
|
||||||
|
|
||||||
deps := depidx.NewDeps(cfg)
|
deps := depidx.NewDeps(cfg)
|
||||||
|
|
|
@ -20,9 +20,9 @@ const (
|
||||||
RoleListNs = "roleList"
|
RoleListNs = "roleList"
|
||||||
InitTimeKey = "initTime"
|
InitTimeKey = "initTime"
|
||||||
|
|
||||||
defaultSpaceLimit = 1024 // 1GB
|
defaultSpaceLimit = 1024 // 1GB
|
||||||
defaultUploadSpeedLimit = 100 * 1024 // 100KB
|
defaultUploadSpeedLimit = 50 * 1024 * 1024 // 50MB
|
||||||
defaultDownloadSpeedLimit = 100 * 1024 // 100KB
|
defaultDownloadSpeedLimit = 50 * 1024 * 1024 // 50MB
|
||||||
)
|
)
|
||||||
|
|
||||||
type Quota struct {
|
type Quota struct {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue