updated vmail
This commit is contained in:
parent
3e8fc9f73e
commit
688846b6c9
1
go.mod
1
go.mod
@ -3,6 +3,7 @@ module git.paulbsd.com/paulbsd/vmail
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d
|
||||
github.com/labstack/echo v3.3.10+incompatible // indirect
|
||||
github.com/labstack/echo/v4 v4.1.16
|
||||
github.com/lib/pq v1.7.0
|
||||
|
2
go.sum
2
go.sum
@ -8,6 +8,8 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
|
12
src/api/admin.go
Normal file
12
src/api/admin.go
Normal file
@ -0,0 +1,12 @@
|
||||
package api
|
||||
|
||||
// Admin defines the admin struct
|
||||
type Admin struct {
|
||||
Username string `json:"username"`
|
||||
Created string `json:"created"`
|
||||
Modified string `json:"modified"`
|
||||
Active bool `json:"active"`
|
||||
Superadmin bool `json:"superadmin"`
|
||||
Phone string `json:"phone"`
|
||||
EmailOther string `json:"emailOther"`
|
||||
}
|
11
src/api/alias.go
Normal file
11
src/api/alias.go
Normal file
@ -0,0 +1,11 @@
|
||||
package api
|
||||
|
||||
// Alias defines the admin struct
|
||||
type Alias struct {
|
||||
Address string `json:"address"`
|
||||
Goto string `json:"goto"`
|
||||
Domain string `json:"domain"`
|
||||
Created string `json:"created"`
|
||||
Modified string `json:"modified"`
|
||||
Active bool `json:"active"`
|
||||
}
|
11
src/api/log.go
Normal file
11
src/api/log.go
Normal file
@ -0,0 +1,11 @@
|
||||
package api
|
||||
|
||||
// Log defines the admin struct
|
||||
type Log struct {
|
||||
ID int `json:"id"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
Username string `json:"username"`
|
||||
Domain string `json:"domain"`
|
||||
Action string `json:"action"`
|
||||
Data string `json:"data"`
|
||||
}
|
16
src/api/mailbox.go
Normal file
16
src/api/mailbox.go
Normal file
@ -0,0 +1,16 @@
|
||||
package api
|
||||
|
||||
// Mailbox defines the admin struct
|
||||
type Mailbox struct {
|
||||
Username string `json:"username"`
|
||||
Name string `json:"name"`
|
||||
Maildir string `json:"maildir"`
|
||||
Quota string `json:"quota"`
|
||||
Created string `json:"created"`
|
||||
Modified string `json:"modified"`
|
||||
Active bool `json:"active"`
|
||||
Domain string `json:"domain"`
|
||||
LocalPart string `json:"localpart"`
|
||||
Phone string `json:"phone"`
|
||||
EmailOther string `json:"emailother"`
|
||||
}
|
@ -40,14 +40,13 @@ func (config *Config) GetConfig() error {
|
||||
|
||||
// Config is the global config of vmail
|
||||
type Config struct {
|
||||
Db *xorm.Engine
|
||||
DbHostname string
|
||||
DbName string
|
||||
DbUsername string
|
||||
DbPassword string
|
||||
URLBase string
|
||||
vmailGroups []string
|
||||
Port int
|
||||
Init bool
|
||||
Version string
|
||||
Db *xorm.Engine
|
||||
DbHostname string
|
||||
DbName string
|
||||
DbUsername string
|
||||
DbPassword string
|
||||
URLBase string
|
||||
Port int
|
||||
Init bool
|
||||
Version string
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ func Initialize(ctx *context.Context, config *config.Config) (err error) {
|
||||
}
|
||||
|
||||
config.Db.SetMapper(names.GonicMapper{})
|
||||
config.Db.ShowSQL(false)
|
||||
config.Db.ShowSQL(true)
|
||||
|
||||
err = models.NewEngine(ctx, config)
|
||||
|
||||
|
@ -4,25 +4,57 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.paulbsd.com/paulbsd/vmail/src/api"
|
||||
"git.paulbsd.com/paulbsd/vmail/src/config"
|
||||
)
|
||||
|
||||
// GetAdmins ...
|
||||
func GetAdmins(ctx *context.Context, config *config.Config) (admins []Admin, err error) {
|
||||
err = config.Db.Cols("username").Find(&admins)
|
||||
// GetAdmins return list of apiadmins
|
||||
func GetAdmins(ctx *context.Context, config *config.Config) (apiadmins []*api.Admin, err error) {
|
||||
var admins []Admin
|
||||
err = config.Db.Find(&admins)
|
||||
for _, adm := range admins {
|
||||
apiadmins = append(apiadmins, adm.APIFormat())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetAdmin ...
|
||||
func GetAdmin(ctx *context.Context, config *config.Config, id interface{}) (apiadmin *api.Admin, err error) {
|
||||
var admin Admin
|
||||
has, err := config.Db.Where("username = ?", id).Get(&admin)
|
||||
if !has || err != nil {
|
||||
return
|
||||
}
|
||||
apiadmin = admin.APIFormat()
|
||||
return
|
||||
}
|
||||
|
||||
// APIFormat returns a JSON formatted object of Admin
|
||||
func (admin *Admin) APIFormat() *api.Admin {
|
||||
if admin == nil {
|
||||
return nil
|
||||
}
|
||||
return &api.Admin{
|
||||
Username: admin.Username,
|
||||
Created: admin.Created.Format(timetostring),
|
||||
Modified: admin.Modified.Format(timetostring),
|
||||
Active: admin.Active,
|
||||
Superadmin: admin.Superadmin,
|
||||
Phone: admin.Phone,
|
||||
EmailOther: admin.EmailOther,
|
||||
}
|
||||
}
|
||||
|
||||
// Admin defines the admin struct
|
||||
type Admin struct {
|
||||
Username string `xorm:"not null pk unique VARCHAR(255)"`
|
||||
password string `xorm:"not null default '' VARCHAR(255)"`
|
||||
Password string `xorm:"not null default '' VARCHAR(255)"`
|
||||
Created time.Time `xorm:"default now() TIMESTAMPZ"`
|
||||
Modified time.Time `xorm:"default now() TIMESTAMPZ"`
|
||||
Active bool `xorm:"not null default true BOOL"`
|
||||
Superadmin bool `xorm:"not null default false BOOL"`
|
||||
Phone string `xorm:"not null default '' VARCHAR(30)"`
|
||||
EmailOther string `xorm:"not null default '' VARCHAR(255)"`
|
||||
token string `xorm:"not null default '' VARCHAR(255)"`
|
||||
tokenValidity time.Time `xorm:"default '2000-01-01 00:00:00+01' TIMESTAMPZ"`
|
||||
Token string `xorm:"not null default '' VARCHAR(255)"`
|
||||
TokenValidity time.Time `xorm:"default '2000-01-01 00:00:00+01' TIMESTAMPZ"`
|
||||
}
|
||||
|
@ -4,15 +4,46 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.paulbsd.com/paulbsd/vmail/src/api"
|
||||
"git.paulbsd.com/paulbsd/vmail/src/config"
|
||||
)
|
||||
|
||||
// GetAliases ...
|
||||
func GetAliases(ctx *context.Context, config *config.Config) (aliases []Alias, err error) {
|
||||
err = config.Db.Cols("address").Find(&aliases)
|
||||
func GetAliases(ctx *context.Context, config *config.Config) (apialiases []*api.Alias, err error) {
|
||||
var aliases []Alias
|
||||
err = config.Db.Find(&aliases)
|
||||
for _, al := range aliases {
|
||||
apialiases = append(apialiases, al.APIFormat())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetAlias ...
|
||||
func GetAlias(ctx *context.Context, config *config.Config, id interface{}) (apialias *api.Alias, err error) {
|
||||
var alias Alias
|
||||
has, err := config.Db.Where("username = ?", id).Get(&alias)
|
||||
if !has || err != nil {
|
||||
return
|
||||
}
|
||||
apialias = alias.APIFormat()
|
||||
return
|
||||
}
|
||||
|
||||
// APIFormat returns a JSON formatted object of Admin
|
||||
func (alias *Alias) APIFormat() *api.Alias {
|
||||
if alias == nil {
|
||||
return nil
|
||||
}
|
||||
return &api.Alias{
|
||||
Address: alias.Address,
|
||||
Goto: alias.Goto,
|
||||
Domain: alias.Domain,
|
||||
Created: alias.Created.Format(timetostring),
|
||||
Modified: alias.Modified.Format(timetostring),
|
||||
Active: alias.Active,
|
||||
}
|
||||
}
|
||||
|
||||
// Alias defines the admin struct
|
||||
type Alias struct {
|
||||
Address string `xorm:"not null pk index(alias_address_active) unique VARCHAR(255)"`
|
||||
|
@ -1,12 +1,44 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.paulbsd.com/paulbsd/vmail/src/api"
|
||||
"git.paulbsd.com/paulbsd/vmail/src/config"
|
||||
)
|
||||
|
||||
// GetLogs return list of Log
|
||||
func GetLogs(ctx *context.Context, config *config.Config) (apilogs []*api.Log, err error) {
|
||||
var logs []Log
|
||||
err = config.Db.Find(&logs)
|
||||
for _, log := range logs {
|
||||
apilogs = append(apilogs, log.APIFormat())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// APIFormat returns a JSON formatted object of Admin
|
||||
func (log *Log) APIFormat() *api.Log {
|
||||
if log == nil {
|
||||
return nil
|
||||
}
|
||||
return &api.Log{
|
||||
Timestamp: log.Timestamp.Format(timetostring),
|
||||
Username: log.Username,
|
||||
Domain: log.Domain,
|
||||
Action: log.Action,
|
||||
Data: log.Data,
|
||||
ID: log.ID,
|
||||
}
|
||||
}
|
||||
|
||||
// Log ...
|
||||
type Log struct {
|
||||
ID int `xorm:"not null pk autoincr INTEGER"`
|
||||
Timestamp time.Time `xorm:"default now() index(log_domain_timestamp_idx) TIMESTAMPZ"`
|
||||
Username string `xorm:"not null default '' VARCHAR(255)"`
|
||||
Domain string `xorm:"not null default '' index(log_domain_timestamp_idx) VARCHAR(255)"`
|
||||
Action string `xorm:"not null default '' VARCHAR(255)"`
|
||||
Data string `xorm:"not null default '' TEXT"`
|
||||
Id int `xorm:"not null pk autoincr INTEGER"`
|
||||
}
|
||||
|
@ -4,15 +4,52 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.paulbsd.com/paulbsd/vmail/src/api"
|
||||
"git.paulbsd.com/paulbsd/vmail/src/config"
|
||||
)
|
||||
|
||||
// GetMailboxes ...
|
||||
func GetMailboxes(ctx *context.Context, config *config.Config) (mailboxes []Mailbox, err error) {
|
||||
err = config.Db.Cols("username").Find(&mailboxes)
|
||||
func GetMailboxes(ctx *context.Context, config *config.Config) (apimailboxes []*api.Mailbox, err error) {
|
||||
var mailboxes []Mailbox
|
||||
err = config.Db.Find(&mailboxes)
|
||||
for _, ml := range mailboxes {
|
||||
apimailboxes = append(apimailboxes, ml.APIFormat())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetMailbox ...
|
||||
func GetMailbox(ctx *context.Context, config *config.Config, id interface{}) (apimailbox *api.Mailbox, err error) {
|
||||
var mailbox Mailbox
|
||||
has, err := config.Db.Where("username = ?", id).Get(&mailbox)
|
||||
if !has || err != nil {
|
||||
return
|
||||
}
|
||||
apimailbox = mailbox.APIFormat()
|
||||
return
|
||||
}
|
||||
|
||||
// APIFormat returns a JSON formatted object of Admin
|
||||
func (mailbox *Mailbox) APIFormat() *api.Mailbox {
|
||||
if mailbox == nil {
|
||||
return nil
|
||||
}
|
||||
return &api.Mailbox{
|
||||
Username: mailbox.Username,
|
||||
Name: mailbox.Name,
|
||||
Maildir: mailbox.Maildir,
|
||||
Quota: quotaFormat(mailbox.Quota),
|
||||
Created: mailbox.Created.Format(timetostring),
|
||||
Modified: mailbox.Modified.Format(timetostring),
|
||||
Active: mailbox.Active,
|
||||
Domain: mailbox.Domain,
|
||||
LocalPart: mailbox.LocalPart,
|
||||
Phone: mailbox.Phone,
|
||||
EmailOther: mailbox.EmailOther,
|
||||
}
|
||||
}
|
||||
|
||||
// Mailbox ...
|
||||
type Mailbox struct {
|
||||
Username string `xorm:"not null pk unique index(mailbox_username_active) VARCHAR(255)"`
|
||||
Password string `xorm:"not null default '' VARCHAR(255)"`
|
||||
|
18
src/models/utils.go
Normal file
18
src/models/utils.go
Normal file
@ -0,0 +1,18 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/alecthomas/units"
|
||||
)
|
||||
|
||||
const timetostring = "02/01/2006 15:04"
|
||||
|
||||
func quotaFormat(in int64) (out string) {
|
||||
var converted units.Base2Bytes
|
||||
converted, err := units.ParseBase2Bytes(fmt.Sprintf("%d%s", in, "B"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return converted.String()
|
||||
}
|
@ -23,11 +23,7 @@ func RunServer(ctx *context.Context, cfg *config.Config) (err error) {
|
||||
}))
|
||||
|
||||
e.GET("/", func(c echo.Context) (err error) {
|
||||
return c.HTML(http.StatusOK, "Welcome to Vmail")
|
||||
})
|
||||
e.GET("menu", func(c echo.Context) (err error) {
|
||||
ret := []string{"admins", "domains", "mailboxes"}
|
||||
return c.JSON(http.StatusOK, ret)
|
||||
return c.HTML(http.StatusOK, "Welcome to Vmail API")
|
||||
})
|
||||
e.POST("/auth", func(c echo.Context) (err error) {
|
||||
return c.String(http.StatusOK, "/auth")
|
||||
@ -36,6 +32,7 @@ func RunServer(ctx *context.Context, cfg *config.Config) (err error) {
|
||||
return c.JSON(http.StatusOK, "/api")
|
||||
})
|
||||
|
||||
// Admins
|
||||
e.GET("/api/admin", func(c echo.Context) (err error) {
|
||||
admins, err := models.GetAdmins(ctx, cfg)
|
||||
return c.JSON(http.StatusOK, admins)
|
||||
@ -45,15 +42,7 @@ func RunServer(ctx *context.Context, cfg *config.Config) (err error) {
|
||||
return c.JSON(http.StatusOK, admins)
|
||||
})
|
||||
|
||||
e.GET("/api/mailbox", func(c echo.Context) (err error) {
|
||||
mailboxes, err := models.GetMailboxes(ctx, cfg)
|
||||
return c.JSON(http.StatusOK, mailboxes)
|
||||
})
|
||||
e.GET("/api/mailbox/:id", func(c echo.Context) (err error) {
|
||||
mailboxes, err := models.GetMailboxes(ctx, cfg)
|
||||
return c.JSON(http.StatusOK, mailboxes)
|
||||
})
|
||||
|
||||
// Aliases
|
||||
e.GET("/api/alias", func(c echo.Context) (err error) {
|
||||
aliases, err := models.GetAliases(ctx, cfg)
|
||||
return c.JSON(http.StatusOK, aliases)
|
||||
@ -63,6 +52,22 @@ func RunServer(ctx *context.Context, cfg *config.Config) (err error) {
|
||||
return c.JSON(http.StatusOK, aliases)
|
||||
})
|
||||
|
||||
// Mailboxes
|
||||
e.GET("/api/mailbox", func(c echo.Context) (err error) {
|
||||
mailboxes, err := models.GetMailboxes(ctx, cfg)
|
||||
return c.JSON(http.StatusOK, mailboxes)
|
||||
})
|
||||
e.GET("/api/mailbox/:id", func(c echo.Context) (err error) {
|
||||
mailbox, err := models.GetMailbox(ctx, cfg, c.Param("id"))
|
||||
return c.JSON(http.StatusOK, mailbox)
|
||||
})
|
||||
|
||||
// Logs
|
||||
e.GET("/api/log", func(c echo.Context) (err error) {
|
||||
logs, err := models.GetLogs(ctx, cfg)
|
||||
return c.JSON(http.StatusOK, logs)
|
||||
})
|
||||
|
||||
e.Logger.Fatal(e.Start(fmt.Sprintf(":%d", cfg.Port)))
|
||||
return
|
||||
}
|
||||
|
19
vendor/github.com/alecthomas/units/COPYING
generated
vendored
Normal file
19
vendor/github.com/alecthomas/units/COPYING
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (C) 2014 Alec Thomas
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
11
vendor/github.com/alecthomas/units/README.md
generated
vendored
Normal file
11
vendor/github.com/alecthomas/units/README.md
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
# Units - Helpful unit multipliers and functions for Go
|
||||
|
||||
The goal of this package is to have functionality similar to the [time](http://golang.org/pkg/time/) package.
|
||||
|
||||
It allows for code like this:
|
||||
|
||||
```go
|
||||
n, err := ParseBase2Bytes("1KB")
|
||||
// n == 1024
|
||||
n = units.Mebibyte * 512
|
||||
```
|
85
vendor/github.com/alecthomas/units/bytes.go
generated
vendored
Normal file
85
vendor/github.com/alecthomas/units/bytes.go
generated
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
package units
|
||||
|
||||
// Base2Bytes is the old non-SI power-of-2 byte scale (1024 bytes in a kilobyte,
|
||||
// etc.).
|
||||
type Base2Bytes int64
|
||||
|
||||
// Base-2 byte units.
|
||||
const (
|
||||
Kibibyte Base2Bytes = 1024
|
||||
KiB = Kibibyte
|
||||
Mebibyte = Kibibyte * 1024
|
||||
MiB = Mebibyte
|
||||
Gibibyte = Mebibyte * 1024
|
||||
GiB = Gibibyte
|
||||
Tebibyte = Gibibyte * 1024
|
||||
TiB = Tebibyte
|
||||
Pebibyte = Tebibyte * 1024
|
||||
PiB = Pebibyte
|
||||
Exbibyte = Pebibyte * 1024
|
||||
EiB = Exbibyte
|
||||
)
|
||||
|
||||
var (
|
||||
bytesUnitMap = MakeUnitMap("iB", "B", 1024)
|
||||
oldBytesUnitMap = MakeUnitMap("B", "B", 1024)
|
||||
)
|
||||
|
||||
// ParseBase2Bytes supports both iB and B in base-2 multipliers. That is, KB
|
||||
// and KiB are both 1024.
|
||||
// However "kB", which is the correct SI spelling of 1000 Bytes, is rejected.
|
||||
func ParseBase2Bytes(s string) (Base2Bytes, error) {
|
||||
n, err := ParseUnit(s, bytesUnitMap)
|
||||
if err != nil {
|
||||
n, err = ParseUnit(s, oldBytesUnitMap)
|
||||
}
|
||||
return Base2Bytes(n), err
|
||||
}
|
||||
|
||||
func (b Base2Bytes) String() string {
|
||||
return ToString(int64(b), 1024, "iB", "B")
|
||||
}
|
||||
|
||||
var (
|
||||
metricBytesUnitMap = MakeUnitMap("B", "B", 1000)
|
||||
)
|
||||
|
||||
// MetricBytes are SI byte units (1000 bytes in a kilobyte).
|
||||
type MetricBytes SI
|
||||
|
||||
// SI base-10 byte units.
|
||||
const (
|
||||
Kilobyte MetricBytes = 1000
|
||||
KB = Kilobyte
|
||||
Megabyte = Kilobyte * 1000
|
||||
MB = Megabyte
|
||||
Gigabyte = Megabyte * 1000
|
||||
GB = Gigabyte
|
||||
Terabyte = Gigabyte * 1000
|
||||
TB = Terabyte
|
||||
Petabyte = Terabyte * 1000
|
||||
PB = Petabyte
|
||||
Exabyte = Petabyte * 1000
|
||||
EB = Exabyte
|
||||
)
|
||||
|
||||
// ParseMetricBytes parses base-10 metric byte units. That is, KB is 1000 bytes.
|
||||
func ParseMetricBytes(s string) (MetricBytes, error) {
|
||||
n, err := ParseUnit(s, metricBytesUnitMap)
|
||||
return MetricBytes(n), err
|
||||
}
|
||||
|
||||
// TODO: represents 1000B as uppercase "KB", while SI standard requires "kB".
|
||||
func (m MetricBytes) String() string {
|
||||
return ToString(int64(m), 1000, "B", "B")
|
||||
}
|
||||
|
||||
// ParseStrictBytes supports both iB and B suffixes for base 2 and metric,
|
||||
// respectively. That is, KiB represents 1024 and kB, KB represent 1000.
|
||||
func ParseStrictBytes(s string) (int64, error) {
|
||||
n, err := ParseUnit(s, bytesUnitMap)
|
||||
if err != nil {
|
||||
n, err = ParseUnit(s, metricBytesUnitMap)
|
||||
}
|
||||
return int64(n), err
|
||||
}
|
13
vendor/github.com/alecthomas/units/doc.go
generated
vendored
Normal file
13
vendor/github.com/alecthomas/units/doc.go
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
// Package units provides helpful unit multipliers and functions for Go.
|
||||
//
|
||||
// The goal of this package is to have functionality similar to the time [1] package.
|
||||
//
|
||||
//
|
||||
// [1] http://golang.org/pkg/time/
|
||||
//
|
||||
// It allows for code like this:
|
||||
//
|
||||
// n, err := ParseBase2Bytes("1KB")
|
||||
// // n == 1024
|
||||
// n = units.Mebibyte * 512
|
||||
package units
|
3
vendor/github.com/alecthomas/units/go.mod
generated
vendored
Normal file
3
vendor/github.com/alecthomas/units/go.mod
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
module github.com/alecthomas/units
|
||||
|
||||
require github.com/stretchr/testify v1.4.0
|
11
vendor/github.com/alecthomas/units/go.sum
generated
vendored
Normal file
11
vendor/github.com/alecthomas/units/go.sum
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
50
vendor/github.com/alecthomas/units/si.go
generated
vendored
Normal file
50
vendor/github.com/alecthomas/units/si.go
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
package units
|
||||
|
||||
// SI units.
|
||||
type SI int64
|
||||
|
||||
// SI unit multiples.
|
||||
const (
|
||||
Kilo SI = 1000
|
||||
Mega = Kilo * 1000
|
||||
Giga = Mega * 1000
|
||||
Tera = Giga * 1000
|
||||
Peta = Tera * 1000
|
||||
Exa = Peta * 1000
|
||||
)
|
||||
|
||||
func MakeUnitMap(suffix, shortSuffix string, scale int64) map[string]float64 {
|
||||
res := map[string]float64{
|
||||
shortSuffix: 1,
|
||||
// see below for "k" / "K"
|
||||
"M" + suffix: float64(scale * scale),
|
||||
"G" + suffix: float64(scale * scale * scale),
|
||||
"T" + suffix: float64(scale * scale * scale * scale),
|
||||
"P" + suffix: float64(scale * scale * scale * scale * scale),
|
||||
"E" + suffix: float64(scale * scale * scale * scale * scale * scale),
|
||||
}
|
||||
|
||||
// Standard SI prefixes use lowercase "k" for kilo = 1000.
|
||||
// For compatibility, and to be fool-proof, we accept both "k" and "K" in metric mode.
|
||||
//
|
||||
// However, official binary prefixes are always capitalized - "KiB" -
|
||||
// and we specifically never parse "kB" as 1024B because:
|
||||
//
|
||||
// (1) people pedantic enough to use lowercase according to SI unlikely to abuse "k" to mean 1024 :-)
|
||||
//
|
||||
// (2) Use of capital K for 1024 was an informal tradition predating IEC prefixes:
|
||||
// "The binary meaning of the kilobyte for 1024 bytes typically uses the symbol KB, with an
|
||||
// uppercase letter K."
|
||||
// -- https://en.wikipedia.org/wiki/Kilobyte#Base_2_(1024_bytes)
|
||||
// "Capitalization of the letter K became the de facto standard for binary notation, although this
|
||||
// could not be extended to higher powers, and use of the lowercase k did persist.[13][14][15]"
|
||||
// -- https://en.wikipedia.org/wiki/Binary_prefix#History
|
||||
// See also the extensive https://en.wikipedia.org/wiki/Timeline_of_binary_prefixes.
|
||||
if scale == 1024 {
|
||||
res["K"+suffix] = float64(scale)
|
||||
} else {
|
||||
res["k"+suffix] = float64(scale)
|
||||
res["K"+suffix] = float64(scale)
|
||||
}
|
||||
return res
|
||||
}
|
138
vendor/github.com/alecthomas/units/util.go
generated
vendored
Normal file
138
vendor/github.com/alecthomas/units/util.go
generated
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
package units
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
siUnits = []string{"", "K", "M", "G", "T", "P", "E"}
|
||||
)
|
||||
|
||||
func ToString(n int64, scale int64, suffix, baseSuffix string) string {
|
||||
mn := len(siUnits)
|
||||
out := make([]string, mn)
|
||||
for i, m := range siUnits {
|
||||
if n%scale != 0 || i == 0 && n == 0 {
|
||||
s := suffix
|
||||
if i == 0 {
|
||||
s = baseSuffix
|
||||
}
|
||||
out[mn-1-i] = fmt.Sprintf("%d%s%s", n%scale, m, s)
|
||||
}
|
||||
n /= scale
|
||||
if n == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return strings.Join(out, "")
|
||||
}
|
||||
|
||||
// Below code ripped straight from http://golang.org/src/pkg/time/format.go?s=33392:33438#L1123
|
||||
var errLeadingInt = errors.New("units: bad [0-9]*") // never printed
|
||||
|
||||
// leadingInt consumes the leading [0-9]* from s.
|
||||
func leadingInt(s string) (x int64, rem string, err error) {
|
||||
i := 0
|
||||
for ; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if c < '0' || c > '9' {
|
||||
break
|
||||
}
|
||||
if x >= (1<<63-10)/10 {
|
||||
// overflow
|
||||
return 0, "", errLeadingInt
|
||||
}
|
||||
x = x*10 + int64(c) - '0'
|
||||
}
|
||||
return x, s[i:], nil
|
||||
}
|
||||
|
||||
func ParseUnit(s string, unitMap map[string]float64) (int64, error) {
|
||||
// [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
|
||||
orig := s
|
||||
f := float64(0)
|
||||
neg := false
|
||||
|
||||
// Consume [-+]?
|
||||
if s != "" {
|
||||
c := s[0]
|
||||
if c == '-' || c == '+' {
|
||||
neg = c == '-'
|
||||
s = s[1:]
|
||||
}
|
||||
}
|
||||
// Special case: if all that is left is "0", this is zero.
|
||||
if s == "0" {
|
||||
return 0, nil
|
||||
}
|
||||
if s == "" {
|
||||
return 0, errors.New("units: invalid " + orig)
|
||||
}
|
||||
for s != "" {
|
||||
g := float64(0) // this element of the sequence
|
||||
|
||||
var x int64
|
||||
var err error
|
||||
|
||||
// The next character must be [0-9.]
|
||||
if !(s[0] == '.' || ('0' <= s[0] && s[0] <= '9')) {
|
||||
return 0, errors.New("units: invalid " + orig)
|
||||
}
|
||||
// Consume [0-9]*
|
||||
pl := len(s)
|
||||
x, s, err = leadingInt(s)
|
||||
if err != nil {
|
||||
return 0, errors.New("units: invalid " + orig)
|
||||
}
|
||||
g = float64(x)
|
||||
pre := pl != len(s) // whether we consumed anything before a period
|
||||
|
||||
// Consume (\.[0-9]*)?
|
||||
post := false
|
||||
if s != "" && s[0] == '.' {
|
||||
s = s[1:]
|
||||
pl := len(s)
|
||||
x, s, err = leadingInt(s)
|
||||
if err != nil {
|
||||
return 0, errors.New("units: invalid " + orig)
|
||||
}
|
||||
scale := 1.0
|
||||
for n := pl - len(s); n > 0; n-- {
|
||||
scale *= 10
|
||||
}
|
||||
g += float64(x) / scale
|
||||
post = pl != len(s)
|
||||
}
|
||||
if !pre && !post {
|
||||
// no digits (e.g. ".s" or "-.s")
|
||||
return 0, errors.New("units: invalid " + orig)
|
||||
}
|
||||
|
||||
// Consume unit.
|
||||
i := 0
|
||||
for ; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if c == '.' || ('0' <= c && c <= '9') {
|
||||
break
|
||||
}
|
||||
}
|
||||
u := s[:i]
|
||||
s = s[i:]
|
||||
unit, ok := unitMap[u]
|
||||
if !ok {
|
||||
return 0, errors.New("units: unknown unit " + u + " in " + orig)
|
||||
}
|
||||
|
||||
f += g * unit
|
||||
}
|
||||
|
||||
if neg {
|
||||
f = -f
|
||||
}
|
||||
if f < float64(-1<<63) || f > float64(1<<63-1) {
|
||||
return 0, errors.New("units: overflow parsing unit")
|
||||
}
|
||||
return int64(f), nil
|
||||
}
|
3
vendor/modules.txt
vendored
3
vendor/modules.txt
vendored
@ -1,3 +1,6 @@
|
||||
# github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d
|
||||
## explicit
|
||||
github.com/alecthomas/units
|
||||
# github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/dgrijalva/jwt-go
|
||||
# github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db
|
||||
|
Loading…
Reference in New Issue
Block a user