Compare commits

...

25 Commits

1
.gitignore vendored

@ -0,0 +1 @@
/.idea

@ -1,125 +0,0 @@
linters-settings:
depguard:
list-type: blacklist
packages:
# logging is allowed only by logutils.Log, logrus
# is allowed to use only in logutils package
- github.com/sirupsen/logrus
packages-with-error-message:
- github.com/sirupsen/logrus: "logging is allowed only by logutils.Log"
dupl:
threshold: 100
funlen:
lines: 100
statements: 50
goconst:
min-len: 2
min-occurrences: 2
gocritic:
enabled-tags:
- diagnostic
- experimental
- opinionated
- performance
- style
disabled-checks:
- dupImport # https://github.com/go-critic/go-critic/issues/845
- ifElseChain
- octalLiteral
- whyNoLint
- wrapperFunc
gocyclo:
min-complexity: 15
goimports:
local-prefixes: github.com/golangci/golangci-lint
golint:
min-confidence: 0
gomnd:
settings:
mnd:
# don't include the "operation" and "assign"
checks: argument,case,condition,return
govet:
check-shadowing: true
settings:
printf:
funcs:
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
lll:
line-length: 140
maligned:
suggest-new: true
misspell:
locale: US
linters:
# please, do not use `enable-all`: it's deprecated and will be removed soon.
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
disable-all: true
enable:
- bodyclose
- deadcode
- depguard
- dogsled
- dupl
- errcheck
- funlen
- gochecknoinits
- goconst
- gocritic
- gocyclo
- gofmt
- goimports
- golint
- gomnd
- goprintffuncname
- gosec
- gosimple
- govet
- ineffassign
- interfacer
- lll
- misspell
- nakedret
- rowserrcheck
- scopelint
- staticcheck
- structcheck
- stylecheck
- typecheck
- unconvert
- unparam
- unused
- varcheck
- whitespace
# don't enable:
# - gochecknoglobals
# - gocognit
# - godox
# - maligned
# - prealloc
issues:
# Excluding configuration per-path, per-linter, per-text and per-source
exclude-rules:
- path: _test\.go
linters:
- gomnd
run:
skip-dirs:
- test/testdata_etc
- internal/cache
- internal/renameio
- internal/robustio
# golangci.com configuration
# https://github.com/golangci/golangci/wiki/Configuration
service:
golangci-lint-version: 1.23.x # use the fixed version to not introduce new linters unexpectedly
prepare:
- echo "here I can run custom commands, but no preparation needed for this repo"

@ -0,0 +1,106 @@
package crypto
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"fmt"
"github.com/Luzifer/go-openssl/v3"
)
func addPKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padText...)
}
func removePKCS7Padding(data []byte) ([]byte, error) {
if len(data) == 0 {
return nil, fmt.Errorf("data cannot be empty")
}
padding := int(data[len(data)-1])
if padding > len(data) {
return nil, fmt.Errorf("invalid padding size")
}
return data[:len(data)-padding], nil
}
// EncryptAES 加密函式
func EncryptAES(plaintext, key, iv []byte) ([]byte, error) {
// 驗證密鑰長度是否符合 AES 的要求
if len(key) != aes.BlockSize && len(key) != 16 && len(key) != 24 && len(key) != 32 {
return nil, fmt.Errorf("invalid key size: %d, expected 16, 24, or 32", len(key))
}
// 創建 AES 密碼器
block, err := aes.NewCipher(key)
if err != nil {
return nil, fmt.Errorf("failed to create AES cipher: %w", err)
}
// 確保輸入的資料長度符合 block size並進行填充
blockSize := block.BlockSize()
plaintext = addPKCS7Padding(plaintext, blockSize)
// 創建 CBC 模式加密器
blockMode := cipher.NewCBCEncrypter(block, iv)
// 用來保存加密結果的緩衝區
enc := make([]byte, len(plaintext))
blockMode.CryptBlocks(enc, plaintext)
return enc, nil
}
// DecryptAES 使用 AES CBC 模式進行解密
func DecryptAES(ciphertext, key, iv []byte) ([]byte, error) {
// 驗證密鑰長度是否符合 AES 的要求
if len(key) != aes.BlockSize && len(key) != 16 && len(key) != 24 && len(key) != 32 {
return nil, fmt.Errorf("invalid key size: %d, expected 16, 24, or 32", len(key))
}
// 創建 AES 密碼器
block, err := aes.NewCipher(key)
if err != nil {
return nil, fmt.Errorf("failed to create AES cipher: %w", err)
}
// 確保輸入的資料長度符合 block size並進行解密
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, iv[:blockSize])
// 用來保存解密結果的緩衝區
origData := make([]byte, len(ciphertext))
blockMode.CryptBlocks(origData, ciphertext)
// 去除 PKCS7 填充
return removePKCS7Padding(origData)
}
// EncryptAESWithOpenSSL 使用Openssl 加密AES
func EncryptAESWithOpenSSL(value, key string) ([]byte, error) {
o := openssl.New()
enc, err := o.EncryptBytes(key, []byte(value), openssl.DigestMD5Sum)
if err != nil {
return nil, fmt.Errorf("failed to encrypt with OpenSSL: %w", err)
}
return enc, nil
}
// DecryptAESWithOpenSSL 使用Openssl 解密AES
func DecryptAESWithOpenSSL(value, key string) ([]byte, error) {
o := openssl.New()
dec, err := o.DecryptBytes(key, []byte(value), openssl.DigestMD5Sum)
if err != nil {
return nil, fmt.Errorf("failed to decrypt with OpenSSL: %w", err)
}
return dec, nil
}

