response.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. package rest
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "io"
  6. "log"
  7. "mime/multipart"
  8. "net/http"
  9. "net/textproto"
  10. mjson "git.ali33.ru/fcg-xvii/go-tools/json"
  11. )
  12. func NewResponse() *Response {
  13. return &Response{
  14. data: make(mjson.Map),
  15. files: make(map[string]io.ReadCloser),
  16. }
  17. }
  18. // Response реализует объект ответа
  19. type Response struct {
  20. data mjson.Map
  21. files map[string]io.ReadCloser
  22. err IErrorArgs
  23. code int
  24. }
  25. func (s *Response) IsError() bool {
  26. return s.err != nil
  27. }
  28. // KeySet устанавливает значение в словаре ответа по ключу
  29. func (s *Response) KeySet(key string, val any) {
  30. s.data[key] = val
  31. }
  32. // FileSet устанавливает файл в словаре файлов по ключу
  33. func (s *Response) FileSet(name string, file io.ReadCloser) {
  34. s.files[name] = file
  35. }
  36. // Close закрывает ресурсы ответа после завершения отдачи серверу
  37. func (s *Response) Close() {
  38. for _, file := range s.files {
  39. file.Close()
  40. }
  41. }
  42. // Send отправляет запрос серверу
  43. func (s *Response) Send(w http.ResponseWriter) IErrorArgs {
  44. log.Println("SEND...")
  45. defer s.Close()
  46. if s.IsError() {
  47. w.Header().Set("Content-Type", "application/json")
  48. w.WriteHeader(s.code)
  49. w.Write([]byte(s.err.Error()))
  50. return nil
  51. }
  52. // Если есть файлы, то используем multipart
  53. if len(s.files) > 0 {
  54. var b bytes.Buffer
  55. writer := multipart.NewWriter(&b)
  56. w.Header().Set("Content-Type", writer.FormDataContentType())
  57. // Добавляем JSON-данные как часть
  58. partHeader := make(textproto.MIMEHeader)
  59. partHeader.Set("Content-Type", "application/json")
  60. partHeader.Set("Content-Disposition", `form-data; name="data"`)
  61. dataPart, err := writer.CreatePart(partHeader)
  62. if err != nil {
  63. return NewErrorMessage("ErrResponsePartDataCreate", err.Error())
  64. }
  65. if err := json.NewEncoder(dataPart).Encode(s.data); err != nil {
  66. return NewErrorMessage("ErrResponseDataJsonEncode", err.Error())
  67. }
  68. // Добавляем файлы
  69. for filename, file := range s.files {
  70. part, err := writer.CreateFormFile("file", filename)
  71. if err != nil {
  72. return NewErrorMessage("ErrResponsePartFileCreate", err.Error())
  73. }
  74. if _, err := io.Copy(part, file); err != nil {
  75. return NewErrorMessage("ErrResponsePartFileCopy", err.Error())
  76. }
  77. }
  78. // Закрываем multipart writer
  79. if err := writer.Close(); err != nil {
  80. return NewErrorMessage("ErrResponsePartFileClose", err.Error())
  81. }
  82. // Отправляем multipart response
  83. w.Header().Set("Content-Type", writer.FormDataContentType())
  84. w.Write(b.Bytes())
  85. } else {
  86. // Если нет файлов, просто отправляем JSON
  87. w.Header().Set("Content-Type", "application/json")
  88. if err := json.NewEncoder(w).Encode(s.data); err != nil {
  89. return NewErrorMessage("ErrResponseDataJsonEncode", err.Error())
  90. }
  91. }
  92. return nil
  93. }
  94. // Успрешный ответ
  95. func ResponseSuccess(data mjson.Map, files map[string]io.ReadCloser) *Response {
  96. return &Response{
  97. code: 200,
  98. data: data,
  99. files: files,
  100. }
  101. }
  102. // Конструкторы ошибок /////////////////////////////////////////
  103. func ResponseErrorArgs(err IErrorArgs, code int) *Response {
  104. return &Response{
  105. code: code,
  106. err: err,
  107. }
  108. }
  109. func ResponseErrorMessage(err, message string, code int) *Response {
  110. return &Response{
  111. code: code,
  112. err: NewErrorMessage(err, message),
  113. }
  114. }
  115. ///////////////////////////////////////////
  116. func ResponseError(err IErrorArgs) *Response {
  117. return &Response{
  118. code: 500,
  119. err: err,
  120. }
  121. }
  122. func ResponseErrField(field, message string) *Response {
  123. return ResponseError(ErrorFiled(field, message))
  124. }
  125. func ResponseNotFound(path string) *Response {
  126. return &Response{
  127. code: 404,
  128. err: NewErrorMessage("ErrNotFound", path),
  129. }
  130. }