package client import ( "crypto/tls" "net" "sync" "git.loafle.net/commons_go/logging" ) type Socket interface { Context() SocketContext net.Conn } func NewSocket(sb SocketBuilder, parentContext cuc.Context) (Socket, error) { if nil == sb { logging.Logger().Panic("Client Socket: SocketBuilder must be specified") } sb.Validate() sc := sb.SocketContext(parentContext) if nil == sc { logging.Logger().Panic("Client Socket: SocketContext must be specified") } sh := sb.SocketHandler() if nil == sh { logging.Logger().Panic("Client Socket: SocketHandler must be specified") } sh.Validate() d := &net.Dialer{} d.Timeout = sb.GetTimeout() d.KeepAlive = sb.GetKeepAlive() d.LocalAddr = sb.GetLocalAddress() network := sb.GetNetwork() address := sb.GetAddress() tlsConfig := sb.GetTLSConfig() var conn net.Conn var err error if nil == tlsConfig { conn, err = d.Dial(network, address) } else { conn, err = tls.DialWithDialer(d, network, address, tlsConfig) } if nil != err { return nil, err } sh.OnConnect(sc, conn) s := retainSocket() s.ctx = sc s.sh = sh return s, nil } type netSocket struct { net.Conn ctx SocketContext sh SocketHandler } func (s *netSocket) Context() SocketContext { return s.ctx } func (s *netSocket) Close() error { err := s.Conn.Close() s.sh.OnDisconnect(s) releaseSocket(s) return err } var socketPool sync.Pool func retainSocket() *netSocket { v := socketPool.Get() if v == nil { return &netSocket{} } return v.(*netSocket) } func releaseSocket(s *netSocket) { s.sh = nil s.ctx = nil socketPool.Put(s) }