Working on client
This commit is contained in:
parent
ae7f26766f
commit
067e2a7129
171
client.go
171
client.go
|
@ -1,9 +1,9 @@
|
||||||
package srpc
|
package srpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
//"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
//"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -93,9 +93,20 @@ type clientMessage struct {
|
||||||
|
|
||||||
type call struct {
|
type call struct {
|
||||||
Response serverMessage
|
Response serverMessage
|
||||||
|
Request clientMessage
|
||||||
|
Error error
|
||||||
|
state messageState
|
||||||
t time.Time
|
t time.Time
|
||||||
done chan struct{}
|
done chan bool
|
||||||
request clientMessage
|
sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCall() (ret *call) {
|
||||||
|
ret = new(call)
|
||||||
|
ret.state = FREE
|
||||||
|
ret.done = make(chan bool)
|
||||||
|
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResponseDataHandlerFunc func() (response interface{})
|
type ResponseDataHandlerFunc func() (response interface{})
|
||||||
|
@ -112,16 +123,31 @@ func unixDial(addr string) (conn io.ReadWriteCloser, err error) {
|
||||||
|
|
||||||
type RPCClient struct {
|
type RPCClient struct {
|
||||||
Addr string
|
Addr string
|
||||||
|
MaxRequests int
|
||||||
LogError LogErrorFunc
|
LogError LogErrorFunc
|
||||||
ConnectHander ConnectHandlerFunc
|
ConnectHander ConnectHandlerFunc
|
||||||
ResponseDataHandler ResponseDataHandlerFunc
|
ResponseDataHandler ResponseDataHandlerFunc
|
||||||
DialHandler DialHandlerFunc
|
DialHandler DialHandlerFunc
|
||||||
Ed IEncoderDecoder
|
Ed IEncoderDecoder
|
||||||
|
calls []*call
|
||||||
|
callChan chan *call
|
||||||
|
nextID uint64
|
||||||
stopChan chan struct{}
|
stopChan chan struct{}
|
||||||
stopWg sync.WaitGroup
|
stopWg sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RPCClient) Start() (err error) {
|
func (c *RPCClient) Start() (err error) {
|
||||||
|
if c.MaxRequests <= 0 {
|
||||||
|
c.MaxRequests = DefaultMaxClientRequests
|
||||||
|
}
|
||||||
|
|
||||||
|
c.calls = make([]*call, c.MaxRequests)
|
||||||
|
for i := 0; i < c.MaxRequests; i++ {
|
||||||
|
c.calls[i] = newCall()
|
||||||
|
}
|
||||||
|
c.nextID = 0
|
||||||
|
c.callChan = make(chan *call)
|
||||||
|
|
||||||
if c.LogError == nil {
|
if c.LogError == nil {
|
||||||
c.LogError = logError
|
c.LogError = logError
|
||||||
}
|
}
|
||||||
|
@ -140,6 +166,7 @@ func (c *RPCClient) Start() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
c.stopWg.Add(1)
|
c.stopWg.Add(1)
|
||||||
|
go clientHandler(c)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,6 +179,39 @@ func (c *RPCClient) Stop() {
|
||||||
c.stopChan = nil
|
c.stopChan = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *RPCClient) Call(request interface{}) (response interface{}, err error) {
|
||||||
|
var requestCall *call
|
||||||
|
|
||||||
|
for _, e := range c.calls {
|
||||||
|
e.Lock()
|
||||||
|
if e.state == FREE {
|
||||||
|
requestCall = e
|
||||||
|
requestCall.state = PENDING
|
||||||
|
requestCall.Request.ID = c.nextID
|
||||||
|
requestCall.Request.ClientAddr = c.Addr
|
||||||
|
requestCall.Request.Data = request
|
||||||
|
c.nextID++
|
||||||
|
e.Unlock()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
e.Unlock()
|
||||||
|
}
|
||||||
|
if requestCall == nil {
|
||||||
|
return nil, errors.New("srpc - Client requests are full")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.callChan <- requestCall
|
||||||
|
|
||||||
|
<-requestCall.done
|
||||||
|
requestCall.Lock()
|
||||||
|
response = requestCall.Response.Data
|
||||||
|
err = requestCall.Error
|
||||||
|
requestCall.state = FREE
|
||||||
|
requestCall.Unlock()
|
||||||
|
|
||||||
|
return response, err
|
||||||
|
}
|
||||||
|
|
||||||
func clientHandler(c *RPCClient) {
|
func clientHandler(c *RPCClient) {
|
||||||
defer c.stopWg.Done()
|
defer c.stopWg.Done()
|
||||||
|
|
||||||
|
@ -187,8 +247,12 @@ func clientHandler(c *RPCClient) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
c.stopWg.Add(1)
|
clientHandleConnection(c, conn)
|
||||||
go clientHandleConnection(c, conn)
|
select {
|
||||||
|
case <-c.stopChan:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,4 +266,99 @@ func clientHandleConnection(c *RPCClient, conn io.ReadWriteCloser) {
|
||||||
conn = newConn
|
conn = newConn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stopChan := make(chan struct{})
|
||||||
|
|
||||||
|
writerDone := make(chan error, 1)
|
||||||
|
go clientWriter(c, conn, stopChan, writerDone)
|
||||||
|
|
||||||
|
readerDone := make(chan error, 1)
|
||||||
|
go clientReader(c, conn, readerDone)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
select {
|
||||||
|
case err = <-writerDone:
|
||||||
|
close(stopChan)
|
||||||
|
conn.Close()
|
||||||
|
<-readerDone
|
||||||
|
case err = <-readerDone:
|
||||||
|
close(stopChan)
|
||||||
|
conn.Close()
|
||||||
|
<-writerDone
|
||||||
|
case <-c.stopChan:
|
||||||
|
close(stopChan)
|
||||||
|
conn.Close()
|
||||||
|
<-readerDone
|
||||||
|
<-writerDone
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.LogError("srpc - '%s'\n", err)
|
||||||
|
}
|
||||||
|
for _, e := range c.calls {
|
||||||
|
e.Lock()
|
||||||
|
if e.state == PENDING {
|
||||||
|
e.Error = err
|
||||||
|
e.done <- true
|
||||||
|
}
|
||||||
|
e.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func clientWriter(c *RPCClient, conn io.Writer, stopChan <-chan struct{}, done chan<- error) {
|
||||||
|
var err error
|
||||||
|
defer func() { done <- err }()
|
||||||
|
|
||||||
|
enc := c.Ed.NewEncoder(conn)
|
||||||
|
b := bytes.Buffer{}
|
||||||
|
enc2 := c.Ed.NewEncoder(&b)
|
||||||
|
|
||||||
|
for {
|
||||||
|
err = nil
|
||||||
|
var requestCall *call
|
||||||
|
|
||||||
|
select {
|
||||||
|
case requestCall = <-c.callChan:
|
||||||
|
requestCall.Lock()
|
||||||
|
enc2.Encode(requestCall.Request)
|
||||||
|
fmt.Println(b.Bytes())
|
||||||
|
if err = enc.Encode(requestCall.Request); err != nil {
|
||||||
|
if !serverDisconnect(err) && !clientStop(c.stopChan) {
|
||||||
|
requestCall.Error = errors.New("srpc - '%s'=>'%s': Cannot encode request: '%s'\n")
|
||||||
|
requestCall.Unlock()
|
||||||
|
requestCall.done <- true
|
||||||
|
} else {
|
||||||
|
requestCall.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case <-stopChan:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func clientReader(c *RPCClient, conn io.Reader, done <-chan error) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func serverDisconnect(err error) bool {
|
||||||
|
return err == io.ErrUnexpectedEOF || err == io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
func clientStop(stopChan <-chan struct{}) bool {
|
||||||
|
select {
|
||||||
|
case <-stopChan:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUnixClient(addr string, handler ResponseDataHandlerFunc) *RPCClient {
|
||||||
|
return &RPCClient{
|
||||||
|
Addr: addr,
|
||||||
|
ResponseDataHandler: handler,
|
||||||
|
DialHandler: unixDial,
|
||||||
|
Ed: NewEncoderDecoder(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,3 +11,14 @@ var logError = LogErrorFunc(log.Printf)
|
||||||
func SetLogError(f LogErrorFunc) {
|
func SetLogError(f LogErrorFunc) {
|
||||||
logError = f
|
logError = f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type messageState uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
FREE messageState = 0
|
||||||
|
PENDING messageState = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultMaxClientRequests = int(128)
|
||||||
|
)
|
||||||
|
|
4
rpc.go
4
rpc.go
|
@ -145,8 +145,8 @@ func RequestDataHandler() (request interface{}) {
|
||||||
return new(RPCRequest)
|
return new(RPCRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ResponseDataHandler() (request interface{}) {
|
func ResponseDataHandler() (response interface{}) {
|
||||||
return new(RPCRequest)
|
return new(RPCResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRPC(ed IEncoderDecoder) *RPC {
|
func NewRPC(ed IEncoderDecoder) *RPC {
|
||||||
|
|
12
server.go
12
server.go
|
@ -1,6 +1,7 @@
|
||||||
package srpc
|
package srpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -177,16 +178,23 @@ func serverHandleConnection(s *RPCServer, conn io.ReadWriteCloser, clientAddr st
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
var msg serverMessage
|
var msg clientMessage
|
||||||
msg.Data = s.RequestDataHandler()
|
msg.Data = s.RequestDataHandler()
|
||||||
|
fmt.Println(msg)
|
||||||
|
p := make([]byte, 62)
|
||||||
|
|
||||||
dec := s.Ed.NewDecoder(conn)
|
conn.Read(p)
|
||||||
|
fmt.Println(p)
|
||||||
|
|
||||||
|
dec := s.Ed.NewDecoder(bytes.NewBuffer(p))
|
||||||
|
//dec := s.Ed.NewDecoder(conn)
|
||||||
enc := s.Ed.NewEncoder(conn)
|
enc := s.Ed.NewEncoder(conn)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if err = dec.Decode(&msg); err != nil {
|
if err = dec.Decode(&msg); err != nil {
|
||||||
if !clientDisconnect(err) && !serverStop(s.stopChan) {
|
if !clientDisconnect(err) && !serverStop(s.stopChan) {
|
||||||
s.LogError("srpc - '%s'=>'%s': Cannot decode request: '%s'\n", clientAddr, s.Addr, err)
|
s.LogError("srpc - '%s'=>'%s': Cannot decode request: '%s'\n", clientAddr, s.Addr, err)
|
||||||
|
fmt.Println(msg)
|
||||||
}
|
}
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in New Issue