Skip to content

Commit

Permalink
+ 文件上传接口
Browse files Browse the repository at this point in the history
  • Loading branch information
trheyi committed Oct 12, 2021
1 parent 1a91125 commit 3d2d97f
Show file tree
Hide file tree
Showing 14 changed files with 322 additions and 96 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@
.tmp
dist
ui
^ui/index.html
^ui/index.html
app/data/*/*
13 changes: 13 additions & 0 deletions app/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,18 @@
"name": "象传应用",
"short": "象传",
"description": "象传应用后台",
"storage": {
"default": "oss",
"oss": {
"comment": "https://www.alibabacloud.com/help/zh/doc-detail/100624.htm",
"endpoint": "oss-cn-hangzhou.aliyuncs.com",
"id": "LTAI5tLC5cnKqF2eB4L7De3S",
"secret": "OkD17XjvjNQoiLgRyyjIsTnviULr0w",
"roleArn": "RamOssTest",
"sessionName": "SessionTest"
},
"cos": {},
"s3": {}
},
"option": {}
}
1 change: 1 addition & 0 deletions app/data/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
文件上传
18 changes: 16 additions & 2 deletions cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,23 @@ var startCmd = &cobra.Command{
global.Load(config.Conf)

// 打印应用目录信息
fmt.Printf(color.GreenString("\n应用根目录: %s\n", config.Conf.Root))
fmt.Printf(color.WhiteString("\n---------------------------------"))
fmt.Printf(color.GreenString("\n应用名称: %s v%s", global.App.Name, global.App.Version))
fmt.Printf(color.GreenString("\n应用根目录: %s", config.Conf.Root))
fmt.Printf(color.GreenString("\n数据存储目录: %s", config.Conf.RootData))
fmt.Printf(color.GreenString("\n数据存储引擎: %s", global.App.Storage.Default))
fmt.Printf(color.WhiteString("\n---------------------------------\n\n"))

fmt.Printf(color.GreenString("\n已注册API"))
fmt.Printf(color.WhiteString("\n---------------------------------"))

for _, api := range gou.APIs { // API信息
if len(api.HTTP.Paths) <= 0 {
continue
}

fmt.Printf(color.CyanString("\n%s(%d)\n", api.Name, len(api.HTTP.Paths)))
for _, p := range api.HTTP.Paths {

fmt.Println(
colorMehtod(p.Method),
color.WhiteString(filepath.Join("/api", api.HTTP.Group, p.Path)),
Expand All @@ -56,6 +68,8 @@ var startCmd = &cobra.Command{
port = ""
}

fmt.Printf(color.GreenString("\n\n访问入口"))
fmt.Printf(color.WhiteString("\n---------------------------------"))
fmt.Printf(color.GreenString("\n前台界面: http://%s%s/\n", domain, port))
fmt.Printf(color.GreenString("管理后台: http://%s%s/xiang/login\n", domain, port))
fmt.Printf(color.GreenString("API 接口: http://%s%s/api\n", domain, port))
Expand Down
10 changes: 3 additions & 7 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ type Config struct {
XiangConfig
Service ServiceConfig `json:"service,omitempty"`
Database DatabaseConfig `json:"database,omitempty"`
Storage StorageConfig `json:"storage,omitempty"`
JWT JWTConfig `json:"jwt,omitempty"`
Log LogConfig `json:"log,omitempty"`
}
Expand Down Expand Up @@ -65,12 +64,6 @@ type DatabaseConfig struct {
AESKey string `json:"aeskey,omitempty" env:"XIANG_DB_AESKEY"` // 加密存储KEY
}

// StorageConfig 存储配置
type StorageConfig struct {
Debug bool `json:"debug,omitempty" env:"XIANG_STOR_DEBUG" envDefault:"false"` // DEBUG 开关
Path string `json:"path,omitempty" env:"XIANG_STOR_PATH" envDefault:"fs:///data/xiang"` // 数据存储目录
}

// JWTConfig JWT配置
type JWTConfig struct {
Debug bool `json:"debug,omitempty" env:"XIANG_JWT_DEBUG" envDefault:"false"` // DEBUG 开关
Expand Down Expand Up @@ -185,8 +178,11 @@ func (cfg *Config) SetDefaults() {
// 过滤数据
cfg.RootDB = strings.TrimPrefix(cfg.RootDB, "fs://")
cfg.RootDB = strings.TrimPrefix(cfg.RootDB, "file://")
cfg.RootData = strings.TrimPrefix(cfg.RootData, "fs://")
cfg.RootData = strings.TrimPrefix(cfg.RootData, "file://")
cfg.RootUI = strings.TrimPrefix(cfg.RootUI, "fs://")
cfg.RootUI = strings.TrimPrefix(cfg.RootUI, "file://")

}

// SetEnvFile 指定ENV文件
Expand Down
3 changes: 0 additions & 3 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,6 @@ func TestNewConfig(t *testing.T) {
assert.Equal(t, cfg.JWT.Debug, vBool(os.Getenv("XIANG_JWT_DEBUG")))
assert.Equal(t, cfg.JWT.Secret, os.Getenv("XIANG_JWT_SECRET"))

assert.Equal(t, cfg.Storage.Debug, vBool(os.Getenv("XIANG_STOR_DEBUG")))
assert.Equal(t, cfg.Storage.Path, os.Getenv("XIANG_STOR_PATH"))

assert.Equal(t, cfg.Log.Access, os.Getenv("XIANG_LOG_ACCESS"))
assert.Equal(t, cfg.Log.Error, os.Getenv("XIANG_LOG_ERROR"))
assert.Equal(t, cfg.Log.DB, os.Getenv("XIANG_LOG_DB"))
Expand Down
90 changes: 68 additions & 22 deletions data/bindata.go

Large diffs are not rendered by default.

81 changes: 81 additions & 0 deletions global/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package global

import (
jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/xiang/data"
"github.com/yaoapp/xiang/xfs"
)

// App 应用信息
var App AppInfo

// AppInfo 应用信息
type AppInfo struct {
Name string `json:"name,omitempty"`
Short string `json:"short,omitempty"`
Version string `json:"version,omitempty"`
Description string `json:"description,omitempty"`
Icons map[string]string `json:"icons,omitempty"`
Storage AppStorage `json:"storage,omitempty"`
Option map[string]interface{} `json:"option,omitempty"`
}

// AppStorage 应用存储
type AppStorage struct {
Default string `json:"default"`
Buckets map[string]string `json:"buckets,omitempty"`
S3 map[string]interface{} `json:"s3,omitempty"`
OSS map[string]interface{} `json:"oss,omitempty"`
COS map[string]interface{} `json:"cos,omitempty"`
}

// LoadAppInfo 读取应用信息
func LoadAppInfo(root string) {
info := defaultAppInfo()
fs := xfs.New(root)
if fs.MustExists("/app.json") {
err := jsoniter.Unmarshal(fs.MustReadFile("/app.json"), &info)
if err != nil {
exception.New("解析应用失败 %s", 500, err).Throw()
}
}

if fs.MustExists("/xiang/icons/icon.icns") {
info.Icons["icns"] = xfs.Encode(fs.MustReadFile("/xiang/icons/icon.icns"))
}

if fs.MustExists("/xiang/icons/icon.ico") {
info.Icons["ico"] = xfs.Encode(fs.MustReadFile("/xiang/icons/icon.ico"))
}

if fs.MustExists("/xiang/icons/icon.png") {
info.Icons["png"] = xfs.Encode(fs.MustReadFile("/xiang/icons/icon.png"))
}

App = info
}

// defaultAppInfo 读取默认应用信息
func defaultAppInfo() AppInfo {
info := AppInfo{}
err := jsoniter.Unmarshal(data.MustAsset("xiang/data/app.json"), &info)
if err != nil {
exception.New("解析默认应用失败 %s", 500, err).Throw()
}

info.Version = VERSION
info.Icons["icns"] = xfs.Encode(data.MustAsset("xiang/data/icons/icon.icns"))
info.Icons["ico"] = xfs.Encode(data.MustAsset("xiang/data/icons/icon.ico"))
info.Icons["png"] = xfs.Encode(data.MustAsset("xiang/data/icons/icon.png"))

return info
}

// Public 输出公共信息
func (app AppInfo) Public() AppInfo {
app.Storage.COS = nil
app.Storage.OSS = nil
app.Storage.S3 = nil
return app
}
62 changes: 3 additions & 59 deletions global/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@ import (
"path/filepath"
"strings"

jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/data"
"github.com/yaoapp/xiang/table"
"github.com/yaoapp/xiang/xfs"
"github.com/yaoapp/xun/capsule"
)

Expand All @@ -39,19 +37,6 @@ type AppRoot struct {
Data string
}

// AppInfo 应用信息
type AppInfo struct {
Name string `json:"name,omitempty"`
Short string `json:"short,omitempty"`
Version string `json:"version,omitempty"`
Description string `json:"description,omitempty"`
Icons map[string]string `json:"icons,omitempty"`
Option map[string]interface{} `json:"option,omitempty"`
}

// App 应用信息
var App AppInfo

// Load 根据配置加载 API, FLow, Model, Plugin
func Load(cfg config.Config) {

Expand Down Expand Up @@ -121,53 +106,12 @@ func AppInit(cfg config.Config) {
}
}

if _, err := os.Stat(cfg.RootTable); os.IsNotExist(err) {
err := os.MkdirAll(cfg.RootTable, os.ModePerm)
if err != nil {
log.Panicf("创建目录失败(%s) %s", cfg.RootTable, err)
}
}
}

// LoadAppInfo 读取应用信息
func LoadAppInfo(root string) {
info := defaultAppInfo()
fs := xfs.New(root)
if fs.MustExists("/app.json") {
err := jsoniter.Unmarshal(fs.MustReadFile("/app.json"), &info)
if _, err := os.Stat(cfg.RootData); os.IsNotExist(err) {
err := os.MkdirAll(cfg.RootData, os.ModePerm)
if err != nil {
exception.New("解析应用失败 %s", 500, err).Throw()
log.Panicf("创建目录失败(%s) %s", cfg.RootData, err)
}
}

if fs.MustExists("/xiang/icons/icon.icns") {
info.Icons["icns"] = xfs.Encode(fs.MustReadFile("/xiang/icons/icon.icns"))
}

if fs.MustExists("/xiang/icons/icon.ico") {
info.Icons["ico"] = xfs.Encode(fs.MustReadFile("/xiang/icons/icon.ico"))
}

if fs.MustExists("/xiang/icons/icon.png") {
info.Icons["png"] = xfs.Encode(fs.MustReadFile("/xiang/icons/icon.png"))
}
App = info
}

// defaultAppInfo 读取默认应用信息
func defaultAppInfo() AppInfo {
info := AppInfo{}
err := jsoniter.Unmarshal(data.MustAsset("xiang/data/app.json"), &info)
if err != nil {
exception.New("解析默认应用失败 %s", 500, err).Throw()
}

info.Version = VERSION
info.Icons["icns"] = xfs.Encode(data.MustAsset("xiang/data/icons/icon.icns"))
info.Icons["ico"] = xfs.Encode(data.MustAsset("xiang/data/icons/icon.ico"))
info.Icons["png"] = xfs.Encode(data.MustAsset("xiang/data/icons/icon.png"))

return info
}

// LoadEngine 加载引擎的 API, Flow, Model 配置
Expand Down
2 changes: 1 addition & 1 deletion global/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func processPing(process *gou.Process) interface{} {
// processInspect 返回系统信息
func processInspect(process *gou.Process) interface{} {
App.Icons["favicon"] = "/api/xiang/favicon.ico"
return App
return App.Public()
}

// processFavicon 运行模型 MustCreate
Expand Down
85 changes: 85 additions & 0 deletions xfs/process.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package xfs

import (
"crypto/md5"
"encoding/hex"
"fmt"
"os"
"path/filepath"
"strings"
"time"

"github.com/yaoapp/gou"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/maps"
"github.com/yaoapp/xun"
)

func init() {
// 注册处理器
gou.RegisterProcessHandler("xiang.fs.Upload", processUpload)
gou.RegisterProcessHandler("xiang.fs.GetToken", processGetToken)
gou.RegisterProcessHandler("xiang.fs.GetURL", processGetURL)
gou.RegisterProcessHandler("xiang.fs.ReadFile", processReadFile)
}

// processUpload 上传文件到本地服务器
func processUpload(process *gou.Process) interface{} {
process.ValidateArgNums(1)
tmpfile, ok := process.Args[0].(xun.UploadFile)
if !ok {
exception.New("上传文件参数错误", 400, process.Args[0]).Throw()
}

hash := md5.Sum([]byte(time.Now().Format("20060102-15:04:05")))
fingerprint := string(hex.EncodeToString(hash[:]))
fingerprint = strings.ToUpper(fingerprint)

dir := time.Now().Format("20060102")
ext := filepath.Ext(tmpfile.Name)
filename := filepath.Join(dir, fmt.Sprintf("%s%s", fingerprint, ext))
Stor.MustMkdirAll(dir, os.ModePerm)

content, err := New("/").ReadFile(tmpfile.TempFile)
if err != nil {
exception.New("不能读取上传文件 %s", 500, err.Error()).Throw()
}

Stor.MustWriteFile(filename, content, os.ModePerm)
return filename
}

// processGetContent 返回文件正文
func processReadFile(process *gou.Process) interface{} {
process.ValidateArgNums(1)
filename := process.ArgsString(0)
encode := process.ArgsBool(1, true)

stats, err := Stor.Stat(filename)
if err != nil {
exception.New("读取文件信息失败 %s", 500, err.Error()).Throw()
}

var content string
body := Stor.MustReadFile(filename)
if encode {
content = Encode(body)
} else {
content = string(body)
}

return maps.Map{
"size": stats.Size(),
"content": content,
}
}

// processGetToken 上传文件到腾讯云对象存储 COS
func processGetToken(process *gou.Process) interface{} {
return nil
}

// processGetURL 返回文件CDN地址
func processGetURL(process *gou.Process) interface{} {
return nil
}
2 changes: 1 addition & 1 deletion xfs/xfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type File interface {
}

func init() {
Stor = New(config.Conf.Storage.Path)
Stor = New(config.Conf.RootData)
}

// New 创建文件系统
Expand Down
Loading

0 comments on commit 3d2d97f

Please sign in to comment.