@ -1,101 +1,23 @@
package crypto
import (
"crypto/rand"
"crypto/rsa"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"github.com/Luzifer/go-openssl/v3"
"golang.org/x/crypto/bcrypt"
)
// MD5 回傳md5加密
func MD5(v string) string {
return fmt.Sprintf("%x", md5.Sum([]byte(v)))
}
// SHA1 回傳sha1加密
func SHA1(v string) string {
h := sha1.New()
h.Write([]byte(v))
bs := h.Sum(nil)
return fmt.Sprintf("%x", bs)
return fmt.Sprintf("%x", sha1.Sum([]byte(v)))
}
// SHA256 回傳sha256加密
func SHA256(v string) string {
h := sha256.New()
h.Write([]byte(v))
bs := h.Sum(nil)
return fmt.Sprintf("%x", bs)
}
// EncryptPassword 加密密碼
func EncryptPassword(pwd string) (string, error) {
hash, err := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost)
if err != nil {
return "", err
}
return string(hash), nil
}
// CheckPassword 檢查密碼
func CheckPassword(pwd, hash string) error {
return bcrypt.CompareHashAndPassword([]byte(hash), []byte(pwd))
}
// EncryptAES aes加密
func EncryptAES(value, key string) ([]byte, error) {
o := openssl.New()
enc, err := o.EncryptBytes(key, []byte(value), openssl.DigestMD5Sum)
if err != nil {
return nil, err
}
return enc, nil
}
// DecryptAES aes解密
func DecryptAES(value, key string) ([]byte, error) {
o := openssl.New()
dec, err := o.DecryptBytes(key, []byte(value), openssl.DigestMD5Sum)
if err != nil {
return nil, err
}
return dec, nil
}
// EncryptRSA rsa加密
func EncryptRSA(value, publicKey []byte) ([]byte, error) {
block, _ := pem.Decode(publicKey)
if block == nil {
return nil, errors.New("public key error")
}
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
pub := pubInterface.(*rsa.PublicKey)
return rsa.EncryptPKCS1v15(rand.Reader, pub, value)
}
// DecryptRSA rsa解密
func DecryptRSA(ciphertext, privateKey []byte) ([]byte, error) {
block, _ := pem.Decode(privateKey)
if block == nil {
return nil, errors.New("private key error")
}
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)
return fmt.Sprintf("%x", sha256.Sum256([]byte(v)))
}

@ -0,0 +1,29 @@
package crypto
import (
"fmt"
"golang.org/x/crypto/bcrypt"
)
// EncryptPassword 加密密碼
func EncryptPassword(pwd string) (string, error) {
hash, err := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost)
if err != nil {
return "", fmt.Errorf("failed to encrypt password: %w", err)
}
return string(hash), nil
}
// CheckPassword 檢查密碼
func CheckPassword(pwd, hash string) error {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(pwd))
if err != nil {
// 返回帶有更多上下文信息的錯誤
return fmt.Errorf("password does not match: %w", err)
}
// 如果密碼正確,返回 nil
return nil
}

@ -0,0 +1,86 @@
package crypto
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
)
func NewKeyRSA(bitSize int) (pubPEM []byte, keyPEM []byte, err error) {
// 生成 RSA 密鑰對
key, err := rsa.GenerateKey(rand.Reader, bitSize)
if err != nil {
return nil, nil, fmt.Errorf("failed to generate RSA key: %w", err)
}
// 提取公鑰部分並轉換為 PEM 格式
pubBytes, err := x509.MarshalPKIXPublicKey(key.Public())
if err != nil {
return nil, nil, fmt.Errorf("failed to marshal public key: %w", err)
}
pubPEM = pem.EncodeToMemory(
&pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: pubBytes,
},
)
// 編碼私鑰為 PKCS#1 ASN.1 PEM 格式
keyPEM = pem.EncodeToMemory(
&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(key),
},
)
return pubPEM, keyPEM, nil
}
// EncryptRSA rsa加密
func EncryptRSA(value, publicKey []byte) ([]byte, error) {
block, _ := pem.Decode(publicKey)
if block == nil {
return nil, errors.New("failed to decode public key PEM")
}
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse public key: %w", err)
}
pub, ok := pubInterface.(*rsa.PublicKey)
if !ok {
return nil, errors.New("invalid public key type")
}
// 使用公鑰進行加密
enc, err := rsa.EncryptPKCS1v15(rand.Reader, pub, value)
if err != nil {
return nil, fmt.Errorf("failed to encrypt with RSA: %w", err)
}
return enc, nil
}
// DecryptRSA rsa解密
func DecryptRSA(ciphertext, privateKey []byte) ([]byte, error) {
block, _ := pem.Decode(privateKey)
if block == nil {
return nil, errors.New("failed to decode private key PEM")
}
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse private key: %w", err)
}
dec, err := rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)
if err != nil {
return nil, fmt.Errorf("failed to decrypt with RSA: %w", err)
}
return dec, nil
}

