├── .gitignore ├── README.md ├── cfg.example.json ├── control ├── g ├── config.go └── const.go ├── handler └── home_hander.go ├── http ├── cookie │ └── cookie.go ├── errors │ └── errors.go ├── helper │ └── helper.go ├── http.go ├── middleware │ ├── logger.go │ └── recovery.go ├── param │ └── param.go ├── render │ └── render.go └── routes.go ├── init ├── main.go ├── model └── example.go ├── store └── mysql.go └── views ├── common └── error.html └── home └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | cfg.json 2 | Toruk 3 | /var/* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Toruk 2 | ### go web 开发脚手架 3 | 4 | 主要由下面几个第三方库集成,简单、灵活,可以快速开发web项目 5 | 6 | * 路由:github.com/gorilla/mux 7 | * 渲染模板:github.com/unrolled/render 8 | * Cookie封装:github.com/gorilla/securecookie 9 | * 中间件:github.com/codegangsta/negroni 10 | * 上下文传输:github.com/gorilla/context 11 | 12 | ### 文件结构 13 | 图片描述 14 | 15 | 16 | ### 使用方法 17 | 通过修改http/ruote.go 将数据传到对应的handler中,然后在通过render将数据返回回去。 18 | ruote.go 19 | 20 | func configConfRoutes(r *mux.Router) { 21 | r.HandleFunc("/home", handler.HomeIndex).Methods("GET") 22 | } 23 | 24 | handler.go 25 | 26 | func HomeIndex(w http.ResponseWriter, r *http.Request) { 27 | render.HTML(r, w, "home/index") 28 | } 29 | 30 | ### 初始化 31 | 32 | # set $GOPATH and $GOROOT 33 | # 比如你的项目名称叫做 awosome 34 | cd $GOPATH/src 35 | git clone https://github.com/710leo/Toruk.git 36 | mv Toruk awosome 37 | cd awosome 38 | ./init awosome 39 | go get ./... 40 | 41 | ### 编译&运行 42 | ./control build 43 | ./control start 44 | 45 | ### 答疑 46 | 交流QQ群:173502733 47 | -------------------------------------------------------------------------------- /cfg.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug": false, 3 | "http": { 4 | "listen": "0.0.0.0:4200", 5 | "secret": "secret" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | WORKSPACE=$(cd $(dirname $0)/; pwd) 4 | cd $WORKSPACE 5 | 6 | mkdir -p var 7 | 8 | module=toruk 9 | app=toruk 10 | conf=cfg.json 11 | pidfile=var/app.pid 12 | logfile=var/app.log 13 | 14 | function check_pid() { 15 | if [ -f $pidfile ];then 16 | pid=`cat $pidfile` 17 | if [ -n $pid ]; then 18 | running=`ps -p $pid|grep -v "PID TTY" |wc -l` 19 | return $running 20 | fi 21 | fi 22 | return 0 23 | } 24 | 25 | function start() { 26 | check_pid 27 | running=$? 28 | if [ $running -gt 0 ];then 29 | echo -n "$app now is running already, pid=" 30 | cat $pidfile 31 | return 1 32 | fi 33 | 34 | nohup ./$app -c $conf &> $logfile & 35 | echo $! > $pidfile 36 | echo "$app started..., pid=$!" 37 | } 38 | 39 | function stop() { 40 | pid=`cat $pidfile` 41 | kill $pid 42 | echo "$app stoped..." 43 | } 44 | 45 | function restart() { 46 | stop 47 | sleep 1 48 | start 49 | } 50 | 51 | function status() { 52 | check_pid 53 | running=$? 54 | if [ $running -gt 0 ];then 55 | echo "started" 56 | else 57 | echo "stoped" 58 | fi 59 | } 60 | 61 | function tailf() { 62 | tail -f $logfile 63 | } 64 | 65 | function build() { 66 | go build 67 | if [ $? -ne 0 ]; then 68 | exit $? 69 | fi 70 | mv $module $app 71 | ./$app -v 72 | } 73 | 74 | function help() { 75 | echo "$0 pid|reload|build|pack|packbin|start|stop|restart|status|tail" 76 | } 77 | 78 | function pid() { 79 | cat $pidfile 80 | } 81 | 82 | function reload() { 83 | build 84 | restart 85 | tailf 86 | } 87 | 88 | if [ "$1" == "" ]; then 89 | help 90 | elif [ "$1" == "stop" ];then 91 | stop 92 | elif [ "$1" == "start" ];then 93 | start 94 | elif [ "$1" == "restart" ];then 95 | restart 96 | elif [ "$1" == "status" ];then 97 | status 98 | elif [ "$1" == "tail" ];then 99 | tailf 100 | elif [ "$1" == "build" ];then 101 | build 102 | elif [ "$1" == "pid" ];then 103 | pid 104 | elif [ "$1" == "reload" ];then 105 | reload 106 | else 107 | help 108 | fi 109 | -------------------------------------------------------------------------------- /g/config.go: -------------------------------------------------------------------------------- 1 | package g 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | "sync" 8 | 9 | "github.com/toolkits/file" 10 | ) 11 | 12 | type HttpConfig struct { 13 | Listen string `json:"listen"` 14 | Secret string `json:"secret"` 15 | } 16 | 17 | type GlobalConfig struct { 18 | Debug bool `json:"debug"` 19 | Http *HttpConfig `json:"http"` 20 | } 21 | 22 | var ( 23 | ConfigFile string 24 | config *GlobalConfig 25 | configLock = new(sync.RWMutex) 26 | ) 27 | 28 | func Config() *GlobalConfig { 29 | configLock.RLock() 30 | defer configLock.RUnlock() 31 | return config 32 | } 33 | 34 | func Parse(cfg string) error { 35 | if cfg == "" { 36 | return fmt.Errorf("use -c to specify configuration file") 37 | } 38 | 39 | if !file.IsExist(cfg) { 40 | return fmt.Errorf("configuration file %s is nonexistent", cfg) 41 | } 42 | 43 | ConfigFile = cfg 44 | 45 | configContent, err := file.ToTrimString(cfg) 46 | if err != nil { 47 | return fmt.Errorf("read configuration file %s fail %s", cfg, err.Error()) 48 | } 49 | 50 | var c GlobalConfig 51 | err = json.Unmarshal([]byte(configContent), &c) 52 | if err != nil { 53 | return fmt.Errorf("parse configuration file %s fail %s", cfg, err.Error()) 54 | } 55 | 56 | configLock.Lock() 57 | defer configLock.Unlock() 58 | config = &c 59 | 60 | log.Println("load configuration file", cfg, "successfully") 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /g/const.go: -------------------------------------------------------------------------------- 1 | package g 2 | 3 | const ( 4 | VERSION = "0.0.3" 5 | ) 6 | 7 | //0.0.2 优化render, panic日志展示 8 | //0.0.3 http log 增加ip信息 9 | -------------------------------------------------------------------------------- /handler/home_hander.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/710leo/Toruk/http/render" 7 | ) 8 | 9 | func HomeIndex(w http.ResponseWriter, r *http.Request) { 10 | render.HTML(r, w, "home/index") 11 | } 12 | -------------------------------------------------------------------------------- /http/cookie/cookie.go: -------------------------------------------------------------------------------- 1 | package cookie 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gorilla/securecookie" 7 | ) 8 | 9 | var SecureCookie *securecookie.SecureCookie 10 | 11 | func Init() { 12 | var hashKey = []byte(nil) 13 | var blockKey = []byte(nil) 14 | SecureCookie = securecookie.New(hashKey, blockKey) 15 | } 16 | 17 | func ReadUser(r *http.Request) (example string) { 18 | if cookie, err := r.Cookie("u"); err == nil { 19 | value := make(map[string]interface{}) 20 | if err = SecureCookie.Decode("u", cookie.Value, &value); err == nil { 21 | example = value["example"].(string) 22 | } 23 | } 24 | return 25 | } 26 | 27 | func WriteUser(w http.ResponseWriter, example string) error { 28 | value := make(map[string]interface{}) 29 | value["example"] = example 30 | encoded, err := SecureCookie.Encode("u", value) 31 | if err != nil { 32 | return err 33 | } 34 | 35 | cookie := &http.Cookie{ 36 | Name: "u", 37 | Value: encoded, 38 | Path: "/", 39 | MaxAge: 3600 * 24 * 7, 40 | HttpOnly: true, 41 | } 42 | http.SetCookie(w, cookie) 43 | 44 | return nil 45 | } 46 | 47 | func RemoveUser(w http.ResponseWriter) error { 48 | value := make(map[string]interface{}) 49 | value["example"] = "" 50 | encoded, err := SecureCookie.Encode("u", value) 51 | if err != nil { 52 | return err 53 | } 54 | 55 | cookie := &http.Cookie{ 56 | Name: "u", 57 | Value: encoded, 58 | Path: "/", 59 | MaxAge: -1, 60 | } 61 | http.SetCookie(w, cookie) 62 | 63 | return nil 64 | } 65 | -------------------------------------------------------------------------------- /http/errors/errors.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "net/http" 5 | "runtime" 6 | "strings" 7 | "time" 8 | ) 9 | 10 | type Error struct { 11 | Code int `json:"code"` 12 | Msg string `json:"msg"` 13 | Time string `json:"time"` 14 | File string `json:"file"` 15 | Line int `json:"line"` 16 | } 17 | 18 | // 401 19 | func NotLoginError(msg ...string) Error { 20 | return _build(http.StatusUnauthorized, "unauthorized", msg...) 21 | } 22 | 23 | // 400 24 | func BadRequestError(msg ...string) Error { 25 | return _build(http.StatusBadRequest, "bad request", msg...) 26 | } 27 | 28 | // 403 29 | func NoPrivError(msg ...string) Error { 30 | return _build(http.StatusForbidden, "forbidden", msg...) 31 | } 32 | 33 | // 500 34 | func InternalServerError(msg ...string) Error { 35 | return _build(http.StatusInternalServerError, "internal server error", msg...) 36 | } 37 | 38 | func _build(code int, defval string, custom ...string) Error { 39 | msg := defval 40 | if len(custom) > 0 { 41 | msg = custom[0] 42 | } 43 | return Error{ 44 | Code: code, 45 | Msg: msg, 46 | } 47 | } 48 | 49 | func MaybePanic(err error) { 50 | _, whichFile, line, _ := runtime.Caller(1) 51 | arr := strings.Split(whichFile, "/") 52 | file := arr[len(arr)-1] 53 | t := time.Unix(time.Now().Unix(), 0).Format("2006-01-02 15:04:05") 54 | 55 | if err != nil { 56 | panic(Error{Msg: err.Error(), Time: t, File: file, Line: line}) 57 | } 58 | } 59 | 60 | func Panic(msg string) { 61 | _, whichFile, line, _ := runtime.Caller(1) 62 | arr := strings.Split(whichFile, "/") 63 | file := arr[len(arr)-1] 64 | t := time.Unix(time.Now().Unix(), 0).Format("2006-01-02 15:04:05") 65 | 66 | panic(Error{Msg: msg, Time: t, File: file, Line: line}) 67 | } 68 | -------------------------------------------------------------------------------- /http/helper/helper.go: -------------------------------------------------------------------------------- 1 | package helper 2 | 3 | func Example() string { 4 | return "good luck" 5 | } 6 | -------------------------------------------------------------------------------- /http/http.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "github.com/codegangsta/negroni" 5 | "github.com/gorilla/mux" 6 | 7 | "github.com/710leo/Toruk/g" 8 | "github.com/710leo/Toruk/http/cookie" 9 | "github.com/710leo/Toruk/http/middleware" 10 | "github.com/710leo/Toruk/http/render" 11 | ) 12 | 13 | func Start() { 14 | render.Init() 15 | cookie.Init() 16 | 17 | r := mux.NewRouter().StrictSlash(false) 18 | ConfigRouter(r) 19 | 20 | n := negroni.New() 21 | 22 | if g.Config().Debug { 23 | n.Use(middleware.NewLogger()) 24 | } 25 | 26 | n.Use(middleware.NewRecovery()) 27 | n.UseHandler(r) 28 | n.Run(g.Config().Http.Listen) 29 | } 30 | -------------------------------------------------------------------------------- /http/middleware/logger.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "os" 7 | "time" 8 | 9 | "github.com/codegangsta/negroni" 10 | ) 11 | 12 | // Logger is a middleware handler that logs the request as it goes in and the response as it goes out. 13 | type Logger struct { 14 | // Logger inherits from log.Logger used to log messages with the Logger middleware 15 | *log.Logger 16 | } 17 | 18 | // NewLogger returns a new Logger instance 19 | func NewLogger() *Logger { 20 | return &Logger{log.New(os.Stdout, "", 0)} 21 | } 22 | 23 | func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 24 | start := time.Now() 25 | l.Printf("%v %s %s %s", time.Now().Format("2006/01/02 15:04:05"), r.Method, r.URL.Path, r.RemoteAddr) 26 | 27 | next(rw, r) 28 | 29 | res := rw.(negroni.ResponseWriter) 30 | l.Printf("%v %v %s in %v", time.Now().Format("2006/01/02 15:04:05"), res.Status(), http.StatusText(res.Status()), time.Since(start)) 31 | } 32 | -------------------------------------------------------------------------------- /http/middleware/recovery.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "os" 8 | "runtime" 9 | 10 | "github.com/710leo/Toruk/http/errors" 11 | "github.com/710leo/Toruk/http/render" 12 | ) 13 | 14 | // Recovery is a Negroni middleware that recovers from any panics and writes a 500 if there was one. 15 | type Recovery struct { 16 | Logger *log.Logger 17 | PrintStack bool 18 | StackAll bool 19 | StackSize int 20 | } 21 | 22 | // NewRecovery returns a new instance of Recovery 23 | func NewRecovery() *Recovery { 24 | return &Recovery{ 25 | Logger: log.New(os.Stdout, "[panic] ", 0), 26 | PrintStack: true, 27 | StackAll: false, 28 | StackSize: 1024 * 8, 29 | } 30 | } 31 | 32 | func (rec *Recovery) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 33 | defer func() { 34 | if err := recover(); err != nil { 35 | if customError, ok := err.(errors.Error); ok { 36 | if isAjax(r) { 37 | render.Message(w, customError.Msg) 38 | log.Printf("[%s:%d] %s [Error:]%s", customError.File, customError.Line, customError.Time, customError.Msg) 39 | return 40 | } 41 | 42 | if customError.Code == http.StatusUnauthorized || customError.Code == http.StatusForbidden { 43 | http.Redirect(w, r, "/", 302) 44 | return 45 | } 46 | 47 | render.Put(r, "Error", customError.Msg) 48 | render.HTML(r, w, "inc/error") 49 | return 50 | } 51 | 52 | // Negroni part 53 | w.WriteHeader(http.StatusInternalServerError) 54 | stack := make([]byte, rec.StackSize) 55 | stack = stack[:runtime.Stack(stack, rec.StackAll)] 56 | 57 | f := "PANIC: %s\n%s" 58 | log.Printf(f, err, stack) 59 | 60 | if rec.PrintStack { 61 | fmt.Fprintf(w, f, err, stack) 62 | } 63 | } 64 | }() 65 | 66 | next(w, r) 67 | } 68 | 69 | func isAjax(r *http.Request) bool { 70 | return r.Header.Get("X-Requested-With") == "XMLHttpRequest" 71 | } 72 | -------------------------------------------------------------------------------- /http/param/param.go: -------------------------------------------------------------------------------- 1 | package param 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "strconv" 7 | "strings" 8 | 9 | "github.com/710leo/Toruk/http/errors" 10 | ) 11 | 12 | func String(r *http.Request, key string, defVal string) string { 13 | if val, ok := r.URL.Query()[key]; ok { 14 | if val[0] == "" { 15 | return defVal 16 | } 17 | return strings.TrimSpace(val[0]) 18 | } 19 | 20 | if r.Form == nil { 21 | err := r.ParseForm() 22 | if err != nil { 23 | panic(errors.BadRequestError()) 24 | } 25 | } 26 | 27 | val := r.Form.Get(key) 28 | if val == "" { 29 | return defVal 30 | } 31 | 32 | return strings.TrimSpace(val) 33 | } 34 | 35 | func MustString(r *http.Request, key string, displayName ...string) string { 36 | val := String(r, key, "") 37 | if val == "" { 38 | name := key 39 | if len(displayName) > 0 { 40 | name = displayName[0] 41 | } 42 | panic(errors.BadRequestError(fmt.Sprintf("%s is necessary", name))) 43 | } 44 | return val 45 | } 46 | 47 | func Int64(r *http.Request, key string, defVal int64) int64 { 48 | raw := String(r, key, "") 49 | if raw == "" { 50 | return defVal 51 | } 52 | 53 | val, err := strconv.ParseInt(raw, 10, 64) 54 | if err != nil { 55 | return defVal 56 | } 57 | 58 | return val 59 | } 60 | 61 | func MustInt64(r *http.Request, key string, displayName ...string) int64 { 62 | raw := String(r, key, "") 63 | if raw == "" { 64 | name := key 65 | if len(displayName) > 0 { 66 | name = displayName[0] 67 | } 68 | panic(errors.BadRequestError(fmt.Sprintf("%s is necessary", name))) 69 | } 70 | 71 | val, err := strconv.ParseInt(raw, 10, 64) 72 | if err != nil { 73 | panic(errors.BadRequestError()) 74 | } 75 | 76 | return val 77 | } 78 | 79 | func Int(r *http.Request, key string, defVal int) int { 80 | raw := String(r, key, "") 81 | if raw == "" { 82 | return defVal 83 | } 84 | 85 | val, err := strconv.Atoi(raw) 86 | if err != nil { 87 | return defVal 88 | } 89 | 90 | return val 91 | } 92 | 93 | func MustInt(r *http.Request, key string, displayName ...string) int { 94 | name := key 95 | if len(displayName) > 0 { 96 | name = displayName[0] 97 | } 98 | 99 | raw := String(r, key, "") 100 | if raw == "" { 101 | panic(errors.BadRequestError(fmt.Sprintf("%s is necessary", name))) 102 | } 103 | 104 | val, err := strconv.Atoi(raw) 105 | if err != nil { 106 | panic(errors.BadRequestError(fmt.Sprintf("%s should be integer", name))) 107 | } 108 | 109 | return val 110 | } 111 | 112 | func Float64(r *http.Request, key string, defVal float64) float64 { 113 | raw := String(r, key, "") 114 | if raw == "" { 115 | return defVal 116 | } 117 | 118 | val, err := strconv.ParseFloat(raw, 64) 119 | if err != nil { 120 | return defVal 121 | } 122 | 123 | return val 124 | } 125 | 126 | func MustFloat64(r *http.Request, key string, displayName ...string) float64 { 127 | raw := String(r, key, "") 128 | if raw == "" { 129 | name := key 130 | if len(displayName) > 0 { 131 | name = displayName[0] 132 | } 133 | panic(errors.BadRequestError(fmt.Sprintf("%s is necessary", name))) 134 | } 135 | 136 | val, err := strconv.ParseFloat(raw, 64) 137 | if err != nil { 138 | panic(errors.BadRequestError()) 139 | } 140 | 141 | return val 142 | } 143 | 144 | func Bool(r *http.Request, key string, defVal bool) bool { 145 | raw := String(r, key, "") 146 | if raw == "true" || raw == "1" || raw == "on" || raw == "checked" || raw == "yes" { 147 | return true 148 | } else if raw == "false" || raw == "0" || raw == "off" || raw == "" || raw == "no" { 149 | return false 150 | } else { 151 | return defVal 152 | } 153 | } 154 | 155 | func MustBool(r *http.Request, key string) bool { 156 | raw := String(r, key, "") 157 | if raw == "true" || raw == "1" || raw == "on" || raw == "checked" || raw == "yes" { 158 | return true 159 | } else if raw == "false" || raw == "0" || raw == "off" || raw == "" || raw == "no" { 160 | return false 161 | } else { 162 | panic(errors.BadRequestError()) 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /http/render/render.go: -------------------------------------------------------------------------------- 1 | package render 2 | 3 | import ( 4 | "fmt" 5 | "html/template" 6 | "net/http" 7 | 8 | "github.com/gorilla/context" 9 | "github.com/unrolled/render" 10 | 11 | "github.com/710leo/Toruk/g" 12 | "github.com/710leo/Toruk/http/helper" 13 | ) 14 | 15 | var Render *render.Render 16 | 17 | var funcMap = template.FuncMap{ 18 | "Example": helper.Example, 19 | } 20 | 21 | func Init() { 22 | Render = render.New(render.Options{ 23 | Directory: "views", 24 | Extensions: []string{".html"}, 25 | Delims: render.Delims{"{{", "}}"}, 26 | Funcs: []template.FuncMap{funcMap}, 27 | IndentJSON: false, 28 | IsDevelopment: g.Config().Debug, 29 | }) 30 | } 31 | 32 | func Put(r *http.Request, key string, val interface{}) { 33 | m, ok := context.GetOk(r, "_DATA_MAP_") 34 | if ok { 35 | mm := m.(map[string]interface{}) 36 | mm[key] = val 37 | context.Set(r, "_DATA_MAP_", mm) 38 | } else { 39 | context.Set(r, "_DATA_MAP_", map[string]interface{}{key: val}) 40 | } 41 | } 42 | 43 | func HTML(r *http.Request, w http.ResponseWriter, name string, htmlOpt ...render.HTMLOptions) { 44 | Render.HTML(w, http.StatusOK, name, context.Get(r, "_DATA_MAP_"), htmlOpt...) 45 | } 46 | 47 | func Text(w http.ResponseWriter, v string, codes ...int) { 48 | code := http.StatusOK 49 | if len(codes) > 0 { 50 | code = codes[0] 51 | } 52 | Render.Text(w, code, v) 53 | } 54 | 55 | func Error(w http.ResponseWriter, err error) { 56 | msg := "" 57 | if err != nil { 58 | msg = err.Error() 59 | } 60 | 61 | Render.JSON(w, http.StatusOK, map[string]string{"msg": msg}) 62 | } 63 | 64 | func Message(w http.ResponseWriter, format string, args ...interface{}) { 65 | Render.JSON(w, http.StatusOK, map[string]string{"msg": fmt.Sprintf(format, args...)}) 66 | } 67 | 68 | func Data(w http.ResponseWriter, v interface{}, msg ...string) { 69 | m := "" 70 | if len(msg) > 0 { 71 | m = msg[0] 72 | } 73 | 74 | Render.JSON(w, http.StatusOK, map[string]interface{}{"msg": m, "data": v}) 75 | } 76 | -------------------------------------------------------------------------------- /http/routes.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "github.com/gorilla/mux" 8 | "github.com/710leo/Toruk/handler" 9 | ) 10 | 11 | func ConfigRouter(r *mux.Router) { 12 | configConfRoutes(r) 13 | } 14 | 15 | func configConfRoutes(r *mux.Router) { 16 | r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 17 | fmt.Fprintf(w, "ok") 18 | }).Methods("GET") 19 | 20 | r.HandleFunc("/home", handler.HomeIndex).Methods("GET") 21 | } 22 | -------------------------------------------------------------------------------- /init: -------------------------------------------------------------------------------- 1 | echo $1; 2 | sed -i "s@github.com/710leo/Toruk@$1@g" `grep -rl "github.com/710leo" *`; 3 | sed -i "s@toruk@$1@g" control; -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "os" 8 | "runtime" 9 | 10 | "github.com/710leo/Toruk/g" 11 | "github.com/710leo/Toruk/http" 12 | ) 13 | 14 | func prepare() { 15 | runtime.GOMAXPROCS(runtime.NumCPU()) 16 | } 17 | 18 | func init() { 19 | prepare() 20 | 21 | cfg := flag.String("c", "cfg.json", "configuration file") 22 | version := flag.Bool("v", false, "show version") 23 | help := flag.Bool("h", false, "help") 24 | flag.Parse() 25 | 26 | handleVersion(*version) 27 | handleHelp(*help) 28 | handleConfig(*cfg) 29 | } 30 | 31 | func main() { 32 | http.Start() 33 | } 34 | 35 | func handleVersion(displayVersion bool) { 36 | if displayVersion { 37 | fmt.Println(g.VERSION) 38 | os.Exit(0) 39 | } 40 | } 41 | 42 | func handleHelp(displayHelp bool) { 43 | if displayHelp { 44 | flag.Usage() 45 | os.Exit(0) 46 | } 47 | } 48 | 49 | func handleConfig(configFile string) { 50 | err := g.Parse(configFile) 51 | if err != nil { 52 | log.Fatalln(err) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /model/example.go: -------------------------------------------------------------------------------- 1 | package model 2 | -------------------------------------------------------------------------------- /store/mysql.go: -------------------------------------------------------------------------------- 1 | package store 2 | -------------------------------------------------------------------------------- /views/common/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Oops 6 | 7 | 8 |
9 |

:(

10 |

{{.Error}}

11 |

12 | 返回上页 13 | | 14 | 返回首页

15 |
16 | 17 | -------------------------------------------------------------------------------- /views/home/index.html: -------------------------------------------------------------------------------- 1 | hello! --------------------------------------------------------------------------------