Skip to content

Commit eb81c8a

Browse files
author
bumu
committed
first commit
1 parent 687b095 commit eb81c8a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+3918
-14
lines changed

LICENSE

+13-14
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
1-
MIT License
1+
The MIT License (MIT)
22

3-
Copyright (c) 2023 airdb
3+
Copyright (c) 2017 airdb.com
44

5-
Permission is hereby granted, free of charge, to any person obtaining a copy
6-
of this software and associated documentation files (the "Software"), to deal
7-
in the Software without restriction, including without limitation the rights
8-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9-
copies of the Software, and to permit persons to whom the Software is
10-
furnished to do so, subject to the following conditions:
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of
6+
this software and associated documentation files (the "Software"), to deal in
7+
the Software without restriction, including without limitation the rights to
8+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9+
the Software, and to permit persons to whom the Software is furnished to do so,
10+
subject to the following conditions:
1111

1212
The above copyright notice and this permission notice shall be included in all
1313
copies or substantial portions of the Software.
1414

1515
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21-
SOFTWARE.
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
# toolbox
2+
23
Toolbox is a golang base common library

SECURITY.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Security Policy
2+
3+
## Supported Versions
4+
5+
Use this section to tell people about which versions of your project are
6+
currently being supported with security updates.
7+
8+
| Version | Supported |
9+
| ------- | ------------------ |
10+
| 5.1.x | :white_check_mark: |
11+
| 5.0.x | :x: |
12+
| 4.0.x | :white_check_mark: |
13+
| < 4.0 | :x: |
14+
15+
## Reporting a Vulnerability
16+
17+
Use this section to tell people how to report a vulnerability.
18+
19+
Tell them where to go, how often they can expect to get an update on a
20+
reported vulnerability, what to expect if the vulnerability is accepted or
21+
declined, etc.

dbkit/Makefile

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
SERVICE := redis
2+
3+
up:
4+
sudo docker-compose up -d --build --force-recreate
5+
build:
6+
sudo docker-compose build --no-cache
7+
8+
start:
9+
sudo docker-compose start
10+
11+
stop:
12+
sudo docker-compose stop
13+
14+
restart:
15+
sudo docker-compose restart
16+
17+
ps:
18+
sudo docker-compose ps
19+
20+
log logs:
21+
sudo docker-compose logs
22+
23+
rm: stop
24+
sudo docker-compose rm ${SERVICE}
25+
26+
bash:
27+
sudo docker-compose exec ${SERVICE} bash

