package ss import ( "io" "strings" "encoding/json" "net/http" "net/url" "fmt" "surdeus.su/core/ss/contents" "surdeus.su/core/ss/urlenc" ) type Context struct { R *Request RelUrl *url.URL W ResponseWriter // Custom data to store stuff. Data any scanErr error dec Decoder } func (c *Context) Method() ReqMethod { return ReqMethod(c.R.Method) } // Set the reply status code. func (c *Context) SetStatus(status Status) { c.W.WriteHeader(int(status)) } // Set the reply content type. func (c *Context) SetContentType(typ contents.Type, opts ...contents.Option) { ret := string(typ) for _, opt := range opts { kv := opt.KeyValue() ret += ";"+kv[0]+"="+kv[1] } c.SetHeader("Content-Type", ret) } // Get the request content type. func (c *Context) ContentType() contents.Type { ret, ok := c.Header("Content-Type") if !ok { return "" } if len(ret) < 1 { return "" } splits := strings.SplitN(ret[0], ";", 2) if len(splits) < 0 { return "" } return contents.Type(splits[0]) } func (c *Context) SetHeader(k, v string) { c.W.Header().Set(k, v) } func (c *Context) Header(name string) ([]string, bool) { ret, ok := c.R.Header[name] return ret, ok } // Closes the requests body after finishes scaning. func (c *Context) Close() { c.R.Body.Close() } // Scan the incoming value from body depending // on the content type of the request into the // structure or map[string] any. func (c *Context) Scan(v any) bool { if c.dec == nil { typ := c.ContentType() switch typ { case contents.Json: c.dec = json.NewDecoder(c.R.Body) case contents.UrlEncoded: body, _ := io.ReadAll(c.R.Body) err := urlenc.Unmarshal(body, v) if err != nil { c.scanErr = err } return false default: c.scanErr = UnknownContentTypeErr return false } } err := c.dec.Decode(v) if err != nil { if err != io.EOF { c.scanErr = err } return false } return true } func (c *Context) ScanErr() error { return c.scanErr } func (c *Context) AbsPath() string { return c.R.URL.Path } func (c *Context) PathPrefix() string { pth := c.AbsPath() rpth := c.Path() return pth[:len(pth)-len(rpth)] } func (c *Context) Path() string { return c.RelUrl.Path } func (c *Context) NotFound() { http.NotFound(c.W, c.R) } func (c *Context) InternalServerError(err error) { c.W.WriteHeader(http.StatusInternalServerError) if err != nil { c.Printf("500 Internal Server Error: %q", err) } else { } } func (c *Context) Print(v ...any) (int, error) { return fmt.Print(v...) } func (c *Context) Printf(format string, v ...any) (int, error) { return fmt.Fprintf(c.W, format, v...) } func (c *Context) Query() url.Values { return c.R.URL.Query() } func (c *Context) Redirect(u string, status Status) { pth := c.AbsPath() if len(pth) > 0 && pth[len(pth)-1] != '/' { pth += "/" } c.R.URL.Path = pth http.Redirect(c.W, c.R, u, int(status)) }