Core

/app/controller/act.go (3.4 KB)

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package controller

import (
"fmt"
"time"

"github.com/pkg/errors"
"github.com/valyala/fasthttp"

"{{{ .Package }}}/app"
"{{{ .Package }}}/app/controller/cutil"
"{{{ .Package }}}/app/lib/telemetry"{{{ if .HasAccount }}}
"{{{ .Package }}}/app/lib/user"{{{ end }}}{{{ if.HasModule "marketing" }}}
"{{{ .Package }}}/app/site"{{{ end }}}
"{{{ .Package }}}/app/util"
)

func Act(key string, rc *fasthttp.RequestCtx, f func(as *app.State, ps *cutil.PageState) (string, error)) {
as := _currentAppState
ps := cutil.LoadPageState(as, rc, key, _currentAppRootLogger){{{ if .HasAccount }}}
if allowed, reason := user.Check(string(ps.URI.Path()), ps.Accounts); !allowed {
f = Unauthorized(rc, reason, ps.Accounts)
}{{{ end }}}
if err := initAppRequest(as, ps); err != nil {
ps.Logger.Warnf("%+v", err)
}
actComplete(key, as, ps, rc, f)
}
{{{ if.HasModule "marketing" }}}
func ActSite(key string, rc *fasthttp.RequestCtx, f func(as *app.State, ps *cutil.PageState) (string, error)) {
as := _currentSiteState
ps := cutil.LoadPageState(as, rc, key, _currentSiteRootLogger)
ps.Menu = site.Menu(ps.Context, as, ps.Profile{{{ if .HasAccount }}}, ps.Accounts{{{ end }}}, ps.Logger){{{ if .HasAccount }}}
if allowed, reason := user.Check(string(ps.URI.Path()), ps.Accounts); !allowed {
f = Unauthorized(rc, reason, ps.Accounts)
}{{{ end }}}
if err := initSiteRequest(as, ps); err != nil {
ps.Logger.Warnf("%+v", err)
}
actComplete(key, as, ps, rc, f)
}
{{{ end }}}
func actComplete(key string, as *app.State, ps *cutil.PageState, rc *fasthttp.RequestCtx, f func(as *app.State, ps *cutil.PageState) (string, error)) {
err := ps.Clean(rc, as)
if err != nil {
ps.Logger.Warnf("error while cleaning request, somehow: %+v", err)
}
status := fasthttp.StatusOK
cutil.WriteCORS(rc)
var redir string
logger := ps.Logger
ctx := ps.Context
if !telemetry.SkipControllerMetrics {
var span *telemetry.Span
ctx, span, logger = telemetry.StartSpan(ps.Context, "controller."+key, ps.Logger)
defer span.Complete()
}
logger = logger.With("path", string(rc.URI().Path()), "method", ps.Method, "status", status)
ps.Context = ctx

if ps.ForceRedirect == "" || ps.ForceRedirect == string(rc.URI().Path()) {
redir, err = safeRun(f, as, ps)
if err != nil {
redir, err = handleError(key, as, ps, rc, err)
if err != nil {
ps.Logger.Warnf("unable to handle error: %+v", err)
}
}
} else {
redir = ps.ForceRedirect
}
if redir != "" {
rc.Response.Header.Set("Location", redir)
status = fasthttp.StatusFound
rc.SetStatusCode(status)
}
elapsedMillis := float64((util.TimeCurrentNanos()-ps.Started.UnixNano())/int64(time.Microsecond)) / float64(1000)
defer ps.Close()
rc.Response.Header.Set("Server-Timing", fmt.Sprintf("server:dur=%.3f", elapsedMillis))
logger = logger.With("elapsed", elapsedMillis)
logger.Debugf("processed request in [%.3fms] (render: %.3fms)", elapsedMillis, ps.RenderElapsed)
}

func safeRun(f func(as *app.State, ps *cutil.PageState) (string, error), as *app.State, ps *cutil.PageState) (s string, e error) {
defer func() {
if rec := recover(); rec != nil {
if recoverErr, ok := rec.(error); ok {
e = errors.Wrap(recoverErr, "panic")
} else {
e = errors.Errorf("controller encountered panic recovery of type [%T]: %s", rec, fmt.Sprint(rec))
}
}
}()
s, e = f(as, ps)
return
}