Commit 0a17a4a3 authored by AlexStocks's avatar AlexStocks

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

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