@@ -2,33 +2,51 @@ package common
2
2
3
3
import (
4
4
"fmt"
5
+ "log"
6
+ "math/rand"
5
7
"net"
8
+ "sync"
6
9
"time"
7
10
8
11
"github.com/eryajf/go-ldap-admin/config"
9
12
10
13
ldap "github.com/go-ldap/ldap/v3"
11
14
)
12
15
13
- // 全局ldap数据库变量
14
- var LDAP * ldap.Conn
16
+ var ldapPool * LdapConnPool
17
+ var ldapInit = false
18
+ var ldapInitOne sync.Once
15
19
16
20
// Init 初始化连接
17
21
func InitLDAP () {
22
+ if ldapInit {
23
+ return
24
+ }
25
+
26
+ ldapInitOne .Do (func () {
27
+ ldapInit = true
28
+ })
29
+
18
30
// Dail有两个参数 network, address, 返回 (*Conn, error)
19
- ldap , err := ldap .DialURL (config .Conf .Ldap .Url , ldap .DialWithDialer (& net.Dialer {Timeout : 5 * time .Second }))
31
+ ldapConn , err := ldap .DialURL (config .Conf .Ldap .Url , ldap .DialWithDialer (& net.Dialer {Timeout : 5 * time .Second }))
20
32
if err != nil {
21
33
Log .Panicf ("初始化ldap连接异常: %v" , err )
22
34
panic (fmt .Errorf ("初始化ldap连接异常: %v" , err ))
23
35
}
24
- err = ldap .Bind (config .Conf .Ldap .AdminDN , config .Conf .Ldap .AdminPass )
36
+ err = ldapConn .Bind (config .Conf .Ldap .AdminDN , config .Conf .Ldap .AdminPass )
25
37
if err != nil {
26
38
Log .Panicf ("绑定admin账号异常: %v" , err )
27
39
panic (fmt .Errorf ("绑定admin账号异常: %v" , err ))
28
40
}
29
41
30
- // 全局LDAP赋值
31
- LDAP = ldap
42
+ // 全局变量赋值
43
+ ldapPool = & LdapConnPool {
44
+ conns : make ([]* ldap.Conn , 0 ),
45
+ reqConns : make (map [uint64 ]chan * ldap.Conn ),
46
+ openConn : 0 ,
47
+ maxOpen : config .Conf .Ldap .MaxConn ,
48
+ }
49
+ PutLADPConn (ldapConn )
32
50
33
51
// 隐藏密码
34
52
showDsn := fmt .Sprintf (
@@ -39,3 +57,103 @@ func InitLDAP() {
39
57
40
58
Log .Info ("初始化ldap完成! dsn: " , showDsn )
41
59
}
60
+
61
+ // GetLDAPConn 获取 LDAP 连接
62
+ func GetLDAPConn () (* ldap.Conn , error ) {
63
+ return ldapPool .GetConnection ()
64
+ }
65
+
66
+ // PutLDAPConn 放回 LDAP 连接
67
+ func PutLADPConn (conn * ldap.Conn ) {
68
+ ldapPool .PutConnection (conn )
69
+ }
70
+
71
+ type LdapConnPool struct {
72
+ mu sync.Mutex
73
+ conns []* ldap.Conn
74
+ reqConns map [uint64 ]chan * ldap.Conn
75
+ openConn int
76
+ maxOpen int
77
+ }
78
+
79
+ // 获取一个 ladp Conn
80
+ func (lcp * LdapConnPool ) GetConnection () (* ldap.Conn , error ) {
81
+ lcp .mu .Lock ()
82
+ // 判断当前连接池内是否存在连接
83
+ connNum := len (lcp .conns )
84
+ if connNum > 0 {
85
+ lcp .openConn ++
86
+ conn := lcp .conns [0 ]
87
+ copy (lcp .conns , lcp .conns [1 :])
88
+ lcp .conns = lcp .conns [:connNum - 1 ]
89
+
90
+ lcp .mu .Unlock ()
91
+ // 发现连接已经 close 重新获取连接
92
+ if conn .IsClosing () {
93
+ return initLDAPConn ()
94
+ }
95
+ return conn , nil
96
+ }
97
+
98
+ // 当现有连接池为空时,并且当前超过最大连接限制
99
+ if lcp .maxOpen != 0 && lcp .openConn > lcp .maxOpen {
100
+ // 创建一个等待队列
101
+ req := make (chan * ldap.Conn , 1 )
102
+ reqKey := lcp .nextRequestKeyLocked ()
103
+ lcp .reqConns [reqKey ] = req
104
+ lcp .mu .Unlock ()
105
+
106
+ // 等待请求归还
107
+ return <- req , nil
108
+ } else {
109
+ lcp .openConn ++
110
+ lcp .mu .Unlock ()
111
+ return initLDAPConn ()
112
+ }
113
+ }
114
+
115
+ func (lcp * LdapConnPool ) PutConnection (conn * ldap.Conn ) {
116
+ log .Println ("放回了一个连接" )
117
+ lcp .mu .Lock ()
118
+ defer lcp .mu .Unlock ()
119
+
120
+ // 先判断是否存在等待的队列
121
+ if num := len (lcp .reqConns ); num > 0 {
122
+ var req chan * ldap.Conn
123
+ var reqKey uint64
124
+ for reqKey , req = range lcp .reqConns {
125
+ break
126
+ }
127
+ delete (lcp .reqConns , reqKey )
128
+ req <- conn
129
+ return
130
+ } else {
131
+ lcp .openConn --
132
+ if ! conn .IsClosing () {
133
+ lcp .conns = append (lcp .conns , conn )
134
+ }
135
+ }
136
+ }
137
+
138
+ // 获取下一个请求令牌
139
+ func (lcp * LdapConnPool ) nextRequestKeyLocked () uint64 {
140
+ for {
141
+ reqKey := rand .Uint64 ()
142
+ if _ , ok := lcp .reqConns [reqKey ]; ! ok {
143
+ return reqKey
144
+ }
145
+ }
146
+ }
147
+
148
+ // 获取 ladp 连接
149
+ func initLDAPConn () (* ldap.Conn , error ) {
150
+ ldap , err := ldap .DialURL (config .Conf .Ldap .Url , ldap .DialWithDialer (& net.Dialer {Timeout : 5 * time .Second }))
151
+ if err != nil {
152
+ return nil , err
153
+ }
154
+ err = ldap .Bind (config .Conf .Ldap .AdminDN , config .Conf .Ldap .AdminPass )
155
+ if err != nil {
156
+ return nil , err
157
+ }
158
+ return ldap , err
159
+ }
0 commit comments