qdy 3 месяцев назад
Родитель
Сommit
6a061057b9

factory/db_factory.go → factory/database/db_factory.go Просмотреть файл

@@ -1,4 +1,4 @@
1
-package factory
1
+package database
2 2
 
3 3
 import (
4 4
 	"fmt"

factory/doris_factory.go → factory/doris/doris_factory.go Просмотреть файл

@@ -1,4 +1,4 @@
1
-package factory
1
+package doris
2 2
 
3 3
 import (
4 4
 	"encoding/json"
@@ -7,6 +7,7 @@ import (
7 7
 	"time"
8 8
 
9 9
 	"git.x2erp.com/qdy/go-base/config"
10
+	"git.x2erp.com/qdy/go-db/factory/http"
10 11
 	"github.com/go-resty/resty/v2"
11 12
 )
12 13
 
@@ -29,7 +30,7 @@ var (
29 30
 )
30 31
 
31 32
 // GetDorisFactory 获取Doris工厂单例
32
-func GetDorisFactory(httpFactory *HTTPFactory) (*DorisFactory, error) {
33
+func GetDorisFactory(httpFactory *http.HTTPFactory) (*DorisFactory, error) {
33 34
 	var initErr error
34 35
 	instanceOnce.Do(func() {
35 36
 		cfg := config.GetConfig()
@@ -46,7 +47,7 @@ func GetDorisFactory(httpFactory *HTTPFactory) (*DorisFactory, error) {
46 47
 
47 48
 		dorisConfig := cfg.GetDoris()
48 49
 		instance = &DorisFactory{
49
-			client:   httpFactory.CreateClient().client,
50
+			client:   httpFactory.GetUnderlyingClient(),
50 51
 			FEHost:   dorisConfig.FEHost,
51 52
 			FEPort:   dorisConfig.FEPort,
52 53
 			Username: dorisConfig.FEUsername,

factory/http_factory.go → factory/http/http_factory.go Просмотреть файл

@@ -1,4 +1,4 @@
1
-package factory
1
+package http
2 2
 
3 3
 import (
4 4
 	"encoding/base64"
@@ -74,6 +74,14 @@ func (f *HTTPFactory) CreateClient() *HTTPClient {
74 74
 	}
75 75
 }
76 76
 
77
+// GetUnderlyingClient 获取底层resty客户端(用于特殊场景)
78
+func (f *HTTPFactory) GetUnderlyingClient() *resty.Client {
79
+	if f == nil {
80
+		return nil
81
+	}
82
+	return f.client
83
+}
84
+
77 85
 // CreateClient 全局便捷函数:创建HTTP客户端
78 86
 func CreateClient() (*HTTPClient, error) {
79 87
 	factory, err := GetHTTPFactory()

+ 193
- 0
factory/rabbitmq/rabbitmq_factory.go Просмотреть файл

@@ -0,0 +1,193 @@
1
+// factory/rabbitmq_factory.go
2
+package rabbitmq
3
+
4
+import (
5
+	"fmt"
6
+	"sync"
7
+
8
+	"git.x2erp.com/qdy/go-base/config"
9
+	amqp "github.com/streadway/amqp"
10
+)
11
+
12
+// RabbitMQFactory RabbitMQ工厂
13
+type RabbitMQFactory struct {
14
+	mu      sync.RWMutex
15
+	clients map[string]*amqp.Channel
16
+	conn    *amqp.Connection
17
+	config  config.RabbitMQConfig
18
+}
19
+
20
+// NewRabbitMQFactory 创建RabbitMQ工厂
21
+func NewRabbitMQFactory() (*RabbitMQFactory, error) {
22
+	cfg := config.GetConfig()
23
+
24
+	if err := config.GetInitError(); err != nil {
25
+		return nil, fmt.Errorf("failed to load config: %v", err)
26
+	}
27
+
28
+	rabbitConfig := cfg.GetRabbitMQ()
29
+	if rabbitConfig.Host == "" || rabbitConfig.Port == 0 {
30
+		return nil, fmt.Errorf("rabbitmq configuration is incomplete")
31
+	}
32
+
33
+	// 构建连接URL
34
+	url := fmt.Sprintf("amqp://%s:%s@%s:%d/%s",
35
+		rabbitConfig.Username,
36
+		rabbitConfig.Password,
37
+		rabbitConfig.Host,
38
+		rabbitConfig.Port,
39
+		rabbitConfig.Vhost)
40
+
41
+	// 建立连接
42
+	conn, err := amqp.Dial(url)
43
+	if err != nil {
44
+		return nil, fmt.Errorf("failed to connect to rabbitmq: %v", err)
45
+	}
46
+
47
+	return &RabbitMQFactory{
48
+		conn:    conn,
49
+		config:  rabbitConfig,
50
+		clients: make(map[string]*amqp.Channel),
51
+	}, nil
52
+}
53
+
54
+// CreateChannel 创建消息通道
55
+func (f *RabbitMQFactory) CreateChannel(name string) (*amqp.Channel, error) {
56
+	f.mu.Lock()
57
+	defer f.mu.Unlock()
58
+
59
+	// 如果已存在,直接返回
60
+	if channel, ok := f.clients[name]; ok && channel != nil {
61
+		return channel, nil
62
+	}
63
+
64
+	// 创建新通道
65
+	channel, err := f.conn.Channel()
66
+	if err != nil {
67
+		return nil, fmt.Errorf("failed to create channel '%s': %v", name, err)
68
+	}
69
+
70
+	// 设置QoS(可选)
71
+	if f.config.PrefetchCount > 0 {
72
+		err = channel.Qos(
73
+			f.config.PrefetchCount,
74
+			f.config.PrefetchSize,
75
+			f.config.Global,
76
+		)
77
+		if err != nil {
78
+			channel.Close()
79
+			return nil, fmt.Errorf("failed to set qos for channel '%s': %v", name, err)
80
+		}
81
+	}
82
+
83
+	f.clients[name] = channel
84
+	return channel, nil
85
+}
86
+
87
+// GetChannel 获取已创建的通道
88
+func (f *RabbitMQFactory) GetChannel(name string) (*amqp.Channel, error) {
89
+	f.mu.RLock()
90
+	defer f.mu.RUnlock()
91
+
92
+	channel, ok := f.clients[name]
93
+	if !ok || channel == nil {
94
+		return nil, fmt.Errorf("channel '%s' not found", name)
95
+	}
96
+	return channel, nil
97
+}
98
+
99
+// CloseChannel 关闭指定通道
100
+func (f *RabbitMQFactory) CloseChannel(name string) error {
101
+	f.mu.Lock()
102
+	defer f.mu.Unlock()
103
+
104
+	channel, ok := f.clients[name]
105
+	if ok && channel != nil {
106
+		if err := channel.Close(); err != nil {
107
+			return fmt.Errorf("failed to close channel '%s': %v", name, err)
108
+		}
109
+		delete(f.clients, name)
110
+	}
111
+	return nil
112
+}
113
+
114
+// AddExchange 添加交换机
115
+func (f *RabbitMQFactory) AddExchange(channelName, exchange, exchangeType string, durable bool) error {
116
+	channel, err := f.GetChannel(channelName)
117
+	if err != nil {
118
+		return err
119
+	}
120
+
121
+	return channel.ExchangeDeclare(
122
+		exchange,
123
+		exchangeType, // "direct", "fanout", "topic", "headers"
124
+		durable,      // durable
125
+		false,        // auto-deleted
126
+		false,        // internal
127
+		false,        // no-wait
128
+		nil,          // arguments
129
+	)
130
+}
131
+
132
+// AddQueue 添加队列
133
+func (f *RabbitMQFactory) AddQueue(channelName, queue string, durable, exclusive, autoDelete bool) error {
134
+	channel, err := f.GetChannel(channelName)
135
+	if err != nil {
136
+		return err
137
+	}
138
+
139
+	_, err = channel.QueueDeclare(
140
+		queue,
141
+		durable,    // durable
142
+		autoDelete, // delete when unused
143
+		exclusive,  // exclusive
144
+		false,      // no-wait
145
+		nil,        // arguments
146
+	)
147
+	return err
148
+}
149
+
150
+// BindQueue 绑定队列到交换机
151
+func (f *RabbitMQFactory) BindQueue(channelName, queue, exchange, routingKey string) error {
152
+	channel, err := f.GetChannel(channelName)
153
+	if err != nil {
154
+		return err
155
+	}
156
+
157
+	return channel.QueueBind(
158
+		queue,
159
+		routingKey,
160
+		exchange,
161
+		false, // no-wait
162
+		nil,   // arguments
163
+	)
164
+}
165
+
166
+// Close 关闭所有连接
167
+func (f *RabbitMQFactory) Close() error {
168
+	f.mu.Lock()
169
+	defer f.mu.Unlock()
170
+
171
+	// 关闭所有通道
172
+	var errs []error
173
+	for name, channel := range f.clients {
174
+		if channel != nil {
175
+			if err := channel.Close(); err != nil {
176
+				errs = append(errs, fmt.Errorf("close channel '%s' error: %v", name, err))
177
+			}
178
+		}
179
+	}
180
+	f.clients = make(map[string]*amqp.Channel)
181
+
182
+	// 关闭连接
183
+	if f.conn != nil {
184
+		if err := f.conn.Close(); err != nil {
185
+			errs = append(errs, fmt.Errorf("close connection error: %v", err))
186
+		}
187
+	}
188
+
189
+	if len(errs) > 0 {
190
+		return fmt.Errorf("errors closing rabbitmq: %v", errs)
191
+	}
192
+	return nil
193
+}

factory/redis_factory.go → factory/redis/redis_factory.go Просмотреть файл

@@ -1,4 +1,4 @@
1
-package factory
1
+package redis
2 2
 
3 3
 import (
4 4
 	"context"

+ 3
- 0
go.mod Просмотреть файл

@@ -10,6 +10,7 @@ require (
10 10
 	github.com/sijms/go-ora/v2 v2.9.0
11 11
 )
12 12
 
13
+
13 14
 require (
14 15
 	github.com/cespare/xxhash/v2 v2.1.2 // indirect
15 16
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
@@ -26,6 +27,8 @@ require (
26 27
 	github.com/golang-sql/sqlexp v0.1.0 // indirect
27 28
 	github.com/google/uuid v1.6.0 // indirect
28 29
 	github.com/jmoiron/sqlx v1.4.0
30
+	github.com/rabbitmq/amqp091-go v1.10.0
31
+	github.com/streadway/amqp v1.1.0
29 32
 	golang.org/x/crypto v0.41.0 // indirect
30 33
 	golang.org/x/text v0.28.0 // indirect
31 34
 )

+ 4
- 0
go.sum Просмотреть файл

@@ -58,8 +58,12 @@ github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmd
58 58
 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
59 59
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
60 60
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
61
+github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw=
62
+github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o=
61 63
 github.com/sijms/go-ora/v2 v2.9.0 h1:+iQbUeTeCOFMb5BsOMgUhV8KWyrv9yjKpcK4x7+MFrg=
62 64
 github.com/sijms/go-ora/v2 v2.9.0/go.mod h1:QgFInVi3ZWyqAiJwzBQA+nbKYKH77tdp1PYoCqhR2dU=
65
+github.com/streadway/amqp v1.1.0 h1:py12iX8XSyI7aN/3dUT8DFIDJazNJsVJdxNVEpnQTZM=
66
+github.com/streadway/amqp v1.1.0/go.mod h1:WYSrTEYHOXHd0nwFeUXAe2G2hRnQT+deZJJf88uS9Bg=
63 67
 github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
64 68
 github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
65 69
 golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=

+ 3
- 3
test.go Просмотреть файл

@@ -5,7 +5,7 @@ import (
5 5
 	"log"
6 6
 
7 7
 	"git.x2erp.com/qdy/go-base/config"
8
-	"git.x2erp.com/qdy/go-db/factory"
8
+	"git.x2erp.com/qdy/go-db/factory/database"
9 9
 )
10 10
 
11 11
 func main() {
@@ -19,7 +19,7 @@ func main() {
19 19
 
20 20
 	// 创建数据库工厂
21 21
 	fmt.Printf("第1次.\n")
22
-	dbFactory, err := factory.GetDBFactory()
22
+	dbFactory, err := database.GetDBFactory()
23 23
 
24 24
 	if err != nil {
25 25
 		log.Fatalf("Failed to create DB factory: %v", err)
@@ -27,7 +27,7 @@ func main() {
27 27
 
28 28
 	//测试单例是否生效
29 29
 	fmt.Printf("第2次.\n")
30
-	dbFactory1, err1 := factory.GetDBFactory()
30
+	dbFactory1, err1 := database.GetDBFactory()
31 31
 
32 32
 	if err1 != nil {
33 33
 		log.Fatalf("Failed to create DB factory: %v", err1)

Загрузка…
Отмена
Сохранить