2022-10-23 20:12:23 +03:00
|
|
|
|
package ytfunction
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"crypto/rand"
|
|
|
|
|
"fmt"
|
2022-10-25 12:59:22 +03:00
|
|
|
|
"strings"
|
2022-10-28 11:19:03 +03:00
|
|
|
|
"sync"
|
2022-10-25 12:59:22 +03:00
|
|
|
|
"time"
|
2022-10-23 20:12:23 +03:00
|
|
|
|
|
2022-12-01 15:23:42 +03:00
|
|
|
|
"git.ymnuktech.ru/ymnuk/yt-function-sdk-go/network"
|
|
|
|
|
ytlogger "git.ymnuktech.ru/ymnuk/yt-logger-go"
|
|
|
|
|
"git.ymnuktech.ru/ymnuk/yt-logger-go/log"
|
2022-10-23 20:12:23 +03:00
|
|
|
|
"github.com/nats-io/nats.go"
|
2022-10-25 12:59:22 +03:00
|
|
|
|
uuid "github.com/satori/go.uuid"
|
|
|
|
|
"google.golang.org/protobuf/proto"
|
2022-10-23 20:12:23 +03:00
|
|
|
|
)
|
|
|
|
|
|
2022-10-28 21:22:30 +03:00
|
|
|
|
type ChanRes struct {
|
2022-11-04 17:10:59 +03:00
|
|
|
|
res []byte
|
|
|
|
|
header *network.Header
|
|
|
|
|
err error
|
2022-10-28 21:22:30 +03:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-23 20:12:23 +03:00
|
|
|
|
type funcDesc struct {
|
2022-10-25 14:47:26 +03:00
|
|
|
|
Name string
|
|
|
|
|
F func(header *network.Header, payload []byte) (result []byte, err error)
|
|
|
|
|
inputChan chan *nats.Msg
|
|
|
|
|
subj *nats.Subscription
|
|
|
|
|
conn *nats.Conn
|
|
|
|
|
timeout time.Duration
|
|
|
|
|
acceptFunc func(access string) bool
|
2022-12-01 15:23:42 +03:00
|
|
|
|
logger *ytlogger.YTLogger
|
2022-10-23 20:12:23 +03:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 12:59:22 +03:00
|
|
|
|
func (fDesc *funcDesc) worker() {
|
2022-10-23 20:12:23 +03:00
|
|
|
|
for {
|
2022-10-25 12:59:22 +03:00
|
|
|
|
data, ok := <-fDesc.inputChan
|
2022-10-23 20:12:23 +03:00
|
|
|
|
if !ok {
|
|
|
|
|
break
|
|
|
|
|
}
|
2022-10-25 12:59:22 +03:00
|
|
|
|
var err error
|
2022-11-04 16:36:03 +03:00
|
|
|
|
pkg := &network.Function{}
|
2022-10-25 12:59:22 +03:00
|
|
|
|
|
2022-11-04 16:36:03 +03:00
|
|
|
|
err = proto.Unmarshal(data.Data, pkg)
|
2022-10-23 20:12:23 +03:00
|
|
|
|
if err != nil {
|
2022-10-25 12:59:22 +03:00
|
|
|
|
panic(err)
|
|
|
|
|
}
|
2022-12-01 15:23:42 +03:00
|
|
|
|
timeStart := time.Now()
|
2022-10-25 14:47:26 +03:00
|
|
|
|
// Проверка может ли вызывающая сторона вызвать функцию
|
|
|
|
|
if !fDesc.acceptFunc(pkg.Metadata.CallFrom) {
|
|
|
|
|
if pkg.Metadata.QueueCallback != "" {
|
|
|
|
|
pkg.ErrNo = 403
|
|
|
|
|
pkg.Error = "forbidden"
|
|
|
|
|
pkg.Metadata.CallResponseID = uuid.NewV4().String()
|
2022-11-04 16:36:03 +03:00
|
|
|
|
buff, err := proto.Marshal(pkg)
|
2022-10-25 14:47:26 +03:00
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
2022-12-01 15:23:42 +03:00
|
|
|
|
if fDesc.logger != nil {
|
|
|
|
|
fDesc.logger.Err(&pkg.Metadata.FuncName, &pkg.Metadata.CallID, &pkg.Header.CallPrevID, &pkg.Metadata.CallFrom, &pkg.Metadata.CallResponseID, &timeStart, &[]time.Time{time.Now()}[0], nil, &pkg.ErrNo, &pkg.Error, &pkg.ErrNo, nil, nil)
|
|
|
|
|
}
|
2022-11-22 09:19:07 +03:00
|
|
|
|
if err = fDesc.conn.Publish(pkg.Metadata.QueueCallback, buff); err != nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2022-12-01 15:23:42 +03:00
|
|
|
|
} else {
|
|
|
|
|
if fDesc.logger != nil {
|
|
|
|
|
fDesc.logger.Err(&pkg.Metadata.FuncName, &pkg.Metadata.CallID, &pkg.Header.CallPrevID, &pkg.Metadata.CallFrom, &pkg.Metadata.CallResponseID, &timeStart, &[]time.Time{time.Now()}[0], nil, &pkg.ErrNo, &pkg.Error, &pkg.ErrNo, nil, nil)
|
|
|
|
|
}
|
2022-10-25 14:47:26 +03:00
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
// Вызов функции
|
2022-10-28 21:22:30 +03:00
|
|
|
|
chanRes := make(chan *ChanRes)
|
2022-10-25 12:59:22 +03:00
|
|
|
|
go func() {
|
2022-11-04 17:10:59 +03:00
|
|
|
|
if pkg.Header.ResponseHeaders == nil {
|
|
|
|
|
pkg.Header.ResponseHeaders = make(map[string]string)
|
|
|
|
|
}
|
2022-10-28 21:22:30 +03:00
|
|
|
|
result, err := fDesc.F(pkg.Header, pkg.Payload)
|
|
|
|
|
chanRes <- &ChanRes{
|
|
|
|
|
res: result,
|
|
|
|
|
err: err,
|
2022-10-25 12:59:22 +03:00
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
select {
|
2022-10-28 21:22:30 +03:00
|
|
|
|
case res := <-chanRes:
|
|
|
|
|
if res.err != nil {
|
|
|
|
|
if pkg.Metadata.QueueCallback != "" {
|
|
|
|
|
pkg.ErrNo = 500
|
2022-11-23 12:09:34 +03:00
|
|
|
|
//if err != nil {
|
|
|
|
|
pkg.Error = res.err.Error()
|
|
|
|
|
/*} else {
|
2022-11-23 09:48:42 +03:00
|
|
|
|
pkg.Error = ""
|
2022-11-23 12:09:34 +03:00
|
|
|
|
}*/
|
2022-10-28 21:22:30 +03:00
|
|
|
|
pkg.Metadata.CallResponseID = uuid.NewV4().String()
|
2022-12-01 15:23:42 +03:00
|
|
|
|
if fDesc.logger != nil {
|
|
|
|
|
fDesc.logger.Err(&pkg.Metadata.FuncName, &pkg.Metadata.CallID, &pkg.Header.CallPrevID, &pkg.Metadata.CallFrom, &pkg.Metadata.CallResponseID, &timeStart, &[]time.Time{time.Now()}[0], nil, &pkg.ErrNo, &pkg.Error, &pkg.ErrNo, nil, nil)
|
|
|
|
|
}
|
2022-11-23 12:09:34 +03:00
|
|
|
|
buff, err := proto.Marshal(pkg)
|
|
|
|
|
if err != nil {
|
|
|
|
|
//panic(err)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
//fDesc.conn.Publish(pkg.Metadata.QueueCallback, []byte(pkg.Error))
|
|
|
|
|
fDesc.conn.Publish(pkg.Metadata.QueueCallback, buff)
|
2022-10-28 21:22:30 +03:00
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
2022-10-25 14:47:26 +03:00
|
|
|
|
if pkg.Metadata.QueueCallback != "" {
|
2022-10-28 21:22:30 +03:00
|
|
|
|
pkg.Payload = res.res
|
2022-10-25 14:47:26 +03:00
|
|
|
|
pkg.Metadata.CallResponseID = uuid.NewV4().String()
|
2022-12-01 15:23:42 +03:00
|
|
|
|
if fDesc.logger != nil {
|
|
|
|
|
fDesc.logger.Info(&pkg.Metadata.FuncName, &pkg.Metadata.CallID, &pkg.Header.CallPrevID, &pkg.Metadata.CallFrom, &pkg.Metadata.CallResponseID, &timeStart, &[]time.Time{time.Now()}[0], nil, &pkg.ErrNo, &pkg.Error, &pkg.ErrNo, &[]int64{int64(len(pkg.Payload))}[0], nil)
|
|
|
|
|
}
|
2022-11-04 16:36:03 +03:00
|
|
|
|
buff, err := proto.Marshal(pkg)
|
2022-10-25 14:47:26 +03:00
|
|
|
|
if err != nil {
|
2022-11-22 09:19:07 +03:00
|
|
|
|
//panic(err)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if err = fDesc.conn.Publish(pkg.Metadata.QueueCallback, buff); err != nil {
|
|
|
|
|
continue
|
2022-10-25 14:47:26 +03:00
|
|
|
|
}
|
2022-10-25 12:59:22 +03:00
|
|
|
|
}
|
2022-10-23 20:12:23 +03:00
|
|
|
|
continue
|
2022-10-25 12:59:22 +03:00
|
|
|
|
case <-time.After(fDesc.timeout):
|
2022-11-23 09:48:42 +03:00
|
|
|
|
//if err != nil {
|
|
|
|
|
if pkg.Metadata.QueueCallback != "" {
|
|
|
|
|
pkg.ErrNo = 408
|
|
|
|
|
//pkg.Error = err.Error()
|
|
|
|
|
pkg.Error = "function call timeout"
|
|
|
|
|
pkg.Metadata.CallResponseID = uuid.NewV4().String()
|
2022-12-01 15:23:42 +03:00
|
|
|
|
if fDesc.logger != nil {
|
|
|
|
|
fDesc.logger.Err(&pkg.Metadata.FuncName, &pkg.Metadata.CallID, &pkg.Header.CallPrevID, &pkg.Metadata.CallFrom, &pkg.Metadata.CallResponseID, &timeStart, &[]time.Time{time.Now()}[0], nil, &pkg.ErrNo, &pkg.Error, &pkg.ErrNo, nil, nil)
|
|
|
|
|
}
|
2022-11-23 12:09:34 +03:00
|
|
|
|
buff, err := proto.Marshal(pkg)
|
|
|
|
|
if err != nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
//fDesc.conn.Publish(pkg.Metadata.QueueCallback, []byte("function call timeout"))
|
|
|
|
|
if err = fDesc.conn.Publish(pkg.Metadata.QueueCallback, buff); err != nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2022-10-25 12:59:22 +03:00
|
|
|
|
}
|
2022-11-23 09:48:42 +03:00
|
|
|
|
continue
|
|
|
|
|
//}
|
2022-10-23 20:12:23 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-05 12:41:03 +03:00
|
|
|
|
type CallbackFunc struct {
|
|
|
|
|
F func(err error, header *network.Header, result []byte)
|
|
|
|
|
TimeCall time.Time
|
2022-11-30 14:24:24 +03:00
|
|
|
|
//Metadata *network.Metadata
|
2022-11-05 12:41:03 +03:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-28 11:19:03 +03:00
|
|
|
|
// Сервер инстанса
|
2022-10-23 20:12:23 +03:00
|
|
|
|
type Serve struct {
|
2022-11-11 19:07:23 +03:00
|
|
|
|
//NatsHost string
|
|
|
|
|
//NatsPort string
|
|
|
|
|
NatsAddr string
|
2022-11-05 12:41:03 +03:00
|
|
|
|
nc *nats.Conn
|
|
|
|
|
hasNats bool
|
|
|
|
|
projectName string
|
|
|
|
|
moduleName string
|
|
|
|
|
funcs map[string]funcDesc
|
|
|
|
|
timeoutCallback time.Duration
|
|
|
|
|
queueCallback string
|
|
|
|
|
chanQueueCallback chan *nats.Msg
|
|
|
|
|
subj *nats.Subscription
|
|
|
|
|
//callbackFuncs map[string]func(err error, header *network.Header, result []byte)
|
|
|
|
|
callbackFuncs map[string]*CallbackFunc
|
2022-10-28 11:19:03 +03:00
|
|
|
|
callbackFuncsMutex sync.Mutex
|
|
|
|
|
accept map[string]map[string]bool
|
2022-12-01 15:23:42 +03:00
|
|
|
|
logger *ytlogger.YTLogger
|
|
|
|
|
queueNameLog *string
|
2022-10-23 20:12:23 +03:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-28 11:19:03 +03:00
|
|
|
|
// Создание нового инстанса сервера
|
2022-12-01 15:23:42 +03:00
|
|
|
|
func NewServe(addr string, projectName string, moduleName string, natsServ *nats.Conn, priority *ytlogger.Priority, queueNameLog *string) *Serve {
|
2022-10-25 12:59:22 +03:00
|
|
|
|
if strings.Trim(moduleName, " ") == "" {
|
|
|
|
|
moduleName = "default"
|
|
|
|
|
} else {
|
|
|
|
|
moduleName = strings.Trim(moduleName, " ")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if strings.Trim(projectName, " ") == "" {
|
|
|
|
|
projectName = "default"
|
|
|
|
|
} else {
|
|
|
|
|
projectName = strings.Trim(projectName, " ")
|
2022-10-23 20:12:23 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
serve := &Serve{}
|
2022-10-27 13:51:12 +03:00
|
|
|
|
if natsServ != nil {
|
|
|
|
|
serve.nc = natsServ
|
|
|
|
|
} else {
|
2022-11-11 19:07:23 +03:00
|
|
|
|
/*serve.NatsHost = host
|
|
|
|
|
serve.NatsPort = port*/
|
|
|
|
|
serve.NatsAddr = addr
|
2022-10-27 13:51:12 +03:00
|
|
|
|
}
|
2022-10-25 12:59:22 +03:00
|
|
|
|
serve.projectName = projectName
|
2022-10-23 20:12:23 +03:00
|
|
|
|
serve.moduleName = moduleName
|
|
|
|
|
serve.funcs = make(map[string]funcDesc)
|
|
|
|
|
|
2022-10-25 14:47:26 +03:00
|
|
|
|
serve.accept = make(map[string]map[string]bool)
|
|
|
|
|
serve.accept["system"] = make(map[string]bool)
|
|
|
|
|
serve.accept["system"]["gateway"] = true
|
|
|
|
|
serve.accept["system"]["security"] = true
|
|
|
|
|
serve.accept["system"]["settings"] = true
|
|
|
|
|
serve.accept["system"]["telegram"] = true
|
|
|
|
|
//serve.accept[projectName][moduleName] = true
|
|
|
|
|
|
2022-11-05 12:41:03 +03:00
|
|
|
|
serve.timeoutCallback = time.Second * 30
|
|
|
|
|
|
2022-12-01 15:23:42 +03:00
|
|
|
|
if queueNameLog != nil {
|
|
|
|
|
if priority == nil {
|
|
|
|
|
priority = &[]ytlogger.Priority{ytlogger.LOG_INFO}[0]
|
|
|
|
|
}
|
|
|
|
|
serve.logger = ytlogger.NewYTLogger(*priority, 100000, serve.sendLog)
|
|
|
|
|
serve.queueNameLog = queueNameLog
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-23 20:12:23 +03:00
|
|
|
|
return serve
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-01 15:23:42 +03:00
|
|
|
|
// Функция отправки логов на удаленный сервер
|
|
|
|
|
func (serve *Serve) sendLog(pkg *log.Pkg) {
|
|
|
|
|
var b []byte
|
|
|
|
|
var err error
|
|
|
|
|
b, err = proto.Marshal(pkg)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
serve.nc.Publish(*serve.queueNameLog, b)
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-28 11:19:03 +03:00
|
|
|
|
// Установка разрешающих правил выполнения функций
|
2022-10-25 14:47:26 +03:00
|
|
|
|
func (serve *Serve) AddAccept(ruleName string) bool {
|
|
|
|
|
return serve.AddAcceptBool(ruleName, true)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Установка разрешающих правил выполнения функций
|
|
|
|
|
func (serve *Serve) AddAcceptBool(ruleName string, allow bool) bool {
|
|
|
|
|
ruleName = strings.Trim(ruleName, " ")
|
|
|
|
|
if ruleName == "" {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if ruleName == "*" {
|
|
|
|
|
serve.accept = make(map[string]map[string]bool)
|
|
|
|
|
serve.accept["*"] = make(map[string]bool)
|
|
|
|
|
serve.accept["*"]["*"] = allow
|
|
|
|
|
} else {
|
|
|
|
|
rules := strings.Split(ruleName, ".")
|
|
|
|
|
for i := range rules {
|
|
|
|
|
rules[i] = strings.Trim(rules[i], " ")
|
|
|
|
|
}
|
|
|
|
|
switch len(rules) {
|
|
|
|
|
case 0:
|
|
|
|
|
return false
|
|
|
|
|
case 1:
|
|
|
|
|
serve.accept[rules[0]] = make(map[string]bool)
|
|
|
|
|
serve.accept[rules[0]]["*"] = allow
|
|
|
|
|
case 2:
|
|
|
|
|
if rules[0] == "*" || rules[0] == "" {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if rules[1] == "" {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if _, ok := serve.accept[rules[0]]; !ok {
|
|
|
|
|
serve.accept[rules[0]] = make(map[string]bool)
|
|
|
|
|
}
|
|
|
|
|
if rules[1] == "*" {
|
|
|
|
|
serve.accept[rules[0]]["*"] = allow
|
|
|
|
|
} else {
|
|
|
|
|
serve.accept[rules[0]][rules[1]] = allow
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-28 13:46:43 +03:00
|
|
|
|
func (serve *Serve) natsErrHandler(nc *nats.Conn, sub *nats.Subscription, natsErr error) {
|
|
|
|
|
fmt.Printf("error: %v\n", natsErr)
|
|
|
|
|
if natsErr == nats.ErrSlowConsumer {
|
|
|
|
|
pendingMsgs, _, err := sub.Pending()
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Printf("couldn't get pending messages: %v", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
fmt.Printf("Falling behind with %d pending messages on subject %q.\n",
|
|
|
|
|
pendingMsgs, sub.Subject)
|
|
|
|
|
// Log error, notify operations...
|
|
|
|
|
}
|
|
|
|
|
// check for other errors
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-28 11:19:03 +03:00
|
|
|
|
// Запуск текущего инстанса сервера
|
2022-10-23 20:12:23 +03:00
|
|
|
|
func (serve *Serve) Run() (err error) {
|
2022-10-27 13:51:12 +03:00
|
|
|
|
if serve.nc == nil {
|
2022-11-11 19:07:23 +03:00
|
|
|
|
serve.nc, err = nats.Connect(serve.NatsAddr, nats.ErrorHandler(serve.natsErrHandler))
|
2022-10-27 13:51:12 +03:00
|
|
|
|
if err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
2022-10-28 15:06:24 +03:00
|
|
|
|
} else {
|
2022-10-27 13:51:12 +03:00
|
|
|
|
serve.hasNats = true
|
2022-10-23 20:12:23 +03:00
|
|
|
|
}
|
2022-10-25 12:59:22 +03:00
|
|
|
|
rnd := make([]byte, 16)
|
|
|
|
|
_, err = rand.Read(rnd)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
2022-11-05 12:41:03 +03:00
|
|
|
|
//serve.callbackFuncs = make(map[string]func(err error, header *network.Header, result []byte))
|
|
|
|
|
serve.callbackFuncs = make(map[string]*CallbackFunc)
|
2022-10-25 12:59:22 +03:00
|
|
|
|
serve.queueCallback = fmt.Sprintf("%s.%s.%x", serve.projectName, serve.moduleName, rnd)
|
|
|
|
|
serve.chanQueueCallback = make(chan *nats.Msg)
|
2022-11-03 19:52:23 +03:00
|
|
|
|
serve.subj, err = serve.nc.ChanQueueSubscribe(serve.queueCallback, serve.projectName+"."+serve.moduleName, serve.chanQueueCallback)
|
2022-10-25 12:59:22 +03:00
|
|
|
|
go serve.worker()
|
2022-10-23 20:12:23 +03:00
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-05 12:41:03 +03:00
|
|
|
|
func (serve *Serve) cleanTimeout() {
|
|
|
|
|
serve.callbackFuncsMutex.Lock()
|
|
|
|
|
defer serve.callbackFuncsMutex.Unlock()
|
|
|
|
|
for k, v := range serve.callbackFuncs {
|
|
|
|
|
if time.Since(v.TimeCall) > serve.timeoutCallback {
|
|
|
|
|
delete(serve.callbackFuncs, k)
|
|
|
|
|
err := fmt.Errorf("call function is timed out")
|
|
|
|
|
go v.F(err, nil, nil)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 12:59:22 +03:00
|
|
|
|
func (serve *Serve) worker() {
|
2022-11-05 12:41:03 +03:00
|
|
|
|
go func() {
|
|
|
|
|
for {
|
|
|
|
|
<-time.After(serve.timeoutCallback)
|
|
|
|
|
serve.cleanTimeout()
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
2022-10-25 12:59:22 +03:00
|
|
|
|
for {
|
|
|
|
|
if msg, ok := <-serve.chanQueueCallback; !ok {
|
|
|
|
|
break
|
|
|
|
|
} else {
|
|
|
|
|
var err error
|
|
|
|
|
var payload network.Function
|
|
|
|
|
err = proto.Unmarshal(msg.Data, &payload)
|
|
|
|
|
if err != nil {
|
2022-11-22 09:19:07 +03:00
|
|
|
|
//panic(err)
|
|
|
|
|
continue
|
2022-10-25 12:59:22 +03:00
|
|
|
|
}
|
2022-11-23 10:44:09 +03:00
|
|
|
|
if payload.Metadata != nil {
|
|
|
|
|
if f, ok := serve.callbackFuncs[payload.Metadata.CallID]; ok {
|
|
|
|
|
serve.callbackFuncsMutex.Lock()
|
|
|
|
|
delete(serve.callbackFuncs, payload.Metadata.CallID)
|
|
|
|
|
serve.callbackFuncsMutex.Unlock()
|
|
|
|
|
if payload.ErrNo != 0 {
|
|
|
|
|
err = fmt.Errorf(payload.Error)
|
|
|
|
|
}
|
|
|
|
|
if f != nil {
|
|
|
|
|
//go f.F(err, payload.Header, payload.Payload)
|
|
|
|
|
f.F(err, payload.Header, payload.Payload)
|
|
|
|
|
}
|
|
|
|
|
//f(err, payload.Header, payload.Payload)
|
2022-11-05 12:41:03 +03:00
|
|
|
|
}
|
2022-10-25 12:59:22 +03:00
|
|
|
|
}
|
2022-10-28 11:19:03 +03:00
|
|
|
|
|
2022-10-25 12:59:22 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-28 11:19:03 +03:00
|
|
|
|
// Завершение текущего инстанса сервера
|
2022-10-23 20:12:23 +03:00
|
|
|
|
func (serve *Serve) Shutdown() {
|
|
|
|
|
for _, value := range serve.funcs {
|
|
|
|
|
value.subj.Unsubscribe()
|
|
|
|
|
close(value.inputChan)
|
|
|
|
|
}
|
2022-10-26 14:45:40 +03:00
|
|
|
|
err := serve.subj.Unsubscribe()
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
2022-10-25 12:59:22 +03:00
|
|
|
|
close(serve.chanQueueCallback)
|
2022-10-27 13:51:12 +03:00
|
|
|
|
if !serve.hasNats {
|
|
|
|
|
serve.nc.Close()
|
|
|
|
|
}
|
2022-10-23 20:12:23 +03:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-28 11:19:03 +03:00
|
|
|
|
// Регистрация функции в текущем инстансе
|
2022-10-25 12:59:22 +03:00
|
|
|
|
func (serve *Serve) RegisterFunction(funcName string, f func(header *network.Header, paylod []byte) (result []byte, err error)) (err error) {
|
2022-11-22 14:21:25 +03:00
|
|
|
|
return serve.RegisterFunctionWithTimeout(funcName, time.Second*30, f)
|
2022-10-25 12:59:22 +03:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-28 11:19:03 +03:00
|
|
|
|
// Регистрация функции с установленным таймаутом в текущем инстансе
|
2022-10-25 12:59:22 +03:00
|
|
|
|
func (serve *Serve) RegisterFunctionWithTimeout(funcName string, timeout time.Duration, f func(header *network.Header, paylod []byte) (result []byte, err error)) (err error) {
|
2022-10-23 20:12:23 +03:00
|
|
|
|
if _, ok := serve.funcs[fmt.Sprintf("%s.%s", serve.moduleName, funcName)]; ok {
|
2022-10-27 13:43:26 +03:00
|
|
|
|
return fmt.Errorf(`restrict duplicate function name`)
|
2022-10-23 20:12:23 +03:00
|
|
|
|
}
|
|
|
|
|
id := make([]byte, 16)
|
|
|
|
|
|
|
|
|
|
_, err = rand.Read(id)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fDesc := funcDesc{
|
2022-12-01 15:23:42 +03:00
|
|
|
|
Name: fmt.Sprintf("%s.%s.%s", serve.projectName, serve.moduleName, funcName),
|
|
|
|
|
F: f,
|
|
|
|
|
logger: serve.logger,
|
2022-10-23 20:12:23 +03:00
|
|
|
|
}
|
|
|
|
|
fDesc.inputChan = make(chan *nats.Msg)
|
2022-11-03 19:52:23 +03:00
|
|
|
|
fDesc.subj, err = serve.nc.ChanQueueSubscribe(fmt.Sprintf("%s.%s.%s", serve.projectName, serve.moduleName, funcName), serve.projectName+"."+serve.moduleName, fDesc.inputChan)
|
2022-10-25 12:59:22 +03:00
|
|
|
|
fDesc.conn = serve.nc
|
|
|
|
|
fDesc.timeout = timeout
|
2022-10-25 14:47:26 +03:00
|
|
|
|
fDesc.acceptFunc = serve.acceptVerify
|
2022-10-23 20:12:23 +03:00
|
|
|
|
go fDesc.worker()
|
|
|
|
|
|
2022-10-25 12:59:22 +03:00
|
|
|
|
serve.funcs[fmt.Sprintf("%s.%s.%s", serve.projectName, serve.moduleName, funcName)] = fDesc
|
2022-10-23 20:12:23 +03:00
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-28 11:19:03 +03:00
|
|
|
|
// Проверка есть ли такая функция в текущем инстансе
|
2022-10-23 20:12:23 +03:00
|
|
|
|
func (serve *Serve) HasFunction(name string) bool {
|
2022-10-25 12:59:22 +03:00
|
|
|
|
_, ok := serve.funcs[fmt.Sprintf("%s.%s.%s", serve.projectName, serve.moduleName, name)]
|
2022-10-23 20:12:23 +03:00
|
|
|
|
return ok
|
|
|
|
|
}
|
2022-10-25 12:59:22 +03:00
|
|
|
|
|
2022-10-25 14:47:26 +03:00
|
|
|
|
// Проверка возможности выполнения функции на основе установленных вызывающих сторон
|
|
|
|
|
func (serve *Serve) acceptVerify(accept string) bool {
|
|
|
|
|
|
|
|
|
|
if _, ok := serve.accept["*"]; ok {
|
|
|
|
|
return true
|
|
|
|
|
} else {
|
|
|
|
|
accept = strings.Trim(accept, " ")
|
|
|
|
|
if accept == "" {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rules := strings.Split(accept, ".")
|
|
|
|
|
for i := range rules {
|
|
|
|
|
rules[i] = strings.Trim(rules[i], " ")
|
|
|
|
|
}
|
|
|
|
|
if len(rules) == 0 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if val, ok := serve.accept[rules[0]]; !ok {
|
|
|
|
|
return false
|
|
|
|
|
} else {
|
|
|
|
|
if _, ok := val["*"]; ok {
|
|
|
|
|
return true
|
|
|
|
|
} else {
|
|
|
|
|
if len(rules) == 1 {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if v, ok := val[rules[1]]; !ok {
|
|
|
|
|
return false
|
|
|
|
|
} else {
|
|
|
|
|
return v
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-28 11:19:03 +03:00
|
|
|
|
// Асинхронный вызов функции
|
2022-11-04 17:10:59 +03:00
|
|
|
|
func (serve *Serve) CallAsync(name string, header *network.Header, payload []byte, f func(err error, header *network.Header, result []byte)) {
|
2022-10-25 12:59:22 +03:00
|
|
|
|
metadata := &network.Metadata{
|
2022-11-30 14:24:24 +03:00
|
|
|
|
//PackageType: network.Metadata_TYPE_REQUEST,
|
2022-10-25 12:59:22 +03:00
|
|
|
|
FuncName: name,
|
|
|
|
|
QueueCallback: serve.queueCallback,
|
|
|
|
|
CallID: uuid.NewV4().String(),
|
2022-10-25 14:47:26 +03:00
|
|
|
|
CallFrom: fmt.Sprintf("%s.%s", serve.projectName, serve.moduleName),
|
2022-10-25 12:59:22 +03:00
|
|
|
|
}
|
2022-10-27 15:19:47 +03:00
|
|
|
|
if header == nil {
|
|
|
|
|
header = &network.Header{}
|
|
|
|
|
}
|
2022-11-30 14:24:24 +03:00
|
|
|
|
header.CallPrevID = header.CallID
|
|
|
|
|
header.CallID = metadata.CallID
|
2022-10-27 15:19:47 +03:00
|
|
|
|
header.Project = serve.projectName
|
2022-10-25 12:59:22 +03:00
|
|
|
|
pkg := network.Function{
|
|
|
|
|
Header: header,
|
|
|
|
|
Payload: payload,
|
|
|
|
|
Metadata: metadata,
|
|
|
|
|
}
|
|
|
|
|
buf, err := proto.Marshal(&pkg)
|
|
|
|
|
if err != nil {
|
2022-11-28 10:13:52 +03:00
|
|
|
|
if f != nil {
|
|
|
|
|
f(err, header, payload)
|
|
|
|
|
}
|
|
|
|
|
return
|
2022-10-25 12:59:22 +03:00
|
|
|
|
}
|
2022-11-05 12:41:03 +03:00
|
|
|
|
|
|
|
|
|
callback := &CallbackFunc{
|
|
|
|
|
F: f,
|
|
|
|
|
TimeCall: time.Now(),
|
2022-11-30 14:24:24 +03:00
|
|
|
|
//Metadata: pkg.Metadata,
|
2022-11-05 12:41:03 +03:00
|
|
|
|
}
|
2022-10-28 14:59:43 +03:00
|
|
|
|
serve.callbackFuncsMutex.Lock()
|
|
|
|
|
defer serve.callbackFuncsMutex.Unlock()
|
2022-11-05 12:41:03 +03:00
|
|
|
|
serve.callbackFuncs[metadata.CallID] = callback
|
|
|
|
|
//serve.callbackFuncs[metadata.CallID] = f
|
2022-10-25 12:59:22 +03:00
|
|
|
|
serve.nc.Publish(name, buf)
|
|
|
|
|
}
|
2022-10-25 13:09:48 +03:00
|
|
|
|
|
2022-10-28 11:19:03 +03:00
|
|
|
|
// Синхронный вызов функции
|
2022-11-04 17:15:34 +03:00
|
|
|
|
func (serve *Serve) Call(name string, header *network.Header, payload []byte) (result []byte, head *network.Header, err error) {
|
2022-10-28 15:01:05 +03:00
|
|
|
|
chanRes := make(chan *ChanRes)
|
2022-11-04 17:10:59 +03:00
|
|
|
|
serve.CallAsync(name, header, payload, func(err error, header *network.Header, result []byte) {
|
2022-10-28 15:01:05 +03:00
|
|
|
|
chanRes <- &ChanRes{
|
2022-11-04 17:10:59 +03:00
|
|
|
|
res: result,
|
|
|
|
|
header: header,
|
|
|
|
|
err: err,
|
2022-10-28 13:46:43 +03:00
|
|
|
|
}
|
2022-10-25 13:09:48 +03:00
|
|
|
|
})
|
2022-10-28 13:46:43 +03:00
|
|
|
|
res := <-chanRes
|
|
|
|
|
err = res.err
|
2022-11-04 17:15:34 +03:00
|
|
|
|
head = res.header
|
2022-10-28 13:46:43 +03:00
|
|
|
|
result = res.res
|
2022-10-25 13:09:48 +03:00
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
2022-11-28 10:13:52 +03:00
|
|
|
|
|
|
|
|
|
// Вызов функции как поток без ожидания возврата результата
|
|
|
|
|
func (serve *Serve) CallStream(name string, header *network.Header, payload []byte) (err error) {
|
|
|
|
|
metadata := &network.Metadata{
|
2022-11-30 14:24:24 +03:00
|
|
|
|
//PackageType: network.Metadata_TYPE_STREAM,
|
2022-11-28 10:13:52 +03:00
|
|
|
|
FuncName: name,
|
|
|
|
|
QueueCallback: serve.queueCallback,
|
|
|
|
|
CallID: uuid.NewV4().String(),
|
|
|
|
|
CallFrom: fmt.Sprintf("%s.%s", serve.projectName, serve.moduleName),
|
|
|
|
|
}
|
|
|
|
|
if header == nil {
|
|
|
|
|
header = &network.Header{}
|
|
|
|
|
}
|
|
|
|
|
header.Project = serve.projectName
|
|
|
|
|
pkg := network.Function{
|
|
|
|
|
Header: header,
|
|
|
|
|
Payload: payload,
|
|
|
|
|
Metadata: metadata,
|
|
|
|
|
}
|
|
|
|
|
var buf []byte
|
|
|
|
|
buf, err = proto.Marshal(&pkg)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
serve.nc.Publish(name, buf)
|
|
|
|
|
return
|
|
|
|
|
}
|