[ADD]创建项目

This commit is contained in:
hehui 2019-08-07 20:56:20 +08:00
parent 74ec91abb5
commit 05eea252ef
23 changed files with 799 additions and 0 deletions

3
.gitignore vendored
View File

@ -10,3 +10,6 @@
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
conf/app.ini
.idea/*

23
conf/app.ini Normal file
View File

@ -0,0 +1,23 @@
RUN_MODE = debug
[app]
PAGE_SIZE = 10
JWT_SECRET = 23347$040412
[server]
HTTP_PORT = 8000
READ_TIMEOUT = 60
WRITE_TIMEOUT = 60
[database]
TYPE = postgres
USER = postgre
PASSWORD = 123456
HOST = 127.0.0.1
PORT = 5432
NAME = data_govern
TABLE_PREFIX = d_
[redis]
HOST = 127.0.0.1
PORT = 6379

19
conf/app.ini.local Normal file
View File

@ -0,0 +1,19 @@
RUN_MODE = debug
[app]
PAGE_SIZE = 10
JWT_SECRET = 23347$040412
[server]
HTTP_PORT = 8000
READ_TIMEOUT = 60
WRITE_TIMEOUT = 60
[database]
TYPE = postgres
USER = postgres
PASSWORD = 123456
HOST = postgres
PORT = 5432
NAME = dbname
TABLE_PREFIX = g_

7
controller/api/auth.go Normal file
View File

@ -0,0 +1,7 @@
package api
import "github.com/gin-gonic/gin"
func GetAuth(c *gin.Context) {
}

View File

@ -0,0 +1,39 @@
package data
import (
"github.com/gin-gonic/gin"
_ "github.com/viletyy/potato/models/data"
data2 "github.com/viletyy/potato/models/data"
"github.com/viletyy/potato/pkg/e"
"github.com/viletyy/potato/pkg/setting"
"github.com/viletyy/potato/pkg/util"
"net/http"
)
// @Summary 数据源列表
// @Tags meta_databases
// @Description
// @Accept json
// @Produce json
// @Success 200 {string} json "{"code" : 200, "data" : {}, "msg": "ok" }"
// @Router /v1/meta_databases [get]
func GetMetaDatabases(c *gin.Context) {
name := c.Query("name")
maps := make(map[string]interface{})
data := make(map[string]interface{})
if name != "" {
maps["name"] = name
}
data["lists"] = data2.GetMetaDatabases(util.GetPage(c), setting.PageSize, maps)
data["total"] = data2.GetMetaDatabaseTotal(maps)
code := e.SUCCESS
c.JSON(http.StatusOK, gin.H{
"code": code,
"msg": e.GetMsg(code),
"data": data,
})
}

View File

@ -0,0 +1,34 @@
package data
import (
"github.com/gin-gonic/gin"
"github.com/viletyy/potato/pkg/e"
"net/http"
)
// @Summary 元数据列表
// @Tags meta_tables
// @Description
// @Accept json
// @Produce json
// @Param id path int true "数据源 ID"
// @Success 200 {string} json "{"code" : 200, "data" : {}, "msg": "ok" }"
// @Router /v1/meta_databases/:id/meta_tables [get]
func GetMetaTables(c *gin.Context) {
name := c.Query("name")
maps := make(map[string]interface{})
data := make(map[string]interface{})
if name != "" {
maps["name"] = name
}
code := e.SUCCESS
c.JSON(http.StatusOK, gin.H{
"code": code,
"msg": e.GetMsg(code),
"data": data,
})
}

76
docs/docs.go Normal file
View File

@ -0,0 +1,76 @@
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// This file was generated by swaggo/swag at
// 2019-08-07 19:40:27.3805 +0800 CST m=+0.046403409
package docs
import (
"bytes"
"encoding/json"
"strings"
"github.com/alecthomas/template"
"github.com/swaggo/swag"
)
var doc = `{
"schemes": {{ marshal .Schemes }},
"swagger": "2.0",
"info": {
"description": "{{.Description}}",
"title": "{{.Title}}",
"contact": {},
"license": {},
"version": "{{.Version}}"
},
"host": "{{.Host}}",
"basePath": "{{.BasePath}}",
"paths": {}
}`
type swaggerInfo struct {
Version string
Host string
BasePath string
Schemes []string
Title string
Description string
}
// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo = swaggerInfo{
Version: "1.0",
Host: "",
BasePath: "/",
Schemes: []string{},
Title: "Potato Api",
Description: "This is a data_govern use golang",
}
type s struct{}
func (s *s) ReadDoc() string {
sInfo := SwaggerInfo
sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1)
t, err := template.New("swagger_info").Funcs(template.FuncMap{
"marshal": func(v interface{}) string {
a, _ := json.Marshal(v)
return string(a)
},
}).Parse(doc)
if err != nil {
return doc
}
var tpl bytes.Buffer
if err := t.Execute(&tpl, sInfo); err != nil {
return doc
}
return tpl.String()
}
func init() {
swag.Register(swag.Name, &s{})
}

12
docs/swagger.json Normal file
View File

@ -0,0 +1,12 @@
{
"swagger": "2.0",
"info": {
"description": "This is a data_govern use golang",
"title": "Potato Api",
"contact": {},
"license": {},
"version": "1.0"
},
"basePath": "/",
"paths": {}
}

9
docs/swagger.yaml Normal file
View File

@ -0,0 +1,9 @@
basePath: /
info:
contact: {}
description: This is a data_govern use golang
license: {}
title: Potato Api
version: "1.0"
paths: {}
swagger: "2.0"

57
main.go Normal file
View File

@ -0,0 +1,57 @@
package main
import (
"context"
"fmt"
"github.com/viletyy/potato/pkg/setting"
"github.com/viletyy/potato/pkg/util"
"github.com/viletyy/potato/routers"
"log"
"net/http"
"os"
"os/signal"
"time"
)
// @title Potato Api
// @version 1.0
// @description This is a data_govern use golang
// @BasePath /api
func main() {
router := routers.InitRouter()
// 数据库配置
_ = util.InitDB()
defer util.CloseDB()
util.InitRedis()
defer util.CloseRedis()
server := &http.Server{
Addr: fmt.Sprintf(":%d", setting.HTTPPort),
Handler: router,
ReadTimeout: setting.ReadTimeout,
WriteTimeout: setting.WriteTimeout,
MaxHeaderBytes: 1 << 20,
}
go func() {
if err := server.ListenAndServe(); err != nil {
log.Printf(fmt.Sprintf("Listen: %s\n", err))
}
}()
quit := make(chan os.Signal)
signal.Notify(quit, os.Interrupt)
<- quit
log.Printf("Shutdown Server")
ctx, cancel := context.WithTimeout(context.Background(), 5 * time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Fatal("Server Shutdown:", err)
}
log.Printf("Server exiting")
}

19
middleware/cors/cors.go Normal file
View File

@ -0,0 +1,19 @@
package cors
import "github.com/gin-gonic/gin"
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}

42
middleware/jwt/jwt.go Normal file
View File

@ -0,0 +1,42 @@
package jwt
import (
"game_demo/pkg/e"
"game_demo/pkg/util"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
func JWT() gin.HandlerFunc {
return func(c *gin.Context) {
var code int
var data interface{}
code = e.SUCCESS
token := c.Request.Header.Get("Authorization")
if token == "" {
code = e.INVALID_PARAMS
} else {
claims, err := util.ParseToken(token)
if err != nil {
code = e.ERROR_AUTH_CHECK_TOKEN_FAIL
} else if time.Now().Unix() > claims.ExpiresAt {
code = e.ERROR_AUTH_CHECK_TOKEN_TIMEOUT
}
}
if code != e.SUCCESS {
c.JSON(http.StatusUnauthorized, gin.H{
"code" : code,
"msg" : e.GetMsg(code),
"data" : data,
})
c.Abort()
return
}
c.Next()
}
}

View File

@ -0,0 +1,23 @@
package data
import "github.com/viletyy/potato/pkg/util"
type MetaDatabase struct {
util.Model
Name string `json:"name"`
CnName string `json:"cn_name"`
Logo string `json:"logo"`
}
func GetMetaDatabases(pageNum int, pageSize int, maps interface{}) (metaDatabases []MetaDatabase) {
util.DB.Where(maps).Offset(pageNum).Limit(pageSize).Find(&metaDatabases)
return
}
func GetMetaDatabaseTotal(maps interface{}) (count int) {
util.DB.Model(&MetaDatabase{}).Where(maps).Count(&count)
return
}

19
pkg/e/code.go Normal file
View File

@ -0,0 +1,19 @@
package e
const (
SUCCESS = 200
ERROR = 500
INVALID_PARAMS = 400
ERROR_EXIST_GAME = 10001
ERROR_EXIST_TEAM = 10002
ERROR_NOT_EXIST_GAME = 10003
ERROR_NOT_EXIST_TEAM = 10004
ERROR_NOT_EXIST_LEAGUE = 10005
ERROR_NOT_EXIST_SERIES = 10006
ERROR_AUTH_CHECK_TOKEN_FAIL = 20001
ERROR_AUTH_CHECK_TOKEN_TIMEOUT = 20002
ERROR_AUTH_TOKEN = 20003
ERROR_AUTH = 20004
)

27
pkg/e/msg.go Normal file
View File

@ -0,0 +1,27 @@
package e
var MsgFlags = map[int]string {
SUCCESS : "ok",
ERROR : "fail",
INVALID_PARAMS : "请求参数错误",
ERROR_EXIST_GAME : "已存在该游戏",
ERROR_EXIST_TEAM : "已存在该队伍",
ERROR_NOT_EXIST_GAME : "该游戏不存在",
ERROR_NOT_EXIST_TEAM : "该队伍不存在",
ERROR_NOT_EXIST_LEAGUE : "该联赛不存在",
ERROR_NOT_EXIST_SERIES : "该系列赛不存在",
ERROR_AUTH_CHECK_TOKEN_FAIL : "Token鉴权失败",
ERROR_AUTH_CHECK_TOKEN_TIMEOUT : "Token已超时",
ERROR_AUTH_TOKEN : "Token生成失败",
ERROR_AUTH : "Token错误",
}
func GetMsg(code int) string {
msg, ok := MsgFlags[code]
if ok {
return msg
}
return MsgFlags[ERROR]
}

51
pkg/logging/file.go Normal file
View File

@ -0,0 +1,51 @@
package logging
import (
"fmt"
"log"
"os"
"time"
)
var (
LogSavePath = "runtime/logs/"
LogSaveName = "log"
LogFileExt = "log"
TimeFormat = "20060102"
)
func getLogFilePath() string {
return fmt.Sprintf("%s", LogSavePath)
}
func getLogFileFullPath() string {
prefixPath := getLogFilePath()
suffixPath := fmt.Sprintf("%s%s.%s", LogSaveName, time.Now().Format(TimeFormat), LogFileExt)
return fmt.Sprintf("%s%s", prefixPath, suffixPath)
}
func openLogFile(filePath string) *os.File {
_, err := os.Stat(filePath)
switch {
case os.IsNotExist(err):
mkDir()
case os.IsPermission(err):
log.Fatalf("Permission :%v1", err)
}
handle, err := os.OpenFile(filePath, os.O_APPEND | os.O_CREATE | os.O_WRONLY, 0644)
if err != nil {
log.Fatalf("Fail to OpenFile :%v1", err)
}
return handle
}
func mkDir() {
dir, _ := os.Getwd()
err := os.MkdirAll(dir + "/" + getLogFilePath(), os.ModePerm)
if err != nil {
panic(err)
}
}

73
pkg/logging/log.go Normal file
View File

@ -0,0 +1,73 @@
package logging
import (
"fmt"
"log"
"os"
"path/filepath"
"runtime"
)
type Level int
var (
F *os.File
DefaultPrefix = ""
DefaultCallerDepth = 2
logger *log.Logger
logPrefix = ""
levelFlags = []string{"DEBUG", "INFO", "WARN", "ERROR", "FATAL"}
)
const (
DEBUG Level = iota
INFO
WARNING
ERROR
FATAL
)
func init() {
filePath := getLogFileFullPath()
F = openLogFile(filePath)
logger = log.New(F, DefaultPrefix, log.LstdFlags)
}
func Debug(v ...interface{}) {
setPrefix(DEBUG)
logger.Println(v)
}
func Info(v ...interface{}) {
setPrefix(INFO)
logger.Println(v)
}
func Warn(v ...interface{}) {
setPrefix(WARNING)
logger.Println(v)
}
func Error(v ...interface{}) {
setPrefix(ERROR)
logger.Println(v)
}
func Fatal(v ...interface{}) {
setPrefix(FATAL)
logger.Fatalln(v)
}
func setPrefix(level Level) {
_, file, line, ok := runtime.Caller(DefaultCallerDepth)
if ok {
logPrefix = fmt.Sprintf("[%s][%s:%d]", levelFlags[level], filepath.Base(file), line)
} else {
logPrefix = fmt.Sprintf("[%s]", levelFlags[level])
}
logger.SetPrefix(logPrefix)
}

59
pkg/setting/setting.go Normal file
View File

@ -0,0 +1,59 @@
package setting
import (
"gopkg.in/ini.v1"
"log"
"time"
)
var (
Cfg *ini.File
RunMode string
HTTPPort int
ReadTimeout time.Duration
WriteTimeout time.Duration
PageSize int
JwtSecret string
)
func init() {
var err error
Cfg, err = ini.Load("conf/app.ini")
if err != nil {
log.Fatal("Fail to parse 'conf/app.ini': %v1", err)
}
LoadBase()
LoadServer()
LoadApp()
}
func LoadBase() {
RunMode = Cfg.Section("").Key("RUN_MODE").MustString("debug")
}
func LoadServer() {
sec, err := Cfg.GetSection("server")
if err != nil {
log.Fatalf("Fail to get section 'server': %v1", err)
}
RunMode = Cfg.Section("").Key("RUN_MODE").MustString("debug")
HTTPPort = sec.Key("HTTP_PORT").MustInt(8000)
ReadTimeout = time.Duration(sec.Key("READ_TIMEOUT").MustInt(60)) * time.Second
WriteTimeout = time.Duration(sec.Key("WRITE_TIMEOUT").MustInt(60)) * time.Second
}
func LoadApp() {
sec, err := Cfg.GetSection("app")
if err != nil {
log.Fatalf("Fail to get section 'app': %v1", err)
}
JwtSecret = sec.Key("JWT_SECRET").MustString("!@)*#)!@U#@*!@!)")
PageSize = sec.Key("PAGE_SIZE").MustInt(10)
}

89
pkg/util/Instance.go Normal file
View File

@ -0,0 +1,89 @@
package util
import (
"fmt"
"github.com/go-redis/redis"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/postgres"
"github.com/viletyy/potato/pkg/logging"
"github.com/viletyy/potato/pkg/setting"
"time"
)
type Model struct {
ID int `gorm:"primary_key" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt *time.Time `sql:"index" json:"deleted_at"`
}
var(
DB *gorm.DB
Redis *redis.Client
)
func InitDB() *gorm.DB {
var (
err error
dbType, dbName, user, password, host, port, tablePrefix string
)
sec, err := setting.Cfg.GetSection("database")
if err != nil {
logging.Info(2, fmt.Sprintf("Fail to get section 'database': %v", err))
}
dbType = sec.Key("TYPE").String()
dbName = sec.Key("NAME").String()
user = sec.Key("USER").String()
password = sec.Key("PASSWORD").String()
host = sec.Key("HOST").String()
port = sec.Key("PORT").String()
tablePrefix = sec.Key("TABLE_PREFIX").String()
DB, err := gorm.Open(dbType, fmt.Sprintf("host=%s user=%s dbname=%s port=%s sslmode=disable password=%s", host, user, dbName, port, password))
if err != nil {
logging.Info(err)
}
gorm.DefaultTableNameHandler = func(db *gorm.DB, defaultTableName string) string {
return tablePrefix + defaultTableName
}
DB.LogMode(true)
DB.SingularTable(true)
DB.DB().SetMaxIdleConns(10)
DB.DB().SetMaxOpenConns(100)
return DB
}
func InitRedis() {
sec, err := setting.Cfg.GetSection("redis")
if err != nil {
logging.Info(2, fmt.Sprintf("Fail to get section 'redis': %v", err))
}
Redis = redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("%s:%s",
sec.Key("HOST").String(),
sec.Key("PORT").String(),
),
})
if _, err := Redis.Ping().Result(); err != nil {
logging.Fatal("redis连接失败!", err)
}
}
func CloseDB() {
DB.Close()
}
func CloseRedis() {
Redis.Close()
}

48
pkg/util/jwt.go Normal file
View File

@ -0,0 +1,48 @@
package util
import (
"github.com/dgrijalva/jwt-go"
"github.com/viletyy/potato/pkg/setting"
"time"
)
var jwtSecret = []byte(setting.JwtSecret)
type Claims struct {
Username string `json:"username"`
Password string `json:"password"`
jwt.StandardClaims
}
func GenerateToken(username, password string) (string, error) {
nowTime := time.Now()
expireTime := nowTime.Add(3 * time.Hour)
claims := Claims{
Username: username,
Password: password,
StandardClaims: jwt.StandardClaims{
ExpiresAt: expireTime.Unix(),
Issuer : "gin-game-demo",
},
}
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
token, err := tokenClaims.SignedString(jwtSecret)
return token, err
}
func ParseToken(token string) (*Claims, error) {
tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return jwtSecret, nil
})
if tokenClaims != nil {
if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
return claims, nil
}
}
return nil, err
}

18
pkg/util/pagination.go Normal file
View File

@ -0,0 +1,18 @@
package util
import (
"github.com/Unknwon/com"
"github.com/viletyy/potato/pkg/setting"
"github.com/gin-gonic/gin"
)
func GetPage(c *gin.Context) int {
result := 0
page, _ := com.StrTo(c.Query("page")).Int()
if page > 0 {
result = (page - 1) * setting.PageSize
}
return result
}

13
routers/data.go Normal file
View File

@ -0,0 +1,13 @@
package routers
import (
"github.com/viletyy/potato/controller/api/v1/data"
)
func V1InitDataRouter() {
metaDatabases := V1RouterGroup.Group("/meta_databases")
{
metaDatabases.GET("", data.GetMetaDatabases)
metaDatabases.GET(":id/meta_tables", data.GetMetaTables)
}
}

39
routers/router.go Normal file
View File

@ -0,0 +1,39 @@
package routers
import (
"github.com/gin-gonic/gin"
_ "github.com/swaggo/gin-swagger"
ginSwagger "github.com/swaggo/gin-swagger"
"github.com/swaggo/gin-swagger/swaggerFiles"
_ "github.com/swaggo/gin-swagger/swaggerFiles"
"github.com/viletyy/potato/controller/api"
_ "github.com/viletyy/potato/docs"
"github.com/viletyy/potato/middleware/cors"
"github.com/viletyy/potato/pkg/setting"
)
var (
Engine = gin.Default()
V1RouterGroup = Engine.Group("../api/v1")
)
func InitRouter() *gin.Engine {
Engine.Use(gin.Logger())
Engine.Use(gin.Recovery())
gin.SetMode(setting.RunMode)
Engine.Use(cors.CORSMiddleware())
Engine.GET("/auth", api.GetAuth)
Engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
V1InitModule()
return Engine
}
func V1InitModule() {
V1InitDataRouter()
}