@ -2,33 +2,37 @@ package generate
import (
"crypto/rand"
"math/big"
"fmt"
)
// GetRandomString 取得隨機字串
func GetRandomString(n int) (string, error) {
const alphaNum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
return getRandomFromCharset(n, alphaNum)
}
buffer := make([]byte, n)
max := big.NewInt(int64(len(alphaNum)))
// GetRandomKey 取得隨機金鑰
func GetRandomKey(n int) (string, error) {
const alphaNum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!@#$%^&*()-_=+"
return getRandomFromCharset(n, alphaNum)
}
for i := 0; i < n; i++ {
index, err := randomInt(max)
if err != nil {
return "", err
}
// getRandomFromCharset 通用隨機字串生成器
func getRandomFromCharset(n int, charset string) (string, error) {
// 預先計算字符集的長度
charsLen := len(charset)
buffer := make([]byte, n)
buffer[i] = alphaNum[index]
// 使用 crypto/rand 生成隨機數據
_, err := rand.Read(buffer)
if err != nil {
return "", fmt.Errorf("failed to generate random data: %w", err)
}
return string(buffer), nil
}
func randomInt(max *big.Int) (int, error) {
random, err := rand.Int(rand.Reader, max)
if err != nil {
return 0, err
// 從字元集選擇字符
for i := 0; i < n; i++ {
buffer[i] = charset[int(buffer[i])%charsLen]
}
return int(random.Int64()), nil
return string(buffer), nil
}

@ -1,11 +1,18 @@
module git.simts.cc/common/lib
go 1.14
go 1.19
require (
github.com/Luzifer/go-openssl/v3 v3.1.0
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/golang-jwt/jwt/v5 v5.0.0-rc.2
github.com/mojocn/base64Captcha v1.3.1
go.uber.org/zap v1.15.0
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/crypto v0.8.0
)
require (
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
go.uber.org/atomic v1.6.0 // indirect
go.uber.org/multierr v1.5.0 // indirect
golang.org/x/image v0.7.0 // indirect
)

@ -5,16 +5,14 @@ github.com/Luzifer/go-openssl/v3 v3.1.0/go.mod h1:liy3FXuuS8hfDlYh1T+l78AwQ/NjZf
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/golang-jwt/jwt/v5 v5.0.0-rc.2 h1:hXPcSazn8wKOfSb9y2m1bdgUMlDxVDarxh3lJVbC6JE=
github.com/golang-jwt/jwt/v5 v5.0.0-rc.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mojocn/base64Captcha v1.3.1 h1:2Wbkt8Oc8qjmNJ5GyOfSo4tgVQPsbKMftqASnq8GlT0=
github.com/mojocn/base64Captcha v1.3.1/go.mod h1:wAQCKEc5bDujxKRmbT6/vTnTt5CjStQ8bRfPWUuz/iY=
@ -27,6 +25,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
@ -36,30 +35,55 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E
go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/image v0.0.0-20190501045829-6d32002ffd75 h1:TbGuee8sSq15Iguxu4deQ7+Bqq/d2rsQejGcEtADAMQ=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.7.0 h1:gzS29xtG1J5ybQlv0PuyfE3nmc6R4qB73m6LUUmvFuw=
golang.org/x/image v0.7.0/go.mod h1:nd/q4ef1AKKYl/4kft7g+6UyGbdiqWqTP1ZAbRoV7Rg=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=

@ -6,7 +6,6 @@ import (
"image/jpeg"
"image/png"
"io"
"io/ioutil"
"mime/multipart"
"os"
)
@ -14,27 +13,42 @@ import (
// CompressImage 壓縮圖片至指定位置
func CompressImage(input interface{}, output string) (err error) {
var file io.Reader
switch input.(type) {
var fileToClose io.Closer
switch v := input.(type) {
case string:
if file, err = os.Open(input.(string)); err != nil {
f, err := os.Open(v)
if err != nil {
return err
}
defer file.(*os.File).Close()
defer os.Remove(input.(string))
file = f
fileToClose = f
defer func() {
if fileToClose != nil {
_ = fileToClose.Close()
}
_ = os.Remove(v)
}()
case *multipart.FileHeader:
fileHeader := input.(*multipart.FileHeader)
file, err = fileHeader.Open()
f, err := v.Open()
if err != nil {
return err
}
defer file.(multipart.File).Close()
file = f
fileToClose = f
defer func() {
if fileToClose != nil {
_ = fileToClose.Close()
}
}()
}
bs, err := ioutil.ReadAll(file)
if err != nil {
var buf bytes.Buffer
if _, err = io.Copy(&buf, file); err != nil {
return err
}
bs := buf.Bytes()
var ext string
if _, err = jpeg.Decode(bytes.NewReader(bs)); err == nil {
@ -49,7 +63,11 @@ func CompressImage(input interface{}, output string) (err error) {
if err != nil {
return err
}
defer outputFile.Close()
defer func() {
if outputFile != nil {
_ = outputFile.Close()
}
}()
switch ext {
case "jpg":
@ -57,34 +75,22 @@ func CompressImage(input interface{}, output string) (err error) {
if err != nil {
return err
}
if err = jpeg.Encode(outputFile, img, &jpeg.Options{Quality: 70}); err != nil {
return err
}
return jpeg.Encode(outputFile, img, &jpeg.Options{Quality: 70})
case "png":
img, err := png.Decode(bytes.NewReader(bs))
if err != nil {
return err
}
encoder := png.Encoder{CompressionLevel: png.BestCompression}
if err = encoder.Encode(outputFile, img); err != nil {
return err
}
return encoder.Encode(outputFile, img)
case "gif":
img, err := gif.DecodeAll(bytes.NewReader(bs))
if err != nil {
return err
}
if err = gif.EncodeAll(outputFile, img); err != nil {
return err
}
return gif.EncodeAll(outputFile, img)
default:
if _, err = outputFile.Write(bs); err != nil {
return err
}
_, err = outputFile.Write(bs)
return err
}
return nil
}

@ -1,25 +1,41 @@
package jwt
import (
"crypto/rsa"
"errors"
"fmt"
"git.simts.cc/common/lib/types"
"github.com/dgrijalva/jwt-go"
"github.com/golang-jwt/jwt/v5"
)
// Encode jwt編碼
func Encode(values types.Data, key string) (string, error) {
claims := jwt.MapClaims{}
for key, value := range values {
claims[key] = value
for k, v := range values {
claims[k] = v
}
tokenString, err := jwt.
NewWithClaims(jwt.SigningMethodHS256, claims).
tokenString, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).
SignedString([]byte(key))
if err != nil {
return "", err
return "", fmt.Errorf("failed to sign JWT with HS256: %w", err)
}
return tokenString, nil
}
// EncodeRS256 jwt編碼
func EncodeRS256(values types.Data, key *rsa.PrivateKey) (string, error) {
claims := jwt.MapClaims{}
for k, v := range values {
claims[k] = v
}
tokenString, err := jwt.NewWithClaims(jwt.SigningMethodRS256, claims).
SignedString(key)
if err != nil {
return "", fmt.Errorf("failed to sign JWT with RS256: %w", err)
}
return tokenString, nil
@ -29,18 +45,27 @@ func Encode(values types.Data, key string) (string, error) {
func Decode(tokenString string, key string) (types.Data, error) {
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Unexpected error: %v. ", token.Header["alg"])
return nil, fmt.Errorf("unexpected signing method: %w", token.Header["alg"])
}
return []byte(key), nil
})
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to parse JWT: %w", err)
}
if token == nil || !token.Valid {
return nil, fmt.Errorf("invalid token or claims")
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok || !token.Valid {
return nil, fmt.Errorf("Token error. ")
if !ok {
return nil, fmt.Errorf("failed to parse token claims")
}
return types.Data(claims), nil
}
// IsExpired 檢查 token 是否過期
func IsExpired(err error) bool {
return errors.Is(err, jwt.ErrTokenExpired)
}

@ -1,25 +0,0 @@
package logger
import (
"go.uber.org/zap"
)
// NewLoggerProduction 正式版紀錄
func NewLoggerProduction() (*zap.SugaredLogger, error) {
logger, err := zap.NewProduction()
if err != nil {
return nil, err
}
return logger.Sugar(), nil
}
// NewLoggerDevelopment 開發版紀錄
func NewLoggerDevelopment() (*zap.SugaredLogger, error) {
logger, err := zap.NewDevelopment()
if err != nil {
return nil, err
}
return logger.Sugar(), nil
}

@ -0,0 +1,10 @@
package sms
import (
"fmt"
)
var (
ErrResponse = fmt.Errorf("Resposne error.")
ErrNotEnoughCredit = fmt.Errorf("Not enough credit.")
)

@ -0,0 +1,59 @@
package sms
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
"time"
)
type Every8D struct {
Username string
Password string
}
func NewSmsEvery8D(username, password string) *Every8D {
return &Every8D{
Username: username,
Password: password,
}
}
func (every8d *Every8D) Send(mobile, msg string) (int, error) {
qs := url.Values{}
qs.Add("UID", every8d.Username)
qs.Add("PWD", every8d.Password)
qs.Add("DEST", mobile)
qs.Add("MSG", url.QueryEscape(msg))
client := http.Client{Timeout: 2 * time.Second}
resp, err := client.Get(fmt.Sprintf("https://oms.every8d.com/API21/HTTP/sendSMS.ashx?%s", qs.Encode()))
if err != nil {
return 0, err
}
bs, err := ioutil.ReadAll(resp.Body)
if err != nil {
return 0, err
}
defer resp.Body.Close()
data := strings.Split(string(bs), ",")
if len(data) != 5 {
return 0, ErrResponse
}
credit, err := strconv.ParseFloat(data[0], 64)
if err != nil {
return 0, err
}
if credit < 0 {
return 0, ErrNotEnoughCredit
}
return int(credit), nil
}

@ -0,0 +1,62 @@
package sms
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
"time"
)
type Mitake struct {
Username string
Password string
}
func NewSmsMitake(username, password string) *Mitake {
return &Mitake{
Username: username,
Password: password,
}
}
func (mitake *Mitake) Send(mobile, msg string) (int, error) {
qs := url.Values{}
qs.Add("CharsetURL", "UTF8")
qs.Add("username", mitake.Username)
qs.Add("password", mitake.Password)
qs.Add("dstaddr", mobile)
qs.Add("smbody", url.QueryEscape(msg))
client := http.Client{Timeout: 2 * time.Second}
resp, err := client.Get(fmt.Sprintf("http://smsb2c.mitake.com.tw/b2c/mtk/SmSend?%s", qs.Encode()))
if err != nil {
return 0, err
}
bs, err := ioutil.ReadAll(resp.Body)
if err != nil {
return 0, err
}
defer resp.Body.Close()
if len(strings.Split(string(bs), "\n")) != 6 {
return 0, ErrResponse
}
qs, err = url.ParseQuery(strings.ReplaceAll(string(bs), "\n", "&"))
if err != nil {
return 0, err
}
credit, err := strconv.ParseInt(strings.ReplaceAll(qs.Get("AccountPoint"), "\r", ""), 10, 64)
if err != nil {
return 0, err
} else if credit < 0 {
return 0, ErrNotEnoughCredit
}
return int(credit), nil
}

@ -0,0 +1,64 @@
package sms
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
)
type SmsGet struct {
Username string
Password string
}
func NewSmsGet(username, password string) *SmsGet {
return &SmsGet{
Username: username,
Password: password,
}
}
func (smsget *SmsGet) Send(mobile, msg string) (int, error) {
qs := url.Values{}
qs.Add("method", "1")
qs.Add("username", smsget.Username)
qs.Add("password", smsget.Password)
qs.Add("sms_msg", url.QueryEscape(msg))
resp, err := http.Get(fmt.Sprintf("https://sms-get2.com/api_send.php?%s", qs.Encode()))
if err != nil {
return 0, err
}
defer resp.Body.Close()
bs, err := ioutil.ReadAll(resp.Body)
if err != nil {
return 0, err
}
var res struct {
Status bool `json:"stats"`
Code int `json:"error_code,string"`
Msg string `json:"error_msg"`
}
if err := json.Unmarshal(bs, &res); err != nil {
return 0, ErrResponse
}
if !res.Status || res.Code != 0 {
if res.Code == 9 {
return 0, ErrNotEnoughCredit
}
return 0, ErrResponse
}
credit, err := strconv.Atoi(strings.Split(res.Msg, "|")[2])
if err != nil {
return 0, err
}
return credit, nil
}

@ -24,6 +24,27 @@ func (data Data) Get(key string) (interface{}, error) {
return value, nil
}
// GetSlice 取得切片
func (data Data) GetSlice(key string) (res Slice, err error) {
value, err := data.Get(key)
if err != nil {
return nil, err
}
switch v := value.(type) {
case []interface{}:
return v, nil
default:
return nil, ErrFormat
}
}
// MustGetSlice 強制取得切片
func (data Data) MustGetSlice(key string) Slice {
values, _ := data.GetSlice(key)
return values
}
// GetString 取得字串
func (data Data) GetString(key string) (string, error) {
value, err := data.Get(key)
@ -31,12 +52,14 @@ func (data Data) GetString(key string) (string, error) {
return "", err
}
switch value.(type) {
switch value := value.(type) {
case []byte:
return string(value), nil
case string:
return value.(string), nil
return value, nil
default:
return "", ErrFormat
}
return "", ErrFormat
}
// MustGetString 強制取得字串
@ -45,63 +68,157 @@ func (data Data) MustGetString(key string) string {
return value
}
// GetSlice 取得切片
func (data Data) GetSlice(key string) (res []interface{}, err error) {
// GetStringSlice 取得字串切片
func (data Data) GetStringSlice(key string) (res []string, err error) {
values, err := data.GetSlice(key)
if err != nil {
return nil, err
}
for _, v := range values {
switch v := v.(type) {
case string:
res = append(res, v)
default:
return nil, ErrFormat
}
}
return res, nil
}
// MustGetStringSlice 強制取得字串切片
func (data Data) MustGetStringSlice(key string) []string {
values, _ := data.GetStringSlice(key)
return values
}
// GetBytes 取得字串
func (data Data) GetBytes(key string) ([]byte, error) {
value, err := data.Get(key)
if err != nil {
return nil, err
}
switch value.(type) {
case []interface{}:
return value.([]interface{}), nil
switch value := value.(type) {
case []byte:
return value, nil
case string:
return []byte(value), nil
default:
return nil, ErrFormat
}
}
// MustGetSlice 強制取得切片
func (data Data) MustGetSlice(key string) []interface{} {
values, _ := data.GetSlice(key)
return values
// MustGetBytes 強制取得字串
func (data Data) MustGetBytes(key string) []byte {
value, _ := data.GetBytes(key)
return value
}
// GetStringSlice 取得字串切片
func (data Data) GetStringSlice(key string) (res []string, err error) {
// GetData 取得資料
func (data Data) GetData(key string) (Data, error) {
value, err := data.Get(key)
if err != nil {
return nil, err
}
switch v := value.(type) {
case map[string]interface{}:
return v, nil
default:
return nil, ErrFormat
}
}
// MustGetData 強制取得資料
func (data Data) MustGetData(key string) Data {
value, _ := data.GetData(key)
return value
}
// GetDataSlice 取得資料切片
func (data Data) GetDataSlice(key string) ([]Data, error) {
values, err := data.GetSlice(key)
if err != nil {
return nil, err
}
for _, v := range values {
switch v.(type) {
case string:
res = append(res, v.(string))
var list []Data
for _, value := range values {
switch v := value.(type) {
case map[string]interface{}:
list = append(list, v)
default:
return nil, ErrFormat
}
}
return res, nil
return list, nil
}
// MustGetStringSlice 強制取得字串切片
func (data Data) MustGetStringSlice(key string) []string {
values, _ := data.GetStringSlice(key)
// MustGetDataSlice 強制取得資料切片
func (data Data) MustGetDataSlice(key string) []Data {
values, _ := data.GetDataSlice(key)
return values
}
// GetIntSlice 取得整數切片
func (data Data) GetIntSlice(key string) (res []int, err error) {
// GetFloat64 取得64位元浮點數
func (data Data) GetFloat64(key string) (float64, error) {
value, err := data.Get(key)
if err != nil {
return 0, err
}
switch value := value.(type) {
case float32:
return float64(value), nil
case float64:
return value, nil
default:
return 0, ErrFormat
}
}
// MustGetFloat64 強制取得64位元浮點數
func (data Data) MustGetFloat64(key string) float64 {
value, _ := data.GetFloat64(key)
return value
}
// GetFloat64Slice 取得64位元浮點數切片
func (data Data) GetFloat64Slice(key string) (res []float64, err error) {
values, err := data.GetSlice(key)
if err != nil {
return nil, err
}
for _, v := range values {
switch v.(type) {
switch v := v.(type) {
case int:
res = append(res, float64(v))
case uint:
res = append(res, float64(v))
case int8:
res = append(res, float64(v))
case uint8:
res = append(res, float64(v))
case int16:
res = append(res, float64(v))
case uint16:
res = append(res, float64(v))
case int32:
res = append(res, float64(v))
case uint32:
res = append(res, float64(v))
case int64:
res = append(res, float64(v))
case uint64:
res = append(res, float64(v))
case float32:
res = append(res, float64(v))
case float64:
res = append(res, int(v.(float64)))
res = append(res, v)
default:
return nil, ErrFormat
}
@ -110,9 +227,9 @@ func (data Data) GetIntSlice(key string) (res []int, err error) {
return res, nil
}
// MustGetIntSlice 強制取得整數切片
func (data Data) MustGetIntSlice(key string) []int {
values, _ := data.GetIntSlice(key)
// MustGetFloat64Slice 強制取得64位元浮點數切片
func (data Data) MustGetFloat64Slice(key string) []float64 {
values, _ := data.GetFloat64Slice(key)
return values
}
@ -123,18 +240,30 @@ func (data Data) GetInt64(key string) (int64, error) {
return 0, err
}
switch value.(type) {
switch value := value.(type) {
case int:
return int64(value.(int)), nil
return int64(value), nil
case uint:
return int64(value), nil
case int8:
return int64(value), nil
case uint8:
return int64(value), nil
case int16:
return int64(value), nil
case uint16:
return int64(value), nil
case int32:
return int64(value), nil
case uint32:
return int64(value), nil
case int64:
return value.(int64), nil
return value, nil
case float64:
return int64(value.(float64)), nil
return int64(value), nil
default:
return 0, ErrFormat
}
return 0, ErrFormat
}
// MustGetInt64 強制取得64位元整數
@ -143,6 +272,53 @@ func (data Data) MustGetInt64(key string) int64 {
return value
}
// GetInt64Slice 取得64位元整數切片
func (data Data) GetInt64Slice(key string) (res []int64, err error) {
values, err := data.GetSlice(key)
if err != nil {
return nil, err
}
for _, v := range values {
switch v := v.(type) {
case int:
res = append(res, int64(v))
case uint:
res = append(res, int64(v))
case int8:
res = append(res, int64(v))
case uint8:
res = append(res, int64(v))
case int16:
res = append(res, int64(v))
case uint16:
res = append(res, int64(v))
case int32:
res = append(res, int64(v))
case uint32:
res = append(res, int64(v))
case int64:
res = append(res, v)
case uint64:
res = append(res, int64(v))
case float32:
res = append(res, int64(v))
case float64:
res = append(res, int64(v))
default:
return nil, ErrFormat
}
}
return res, nil
}
// MustGetInt64Slice 強制取得64位元整數切片
func (data Data) MustGetInt64Slice(key string) []int64 {
values, _ := data.GetInt64Slice(key)
return values
}
// GetUint64 取得64位元正整數
func (data Data) GetUint64(key string) (uint64, error) {
value, err := data.GetInt64(key)
@ -163,6 +339,53 @@ func (data Data) MustGetUint64(key string) uint64 {
return value
}
// GetUint64Slice 取得64位元正整數切片
func (data Data) GetUint64Slice(key string) (res []uint64, err error) {
values, err := data.GetSlice(key)
if err != nil {
return nil, err
}
for _, v := range values {
switch v := v.(type) {
case int:
res = append(res, uint64(v))
case uint:
res = append(res, uint64(v))
case int8:
res = append(res, uint64(v))
case uint8:
res = append(res, uint64(v))
case int16:
res = append(res, uint64(v))
case uint16:
res = append(res, uint64(v))
case int32:
res = append(res, uint64(v))
case uint32:
res = append(res, uint64(v))
case int64:
res = append(res, uint64(v))
case uint64:
res = append(res, v)
case float32:
res = append(res, uint64(v))
case float64:
res = append(res, uint64(v))
default:
return nil, ErrFormat
}
}
return res, nil
}
// MustGetUint64Slice 強制取得64位元正整數切片
func (data Data) MustGetUint64Slice(key string) []uint64 {
values, _ := data.GetUint64Slice(key)
return values
}
// GetInt 取得整數
func (data Data) GetInt(key string) (int, error) {
value, err := data.GetInt64(key)
@ -179,6 +402,53 @@ func (data Data) MustGetInt(key string) int {
return value
}
// GetIntSlice 取得整數切片
func (data Data) GetIntSlice(key string) (res []int, err error) {
values, err := data.GetSlice(key)
if err != nil {
return nil, err
}
for _, v := range values {
switch v := v.(type) {
case int:
res = append(res, v)
case uint:
res = append(res, int(v))
case int8:
res = append(res, int(v))
case uint8:
res = append(res, int(v))
case int16:
res = append(res, int(v))
case uint16:
res = append(res, int(v))
case int32:
res = append(res, int(v))
case uint32:
res = append(res, int(v))
case int64:
res = append(res, int(v))
case uint64:
res = append(res, int(v))
case float32:
res = append(res, int(v))
case float64:
res = append(res, int(v))
default:
return nil, ErrFormat
}
}
return res, nil
}
// MustGetIntSlice 強制取得整數切片
func (data Data) MustGetIntSlice(key string) []int {
values, _ := data.GetIntSlice(key)
return values
}
// GetUint 取得正整數
func (data Data) GetUint(key string) (uint, error) {
value, err := data.GetInt64(key)
@ -199,6 +469,53 @@ func (data Data) MustGetUint(key string) uint {
return value
}
// GetUintSlice 取得正整數切片
func (data Data) GetUintSlice(key string) (res []uint, err error) {
values, err := data.GetSlice(key)
if err != nil {
return nil, err
}
for _, v := range values {
switch v := v.(type) {
case int:
res = append(res, uint(v))
case uint:
res = append(res, v)
case int8:
res = append(res, uint(v))
case uint8:
res = append(res, uint(v))
case int16:
res = append(res, uint(v))
case uint16:
res = append(res, uint(v))
case int32:
res = append(res, uint(v))
case uint32:
res = append(res, uint(v))
case int64:
res = append(res, uint(v))
case uint64:
res = append(res, uint(v))
case float32:
res = append(res, uint(v))
case float64:
res = append(res, uint(v))
default:
return nil, ErrFormat
}
}
return res, nil
}
// MustGetUintSlice 強制取得正整數切片
func (data Data) MustGetUintSlice(key string) []uint {
values, _ := data.GetUintSlice(key)
return values
}
// GetInt16 取得16位元整數
func (data Data) GetInt16(key string) (int16, error) {
value, err := data.GetInt64(key)
@ -215,6 +532,53 @@ func (data Data) MustGetInt16(key string) uint16 {
return value
}
// GetInt16Slice 取得16位元整數切片
func (data Data) GetInt16Slice(key string) (res []int16, err error) {
values, err := data.GetSlice(key)
if err != nil {
return nil, err
}
for _, v := range values {
switch v := v.(type) {
case int:
res = append(res, int16(v))
case uint:
res = append(res, int16(v))
case int8:
res = append(res, int16(v))
case uint8:
res = append(res, int16(v))
case int16:
res = append(res, v)
case uint16:
res = append(res, int16(v))
case int32:
res = append(res, int16(v))
case uint32:
res = append(res, int16(v))
case int64:
res = append(res, int16(v))
case uint64:
res = append(res, int16(v))
case float32:
res = append(res, int16(v))
case float64:
res = append(res, int16(v))
default:
return nil, ErrFormat
}
}
return res, nil
}
// MustGetInt16Slice 強制取得16位元整數切片
func (data Data) MustGetInt16Slice(key string) []int16 {
values, _ := data.GetInt16Slice(key)
return values
}
// GetUint16 取得16位元正整數
func (data Data) GetUint16(key string) (uint16, error) {
value, err := data.GetInt64(key)
@ -235,6 +599,53 @@ func (data Data) MustGetUint16(key string) uint16 {
return value
}
// GetUint16Slice 取得16位元正整數切片
func (data Data) GetUint16Slice(key string) (res []uint16, err error) {
values, err := data.GetSlice(key)
if err != nil {
return nil, err
}
for _, v := range values {
switch v := v.(type) {
case int:
res = append(res, uint16(v))
case uint:
res = append(res, uint16(v))
case int8:
res = append(res, uint16(v))
case uint8:
res = append(res, uint16(v))
case int16:
res = append(res, uint16(v))
case uint16:
res = append(res, v)
case int32:
res = append(res, uint16(v))
case uint32:
res = append(res, uint16(v))
case int64:
res = append(res, uint16(v))
case uint64:
res = append(res, uint16(v))
case float32:
res = append(res, uint16(v))
case float64:
res = append(res, uint16(v))
default:
return nil, ErrFormat
}
}
return res, nil
}
// MustGetUint16Slice 強制取得16位元正整數切片
func (data Data) MustGetUint16Slice(key string) []uint16 {
values, _ := data.GetUint16Slice(key)
return values
}
// GetInt8 取得8位元整數
func (data Data) GetInt8(key string) (int8, error) {
value, err := data.GetInt64(key)
@ -251,6 +662,53 @@ func (data Data) MustGetInt8(key string) int8 {
return value
}
// GetInt8Slice 取得8位元整數切片
func (data Data) GetInt8Slice(key string) (res []int8, err error) {
values, err := data.GetSlice(key)
if err != nil {
return nil, err
}
for _, v := range values {
switch v := v.(type) {
case int:
res = append(res, int8(v))
case uint:
res = append(res, int8(v))
case int8:
res = append(res, v)
case uint8:
res = append(res, int8(v))
case int16:
res = append(res, int8(v))
case uint16:
res = append(res, int8(v))
case int32:
res = append(res, int8(v))
case uint32:
res = append(res, int8(v))
case int64:
res = append(res, int8(v))
case uint64:
res = append(res, int8(v))
case float32:
res = append(res, int8(v))
case float64:
res = append(res, int8(v))
default:
return nil, ErrFormat
}
}
return res, nil
}
// MustGetInt8Slice 強制取得8位元整數切片
func (data Data) MustGetInt8Slice(key string) []int8 {
values, _ := data.GetInt8Slice(key)
return values
}
// GetUint8 取得8位元正整數
func (data Data) GetUint8(key string) (uint8, error) {
value, err := data.GetInt64(key)
@ -271,6 +729,53 @@ func (data Data) MustGetUint8(key string) uint8 {
return value
}
// GetUint8Slice 取得8位元正整數切片
func (data Data) GetUint8Slice(key string) (res []uint8, err error) {
values, err := data.GetSlice(key)
if err != nil {
return nil, err
}
for _, v := range values {
switch v := v.(type) {
case int:
res = append(res, uint8(v))
case uint:
res = append(res, uint8(v))
case int8:
res = append(res, uint8(v))
case uint8:
res = append(res, v)
case int16:
res = append(res, uint8(v))
case uint16:
res = append(res, uint8(v))
case int32:
res = append(res, uint8(v))
case uint32:
res = append(res, uint8(v))
case int64:
res = append(res, uint8(v))
case uint64:
res = append(res, uint8(v))
case float32:
res = append(res, uint8(v))
case float64:
res = append(res, uint8(v))
default:
return nil, ErrFormat
}
}
return res, nil
}
// MustGetUint8Slice 強制取得8位元正整數切片
func (data Data) MustGetUint8Slice(key string) []uint8 {
values, _ := data.GetUint8Slice(key)
return values
}
// GetBool 取得布林值
func (data Data) GetBool(key string) (bool, error) {
value, err := data.Get(key)
@ -278,9 +783,15 @@ func (data Data) GetBool(key string) (bool, error) {
return false, err
}
switch value.(type) {
switch value := value.(type) {
case uint8:
return value > 0, nil
case int64:
return value > 0, nil
case float64:
return value > 0, nil
case bool:
return value.(bool), nil
return value, nil
}
return false, ErrFormat
@ -294,12 +805,28 @@ func (data Data) MustGetBool(key string) bool {
// GetTimestamp 取得時間戳記
func (data Data) GetTimestamp(key string) (Timestamp, error) {
value, err := data.GetInt64(key)
value, err := data.Get(key)
if err != nil {
return 0, err
}
return Timestamp(value), nil
switch value := value.(type) {
case int:
return Timestamp(value), nil
case uint:
return Timestamp(value), nil
case int64:
return Timestamp(value), nil
case uint64:
return Timestamp(value), nil
case float64:
return Timestamp(value), nil
case Timestamp:
return value, nil
}
return 0, ErrFormat
}
// MustGetTimestamp 強制取得時間戳記
@ -323,3 +850,25 @@ func (data Data) MustJSON() []byte {
bs, _ := data.JSON()
return bs
}
// GetPage 取得頁數
func (data Data) GetPage(key string) (*Page, error) {
value, err := data.Get(key)
if err != nil {
return nil, err
}
switch value := value.(type) {
case Page:
return &value, nil
}
return nil, ErrFormat
}
// MustGetPage 強制取得頁數
func (data Data) MustGetPage(key string) *Page {
value, _ := data.GetPage(key)
return value
}

@ -0,0 +1,55 @@
package types
import (
"encoding/json"
)
type Slice []interface{}
// Push 後堆
func (slice *Slice) Push(value interface{}) {
*slice = append(*slice, value)
}
// Pop 後取
func (slice *Slice) Pop() (value interface{}) {
length := len(*slice)
if length > 0 {
value = (*slice)[length-1]
*slice = (*slice)[:length-1]
}
return value
}
// Unshift 前堆
func (slice *Slice) Unshift(value interface{}) {
*slice = append(Slice{value}, *slice...)
}
// Shift 前取
func (slice *Slice) Shift() (value interface{}) {
length := len(*slice)
if length > 0 {
value = (*slice)[0]
*slice = (*slice)[1:length]
}
return value
}
// JSON 取得json
func (slice *Slice) JSON() ([]byte, error) {
bs, err := json.Marshal(slice)
if err != nil {
return nil, err
}
return bs, nil
}
// MustJSON 強制取得json
func (slice *Slice) MustJSON() []byte {
bs, _ := slice.JSON()
return bs
}

@ -10,12 +10,12 @@ const (
FormatDatetime = "2006-01-02 15:04:05"
)
// Local 本地時區
var Local = time.Local
// Location 本地時區
var Location = time.Local
// SetLocation 設定時區
func SetLocation(name string) {
Local, _ = time.LoadLocation(name)
Location, _ = time.LoadLocation(name)
}
// Timestamp 時間戳
@ -26,9 +26,14 @@ func GetUnixNow() Timestamp {
return Timestamp(time.Now().Unix())
}
// GetUnixMilliNow 取得現在時間戳記
func GetUnixMilliNow() Timestamp {
return Timestamp(time.Now().UnixMilli())
}
// GetUnix 嘗試取得時間戳記
func GetUnix(format, datetime string) (Timestamp, error) {
t, err := time.Parse(format, datetime)
t, err := time.ParseInLocation(format, datetime, Location)
return Timestamp(t.Unix()), err
}
@ -48,28 +53,69 @@ func (t Timestamp) Time() time.Time {
return time.Unix(t.Int64(), 0)
}
// TimeMilli 轉為time類型
func (t Timestamp) TimeMilli() time.Time {
return time.UnixMilli(t.Int64())
}
// Date 回傳日期字串
func (t Timestamp) Date() string {
if t == 0 {
return ""
}
return time.
Unix(t.Int64(), 0).
In(Local).
In(Location).
Format(FormatDate)
}
// Datetime 回傳時間字串
func (t Timestamp) Datetime() string {
if t == 0 {
return ""
}
return time.
Unix(t.Int64(), 0).
In(Local).
In(Location).
Format(FormatDatetime)
}
// NowSub 與現在的時間差
func (t Timestamp) NowSub() time.Duration {
// Since 與現在的時間差
func (t Timestamp) Since() time.Duration {
return time.Since(t.Time())
}
// SinceMilli 與現在的時間差
func (t Timestamp) SinceMilli() time.Duration {
return time.Since(t.TimeMilli())
}
// Sub 時間差
func (t Timestamp) Sub(t2 time.Time) time.Duration {
return t2.Sub(t.Time())
}
// SubMilli 時間差
func (t Timestamp) SubMilli(t2 time.Time) time.Duration {
return t2.Sub(t.TimeMilli())
}
// After 是否在指定時間後
func (t Timestamp) After(t2 time.Time) bool {
return t.Time().After(t2)
}
// AfterMilli 是否在指定時間後
func (t Timestamp) AfterMilli(t2 time.Time) bool {
return t.TimeMilli().After(t2)
}
// AfterNow 是否在目前時間後
func (t Timestamp) AfterNow() bool {
return t.After(time.Now())
}
// AfterMilliNow 是否在目前時間後
func (t Timestamp) AfterMilliNow() bool {
return t.AfterMilli(time.Now())
}

Loading…
Cancel
Save