-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor context to add a BaseContext and reduce private context struct size #16455
Conversation
d664d4f
to
b9f4e03
Compare
4f1bed8
to
bd53ab5
Compare
Codecov Report
@@ Coverage Diff @@
## main #16455 +/- ##
=======================================
Coverage ? 45.36%
=======================================
Files ? 816
Lines ? 90718
Branches ? 0
=======================================
Hits ? 41151
Misses ? 42998
Partials ? 6569
Continue to review full report at Codecov.
|
bd53ab5
to
7fc808d
Compare
08338d8
to
90d34b1
Compare
90d34b1
to
c0c243d
Compare
91aa105
to
e5c98f8
Compare
I think I understand the aim but I'm not certain this is getting us going in the right direction. My understanding is that you're trying to reduce the number of things that our context does and just simplify what's there because it's kinda fragile, opaque and smells. I'm not sure that this is actually getting us much out of the hole of having to pass around this special grab bag of things. I think in the end with the way go is built we're going to end up having to pass in a go context into most of our functions - and we're going to have to pass in the context as a grab bag. However our current context is bad for two reasons:
Go gets around this dependency problem by using the We could do that by for example instead of using So my feeling therefore is that we should be trying to get ourselves into a state whereby we pass around gocontext.Contexts and use functions on those to grab things like a package
type Renderer struct { // Maybe IRenderer (not sure - depends on which package)
HTML(status int, name base.TplName)
RenderWithErr(msg string, tpl base.TplName, form interface{})
NotFound(title string, err error)
ServerError(title string, err error)
NotFoundOrServerError(title string, errck func(error) bool, err error)
Header() http.Header
HandleText(status int, title string)
ServeContent(name string, r io.ReadSeeker, params ...interface{})
PlainText(status int, bs []byte)
ServeFile(file string, names ...string)
ServeStream(rd io.Reader, name string)
Error(status int, contents ...string)
JSON(status int, content interface{})
Redirect(location string, status ...int)
} (Perhaps not all of these - clearly some of these are bit more specialised and could be another thing like a instead.) I have a number of ideas for how this could go but none of them is completely fleshed out. For example, to get a Renderer from a go context the function: This could then eventually lead to context becoming: type BaseContext struct {
gocontext.Context
values map[interface{}]interface{}
}
func (b *BaseContext) Value(key interface{}) interface{} {
if value, ok := b.values[key]; ok {
return value
}
return b.Context.Value(key)
}
func (b *BaseContext) SetValue(key, value interface{}) interface{} {
if old, ok := b.values[key]; ok {
b.values[key] = value
return old
}
b.values[key] = value
return nil
}
var _ (gocontext.Context) = &BaseContext{gocontext.Background(), map[interface{}]interface{}{}}
type SettableContext interface {
gocontext.Context
SetValue(key, value interface{}) interface{}
}
func WithValue(ctx gocontext.Context, key, value interface{}) (ret gocontext.Context, cancel gocontext.CancelFunc) {
if base, ok := ctx.(SettableContext); ok {
base.SetValue(key, value)
ret = base
return
}
return gocontext.WithValue(ctx, key, value)
} So things would then get stored on the An alternative is potentially something like:
so functionality could be chained on to the context but then you're in the realm of having to more clearly handle the chain of context creations although this technique allows you to assert types at compile time. (The above interfaces could eventually be asserted at package level and generators could do the rest.) I guess the question is what is driving and depending on this particular PR? Is there something else depending on this particular way of doing things? If you've got some other PRs or ideas that are waiting on this particular implementation then that's more of a reason to merge as is because I do agree it's better than what we've currently got - I'm just not sure it's the best thing to do. |
Call it And I don't think everything should be interface, sometimes it will make things complicated. I think it should be changed as interface only when it's necessary. Yes, I plan to refactor |
ctx.Resp.WriteHeader(status) | ||
if err := json.NewEncoder(ctx.Resp).Encode(content); err != nil { | ||
log.Error("Render JSON failed: %v", err) | ||
ctx.Status(http.StatusInternalServerError) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not think we have a chance to call ctx.Status
again here. Because there is a ctx.Resp.WriteHeader(status)
above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's really a problem except we encode the content before write header.
ctx.Resp.Header().Set("Content-Type", "text/plain;charset=utf-8") | ||
if _, err := ctx.Resp.Write(bs); err != nil { | ||
log.Error("Render PlainText failed: %v", err) | ||
ctx.Status(http.StatusInternalServerError) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above
e5c98f8
to
207d583
Compare
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs during the next 2 months. Thank you for your contributions. |
Closed as so many files conflicted. |
BaseContext will only contain resp, req and data which could be a general context for private request, http and some others.