[Unit] Description=Description After=network.target Requires=mysqld.service [Service] Type=simple User=nginx Group=nginx WorkingDirectory=/usr/share/project_name StandardOutput=journal StandardError=journal ExecStart=/usr/share/project_name/project_name Restart=always [Install] WantedBy=multi-user.target
log.Println("Server is preparing to start")
type MapRoutes map[string]Controller type Application struct { Doc AbstractPage Config Config DB SQL routes MapRoutes }
// Routes URL' func (app *Application) Routes(r MapRoutes) { app.routes = r } func (app *Application) Run() { r := mux.NewRouter() r.StrictSlash(true) for url, ctrl := range app.routes { r.HandleFunc(url, obs(ctrl)) } http.Handle("/", r) listen := fmt.Sprintf("%s:%d", app.Config.Net.Listen_host, app.Config.Net.Listen_port) log.Println("Server is started on", listen) if err := http.ListenAndServe(listen, nil); err != nil { log.Println(err) } }
var appInstance *Application // GetApplication Application func GetApplication() *Application { if appInstance == nil { appInstance = new(Application) // Init code appInstance.Config = loadConfig("config.ini") appInstance.Doc = make(AbstractPage) appInstance.routes = make(MapRoutes) // ... } return appInstance }
package main import ( "interfaces/app" "interfaces/handlers" "log" ) func init() { log.SetFlags(log.LstdFlags | log.Lshortfile) } func main() { log.Println("Server is preparing to start") Application := app.GetApplication() if Application.Config.Site.Disabled { log.Println("Site is disabled") Application.Routes(app.MapRoutes{"/": handlers.HandleDisabled{}}) } else { Application.Routes(app.MapRoutes{ "/": handlers.HandleHome{}, "/v1/ajax/": handlers.HandleAjax{}, // "/{url:.*}": handlers.Handle404{}, }) } Application.Run() log.Println("Exit") }
for url, ctrl := range app.routes { r.HandleFunc(url, obs(ctrl)) }
func ProductHandler(ctx *Context) { // ... }
type Controller interface { GET(app *ContextApplication) POST(app *ContextApplication) PUT(app *ContextApplication) DELETE(app *ContextApplication) PATCH(app *ContextApplication) OPTIONS(app *ContextApplication) HEAD(app *ContextApplication) TRACE(app *ContextApplication) CONNECT(app *ContextApplication) } // obs func obs(handler Controller) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, req *http.Request) { ctx := context.New(w, req) app := GetApplication() doc := app.Doc.Clone("") doc["Ctx"] = ctx doc["User"] = ctx.User() contextApp := &ContextApplication{ctx, doc, app.Config, app.DB} switch ctx.Input.Method() { case "GET": handler.GET(contextApp); case "POST": handler.POST(contextApp); case "PUT": handler.PUT(contextApp); case "DELETE": handler.DELETE(contextApp); case "PATCH": handler.PATCH(contextApp); case "OPTIONS": handler.OPTIONS(contextApp); case "HEAD": handler.HEAD(contextApp); case "TRACE": handler.TRACE(contextApp); case "CONNECT": handler.CONNECT(contextApp); default: http.Error(ctx.Response(), "Method not allowed", http.StatusMethodNotAllowed) } } } // HTTPController , // . type HTTPController struct {} func (h HTTPController) GET(app *ContextApplication) { http.Error(app.Ctx.Response(), "Method not allowed", http.StatusMethodNotAllowed) } func (h HTTPController) POST(app *ContextApplication) { http.Error(app.Ctx.Response(), "Method not allowed", http.StatusMethodNotAllowed) } func (h HTTPController) PUT(app *ContextApplication) { http.Error(app.Ctx.Response(), "Method not allowed", http.StatusMethodNotAllowed) } func (h HTTPController) DELETE(app *ContextApplication) { http.Error(app.Ctx.Response(), "Method not allowed", http.StatusMethodNotAllowed) } func (h HTTPController) PATCH(app *ContextApplication) { http.Error(app.Ctx.Response(), "Method not allowed", http.StatusMethodNotAllowed) } func (h HTTPController) OPTIONS(app *ContextApplication) { http.Error(app.Ctx.Response(), "Method not allowed", http.StatusMethodNotAllowed) } func (h HTTPController) HEAD(app *ContextApplication) { http.Error(app.Ctx.Response(), "Method not allowed", http.StatusMethodNotAllowed) } func (h HTTPController) TRACE(app *ContextApplication) { http.Error(app.Ctx.Response(), "Method not allowed", http.StatusMethodNotAllowed) } func (h HTTPController) CONNECT(app *ContextApplication) { http.Error(app.Ctx.Response(), "Method not allowed", http.StatusMethodNotAllowed) }
type ContextApplication struct { Ctx *context.Context Doc AbstractPage Config Config DB SQL }
import ( "interfaces/app" ) type HandleCustom struct { app.HTTPController } func (h HandleCustom) GET(app *app.ContextApplication) { app.Ctx.SendHTML("html data here") } func (h HandleCustom) POST(app *app.ContextApplication) { // and so on... }
func (c *Context) NotFound() // NotFound sends page with 404 http code from template tpls/404.tpl func (c *Context) Redirect(url string) // Redirect sends http redirect with 301 code func (c *Context) Redirect303(url string) // Redirect303 sends http redirect with 303 code func (c *Context) SendJSON(data string) int // SendJSON sends json-content (data) func (c *Context) SendXML(data string) // SendXML sends xml-content (data) func (c *Context) GetCookie(key string) string // GetCookie return cookie from request by a given key. func (c *Context) SetCookie(name string, value string, others ...interface{}) // SetCookie set cookie for response. func (c *Context) CheckXsrfToken() bool // CheckXsrfToken token func (c *Context) User() User // User func (c *Context) Session(name string) (*Session, error) // Session func (s *Session) Clear() // Clear // ..
// loadTemplate load template from tpls/%s.tpl func loadTemplate(Name string) *html.Template { funcMap := html.FuncMap{ "html": func(val string) html.HTML { return html.HTML(val) }, "typo": func(val string) string { return typo.Typo(val) }, "mod": func(args ...interface{}) interface{} { if len(args) == 0 { return "" } name := args[0].(string) ctx := new(context.Context) if len(args) > 1 { ctx = args[1].(*context.Context) } modules := reflect.ValueOf(modules.Get()) mod := modules.MethodByName(name) if (mod == reflect.Value{}) { return "" } inputs := make([]reflect.Value, 0) inputs = append(inputs, reflect.ValueOf(ctx)) ret := mod.Call(inputs) return ret[0].Interface() }, } return html.Must(html.New("*").Funcs(funcMap).Delims("{{%", "%}}").ParseFiles("tpls/" + Name + ".tpl")) }
<div>{{% .htmlString | html %}}</div>
<h1>{{% .title | typo %}}</h1>
<div>{{% mod "InformMenu" %}}</div>
type AbstractPage map[string]interface{}
func (h HandleCustom) GET(app *app.ContextApplication) { doc := app.Doc.Clone("custom") // AbstractPage, custom.tpl doc["V1"] = "V1" doc["V2"] = 555 result := doc.Compile() app.Ctx.SendHTML(result) }
{{%define "*"%}} <ul> <li>{{% .V1 %}}</li> <li>{{% .V2 %}}</li> </ul> {{%end%}}
// Clone AbstractPage c func (page AbstractPage) Clone(tplName string) AbstractPage { doc := make(AbstractPage) for k, v := range page { doc[k] = v } doc["__tpl"] = tplName return doc }
// Compile return page formatted with template from tpls/%d.tpl func (page AbstractPage) Compile() string { var data bytes.Buffer for k, v := range page { switch val := v.(type) { case AbstractPage: { page[k] = html.HTML(val.Compile()) } case func()string: { page[k] = val() } } } // (ctx doc["Ctx"]) getTpl(page["__tpl"].(string)).Execute(&data, page) return data.String() }
Source: https://habr.com/ru/post/260539/
All Articles