Skip to content

Commit 396546d

Browse files
authored
feat: LDAP 添加连接池支持 (#95)
1 parent 019f7fd commit 396546d

File tree

6 files changed

+243
-21
lines changed

6 files changed

+243
-21
lines changed

config.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ email:
8585
ldap:
8686
# ldap服务器地址
8787
url: ldap://localhost:389
88+
# ladp最大连接数设置
89+
max-conn: 10
8890
# ldap服务器基础DN
8991
base-dn: "dc=eryajf,dc=net"
9092
# ldap管理员DN

config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ type RateLimitConfig struct {
135135

136136
type LdapConfig struct {
137137
Url string `mapstructure:"url" json:"url"`
138+
MaxConn int `mapstructure:"max-conn" json:"maxConn"`
138139
BaseDN string `mapstructure:"base-dn" json:"baseDN"`
139140
AdminDN string `mapstructure:"admin-dn" json:"adminDN"`
140141
AdminPass string `mapstructure:"admin-pass" json:"adminPass"`

public/client/openldap/openldap.go

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,16 @@ func GetAllDepts() (ret []*Dept, err error) {
4444
[]string{}, // Here are the attributes returned by the query, provided as an array. If empty, all attributes are returned
4545
nil,
4646
)
47+
48+
// 获取 LDAP 连接
49+
conn, err := common.GetLDAPConn()
50+
defer common.PutLADPConn(conn)
51+
if err != nil {
52+
return nil, err
53+
}
54+
4755
// Search through ldap built-in search
48-
sr, err := common.LDAP.Search(searchRequest)
56+
sr, err := conn.Search(searchRequest)
4957
if err != nil {
5058
return ret, err
5159
}
@@ -81,8 +89,16 @@ func GetAllUsers() (ret []*User, err error) {
8189
[]string{}, // Here are the attributes returned by the query, provided as an array. If empty, all attributes are returned
8290
nil,
8391
)
92+
93+
// 获取 LDAP 连接
94+
conn, err := common.GetLDAPConn()
95+
defer common.PutLADPConn(conn)
96+
if err != nil {
97+
return nil, err
98+
}
99+
84100
// Search through ldap built-in search
85-
sr, err := common.LDAP.Search(searchRequest)
101+
sr, err := conn.Search(searchRequest)
86102
if err != nil {
87103
return ret, err
88104
}
@@ -128,8 +144,16 @@ func GetUserDeptIds(udn string) (ret []string, err error) {
128144
[]string{}, // Here are the attributes returned by the query, provided as an array. If empty, all attributes are returned
129145
nil,
130146
)
147+
148+
// 获取 LDAP 连接
149+
conn, err := common.GetLDAPConn()
150+
defer common.PutLADPConn(conn)
151+
if err != nil {
152+
return nil, err
153+
}
154+
131155
// Search through ldap built-in search
132-
sr, err := common.LDAP.Search(searchRequest)
156+
sr, err := conn.Search(searchRequest)
133157
if err != nil {
134158
return ret, err
135159
}

public/common/ldap.go

Lines changed: 124 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,51 @@ package common
22

33
import (
44
"fmt"
5+
"log"
6+
"math/rand"
57
"net"
8+
"sync"
69
"time"
710

811
"github.com/eryajf/go-ldap-admin/config"
912

1013
ldap "github.com/go-ldap/ldap/v3"
1114
)
1215

13-
// 全局ldap数据库变量
14-
var LDAP *ldap.Conn
16+
var ldapPool *LdapConnPool
17+
var ldapInit = false
18+
var ldapInitOne sync.Once
1519

1620
// Init 初始化连接
1721
func InitLDAP() {
22+
if ldapInit {
23+
return
24+
}
25+
26+
ldapInitOne.Do(func() {
27+
ldapInit = true
28+
})
29+
1830
// 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}))
2032
if err != nil {
2133
Log.Panicf("初始化ldap连接异常: %v", err)
2234
panic(fmt.Errorf("初始化ldap连接异常: %v", err))
2335
}
24-
err = ldap.Bind(config.Conf.Ldap.AdminDN, config.Conf.Ldap.AdminPass)
36+
err = ldapConn.Bind(config.Conf.Ldap.AdminDN, config.Conf.Ldap.AdminPass)
2537
if err != nil {
2638
Log.Panicf("绑定admin账号异常: %v", err)
2739
panic(fmt.Errorf("绑定admin账号异常: %v", err))
2840
}
2941

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)
3250

3351
// 隐藏密码
3452
showDsn := fmt.Sprintf(
@@ -39,3 +57,103 @@ func InitLDAP() {
3957

4058
Log.Info("初始化ldap完成! dsn: ", showDsn)
4159
}
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+
}

service/ildap/group_ildap.go

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,36 @@ func (x GroupService) Add(g *model.Group) error { //organizationalUnit
2828
add.Attribute(g.GroupType, []string{g.GroupName})
2929
add.Attribute("description", []string{g.Remark})
3030

31-
return common.LDAP.Add(add)
31+
// 获取 LDAP 连接
32+
conn, err := common.GetLDAPConn()
33+
defer common.PutLADPConn(conn)
34+
if err != nil {
35+
return err
36+
}
37+
38+
return conn.Add(add)
3239
}
3340

3441
// UpdateGroup 更新一个分组
3542
func (x GroupService) Update(oldGroup, newGroup *model.Group) error {
3643
modify := ldap.NewModifyRequest(oldGroup.GroupDN, nil)
3744
modify.Replace("description", []string{newGroup.Remark})
38-
err := common.LDAP.Modify(modify)
45+
46+
// 获取 LDAP 连接
47+
conn, err := common.GetLDAPConn()
48+
defer common.PutLADPConn(conn)
49+
if err != nil {
50+
return err
51+
}
52+
53+
err = conn.Modify(modify)
3954
if err != nil {
4055
return err
4156
}
4257
// 如果配置文件允许修改分组名称,且分组名称发生了变化,那么执行修改分组名称
4358
if config.Conf.Ldap.GroupNameModify && newGroup.GroupName != oldGroup.GroupName {
4459
modify := ldap.NewModifyDNRequest(oldGroup.GroupDN, newGroup.GroupDN, true, "")
45-
err := common.LDAP.ModifyDN(modify)
60+
err := conn.ModifyDN(modify)
4661
if err != nil {
4762
return err
4863
}
@@ -53,7 +68,15 @@ func (x GroupService) Update(oldGroup, newGroup *model.Group) error {
5368
// Delete 删除资源
5469
func (x GroupService) Delete(gdn string) error {
5570
del := ldap.NewDelRequest(gdn, nil)
56-
return common.LDAP.Del(del)
71+
72+
// 获取 LDAP 连接
73+
conn, err := common.GetLDAPConn()
74+
defer common.PutLADPConn(conn)
75+
if err != nil {
76+
return err
77+
}
78+
79+
return conn.Del(del)
5780
}
5881

5982
// AddUserToGroup 添加用户到分组
@@ -64,12 +87,28 @@ func (x GroupService) AddUserToGroup(dn, udn string) error {
6487
}
6588
newmr := ldap.NewModifyRequest(dn, nil)
6689
newmr.Add("uniqueMember", []string{udn})
67-
return common.LDAP.Modify(newmr)
90+
91+
// 获取 LDAP 连接
92+
conn, err := common.GetLDAPConn()
93+
defer common.PutLADPConn(conn)
94+
if err != nil {
95+
return err
96+
}
97+
98+
return conn.Modify(newmr)
6899
}
69100

70101
// DelUserFromGroup 将用户从分组删除
71102
func (x GroupService) RemoveUserFromGroup(gdn, udn string) error {
72103
newmr := ldap.NewModifyRequest(gdn, nil)
73104
newmr.Delete("uniqueMember", []string{udn})
74-
return common.LDAP.Modify(newmr)
105+
106+
// 获取 LDAP 连接
107+
conn, err := common.GetLDAPConn()
108+
defer common.PutLADPConn(conn)
109+
if err != nil {
110+
return err
111+
}
112+
113+
return conn.Modify(newmr)
75114
}

0 commit comments

Comments
 (0)