srpc/server.go

182 lines
4.1 KiB
Go

package srpc
import (
"bytes"
"errors"
"fmt"
"net"
"olznet.de/slog"
"reflect"
"sync"
)
type parseInputsFunc func(in []byte) (ret []reflect.Value, err error)
type parseOutputsFunc func(in []reflect.Value) (ret []byte, err error)
type service struct {
f reflect.Value
fin parseInputsFunc
fout parseOutputsFunc
}
type Server struct {
ed IEncoderDecoder
serviceMap sync.Map
}
func (server *Server) ServeConn(conn net.Conn) {
var fs service
var request *RPCRequest
var err error
tcpConn := NewTCPConn(conn, server.ed)
defer tcpConn.Close()
if request, err = tcpConn.ReceiveRequest(); err != nil {
slog.LOG_ERROR("srpc - Malformed request received: '%s'\n", err.Error())
return
}
var response RPCResponse
response.Status = RPCOK
response.Error = ""
if fsRaw, ok := server.serviceMap.Load(request.FuncName); !ok {
slog.LOG_ERROR("srpc - Call to unknown method: '%s'\n", request.FuncName)
err := fmt.Sprintf("Unknown method: '%s'", request.FuncName)
response.Status = RPCERR
response.Error = err
} else {
fs = fsRaw.(service)
if inputs, err := fs.fin(request.Payload); err != nil {
slog.LOG_ERROR("srpc - Error parsing inputs '%s'\n", err.Error())
response.Status = RPCERR
response.Error = err.Error()
} else {
outputs := fs.f.Call(inputs)
if payload, err := fs.fout(outputs); err != nil {
slog.LOG_ERROR("srpc - Error parsing outputs '%s'\n", err.Error())
response.Status = RPCERR
response.Error = err.Error()
} else {
slog.LOG_DEBUG("%v\n", outputs)
response.Payload = append([]byte{}, payload...)
}
}
}
if err = tcpConn.SendResponse(&response); err != nil {
slog.LOG_ERROR("srpc - Error sending response '%s'\n", err.Error())
}
}
func (server *Server) Accept(ln net.Listener) {
for {
conn, err := ln.Accept()
if err != nil {
slog.LOG_INFO("srpc - Accept: '%s'\n", err.Error())
return
}
go server.ServeConn(conn)
}
}
func (server *Server) RegisterName(name string, rcvr interface{}) (err error) {
if _, ok := server.serviceMap.Load(name); ok {
return errors.New("srpc: Function with name '" + name + "' already registerd")
}
ft := reflect.TypeOf(rcvr)
fv := reflect.ValueOf(rcvr)
nIn := ft.NumIn()
fs := service{}
fs.fin = func(in []byte) (ret []reflect.Value, err error) {
var b bytes.Buffer
if _, err = b.Write(in); err != nil {
return nil, err
}
decoder := server.ed.NewDecoder(&b)
ret = make([]reflect.Value, nIn)
for i := 0; i < nIn; i++ {
arg := reflect.New(ft.In(i))
if err = decoder.Decode(arg.Interface()); err != nil {
return nil, err
}
ret[i] = reflect.Indirect(arg)
}
return ret, nil
}
fs.fout = func(in []reflect.Value) (ret []byte, err error) {
var b bytes.Buffer
encoder := server.ed.NewEncoder(&b)
for _, v := range in {
if v.Type() == reflect.TypeOf((*error)(nil)).Elem() {
if v.IsNil() {
if err = encoder.Encode(string("")); err != nil {
return nil, err
}
} else {
if err = encoder.Encode(v.Interface().(error).Error()); err != nil {
fmt.Println(err)
return nil, err
}
}
} else {
if err = encoder.Encode(v.Interface()); err != nil {
return nil, err
}
}
}
return b.Bytes(), nil
}
fs.f = fv
server.serviceMap.Store(name, fs)
return nil
}
func (server *Server) CallName(name string, args ...interface{}) (ret []byte, err error) {
var b bytes.Buffer
var fs service
encoder := server.ed.NewEncoder(&b)
if fsRaw, ok := server.serviceMap.Load(name); !ok {
return nil, errors.New("srpc - Call to unknown method: '" + name + "'")
} else {
fs = fsRaw.(service)
}
for _, a := range args {
if err := encoder.Encode(a); err != nil {
return nil, errors.New("srpc - Error: '" + err.Error() + "'")
}
}
if inputs, err := fs.fin(b.Bytes()); err != nil {
return nil, err
} else {
outputs := fs.f.Call(inputs)
return fs.fout(outputs)
}
}
func NewServer(ed IEncoderDecoder) *Server {
ret := &Server{}
ret.ed = ed
return ret
}
func NewDefaultServer() *Server {
ret := NewServer(NewEncoderDecoder())
return ret
}
var DefaultServer = NewDefaultServer()