dbkit/dbutil.go

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
package dbkit
2+
3+
import (
4+
"log"
5+
"os"
6+
"strings"
7+
"sync"
8+
"sync/atomic"
9+
"time"
10+
11+
"gorm.io/driver/mysql"
12+
"gorm.io/gorm"
13+
"gorm.io/gorm/logger"
14+
"gorm.io/gorm/schema"
15+
)
16+
17+
var (
18+
dbs sync.Map
19+
hasInit int32
20+
hasPend sync.Mutex
21+
)
22+
23+
const (
24+
DSNMainWrite = "DSN_MAIN_WRITE"
25+
DSNMainRead = "DSN_MAIN_READ"
26+
DSNSecondWrite = "DSN_SECOND_WRITE"
27+
DSNSecondRead = "DSN_SECOND_READ"
28+
)
29+
30+
var DefaultDBs = []string{
31+
DSNMainWrite,
32+
DSNMainRead,
33+
DSNSecondWrite,
34+
DSNSecondRead,
35+
}
36+
37+
func InitDefaultDB() {
38+
InitDB(DefaultDBs)
39+
}
40+
41+
func InitDB(dbNames []string) {
42+
if atomic.LoadInt32(&hasInit) == 1 {
43+
return
44+
}
45+
46+
hasPend.Lock()
47+
defer hasPend.Unlock()
48+
49+
for _, dbName := range dbNames {
50+
conn := Connect(dbName)
51+
52+
if conn != nil {
53+
dbs.Store(dbName, conn)
54+
}
55+
}
56+
57+
if atomic.LoadInt32(&hasInit) == 1 {
58+
log.Println("concurrent_between_coroutines")
59+
60+
return
61+
}
62+
63+
atomic.StoreInt32(&hasInit, 1)
64+
}
65+
66+
func WriteDefaultDB() *gorm.DB {
67+
return DB(DSNMainWrite)
68+
}
69+
70+
func ReadDefaultDB() *gorm.DB {
71+
return DB(DSNMainRead)
72+
}
73+
74+
func WriteDB(name string) *gorm.DB {
75+
return DB(name)
76+
}
77+
78+
func ReadDB(name string) *gorm.DB {
79+
return DB(name)
80+
}
81+
82+
func DB(name string) (db *gorm.DB) {
83+
_db, ok := dbs.Load(name)
84+
if ok {
85+
db = _db.(*gorm.DB)
86+
}
87+
88+
if db == nil {
89+
log.Printf("database %s is nil.\n", name)
90+
}
91+
92+
return
93+
}
94+
95+
const (
96+
maxIdleConn = 2
97+
maxOpenConn = 5
98+
)
99+
100+
// Connection gets connection of mysql database
101+
func Connect(dbName string) (db *gorm.DB) {
102+
dsn := os.Getenv(dbName)
103+
if dsn == "" {
104+
return nil
105+
}
106+
107+
if !strings.Contains(dsn, "?") {
108+
dsn += "?charset=utf8mb4&parseTime=True&loc=Local"
109+
}
110+
111+
/*
112+
newLogger := logger.New(
113+
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
114+
logger.Config{
115+
SlowThreshold: time.Second, // Slow SQL threshold
116+
// LogLevel: logger.Info, // Log level
117+
LogLevel: logger.Silent, // Log level
118+
Colorful: false, // Disable color
119+
},
120+
)
121+
*/
122+
123+
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
124+
Logger: logger.Default.LogMode(logger.Info),
125+
NamingStrategy: schema.NamingStrategy{
126+
TablePrefix: "tab_", // table name prefix, table for `User` would be `t_users`
127+
SingularTable: true, // use singular table name, table for `User` would be `user` with this option enabled
128+
},
129+
})
130+
if err != nil {
131+
log.Println(err)
132+
}
133+
134+
sqlDB, _ := db.DB()
135+
136+
sqlDB.SetMaxIdleConns(maxIdleConn)
137+
sqlDB.SetMaxOpenConns(maxOpenConn)
138+
sqlDB.SetConnMaxLifetime(time.Hour)
139+
140+
return db
141+
}
142+
143+
// InitTestDB will init the mock DB and lock the db so that the actual db will not be required.
144+
func InitTestDB(name string, db *gorm.DB) error {
145+
if !atomic.CompareAndSwapInt32(&hasInit, 0, 1) {
146+
return nil
147+
}
148+
149+
dbs.Store(name, db)
150+
151+
return nil
152+
}
153+
154+
// ReleaseTestDB is to release the lock for other unit tests to mock db successfully.
155+
func ReleaseTestDB() {
156+
atomic.CompareAndSwapInt32(&hasInit, 1, 0)
157+
}

dbkit/dbutil_test.go

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package dbkit_test
2+
3+
import (
4+
"os"
5+
"testing"
6+
7+
"github.com/airdb/toolbox/dbkit"
8+
dbutil "github.com/airdb/toolbox/dbkit"
9+
)
10+
11+
func TestInitDB(t *testing.T) {
12+
if !testing.Short() {
13+
t.Skip("skipping testing in short mode")
14+
}
15+
16+
os.Setenv("DSN_MAIN_WRITE", "airdb:airdb@tcp(127.0.0.1:3306)/test")
17+
os.Setenv("DSN_MAIN_READ", "airdb:airdb@tcp(127.0.0.1:3306)/test")
18+
19+
dbkit.InitDefaultDB()
20+
var users []string
21+
// select * from information_schema.user_privileges;
22+
23+
db := dbutil.WriteDB(dbutil.DSNMainWrite).Table("information_schema.user_privileges").
24+
Select("GRANTEE").Distinct("GRANTEE").Find(&users).Debug()
25+
if db.Error != nil {
26+
panic(db.Error)
27+
}
28+
29+
for _, user := range users {
30+
t.Log("user: ", user)
31+
}
32+
}
33+
34+
/*
35+
data := make(map[string]interface{})
36+
data["user_id"] = 0
37+
data["status"] = "ok"
38+
data["updated_at"] = uint(time.Now().Unix())
39+
db := tx.Updates(data)
40+
*/

