Commit e1b101c8 authored by shajiaiming's avatar shajiaiming

币种信息接口

parent e9098da1
[app]
PageSize = 10
JwtSecret = 233
PrefixUrl = http://127.0.0.1:8983
RuntimeRootPath = runtime/
ImageSavePath = upload/images/
# MB
ImageMaxSize = 5
ImageAllowExts = .jpg,.jpeg,.png
ExportSavePath = export/
QrCodeSavePath = qrcode/
FontSavePath = fonts/
LogSavePath = logs/
LogSaveName = log
LogFileExt = log
TimeFormat = 20060102
[server]
#debug or release
RunMode = debug
HttpPort = 8983
ReadTimeout = 60
WriteTimeout = 60
[database]
Type = mysql
User = root
Password = 123456
Host = 172.16.100.216:3306
Name = pc_sources
TablePrefix = coin_
[redis]
Host = 127.0.0.1:6379
Password =
MaxIdle = 30
MaxActive = 30
IdleTimeout = 200
\ No newline at end of file
package main
import (
"fmt"
"log"
"net/http"
"github.com/gin-gonic/gin"
"bwallet/models"
"bwallet/pkg/gredis"
"bwallet/pkg/logging"
"bwallet/pkg/setting"
"bwallet/routers"
"bwallet/pkg/util"
)
func init() {
setting.Setup()
models.Setup()
logging.Setup()
gredis.Setup()
util.Setup()
}
func main() {
gin.SetMode(setting.ServerSetting.RunMode)
routersInit := routers.InitRouter()
readTimeout := setting.ServerSetting.ReadTimeout
writeTimeout := setting.ServerSetting.WriteTimeout
endPoint := fmt.Sprintf(":%d", setting.ServerSetting.HttpPort)
maxHeaderBytes := 1 << 20
server := &http.Server{
Addr: endPoint,
Handler: routersInit,
ReadTimeout: readTimeout,
WriteTimeout: writeTimeout,
MaxHeaderBytes: maxHeaderBytes,
}
log.Printf("[info] start http server listening %s", endPoint)
server.ListenAndServe()
}
package jwt
import (
"github.com/gin-gonic/gin"
"bwallet/pkg/e"
"bwallet/pkg/util"
"github.com/dgrijalva/jwt-go"
"net/http"
)
func JWT() gin.HandlerFunc {
return func(c *gin.Context) {
var code int
var data interface{}
code = e.SUCCESS
token := c.GetHeader("token")
if token == "" {
code = e.INVALID_PARAMS
} else {
_, err := util.ParseToken(token)
if err != nil {
switch err.(*jwt.ValidationError).Errors {
case jwt.ValidationErrorExpired:
code = e.ERROR_AUTH_CHECK_TOKEN_TIMEOUT
default:
code = e.ERROR_AUTH_CHECK_TOKEN_FAIL
}
}
}
if code != e.SUCCESS {
c.JSON(http.StatusUnauthorized, gin.H{
"code": code,
"msg": e.GetMsg(code),
"data": data,
})
c.Abort()
return
}
c.Next()
}
}
package models
import "github.com/jinzhu/gorm"
type Auth struct {
ID int `gorm:"primary_key" json:"id"`
Username string `json:"username"`
Password string `json:"password"`
}
func CheckAuth(username, password string) (bool, error) {
var auth Auth
err := db.Select("id").Where(Auth{Username: username, Password: password}).First(&auth).Error
if err != nil && err != gorm.ErrRecordNotFound {
return false, err
}
if auth.ID > 0 {
return true, nil
}
return false, nil
}
package models
import (
"github.com/jinzhu/gorm"
)
type Coin struct {
Model
Sid string `json:"sid"`
Name string `json:"name"`
OptionalName string `json:"optional_name"`
Nickname string `json:"nickname"`
Icon string `json:"icon"`
Introduce string `json:"introduce"`
Official string `json:"official"`
Paper string `json:"paper"`
Exchange int `json:"exchange"`
Platform string `json:"platform"`
Chain string `json:"chain"`
Release string `json:"release"`
Price float64 `json:"price"`
AreaSearch string `json:"area_search"`
PublishCount float64 `json:"publish_count"`
CirculateCount float64 `json:"circulate_count"`
Decimals int `json:"decimals"`
Address string `json:"address"`
PlatformId string `json:"platform_id"`
Treaty int `json:"treaty"`
//Quotation Quotation `json:"quotation,omitempty"`
}
//type Quotation struct {
// Price float64 `json:"price"`
// Dollar float64 `json:"dollar"`
// Publish_Count float64 `json:"publish_count"`
// Circulate_Count float64 `json:"circulate_count"`
//}
func ExistCoinById(id int) (bool, error) {
var coin Coin
err := db.Select("id").Where("id = ?", id).First(&coin).Error
if err != nil && err != gorm.ErrRecordNotFound {
return false, err
}
if coin.ID > 0 {
return true, nil
}
return false, nil
}
func GetCoinTotal(maps interface{}) (int, error) {
var count int
if err := db.Model(&Coin{}).Where(maps).Count(&count).Error; err != nil {
return 0, err
}
return count, nil
}
func GetCoins(pageNum, pageSize int, maps interface{}) ([]*Coin, error) {
var coins []*Coin
err := db.Where(maps).Offset(pageNum).Limit(pageSize).Find(&coins).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
return coins, nil
}
func GetCoin(id int) (*Coin, error) {
var coin Coin
err := db.Table("coin").Where("id = ?", id).First(&coin).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
err = db.Model(&coin).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
return &coin, nil
}
func AddCoin(data map[string]interface{}) (error) {
coin := Coin{
Sid: data["sid"].(string),
Name: data["name"].(string),
OptionalName: data["optional_name"].(string),
Nickname: data["nickname"].(string),
Icon: data["icon"].(string),
Introduce: data["introduce"].(string),
Official: data["official"].(string),
Paper: data["paper"].(string),
Exchange: data["exchange"].(int),
Platform: data["platform"].(string),
Chain: data["chain"].(string),
Release: data["release"].(string),
Price: data["price"].(float64),
AreaSearch: data["area_search"].(string),
PublishCount: data["publish_count"].(float64),
CirculateCount: data["circulate_count"].(float64),
Decimals: data["decimals"].(int),
Address: data["address"].(string),
PlatformId: data["platform_id"].(string),
Treaty: data["treaty"].(int),
}
if err := db.Create(&coin).Error; err != nil {
return err
}
return nil
}
func EditCoin(id int, data interface{}) error {
if err := db.Model(&Coin{}).Where("id = ?", id).Updates(data).Error; err != nil {
return err
}
return nil
}
func DeleteCoin(id int) error {
if err := db.Where("id = ?", id).Delete(Coin{}).Error; err != nil {
return err
}
return nil
}
package models
import (
"fmt"
"log"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
_ "github.com/go-sql-driver/mysql"
"bwallet/pkg/setting"
"time"
)
var db *gorm.DB
type Model struct {
ID int `gorm:"primary_key" json:"id"`
//CreatedOn int `json:"created_on"`
//ModifiedOn int `json:"modified_on"`
//DeletedOn int `json:"deleted_on"`
}
// Setup initializes the database instance
func Setup() {
var err error
db, err = gorm.Open(setting.DatabaseSetting.Type, fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8&parseTime=True&loc=Local",
setting.DatabaseSetting.User,
setting.DatabaseSetting.Password,
setting.DatabaseSetting.Host,
setting.DatabaseSetting.Name))
if err != nil {
log.Fatalf("models.Setup err: %v", err)
}
gorm.DefaultTableNameHandler = func(db *gorm.DB, defaultTableName string) string {
//return setting.DatabaseSetting.TablePrefix + defaultTableName
return defaultTableName
}
db.SingularTable(true)
//db.Callback().Create().Replace("gorm:update_time_stamp", updateTimeStampForCreateCallback)
//db.Callback().Update().Replace("gorm:update_time_stamp", updateTimeStampForUpdateCallback)
//db.Callback().Delete().Replace("gorm:delete", deleteCallback)
db.DB().SetMaxIdleConns(10)
db.DB().SetMaxOpenConns(100)
}
// CloseDB closes database connection (unnecessary)
func CloseDB() {
defer db.Close()
}
// updateTimeStampForCreateCallback will set `CreatedOn`, `ModifiedOn` when creating
func updateTimeStampForCreateCallback(scope *gorm.Scope) {
if !scope.HasError() {
nowTime := time.Now().Unix()
if createTimeField, ok := scope.FieldByName("CreatedOn"); ok {
if createTimeField.IsBlank {
createTimeField.Set(nowTime)
}
}
if modifyTimeField, ok := scope.FieldByName("ModifiedOn"); ok {
if modifyTimeField.IsBlank {
modifyTimeField.Set(nowTime)
}
}
}
}
// updateTimeStampForUpdateCallback will set `ModifiedOn` when updating
func updateTimeStampForUpdateCallback(scope *gorm.Scope) {
if _, ok := scope.Get("gorm:update_column"); !ok {
scope.SetColumn("ModifiedOn", time.Now().Unix())
}
}
// deleteCallback will set `DeletedOn` where deleting
func deleteCallback(scope *gorm.Scope) {
if !scope.HasError() {
var extraOption string
if str, ok := scope.Get("gorm:delete_option"); ok {
extraOption = fmt.Sprint(str)
}
deletedOnField, hasDeletedOnField := scope.FieldByName("DeletedOn")
if !scope.Search.Unscoped && hasDeletedOnField {
scope.Raw(fmt.Sprintf(
"UPDATE %v SET %v=%v%v%v",
scope.QuotedTableName(),
scope.Quote(deletedOnField.DBName),
scope.AddToVars(time.Now().Unix()),
addExtraSpaceIfExist(scope.CombinedConditionSql()),
addExtraSpaceIfExist(extraOption),
)).Exec()
} else {
scope.Raw(fmt.Sprintf(
"DELETE FROM %v%v%v",
scope.QuotedTableName(),
addExtraSpaceIfExist(scope.CombinedConditionSql()),
addExtraSpaceIfExist(extraOption),
)).Exec()
}
}
}
// addExtraSpaceIfExist adds a separator
func addExtraSpaceIfExist(str string) string {
if str != "" {
return " " + str
}
return ""
}
package app
import (
"github.com/astaxie/beego/validation"
"github.com/gin-gonic/gin"
"net/http"
"bwallet/pkg/e"
"log"
)
// BindAndValid binds and validates data
func BindAndValid(c *gin.Context, form interface{}) (int, int) {
err := c.Bind(form)
if err != nil {
return http.StatusBadRequest, e.INVALID_PARAMS
}
valid := validation.Validation{}
check, err := valid.Valid(form)
if err != nil {
return http.StatusInternalServerError, e.ERROR
}
if !check {
MarkErrors(valid.Errors)
log.Println(valid.Errors)
return http.StatusBadRequest, e.INVALID_PARAMS
}
return http.StatusOK, e.SUCCESS
}
package app
import (
"github.com/astaxie/beego/validation"
"bwallet/pkg/logging"
)
func MarkErrors(errors []*validation.Error){
for _,err := range errors {
logging.Info(err.Key, err.Message)
}
return
}
package app
import (
"github.com/gin-gonic/gin"
"bwallet/pkg/e"
)
type Gin struct {
C *gin.Context
}
//为特定类型定义函数,即为类型对象定义方法
func (g *Gin) Response(httpCode, errCode int, data interface{}) {
g.C.JSON(httpCode, gin.H{
"code": httpCode,
"msg": e.GetMsg(errCode),
"data": data,
})
return
}
package e
const (
CACHE_ARTICLE = "article"
CACHE_TAG = "TAG"
)
package e
const (
SUCCESS = 200
ERROR = 500
INVALID_PARAMS = 400
ERROR_EXIST_TAG = 10001
ERROR_EXIST_TAG_FAIL = 10002
ERROR_NOT_EXIST_TAG = 10003
ERROR_GET_TAGS_FAIL = 10004
ERROR_COUNT_TAG_FAIL = 10005
ERROR_ADD_TAG_FAIL = 10006
ERROR_EDIT_TAG_FAIL = 10007
ERROR_DELETE_TAG_FAIL = 10008
ERROR_EXPORT_TAG_FAIL = 10009
ERROR_IMPORT_TAG_FAIL = 10010
ERROR_NOT_EXIST_ARTICLE = 10011
ERROR_CHECK_EXIST_ARTICLE_FAIL = 10012
ERROR_ADD_ARTICLE_FAIL = 10013
ERROR_DELETE_ARTICLE_FAIL = 10014
ERROR_EDIT_ARTICLE_FAIL = 10015
ERROR_COUNT_ARTICLE_FAIL = 10016
ERROR_GET_ARTICLES_FAIL = 10017
ERROR_GET_ARTICLE_FAIL = 10018
ERROR_GEN_ARTICLE_POSTER_FAIL = 10019
ERROR_AUTH_CHECK_TOKEN_FAIL = 20001
ERROR_AUTH_CHECK_TOKEN_TIMEOUT = 20002
ERROR_AUTH_TOKEN = 20003
ERROR_AUTH = 20004
ERROR_UPLOAD_SAVE_IMAGE_FAIL = 30001
ERROR_UPLOAD_CHECK_IMAGE_FAIL = 30002
ERROR_UPLOAD_CHECK_IMAGE_FORMAT = 30003
)
package e
var MsgFlags = map[int]string{
SUCCESS: "ok",
ERROR: "fail",
INVALID_PARAMS: "请求参数错误",
ERROR_EXIST_TAG: "已存在该标签名称",
ERROR_EXIST_TAG_FAIL: "获取已存在标签失败",
ERROR_NOT_EXIST_TAG: "该标签不存在",
ERROR_GET_TAGS_FAIL: "获取所有标签失败",
ERROR_COUNT_TAG_FAIL: "统计标签失败",
ERROR_ADD_TAG_FAIL: "新增标签失败",
ERROR_EDIT_TAG_FAIL: "修改标签失败",
ERROR_DELETE_TAG_FAIL: "删除标签失败",
ERROR_EXPORT_TAG_FAIL: "导出标签失败",
ERROR_IMPORT_TAG_FAIL: "导入标签失败",
ERROR_NOT_EXIST_ARTICLE: "该文章不存在",
ERROR_ADD_ARTICLE_FAIL: "新增文章失败",
ERROR_DELETE_ARTICLE_FAIL: "删除文章失败",
ERROR_CHECK_EXIST_ARTICLE_FAIL: "检查文章是否存在失败",
ERROR_EDIT_ARTICLE_FAIL: "修改文章失败",
ERROR_COUNT_ARTICLE_FAIL: "统计文章失败",
ERROR_GET_ARTICLES_FAIL: "获取多个文章失败",
ERROR_GET_ARTICLE_FAIL: "获取单个文章失败",
ERROR_GEN_ARTICLE_POSTER_FAIL: "生成文章海报失败",
ERROR_AUTH_CHECK_TOKEN_FAIL: "Token鉴权失败",
ERROR_AUTH_CHECK_TOKEN_TIMEOUT: "Token已超时",
ERROR_AUTH_TOKEN: "Token生成失败",
ERROR_AUTH: "Token错误",
ERROR_UPLOAD_SAVE_IMAGE_FAIL: "保存图片失败",
ERROR_UPLOAD_CHECK_IMAGE_FAIL: "检查图片失败",
ERROR_UPLOAD_CHECK_IMAGE_FORMAT: "校验图片错误,图片格式或大小有问题",
}
// GetMsg get error information based on Code
func GetMsg(code int) string {
msg, ok := MsgFlags[code]
if ok {
return msg
}
return MsgFlags[ERROR]
}
package export
import "bwallet/pkg/setting"
const EXT = ".xlsx"
// GetExcelFullUrl get the full access path of the Excel file
func GetExcelFullUrl(name string) string {
return setting.AppSetting.PrefixUrl + "/" + GetExcelPath() + name
}
// GetExcelPath get the relative save path of the Excel file
func GetExcelPath() string {
return setting.AppSetting.ExportSavePath
}
// GetExcelFullPath Get the full save path of the Excel file
func GetExcelFullPath() string {
return setting.AppSetting.RuntimeRootPath + GetExcelPath()
}
package file
import (
"fmt"
"io/ioutil"
"mime/multipart"
"os"
"path"
)
// GetSize get the file size
func GetSize(f multipart.File) (int, error) {
content, err := ioutil.ReadAll(f)
return len(content), err
}
// GetExt get the file ext
func GetExt(fileName string) string {
return path.Ext(fileName)
}
// CheckNotExist check if the file exists
func CheckNotExist(src string) bool {
_, err := os.Stat(src)
return os.IsNotExist(err)
}
// CheckPermission check if the file has permission
func CheckPermission(src string) bool {
_, err := os.Stat(src)
return os.IsPermission(err)
}
// IsNotExistMkDir create a directory if it does not exist
func IsNotExistMkDir(src string) error {
if notExist := CheckNotExist(src); notExist == true {
if err := MkDir(src); err != nil {
return err
}
}
return nil
}
// MkDir create a directory
func MkDir(src string) error {
err := os.MkdirAll(src, os.ModePerm)
if err != nil {
return err
}
return nil
}
// Open a file according to a specific mode
func Open(name string, flag int, perm os.FileMode) (*os.File, error) {
f, err := os.OpenFile(name, flag, perm)
if err != nil {
return nil, err
}
return f, nil
}
// MustOpen maximize trying to open the file
func MustOpen(fileName, filePath string) (*os.File, error) {
dir, err := os.Getwd()
if err != nil {
return nil, fmt.Errorf("os.Getwd err: %v", err)
}
src := dir + "/" + filePath
perm := CheckPermission(src)
if perm == true {
return nil, fmt.Errorf("file.CheckPermission Permission denied src: %s", src)
}
err = IsNotExistMkDir(src)
if err != nil {
return nil, fmt.Errorf("file.IsNotExistMkDir src: %s, err: %v", src, err)
}
f, err := Open(src+fileName, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644)
if err != nil {
return nil, fmt.Errorf("Fail to OpenFile :%v", err)
}
return f, nil
}
package gredis
import (
"github.com/gomodule/redigo/redis"
"bwallet/pkg/setting"
"time"
"encoding/json"
)
var RedisConn *redis.Pool
func Setup() error {
RedisConn = &redis.Pool{
MaxIdle: setting.RedisSetting.MaxIdle,
MaxActive: setting.RedisSetting.MaxActive,
IdleTimeout: setting.RedisSetting.IdleTimeout,
Dial: func() (redis.Conn, error) {
c, err := redis.Dial("tcp", setting.RedisSetting.Host)
if err != nil {
return nil, err
}
if setting.RedisSetting.Password != "" {
if _, err := c.Do("AUTH", setting.RedisSetting.Password); err != nil {
c.Close()
return nil, err
}
}
return c, err
},
TestOnBorrow: func(c redis.Conn, t time.Time) error {
_, err := c.Do("PING")
return err
},
}
return nil
}
func Set(key string, data interface{}, time int) error {
conn := RedisConn.Get()
defer conn.Close()
value, err := json.Marshal(data)
if err != nil {
return err
}
_, err = conn.Do("SET", key, value)
if err != nil {
return err
}
_, err = conn.Do("EXPIRE", key, time)
if err != nil {
return err
}
return nil
}
func Exists(key string) bool {
conn := RedisConn.Get()
defer conn.Close()
exists, err := redis.Bool(conn.Do("EXISTS", key))
if err != nil {
return false
}
return exists
}
func Get(key string) ([]byte, error) {
conn := RedisConn.Get()
defer conn.Close()
reply, err := redis.Bytes(conn.Do("GET", key))
if err != nil {
return nil, err
}
return reply, nil
}
func Delete(key string) (bool, error) {
conn := RedisConn.Get()
defer conn.Close()
return redis.Bool(conn.Do("DEL", key))
}
func LikeDeletes(key string) error {
conn := RedisConn.Get()
defer conn.Close()
keys, err := redis.Strings(conn.Do("KEYS", "*"+key+"*"))
if err != nil {
return err
}
for _, key := range keys {
_, err = Delete(key)
if err != nil {
return err
}
}
return nil
}
\ No newline at end of file
package logging
import (
"fmt"
"time"
"bwallet/pkg/setting"
)
// getLogFilePath get the log file save path
func getLogFilePath() string {
return fmt.Sprintf("%s%s", setting.AppSetting.RuntimeRootPath, setting.AppSetting.LogSavePath)
}
// getLogFileName get the save name of the log file
func getLogFileName() string {
return fmt.Sprintf("%s%s.%s",
setting.AppSetting.LogSaveName,
time.Now().Format(setting.AppSetting.TimeFormat),
setting.AppSetting.LogFileExt,
)
}
package logging
import (
"fmt"
"bwallet/pkg/file"
"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
)
// Setup initialize the log instance
func Setup() {
var err error
filePath := getLogFilePath()
fileName := getLogFileName()
F, err = file.MustOpen(fileName, filePath)
if err != nil {
log.Fatalf("logging.Setup err: %v", err)
}
logger = log.New(F, DefaultPrefix, log.LstdFlags)
}
// Debug output logs at debug level
func Debug(v ...interface{}) {
setPrefix(DEBUG)
logger.Println(v)
}
// Info output logs at info level
func Info(v ...interface{}) {
setPrefix(INFO)
logger.Println(v)
}
// Warn output logs at warn level
func Warn(v ...interface{}) {
setPrefix(WARNING)
logger.Println(v)
}
// Error output logs at error level
func Error(v ...interface{}) {
setPrefix(ERROR)
logger.Println(v)
}
// Fatal output logs at fatal level
func Fatal(v ...interface{}) {
setPrefix(FATAL)
logger.Fatalln(v)
}
// setPrefix set the prefix of the log output
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)
}
package qrcode
import (
"image/jpeg"
"github.com/boombuler/barcode"
"github.com/boombuler/barcode/qr"
"bwallet/pkg/file"
"bwallet/pkg/setting"
"bwallet/pkg/util"
)
type QrCode struct {
URL string
Width int
Height int
Ext string
Level qr.ErrorCorrectionLevel
Mode qr.Encoding
}
const (
EXT_JPG = ".jpg"
)
// NewQrCode initialize instance
func NewQrCode(url string, width, height int, level qr.ErrorCorrectionLevel, mode qr.Encoding) *QrCode {
return &QrCode{
URL: url,
Width: width,
Height: height,
Level: level,
Mode: mode,
Ext: EXT_JPG,
}
}
// GetQrCodePath get save path
func GetQrCodePath() string {
return setting.AppSetting.QrCodeSavePath
}
// GetQrCodeFullPath get full save path
func GetQrCodeFullPath() string {
return setting.AppSetting.RuntimeRootPath + setting.AppSetting.QrCodeSavePath
}
// GetQrCodeFullUrl get the full access path
func GetQrCodeFullUrl(name string) string {
return setting.AppSetting.PrefixUrl + "/" + GetQrCodePath() + name
}
// GetQrCodeFileName get qr file name
func GetQrCodeFileName(value string) string {
return util.EncodeMD5(value)
}
// GetQrCodeExt get qr file ext
func (q *QrCode) GetQrCodeExt() string {
return q.Ext
}
// Encode generate QR code
func (q *QrCode) Encode(path string) (string, string, error) {
name := GetQrCodeFileName(q.URL) + q.GetQrCodeExt()
src := path + name
if file.CheckNotExist(src) == true {
code, err := qr.Encode(q.URL, q.Level, q.Mode)
if err != nil {
return "", "", err
}
code, err = barcode.Scale(code, q.Width, q.Height)
if err != nil {
return "", "", err
}
f, err := file.MustOpen(name, path)
if err != nil {
return "", "", err
}
defer f.Close()
err = jpeg.Encode(f, code, nil)
if err != nil {
return "", "", err
}
}
return name, path, nil
}
package setting
import (
"log"
"time"
"github.com/go-ini/ini"
)
type App struct {
JwtSecret string
PageSize int
PrefixUrl string
RuntimeRootPath string
ImageSavePath string
ImageMaxSize int
ImageAllowExts []string
ExportSavePath string
QrCodeSavePath string
FontSavePath string
LogSavePath string
LogSaveName string
LogFileExt string
TimeFormat string
}
var AppSetting = &App{}
type Server struct {
RunMode string
HttpPort int
ReadTimeout time.Duration
WriteTimeout time.Duration
}
var ServerSetting = &Server{}
type Database struct {
Type string
User string
Password string
Host string
Name string
TablePrefix string
}
var DatabaseSetting = &Database{}
type Redis struct {
Host string
Password string
MaxIdle int
MaxActive int
IdleTimeout time.Duration
}
var RedisSetting = &Redis{}
var cfg *ini.File
// Setup initialize the configuration instance
func Setup() {
var err error
cfg, err = ini.Load("conf/app.ini")
if err != nil {
log.Fatalf("setting.Setup, fail to parse 'conf/app.ini': %v", err)
}
mapTo("app", AppSetting)
mapTo("server", ServerSetting)
mapTo("database", DatabaseSetting)
mapTo("redis", RedisSetting)
AppSetting.ImageMaxSize = AppSetting.ImageMaxSize * 1024 * 1024
ServerSetting.ReadTimeout = ServerSetting.ReadTimeout * time.Second
ServerSetting.WriteTimeout = ServerSetting.ReadTimeout * time.Second
RedisSetting.IdleTimeout = RedisSetting.IdleTimeout * time.Second
}
// mapTo map section
func mapTo(section string, v interface{}) {
err := cfg.Section(section).MapTo(v)
if err != nil {
log.Fatalf("Cfg.MapTo RedisSetting err: %v", err)
}
}
package upload
import (
"fmt"
"log"
"mime/multipart"
"os"
"path"
"strings"
"bwallet/pkg/file"
"bwallet/pkg/logging"
"bwallet/pkg/setting"
"bwallet/pkg/util"
)
// GetImageFullUrl get the full access path
func GetImageFullUrl(name string) string {
return setting.AppSetting.PrefixUrl + "/" + GetImagePath() + name
}
// GetImageName get image name
func GetImageName(name string) string {
ext := path.Ext(name)
fileName := strings.TrimSuffix(name, ext)
fileName = util.EncodeMD5(fileName)
return fileName + ext
}
// GetImagePath get save path
func GetImagePath() string {
return setting.AppSetting.ImageSavePath
}
// GetImageFullPath get full save path
func GetImageFullPath() string {
return setting.AppSetting.RuntimeRootPath + GetImagePath()
}
// CheckImageExt check image file ext
func CheckImageExt(fileName string) bool {
ext := file.GetExt(fileName)
for _, allowExt := range setting.AppSetting.ImageAllowExts {
if strings.ToUpper(allowExt) == strings.ToUpper(ext) {
return true
}
}
return false
}
// CheckImageSize check image size
func CheckImageSize(f multipart.File) bool {
size, err := file.GetSize(f)
if err != nil {
log.Println(err)
logging.Warn(err)
return false
}
return size <= setting.AppSetting.ImageMaxSize
}
// CheckImage check if the file exists
func CheckImage(src string) error {
dir, err := os.Getwd()
if err != nil {
return fmt.Errorf("os.Getwd err: %v", err)
}
err = file.IsNotExistMkDir(dir + "/" + src)
if err != nil {
return fmt.Errorf("file.IsNotExistMkDir err: %v", err)
}
perm := file.CheckPermission(src)
if perm == true {
return fmt.Errorf("file.CheckPermission Permission denied src: %s", src)
}
return nil
}
package util
import (
"github.com/dgrijalva/jwt-go"
"time"
)
var jwtSecret []byte
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{
EncodeMD5(username),
EncodeMD5(password),
jwt.StandardClaims{
ExpiresAt: expireTime.Unix(),
Issuer: "gin-blog",
},
}
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
}
package util
import (
"crypto/md5"
"encoding/hex"
)
func EncodeMD5(value string) string{
m:= md5.New()
m.Write([]byte(value))
return hex.EncodeToString(m.Sum(nil))
}
\ No newline at end of file
package util
import (
"github.com/Unknwon/com"
"github.com/gin-gonic/gin"
"bwallet/pkg/setting"
)
// GetPage get page parameters
func GetPage(c *gin.Context) int {
result := 0
page := com.StrTo(c.Query("page")).MustInt()
if page > 0 {
result = (page - 1) * setting.AppSetting.PageSize
}
return result
}
package util
import "bwallet/pkg/setting"
// Setup Initialize the util
func Setup() {
jwtSecret = []byte(setting.AppSetting.JwtSecret)
}
\ No newline at end of file
package api
import (
"github.com/gin-gonic/gin"
"github.com/astaxie/beego/validation"
"bwallet/pkg/e"
"bwallet/pkg/util"
"net/http"
"bwallet/pkg/app"
"bwallet/service/auth_service"
)
type auth struct {
Username string `valid:"Required; MaxSize(50)"`
Password string `valid:"Required; MaxSize(50)"`
}
func GetAuth(c *gin.Context){
appG := app.Gin{C: c}
valid := validation.Validation{}
username := c.PostForm("username")
password := c.PostForm("password")
a := auth{Username: username, Password: password}
ok, _ := valid.Valid(&a)
if !ok {
app.MarkErrors(valid.Errors)
appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
return
}
authService := auth_service.Auth{Username: username, Password: password}
isExist, err := authService.Check()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_AUTH_CHECK_TOKEN_FAIL, nil)
return
}
if !isExist {
appG.Response(http.StatusUnauthorized, e.ERROR_AUTH, nil)
return
}
token, err := util.GenerateToken(username, password)
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_AUTH_TOKEN, nil)
return
}
appG.Response(http.StatusOK, e.SUCCESS, map[string]string{
"token": token,
})
}
package api
import (
"net/http"
"github.com/gin-gonic/gin"
"bwallet/pkg/app"
"bwallet/pkg/e"
"bwallet/pkg/logging"
"bwallet/pkg/upload"
)
// @Summary Import Image
// @Produce json
// @Param image formData file true "Image File"
// @Success 200 {object} app.Response
// @Failure 500 {object} app.Response
// @Router /api/v1/tags/import [post]
func UploadImage(c *gin.Context) {
appG := app.Gin{C: c}
file, image, err := c.Request.FormFile("image")
if err != nil {
logging.Warn(err)
appG.Response(http.StatusInternalServerError, e.ERROR, nil)
return
}
if image == nil {
appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
return
}
imageName := upload.GetImageName(image.Filename)
fullPath := upload.GetImageFullPath()
savePath := upload.GetImagePath()
src := fullPath + imageName
if !upload.CheckImageExt(imageName) || !upload.CheckImageSize(file) {
appG.Response(http.StatusBadRequest, e.ERROR_UPLOAD_CHECK_IMAGE_FORMAT, nil)
return
}
err = upload.CheckImage(fullPath)
if err != nil {
logging.Warn(err)
appG.Response(http.StatusInternalServerError, e.ERROR_UPLOAD_CHECK_IMAGE_FAIL, nil)
return
}
if err := c.SaveUploadedFile(image, src); err != nil {
logging.Warn(err)
appG.Response(http.StatusInternalServerError, e.ERROR_UPLOAD_SAVE_IMAGE_FAIL, nil)
return
}
appG.Response(http.StatusOK, e.SUCCESS, map[string]string{
"image_url": upload.GetImageFullUrl(imageName),
"image_save_url": savePath + imageName,
})
}
package v1
import (
"github.com/gin-gonic/gin"
"github.com/astaxie/beego/validation"
"github.com/Unknwon/com"
"net/http"
"bwallet/pkg/app"
"bwallet/pkg/e"
"bwallet/service/coin_service"
"bwallet/pkg/util"
"bwallet/pkg/setting"
)
type AddCoinForm struct {
Sid string `form:"sid" valid:"MinSize(2);MaxSize(10)"`
Name string `form:"name" valid:"Required;MinSize(2);MaxSize(50)"`
OptionalName string `form:"optional_name" valid:"MaxSize(10)"`
Nickname string `form:"nickname" valid:"MaxSize(100)"`
Icon string `form:"icon"`
Introduce string `form:"introduce" valid:"MaxSize(500)"`
Official string `form:"official" valid:"MaxSize(5)"`
Paper string `form:"paper" valid:"MaxSize(10)"`
Exchange int `form:"exchange" valid:"Max(10)"`
Platform string `form:"platform" valid:"MaxSize(10)"`
Chain string `form:"chain" valid:"MaxSize(10)"`
Release string `form:"release" valid:"Required"`
Price float64 `form:"price"`
AreaSearch string `form:"area_search" valid:"MaxSize(100)"`
PublishCount float64 `form:"publish_count"`
CirculateCount float64 `form:"circulate_count"`
Decimals int `form:"decimals" valid:"Max(10)"`
Address string `form:"address" valid:"MaxSize(50)"`
PlatformId string `form:"platform_id" valid:"MaxSize(10)"`
Treaty int `form:"treaty" valid:"Range(1,2)"`
}
type EditCoinForm struct {
Id int `form:"id" valid:"Required;Min(1)"`
Sid string `form:"sid" valid:"MinSize(2);MaxSize(10)"`
Name string `form:"name" valid:"Required;MinSize(2);MaxSize(50)"`
OptionalName string `form:"optional_name" valid:"MaxSize(10)"`
Nickname string `form:"nickname" valid:"MaxSize(100)"`
Icon string `form:"icon"`
Introduce string `form:"introduce" valid:"MaxSize(500)"`
Official string `form:"official" valid:"MaxSize(5)"`
Paper string `form:"paper" valid:"MaxSize(10)"`
Exchange int `form:"exchange" valid:"Max(10)"`
Platform string `form:"platform" valid:"MaxSize(10)"`
Chain string `form:"chain" valid:"MaxSize(10)"`
Release string `form:"release" valid:"Required"`
Price float64 `form:"price"`
AreaSearch string `form:"area_search" valid:"MaxSize(100)"`
PublishCount float64 `form:"publish_count"`
CirculateCount float64 `form:"circulate_count"`
Decimals int `form:"decimals" valid:"Max(10)"`
Address string `form:"address" valid:"MaxSize(50)"`
PlatformId string `form:"platform_id" valid:"MaxSize(10)"`
Treaty int `form:"treaty" valid:"Range(1,2)"`
}
func GetCoin(c *gin.Context) {
appG := app.Gin{c}
id := com.StrTo(c.Param("id")).MustInt()
valid := validation.Validation{}
valid.Min(id, 1, "id").Message("ID必须大于0")
if valid.HasErrors() {
app.MarkErrors(valid.Errors)
appG.Response(http.StatusOK, e.INVALID_PARAMS, nil)
return
}
coinService := coin_service.Coin{Id: id}
exists, err := coinService.ExistById()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_CHECK_EXIST_ARTICLE_FAIL, nil)
return
}
if (!exists) {
appG.Response(http.StatusOK, e.ERROR_NOT_EXIST_ARTICLE, nil)
return
}
coin, err := coinService.Get()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_GET_ARTICLE_FAIL, nil)
return
}
appG.Response(http.StatusOK, e.SUCCESS, coin)
}
func GetCoins(c *gin.Context) {
appG := app.Gin{C: c}
valid := validation.Validation{}
name := ""
if arg := c.Query("name"); arg != "" {
name = c.Query("name")
}
platform := ""
if arg := c.Query("platform"); arg != "" {
platform = c.Query("platform")
}
chain := ""
if arg := c.Query("chain"); arg != "" {
chain = c.Query("chain")
}
if valid.HasErrors() {
app.MarkErrors(valid.Errors)
appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
return
}
coinService := coin_service.Coin{
Name: name,
Chain: chain,
Platform: platform,
PageNum: util.GetPage(c),
PageSize: setting.AppSetting.PageSize,
}
total, err := coinService.Count()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_COUNT_ARTICLE_FAIL, nil)
return
}
coins, err := coinService.GetAll()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_GET_ARTICLES_FAIL, nil)
return
}
data := make(map[string]interface{})
data["lists"] = coins
data["total"] = total
appG.Response(http.StatusOK, e.SUCCESS, data)
}
func AddCoin(c *gin.Context) {
var (
appG = app.Gin{C: c}
form AddCoinForm
)
httpCode, errCode := app.BindAndValid(c, &form)
if errCode != e.SUCCESS {
appG.Response(httpCode, errCode, nil)
return
}
coinService := coin_service.Coin{
Sid: form.Sid,
Name: form.Name,
OptionalName: form.OptionalName,
Nickname: form.Nickname,
Icon: form.Icon,
Introduce: form.Introduce,
Official: form.Official,
Paper: form.Paper,
Exchange: form.Exchange,
Platform: form.Platform,
Chain: form.Chain,
Release: form.Release,
Price: form.Price,
AreaSearch: form.AreaSearch,
PublishCount: form.PublishCount,
CirculateCount: form.CirculateCount,
Decimals: form.Decimals,
Address: form.Address,
PlatformId: form.PlatformId,
Treaty: form.Treaty,
}
if err := coinService.Add(); err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_ADD_ARTICLE_FAIL, nil)
return
}
appG.Response(http.StatusOK, e.SUCCESS, nil)
}
func EditCoin(c *gin.Context) {
var (
appG = app.Gin{C: c}
form = EditCoinForm{Id: com.StrTo(c.Param("id")).MustInt()}
)
httpCode, errCode := app.BindAndValid(c, &form)
if errCode != e.SUCCESS {
appG.Response(httpCode, errCode, nil)
return
}
coinService := coin_service.Coin{
Id: form.Id,
Sid: form.Sid,
Name: form.Name,
OptionalName: form.OptionalName,
Nickname: form.Nickname,
Icon: form.Icon,
Introduce: form.Introduce,
Official: form.Official,
Paper: form.Paper,
Exchange: form.Exchange,
Platform: form.Platform,
Chain: form.Chain,
Release: form.Release,
Price: form.Price,
AreaSearch: form.AreaSearch,
PublishCount: form.PublishCount,
CirculateCount: form.CirculateCount,
Decimals: form.Decimals,
Address: form.Address,
PlatformId: form.PlatformId,
Treaty: form.Treaty,
}
exists, err := coinService.ExistById()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_CHECK_EXIST_ARTICLE_FAIL, nil)
return
}
if !exists {
appG.Response(http.StatusOK, e.ERROR_NOT_EXIST_ARTICLE, nil)
return
}
if err := coinService.Edit(); err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_ADD_ARTICLE_FAIL, nil)
return
}
appG.Response(http.StatusOK, e.SUCCESS, nil)
}
func DeleteCoin(c *gin.Context) {
appG := app.Gin{C: c}
valid := validation.Validation{}
id := com.StrTo(c.Param("id")).MustInt()
valid.Min(id, 1, "id").Message("ID必须大于0")
if valid.HasErrors() {
app.MarkErrors(valid.Errors)
appG.Response(http.StatusOK, e.INVALID_PARAMS, nil)
return
}
coinService := coin_service.Coin{Id: id}
exists, err := coinService.ExistById()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_CHECK_EXIST_ARTICLE_FAIL, nil)
return
}
if !exists {
appG.Response(http.StatusOK, e.ERROR_NOT_EXIST_ARTICLE, nil)
return
}
err = coinService.Delete()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_DELETE_ARTICLE_FAIL, nil)
return
}
appG.Response(http.StatusOK, e.SUCCESS, nil)
}
package routers
import (
"github.com/gin-gonic/gin"
"net/http"
"bwallet/pkg/upload"
"bwallet/pkg/qrcode"
"bwallet/routers/api"
"bwallet/routers/api/v1"
)
func InitRouter() *gin.Engine {
r := gin.New()
r.Use(gin.Logger())
r.Use(gin.Recovery())
r.StaticFS("/upload/images", http.Dir(upload.GetImageFullPath()))
r.StaticFS("/qrcode", http.Dir(qrcode.GetQrCodeFullPath()))
r.POST("/auth", api.GetAuth)
r.POST("/upload", api.UploadImage)
apiv1 := r.Group("/api")
//apiv1.Use(jwt.JWT())
{
apiv1.GET("/coins", v1.GetCoins)
apiv1.POST("/coin", v1.AddCoin)
apiv1.GET("/coin/:id", v1.GetCoin)
apiv1.PUT("/coin/:id", v1.EditCoin)
apiv1.DELETE("/coin/:id", v1.DeleteCoin)
}
return r
}
package auth_service
import "bwallet/models"
type Auth struct {
Username string
Password string
}
func (a *Auth) Check() (bool, error){
return models.CheckAuth(a.Username, a.Password)
}
package cache_service
import (
"strings"
)
type Ticker struct {
Coin string
}
func (ticker *Ticker) GetTicker() (map[string]interface{}) {
maps := make(map[string]interface{})
if strings.ToUpper(ticker.Coin) == "CCNY" {
maps["price"] = 1.11
maps["dollar"] = 1.11
}
return maps
}
package coin_service
import (
"bwallet/models"
)
type Coin struct {
Id int
Sid string
Name string
OptionalName string
Nickname string
Icon string
Introduce string
Official string
Paper string
Exchange int
Platform string
Chain string
Release string
Price float64
AreaSearch string
PublishCount float64
CirculateCount float64
Decimals int
Address string
PlatformId string
Treaty int
PageNum int
PageSize int
}
func (c *Coin) Get() (*models.Coin, error) {
coin, err := models.GetCoin(c.Id)
if err != nil {
return nil, err
}
return coin, nil
}
func (c *Coin) GetAll() ([]*models.Coin, error) {
var coins []*models.Coin
coins, err := models.GetCoins(c.PageNum, c.PageSize, c.getMaps())
if err != nil {
return nil, err
}
return coins, nil
}
func (c *Coin) Add() error {
coin := map[string]interface{}{
"sid": c.Sid,
"name": c.Name,
"optional_name": c.OptionalName,
"nickname": c.Nickname,
"icon": c.Icon,
"introduce": c.Introduce,
"official": c.Official,
"paper": c.Paper,
"exchange": c.Exchange,
"platform": c.Platform,
"chain": c.Chain,
"release": c.Release,
"price": c.Price,
"area_search": c.AreaSearch,
"publish_count": c.PublishCount,
"circulate_count": c.CirculateCount,
"decimals": c.Decimals,
"address": c.Address,
"platform_id": c.PlatformId,
"treaty": c.Treaty,
}
if err := models.AddCoin(coin); err != nil {
return err
}
return nil
}
func (c *Coin) Edit() error {
return models.EditCoin(c.Id, map[string]interface{}{
"sid": c.Sid,
"name": c.Name,
"optional_name": c.OptionalName,
"nickname": c.Nickname,
"icon": c.Icon,
"introduce": c.Introduce,
"official": c.Official,
"paper": c.Paper,
"exchange": c.Exchange,
"platform": c.Platform,
"chain": c.Chain,
"release": c.Release,
"price": c.Price,
"area_search": c.AreaSearch,
"publish_count": c.PublishCount,
"circulate_count": c.CirculateCount,
"decimals": c.Decimals,
"address": c.Address,
"platform_id": c.PlatformId,
"treaty": c.Treaty,
})
}
func (c *Coin) ExistById() (bool, error) {
return models.ExistCoinById(c.Id)
}
func (c *Coin) Count() (int, error) {
return models.GetCoinTotal(c.getMaps())
}
func (c *Coin) Delete() error {
return models.DeleteCoin(c.Id)
}
func (c *Coin) getMaps() (map[string]interface{}) {
maps := make(map[string]interface{})
if c.Name != "" {
maps["name"] = c.Name
}
if c.Chain != "" {
maps["chain"] = c.Chain
}
if c.Platform != "" {
maps["platform"] = c.Platform
}
return maps
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment