Commit 0a17a4a3 authored by AlexStocks's avatar AlexStocks

add ClientOptions & Client; add ServerOptions & Server; version 0.8.2

parent 09d0a578
...@@ -17,7 +17,9 @@ ...@@ -17,7 +17,9 @@
- 2018/03/17 - 2018/03/17
> improvement > improvement
* add end point type * add end point type
* add Client & Server interface * add ClientOptions & Client
* add ServerOptions & Server
* version 0.8.2
- 2018/03/16 - 2018/03/16
> bug fix > bug fix
......
...@@ -28,9 +28,9 @@ import ( ...@@ -28,9 +28,9 @@ import (
) )
const ( const (
defaultInterval = 3e9 // 3s connInterval = 3e9 // 3s
connectTimeout = 5e9 connectTimeout = 5e9
maxTimes = 10 maxTimes = 10
) )
///////////////////////////////////////// /////////////////////////////////////////
...@@ -38,134 +38,106 @@ const ( ...@@ -38,134 +38,106 @@ const (
///////////////////////////////////////// /////////////////////////////////////////
type client struct { type client struct {
ClientOptions
// net // net
sync.Mutex sync.Mutex
endPointType EndPointType endPointType EndPointType
number int
interval time.Duration newSession NewSessionCallback
addr string ssMap map[Session]gxsync.Empty
newSession NewSessionCallback
ssMap map[Session]gxsync.Empty
sync.Once sync.Once
done chan gxsync.Empty done chan gxsync.Empty
wg sync.WaitGroup wg sync.WaitGroup
// for wss client
// 服务端的证书文件(包含了公钥以及服务端其他一些验证信息:服务端域名、
// 服务端ip、起始有效日期、有效时长、hash算法、秘钥长度等)
cert string
} }
// NewTcpClient function builds a tcp client. func (c *client) init(opts ...ClientOption) {
// @connNum is connection number. for _, opt := range opts {
// @connInterval is reconnect sleep interval when getty fails to connect the server. opt(&(c.ClientOptions))
// @serverAddr is server address.
func NewTCPClient(connNum int, connInterval time.Duration, serverAddr string) Client {
if connNum <= 0 || serverAddr == "" {
panic(fmt.Sprintf("@connNum:%d, @serverAddr:%s", connNum, serverAddr))
}
if connInterval < defaultInterval {
connInterval = defaultInterval
} }
}
return &client{ // NewTcpClient function builds a tcp client.
func NewTCPClient(opts ...ClientOption) Client {
c := &client{
endPointType: TCP_CLIENT, endPointType: TCP_CLIENT,
number: connNum,
interval: connInterval,
addr: serverAddr,
ssMap: make(map[Session]gxsync.Empty, connNum),
done: make(chan gxsync.Empty), done: make(chan gxsync.Empty),
} }
c.init(opts...)
if c.number <= 0 || c.addr == "" {
panic(fmt.Sprintf("@connNum:%d, @serverAddr:%s", c.number, c.addr))
}
c.ssMap = make(map[Session]gxsync.Empty, c.number)
return c
} }
// NewUdpClient function builds a udp client // NewUdpClient function builds a udp client
// @connNum is connection number. func NewUDPClient(opts ...ClientOption) Client {
// @connInterval is reconnect sleep interval when getty fails to connect the server. c := &client{
// @serverAddr is server address. if this value is none-nil-string, getty will build some connected udp clients. done: make(chan gxsync.Empty),
func NewUDPClient(connNum int, connInterval time.Duration, serverAddr string) Client { }
var endPointType = UNCONNECTED_UDP_CLIENT
if len(serverAddr) != 0 { c.init(opts...)
if connNum <= 0 {
c.endPointType = UNCONNECTED_UDP_CLIENT
if len(c.addr) != 0 {
if c.number <= 0 {
panic(fmt.Sprintf("getty will build a preconected connection by @serverAddr:%s while @connNum is %d", panic(fmt.Sprintf("getty will build a preconected connection by @serverAddr:%s while @connNum is %d",
serverAddr, connNum)) c.addr, c.number))
} }
endPointType = CONNECTED_UDP_CLIENT c.endPointType = CONNECTED_UDP_CLIENT
} }
c.ssMap = make(map[Session]gxsync.Empty, c.number)
if connInterval < defaultInterval { return c
connInterval = defaultInterval }
}
return &client{ // NewWsClient function builds a ws client.
endPointType: endPointType, func NewWSClient(opts ...ClientOption) Client {
number: connNum, c := &client{
interval: connInterval, endPointType: WS_CLIENT,
addr: serverAddr,
ssMap: make(map[Session]gxsync.Empty, connNum),
done: make(chan gxsync.Empty), done: make(chan gxsync.Empty),
} }
}
// NewWsClient function builds a ws client. c.init(opts...)
// @connNum is connection number.
// @connInterval is reconnect sleep interval when getty fails to connect the server. if c.number <= 0 || c.addr == "" {
// @serverAddr is server address. its prefix should be "ws://". panic(fmt.Sprintf("@connNum:%d, @serverAddr:%s", c.number, c.addr))
func NewWSClient(connNum int, connInterval time.Duration, serverAddr string) Client {
if connNum <= 0 || serverAddr == "" {
panic(fmt.Sprintf("@connNum:%d, @serverAddr:%s", connNum, serverAddr))
} }
if connInterval < defaultInterval { if !strings.HasPrefix(c.addr, "ws://") {
connInterval = defaultInterval panic(fmt.Sprintf("the prefix @serverAddr:%s is not ws://", c.addr))
} }
if !strings.HasPrefix(serverAddr, "ws://") { c.ssMap = make(map[Session]gxsync.Empty, c.number)
return nil
}
return &client{ return c
endPointType: WS_CLIENT,
number: connNum,
interval: connInterval,
addr: serverAddr,
ssMap: make(map[Session]gxsync.Empty, connNum),
done: make(chan gxsync.Empty),
}
} }
// NewWSSClient function builds a wss client. // NewWSSClient function builds a wss client.
// @connNum is connection number. func NewWSSClient(opts ...ClientOption) Client {
// @connInterval is reconnect sleep interval when getty fails to connect the server. c := &client{
// @serverAddr is server address. endPointType: WSS_CLIENT,
// @cert is client certificate file. it can be emtpy. done: make(chan gxsync.Empty),
// @privateKey is client private key(contains its public key). it can be empty.
// @caCert is the root certificate file to verify the legitimacy of server
func NewWSSClient(connNum int, connInterval time.Duration, serverAddr string, cert string) Client {
if connNum <= 0 || serverAddr == "" || cert == "" {
panic(fmt.Sprintf("@connNum:%d, @serverAddr:%s, @cert:%s", connNum, serverAddr, cert))
} }
if connNum <= 0 { c.init(opts...)
connNum = 1
if c.number <= 0 || c.addr == "" || c.cert == "" {
panic(fmt.Sprintf("@connNum:%d, @serverAddr:%s, @cert:%s", c.number, c.addr, c.cert))
} }
if connInterval < defaultInterval { if !strings.HasPrefix(c.addr, "wss://") {
connInterval = defaultInterval panic(fmt.Sprintf("the prefix @serverAddr:%s is not wss://", c.addr))
} }
if !strings.HasPrefix(serverAddr, "wss://") { c.ssMap = make(map[Session]gxsync.Empty, c.number)
return nil
}
return &client{ return c
endPointType: WSS_CLIENT,
number: connNum,
interval: connInterval,
addr: serverAddr,
ssMap: make(map[Session]gxsync.Empty, connNum),
done: make(chan gxsync.Empty),
cert: cert,
}
} }
func (c client) Type() EndPointType { func (c client) Type() EndPointType {
...@@ -191,7 +163,7 @@ func (c *client) dialTCP() Session { ...@@ -191,7 +163,7 @@ func (c *client) dialTCP() Session {
} }
log.Info("net.DialTimeout(addr:%s, timeout:%v) = error{%v}", c.addr, err) log.Info("net.DialTimeout(addr:%s, timeout:%v) = error{%v}", c.addr, err)
time.Sleep(c.interval) time.Sleep(connInterval)
} }
} }
...@@ -223,7 +195,7 @@ func (c *client) dialUDP() Session { ...@@ -223,7 +195,7 @@ func (c *client) dialUDP() Session {
} }
log.Info("net.DialTimeout(addr:%s, timeout:%v) = error{%v}", c.addr, err) log.Info("net.DialTimeout(addr:%s, timeout:%v) = error{%v}", c.addr, err)
time.Sleep(c.interval) time.Sleep(connInterval)
} }
} }
...@@ -255,7 +227,7 @@ func (c *client) dialWS() Session { ...@@ -255,7 +227,7 @@ func (c *client) dialWS() Session {
} }
log.Info("websocket.dialer.Dial(addr:%s) = error{%v}", c.addr, err) log.Info("websocket.dialer.Dial(addr:%s) = error{%v}", c.addr, err)
time.Sleep(c.interval) time.Sleep(connInterval)
} }
} }
...@@ -332,7 +304,7 @@ func (c *client) dialWSS() Session { ...@@ -332,7 +304,7 @@ func (c *client) dialWSS() Session {
} }
log.Info("websocket.dialer.Dial(addr:%s) = error{%v}", c.addr, err) log.Info("websocket.dialer.Dial(addr:%s) = error{%v}", c.addr, err)
time.Sleep(c.interval) time.Sleep(connInterval)
} }
} }
...@@ -421,7 +393,7 @@ func (c *client) RunEventLoop(newSession NewSessionCallback) { ...@@ -421,7 +393,7 @@ func (c *client) RunEventLoop(newSession NewSessionCallback) {
if maxTimes < times { if maxTimes < times {
times = maxTimes times = maxTimes
} }
time.Sleep(time.Duration(int64(times) * defaultInterval)) time.Sleep(time.Duration(int64(times) * connInterval))
continue continue
} }
times = 0 times = 0
......
...@@ -153,7 +153,7 @@ type Session interface { ...@@ -153,7 +153,7 @@ type Session interface {
type EndPoint interface { type EndPoint interface {
// get endpoint type // get endpoint type
Type() EndPointType Type() EndPointType
// run event loop // run event loop and serves client request.
RunEventLoop(newSession NewSessionCallback) RunEventLoop(newSession NewSessionCallback)
// check the endpoint has been closed // check the endpoint has been closed
IsClosed() bool IsClosed() bool
......
...@@ -35,89 +35,66 @@ var ( ...@@ -35,89 +35,66 @@ var (
) )
type server struct { type server struct {
ServerOptions
// net // net
addr string
pktListener net.PacketConn pktListener net.PacketConn
streamListener net.Listener streamListener net.Listener
lock sync.Mutex // for server lock sync.Mutex // for server
endPointType EndPointType endPointType EndPointType
server *http.Server // for ws or wss server server *http.Server // for ws or wss server
// websocket
path string
cert string
privateKey string
caCert string
sync.Once sync.Once
done chan gxsync.Empty done chan gxsync.Empty
wg sync.WaitGroup wg sync.WaitGroup
} }
// NewTCServer builds a tcp server. func (s *server) init(opts ...ServerOption) {
// @addr server listen address. for _, opt := range opts {
func NewTCPServer(addr string) Server { opt(&(s.ServerOptions))
if addr == "" {
panic(fmt.Sprintf("@addr:%s", addr))
} }
}
return &server{ func newServer(t EndPointType, opts ...ServerOption) *server {
endPointType: TCP_SERVER, s := &server{
endPointType: t,
done: make(chan gxsync.Empty), done: make(chan gxsync.Empty),
addr: addr,
} }
}
// NewUDPServer builds a unconnected udp server. s.init(opts...)
// @addr server listen address.
func NewUDPPServer(addr string) Server {
if addr == "" {
panic(fmt.Sprintf("@addr:%s", addr))
}
return &server{ if s.addr == "" {
endPointType: UDP_SERVER, panic(fmt.Sprintf("@addr:%s", s.addr))
done: make(chan gxsync.Empty),
addr: addr,
} }
return s
} }
// NewWSServer builds a websocket server. // NewTCServer builds a tcp server.
// @addr server listen address. func NewTCPServer(opts ...ServerOption) Server {
// @path: websocket request url path return newServer(TCP_SERVER, opts...)
func NewWSServer(addr string, path string) Server { }
if addr == "" {
panic(fmt.Sprintf("@addr:%s", addr))
}
return &server{ // NewUDPServer builds a unconnected udp server.
endPointType: WS_SERVER, func NewUDPPServer(opts ...ServerOption) Server {
done: make(chan gxsync.Empty), return newServer(UDP_SERVER, opts...)
addr: addr, }
path: path,
} // NewWSServer builds a websocket server.
func NewWSServer(opts ...ServerOption) Server {
return newServer(WS_SERVER, opts...)
} }
// NewWSSServer builds a secure websocket server. // NewWSSServer builds a secure websocket server.
// @addr server listen address. func NewWSSServer(opts ...ServerOption) Server {
// @path: websocket request url path s := newServer(WSS_SERVER, opts...)
// @cert: server certificate file
// @privateKey: server private key(contains its public key)
// @caCert: root certificate file. to verify the legitimacy of client. it can be nil.
func NewWSSServer(addr, path, cert, privateKey, caCert string) Server {
if addr == "" || cert == "" || privateKey == "" || caCert == "" {
panic(fmt.Sprintf("@addr:%s, @cert:%s, @privateKey:%s, @caCert:%s", addr, cert, privateKey, caCert))
}
return &server{ if s.addr == "" || s.cert == "" || s.privateKey == "" || s.caCert == "" {
endPointType: WSS_SERVER, panic(fmt.Sprintf("@addr:%s, @cert:%s, @privateKey:%s, @caCert:%s",
done: make(chan gxsync.Empty), s.addr, s.cert, s.privateKey, s.caCert))
addr: addr,
path: path,
cert: cert,
privateKey: privateKey,
caCert: caCert,
} }
return s
} }
func (s server) Type() EndPointType { func (s server) Type() EndPointType {
...@@ -356,7 +333,6 @@ func (s *wsHandler) serveWSRequest(w http.ResponseWriter, r *http.Request) { ...@@ -356,7 +333,6 @@ func (s *wsHandler) serveWSRequest(w http.ResponseWriter, r *http.Request) {
// runWSEventLoop serve websocket client request // runWSEventLoop serve websocket client request
// @newSession: new websocket connection callback // @newSession: new websocket connection callback
// @path: websocket request url path
func (s *server) runWSEventLoop(newSession NewSessionCallback) { func (s *server) runWSEventLoop(newSession NewSessionCallback) {
s.wg.Add(1) s.wg.Add(1)
go func() { go func() {
...@@ -387,11 +363,6 @@ func (s *server) runWSEventLoop(newSession NewSessionCallback) { ...@@ -387,11 +363,6 @@ func (s *server) runWSEventLoop(newSession NewSessionCallback) {
// serve websocket client request // serve websocket client request
// RunWSSEventLoop serve websocket client request // RunWSSEventLoop serve websocket client request
// @newSession: new websocket connection callback
// @path: websocket request url path
// @cert: server certificate file
// @privateKey: server private key(contains its public key)
// @caCert: root certificate file. to verify the legitimacy of client. it can be nil.
func (s *server) runWSSEventLoop(newSession NewSessionCallback) { func (s *server) runWSSEventLoop(newSession NewSessionCallback) {
s.wg.Add(1) s.wg.Add(1)
go func() { go func() {
......
...@@ -10,9 +10,9 @@ ...@@ -10,9 +10,9 @@
package getty package getty
const ( const (
Version = "0.8.1" Version = "0.8.2"
DATE = "2018/03/08" DATE = "2018/03/17"
GETTY_MAJOR = 0 GETTY_MAJOR = 0
GETTY_MINOR = 8 GETTY_MINOR = 8
GETTY_BUILD = 1 GETTY_BUILD = 2
) )
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment