Implement server to client ChannelDone
This commit is contained in:
parent
073ebbd8ba
commit
888d5902ae
@ -111,6 +111,18 @@ func (c *Client) Call(rcvr, method string, arg interface{}, ret interface{}) err
|
|||||||
chElemType := retVal.Type().Elem()
|
chElemType := retVal.Type().Elem()
|
||||||
// For every value received from channel
|
// For every value received from channel
|
||||||
for val := range c.chs[chID] {
|
for val := range c.chs[chID] {
|
||||||
|
if val.ChannelDone {
|
||||||
|
// Close and delete channel
|
||||||
|
c.chMtx.Lock()
|
||||||
|
close(c.chs[chID])
|
||||||
|
delete(c.chs, chID)
|
||||||
|
c.chMtx.Unlock()
|
||||||
|
|
||||||
|
// Close return channel
|
||||||
|
retVal.Close()
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
// Get reflect value from channel response
|
// Get reflect value from channel response
|
||||||
rVal := reflect.ValueOf(val.Return)
|
rVal := reflect.ValueOf(val.Return)
|
||||||
|
|
||||||
@ -124,25 +136,25 @@ func (c *Client) Call(rcvr, method string, arg interface{}, ret interface{}) err
|
|||||||
rVal = newVal
|
rVal = newVal
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to read from the channel
|
|
||||||
recvVal, ok := retVal.TryRecv()
|
|
||||||
// IF the channel cannot be read but the value is valid,
|
|
||||||
// the channel must be closed
|
|
||||||
if !ok && recvVal.IsValid() {
|
|
||||||
// Send done signal
|
|
||||||
c.Call("lrpc", "ChannelDone", idStr, nil)
|
|
||||||
// Close and delete channel
|
|
||||||
c.chMtx.Lock()
|
|
||||||
close(c.chs[chID])
|
|
||||||
delete(c.chs, chID)
|
|
||||||
c.chMtx.Unlock()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send value to channel
|
// Send value to channel
|
||||||
retVal.Send(rVal)
|
retVal.Send(rVal)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
val, ok := retVal.Recv()
|
||||||
|
if !ok && val.IsValid() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.Call("lrpc", "ChannelDone", id, nil)
|
||||||
|
// Close and delete channel
|
||||||
|
c.chMtx.Lock()
|
||||||
|
close(c.chs[chID])
|
||||||
|
delete(c.chs, chID)
|
||||||
|
c.chMtx.Unlock()
|
||||||
|
}()
|
||||||
} else {
|
} else {
|
||||||
// IF return value is not a pointer, return error
|
// IF return value is not a pointer, return error
|
||||||
if retVal.Kind() != reflect.Ptr {
|
if retVal.Kind() != reflect.Ptr {
|
||||||
|
@ -11,6 +11,7 @@ type Request struct {
|
|||||||
// Response represents a response returned by the server
|
// Response represents a response returned by the server
|
||||||
type Response struct {
|
type Response struct {
|
||||||
ID string
|
ID string
|
||||||
|
ChannelDone bool
|
||||||
IsChannel bool
|
IsChannel bool
|
||||||
IsError bool
|
IsError bool
|
||||||
Error string
|
Error string
|
||||||
|
@ -2,6 +2,7 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
@ -243,7 +244,9 @@ func (s *Server) handleConn(c codec.Codec) {
|
|||||||
var call types.Request
|
var call types.Request
|
||||||
// Read request using codec
|
// Read request using codec
|
||||||
err := c.Decode(&call)
|
err := c.Decode(&call)
|
||||||
if err != nil {
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
s.sendErr(c, call, nil, err)
|
s.sendErr(c, call, nil, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -285,6 +288,18 @@ func (s *Server) handleConn(c codec.Codec) {
|
|||||||
Return: val,
|
Return: val,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cancel context
|
||||||
|
ctx.Cancel()
|
||||||
|
// Delete context from map
|
||||||
|
s.contextsMtx.Lock()
|
||||||
|
delete(s.contexts, ctx.channelID)
|
||||||
|
s.contextsMtx.Unlock()
|
||||||
|
|
||||||
|
c.Encode(types.Response{
|
||||||
|
ID: ctx.channelID,
|
||||||
|
ChannelDone: true,
|
||||||
|
})
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,5 +336,7 @@ func (l lrpc) ChannelDone(_ *Context, id string) {
|
|||||||
// Cancel context
|
// Cancel context
|
||||||
ctx.Cancel()
|
ctx.Cancel()
|
||||||
// Delete context from map
|
// Delete context from map
|
||||||
|
l.srv.contextsMtx.Lock()
|
||||||
delete(l.srv.contexts, id)
|
delete(l.srv.contexts, id)
|
||||||
|
l.srv.contextsMtx.Unlock()
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user