github.com/easysoft/zendata@v0.0.0-20240513203326-705bd5a7fd67/internal/server/service/mock.go (about)

     1  package serverService
     2  
     3  import (
     4  	"encoding/json"
     5  	"encoding/xml"
     6  	"errors"
     7  	"fmt"
     8  	"mime/multipart"
     9  	"os"
    10  	"path/filepath"
    11  	"regexp"
    12  	"strings"
    13  	"time"
    14  
    15  	consts "github.com/easysoft/zendata/internal/pkg/const"
    16  	"github.com/easysoft/zendata/internal/pkg/domain"
    17  	"github.com/easysoft/zendata/internal/pkg/helper"
    18  	"github.com/easysoft/zendata/internal/pkg/model"
    19  	"github.com/easysoft/zendata/internal/pkg/service"
    20  	serverRepo "github.com/easysoft/zendata/internal/server/repo"
    21  	dateUtils "github.com/easysoft/zendata/pkg/utils/date"
    22  	fileUtils "github.com/easysoft/zendata/pkg/utils/file"
    23  	logUtils "github.com/easysoft/zendata/pkg/utils/log"
    24  	stringUtils "github.com/easysoft/zendata/pkg/utils/string"
    25  	"github.com/easysoft/zendata/pkg/utils/vari"
    26  	"github.com/kataras/iris/v12"
    27  	"github.com/snowlyg/helper/dir"
    28  	"gopkg.in/yaml.v2"
    29  )
    30  
    31  var (
    32  	MockServiceDataMap                = map[string]domain.MockPathMap{}
    33  	MockServiceDataDefMap             = map[string]string{}
    34  	MockServiceDataRegxPathToOrigPath = map[string]map[string]string{}
    35  )
    36  
    37  type MockService struct {
    38  	MainService   *service.MainService   `inject:""`
    39  	OutputService *service.OutputService `inject:""`
    40  	MockService   *service.MockService   `inject:""`
    41  	DefService    *DefService            `inject:""`
    42  	MockRepo      *serverRepo.MockRepo   `inject:""`
    43  }
    44  
    45  func (s *MockService) List(keywords string, page int) (pos []*model.ZdMock, total int, err error) {
    46  	pos, total, err = s.MockRepo.List(strings.TrimSpace(keywords), page)
    47  	return
    48  }
    49  
    50  func (s *MockService) Get(id int) (po model.ZdMock, err error) {
    51  	po, err = s.MockRepo.Get(uint(id))
    52  
    53  	return
    54  }
    55  
    56  func (s *MockService) Save(po *model.ZdMock) (err error) {
    57  	zdDef, err := helper.GetDefFromYamlString(po.MockContent)
    58  	if err != nil {
    59  		return
    60  	}
    61  	po.Name = zdDef.Title
    62  
    63  	if po.DefId == 0 {
    64  		fi := domain.ResFile{FileName: po.Name, Path: po.DataPath}
    65  		_, po.DefId = s.DefService.SyncToDB(fi, true)
    66  	}
    67  	err = s.MockRepo.Save(po)
    68  
    69  	return
    70  }
    71  
    72  func (s *MockService) Remove(id int) (err error) {
    73  	err = s.MockRepo.Remove(uint(id))
    74  
    75  	return
    76  }
    77  
    78  func (s *MockService) LoadDef(pth string, files *[]string, level int) (err error) {
    79  	if !fileUtils.IsDir(pth) {
    80  		*files = append(*files, pth)
    81  		return
    82  	}
    83  
    84  	dir, err := os.ReadDir(pth)
    85  	if err != nil {
    86  		return err
    87  	}
    88  
    89  	for _, fi := range dir {
    90  		childPath := filepath.Join(pth, fi.Name())
    91  
    92  		if fi.IsDir() && level < 3 {
    93  			s.LoadDef(childPath, files, level+1)
    94  
    95  		} else {
    96  			*files = append(*files, childPath)
    97  
    98  		}
    99  	}
   100  
   101  	return nil
   102  }
   103  
   104  func (s *MockService) GetResp(reqPath, reqMethod, respCode, mediaType string) (ret interface{}, err error) {
   105  	servicePath, apiPath := s.getServiceAndApiPath(reqPath)
   106  	reqMethod = strings.ToLower(reqMethod)
   107  
   108  	if MockServiceDataMap[servicePath] == nil {
   109  		err = errors.New("no matched service OR service not start")
   110  		return
   111  	}
   112  
   113  	for pth, mp := range MockServiceDataMap[servicePath] {
   114  		if !regexp.MustCompile(pth).MatchString(apiPath) { // no match
   115  			continue
   116  		}
   117  
   118  		if mp[reqMethod] == nil { // no such a method
   119  			continue
   120  		}
   121  
   122  		mockPo, err := s.MockRepo.GetByPath(servicePath)
   123  		if err != nil {
   124  			continue
   125  		}
   126  
   127  		endpoint := mp[reqMethod][respCode][mediaType]
   128  
   129  		key := fmt.Sprintf("%s-%s-%s-%s",
   130  			MockServiceDataRegxPathToOrigPath[servicePath][pth], reqMethod, respCode, mediaType)
   131  		src, _ := s.MockRepo.GetSampleSrc(mockPo.ID, key)
   132  		if src.Value != "" && src.Value != "schema" {
   133  			str := endpoint.Samples[src.Value]
   134  			if src.Value == "json" {
   135  				json.Unmarshal([]byte(str), &ret)
   136  			} else if src.Value == "xml" {
   137  				xml.Unmarshal([]byte(str), &ret)
   138  			} else {
   139  				ret = str
   140  			}
   141  		} else {
   142  			ret, err = s.GenDataForServerRequest(mp[reqMethod][respCode][mediaType], MockServiceDataDefMap[servicePath])
   143  			if err != nil {
   144  				continue
   145  			}
   146  		}
   147  	}
   148  
   149  	if ret == nil {
   150  		err = errors.New("no matched api")
   151  		return
   152  	}
   153  
   154  	return
   155  }
   156  
   157  func (s *MockService) GenDataForServerRequest(endpoint *domain.EndPoint, dataConfigContent string) (ret interface{}, err error) {
   158  	if endpoint == nil || dataConfigContent == "" {
   159  		return
   160  	}
   161  
   162  	vari.GlobalVars.RunMode = consts.RunModeServerRequest
   163  	vari.GlobalVars.Total = endpoint.Lines
   164  	vari.GlobalVars.OutputFormat = "json"
   165  	vari.GlobalVars.ExportFields = strings.Split(endpoint.Fields, ",")
   166  
   167  	dataType := endpoint.Type
   168  	if dataType != consts.SchemaTypeArray {
   169  		vari.GlobalVars.Total = 1
   170  	}
   171  
   172  	contents := [][]byte{[]byte(dataConfigContent)}
   173  
   174  	s.MainService.GenerateDataByContents(contents)
   175  
   176  	records := s.OutputService.GenRecords()
   177  	if dataType == "item" {
   178  		ret = records[0]
   179  	} else {
   180  		ret = records
   181  	}
   182  
   183  	return
   184  }
   185  
   186  func (s *MockService) GenDataForMockPreview(endpoint *domain.EndPoint, dataConfig string) (ret interface{}, err error) {
   187  	vari.GlobalVars.RunMode = consts.RunModeMockPreview
   188  	vari.GlobalVars.Total = endpoint.Lines
   189  	vari.GlobalVars.OutputFormat = "json"
   190  	vari.GlobalVars.ExportFields = strings.Split(endpoint.Fields, ",")
   191  
   192  	dataType := endpoint.Type
   193  	if dataType != consts.SchemaTypeArray {
   194  		vari.GlobalVars.Total = 1
   195  	}
   196  
   197  	contents := [][]byte{[]byte(dataConfig)}
   198  	s.MainService.GenerateDataByContents(contents)
   199  
   200  	records := s.OutputService.GenRecords()
   201  	if dataType == consts.SchemaTypeObject {
   202  		ret = records[0]
   203  	} else {
   204  		ret = records
   205  	}
   206  
   207  	return
   208  }
   209  
   210  func (s *MockService) addPrefixIfNeeded(pth string) (ret string) {
   211  	ret = "/" + strings.TrimPrefix(pth, "/")
   212  	return
   213  }
   214  
   215  func (s *MockService) getPathPatten(pth string) (ret string) {
   216  	regx := regexp.MustCompile(`({[^}]+?})`)
   217  	ret = regx.ReplaceAllString(pth, "(.+)")
   218  
   219  	ret = "^" + ret + "$"
   220  
   221  	return
   222  }
   223  
   224  func (s *MockService) Upload(ctx iris.Context, fh *multipart.FileHeader) (
   225  	name, content, mockConf, dataConf, pth string, err error, dataPath string) {
   226  
   227  	filename, err := fileUtils.GetUploadFileName(fh.Filename)
   228  	if err != nil {
   229  		logUtils.PrintTo(fmt.Sprintf("获取文件名失败,错误%s", err.Error()))
   230  		return
   231  	}
   232  
   233  	targetDir := filepath.Join("upload", dateUtils.DateStr(time.Now()))
   234  	absDir := filepath.Join(dir.GetCurrentAbPath(), targetDir)
   235  
   236  	err = dir.InsureDir(targetDir)
   237  	if err != nil {
   238  		logUtils.PrintTo(fmt.Sprintf("文件上传失败,错误%s", err.Error()))
   239  		return
   240  	}
   241  
   242  	pth = filepath.Join(absDir, filename)
   243  	_, err = ctx.SaveFormFile(fh, pth)
   244  	if err != nil {
   245  		logUtils.PrintTo(fmt.Sprintf("文件上传失败,错误%s", err.Error()))
   246  		return
   247  	}
   248  
   249  	content = fileUtils.ReadFile(pth)
   250  
   251  	vari.GlobalVars.Output = fileUtils.GetFileOrFolderDir(pth)
   252  	name, mockPath, dataPath, err := s.MockService.GenMockDef(pth)
   253  
   254  	if err == nil {
   255  		mockConf = fileUtils.ReadFile(mockPath)
   256  		dataConf = fileUtils.ReadFile(dataPath)
   257  	}
   258  
   259  	return
   260  }
   261  
   262  func (s *MockService) GetPreviewData(id int) (data domain.MockData, err error) {
   263  	po, err := s.MockRepo.Get(uint(id))
   264  
   265  	yaml.Unmarshal([]byte(po.MockContent), &data)
   266  	data.Id = id
   267  
   268  	return
   269  }
   270  
   271  func (s *MockService) GetPreviewResp(req domain.MockPreviewReq) (ret interface{}, err error) {
   272  	po, err := s.MockRepo.Get(uint(req.Id))
   273  
   274  	data := domain.MockData{}
   275  	err = yaml.Unmarshal([]byte(po.MockContent), &data)
   276  	if err != nil {
   277  		return
   278  	}
   279  
   280  	for pth, mp := range data.Paths {
   281  		if req.Url == pth {
   282  			endpoint := mp[req.Method][req.Code][req.Media]
   283  
   284  			key := fmt.Sprintf("%s-%s-%s-%s", pth, req.Method, req.Code, req.Media)
   285  			src, _ := s.MockRepo.GetSampleSrc(uint(req.Id), key)
   286  			if src.Value != "" && src.Value != "schema" {
   287  				str := endpoint.Samples[src.Value]
   288  				if src.Value == "json" {
   289  					ret = stringUtils.FormatJsonStr(str)
   290  				} else {
   291  					ret = str
   292  				}
   293  			} else {
   294  				ret, _ = s.GenDataForMockPreview(endpoint, po.DataContent)
   295  			}
   296  
   297  			return
   298  		}
   299  	}
   300  
   301  	return
   302  }
   303  
   304  func (s *MockService) StartMockService(id int) (err error) {
   305  	po, err := s.MockRepo.Get(uint(id))
   306  
   307  	mockDef := domain.MockData{}
   308  	err = yaml.Unmarshal([]byte(po.MockContent), &mockDef)
   309  	if err != nil {
   310  		return
   311  	}
   312  
   313  	dataDef := domain.DefData{}
   314  	err = yaml.Unmarshal([]byte(po.DataContent), &dataDef)
   315  	if err != nil {
   316  		return
   317  	}
   318  
   319  	apiPath := po.Path
   320  	MockServiceDataDefMap[apiPath] = po.DataContent
   321  
   322  	if MockServiceDataMap[apiPath] == nil {
   323  		MockServiceDataMap[apiPath] = domain.MockPathMap{}
   324  	}
   325  
   326  	for pth, mp := range mockDef.Paths {
   327  		pattern := s.getPathPatten(pth)
   328  		MockServiceDataMap[apiPath][pattern] = mp
   329  
   330  		if MockServiceDataRegxPathToOrigPath[apiPath] == nil {
   331  			MockServiceDataRegxPathToOrigPath[apiPath] = map[string]string{}
   332  		}
   333  		MockServiceDataRegxPathToOrigPath[apiPath][pattern] = pth
   334  	}
   335  
   336  	return
   337  }
   338  
   339  func (s *MockService) StopMockService(id int) (err error) {
   340  	po, err := s.MockRepo.Get(uint(id))
   341  
   342  	mockDef := domain.MockData{}
   343  	err = yaml.Unmarshal([]byte(po.MockContent), &mockDef)
   344  	if err != nil {
   345  		return
   346  	}
   347  
   348  	dataDef := domain.DefData{}
   349  	err = yaml.Unmarshal([]byte(po.DataContent), &dataDef)
   350  	if err != nil {
   351  		return
   352  	}
   353  
   354  	apiPath := po.Path
   355  
   356  	MockServiceDataMap[apiPath] = domain.MockPathMap{}
   357  
   358  	return
   359  }
   360  
   361  func (s *MockService) getServiceAndApiPath(uri string) (servicePath, apiPath string) {
   362  	arr := strings.Split(uri, "/")
   363  	if len(arr) < 2 {
   364  		return
   365  	}
   366  
   367  	servicePath = arr[0]
   368  	apiPath = strings.Join(arr[1:], "/")
   369  
   370  	apiPath = s.addPrefixIfNeeded(apiPath)
   371  
   372  	return
   373  }
   374  
   375  func (s *MockService) ListSampleSrc(mockId int) (ret map[string]string, err error) {
   376  	pos, err := s.MockRepo.ListSampleSrc(mockId)
   377  	if err != nil {
   378  		return
   379  	}
   380  
   381  	ret = map[string]string{}
   382  	for _, po := range pos {
   383  		ret[po.Key] = po.Value
   384  	}
   385  
   386  	return
   387  }
   388  
   389  func (s *MockService) ChangeSampleSrc(mockId int, req model.ZdMockSampleSrc) (err error) {
   390  	return s.MockRepo.ChangeSampleSrc(mockId, req)
   391  }