github.com/blend/go-sdk@v1.20220411.3/web/view_result.go (about) 1 /* 2 3 Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file. 5 6 */ 7 8 package web 9 10 import ( 11 "bytes" 12 "fmt" 13 "html/template" 14 "net" 15 "net/http" 16 17 "github.com/blend/go-sdk/env" 18 "github.com/blend/go-sdk/ex" 19 "github.com/blend/go-sdk/logger" 20 "github.com/blend/go-sdk/webutil" 21 ) 22 23 // ViewResult is a result that renders a view. 24 type ViewResult struct { 25 ViewName string 26 StatusCode int 27 ViewModel interface{} 28 Views *ViewCache 29 Template *template.Template 30 } 31 32 // Render renders the result to the given response writer. 33 func (vr *ViewResult) Render(ctx *Ctx) (err error) { 34 // you must set the template to be rendered. 35 if vr.Template == nil { 36 err = ex.New(ErrUnsetViewTemplate) 37 return 38 } 39 40 if ctx.Tracer != nil { 41 if typed, ok := ctx.Tracer.(ViewTracer); ok { 42 tf := typed.StartView(ctx, vr) 43 defer func() { 44 tf.FinishView(ctx, vr, err) 45 }() 46 } 47 } 48 49 ctx.Response.Header().Set(webutil.HeaderContentType, webutil.ContentTypeHTML) 50 51 // use a pooled buffer if possible 52 var buffer *bytes.Buffer 53 if vr.Views != nil && vr.Views.BufferPool != nil { 54 buffer = vr.Views.BufferPool.Get() 55 defer vr.Views.BufferPool.Put(buffer) 56 } else { 57 buffer = new(bytes.Buffer) 58 } 59 60 err = vr.Template.Execute(buffer, &ViewModel{ 61 Env: env.Env(), 62 Ctx: ctx, 63 Status: ViewStatus{ 64 Text: http.StatusText(vr.StatusCode), 65 Code: vr.StatusCode, 66 }, 67 ViewModel: vr.ViewModel, 68 }) 69 if err != nil { 70 err = ex.New(err) 71 if ctx.App != nil { 72 logger.MaybeErrorContext(ctx.Context(), ctx.App.Log, err) 73 } 74 ctx.Response.WriteHeader(http.StatusInternalServerError) 75 _, _ = ctx.Response.Write([]byte(fmt.Sprintf("%+v\n", err))) 76 return 77 } 78 79 ctx.Response.WriteHeader(vr.StatusCode) 80 _, err = ctx.Response.Write(buffer.Bytes()) 81 if err != nil { 82 if typed, ok := err.(*net.OpError); ok { 83 err = ex.New(webutil.ErrNetWrite, ex.OptInner(typed)) 84 return 85 } 86 err = ex.New(err) 87 return 88 } 89 return 90 }