ldap-1-backend/public/common/ldap.go

160 lines
3.4 KiB
Go
Raw Normal View History

2022-05-18 17:57:03 +08:00
package common
import (
"fmt"
2022-07-24 21:24:08 +08:00
"log"
"math/rand"
2022-05-18 17:57:03 +08:00
"net"
2022-07-24 21:24:08 +08:00
"sync"
2022-05-18 17:57:03 +08:00
"time"
2022-05-29 10:06:21 +08:00
"github.com/eryajf/go-ldap-admin/config"
2022-05-18 17:57:03 +08:00
ldap "github.com/go-ldap/ldap/v3"
)
2022-07-24 21:24:08 +08:00
var ldapPool *LdapConnPool
var ldapInit = false
var ldapInitOne sync.Once
2022-05-18 17:57:03 +08:00
// Init 初始化连接
func InitLDAP() {
2022-07-24 21:24:08 +08:00
if ldapInit {
return
}
ldapInitOne.Do(func() {
ldapInit = true
})
2022-05-18 17:57:03 +08:00
// Dail有两个参数 network, address, 返回 (*Conn, error)
2022-07-24 21:24:08 +08:00
ldapConn, err := ldap.DialURL(config.Conf.Ldap.Url, ldap.DialWithDialer(&net.Dialer{Timeout: 5 * time.Second}))
2022-05-18 17:57:03 +08:00
if err != nil {
Log.Panicf("初始化ldap连接异常: %v", err)
panic(fmt.Errorf("初始化ldap连接异常: %v", err))
}
2022-07-24 21:24:08 +08:00
err = ldapConn.Bind(config.Conf.Ldap.AdminDN, config.Conf.Ldap.AdminPass)
2022-05-18 17:57:03 +08:00
if err != nil {
Log.Panicf("绑定admin账号异常: %v", err)
panic(fmt.Errorf("绑定admin账号异常: %v", err))
}
2022-07-24 21:24:08 +08:00
// 全局变量赋值
ldapPool = &LdapConnPool{
conns: make([]*ldap.Conn, 0),
reqConns: make(map[uint64]chan *ldap.Conn),
openConn: 0,
maxOpen: config.Conf.Ldap.MaxConn,
}
PutLADPConn(ldapConn)
2022-05-18 17:57:03 +08:00
// 隐藏密码
showDsn := fmt.Sprintf(
"%s:******@tcp(%s)",
config.Conf.Ldap.AdminDN,
config.Conf.Ldap.Url,
2022-05-18 17:57:03 +08:00
)
Log.Info("初始化ldap完成! dsn: ", showDsn)
}
2022-07-24 21:24:08 +08:00
// GetLDAPConn 获取 LDAP 连接
func GetLDAPConn() (*ldap.Conn, error) {
return ldapPool.GetConnection()
}
// PutLDAPConn 放回 LDAP 连接
func PutLADPConn(conn *ldap.Conn) {
ldapPool.PutConnection(conn)
}
type LdapConnPool struct {
mu sync.Mutex
conns []*ldap.Conn
reqConns map[uint64]chan *ldap.Conn
openConn int
maxOpen int
}
// 获取一个 ladp Conn
func (lcp *LdapConnPool) GetConnection() (*ldap.Conn, error) {
lcp.mu.Lock()
// 判断当前连接池内是否存在连接
connNum := len(lcp.conns)
if connNum > 0 {
lcp.openConn++
conn := lcp.conns[0]
copy(lcp.conns, lcp.conns[1:])
lcp.conns = lcp.conns[:connNum-1]
lcp.mu.Unlock()
// 发现连接已经 close 重新获取连接
if conn.IsClosing() {
return initLDAPConn()
}
return conn, nil
}
// 当现有连接池为空时,并且当前超过最大连接限制
if lcp.maxOpen != 0 && lcp.openConn > lcp.maxOpen {
// 创建一个等待队列
req := make(chan *ldap.Conn, 1)
reqKey := lcp.nextRequestKeyLocked()
lcp.reqConns[reqKey] = req
lcp.mu.Unlock()
// 等待请求归还
return <-req, nil
} else {
lcp.openConn++
lcp.mu.Unlock()
return initLDAPConn()
}
}
func (lcp *LdapConnPool) PutConnection(conn *ldap.Conn) {
log.Println("放回了一个连接")
lcp.mu.Lock()
defer lcp.mu.Unlock()
// 先判断是否存在等待的队列
if num := len(lcp.reqConns); num > 0 {
var req chan *ldap.Conn
var reqKey uint64
for reqKey, req = range lcp.reqConns {
break
}
delete(lcp.reqConns, reqKey)
req <- conn
return
} else {
lcp.openConn--
if !conn.IsClosing() {
lcp.conns = append(lcp.conns, conn)
}
}
}
// 获取下一个请求令牌
func (lcp *LdapConnPool) nextRequestKeyLocked() uint64 {
for {
reqKey := rand.Uint64()
if _, ok := lcp.reqConns[reqKey]; !ok {
return reqKey
}
}
}
// 获取 ladp 连接
func initLDAPConn() (*ldap.Conn, error) {
ldap, err := ldap.DialURL(config.Conf.Ldap.Url, ldap.DialWithDialer(&net.Dialer{Timeout: 5 * time.Second}))
if err != nil {
return nil, err
}
err = ldap.Bind(config.Conf.Ldap.AdminDN, config.Conf.Ldap.AdminPass)
if err != nil {
return nil, err
}
return ldap, err
}