github.com/ngocphuongnb/tetua@v0.0.7-alpha/packages/fiberserver/context.go (about)

     1  package fiberserver
     2  
     3  import (
     4  	"bufio"
     5  	"context"
     6  	"fmt"
     7  	"mime/multipart"
     8  	"runtime"
     9  	"strconv"
    10  
    11  	"github.com/gofiber/fiber/v2"
    12  	fiberUtils "github.com/gofiber/utils"
    13  	"github.com/ngocphuongnb/tetua/app/config"
    14  	"github.com/ngocphuongnb/tetua/app/entities"
    15  	"github.com/ngocphuongnb/tetua/app/logger"
    16  	"github.com/ngocphuongnb/tetua/app/server"
    17  	"github.com/ngocphuongnb/tetua/app/utils"
    18  	"github.com/valyala/fasthttp"
    19  )
    20  
    21  type Context struct {
    22  	*fiber.Ctx
    23  	MetaData *entities.Meta
    24  }
    25  
    26  type Response struct {
    27  	*fasthttp.Response
    28  }
    29  
    30  func (c *Context) RequestID() string {
    31  	return fmt.Sprintf("%v", c.Locals("request_id"))
    32  }
    33  
    34  func (c *Context) Hostname() string {
    35  	return c.Ctx.Hostname()
    36  }
    37  
    38  func (c *Context) BaseUrl() string {
    39  	return c.Ctx.Protocol() + "://" + c.Ctx.Hostname()
    40  }
    41  
    42  func (c *Context) RouteName() string {
    43  	return c.Ctx.Route().Name
    44  }
    45  
    46  func (c *Context) Context() context.Context {
    47  	return context.WithValue(context.Background(), "request_id", c.RequestID())
    48  }
    49  
    50  func (c *Context) File(name string) (*multipart.FileHeader, error) {
    51  	return c.Ctx.FormFile(name)
    52  }
    53  
    54  func (c *Context) Logger() logger.Logger {
    55  	return logger.Get().WithContext(logger.Context{"request_id": c.RequestID()})
    56  }
    57  
    58  func (c *Context) Messages(ms ...*entities.Messages) *entities.Messages {
    59  	if len(ms) > 0 {
    60  		c.MetaData.Messages = ms[0]
    61  		return ms[0]
    62  	}
    63  	return c.MetaData.Messages
    64  }
    65  
    66  func (c *Context) Meta(metas ...*entities.Meta) *entities.Meta {
    67  	if len(metas) > 0 {
    68  		c.MetaData = metas[0]
    69  		c.MetaData.User = c.User()
    70  
    71  		if c.MetaData.Messages == nil {
    72  			c.MetaData.Messages = &entities.Messages{}
    73  		}
    74  		return c.MetaData
    75  	}
    76  
    77  	if c.MetaData == nil {
    78  		appName := config.Setting("app_name")
    79  		c.MetaData = &entities.Meta{
    80  			Title:       appName,
    81  			Description: appName,
    82  			User:        c.User(),
    83  			Messages:    &entities.Messages{},
    84  		}
    85  	}
    86  
    87  	return c.MetaData
    88  }
    89  
    90  func (c *Context) Render(fn func(meta *entities.Meta, wr *bufio.Writer)) error {
    91  	if c.Meta().Canonical == "" {
    92  		c.Meta().Canonical = utils.Url(c.Path())
    93  	}
    94  
    95  	if c.Meta().Type == "" {
    96  		c.Meta().Type = "website"
    97  	}
    98  
    99  	c.Response().Header("content-type", "text/html; charset=utf-8")
   100  	requestID := fiberUtils.ImmutableString(c.RequestID())
   101  	c.Ctx.Response().SetBodyStreamWriter(func(w *bufio.Writer) {
   102  		defer func(requestID string) {
   103  			if r := recover(); r != nil {
   104  				err, ok := r.(error)
   105  				if !ok {
   106  					err = fmt.Errorf("%v", r)
   107  				}
   108  				stack := make([]byte, 4<<10)
   109  				length := runtime.Stack(stack, true)
   110  				msg := fmt.Sprintf("%v %s\n", err, stack[:length])
   111  				logger.Get().WithContext(logger.Context{"request_id": requestID, "recovered": true}).Error(msg)
   112  				if _, err := w.WriteString("Something went wrong"); err != nil {
   113  					fmt.Println(err)
   114  				}
   115  			}
   116  		}(requestID)
   117  		fn(c.Meta(), w)
   118  		w.Flush()
   119  	})
   120  
   121  	return nil
   122  }
   123  
   124  func (c *Context) User() *entities.User {
   125  	if user, ok := c.Locals("user").(*entities.User); ok {
   126  		return user
   127  	}
   128  
   129  	return nil
   130  }
   131  
   132  func (c *Context) Post(posts ...*entities.Post) *entities.Post {
   133  	if len(posts) > 0 {
   134  		c.Locals("post", posts[0])
   135  	}
   136  
   137  	if post, ok := c.Locals("post").(*entities.Post); ok {
   138  		return post
   139  	}
   140  
   141  	return nil
   142  }
   143  
   144  func (c *Context) Json(v interface{}) error {
   145  	return c.Ctx.JSON(v)
   146  }
   147  
   148  func (c *Context) Cookies(key string, defaultValue ...string) string {
   149  	return c.Ctx.Cookies(key, defaultValue...)
   150  }
   151  
   152  func (c *Context) Cookie(v *server.Cookie) {
   153  	cookie := fiber.Cookie{
   154  		Name:     v.Name,
   155  		Value:    v.Value,
   156  		Path:     v.Path,
   157  		Domain:   v.Domain,
   158  		Expires:  v.Expires,
   159  		Secure:   v.Secure,
   160  		HTTPOnly: v.HTTPOnly,
   161  		SameSite: v.SameSite,
   162  	}
   163  	c.Ctx.Cookie(&cookie)
   164  }
   165  
   166  func (c *Context) Status(v int) server.Context {
   167  	c.Ctx.Status(v)
   168  	return c
   169  }
   170  func (c *Context) Next() error {
   171  	return c.Ctx.Next()
   172  }
   173  
   174  func (c *Context) Locals(key string, value ...interface{}) (val interface{}) {
   175  	return c.Ctx.Locals(key, value...)
   176  }
   177  
   178  func (c *Context) Param(key string) string {
   179  	return c.Ctx.Params(key)
   180  }
   181  
   182  func (c *Context) ParamInt(key string, values ...int) int {
   183  	if p, err := strconv.Atoi(c.Ctx.Params(key)); err == nil {
   184  		return p
   185  	}
   186  
   187  	if len(values) > 0 {
   188  		return values[0]
   189  	}
   190  
   191  	return 0
   192  }
   193  
   194  func (c *Context) WithError(msg string, err error) {
   195  	c.Messages().AppendError(msg)
   196  	c.Logger().Error(msg, err)
   197  }
   198  
   199  func (c *Context) Query(key string, values ...string) string {
   200  	if value := c.Ctx.Query(key); value != "" {
   201  		return value
   202  	}
   203  
   204  	if len(values) > 0 {
   205  		return values[0]
   206  	}
   207  
   208  	return ""
   209  }
   210  
   211  func (c *Context) QueryInt(key string, values ...int) int {
   212  	if p, err := strconv.Atoi(c.Ctx.Query(key)); err == nil {
   213  		return p
   214  	}
   215  
   216  	if len(values) > 0 {
   217  		return values[0]
   218  	}
   219  
   220  	return 0
   221  }
   222  
   223  func (c *Context) Response() server.Response {
   224  	return &Response{c.Ctx.Response()}
   225  }
   226  
   227  func (c *Context) Method() string {
   228  	return c.Ctx.Method()
   229  }
   230  
   231  func (c *Context) Send(data []byte) error {
   232  	return c.Ctx.Send(data)
   233  }
   234  
   235  func (c *Context) SendString(data string) error {
   236  	return c.Ctx.SendString(data)
   237  }
   238  
   239  func (c *Context) OriginalURL() string {
   240  	return c.Ctx.OriginalURL()
   241  }
   242  
   243  func (c *Context) Path() string {
   244  	return c.Ctx.Path()
   245  }
   246  
   247  func (c *Context) Redirect(path string) error {
   248  	return c.Ctx.Redirect(path)
   249  }
   250  
   251  func (c *Context) RedirectToRoute(name string, params ...map[string]interface{}) error {
   252  	if len(params) > 0 {
   253  		return c.Ctx.RedirectToRoute(name, params[0])
   254  	}
   255  	return c.Ctx.RedirectToRoute(name, fiber.Map{})
   256  }
   257  
   258  func (c *Context) Header(key string, vals ...string) string {
   259  
   260  	if len(vals) > 0 {
   261  		c.Ctx.Set(key, vals[0])
   262  		return vals[0]
   263  	}
   264  
   265  	return c.Ctx.Get(key)
   266  }
   267  
   268  func (c *Context) BodyParser(v interface{}) error {
   269  	return c.Ctx.BodyParser(v)
   270  }
   271  
   272  func (r *Response) Header(key string, vals ...string) string {
   273  	if len(vals) > 0 {
   274  		r.Response.Header.Add(key, vals[0])
   275  		return vals[0]
   276  	}
   277  
   278  	return string(r.Response.Header.Peek(key))
   279  }