dbkit/docker-compose.yml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
version: '3'
2+
3+
services:
4+
redis:
5+
platform: linux/amd64
6+
image: 'redis'
7+
#command: sleep 3600
8+
command: redis-server --requirepass airdb
9+
volumes:
10+
- ./:/srv/redis/
11+
ports:
12+
- "6379:6379"
13+
environment:
14+
- REDIS_PORT_NUMBER=6379
15+
- ALLOW_EMPTY_PASSWORD=yes
16+
- REDIS_PASSWORD=airdb
17+
container_name: redis

dbkit/init.sql

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
GRANT ALL PRIVILEGES ON *.* TO 'root' @'%';
2+
3+
CREATE USER 'airdb'@'%' IDENTIFIED BY 'airdb';
4+
5+
ALTER user 'airdb'@'%'IDENTIFIED BY 'airdb';
6+
7+
GRANT ALL PRIVILEGES ON *.* TO 'airdb' @'%';
8+
9+
GRANT ALL ON *.* TO 'airdb'@'%';
10+
11+
FLUSH PRIVILEGES;
12+
13+
CREATE DATABASE IF NOT EXISTS `test`;
14+
15+
USE `test`;
16+
17+
CREATE TABLE
18+
IF NOT EXISTS `tab_user` (
19+
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
20+
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
21+
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
22+
`deleted_at` TIMESTAMP NULL DEFAULT NULL,
23+
`user` varchar(512) COLLATE utf8mb4_unicode_ci NOT NULL,
24+
PRIMARY KEY (`id`)
25+
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;

dbkit/redis.go

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package dbkit
2+
3+
import (
4+
"log"
5+
6+
"github.com/go-redis/redis"
7+
)
8+
9+
func NewRedisClient(opt *redis.Options) *redis.Client {
10+
redisdb := redis.NewClient(opt)
11+
12+
log.Println("redis status:", redisdb.Ping())
13+
14+
return redisdb
15+
}

dbkit/redis_test.go

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package dbkit_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/airdb/toolbox/dbkit"
7+
"github.com/go-redis/redis"
8+
)
9+
10+
func TestNewRedisClient(t *testing.T) {
11+
if !testing.Short() {
12+
t.Skip("skipping testing in short mode")
13+
}
14+
15+
opt := redis.Options{}
16+
opt.Addr = "127.0.0.1:6379"
17+
opt.DB = 2
18+
opt.Password = "airdb"
19+
20+
redisdb := dbkit.NewRedisClient(&opt)
21+
t.Log(redisdb.Ping())
22+
}

docker-compose.yml

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
version: '3'
2+
3+
services:
4+
mysql:
5+
image: mysql:latest
6+
#command: --init-file /srv/sql/init.sql
7+
command: --default-authentication-plugin=mysql_native_password
8+
volumes:
9+
- ./dbutil/init.sql:/docker-entrypoint-initdb.d/init.sql
10+
ports:
11+
- "3306:3306"
12+
environment:
13+
MYSQL_ROOT_HOST: '%'
14+
MYSQL_DATABASE: test
15+
MYSQL_USER: airdb
16+
MYSQL_PASSWORD: airdb
17+
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
18+
container_name: mysql
19+
20+
redis:
21+
image: redis:6.2-alpine
22+
restart: always
23+
ports:
24+
- '6379:6379'
25+
command: redis-server --save 20 1 --loglevel warning --requirepass eYVX7EwVmmxKPCDmwMtyKVge8oLd2t81
26+
container_name: redis

0 commit comments

Comments
 (0)