refactor foundry lib structure; add transport classes for db,http,websocket; add action interface instead of multiple function that accepts action classes; add changing foundry status on websocket responses
This commit is contained in:
40
internal/foundry/types/codes.go
Normal file
40
internal/foundry/types/codes.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package types
|
||||
|
||||
type DirectionCode int
|
||||
type TransportCode int
|
||||
|
||||
const (
|
||||
WriterCode = DirectionCode(0)
|
||||
ReaderCode = DirectionCode(1)
|
||||
|
||||
DbCode = TransportCode(0)
|
||||
HttpCode = TransportCode(1)
|
||||
WebSocketCode = TransportCode(2)
|
||||
)
|
||||
|
||||
const (
|
||||
RespSessionDataCode = "0"
|
||||
RespPingCode = "2"
|
||||
RespSessionIdCode = "40"
|
||||
RespServerChangeCode = "42"
|
||||
RespDataCode = "43"
|
||||
|
||||
ReqPongCode = "3"
|
||||
ReqCreateSessionCode = "40"
|
||||
ReqDataCode = "42"
|
||||
)
|
||||
|
||||
var RequestCodes = []string{
|
||||
RespSessionDataCode,
|
||||
RespPingCode,
|
||||
RespSessionIdCode,
|
||||
RespServerChangeCode,
|
||||
RespDataCode,
|
||||
}
|
||||
|
||||
var CodesRespToReq = map[string]string{
|
||||
RespSessionDataCode: ReqCreateSessionCode,
|
||||
RespPingCode: ReqPongCode,
|
||||
RespServerChangeCode: ReqDataCode,
|
||||
//ReqDataCode: RespServerChangeCode,
|
||||
}
|
||||
24
internal/foundry/types/error.go
Normal file
24
internal/foundry/types/error.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package types
|
||||
|
||||
import "fmt"
|
||||
|
||||
type FoundryError struct {
|
||||
Err error
|
||||
Direction DirectionCode
|
||||
Type TransportCode
|
||||
IsFatal bool
|
||||
}
|
||||
|
||||
func (e *FoundryError) Error() string {
|
||||
return fmt.Sprintf("Received from %d: %s", e.Type, e.Err.Error())
|
||||
}
|
||||
|
||||
func (e *FoundryError) Unwrap() error { return e.Err }
|
||||
|
||||
// func NewWriterError(err error, isFatal bool) *FoundryError {
|
||||
// return &FoundryError{Direction: WriterCode, Err: err, IsFatal: isFatal}
|
||||
// }
|
||||
|
||||
// func NewReaderError(err error, isFatal bool) *FoundryError {
|
||||
// return &FoundryError{Type: ReaderCode, Err: err, IsFatal: isFatal}
|
||||
// }
|
||||
@@ -1,9 +0,0 @@
|
||||
package types
|
||||
|
||||
import "sync"
|
||||
|
||||
type ExchangeChannels struct {
|
||||
Msgs map[int](chan []byte)
|
||||
ProgressMsg map[string](chan struct{})
|
||||
ProgressMutex sync.Mutex
|
||||
}
|
||||
35
internal/foundry/types/status.go
Normal file
35
internal/foundry/types/status.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package types
|
||||
|
||||
import "gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/models/json"
|
||||
|
||||
type FoundryStatus struct {
|
||||
IsActive bool
|
||||
Version string
|
||||
World string
|
||||
System string
|
||||
SystemVersion string
|
||||
Users int
|
||||
Uptime int64
|
||||
}
|
||||
|
||||
func NewFoundryStatus(status *json.Status) *FoundryStatus {
|
||||
return &FoundryStatus{
|
||||
IsActive: status.Active,
|
||||
Version: status.Version,
|
||||
World: status.World,
|
||||
System: status.System,
|
||||
SystemVersion: status.SystemVersion,
|
||||
Users: status.Users,
|
||||
Uptime: status.Uptime,
|
||||
}
|
||||
}
|
||||
|
||||
func (fs *FoundryStatus) Update(status *json.Status) {
|
||||
fs.IsActive = status.Active
|
||||
fs.Version = status.Version
|
||||
fs.World = status.World
|
||||
fs.System = status.System
|
||||
fs.SystemVersion = status.SystemVersion
|
||||
fs.Users = status.Users
|
||||
fs.Uptime = status.Uptime
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func findByTag(obj any, tag string) (int, error) {
|
||||
structType := reflect.TypeOf(obj).Elem()
|
||||
for i := 0; i < structType.NumField(); i++ {
|
||||
fieldTags := structType.Field(i).Tag.Get("json")
|
||||
if tag == strings.Split(fieldTags, ",")[0] {
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
return -1, fmt.Errorf("No such field: %s in obj", tag)
|
||||
}
|
||||
|
||||
func setField(obj any, name string, value any) error {
|
||||
structValue := reflect.ValueOf(obj).Elem()
|
||||
idx, err := findByTag(obj, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
structFieldValue := structValue.Field(idx)
|
||||
|
||||
if !structFieldValue.IsValid() {
|
||||
return fmt.Errorf("No such field: %s in obj", name)
|
||||
}
|
||||
|
||||
if !structFieldValue.CanSet() {
|
||||
return fmt.Errorf("Cannot set %s field value", name)
|
||||
}
|
||||
|
||||
structFieldType := structFieldValue.Type()
|
||||
val := reflect.ValueOf(value)
|
||||
if structFieldType != val.Type() {
|
||||
return errors.New("Provided value type didn't match obj field type")
|
||||
}
|
||||
|
||||
if value == nil {
|
||||
structFieldValue.Set(reflect.Zero(structFieldType))
|
||||
} else {
|
||||
structFieldValue.Set(val)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isPointer(obj any) bool {
|
||||
iv := reflect.ValueOf(obj)
|
||||
if !iv.IsValid() {
|
||||
return false
|
||||
}
|
||||
|
||||
return iv.Kind() == reflect.Pointer
|
||||
}
|
||||
|
||||
func FillStruct(m map[string]any, obj any) error {
|
||||
if !isPointer(obj) {
|
||||
return errors.New("Passed obj is not pointer")
|
||||
}
|
||||
|
||||
for k, v := range m {
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
err := setField(obj, k, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Dereference(input any) any {
|
||||
v := reflect.ValueOf(input)
|
||||
|
||||
// Check if the value is a pointer
|
||||
if v.Kind() == reflect.Pointer {
|
||||
// v.Elem() returns the value the pointer points to
|
||||
return v.Elem().Interface()
|
||||
}
|
||||
|
||||
return input
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package types
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
WsSessionType = "session"
|
||||
WsProgressType = "progress"
|
||||
WsUserActivityType = "userActivity"
|
||||
WsShutdownType = "shutdown"
|
||||
)
|
||||
|
||||
var WsMsgActions = map[string]func() any{
|
||||
"session": func() any { return &WsSessionMsg{} },
|
||||
"progress": func() any { return &WsProgressMsg{} },
|
||||
// "userActivity": WsUserActivityCursor{},
|
||||
"shutdown": func() any { return &WsShutdownMsg{} },
|
||||
}
|
||||
|
||||
func GetWsMsgAction(dataType string) any {
|
||||
if factory, ok := WsMsgActions[dataType]; ok {
|
||||
return factory()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type WsSessionMsg struct {
|
||||
SessionId string `json:"sessionId"`
|
||||
UserId *string `json:"userId,omitempty"`
|
||||
}
|
||||
|
||||
func (msg WsSessionMsg) Action() error {
|
||||
fmt.Println("WsSessionMsg")
|
||||
return nil
|
||||
}
|
||||
|
||||
type WsProgressMsg struct {
|
||||
Id string `json:"id"`
|
||||
Message string `json:"message"`
|
||||
Pct float64 `json:"pct"`
|
||||
HasChanged bool `json:"hasChanged,omitempty"`
|
||||
Act string `json:"action"`
|
||||
Step string `json:"step"`
|
||||
}
|
||||
|
||||
func (msg WsProgressMsg) Action() error {
|
||||
fmt.Println("WsProgressMsg")
|
||||
return nil
|
||||
}
|
||||
|
||||
type WsUserActivityMsg struct {
|
||||
Cursor WsUserActivityCursor `json:"cursor"`
|
||||
}
|
||||
|
||||
type WsUserActivityCursor struct {
|
||||
X int `json:"x"`
|
||||
Y int `json:"y"`
|
||||
}
|
||||
|
||||
func (msg WsUserActivityMsg) Action() error {
|
||||
fmt.Println("WsUserActivityMsg")
|
||||
return nil
|
||||
}
|
||||
|
||||
type WsShutdownMsg struct {
|
||||
World string `json:"world"`
|
||||
UserId *string `json:"userId,omitempty"`
|
||||
}
|
||||
|
||||
func (msg WsShutdownMsg) Action() error {
|
||||
fmt.Println("WsShutdownMsg")
|
||||
return nil
|
||||
}
|
||||
@@ -1,5 +1,13 @@
|
||||
package types
|
||||
|
||||
import "sync"
|
||||
|
||||
type ExchangeChannels struct {
|
||||
Msgs map[int](chan []byte)
|
||||
ProgressMsg map[string](chan struct{})
|
||||
ProgressMutex sync.Mutex
|
||||
}
|
||||
|
||||
type ReadChannels struct {
|
||||
done chan struct{}
|
||||
msg chan *WsMessage
|
||||
@@ -25,11 +33,9 @@ func (channels *ReadChannels) Close() {
|
||||
}
|
||||
|
||||
func InitWsChannels() *ReadChannels {
|
||||
channels := ReadChannels{
|
||||
return &ReadChannels{
|
||||
done: make(chan struct{}),
|
||||
err: make(chan error, 10),
|
||||
msg: make(chan *WsMessage, 10),
|
||||
}
|
||||
|
||||
return &channels
|
||||
}
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
package types
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/requests"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrorMsgNotHaveNumber = errors.New("Message doesn't have dataCode and id")
|
||||
)
|
||||
|
||||
type WsMessage struct {
|
||||
Code string
|
||||
@@ -15,3 +26,58 @@ func (w WsMessage) ToString() string {
|
||||
func (w WsMessage) ToByteSlice() []byte {
|
||||
return fmt.Appendf([]byte{}, "%s%d%s", w.Code, w.Id, w.MsgJson)
|
||||
}
|
||||
|
||||
func parseCode(msg *string, requestCodes []string) string {
|
||||
for j := range requestCodes {
|
||||
if !strings.HasPrefix(*msg, requestCodes[j]) {
|
||||
continue
|
||||
}
|
||||
return requestCodes[j]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func parseId(msg *string, start int) (int, int) {
|
||||
msgLen := len(*msg)
|
||||
j := start
|
||||
for ; j < msgLen; j++ {
|
||||
if (*msg)[j] < '0' || (*msg)[j] > '9' {
|
||||
break
|
||||
}
|
||||
}
|
||||
if j >= msgLen || j <= 0 {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
msgId, err := strconv.Atoi((*msg)[start:j])
|
||||
if err != nil {
|
||||
return 0, 0
|
||||
}
|
||||
return msgId, j
|
||||
}
|
||||
|
||||
func ParseWsRespMessage(msg string, requestCodes []string) (*WsMessage, error) {
|
||||
data := &WsMessage{}
|
||||
|
||||
data.Code = parseCode(&msg, requestCodes)
|
||||
|
||||
i := len(data.Code)
|
||||
if i == 0 {
|
||||
return nil, ErrorMsgNotHaveNumber
|
||||
}
|
||||
|
||||
data.Id, i = parseId(&msg, i)
|
||||
if i == 0 {
|
||||
i = len(data.Code)
|
||||
}
|
||||
// if i == 0 {
|
||||
// return nil, ErrorMsgNotHaveNumber
|
||||
// }
|
||||
|
||||
data.MsgJson = msg[i:]
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func NewWsMessageByPage(page string, currWsId int) *WsMessage {
|
||||
return &WsMessage{Code: CodesRespToReq[RespServerChangeCode], Id: currWsId, MsgJson: fmt.Sprintf("[\"%s\"]", requests.WsTypeData[page])}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user