Finish all the i18n things of code.
This commit is contained in:
parent
e37b248c8c
commit
54c5905a58
@ -2,7 +2,6 @@ package rest
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/eyebluecn/tank/code/core"
|
"github.com/eyebluecn/tank/code/core"
|
||||||
"github.com/eyebluecn/tank/code/tool/i18n"
|
|
||||||
"github.com/eyebluecn/tank/code/tool/result"
|
"github.com/eyebluecn/tank/code/tool/result"
|
||||||
"github.com/eyebluecn/tank/code/tool/util"
|
"github.com/eyebluecn/tank/code/tool/util"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -119,11 +118,7 @@ func (this *AlienController) FetchUploadToken(writer http.ResponseWriter, reques
|
|||||||
//store dir path
|
//store dir path
|
||||||
dirPath := request.FormValue("dirPath")
|
dirPath := request.FormValue("dirPath")
|
||||||
|
|
||||||
if filename == "" {
|
filename = CheckMatterName(request, filename)
|
||||||
panic(result.BadRequest("filename cannot be null"))
|
|
||||||
} else if m, _ := regexp.MatchString(MATTER_NAME_PATTERN, filename); m {
|
|
||||||
panic(result.BadRequestI18n(request, i18n.MatterNameContainSpecialChars))
|
|
||||||
}
|
|
||||||
|
|
||||||
var expireTime time.Time
|
var expireTime time.Time
|
||||||
if expireTimeStr == "" {
|
if expireTimeStr == "" {
|
||||||
@ -288,11 +283,7 @@ func (this *AlienController) CrawlDirect(writer http.ResponseWriter, request *ht
|
|||||||
dirPath := request.FormValue("dirPath")
|
dirPath := request.FormValue("dirPath")
|
||||||
url := request.FormValue("url")
|
url := request.FormValue("url")
|
||||||
|
|
||||||
if filename == "" {
|
filename = CheckMatterName(request, filename)
|
||||||
panic(result.BadRequest("filename cannot be null."))
|
|
||||||
} else if m, _ := regexp.MatchString(MATTER_NAME_PATTERN, filename); m {
|
|
||||||
panic(result.BadRequestI18n(request, i18n.MatterNameContainSpecialChars))
|
|
||||||
}
|
|
||||||
|
|
||||||
var privacy bool
|
var privacy bool
|
||||||
if privacyStr == TRUE {
|
if privacyStr == TRUE {
|
||||||
|
@ -111,7 +111,7 @@ func (this *AlienService) PreviewOrDownload(
|
|||||||
shareCode := request.FormValue("shareCode")
|
shareCode := request.FormValue("shareCode")
|
||||||
shareRootUuid := request.FormValue("shareRootUuid")
|
shareRootUuid := request.FormValue("shareRootUuid")
|
||||||
|
|
||||||
this.shareService.ValidateMatter(shareUuid, shareCode, operator, shareRootUuid, matter)
|
this.shareService.ValidateMatter(request, shareUuid, shareCode, operator, shareRootUuid, matter)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ func (this *DashboardService) etl() {
|
|||||||
longTimeAgo := time.Now()
|
longTimeAgo := time.Now()
|
||||||
longTimeAgo = longTimeAgo.AddDate(-20, 0, 0)
|
longTimeAgo = longTimeAgo.AddDate(-20, 0, 0)
|
||||||
|
|
||||||
this.logger.Info("Time %s -> %s", util.ConvertTimeToDateTimeString(startTime), util.ConvertTimeToDateTimeString(endTime))
|
this.logger.Info("ETL dashboard data from %s to %s", util.ConvertTimeToDateTimeString(startTime), util.ConvertTimeToDateTimeString(endTime))
|
||||||
|
|
||||||
//check whether the record has created.
|
//check whether the record has created.
|
||||||
dbDashboard := this.dashboardDao.FindByDt(dt)
|
dbDashboard := this.dashboardDao.FindByDt(dt)
|
||||||
|
@ -272,8 +272,8 @@ func (this *InstallController) CreateAdmin(writer http.ResponseWriter, request *
|
|||||||
adminPassword := request.FormValue("adminPassword")
|
adminPassword := request.FormValue("adminPassword")
|
||||||
|
|
||||||
//validate admin's username
|
//validate admin's username
|
||||||
if m, _ := regexp.MatchString(`^[0-9a-zA-Z_]+$`, adminUsername); !m {
|
if m, _ := regexp.MatchString(USERNAME_PATTERN, adminUsername); !m {
|
||||||
panic(result.BadRequest(`admin's username cannot oly be alphabet, number or '_'`))
|
panic(result.BadRequestI18n(request, i18n.UsernameError))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(adminPassword) < 6 {
|
if len(adminPassword) < 6 {
|
||||||
|
@ -142,7 +142,7 @@ func (this *MatterController) Page(writer http.ResponseWriter, request *http.Req
|
|||||||
|
|
||||||
user := this.findUser(request)
|
user := this.findUser(request)
|
||||||
|
|
||||||
this.shareService.ValidateMatter(shareUuid, shareCode, user, shareRootUuid, dirMatter)
|
this.shareService.ValidateMatter(request, shareUuid, shareCode, user, shareRootUuid, dirMatter)
|
||||||
userUuid = dirMatter.Uuid
|
userUuid = dirMatter.Uuid
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -3,7 +3,12 @@ package rest
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/eyebluecn/tank/code/core"
|
"github.com/eyebluecn/tank/code/core"
|
||||||
|
"github.com/eyebluecn/tank/code/tool/i18n"
|
||||||
|
"github.com/eyebluecn/tank/code/tool/result"
|
||||||
"github.com/eyebluecn/tank/code/tool/util"
|
"github.com/eyebluecn/tank/code/tool/util"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -89,3 +94,22 @@ func GetUserZipRootDir(username string) (rootDirPath string) {
|
|||||||
|
|
||||||
return rootDirPath
|
return rootDirPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//check matter's name. If error, panic.
|
||||||
|
func CheckMatterName(request *http.Request, name string) string {
|
||||||
|
|
||||||
|
if name == "" {
|
||||||
|
panic(result.BadRequest("name cannot be null"))
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(name, " ") || strings.HasSuffix(name, " ") {
|
||||||
|
panic(result.BadRequest("name cannot start with or end with space"))
|
||||||
|
}
|
||||||
|
if m, _ := regexp.MatchString(MATTER_NAME_PATTERN, name); m {
|
||||||
|
panic(result.BadRequestI18n(request, i18n.MatterNameContainSpecialChars))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(name) > MATTER_NAME_MAX_LENGTH {
|
||||||
|
panic(result.BadRequestI18n(request, i18n.MatterNameLengthExceedLimit, len(name), MATTER_NAME_MAX_LENGTH))
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
@ -12,14 +12,14 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 操作文件的Service
|
* Methods start with Atomic has Lock. These method cannot be invoked by other Atomic Methods.
|
||||||
* 以 Atomic 开头的方法带有操作锁,这种方法不能被其他的Atomic方法调用,只能提供给外部调用。
|
|
||||||
*/
|
*/
|
||||||
//@Service
|
//@Service
|
||||||
type MatterService struct {
|
type MatterService struct {
|
||||||
@ -67,7 +67,7 @@ func (this *MatterService) Init() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//文件下载。支持分片下载
|
//Download. Support chunk download.
|
||||||
func (this *MatterService) DownloadFile(
|
func (this *MatterService) DownloadFile(
|
||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
request *http.Request,
|
request *http.Request,
|
||||||
@ -78,7 +78,7 @@ func (this *MatterService) DownloadFile(
|
|||||||
download.DownloadFile(writer, request, filePath, filename, withContentDisposition)
|
download.DownloadFile(writer, request, filePath, filename, withContentDisposition)
|
||||||
}
|
}
|
||||||
|
|
||||||
//下载文件 要求必须是同一个父matter下的。
|
//Download specified matters. matters must have the same puuid.
|
||||||
func (this *MatterService) DownloadZip(
|
func (this *MatterService) DownloadZip(
|
||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
request *http.Request,
|
request *http.Request,
|
||||||
@ -100,34 +100,31 @@ func (this *MatterService) DownloadZip(
|
|||||||
|
|
||||||
preference := this.preferenceService.Fetch()
|
preference := this.preferenceService.Fetch()
|
||||||
|
|
||||||
|
//count the num of files will be downloaded.
|
||||||
var count int64 = 0
|
var count int64 = 0
|
||||||
for _, matter := range matters {
|
for _, matter := range matters {
|
||||||
//验证文件夹中文件数量
|
|
||||||
count = count + this.matterDao.CountByUserUuidAndPath(matter.UserUuid, matter.Path)
|
count = count + this.matterDao.CountByUserUuidAndPath(matter.UserUuid, matter.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
//文件数量判断。
|
|
||||||
if preference.DownloadDirMaxNum >= 0 {
|
if preference.DownloadDirMaxNum >= 0 {
|
||||||
if count > preference.DownloadDirMaxNum {
|
if count > preference.DownloadDirMaxNum {
|
||||||
panic(result.BadRequestI18n(request, i18n.MatterSelectNumExceedLimit, count, preference.DownloadDirMaxNum))
|
panic(result.BadRequestI18n(request, i18n.MatterSelectNumExceedLimit, count, preference.DownloadDirMaxNum))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//count the size of files will be downloaded.
|
||||||
var sumSize int64 = 0
|
var sumSize int64 = 0
|
||||||
for _, matter := range matters {
|
for _, matter := range matters {
|
||||||
//验证文件夹中文件数量
|
|
||||||
sumSize = sumSize + this.matterDao.SumSizeByUserUuidAndPath(matter.UserUuid, matter.Path)
|
sumSize = sumSize + this.matterDao.SumSizeByUserUuidAndPath(matter.UserUuid, matter.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
//判断用户自身上传大小的限制
|
|
||||||
//大小判断
|
|
||||||
if preference.DownloadDirMaxSize >= 0 {
|
if preference.DownloadDirMaxSize >= 0 {
|
||||||
if sumSize > preference.DownloadDirMaxSize {
|
if sumSize > preference.DownloadDirMaxSize {
|
||||||
panic(result.BadRequestI18n(request, i18n.MatterSelectSizeExceedLimit, util.HumanFileSize(sumSize), util.HumanFileSize(preference.DownloadDirMaxSize)))
|
panic(result.BadRequestI18n(request, i18n.MatterSelectSizeExceedLimit, util.HumanFileSize(sumSize), util.HumanFileSize(preference.DownloadDirMaxSize)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//准备zip放置的目录。
|
//prepare the temp zip dir
|
||||||
destZipDirPath := fmt.Sprintf("%s/%d", GetUserZipRootDir(matters[0].Username), time.Now().UnixNano()/1e6)
|
destZipDirPath := fmt.Sprintf("%s/%d", GetUserZipRootDir(matters[0].Username), time.Now().UnixNano()/1e6)
|
||||||
util.MakeDirAll(destZipDirPath)
|
util.MakeDirAll(destZipDirPath)
|
||||||
|
|
||||||
@ -138,13 +135,11 @@ func (this *MatterService) DownloadZip(
|
|||||||
|
|
||||||
destZipPath := fmt.Sprintf("%s/%s", destZipDirPath, destZipName)
|
destZipPath := fmt.Sprintf("%s/%s", destZipDirPath, destZipName)
|
||||||
|
|
||||||
//_ = util.Zip(matter.AbsolutePath(), destZipPath)
|
|
||||||
this.zipMatters(request, matters, destZipPath)
|
this.zipMatters(request, matters, destZipPath)
|
||||||
|
|
||||||
//下载
|
|
||||||
download.DownloadFile(writer, request, destZipPath, destZipName, true)
|
download.DownloadFile(writer, request, destZipPath, destZipName, true)
|
||||||
|
|
||||||
//删除临时压缩文件
|
//delete the temp zip file.
|
||||||
err := os.Remove(destZipPath)
|
err := os.Remove(destZipPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.logger.Error("error while deleting zip file %s", err.Error())
|
this.logger.Error("error while deleting zip file %s", err.Error())
|
||||||
@ -153,14 +148,14 @@ func (this *MatterService) DownloadZip(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//打包一系列的matter
|
//zip matters.
|
||||||
func (this *MatterService) zipMatters(request *http.Request, matters []*Matter, destPath string) {
|
func (this *MatterService) zipMatters(request *http.Request, matters []*Matter, destPath string) {
|
||||||
|
|
||||||
if util.PathExists(destPath) {
|
if util.PathExists(destPath) {
|
||||||
panic(result.BadRequest("%s exists", destPath))
|
panic(result.BadRequest("%s exists", destPath))
|
||||||
}
|
}
|
||||||
|
|
||||||
//要求必须是同一个父matter下的。
|
//matters must have the same puuid.
|
||||||
if matters == nil || len(matters) == 0 {
|
if matters == nil || len(matters) == 0 {
|
||||||
panic(result.BadRequest("matters cannot be nil."))
|
panic(result.BadRequest("matters cannot be nil."))
|
||||||
}
|
}
|
||||||
@ -176,12 +171,12 @@ func (this *MatterService) zipMatters(request *http.Request, matters []*Matter,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//将每个matter的children装填好
|
//wrap children for every matter.
|
||||||
for _, m := range matters {
|
for _, m := range matters {
|
||||||
this.WrapChildrenDetail(request, m)
|
this.WrapChildrenDetail(request, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建准备写入的文件
|
// create temp zip file.
|
||||||
fileWriter, err := os.Create(destPath)
|
fileWriter, err := os.Create(destPath)
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
|
|
||||||
@ -190,15 +185,13 @@ func (this *MatterService) zipMatters(request *http.Request, matters []*Matter,
|
|||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// 通过 fileWriter 来创建 zip.Write
|
|
||||||
zipWriter := zip.NewWriter(fileWriter)
|
zipWriter := zip.NewWriter(fileWriter)
|
||||||
defer func() {
|
defer func() {
|
||||||
// 检测一下是否成功关闭
|
|
||||||
err := zipWriter.Close()
|
err := zipWriter.Close()
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
//采用深度优先搜索算法。
|
//DFS algorithm
|
||||||
var walkFunc func(matter *Matter)
|
var walkFunc func(matter *Matter)
|
||||||
walkFunc = func(matter *Matter) {
|
walkFunc = func(matter *Matter) {
|
||||||
|
|
||||||
@ -207,27 +200,24 @@ func (this *MatterService) zipMatters(request *http.Request, matters []*Matter,
|
|||||||
fileInfo, err := os.Stat(path)
|
fileInfo, err := os.Stat(path)
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
|
|
||||||
// 通过文件信息,创建 zip 的文件信息
|
// Create file info.
|
||||||
fileHeader, err := zip.FileInfoHeader(fileInfo)
|
fileHeader, err := zip.FileInfoHeader(fileInfo)
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
|
|
||||||
// 替换文件信息中的文件名
|
// Trim the baseDirPath
|
||||||
fileHeader.Name = strings.TrimPrefix(path, baseDirPath)
|
fileHeader.Name = strings.TrimPrefix(path, baseDirPath)
|
||||||
|
|
||||||
// 目录前要加上/
|
// directory has prefix /
|
||||||
if matter.Dir {
|
if matter.Dir {
|
||||||
fileHeader.Name += "/"
|
fileHeader.Name += "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
// 写入文件信息,并返回一个 Write 结构
|
|
||||||
writer, err := zipWriter.CreateHeader(fileHeader)
|
writer, err := zipWriter.CreateHeader(fileHeader)
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
|
|
||||||
// 检测,如果不是标准文件就只写入头信息,不写入文件数据到 writer
|
// only regular file has things to write.
|
||||||
// 如目录,也没有数据需要写
|
|
||||||
if fileHeader.Mode().IsRegular() {
|
if fileHeader.Mode().IsRegular() {
|
||||||
|
|
||||||
// 打开要压缩的文件
|
|
||||||
fileToBeZip, err := os.Open(path)
|
fileToBeZip, err := os.Open(path)
|
||||||
defer func() {
|
defer func() {
|
||||||
err = fileToBeZip.Close()
|
err = fileToBeZip.Close()
|
||||||
@ -235,13 +225,12 @@ func (this *MatterService) zipMatters(request *http.Request, matters []*Matter,
|
|||||||
}()
|
}()
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
|
|
||||||
// 将打开的文件 Copy 到 writer
|
|
||||||
_, err = io.Copy(writer, fileToBeZip)
|
_, err = io.Copy(writer, fileToBeZip)
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//如果有子文件,继续往下钻
|
//dfs.
|
||||||
for _, m := range matter.Children {
|
for _, m := range matter.Children {
|
||||||
walkFunc(m)
|
walkFunc(m)
|
||||||
}
|
}
|
||||||
@ -252,7 +241,7 @@ func (this *MatterService) zipMatters(request *http.Request, matters []*Matter,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//删除文件
|
//delete files.
|
||||||
func (this *MatterService) Delete(request *http.Request, matter *Matter) {
|
func (this *MatterService) Delete(request *http.Request, matter *Matter) {
|
||||||
|
|
||||||
if matter == nil {
|
if matter == nil {
|
||||||
@ -261,42 +250,39 @@ func (this *MatterService) Delete(request *http.Request, matter *Matter) {
|
|||||||
|
|
||||||
this.matterDao.Delete(matter)
|
this.matterDao.Delete(matter)
|
||||||
|
|
||||||
//重新计算文件大小
|
//re compute the size of Route.
|
||||||
this.matterDao.ComputeRouteSize(matter.Puuid, matter.UserUuid)
|
this.matterDao.ComputeRouteSize(matter.Puuid, matter.UserUuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
//删除文件
|
//atomic delete files
|
||||||
func (this *MatterService) AtomicDelete(request *http.Request, matter *Matter) {
|
func (this *MatterService) AtomicDelete(request *http.Request, matter *Matter) {
|
||||||
|
|
||||||
if matter == nil {
|
if matter == nil {
|
||||||
panic(result.BadRequest("matter cannot be nil"))
|
panic(result.BadRequest("matter cannot be nil"))
|
||||||
}
|
}
|
||||||
|
|
||||||
//操作锁
|
//lock
|
||||||
this.userService.MatterLock(matter.UserUuid)
|
this.userService.MatterLock(matter.UserUuid)
|
||||||
defer this.userService.MatterUnlock(matter.UserUuid)
|
defer this.userService.MatterUnlock(matter.UserUuid)
|
||||||
|
|
||||||
this.Delete(request, matter)
|
this.Delete(request, matter)
|
||||||
}
|
}
|
||||||
|
|
||||||
//上传文件
|
//upload files.
|
||||||
func (this *MatterService) Upload(request *http.Request, file io.Reader, user *User, dirMatter *Matter, filename string, privacy bool) *Matter {
|
func (this *MatterService) Upload(request *http.Request, file io.Reader, user *User, dirMatter *Matter, filename string, privacy bool) *Matter {
|
||||||
|
|
||||||
if user == nil {
|
if user == nil {
|
||||||
panic(result.BadRequest("user cannot be nil."))
|
panic(result.BadRequest("user cannot be nil."))
|
||||||
}
|
}
|
||||||
|
|
||||||
//验证dirMatter
|
|
||||||
if dirMatter == nil {
|
if dirMatter == nil {
|
||||||
panic(result.BadRequest("dirMatter cannot be nil."))
|
panic(result.BadRequest("dirMatter cannot be nil."))
|
||||||
}
|
}
|
||||||
|
|
||||||
//文件名不能太长。
|
|
||||||
if len(filename) > MATTER_NAME_MAX_LENGTH {
|
if len(filename) > MATTER_NAME_MAX_LENGTH {
|
||||||
panic(result.BadRequestI18n(request, i18n.MatterNameLengthExceedLimit, len(filename), MATTER_NAME_MAX_LENGTH))
|
panic(result.BadRequestI18n(request, i18n.MatterNameLengthExceedLimit, len(filename), MATTER_NAME_MAX_LENGTH))
|
||||||
}
|
}
|
||||||
|
|
||||||
//文件夹路径
|
|
||||||
dirAbsolutePath := dirMatter.AbsolutePath()
|
dirAbsolutePath := dirMatter.AbsolutePath()
|
||||||
dirRelativePath := dirMatter.Path
|
dirRelativePath := dirMatter.Path
|
||||||
|
|
||||||
@ -305,17 +291,15 @@ func (this *MatterService) Upload(request *http.Request, file io.Reader, user *U
|
|||||||
panic(result.BadRequest("%s already exists", filename))
|
panic(result.BadRequest("%s already exists", filename))
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取文件应该存放在的物理路径的绝对路径和相对路径。
|
|
||||||
fileAbsolutePath := dirAbsolutePath + "/" + filename
|
fileAbsolutePath := dirAbsolutePath + "/" + filename
|
||||||
fileRelativePath := dirRelativePath + "/" + filename
|
fileRelativePath := dirRelativePath + "/" + filename
|
||||||
|
|
||||||
//创建父文件夹
|
|
||||||
util.MakeDirAll(dirAbsolutePath)
|
util.MakeDirAll(dirAbsolutePath)
|
||||||
|
|
||||||
//如果文件已经存在了,那么直接覆盖。
|
//if exist, overwrite it.
|
||||||
exist := util.PathExists(fileAbsolutePath)
|
exist := util.PathExists(fileAbsolutePath)
|
||||||
if exist {
|
if exist {
|
||||||
this.logger.Error("%s已经存在,将其删除", fileAbsolutePath)
|
this.logger.Error("%s exits, overwrite it.", fileAbsolutePath)
|
||||||
removeError := os.Remove(fileAbsolutePath)
|
removeError := os.Remove(fileAbsolutePath)
|
||||||
this.PanicError(removeError)
|
this.PanicError(removeError)
|
||||||
}
|
}
|
||||||
@ -331,20 +315,20 @@ func (this *MatterService) Upload(request *http.Request, file io.Reader, user *U
|
|||||||
fileSize, err := io.Copy(destFile, file)
|
fileSize, err := io.Copy(destFile, file)
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
|
|
||||||
this.logger.Info("上传文件 %s 大小为 %v ", filename, util.HumanFileSize(fileSize))
|
this.logger.Info("upload %s %v ", filename, util.HumanFileSize(fileSize))
|
||||||
|
|
||||||
//判断用户自身上传大小的限制。
|
//check the size limit.
|
||||||
if user.SizeLimit >= 0 {
|
if user.SizeLimit >= 0 {
|
||||||
if fileSize > user.SizeLimit {
|
if fileSize > user.SizeLimit {
|
||||||
//删除上传过来的内容
|
//delete the file on disk.
|
||||||
err = os.Remove(fileAbsolutePath)
|
err = os.Remove(fileAbsolutePath)
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
|
|
||||||
panic(result.BadRequest("file's size exceed the limit %s > %s ", util.HumanFileSize(user.SizeLimit), util.HumanFileSize(fileSize)))
|
panic(result.BadRequestI18n(request, i18n.MatterSizeExceedLimit, util.HumanFileSize(fileSize), util.HumanFileSize(user.SizeLimit)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//将文件信息存入数据库中。
|
//write to db.
|
||||||
matter := &Matter{
|
matter := &Matter{
|
||||||
Puuid: dirMatter.Uuid,
|
Puuid: dirMatter.Uuid,
|
||||||
UserUuid: user.Uuid,
|
UserUuid: user.Uuid,
|
||||||
@ -358,7 +342,7 @@ func (this *MatterService) Upload(request *http.Request, file io.Reader, user *U
|
|||||||
}
|
}
|
||||||
matter = this.matterDao.Create(matter)
|
matter = this.matterDao.Create(matter)
|
||||||
|
|
||||||
//统计文件夹的大小。
|
//compute the size of directory
|
||||||
go core.RunWithRecovery(func() {
|
go core.RunWithRecovery(func() {
|
||||||
this.matterDao.ComputeRouteSize(dirMatter.Uuid, user.Uuid)
|
this.matterDao.ComputeRouteSize(dirMatter.Uuid, user.Uuid)
|
||||||
})
|
})
|
||||||
@ -366,15 +350,13 @@ func (this *MatterService) Upload(request *http.Request, file io.Reader, user *U
|
|||||||
return matter
|
return matter
|
||||||
}
|
}
|
||||||
|
|
||||||
//内部创建文件,不带操作锁。
|
//inner create directory.
|
||||||
func (this *MatterService) createDirectory(request *http.Request, dirMatter *Matter, name string, user *User) *Matter {
|
func (this *MatterService) createDirectory(request *http.Request, dirMatter *Matter, name string, user *User) *Matter {
|
||||||
|
|
||||||
//父级matter必须存在
|
|
||||||
if dirMatter == nil {
|
if dirMatter == nil {
|
||||||
panic(result.BadRequest("dirMatter cannot be nil"))
|
panic(result.BadRequest("dirMatter cannot be nil"))
|
||||||
}
|
}
|
||||||
|
|
||||||
//必须是文件夹
|
|
||||||
if !dirMatter.Dir {
|
if !dirMatter.Dir {
|
||||||
panic(result.BadRequest("dirMatter must be directory"))
|
panic(result.BadRequest("dirMatter must be directory"))
|
||||||
}
|
}
|
||||||
@ -385,7 +367,6 @@ func (this *MatterService) createDirectory(request *http.Request, dirMatter *Mat
|
|||||||
}
|
}
|
||||||
|
|
||||||
name = strings.TrimSpace(name)
|
name = strings.TrimSpace(name)
|
||||||
//验证参数。
|
|
||||||
if name == "" {
|
if name == "" {
|
||||||
panic(result.BadRequest("name cannot be blank"))
|
panic(result.BadRequest("name cannot be blank"))
|
||||||
}
|
}
|
||||||
@ -400,7 +381,7 @@ func (this *MatterService) createDirectory(request *http.Request, dirMatter *Mat
|
|||||||
panic(result.BadRequestI18n(request, i18n.MatterNameContainSpecialChars))
|
panic(result.BadRequestI18n(request, i18n.MatterNameContainSpecialChars))
|
||||||
}
|
}
|
||||||
|
|
||||||
//判断同级文件夹中是否有同名的文件夹。存在了直接返回即可。
|
//if exist. return.
|
||||||
matter := this.matterDao.FindByUserUuidAndPuuidAndDirAndName(user.Uuid, dirMatter.Uuid, true, name)
|
matter := this.matterDao.FindByUserUuidAndPuuidAndDirAndName(user.Uuid, dirMatter.Uuid, true, name)
|
||||||
if matter != nil {
|
if matter != nil {
|
||||||
return matter
|
return matter
|
||||||
@ -412,17 +393,15 @@ func (this *MatterService) createDirectory(request *http.Request, dirMatter *Mat
|
|||||||
panic(result.BadRequestI18n(request, i18n.MatterDepthExceedLimit, len(parts), MATTER_NAME_MAX_DEPTH))
|
panic(result.BadRequestI18n(request, i18n.MatterDepthExceedLimit, len(parts), MATTER_NAME_MAX_DEPTH))
|
||||||
}
|
}
|
||||||
|
|
||||||
//绝对路径
|
|
||||||
absolutePath := GetUserMatterRootDir(user.Username) + dirMatter.Path + "/" + name
|
absolutePath := GetUserMatterRootDir(user.Username) + dirMatter.Path + "/" + name
|
||||||
|
|
||||||
//相对路径
|
|
||||||
relativePath := dirMatter.Path + "/" + name
|
relativePath := dirMatter.Path + "/" + name
|
||||||
|
|
||||||
//磁盘中创建文件夹。
|
//crate directory on disk.
|
||||||
dirPath := util.MakeDirAll(absolutePath)
|
dirPath := util.MakeDirAll(absolutePath)
|
||||||
this.logger.Info("Create Directory: %s", dirPath)
|
this.logger.Info("Create Directory: %s", dirPath)
|
||||||
|
|
||||||
//数据库中创建文件夹。
|
//create in db
|
||||||
matter = &Matter{
|
matter = &Matter{
|
||||||
Puuid: dirMatter.Uuid,
|
Puuid: dirMatter.Uuid,
|
||||||
UserUuid: user.Uuid,
|
UserUuid: user.Uuid,
|
||||||
@ -437,10 +416,8 @@ func (this *MatterService) createDirectory(request *http.Request, dirMatter *Mat
|
|||||||
return matter
|
return matter
|
||||||
}
|
}
|
||||||
|
|
||||||
//在dirMatter中创建文件夹 返回刚刚创建的这个文件夹
|
|
||||||
func (this *MatterService) AtomicCreateDirectory(request *http.Request, dirMatter *Matter, name string, user *User) *Matter {
|
func (this *MatterService) AtomicCreateDirectory(request *http.Request, dirMatter *Matter, name string, user *User) *Matter {
|
||||||
|
|
||||||
//操作锁
|
|
||||||
this.userService.MatterLock(user.Uuid)
|
this.userService.MatterLock(user.Uuid)
|
||||||
defer this.userService.MatterUnlock(user.Uuid)
|
defer this.userService.MatterUnlock(user.Uuid)
|
||||||
|
|
||||||
@ -449,16 +426,14 @@ func (this *MatterService) AtomicCreateDirectory(request *http.Request, dirMatte
|
|||||||
return matter
|
return matter
|
||||||
}
|
}
|
||||||
|
|
||||||
//处理 移动和复制时可能存在的覆盖问题。
|
//copy or move may overwrite.
|
||||||
func (this *MatterService) handleOverwrite(request *http.Request, userUuid string, destinationPath string, overwrite bool) {
|
func (this *MatterService) handleOverwrite(request *http.Request, userUuid string, destinationPath string, overwrite bool) {
|
||||||
|
|
||||||
//目标matter。因为有可能已经存在了
|
|
||||||
destMatter := this.matterDao.findByUserUuidAndPath(userUuid, destinationPath)
|
destMatter := this.matterDao.findByUserUuidAndPath(userUuid, destinationPath)
|
||||||
//如果目标matter存在了。
|
|
||||||
if destMatter != nil {
|
if destMatter != nil {
|
||||||
//如果目标matter还存在了。
|
//if exist
|
||||||
if overwrite {
|
if overwrite {
|
||||||
//要求覆盖。那么删除。
|
//delete.
|
||||||
this.Delete(request, destMatter)
|
this.Delete(request, destMatter)
|
||||||
} else {
|
} else {
|
||||||
panic(result.BadRequestI18n(request, i18n.MatterExist, destMatter.Path))
|
panic(result.BadRequestI18n(request, i18n.MatterExist, destMatter.Path))
|
||||||
@ -467,7 +442,7 @@ func (this *MatterService) handleOverwrite(request *http.Request, userUuid strin
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//将一个srcMatter放置到另一个destMatter(必须为文件夹)下 不关注 overwrite 和 lock.
|
//move srcMatter to destMatter. invoker must handled the overwrite and lock.
|
||||||
func (this *MatterService) move(request *http.Request, srcMatter *Matter, destDirMatter *Matter) {
|
func (this *MatterService) move(request *http.Request, srcMatter *Matter, destDirMatter *Matter) {
|
||||||
|
|
||||||
if srcMatter == nil {
|
if srcMatter == nil {
|
||||||
@ -483,59 +458,59 @@ func (this *MatterService) move(request *http.Request, srcMatter *Matter, destDi
|
|||||||
destDirUuid := destDirMatter.Uuid
|
destDirUuid := destDirMatter.Uuid
|
||||||
|
|
||||||
if srcMatter.Dir {
|
if srcMatter.Dir {
|
||||||
//如果源是文件夹
|
|
||||||
|
//if src is dir.
|
||||||
destAbsolutePath := destDirMatter.AbsolutePath() + "/" + srcMatter.Name
|
destAbsolutePath := destDirMatter.AbsolutePath() + "/" + srcMatter.Name
|
||||||
srcAbsolutePath := srcMatter.AbsolutePath()
|
srcAbsolutePath := srcMatter.AbsolutePath()
|
||||||
|
|
||||||
//物理文件一口气移动
|
//move src to dest on disk.
|
||||||
err := os.Rename(srcAbsolutePath, destAbsolutePath)
|
err := os.Rename(srcAbsolutePath, destAbsolutePath)
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
|
|
||||||
//修改数据库中信息
|
//change info on db.
|
||||||
srcMatter.Puuid = destDirMatter.Uuid
|
srcMatter.Puuid = destDirMatter.Uuid
|
||||||
srcMatter.Path = destDirMatter.Path + "/" + srcMatter.Name
|
srcMatter.Path = destDirMatter.Path + "/" + srcMatter.Name
|
||||||
srcMatter = this.matterDao.Save(srcMatter)
|
srcMatter = this.matterDao.Save(srcMatter)
|
||||||
|
|
||||||
//调整该文件夹下文件的Path.
|
//reCompute the path.
|
||||||
matters := this.matterDao.ListByPuuidAndUserUuid(srcMatter.Uuid, srcMatter.UserUuid, nil)
|
matters := this.matterDao.ListByPuuidAndUserUuid(srcMatter.Uuid, srcMatter.UserUuid, nil)
|
||||||
for _, m := range matters {
|
for _, m := range matters {
|
||||||
this.adjustPath(m, srcMatter)
|
this.adjustPath(m, srcMatter)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
//如果源是普通文件
|
|
||||||
|
|
||||||
|
//if src is NOT dir.
|
||||||
destAbsolutePath := destDirMatter.AbsolutePath() + "/" + srcMatter.Name
|
destAbsolutePath := destDirMatter.AbsolutePath() + "/" + srcMatter.Name
|
||||||
srcAbsolutePath := srcMatter.AbsolutePath()
|
srcAbsolutePath := srcMatter.AbsolutePath()
|
||||||
|
|
||||||
//物理文件进行移动
|
//move src to dest on disk.
|
||||||
err := os.Rename(srcAbsolutePath, destAbsolutePath)
|
err := os.Rename(srcAbsolutePath, destAbsolutePath)
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
|
|
||||||
//删除对应的缓存。
|
//delete caches.
|
||||||
this.imageCacheDao.DeleteByMatterUuid(srcMatter.Uuid)
|
this.imageCacheDao.DeleteByMatterUuid(srcMatter.Uuid)
|
||||||
|
|
||||||
//修改数据库中信息
|
//change info in db.
|
||||||
srcMatter.Puuid = destDirMatter.Uuid
|
srcMatter.Puuid = destDirMatter.Uuid
|
||||||
srcMatter.Path = destDirMatter.Path + "/" + srcMatter.Name
|
srcMatter.Path = destDirMatter.Path + "/" + srcMatter.Name
|
||||||
srcMatter = this.matterDao.Save(srcMatter)
|
srcMatter = this.matterDao.Save(srcMatter)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//调整两个文件夹的大小
|
//reCompute the size of src and dest.
|
||||||
this.matterDao.ComputeRouteSize(srcPuuid, userUuid)
|
this.matterDao.ComputeRouteSize(srcPuuid, userUuid)
|
||||||
this.matterDao.ComputeRouteSize(destDirUuid, userUuid)
|
this.matterDao.ComputeRouteSize(destDirUuid, userUuid)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//将一个srcMatter放置到另一个destMatter(必须为文件夹)下
|
//move srcMatter to destMatter(must be dir)
|
||||||
func (this *MatterService) AtomicMove(request *http.Request, srcMatter *Matter, destDirMatter *Matter, overwrite bool) {
|
func (this *MatterService) AtomicMove(request *http.Request, srcMatter *Matter, destDirMatter *Matter, overwrite bool) {
|
||||||
|
|
||||||
if srcMatter == nil {
|
if srcMatter == nil {
|
||||||
panic(result.BadRequest("srcMatter cannot be nil."))
|
panic(result.BadRequest("srcMatter cannot be nil."))
|
||||||
}
|
}
|
||||||
|
|
||||||
//操作锁
|
|
||||||
this.userService.MatterLock(srcMatter.UserUuid)
|
this.userService.MatterLock(srcMatter.UserUuid)
|
||||||
defer this.userService.MatterUnlock(srcMatter.UserUuid)
|
defer this.userService.MatterUnlock(srcMatter.UserUuid)
|
||||||
|
|
||||||
@ -546,7 +521,7 @@ func (this *MatterService) AtomicMove(request *http.Request, srcMatter *Matter,
|
|||||||
panic(result.BadRequestI18n(request, i18n.MatterDestinationMustDirectory))
|
panic(result.BadRequestI18n(request, i18n.MatterDestinationMustDirectory))
|
||||||
}
|
}
|
||||||
|
|
||||||
//文件夹不能把自己移入到自己中,也不可以移入到自己的子文件夹下。
|
//neither move to itself, nor move to its children.
|
||||||
destDirMatter = this.WrapParentDetail(request, destDirMatter)
|
destDirMatter = this.WrapParentDetail(request, destDirMatter)
|
||||||
tmpMatter := destDirMatter
|
tmpMatter := destDirMatter
|
||||||
for tmpMatter != nil {
|
for tmpMatter != nil {
|
||||||
@ -556,22 +531,21 @@ func (this *MatterService) AtomicMove(request *http.Request, srcMatter *Matter,
|
|||||||
tmpMatter = tmpMatter.Parent
|
tmpMatter = tmpMatter.Parent
|
||||||
}
|
}
|
||||||
|
|
||||||
//处理覆盖的问题
|
//handle the overwrite
|
||||||
destinationPath := destDirMatter.Path + "/" + srcMatter.Name
|
destinationPath := destDirMatter.Path + "/" + srcMatter.Name
|
||||||
this.handleOverwrite(request, srcMatter.UserUuid, destinationPath, overwrite)
|
this.handleOverwrite(request, srcMatter.UserUuid, destinationPath, overwrite)
|
||||||
|
|
||||||
//做move操作。
|
//do the move operation.
|
||||||
this.move(request, srcMatter, destDirMatter)
|
this.move(request, srcMatter, destDirMatter)
|
||||||
}
|
}
|
||||||
|
|
||||||
//将一个srcMatter放置到另一个destMatter(必须为文件夹)下
|
//move srcMatters to destMatter(must be dir)
|
||||||
func (this *MatterService) AtomicMoveBatch(request *http.Request, srcMatters []*Matter, destDirMatter *Matter) {
|
func (this *MatterService) AtomicMoveBatch(request *http.Request, srcMatters []*Matter, destDirMatter *Matter) {
|
||||||
|
|
||||||
if destDirMatter == nil {
|
if destDirMatter == nil {
|
||||||
panic(result.BadRequest("destDirMatter cannot be nil."))
|
panic(result.BadRequest("destDirMatter cannot be nil."))
|
||||||
}
|
}
|
||||||
|
|
||||||
//操作锁
|
|
||||||
this.userService.MatterLock(destDirMatter.UserUuid)
|
this.userService.MatterLock(destDirMatter.UserUuid)
|
||||||
defer this.userService.MatterUnlock(destDirMatter.UserUuid)
|
defer this.userService.MatterUnlock(destDirMatter.UserUuid)
|
||||||
|
|
||||||
@ -583,14 +557,14 @@ func (this *MatterService) AtomicMoveBatch(request *http.Request, srcMatters []*
|
|||||||
panic(result.BadRequestI18n(request, i18n.MatterDestinationMustDirectory))
|
panic(result.BadRequestI18n(request, i18n.MatterDestinationMustDirectory))
|
||||||
}
|
}
|
||||||
|
|
||||||
//文件夹不能把自己移入到自己中,也不可以移入到自己的子文件夹下。
|
//neither move to itself, nor move to its children.
|
||||||
destDirMatter = this.WrapParentDetail(request, destDirMatter)
|
destDirMatter = this.WrapParentDetail(request, destDirMatter)
|
||||||
for _, srcMatter := range srcMatters {
|
for _, srcMatter := range srcMatters {
|
||||||
|
|
||||||
tmpMatter := destDirMatter
|
tmpMatter := destDirMatter
|
||||||
for tmpMatter != nil {
|
for tmpMatter != nil {
|
||||||
if srcMatter.Uuid == tmpMatter.Uuid {
|
if srcMatter.Uuid == tmpMatter.Uuid {
|
||||||
panic("文件夹不能把自己移入到自己中,也不可以移入到自己的子文件夹下。")
|
panic(result.BadRequestI18n(request, i18n.MatterMoveRecursive))
|
||||||
}
|
}
|
||||||
tmpMatter = tmpMatter.Parent
|
tmpMatter = tmpMatter.Parent
|
||||||
}
|
}
|
||||||
@ -602,14 +576,11 @@ func (this *MatterService) AtomicMoveBatch(request *http.Request, srcMatters []*
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//内部移动一个文件(提供给Copy调用),无需关心overwrite问题。
|
//copy srcMatter to destMatter. invoker must handled the overwrite and lock.
|
||||||
func (this *MatterService) copy(request *http.Request, srcMatter *Matter, destDirMatter *Matter, name string) {
|
func (this *MatterService) copy(request *http.Request, srcMatter *Matter, destDirMatter *Matter, name string) {
|
||||||
|
|
||||||
if srcMatter.Dir {
|
if srcMatter.Dir {
|
||||||
|
|
||||||
//如果源是文件夹
|
|
||||||
|
|
||||||
//在目标地址创建新文件夹。
|
|
||||||
newMatter := &Matter{
|
newMatter := &Matter{
|
||||||
Puuid: destDirMatter.Uuid,
|
Puuid: destDirMatter.Uuid,
|
||||||
UserUuid: srcMatter.UserUuid,
|
UserUuid: srcMatter.UserUuid,
|
||||||
@ -624,7 +595,7 @@ func (this *MatterService) copy(request *http.Request, srcMatter *Matter, destDi
|
|||||||
|
|
||||||
newMatter = this.matterDao.Create(newMatter)
|
newMatter = this.matterDao.Create(newMatter)
|
||||||
|
|
||||||
//复制子文件或文件夹
|
//copy children
|
||||||
matters := this.matterDao.ListByPuuidAndUserUuid(srcMatter.Uuid, srcMatter.UserUuid, nil)
|
matters := this.matterDao.ListByPuuidAndUserUuid(srcMatter.Uuid, srcMatter.UserUuid, nil)
|
||||||
for _, m := range matters {
|
for _, m := range matters {
|
||||||
this.copy(request, m, newMatter, m.Name)
|
this.copy(request, m, newMatter, m.Name)
|
||||||
@ -632,14 +603,12 @@ func (this *MatterService) copy(request *http.Request, srcMatter *Matter, destDi
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
//如果源是普通文件
|
|
||||||
destAbsolutePath := destDirMatter.AbsolutePath() + "/" + name
|
destAbsolutePath := destDirMatter.AbsolutePath() + "/" + name
|
||||||
srcAbsolutePath := srcMatter.AbsolutePath()
|
srcAbsolutePath := srcMatter.AbsolutePath()
|
||||||
|
|
||||||
//物理文件进行复制
|
//copy file on disk.
|
||||||
util.CopyFile(srcAbsolutePath, destAbsolutePath)
|
util.CopyFile(srcAbsolutePath, destAbsolutePath)
|
||||||
|
|
||||||
//创建新文件的数据库信息。
|
|
||||||
newMatter := &Matter{
|
newMatter := &Matter{
|
||||||
Puuid: destDirMatter.Uuid,
|
Puuid: destDirMatter.Uuid,
|
||||||
UserUuid: srcMatter.UserUuid,
|
UserUuid: srcMatter.UserUuid,
|
||||||
@ -656,14 +625,13 @@ func (this *MatterService) copy(request *http.Request, srcMatter *Matter, destDi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//将一个srcMatter复制到另一个destMatter(必须为文件夹)下,名字叫做name
|
//copy srcMatter to destMatter.
|
||||||
func (this *MatterService) AtomicCopy(request *http.Request, srcMatter *Matter, destDirMatter *Matter, name string, overwrite bool) {
|
func (this *MatterService) AtomicCopy(request *http.Request, srcMatter *Matter, destDirMatter *Matter, name string, overwrite bool) {
|
||||||
|
|
||||||
if srcMatter == nil {
|
if srcMatter == nil {
|
||||||
panic(result.BadRequest("srcMatter cannot be nil."))
|
panic(result.BadRequest("srcMatter cannot be nil."))
|
||||||
}
|
}
|
||||||
|
|
||||||
//操作锁
|
|
||||||
this.userService.MatterLock(srcMatter.UserUuid)
|
this.userService.MatterLock(srcMatter.UserUuid)
|
||||||
defer this.userService.MatterUnlock(srcMatter.UserUuid)
|
defer this.userService.MatterUnlock(srcMatter.UserUuid)
|
||||||
|
|
||||||
@ -677,29 +645,17 @@ func (this *MatterService) AtomicCopy(request *http.Request, srcMatter *Matter,
|
|||||||
this.copy(request, srcMatter, destDirMatter, name)
|
this.copy(request, srcMatter, destDirMatter, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
//将一个matter 重命名为 name
|
//rename matter to name
|
||||||
func (this *MatterService) AtomicRename(request *http.Request, matter *Matter, name string, user *User) {
|
func (this *MatterService) AtomicRename(request *http.Request, matter *Matter, name string, user *User) {
|
||||||
|
|
||||||
if user == nil {
|
if user == nil {
|
||||||
panic(result.BadRequest("user cannot be nil"))
|
panic(result.BadRequest("user cannot be nil"))
|
||||||
}
|
}
|
||||||
|
|
||||||
//操作锁
|
|
||||||
this.userService.MatterLock(user.Uuid)
|
this.userService.MatterLock(user.Uuid)
|
||||||
defer this.userService.MatterUnlock(user.Uuid)
|
defer this.userService.MatterUnlock(user.Uuid)
|
||||||
|
|
||||||
//验证参数。
|
name = CheckMatterName(request, name)
|
||||||
if name == "" {
|
|
||||||
panic(result.BadRequest("name cannot be null"))
|
|
||||||
}
|
|
||||||
if m, _ := regexp.MatchString(MATTER_NAME_PATTERN, name); m {
|
|
||||||
panic(result.BadRequestI18n(request, i18n.MatterNameContainSpecialChars))
|
|
||||||
}
|
|
||||||
|
|
||||||
//文件名不能太长。
|
|
||||||
if len(name) > MATTER_NAME_MAX_LENGTH {
|
|
||||||
panic(result.BadRequestI18n(request, i18n.MatterNameLengthExceedLimit, len(name), MATTER_NAME_MAX_LENGTH))
|
|
||||||
}
|
|
||||||
|
|
||||||
if name == matter.Name {
|
if name == matter.Name {
|
||||||
panic(result.BadRequestI18n(request, i18n.MatterNameNoChange))
|
panic(result.BadRequestI18n(request, i18n.MatterNameNoChange))
|
||||||
@ -853,36 +809,33 @@ func (this *MatterService) mirror(request *http.Request, srcPath string, destDir
|
|||||||
//根据一个文件夹路径,依次创建,找到最后一个文件夹的matter,如果中途出错,返回err. 如果存在了那就直接返回即可。
|
//根据一个文件夹路径,依次创建,找到最后一个文件夹的matter,如果中途出错,返回err. 如果存在了那就直接返回即可。
|
||||||
func (this *MatterService) CreateDirectories(request *http.Request, user *User, dirPath string) *Matter {
|
func (this *MatterService) CreateDirectories(request *http.Request, user *User, dirPath string) *Matter {
|
||||||
|
|
||||||
if dirPath == "" {
|
dirPath = path.Clean(dirPath)
|
||||||
panic(`文件夹不能为空`)
|
|
||||||
} else if dirPath[0:1] != "/" {
|
|
||||||
panic(`文件夹必须以/开头`)
|
|
||||||
} else if strings.Index(dirPath, "//") != -1 {
|
|
||||||
panic(`文件夹不能出现连续的//`)
|
|
||||||
} else if m, _ := regexp.MatchString(MATTER_NAME_PATTERN, dirPath); m {
|
|
||||||
panic(result.BadRequestI18n(request, i18n.MatterNameContainSpecialChars))
|
|
||||||
}
|
|
||||||
|
|
||||||
if dirPath == "/" {
|
if dirPath == "/" {
|
||||||
return NewRootMatter(user)
|
return NewRootMatter(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
//如果最后一个符号为/自动忽略
|
//ignore the last slash.
|
||||||
if dirPath[len(dirPath)-1] == '/' {
|
dirPath = strings.TrimSuffix(dirPath, "/")
|
||||||
dirPath = dirPath[:len(dirPath)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
//递归找寻文件的上级目录uuid.
|
|
||||||
folders := strings.Split(dirPath, "/")
|
folders := strings.Split(dirPath, "/")
|
||||||
|
|
||||||
if len(folders) > MATTER_NAME_MAX_DEPTH {
|
if len(folders) > MATTER_NAME_MAX_DEPTH {
|
||||||
panic(result.BadRequestI18n(request, i18n.MatterDepthExceedLimit, len(folders), MATTER_NAME_MAX_DEPTH))
|
panic(result.BadRequestI18n(request, i18n.MatterDepthExceedLimit, len(folders), MATTER_NAME_MAX_DEPTH))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//validate every matter name.
|
||||||
|
for k, name := range folders {
|
||||||
|
//first element is ""
|
||||||
|
if k != 0 {
|
||||||
|
CheckMatterName(request, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var dirMatter *Matter
|
var dirMatter *Matter
|
||||||
for k, name := range folders {
|
for k, name := range folders {
|
||||||
|
|
||||||
//split的第一个元素为空字符串,忽略。
|
//ignore the first element.
|
||||||
if k == 0 {
|
if k == 0 {
|
||||||
dirMatter = NewRootMatter(user)
|
dirMatter = NewRootMatter(user)
|
||||||
continue
|
continue
|
||||||
@ -894,14 +847,13 @@ func (this *MatterService) CreateDirectories(request *http.Request, user *User,
|
|||||||
return dirMatter
|
return dirMatter
|
||||||
}
|
}
|
||||||
|
|
||||||
//包装某个matter的详情。会把父级依次倒着装进去。如果中途出错,直接抛出异常。
|
//wrap a matter. put its parent.
|
||||||
func (this *MatterService) WrapParentDetail(request *http.Request, matter *Matter) *Matter {
|
func (this *MatterService) WrapParentDetail(request *http.Request, matter *Matter) *Matter {
|
||||||
|
|
||||||
if matter == nil {
|
if matter == nil {
|
||||||
panic(result.BadRequest("matter cannot be nil."))
|
panic(result.BadRequest("matter cannot be nil."))
|
||||||
}
|
}
|
||||||
|
|
||||||
//组装file的内容,展示其父组件。
|
|
||||||
puuid := matter.Puuid
|
puuid := matter.Puuid
|
||||||
tmpMatter := matter
|
tmpMatter := matter
|
||||||
for puuid != MATTER_ROOT {
|
for puuid != MATTER_ROOT {
|
||||||
@ -914,7 +866,7 @@ func (this *MatterService) WrapParentDetail(request *http.Request, matter *Matte
|
|||||||
return matter
|
return matter
|
||||||
}
|
}
|
||||||
|
|
||||||
//包装某个matter的详情。会把子级依次装进去。如果中途出错,直接抛出异常。
|
//wrap a matter ,put its children
|
||||||
func (this *MatterService) WrapChildrenDetail(request *http.Request, matter *Matter) {
|
func (this *MatterService) WrapChildrenDetail(request *http.Request, matter *Matter) {
|
||||||
|
|
||||||
if matter == nil {
|
if matter == nil {
|
||||||
@ -933,20 +885,19 @@ func (this *MatterService) WrapChildrenDetail(request *http.Request, matter *Mat
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取某个文件的详情,会把父级依次倒着装进去。如果中途出错,直接抛出异常。
|
//fetch a matter's detail with parent info.
|
||||||
func (this *MatterService) Detail(request *http.Request, uuid string) *Matter {
|
func (this *MatterService) Detail(request *http.Request, uuid string) *Matter {
|
||||||
matter := this.matterDao.CheckByUuid(uuid)
|
matter := this.matterDao.CheckByUuid(uuid)
|
||||||
return this.WrapParentDetail(request, matter)
|
return this.WrapParentDetail(request, matter)
|
||||||
}
|
}
|
||||||
|
|
||||||
//去指定的url中爬文件
|
//crawl a url to dirMatter
|
||||||
func (this *MatterService) AtomicCrawl(request *http.Request, url string, filename string, user *User, dirMatter *Matter, privacy bool) *Matter {
|
func (this *MatterService) AtomicCrawl(request *http.Request, url string, filename string, user *User, dirMatter *Matter, privacy bool) *Matter {
|
||||||
|
|
||||||
if user == nil {
|
if user == nil {
|
||||||
panic(result.BadRequest("user cannot be nil."))
|
panic(result.BadRequest("user cannot be nil."))
|
||||||
}
|
}
|
||||||
|
|
||||||
//操作锁
|
|
||||||
this.userService.MatterLock(user.Uuid)
|
this.userService.MatterLock(user.Uuid)
|
||||||
defer this.userService.MatterUnlock(user.Uuid)
|
defer this.userService.MatterUnlock(user.Uuid)
|
||||||
|
|
||||||
@ -958,36 +909,31 @@ func (this *MatterService) AtomicCrawl(request *http.Request, url string, filena
|
|||||||
panic(result.BadRequest("filename cannot be null."))
|
panic(result.BadRequest("filename cannot be null."))
|
||||||
}
|
}
|
||||||
|
|
||||||
//从指定的url下载一个文件。参考:https://golangcode.com/download-a-file-from-a-url/
|
//download from url.
|
||||||
resp, err := http.Get(url)
|
resp, err := http.Get(url)
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
|
|
||||||
return this.Upload(request, resp.Body, user, dirMatter, filename, privacy)
|
return this.Upload(request, resp.Body, user, dirMatter, filename, privacy)
|
||||||
}
|
}
|
||||||
|
|
||||||
//调整一个Matter的path值
|
//adjust a matter's path.
|
||||||
func (this *MatterService) adjustPath(matter *Matter, parentMatter *Matter) {
|
func (this *MatterService) adjustPath(matter *Matter, parentMatter *Matter) {
|
||||||
|
|
||||||
if matter.Dir {
|
if matter.Dir {
|
||||||
//如果源是文件夹
|
|
||||||
|
|
||||||
//首先调整好自己
|
|
||||||
matter.Path = parentMatter.Path + "/" + matter.Name
|
matter.Path = parentMatter.Path + "/" + matter.Name
|
||||||
matter = this.matterDao.Save(matter)
|
matter = this.matterDao.Save(matter)
|
||||||
|
|
||||||
//调整该文件夹下文件的Path.
|
//adjust children.
|
||||||
matters := this.matterDao.ListByPuuidAndUserUuid(matter.Uuid, matter.UserUuid, nil)
|
matters := this.matterDao.ListByPuuidAndUserUuid(matter.Uuid, matter.UserUuid, nil)
|
||||||
for _, m := range matters {
|
for _, m := range matters {
|
||||||
this.adjustPath(m, matter)
|
this.adjustPath(m, matter)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
//如果源是普通文件
|
//delete caches.
|
||||||
|
|
||||||
//删除该文件的所有缓存
|
|
||||||
this.imageCacheDao.DeleteByMatterUuid(matter.Uuid)
|
this.imageCacheDao.DeleteByMatterUuid(matter.Uuid)
|
||||||
|
|
||||||
//调整path
|
|
||||||
matter.Path = parentMatter.Path + "/" + matter.Name
|
matter.Path = parentMatter.Path + "/" + matter.Name
|
||||||
matter = this.matterDao.Save(matter)
|
matter = this.matterDao.Save(matter)
|
||||||
}
|
}
|
||||||
|
@ -41,14 +41,13 @@ func (this *PreferenceController) RegisterRoutes() map[string]func(writer http.R
|
|||||||
return routeMap
|
return routeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
//简单验证蓝眼云盘服务是否已经启动了。
|
//ping the application. Return current version.
|
||||||
func (this *PreferenceController) Ping(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *PreferenceController) Ping(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
return this.Success(nil)
|
return this.Success(core.VERSION)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//查看某个偏好设置的详情。
|
|
||||||
func (this *PreferenceController) Fetch(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *PreferenceController) Fetch(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
preference := this.preferenceService.Fetch()
|
preference := this.preferenceService.Fetch()
|
||||||
@ -56,14 +55,9 @@ func (this *PreferenceController) Fetch(writer http.ResponseWriter, request *htt
|
|||||||
return this.Success(preference)
|
return this.Success(preference)
|
||||||
}
|
}
|
||||||
|
|
||||||
//修改
|
|
||||||
func (this *PreferenceController) Edit(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *PreferenceController) Edit(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
//验证参数。
|
|
||||||
name := request.FormValue("name")
|
name := request.FormValue("name")
|
||||||
if name == "" {
|
|
||||||
panic("name参数必填")
|
|
||||||
}
|
|
||||||
|
|
||||||
logoUrl := request.FormValue("logoUrl")
|
logoUrl := request.FormValue("logoUrl")
|
||||||
faviconUrl := request.FormValue("faviconUrl")
|
faviconUrl := request.FormValue("faviconUrl")
|
||||||
@ -74,9 +68,13 @@ func (this *PreferenceController) Edit(writer http.ResponseWriter, request *http
|
|||||||
defaultTotalSizeLimitStr := request.FormValue("defaultTotalSizeLimit")
|
defaultTotalSizeLimitStr := request.FormValue("defaultTotalSizeLimit")
|
||||||
allowRegisterStr := request.FormValue("allowRegister")
|
allowRegisterStr := request.FormValue("allowRegister")
|
||||||
|
|
||||||
|
if name == "" {
|
||||||
|
panic(result.BadRequest("name cannot be null"))
|
||||||
|
}
|
||||||
|
|
||||||
var downloadDirMaxSize int64 = 0
|
var downloadDirMaxSize int64 = 0
|
||||||
if downloadDirMaxSizeStr == "" {
|
if downloadDirMaxSizeStr == "" {
|
||||||
panic("文件下载大小限制必填!")
|
panic(result.BadRequest("downloadDirMaxSize cannot be null"))
|
||||||
} else {
|
} else {
|
||||||
intDownloadDirMaxSize, err := strconv.Atoi(downloadDirMaxSizeStr)
|
intDownloadDirMaxSize, err := strconv.Atoi(downloadDirMaxSizeStr)
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
@ -85,7 +83,7 @@ func (this *PreferenceController) Edit(writer http.ResponseWriter, request *http
|
|||||||
|
|
||||||
var downloadDirMaxNum int64 = 0
|
var downloadDirMaxNum int64 = 0
|
||||||
if downloadDirMaxNumStr == "" {
|
if downloadDirMaxNumStr == "" {
|
||||||
panic("文件下载数量限制必填!")
|
panic(result.BadRequest("downloadDirMaxNum cannot be null"))
|
||||||
} else {
|
} else {
|
||||||
intDownloadDirMaxNum, err := strconv.Atoi(downloadDirMaxNumStr)
|
intDownloadDirMaxNum, err := strconv.Atoi(downloadDirMaxNumStr)
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
@ -94,7 +92,7 @@ func (this *PreferenceController) Edit(writer http.ResponseWriter, request *http
|
|||||||
|
|
||||||
var defaultTotalSizeLimit int64 = 0
|
var defaultTotalSizeLimit int64 = 0
|
||||||
if defaultTotalSizeLimitStr == "" {
|
if defaultTotalSizeLimitStr == "" {
|
||||||
panic("用户默认总限制!")
|
panic(result.BadRequest("defaultTotalSizeLimit cannot be null"))
|
||||||
} else {
|
} else {
|
||||||
intDefaultTotalSizeLimit, err := strconv.Atoi(defaultTotalSizeLimitStr)
|
intDefaultTotalSizeLimit, err := strconv.Atoi(defaultTotalSizeLimitStr)
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
@ -119,13 +117,13 @@ func (this *PreferenceController) Edit(writer http.ResponseWriter, request *http
|
|||||||
|
|
||||||
preference = this.preferenceDao.Save(preference)
|
preference = this.preferenceDao.Save(preference)
|
||||||
|
|
||||||
//重置缓存中的偏好
|
//reset the preference cache
|
||||||
this.preferenceService.Reset()
|
this.preferenceService.Reset()
|
||||||
|
|
||||||
return this.Success(preference)
|
return this.Success(preference)
|
||||||
}
|
}
|
||||||
|
|
||||||
//清扫系统,所有数据全部丢失。一定要非常慎点,非常慎点!只在系统初始化的时候点击!
|
//cleanup system data.
|
||||||
func (this *PreferenceController) SystemCleanup(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *PreferenceController) SystemCleanup(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
user := this.checkUser(request)
|
user := this.checkUser(request)
|
||||||
@ -135,7 +133,7 @@ func (this *PreferenceController) SystemCleanup(writer http.ResponseWriter, requ
|
|||||||
panic(result.BadRequest("password error"))
|
panic(result.BadRequest("password error"))
|
||||||
}
|
}
|
||||||
|
|
||||||
//清空系统
|
//this will trigger every bean to cleanup.
|
||||||
core.CONTEXT.Cleanup()
|
core.CONTEXT.Cleanup()
|
||||||
|
|
||||||
return this.Success("OK")
|
return this.Success("OK")
|
||||||
|
@ -33,7 +33,6 @@ func (this *PreferenceDao) Fetch() *Preference {
|
|||||||
return preference
|
return preference
|
||||||
}
|
}
|
||||||
|
|
||||||
//创建
|
|
||||||
func (this *PreferenceDao) Create(preference *Preference) *Preference {
|
func (this *PreferenceDao) Create(preference *Preference) *Preference {
|
||||||
|
|
||||||
timeUUID, _ := uuid.NewV4()
|
timeUUID, _ := uuid.NewV4()
|
||||||
@ -47,7 +46,6 @@ func (this *PreferenceDao) Create(preference *Preference) *Preference {
|
|||||||
return preference
|
return preference
|
||||||
}
|
}
|
||||||
|
|
||||||
//修改一个偏好设置
|
|
||||||
func (this *PreferenceDao) Save(preference *Preference) *Preference {
|
func (this *PreferenceDao) Save(preference *Preference) *Preference {
|
||||||
|
|
||||||
preference.UpdateTime = time.Now()
|
preference.UpdateTime = time.Now()
|
||||||
|
@ -19,7 +19,6 @@ func (this *PreferenceService) Init() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取单例的配置。
|
|
||||||
func (this *PreferenceService) Fetch() *Preference {
|
func (this *PreferenceService) Fetch() *Preference {
|
||||||
|
|
||||||
if this.preference == nil {
|
if this.preference == nil {
|
||||||
|
@ -34,7 +34,6 @@ func (this *SessionDao) CheckByUuid(uuid string) *Session {
|
|||||||
return entity
|
return entity
|
||||||
}
|
}
|
||||||
|
|
||||||
//创建一个session并且持久化到数据库中。
|
|
||||||
func (this *SessionDao) Create(session *Session) *Session {
|
func (this *SessionDao) Create(session *Session) *Session {
|
||||||
|
|
||||||
timeUUID, _ := uuid.NewV4()
|
timeUUID, _ := uuid.NewV4()
|
||||||
@ -48,7 +47,6 @@ func (this *SessionDao) Create(session *Session) *Session {
|
|||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
//修改一个session
|
|
||||||
func (this *SessionDao) Save(session *Session) *Session {
|
func (this *SessionDao) Save(session *Session) *Session {
|
||||||
|
|
||||||
session.UpdateTime = time.Now()
|
session.UpdateTime = time.Now()
|
||||||
|
@ -66,7 +66,6 @@ func (this *ShareController) RegisterRoutes() map[string]func(writer http.Respon
|
|||||||
return routeMap
|
return routeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
//创建一个分享
|
|
||||||
func (this *ShareController) Create(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *ShareController) Create(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
matterUuids := request.FormValue("matterUuids")
|
matterUuids := request.FormValue("matterUuids")
|
||||||
@ -113,9 +112,8 @@ func (this *ShareController) Create(writer http.ResponseWriter, request *http.Re
|
|||||||
|
|
||||||
matter := this.matterDao.CheckByUuid(uuid)
|
matter := this.matterDao.CheckByUuid(uuid)
|
||||||
|
|
||||||
//判断文件的所属人是否正确
|
|
||||||
if matter.UserUuid != user.Uuid {
|
if matter.UserUuid != user.Uuid {
|
||||||
panic(result.Unauthorized("不是你的文件,没有权限"))
|
panic(result.UNAUTHORIZED)
|
||||||
}
|
}
|
||||||
|
|
||||||
matters = append(matters, matter)
|
matters = append(matters, matter)
|
||||||
@ -130,7 +128,7 @@ func (this *ShareController) Create(writer http.ResponseWriter, request *http.Re
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if matter.Puuid != puuid {
|
if matter.Puuid != puuid {
|
||||||
panic(result.Unauthorized("一次只能分享同一个文件夹中的内容"))
|
panic(result.Unauthorized("you can only share files in the same directory"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,10 +136,9 @@ func (this *ShareController) Create(writer http.ResponseWriter, request *http.Re
|
|||||||
|
|
||||||
if len(matters) > 1 {
|
if len(matters) > 1 {
|
||||||
shareType = SHARE_TYPE_MIX
|
shareType = SHARE_TYPE_MIX
|
||||||
name = matters[0].Name + "," + matters[1].Name + " 等"
|
name = matters[0].Name + "," + matters[1].Name + " ..."
|
||||||
}
|
}
|
||||||
|
|
||||||
//创建share记录
|
|
||||||
share := &Share{
|
share := &Share{
|
||||||
Name: name,
|
Name: name,
|
||||||
ShareType: shareType,
|
ShareType: shareType,
|
||||||
@ -154,7 +151,6 @@ func (this *ShareController) Create(writer http.ResponseWriter, request *http.Re
|
|||||||
}
|
}
|
||||||
this.shareDao.Create(share)
|
this.shareDao.Create(share)
|
||||||
|
|
||||||
//创建关联的matter
|
|
||||||
for _, matter := range matters {
|
for _, matter := range matters {
|
||||||
bridge := &Bridge{
|
bridge := &Bridge{
|
||||||
ShareUuid: share.Uuid,
|
ShareUuid: share.Uuid,
|
||||||
@ -177,7 +173,6 @@ func (this *ShareController) Delete(writer http.ResponseWriter, request *http.Re
|
|||||||
|
|
||||||
if share != nil {
|
if share != nil {
|
||||||
|
|
||||||
//删除对应的bridge.
|
|
||||||
this.bridgeDao.DeleteByShareUuid(share.Uuid)
|
this.bridgeDao.DeleteByShareUuid(share.Uuid)
|
||||||
|
|
||||||
this.shareDao.Delete(share)
|
this.shareDao.Delete(share)
|
||||||
@ -186,7 +181,6 @@ func (this *ShareController) Delete(writer http.ResponseWriter, request *http.Re
|
|||||||
return this.Success(nil)
|
return this.Success(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
//删除一系列分享
|
|
||||||
func (this *ShareController) DeleteBatch(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *ShareController) DeleteBatch(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
uuids := request.FormValue("uuids")
|
uuids := request.FormValue("uuids")
|
||||||
@ -200,7 +194,6 @@ func (this *ShareController) DeleteBatch(writer http.ResponseWriter, request *ht
|
|||||||
|
|
||||||
imageCache := this.shareDao.FindByUuid(uuid)
|
imageCache := this.shareDao.FindByUuid(uuid)
|
||||||
|
|
||||||
//判断图片缓存的所属人是否正确
|
|
||||||
user := this.checkUser(request)
|
user := this.checkUser(request)
|
||||||
if imageCache.UserUuid != user.Uuid {
|
if imageCache.UserUuid != user.Uuid {
|
||||||
panic(result.UNAUTHORIZED)
|
panic(result.UNAUTHORIZED)
|
||||||
@ -209,10 +202,9 @@ func (this *ShareController) DeleteBatch(writer http.ResponseWriter, request *ht
|
|||||||
this.shareDao.Delete(imageCache)
|
this.shareDao.Delete(imageCache)
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.Success("删除成功!")
|
return this.Success("OK")
|
||||||
}
|
}
|
||||||
|
|
||||||
//查看详情。
|
|
||||||
func (this *ShareController) Detail(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *ShareController) Detail(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
uuid := request.FormValue("uuid")
|
uuid := request.FormValue("uuid")
|
||||||
@ -222,7 +214,6 @@ func (this *ShareController) Detail(writer http.ResponseWriter, request *http.Re
|
|||||||
|
|
||||||
share := this.shareDao.CheckByUuid(uuid)
|
share := this.shareDao.CheckByUuid(uuid)
|
||||||
|
|
||||||
//验证当前之人是否有权限查看这么详细。
|
|
||||||
user := this.checkUser(request)
|
user := this.checkUser(request)
|
||||||
|
|
||||||
if share.UserUuid != user.Uuid {
|
if share.UserUuid != user.Uuid {
|
||||||
@ -233,10 +224,8 @@ func (this *ShareController) Detail(writer http.ResponseWriter, request *http.Re
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//按照分页的方式查询
|
|
||||||
func (this *ShareController) Page(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *ShareController) Page(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
//如果是根目录,那么就传入root.
|
|
||||||
pageStr := request.FormValue("page")
|
pageStr := request.FormValue("page")
|
||||||
pageSizeStr := request.FormValue("pageSize")
|
pageSizeStr := request.FormValue("pageSize")
|
||||||
orderCreateTime := request.FormValue("orderCreateTime")
|
orderCreateTime := request.FormValue("orderCreateTime")
|
||||||
@ -268,37 +257,30 @@ func (this *ShareController) Page(writer http.ResponseWriter, request *http.Requ
|
|||||||
return this.Success(pager)
|
return this.Success(pager)
|
||||||
}
|
}
|
||||||
|
|
||||||
//验证提取码对应的某个shareUuid是否有效
|
|
||||||
func (this *ShareController) CheckShare(writer http.ResponseWriter, request *http.Request) *Share {
|
func (this *ShareController) CheckShare(writer http.ResponseWriter, request *http.Request) *Share {
|
||||||
|
|
||||||
//如果是根目录,那么就传入root.
|
|
||||||
shareUuid := request.FormValue("shareUuid")
|
shareUuid := request.FormValue("shareUuid")
|
||||||
code := request.FormValue("code")
|
code := request.FormValue("code")
|
||||||
user := this.findUser(request)
|
user := this.findUser(request)
|
||||||
|
|
||||||
return this.shareService.CheckShare(shareUuid, code, user)
|
return this.shareService.CheckShare(request, shareUuid, code, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
//浏览某个分享中的文件
|
|
||||||
func (this *ShareController) Browse(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *ShareController) Browse(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
//如果是根目录,那么就传入root.
|
|
||||||
shareUuid := request.FormValue("shareUuid")
|
shareUuid := request.FormValue("shareUuid")
|
||||||
code := request.FormValue("code")
|
code := request.FormValue("code")
|
||||||
|
|
||||||
//当前查看的puuid。 puuid=root表示查看分享的根目录,其余表示查看某个文件夹下的文件。
|
//puuid can be "root"
|
||||||
puuid := request.FormValue("puuid")
|
puuid := request.FormValue("puuid")
|
||||||
rootUuid := request.FormValue("rootUuid")
|
rootUuid := request.FormValue("rootUuid")
|
||||||
|
|
||||||
user := this.findUser(request)
|
user := this.findUser(request)
|
||||||
share := this.shareService.CheckShare(shareUuid, code, user)
|
share := this.shareService.CheckShare(request, shareUuid, code, user)
|
||||||
bridges := this.bridgeDao.FindByShareUuid(share.Uuid)
|
bridges := this.bridgeDao.FindByShareUuid(share.Uuid)
|
||||||
|
|
||||||
if puuid == MATTER_ROOT {
|
if puuid == MATTER_ROOT {
|
||||||
|
|
||||||
//分享的根目录
|
|
||||||
|
|
||||||
//获取对应的 matter.
|
|
||||||
var matters []*Matter
|
var matters []*Matter
|
||||||
if len(bridges) != 0 {
|
if len(bridges) != 0 {
|
||||||
uuids := make([]string, 0)
|
uuids := make([]string, 0)
|
||||||
@ -318,21 +300,21 @@ func (this *ShareController) Browse(writer http.ResponseWriter, request *http.Re
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
//如果当前查看的目录就是根目录,那么无需再验证
|
//if root. No need to validate.
|
||||||
if puuid == rootUuid {
|
if puuid == rootUuid {
|
||||||
dirMatter := this.matterDao.CheckByUuid(puuid)
|
dirMatter := this.matterDao.CheckByUuid(puuid)
|
||||||
share.DirMatter = dirMatter
|
share.DirMatter = dirMatter
|
||||||
} else {
|
} else {
|
||||||
dirMatter := this.matterService.Detail(request, puuid)
|
dirMatter := this.matterService.Detail(request, puuid)
|
||||||
|
|
||||||
//验证 shareRootMatter是否在被分享。
|
//check whether shareRootMatter is being sharing
|
||||||
shareRootMatter := this.matterDao.CheckByUuid(rootUuid)
|
shareRootMatter := this.matterDao.CheckByUuid(rootUuid)
|
||||||
if !shareRootMatter.Dir {
|
if !shareRootMatter.Dir {
|
||||||
panic(result.BadRequestI18n(request, i18n.MatterDestinationMustDirectory))
|
panic(result.BadRequestI18n(request, i18n.MatterDestinationMustDirectory))
|
||||||
}
|
}
|
||||||
this.bridgeDao.CheckByShareUuidAndMatterUuid(share.Uuid, shareRootMatter.Uuid)
|
this.bridgeDao.CheckByShareUuidAndMatterUuid(share.Uuid, shareRootMatter.Uuid)
|
||||||
|
|
||||||
//到rootUuid的地方掐断。
|
//stop at rootUuid
|
||||||
find := false
|
find := false
|
||||||
parentMatter := dirMatter.Parent
|
parentMatter := dirMatter.Parent
|
||||||
for parentMatter != nil {
|
for parentMatter != nil {
|
||||||
@ -357,14 +339,11 @@ func (this *ShareController) Browse(writer http.ResponseWriter, request *http.Re
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//下载压缩包
|
|
||||||
func (this *ShareController) Zip(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *ShareController) Zip(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
//如果是根目录,那么就传入root.
|
|
||||||
shareUuid := request.FormValue("shareUuid")
|
shareUuid := request.FormValue("shareUuid")
|
||||||
code := request.FormValue("code")
|
code := request.FormValue("code")
|
||||||
|
|
||||||
//当前查看的puuid。 puuid=root表示查看分享的根目录,其余表示查看某个文件夹下的文件。
|
|
||||||
puuid := request.FormValue("puuid")
|
puuid := request.FormValue("puuid")
|
||||||
rootUuid := request.FormValue("rootUuid")
|
rootUuid := request.FormValue("rootUuid")
|
||||||
|
|
||||||
@ -372,8 +351,8 @@ func (this *ShareController) Zip(writer http.ResponseWriter, request *http.Reque
|
|||||||
|
|
||||||
if puuid == MATTER_ROOT {
|
if puuid == MATTER_ROOT {
|
||||||
|
|
||||||
//下载分享全部内容。
|
//download all things.
|
||||||
share := this.shareService.CheckShare(shareUuid, code, user)
|
share := this.shareService.CheckShare(request, shareUuid, code, user)
|
||||||
bridges := this.bridgeDao.FindByShareUuid(share.Uuid)
|
bridges := this.bridgeDao.FindByShareUuid(share.Uuid)
|
||||||
var matterUuids []string
|
var matterUuids []string
|
||||||
for _, bridge := range bridges {
|
for _, bridge := range bridges {
|
||||||
@ -384,9 +363,9 @@ func (this *ShareController) Zip(writer http.ResponseWriter, request *http.Reque
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
//下载某个目录。
|
//download a folder.
|
||||||
matter := this.matterDao.CheckByUuid(puuid)
|
matter := this.matterDao.CheckByUuid(puuid)
|
||||||
this.shareService.ValidateMatter(shareUuid, code, user, rootUuid, matter)
|
this.shareService.ValidateMatter(request, shareUuid, code, user, rootUuid, matter)
|
||||||
this.matterService.DownloadZip(writer, request, []*Matter{matter})
|
this.matterService.DownloadZip(writer, request, []*Matter{matter})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@ func (this *ShareDao) CheckByUuid(uuid string) *Share {
|
|||||||
return entity
|
return entity
|
||||||
}
|
}
|
||||||
|
|
||||||
//按分页条件获取分页
|
|
||||||
func (this *ShareDao) Page(page int, pageSize int, userUuid string, sortArray []builder.OrderPair) *Pager {
|
func (this *ShareDao) Page(page int, pageSize int, userUuid string, sortArray []builder.OrderPair) *Pager {
|
||||||
|
|
||||||
var wp = &builder.WherePair{}
|
var wp = &builder.WherePair{}
|
||||||
@ -61,7 +60,6 @@ func (this *ShareDao) Page(page int, pageSize int, userUuid string, sortArray []
|
|||||||
return pager
|
return pager
|
||||||
}
|
}
|
||||||
|
|
||||||
//创建
|
|
||||||
func (this *ShareDao) Create(share *Share) *Share {
|
func (this *ShareDao) Create(share *Share) *Share {
|
||||||
|
|
||||||
timeUUID, _ := uuid.NewV4()
|
timeUUID, _ := uuid.NewV4()
|
||||||
@ -75,7 +73,6 @@ func (this *ShareDao) Create(share *Share) *Share {
|
|||||||
return share
|
return share
|
||||||
}
|
}
|
||||||
|
|
||||||
//修改一条记录
|
|
||||||
func (this *ShareDao) Save(share *Share) *Share {
|
func (this *ShareDao) Save(share *Share) *Share {
|
||||||
|
|
||||||
share.UpdateTime = time.Now()
|
share.UpdateTime = time.Now()
|
||||||
|
@ -6,11 +6,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
//单文件
|
//single file.
|
||||||
SHARE_TYPE_FILE = "FILE"
|
SHARE_TYPE_FILE = "FILE"
|
||||||
//文件夹
|
//directory
|
||||||
SHARE_TYPE_DIRECTORY = "DIRECTORY"
|
SHARE_TYPE_DIRECTORY = "DIRECTORY"
|
||||||
//混合体
|
//mix things
|
||||||
SHARE_TYPE_MIX = "MIX"
|
SHARE_TYPE_MIX = "MIX"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分享记录
|
* share record
|
||||||
*/
|
*/
|
||||||
type Share struct {
|
type Share struct {
|
||||||
Base
|
Base
|
||||||
|
@ -2,7 +2,9 @@ package rest
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/eyebluecn/tank/code/core"
|
"github.com/eyebluecn/tank/code/core"
|
||||||
|
"github.com/eyebluecn/tank/code/tool/i18n"
|
||||||
"github.com/eyebluecn/tank/code/tool/result"
|
"github.com/eyebluecn/tank/code/tool/result"
|
||||||
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -41,7 +43,6 @@ func (this *ShareService) Init() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取某个分享的详情。
|
|
||||||
func (this *ShareService) Detail(uuid string) *Share {
|
func (this *ShareService) Detail(uuid string) *Share {
|
||||||
|
|
||||||
share := this.shareDao.CheckByUuid(uuid)
|
share := this.shareDao.CheckByUuid(uuid)
|
||||||
@ -49,17 +50,17 @@ func (this *ShareService) Detail(uuid string) *Share {
|
|||||||
return share
|
return share
|
||||||
}
|
}
|
||||||
|
|
||||||
//验证一个shareUuid和shareCode是否匹配和有权限。
|
// check whether shareUuid and shareCode matches. check whether user can access.
|
||||||
func (this *ShareService) CheckShare(shareUuid string, code string, user *User) *Share {
|
func (this *ShareService) CheckShare(request *http.Request, shareUuid string, code string, user *User) *Share {
|
||||||
|
|
||||||
share := this.shareDao.CheckByUuid(shareUuid)
|
share := this.shareDao.CheckByUuid(shareUuid)
|
||||||
//如果是自己的分享,可以不要提取码
|
//if self, not need shareCode
|
||||||
if user == nil || user.Uuid != share.UserUuid {
|
if user == nil || user.Uuid != share.UserUuid {
|
||||||
//没有登录,或者查看的不是自己的分享,要求有验证码
|
//if not login or not self's share, shareCode is required.
|
||||||
if code == "" {
|
if code == "" {
|
||||||
panic(result.CustomWebResult(result.NEED_SHARE_CODE, "提取码必填"))
|
panic(result.CustomWebResultI18n(request, result.NEED_SHARE_CODE, i18n.ShareCodeRequired))
|
||||||
} else if share.Code != code {
|
} else if share.Code != code {
|
||||||
panic(result.CustomWebResult(result.SHARE_CODE_ERROR, "提取码错误"))
|
panic(result.CustomWebResultI18n(request, result.SHARE_CODE_ERROR, i18n.ShareCodeError))
|
||||||
} else {
|
} else {
|
||||||
if !share.ExpireInfinity {
|
if !share.ExpireInfinity {
|
||||||
if share.ExpireTime.Before(time.Now()) {
|
if share.ExpireTime.Before(time.Now()) {
|
||||||
@ -71,15 +72,14 @@ func (this *ShareService) CheckShare(shareUuid string, code string, user *User)
|
|||||||
return share
|
return share
|
||||||
}
|
}
|
||||||
|
|
||||||
//根据某个shareUuid和code,某个用户是否有权限获取 shareRootUuid 下面的 matterUuid
|
//check whether a user can access a matter. shareRootUuid is matter's parent(or parent's parent and so on)
|
||||||
//如果是根目录下的文件,那么shareRootUuid传root.
|
func (this *ShareService) ValidateMatter(request *http.Request, shareUuid string, code string, user *User, shareRootUuid string, matter *Matter) {
|
||||||
func (this *ShareService) ValidateMatter(shareUuid string, code string, user *User, shareRootUuid string, matter *Matter) {
|
|
||||||
|
|
||||||
if matter == nil {
|
if matter == nil {
|
||||||
panic(result.Unauthorized("matter cannot be nil"))
|
panic(result.Unauthorized("matter cannot be nil"))
|
||||||
}
|
}
|
||||||
|
|
||||||
//如果文件是自己的,那么放行
|
//if self's matter, ok.
|
||||||
if user != nil && matter.UserUuid == user.Uuid {
|
if user != nil && matter.UserUuid == user.Uuid {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -88,19 +88,19 @@ func (this *ShareService) ValidateMatter(shareUuid string, code string, user *Us
|
|||||||
panic(result.Unauthorized("shareUuid,code,shareRootUuid cannot be null"))
|
panic(result.Unauthorized("shareUuid,code,shareRootUuid cannot be null"))
|
||||||
}
|
}
|
||||||
|
|
||||||
share := this.CheckShare(shareUuid, code, user)
|
share := this.CheckShare(request, shareUuid, code, user)
|
||||||
|
|
||||||
//如果shareRootUuid是根,那么matterUuid在bridge中应该有记录
|
//if shareRootUuid is root. Bridge must has record.
|
||||||
if shareRootUuid == MATTER_ROOT {
|
if shareRootUuid == MATTER_ROOT {
|
||||||
|
|
||||||
this.bridgeDao.CheckByShareUuidAndMatterUuid(share.Uuid, matter.Uuid)
|
this.bridgeDao.CheckByShareUuidAndMatterUuid(share.Uuid, matter.Uuid)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
//验证 shareRootMatter是否在被分享。
|
//check whether shareRootMatter is being sharing
|
||||||
shareRootMatter := this.matterDao.CheckByUuid(shareRootUuid)
|
shareRootMatter := this.matterDao.CheckByUuid(shareRootUuid)
|
||||||
this.bridgeDao.CheckByShareUuidAndMatterUuid(share.Uuid, shareRootMatter.Uuid)
|
this.bridgeDao.CheckByShareUuidAndMatterUuid(share.Uuid, shareRootMatter.Uuid)
|
||||||
|
|
||||||
//保证 puuid对应的matter是shareRootMatter的子文件夹。
|
// shareRootMatter is ancestor of matter.
|
||||||
child := strings.HasPrefix(matter.Path, shareRootMatter.Path)
|
child := strings.HasPrefix(matter.Path, shareRootMatter.Path)
|
||||||
if !child {
|
if !child {
|
||||||
panic(result.BadRequest("%s is not %s's children", matter.Uuid, shareRootUuid))
|
panic(result.BadRequest("%s is not %s's children", matter.Uuid, shareRootUuid))
|
||||||
|
@ -34,7 +34,6 @@ func (this *UploadTokenDao) CheckByUuid(uuid string) *UploadToken {
|
|||||||
return entity
|
return entity
|
||||||
}
|
}
|
||||||
|
|
||||||
//创建一个session并且持久化到数据库中。
|
|
||||||
func (this *UploadTokenDao) Create(uploadToken *UploadToken) *UploadToken {
|
func (this *UploadTokenDao) Create(uploadToken *UploadToken) *UploadToken {
|
||||||
|
|
||||||
timeUUID, _ := uuid.NewV4()
|
timeUUID, _ := uuid.NewV4()
|
||||||
@ -49,7 +48,6 @@ func (this *UploadTokenDao) Create(uploadToken *UploadToken) *UploadToken {
|
|||||||
return uploadToken
|
return uploadToken
|
||||||
}
|
}
|
||||||
|
|
||||||
//修改一个uploadToken
|
|
||||||
func (this *UploadTokenDao) Save(uploadToken *UploadToken) *UploadToken {
|
func (this *UploadTokenDao) Save(uploadToken *UploadToken) *UploadToken {
|
||||||
|
|
||||||
uploadToken.UpdateTime = time.Now()
|
uploadToken.UpdateTime = time.Now()
|
||||||
|
@ -47,11 +47,11 @@ func (this *UserController) RegisterRoutes() map[string]func(writer http.Respons
|
|||||||
|
|
||||||
func (this *UserController) innerLogin(writer http.ResponseWriter, request *http.Request, user *User) {
|
func (this *UserController) innerLogin(writer http.ResponseWriter, request *http.Request, user *User) {
|
||||||
|
|
||||||
//登录成功,设置Cookie。有效期30天。
|
//set cookie. expire after 30 days.
|
||||||
expiration := time.Now()
|
expiration := time.Now()
|
||||||
expiration = expiration.AddDate(0, 0, 30)
|
expiration = expiration.AddDate(0, 0, 30)
|
||||||
|
|
||||||
//持久化用户的session.
|
//save session to db.
|
||||||
session := &Session{
|
session := &Session{
|
||||||
UserUuid: user.Uuid,
|
UserUuid: user.Uuid,
|
||||||
Ip: util.GetIpAddress(request),
|
Ip: util.GetIpAddress(request),
|
||||||
@ -61,7 +61,7 @@ func (this *UserController) innerLogin(writer http.ResponseWriter, request *http
|
|||||||
session.CreateTime = time.Now()
|
session.CreateTime = time.Now()
|
||||||
session = this.sessionDao.Create(session)
|
session = this.sessionDao.Create(session)
|
||||||
|
|
||||||
//设置用户的cookie.
|
//set cookie
|
||||||
cookie := http.Cookie{
|
cookie := http.Cookie{
|
||||||
Name: core.COOKIE_AUTH_KEY,
|
Name: core.COOKIE_AUTH_KEY,
|
||||||
Path: "/",
|
Path: "/",
|
||||||
@ -69,16 +69,13 @@ func (this *UserController) innerLogin(writer http.ResponseWriter, request *http
|
|||||||
Expires: expiration}
|
Expires: expiration}
|
||||||
http.SetCookie(writer, &cookie)
|
http.SetCookie(writer, &cookie)
|
||||||
|
|
||||||
//更新用户上次登录时间和ip
|
//update lastTime and lastIp
|
||||||
user.LastTime = time.Now()
|
user.LastTime = time.Now()
|
||||||
user.LastIp = util.GetIpAddress(request)
|
user.LastIp = util.GetIpAddress(request)
|
||||||
this.userDao.Save(user)
|
this.userDao.Save(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
//使用用户名和密码进行登录。
|
//login by username and password
|
||||||
//参数:
|
|
||||||
// @username:用户名
|
|
||||||
// @password:密码
|
|
||||||
func (this *UserController) Login(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *UserController) Login(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
username := request.FormValue("username")
|
username := request.FormValue("username")
|
||||||
@ -101,7 +98,7 @@ func (this *UserController) Login(writer http.ResponseWriter, request *http.Requ
|
|||||||
return this.Success(user)
|
return this.Success(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
//使用Authentication进行登录。
|
//login by authentication.
|
||||||
func (this *UserController) AuthenticationLogin(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *UserController) AuthenticationLogin(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
authentication := request.FormValue("authentication")
|
authentication := request.FormValue("authentication")
|
||||||
@ -122,7 +119,7 @@ func (this *UserController) AuthenticationLogin(writer http.ResponseWriter, requ
|
|||||||
return this.Success(user)
|
return this.Success(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
//用户自主注册。
|
//register by username and password. After registering, will auto login.
|
||||||
func (this *UserController) Register(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *UserController) Register(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
username := request.FormValue("username")
|
username := request.FormValue("username")
|
||||||
@ -133,7 +130,7 @@ func (this *UserController) Register(writer http.ResponseWriter, request *http.R
|
|||||||
panic(result.BadRequestI18n(request, i18n.UserRegisterNotAllowd))
|
panic(result.BadRequestI18n(request, i18n.UserRegisterNotAllowd))
|
||||||
}
|
}
|
||||||
|
|
||||||
if m, _ := regexp.MatchString(`^[0-9a-zA-Z_]+$`, username); !m {
|
if m, _ := regexp.MatchString(USERNAME_PATTERN, username); !m {
|
||||||
panic(result.BadRequestI18n(request, i18n.UsernameError))
|
panic(result.BadRequestI18n(request, i18n.UsernameError))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +138,6 @@ func (this *UserController) Register(writer http.ResponseWriter, request *http.R
|
|||||||
panic(result.BadRequestI18n(request, i18n.UserPasswordLengthError))
|
panic(result.BadRequestI18n(request, i18n.UserPasswordLengthError))
|
||||||
}
|
}
|
||||||
|
|
||||||
//判断重名。
|
|
||||||
if this.userDao.CountByUsername(username) > 0 {
|
if this.userDao.CountByUsername(username) > 0 {
|
||||||
panic(result.BadRequestI18n(request, i18n.UsernameExist, username))
|
panic(result.BadRequestI18n(request, i18n.UsernameExist, username))
|
||||||
}
|
}
|
||||||
@ -156,50 +152,45 @@ func (this *UserController) Register(writer http.ResponseWriter, request *http.R
|
|||||||
|
|
||||||
user = this.userDao.Create(user)
|
user = this.userDao.Create(user)
|
||||||
|
|
||||||
//做一次登录操作
|
//auto login
|
||||||
this.innerLogin(writer, request, user)
|
this.innerLogin(writer, request, user)
|
||||||
|
|
||||||
return this.Success(user)
|
return this.Success(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
//编辑一个用户的资料。
|
|
||||||
func (this *UserController) Edit(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *UserController) Edit(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
avatarUrl := request.FormValue("avatarUrl")
|
avatarUrl := request.FormValue("avatarUrl")
|
||||||
uuid := request.FormValue("uuid")
|
uuid := request.FormValue("uuid")
|
||||||
|
|
||||||
currentUser := this.checkUser(request)
|
|
||||||
user := this.userDao.CheckByUuid(uuid)
|
|
||||||
|
|
||||||
if currentUser.Role == USER_ROLE_ADMINISTRATOR {
|
|
||||||
//只有管理员可以改变用户上传的大小
|
|
||||||
//判断用户上传大小限制。
|
|
||||||
sizeLimitStr := request.FormValue("sizeLimit")
|
sizeLimitStr := request.FormValue("sizeLimit")
|
||||||
|
|
||||||
|
user := this.checkUser(request)
|
||||||
|
currentUser := this.userDao.CheckByUuid(uuid)
|
||||||
|
|
||||||
|
if user.Role == USER_ROLE_ADMINISTRATOR {
|
||||||
|
//only admin can edit user's sizeLimit
|
||||||
var sizeLimit int64 = 0
|
var sizeLimit int64 = 0
|
||||||
if sizeLimitStr == "" {
|
if sizeLimitStr == "" {
|
||||||
panic("用户上传限制必填!")
|
panic("user's limit size is required")
|
||||||
} else {
|
} else {
|
||||||
intsizeLimit, err := strconv.Atoi(sizeLimitStr)
|
intSizeLimit, err := strconv.Atoi(sizeLimitStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
}
|
}
|
||||||
sizeLimit = int64(intsizeLimit)
|
sizeLimit = int64(intSizeLimit)
|
||||||
}
|
}
|
||||||
user.SizeLimit = sizeLimit
|
currentUser.SizeLimit = sizeLimit
|
||||||
} else {
|
} else if user.Uuid != uuid {
|
||||||
if currentUser.Uuid != uuid {
|
|
||||||
panic(result.UNAUTHORIZED)
|
panic(result.UNAUTHORIZED)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentUser.AvatarUrl = avatarUrl
|
||||||
|
|
||||||
|
currentUser = this.userDao.Save(currentUser)
|
||||||
|
|
||||||
|
return this.Success(currentUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
user.AvatarUrl = avatarUrl
|
|
||||||
|
|
||||||
user = this.userDao.Save(user)
|
|
||||||
|
|
||||||
return this.Success(user)
|
|
||||||
}
|
|
||||||
|
|
||||||
//获取用户详情
|
|
||||||
func (this *UserController) Detail(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *UserController) Detail(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
uuid := request.FormValue("uuid")
|
uuid := request.FormValue("uuid")
|
||||||
@ -210,13 +201,12 @@ func (this *UserController) Detail(writer http.ResponseWriter, request *http.Req
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//退出登录
|
|
||||||
func (this *UserController) Logout(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *UserController) Logout(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
//session置为过期
|
//expire session.
|
||||||
sessionCookie, err := request.Cookie(core.COOKIE_AUTH_KEY)
|
sessionCookie, err := request.Cookie(core.COOKIE_AUTH_KEY)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return this.Success("已经退出登录了!")
|
return this.Success("OK")
|
||||||
}
|
}
|
||||||
sessionId := sessionCookie.Value
|
sessionId := sessionCookie.Value
|
||||||
|
|
||||||
@ -227,13 +217,13 @@ func (this *UserController) Logout(writer http.ResponseWriter, request *http.Req
|
|||||||
this.sessionDao.Save(session)
|
this.sessionDao.Save(session)
|
||||||
}
|
}
|
||||||
|
|
||||||
//删掉session缓存
|
//delete session.
|
||||||
_, err = core.CONTEXT.GetSessionCache().Delete(sessionId)
|
_, err = core.CONTEXT.GetSessionCache().Delete(sessionId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.logger.Error("删除用户session缓存时出错")
|
this.logger.Error("error while deleting session.")
|
||||||
}
|
}
|
||||||
|
|
||||||
//清空客户端的cookie.
|
//clear cookie.
|
||||||
expiration := time.Now()
|
expiration := time.Now()
|
||||||
expiration = expiration.AddDate(-1, 0, 0)
|
expiration = expiration.AddDate(-1, 0, 0)
|
||||||
cookie := http.Cookie{
|
cookie := http.Cookie{
|
||||||
@ -243,10 +233,9 @@ func (this *UserController) Logout(writer http.ResponseWriter, request *http.Req
|
|||||||
Expires: expiration}
|
Expires: expiration}
|
||||||
http.SetCookie(writer, &cookie)
|
http.SetCookie(writer, &cookie)
|
||||||
|
|
||||||
return this.Success("退出成功!")
|
return this.Success("OK")
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取用户列表 管理员的权限。
|
|
||||||
func (this *UserController) Page(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *UserController) Page(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
pageStr := request.FormValue("page")
|
pageStr := request.FormValue("page")
|
||||||
@ -298,14 +287,13 @@ func (this *UserController) Page(writer http.ResponseWriter, request *http.Reque
|
|||||||
return this.Success(pager)
|
return this.Success(pager)
|
||||||
}
|
}
|
||||||
|
|
||||||
//修改用户状态
|
|
||||||
func (this *UserController) ToggleStatus(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *UserController) ToggleStatus(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
uuid := request.FormValue("uuid")
|
uuid := request.FormValue("uuid")
|
||||||
currentUser := this.userDao.CheckByUuid(uuid)
|
currentUser := this.userDao.CheckByUuid(uuid)
|
||||||
user := this.checkUser(request)
|
user := this.checkUser(request)
|
||||||
if uuid == user.Uuid {
|
if uuid == user.Uuid {
|
||||||
panic(result.Unauthorized("你不能操作自己的状态。"))
|
panic(result.UNAUTHORIZED)
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentUser.Status == USER_STATUS_OK {
|
if currentUser.Status == USER_STATUS_OK {
|
||||||
@ -320,17 +308,15 @@ func (this *UserController) ToggleStatus(writer http.ResponseWriter, request *ht
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//变身为指定用户。
|
|
||||||
func (this *UserController) Transfiguration(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *UserController) Transfiguration(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
uuid := request.FormValue("uuid")
|
uuid := request.FormValue("uuid")
|
||||||
currentUser := this.userDao.CheckByUuid(uuid)
|
currentUser := this.userDao.CheckByUuid(uuid)
|
||||||
|
|
||||||
//有效期10分钟
|
//expire after 10 minutes.
|
||||||
expiration := time.Now()
|
expiration := time.Now()
|
||||||
expiration = expiration.Add(10 * time.Minute)
|
expiration = expiration.Add(10 * time.Minute)
|
||||||
|
|
||||||
//持久化用户的session.
|
|
||||||
session := &Session{
|
session := &Session{
|
||||||
UserUuid: currentUser.Uuid,
|
UserUuid: currentUser.Uuid,
|
||||||
Ip: util.GetIpAddress(request),
|
Ip: util.GetIpAddress(request),
|
||||||
@ -343,7 +329,6 @@ func (this *UserController) Transfiguration(writer http.ResponseWriter, request
|
|||||||
return this.Success(session.Uuid)
|
return this.Success(session.Uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
//用户修改密码
|
|
||||||
func (this *UserController) ChangePassword(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *UserController) ChangePassword(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
oldPassword := request.FormValue("oldPassword")
|
oldPassword := request.FormValue("oldPassword")
|
||||||
@ -354,8 +339,8 @@ func (this *UserController) ChangePassword(writer http.ResponseWriter, request *
|
|||||||
|
|
||||||
user := this.checkUser(request)
|
user := this.checkUser(request)
|
||||||
|
|
||||||
//如果是demo账号,不提供修改密码的功能。
|
//if username is demo, cannot change password.
|
||||||
if user.Username == "demo" {
|
if user.Username == USERNAME_DEMO {
|
||||||
return this.Success(user)
|
return this.Success(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,7 +355,7 @@ func (this *UserController) ChangePassword(writer http.ResponseWriter, request *
|
|||||||
return this.Success(user)
|
return this.Success(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
//管理员重置用户密码
|
//admin reset password.
|
||||||
func (this *UserController) ResetPassword(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
func (this *UserController) ResetPassword(writer http.ResponseWriter, request *http.Request) *result.WebResult {
|
||||||
|
|
||||||
userUuid := request.FormValue("userUuid")
|
userUuid := request.FormValue("userUuid")
|
||||||
|
@ -16,11 +16,10 @@ func (this *UserDao) Init() {
|
|||||||
this.BaseDao.Init()
|
this.BaseDao.Init()
|
||||||
}
|
}
|
||||||
|
|
||||||
//创建用户
|
|
||||||
func (this *UserDao) Create(user *User) *User {
|
func (this *UserDao) Create(user *User) *User {
|
||||||
|
|
||||||
if user == nil {
|
if user == nil {
|
||||||
panic("参数不能为nil")
|
panic(result.BadRequest("user cannot be nil"))
|
||||||
}
|
}
|
||||||
|
|
||||||
timeUUID, _ := uuid.NewV4()
|
timeUUID, _ := uuid.NewV4()
|
||||||
@ -59,7 +58,6 @@ func (this *UserDao) CheckByUuid(uuid string) *User {
|
|||||||
return entity
|
return entity
|
||||||
}
|
}
|
||||||
|
|
||||||
//查询用户。
|
|
||||||
func (this *UserDao) FindByUsername(username string) *User {
|
func (this *UserDao) FindByUsername(username string) *User {
|
||||||
|
|
||||||
var user = &User{}
|
var user = &User{}
|
||||||
@ -74,7 +72,6 @@ func (this *UserDao) FindByUsername(username string) *User {
|
|||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
//显示用户列表。
|
|
||||||
func (this *UserDao) Page(page int, pageSize int, username string, email string, phone string, status string, sortArray []builder.OrderPair) *Pager {
|
func (this *UserDao) Page(page int, pageSize int, username string, email string, phone string, status string, sortArray []builder.OrderPair) *Pager {
|
||||||
|
|
||||||
var wp = &builder.WherePair{}
|
var wp = &builder.WherePair{}
|
||||||
@ -114,7 +111,6 @@ func (this *UserDao) Page(page int, pageSize int, username string, email string,
|
|||||||
return pager
|
return pager
|
||||||
}
|
}
|
||||||
|
|
||||||
//查询某个用户名是否已经有用户了
|
|
||||||
func (this *UserDao) CountByUsername(username string) int {
|
func (this *UserDao) CountByUsername(username string) int {
|
||||||
var count int
|
var count int
|
||||||
db := core.CONTEXT.GetDB().
|
db := core.CONTEXT.GetDB().
|
||||||
@ -125,7 +121,6 @@ func (this *UserDao) CountByUsername(username string) int {
|
|||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
//保存用户
|
|
||||||
func (this *UserDao) Save(user *User) *User {
|
func (this *UserDao) Save(user *User) *User {
|
||||||
|
|
||||||
user.UpdateTime = time.Now()
|
user.UpdateTime = time.Now()
|
||||||
|
@ -6,21 +6,27 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
//游客身份
|
//guest
|
||||||
USER_ROLE_GUEST = "GUEST"
|
USER_ROLE_GUEST = "GUEST"
|
||||||
//普通注册用户
|
//normal user
|
||||||
USER_ROLE_USER = "USER"
|
USER_ROLE_USER = "USER"
|
||||||
//管理员
|
//administrator
|
||||||
USER_ROLE_ADMINISTRATOR = "ADMINISTRATOR"
|
USER_ROLE_ADMINISTRATOR = "ADMINISTRATOR"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
//正常状态
|
//ok
|
||||||
USER_STATUS_OK = "OK"
|
USER_STATUS_OK = "OK"
|
||||||
//被禁用
|
//disabled
|
||||||
USER_STATUS_DISABLED = "DISABLED"
|
USER_STATUS_DISABLED = "DISABLED"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
//username pattern
|
||||||
|
USERNAME_PATTERN = `^[0-9a-z_]+$`
|
||||||
|
USERNAME_DEMO = "demo"
|
||||||
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
Base
|
Base
|
||||||
Role string `json:"role" gorm:"type:varchar(45)"`
|
Role string `json:"role" gorm:"type:varchar(45)"`
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"github.com/eyebluecn/tank/code/tool/cache"
|
"github.com/eyebluecn/tank/code/tool/cache"
|
||||||
"github.com/eyebluecn/tank/code/tool/result"
|
"github.com/eyebluecn/tank/code/tool/result"
|
||||||
"github.com/eyebluecn/tank/code/tool/util"
|
"github.com/eyebluecn/tank/code/tool/util"
|
||||||
uuid "github.com/nu7hatch/gouuid"
|
gouuid "github.com/nu7hatch/gouuid"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -16,7 +16,7 @@ type UserService struct {
|
|||||||
userDao *UserDao
|
userDao *UserDao
|
||||||
sessionDao *SessionDao
|
sessionDao *SessionDao
|
||||||
|
|
||||||
//操作文件的锁。
|
//file lock
|
||||||
locker *cache.Table
|
locker *cache.Table
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,31 +33,27 @@ func (this *UserService) Init() {
|
|||||||
this.sessionDao = b
|
this.sessionDao = b
|
||||||
}
|
}
|
||||||
|
|
||||||
//创建一个用于存储用户文件锁的缓存。
|
//create a lock cache.
|
||||||
this.locker = cache.NewTable()
|
this.locker = cache.NewTable()
|
||||||
}
|
}
|
||||||
|
|
||||||
//对某个用户进行加锁。加锁阶段用户是不允许操作文件的。
|
//lock a user's operation. If lock, user cannot operate file.
|
||||||
func (this *UserService) MatterLock(userUuid string) {
|
func (this *UserService) MatterLock(userUuid string) {
|
||||||
//如果已经是锁住的状态,直接报错
|
|
||||||
|
|
||||||
//去缓存中捞取
|
|
||||||
cacheItem, err := this.locker.Value(userUuid)
|
cacheItem, err := this.locker.Value(userUuid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.logger.Error("error while get cache" + err.Error())
|
this.logger.Error("error while get cache" + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
//当前被锁住了。
|
|
||||||
if cacheItem != nil && cacheItem.Data() != nil {
|
if cacheItem != nil && cacheItem.Data() != nil {
|
||||||
panic(result.BadRequest("file is being operating, retry later"))
|
panic(result.BadRequest("file is being operating, retry later"))
|
||||||
}
|
}
|
||||||
|
|
||||||
//添加一把新锁,有效期为12小时
|
|
||||||
duration := 12 * time.Hour
|
duration := 12 * time.Hour
|
||||||
this.locker.Add(userUuid, duration, true)
|
this.locker.Add(userUuid, duration, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
//对某个用户解锁,解锁后用户可以操作文件。
|
//unlock
|
||||||
func (this *UserService) MatterUnlock(userUuid string) {
|
func (this *UserService) MatterUnlock(userUuid string) {
|
||||||
|
|
||||||
exist := this.locker.Exists(userUuid)
|
exist := this.locker.Exists(userUuid)
|
||||||
@ -65,58 +61,53 @@ func (this *UserService) MatterUnlock(userUuid string) {
|
|||||||
_, err := this.locker.Delete(userUuid)
|
_, err := this.locker.Delete(userUuid)
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
} else {
|
} else {
|
||||||
this.logger.Error("%s已经不存在matter锁了,解锁错误。", userUuid)
|
this.logger.Error("unlock error. %s has no matter lock ", userUuid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//装载session信息,如果session没有了根据cookie去装填用户信息。
|
//load session to SessionCache. This method will be invoked in every request.
|
||||||
//在所有的路由最初会调用这个方法
|
//authorize by 1. cookie 2. username and password in request form. 3. Basic Auth
|
||||||
//1. 支持cookie形式 2.支持入参传入username和password 3.支持Basic Auth
|
|
||||||
func (this *UserService) PreHandle(writer http.ResponseWriter, request *http.Request) {
|
func (this *UserService) PreHandle(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
|
||||||
//登录身份有效期以数据库中记录的为准
|
|
||||||
|
|
||||||
//验证用户是否已经登录。
|
|
||||||
sessionId := util.GetSessionUuidFromRequest(request, core.COOKIE_AUTH_KEY)
|
sessionId := util.GetSessionUuidFromRequest(request, core.COOKIE_AUTH_KEY)
|
||||||
|
|
||||||
if sessionId != "" {
|
if sessionId != "" {
|
||||||
|
|
||||||
//去缓存中捞取
|
|
||||||
cacheItem, err := core.CONTEXT.GetSessionCache().Value(sessionId)
|
cacheItem, err := core.CONTEXT.GetSessionCache().Value(sessionId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.logger.Error("获取缓存时出错了" + err.Error())
|
this.logger.Error("occur error will get session cache %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
//缓存中没有,尝试去数据库捞取
|
//if no cache. try to find in db.
|
||||||
if cacheItem == nil || cacheItem.Data() == nil {
|
if cacheItem == nil || cacheItem.Data() == nil {
|
||||||
session := this.sessionDao.FindByUuid(sessionId)
|
session := this.sessionDao.FindByUuid(sessionId)
|
||||||
if session != nil {
|
if session != nil {
|
||||||
duration := session.ExpireTime.Sub(time.Now())
|
duration := session.ExpireTime.Sub(time.Now())
|
||||||
if duration <= 0 {
|
if duration <= 0 {
|
||||||
this.logger.Error("登录信息已过期")
|
this.logger.Error("login info has expired.")
|
||||||
} else {
|
} else {
|
||||||
user := this.userDao.FindByUuid(session.UserUuid)
|
user := this.userDao.FindByUuid(session.UserUuid)
|
||||||
if user != nil {
|
if user != nil {
|
||||||
//将用户装填进缓存中
|
|
||||||
core.CONTEXT.GetSessionCache().Add(sessionId, duration, user)
|
core.CONTEXT.GetSessionCache().Add(sessionId, duration, user)
|
||||||
} else {
|
} else {
|
||||||
this.logger.Error("没有找到对应的user %s", session.UserUuid)
|
this.logger.Error("no user with sessionId %s", session.UserUuid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//再尝试读取一次,这次从 USERNAME_KEY PASSWORD_KEY 中装填用户登录信息
|
//try to auth by USERNAME_KEY PASSWORD_KEY
|
||||||
cacheItem, err := core.CONTEXT.GetSessionCache().Value(sessionId)
|
cacheItem, err := core.CONTEXT.GetSessionCache().Value(sessionId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.logger.Error("获取缓存时出错了" + err.Error())
|
this.logger.Error("occur error will get session cache %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if cacheItem == nil || cacheItem.Data() == nil {
|
if cacheItem == nil || cacheItem.Data() == nil {
|
||||||
username := request.FormValue(core.USERNAME_KEY)
|
username := request.FormValue(core.USERNAME_KEY)
|
||||||
password := request.FormValue(core.PASSWORD_KEY)
|
password := request.FormValue(core.PASSWORD_KEY)
|
||||||
|
|
||||||
|
//try to read from BasicAuth
|
||||||
if username == "" || password == "" {
|
if username == "" || password == "" {
|
||||||
username, password, _ = request.BasicAuth()
|
username, password, _ = request.BasicAuth()
|
||||||
}
|
}
|
||||||
@ -125,19 +116,18 @@ func (this *UserService) PreHandle(writer http.ResponseWriter, request *http.Req
|
|||||||
|
|
||||||
user := this.userDao.FindByUsername(username)
|
user := this.userDao.FindByUsername(username)
|
||||||
if user == nil {
|
if user == nil {
|
||||||
this.logger.Error("%s 用户名或密码错误", core.USERNAME_KEY)
|
this.logger.Error("%s no such user in db.", username)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if !util.MatchBcrypt(password, user.Password) {
|
if !util.MatchBcrypt(password, user.Password) {
|
||||||
this.logger.Error("%s 用户名或密码错误", core.USERNAME_KEY)
|
this.logger.Error("%s password error", username)
|
||||||
} else {
|
} else {
|
||||||
//装填一个临时的session用作后续使用。
|
|
||||||
this.logger.Info("准备装载一个临时的用作。")
|
this.logger.Info("load a temp session by username and password.")
|
||||||
timeUUID, _ := uuid.NewV4()
|
timeUUID, _ := gouuid.NewV4()
|
||||||
uuidStr := string(timeUUID.String())
|
uuidStr := string(timeUUID.String())
|
||||||
request.Form[core.COOKIE_AUTH_KEY] = []string{uuidStr}
|
request.Form[core.COOKIE_AUTH_KEY] = []string{uuidStr}
|
||||||
|
|
||||||
//将用户装填进缓存中
|
|
||||||
core.CONTEXT.GetSessionCache().Add(uuidStr, 10*time.Second, user)
|
core.CONTEXT.GetSessionCache().Add(uuidStr, 10*time.Second, user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,39 +17,37 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
//启动web服务,默认是这种方式
|
//start web. This is the default mode.
|
||||||
MODE_WEB = "web"
|
MODE_WEB = "web"
|
||||||
//映射本地文件到云盘中
|
//mirror local files to EyeblueTank.
|
||||||
MODE_MIRROR = "mirror"
|
MODE_MIRROR = "mirror"
|
||||||
//将远程的一个文件爬取到蓝眼云盘中
|
//crawl remote file to EyeblueTank
|
||||||
MODE_CRAWL = "crawl"
|
MODE_CRAWL = "crawl"
|
||||||
//TODO: 查看当前蓝眼云盘版本
|
//Current version.
|
||||||
MODE_VERSION = "version"
|
MODE_VERSION = "version"
|
||||||
)
|
)
|
||||||
|
|
||||||
//命令行输入相关的对象
|
|
||||||
type TankApplication struct {
|
type TankApplication struct {
|
||||||
//模式
|
//mode
|
||||||
mode string
|
mode string
|
||||||
|
|
||||||
//蓝眼云盘的主机,需要带上协议和端口号。默认: http://127.0.0.1:core.DEFAULT_SERVER_PORT
|
//EyeblueTank host and port default: http://127.0.0.1:core.DEFAULT_SERVER_PORT
|
||||||
host string
|
host string
|
||||||
//用户名
|
//username
|
||||||
username string
|
username string
|
||||||
//密码
|
//password
|
||||||
password string
|
password string
|
||||||
|
|
||||||
//源文件/文件夹,本地绝对路径/远程资源url
|
//source file/directory different mode has different usage.
|
||||||
src string
|
src string
|
||||||
//目标(表示的是文件夹)路径,蓝眼云盘中的路径。相对于root的路径。
|
//destination directory path(relative to root) in EyeblueTank
|
||||||
dest string
|
dest string
|
||||||
//同名文件或文件夹是否直接替换 true 全部替换; false 跳过
|
//true: overwrite, false:skip
|
||||||
overwrite bool
|
overwrite bool
|
||||||
//拉取文件存储的名称
|
|
||||||
filename string
|
filename string
|
||||||
}
|
}
|
||||||
|
|
||||||
//启动应用。可能是web形式,也可能是命令行工具。
|
//Start the application.
|
||||||
func (this *TankApplication) Start() {
|
func (this *TankApplication) Start() {
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -58,7 +56,6 @@ func (this *TankApplication) Start() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
//超级管理员信息
|
|
||||||
modePtr := flag.String("mode", this.mode, "cli mode web/mirror/crawl")
|
modePtr := flag.String("mode", this.mode, "cli mode web/mirror/crawl")
|
||||||
hostPtr := flag.String("host", this.username, "tank host")
|
hostPtr := flag.String("host", this.username, "tank host")
|
||||||
usernamePtr := flag.String("username", this.username, "username")
|
usernamePtr := flag.String("username", this.username, "username")
|
||||||
@ -68,7 +65,7 @@ func (this *TankApplication) Start() {
|
|||||||
overwritePtr := flag.Bool("overwrite", this.overwrite, "whether same file overwrite")
|
overwritePtr := flag.Bool("overwrite", this.overwrite, "whether same file overwrite")
|
||||||
filenamePtr := flag.String("filename", this.filename, "filename when crawl")
|
filenamePtr := flag.String("filename", this.filename, "filename when crawl")
|
||||||
|
|
||||||
//flag.Parse()方法必须要在使用之前调用。
|
//flag.Parse() must invoke before use.
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
this.mode = *modePtr
|
this.mode = *modePtr
|
||||||
@ -80,36 +77,30 @@ func (this *TankApplication) Start() {
|
|||||||
this.overwrite = *overwritePtr
|
this.overwrite = *overwritePtr
|
||||||
this.filename = *filenamePtr
|
this.filename = *filenamePtr
|
||||||
|
|
||||||
//默认采用web的形式启动
|
//default start as web.
|
||||||
if this.mode == "" || strings.ToLower(this.mode) == MODE_WEB {
|
if this.mode == "" || strings.ToLower(this.mode) == MODE_WEB {
|
||||||
|
|
||||||
//直接web启动
|
|
||||||
this.HandleWeb()
|
this.HandleWeb()
|
||||||
|
|
||||||
} else if strings.ToLower(this.mode) == MODE_VERSION {
|
} else if strings.ToLower(this.mode) == MODE_VERSION {
|
||||||
|
|
||||||
//直接web启动
|
|
||||||
this.HandleVersion()
|
this.HandleVersion()
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
//准备蓝眼云盘地址
|
//default host.
|
||||||
if this.host == "" {
|
if this.host == "" {
|
||||||
this.host = fmt.Sprintf("http://127.0.0.1:%d", core.DEFAULT_SERVER_PORT)
|
this.host = fmt.Sprintf("http://127.0.0.1:%d", core.DEFAULT_SERVER_PORT)
|
||||||
}
|
}
|
||||||
|
|
||||||
//准备用户名
|
|
||||||
if this.username == "" {
|
if this.username == "" {
|
||||||
panic(result.BadRequest("%s模式下,用户名必填", this.mode))
|
panic(result.BadRequest("in mode %s, username is required", this.mode))
|
||||||
}
|
}
|
||||||
|
|
||||||
//准备密码
|
|
||||||
if this.password == "" {
|
if this.password == "" {
|
||||||
|
|
||||||
if util.EnvDevelopment() {
|
if util.EnvDevelopment() {
|
||||||
|
panic(result.BadRequest("If run in IDE, use -password yourPassword to input password"))
|
||||||
panic(result.BadRequest("IDE中请运行请直接使用 -password yourPassword 的形式输入密码"))
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
fmt.Print("Enter Password:")
|
fmt.Print("Enter Password:")
|
||||||
@ -125,42 +116,39 @@ func (this *TankApplication) Start() {
|
|||||||
|
|
||||||
if strings.ToLower(this.mode) == MODE_MIRROR {
|
if strings.ToLower(this.mode) == MODE_MIRROR {
|
||||||
|
|
||||||
//映射本地文件到蓝眼云盘
|
|
||||||
this.HandleMirror()
|
this.HandleMirror()
|
||||||
|
|
||||||
} else if strings.ToLower(this.mode) == MODE_CRAWL {
|
} else if strings.ToLower(this.mode) == MODE_CRAWL {
|
||||||
|
|
||||||
//将远程文件拉取到蓝眼云盘中
|
|
||||||
this.HandleCrawl()
|
this.HandleCrawl()
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
panic(result.BadRequest("不能处理命名行模式: %s \r\n", this.mode))
|
panic(result.BadRequest("cannot handle mode %s \r\n", this.mode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//采用Web的方式启动应用
|
|
||||||
func (this *TankApplication) HandleWeb() {
|
func (this *TankApplication) HandleWeb() {
|
||||||
|
|
||||||
//第1步。日志
|
//Step 1. Logger
|
||||||
tankLogger := &TankLogger{}
|
tankLogger := &TankLogger{}
|
||||||
core.LOGGER = tankLogger
|
core.LOGGER = tankLogger
|
||||||
tankLogger.Init()
|
tankLogger.Init()
|
||||||
defer tankLogger.Destroy()
|
defer tankLogger.Destroy()
|
||||||
|
|
||||||
//第2步。配置
|
//Step 2. Configuration
|
||||||
tankConfig := &TankConfig{}
|
tankConfig := &TankConfig{}
|
||||||
core.CONFIG = tankConfig
|
core.CONFIG = tankConfig
|
||||||
tankConfig.Init()
|
tankConfig.Init()
|
||||||
|
|
||||||
//第3步。全局运行的上下文
|
//Step 3. Global Context
|
||||||
tankContext := &TankContext{}
|
tankContext := &TankContext{}
|
||||||
core.CONTEXT = tankContext
|
core.CONTEXT = tankContext
|
||||||
tankContext.Init()
|
tankContext.Init()
|
||||||
defer tankContext.Destroy()
|
defer tankContext.Destroy()
|
||||||
|
|
||||||
//第4步。启动http服务
|
//Step 4. Start http
|
||||||
http.Handle("/", core.CONTEXT)
|
http.Handle("/", core.CONTEXT)
|
||||||
core.LOGGER.Info("App started at http://localhost:%v", core.CONFIG.ServerPort())
|
core.LOGGER.Info("App started at http://localhost:%v", core.CONFIG.ServerPort())
|
||||||
|
|
||||||
@ -172,17 +160,16 @@ func (this *TankApplication) HandleWeb() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//处理本地映射的情形
|
|
||||||
func (this *TankApplication) HandleMirror() {
|
func (this *TankApplication) HandleMirror() {
|
||||||
|
|
||||||
if this.src == "" {
|
if this.src == "" {
|
||||||
panic("src 必填")
|
panic("src is required")
|
||||||
}
|
}
|
||||||
if this.dest == "" {
|
if this.dest == "" {
|
||||||
panic("dest 必填")
|
panic("dest is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("开始映射本地文件 %s 到蓝眼云盘 %s\r\n", this.src, this.dest)
|
fmt.Printf("start mirror %s to EyeblueTank %s\r\n", this.src, this.dest)
|
||||||
|
|
||||||
urlString := fmt.Sprintf("%s/api/matter/mirror", this.host)
|
urlString := fmt.Sprintf("%s/api/matter/mirror", this.host)
|
||||||
|
|
||||||
@ -203,7 +190,7 @@ func (this *TankApplication) HandleMirror() {
|
|||||||
|
|
||||||
err = jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(bodyBytes, webResult)
|
err = jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(bodyBytes, webResult)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("返回格式错误!%s \r\n", err.Error())
|
fmt.Printf("error response format %s \r\n", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,21 +202,20 @@ func (this *TankApplication) HandleMirror() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//拉取远程文件到本地。
|
|
||||||
func (this *TankApplication) HandleCrawl() {
|
func (this *TankApplication) HandleCrawl() {
|
||||||
|
|
||||||
if this.src == "" {
|
if this.src == "" {
|
||||||
panic("src 必填")
|
panic("src is required")
|
||||||
}
|
}
|
||||||
if this.dest == "" {
|
if this.dest == "" {
|
||||||
panic("dest 必填")
|
panic("dest is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
if this.filename == "" {
|
if this.filename == "" {
|
||||||
panic("filename 必填")
|
panic("filename is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("开始映射拉取远程文件 %s 到蓝眼云盘 %s\r\n", this.src, this.dest)
|
fmt.Printf("crawl %s to EyeblueTank %s\r\n", this.src, this.dest)
|
||||||
|
|
||||||
urlString := fmt.Sprintf("%s/api/matter/crawl", this.host)
|
urlString := fmt.Sprintf("%s/api/matter/crawl", this.host)
|
||||||
|
|
||||||
@ -250,7 +236,7 @@ func (this *TankApplication) HandleCrawl() {
|
|||||||
|
|
||||||
err = jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(bodyBytes, webResult)
|
err = jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(bodyBytes, webResult)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("返回格式错误!%s \r\n", err.Error())
|
fmt.Printf("Error response format %s \r\n", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,76 +10,68 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
|
||||||
如果你需要在本地127.0.0.1创建默认的数据库和账号,使用以下语句。
|
|
||||||
create database tank;
|
|
||||||
grant all privileges on tank.* to tank identified by 'tank123';
|
|
||||||
flush privileges;
|
|
||||||
*/
|
|
||||||
|
|
||||||
//依赖外部定义的变量。
|
|
||||||
type TankConfig struct {
|
type TankConfig struct {
|
||||||
//默认监听端口号
|
//server port
|
||||||
serverPort int
|
serverPort int
|
||||||
//网站是否已经完成安装
|
//whether installed
|
||||||
installed bool
|
installed bool
|
||||||
//上传的文件路径,要求不以/结尾。如果没有指定,默认在根目录下的matter文件夹中。eg: /var/www/matter
|
//file storage location. eg./var/www/matter
|
||||||
matterPath string
|
matterPath string
|
||||||
//数据库连接信息。
|
//mysql url.
|
||||||
mysqlUrl string
|
mysqlUrl string
|
||||||
//配置文件中的项
|
//configs in tank.json
|
||||||
item *ConfigItem
|
item *ConfigItem
|
||||||
}
|
}
|
||||||
|
|
||||||
//和tank.json文件中的键值一一对应。
|
//tank.json config items.
|
||||||
type ConfigItem struct {
|
type ConfigItem struct {
|
||||||
//默认监听端口号
|
//server port
|
||||||
ServerPort int
|
ServerPort int
|
||||||
//上传的文件路径,要求不以/结尾。如果没有指定,默认在根目录下的matter文件夹中。eg: /var/www/matter
|
//file storage location. eg./var/www/matter
|
||||||
MatterPath string
|
MatterPath string
|
||||||
//mysql相关配置。
|
//mysql configurations.
|
||||||
//数据库端口
|
//mysql port
|
||||||
MysqlPort int
|
MysqlPort int
|
||||||
//数据库Host
|
//mysql host
|
||||||
MysqlHost string
|
MysqlHost string
|
||||||
//数据库名字
|
//mysql schema
|
||||||
MysqlSchema string
|
MysqlSchema string
|
||||||
//用户名
|
//mysql username
|
||||||
MysqlUsername string
|
MysqlUsername string
|
||||||
//密码
|
//mysql password
|
||||||
MysqlPassword string
|
MysqlPassword string
|
||||||
}
|
}
|
||||||
|
|
||||||
//验证配置文件的正确性。
|
//validate whether the config file is ok
|
||||||
func (this *ConfigItem) validate() bool {
|
func (this *ConfigItem) validate() bool {
|
||||||
|
|
||||||
if this.ServerPort == 0 {
|
if this.ServerPort == 0 {
|
||||||
core.LOGGER.Error("ServerPort 未配置")
|
core.LOGGER.Error("ServerPort is not configured")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if this.MysqlUsername == "" {
|
if this.MysqlUsername == "" {
|
||||||
core.LOGGER.Error("MysqlUsername 未配置")
|
core.LOGGER.Error("MysqlUsername is not configured")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if this.MysqlPassword == "" {
|
if this.MysqlPassword == "" {
|
||||||
core.LOGGER.Error("MysqlPassword 未配置")
|
core.LOGGER.Error("MysqlPassword is not configured")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if this.MysqlHost == "" {
|
if this.MysqlHost == "" {
|
||||||
core.LOGGER.Error("MysqlHost 未配置")
|
core.LOGGER.Error("MysqlHost is not configured")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if this.MysqlPort == 0 {
|
if this.MysqlPort == 0 {
|
||||||
core.LOGGER.Error("MysqlPort 未配置")
|
core.LOGGER.Error("MysqlPort is not configured")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if this.MysqlSchema == "" {
|
if this.MysqlSchema == "" {
|
||||||
core.LOGGER.Error("MysqlSchema 未配置")
|
core.LOGGER.Error("MysqlSchema is not configured")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,12 +79,11 @@ func (this *ConfigItem) validate() bool {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//验证配置文件是否完好
|
|
||||||
func (this *TankConfig) Init() {
|
func (this *TankConfig) Init() {
|
||||||
|
|
||||||
//JSON初始化
|
//JSON init.
|
||||||
jsoniter.RegisterTypeDecoderFunc("time.Time", func(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
|
jsoniter.RegisterTypeDecoderFunc("time.Time", func(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
|
||||||
//如果使用time.UTC,那么时间会相差8小时
|
//if use time.UTC there will be 8 hours gap.
|
||||||
t, err := time.ParseInLocation("2006-01-02 15:04:05", iter.ReadString(), time.Local)
|
t, err := time.ParseInLocation("2006-01-02 15:04:05", iter.ReadString(), time.Local)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
iter.Error = err
|
iter.Error = err
|
||||||
@ -103,45 +94,44 @@ func (this *TankConfig) Init() {
|
|||||||
|
|
||||||
jsoniter.RegisterTypeEncoderFunc("time.Time", func(ptr unsafe.Pointer, stream *jsoniter.Stream) {
|
jsoniter.RegisterTypeEncoderFunc("time.Time", func(ptr unsafe.Pointer, stream *jsoniter.Stream) {
|
||||||
t := *((*time.Time)(ptr))
|
t := *((*time.Time)(ptr))
|
||||||
//如果使用time.UTC,那么时间会相差8小时
|
//if use time.UTC there will be 8 hours gap.
|
||||||
stream.WriteString(t.Local().Format("2006-01-02 15:04:05"))
|
stream.WriteString(t.Local().Format("2006-01-02 15:04:05"))
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
//默认从core.DEFAULT_SERVER_PORT端口启动
|
//default server port.
|
||||||
this.serverPort = core.DEFAULT_SERVER_PORT
|
this.serverPort = core.DEFAULT_SERVER_PORT
|
||||||
|
|
||||||
this.ReadFromConfigFile()
|
this.ReadFromConfigFile()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//系统如果安装好了就调用这个方法。
|
|
||||||
func (this *TankConfig) ReadFromConfigFile() {
|
func (this *TankConfig) ReadFromConfigFile() {
|
||||||
|
|
||||||
//读取配置文件
|
//read from tank.json
|
||||||
filePath := util.GetConfPath() + "/tank.json"
|
filePath := util.GetConfPath() + "/tank.json"
|
||||||
content, err := ioutil.ReadFile(filePath)
|
content, err := ioutil.ReadFile(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LOGGER.Warn("无法找到配置文件:%s 即将进入安装过程!", filePath)
|
core.LOGGER.Warn("cannot find config file %s, installation will start!", filePath)
|
||||||
this.installed = false
|
this.installed = false
|
||||||
} else {
|
} else {
|
||||||
this.item = &ConfigItem{}
|
this.item = &ConfigItem{}
|
||||||
core.LOGGER.Warn("读取配置文件:%s", filePath)
|
core.LOGGER.Warn("read config file %s", filePath)
|
||||||
err := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(content, this.item)
|
err := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(content, this.item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LOGGER.Error("配置文件格式错误! 即将进入安装过程!")
|
core.LOGGER.Error("config file error, installation will start!")
|
||||||
this.installed = false
|
this.installed = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//验证项是否齐全
|
//check the integrity
|
||||||
itemValidate := this.item.validate()
|
itemValidate := this.item.validate()
|
||||||
if !itemValidate {
|
if !itemValidate {
|
||||||
core.LOGGER.Error("配置文件信息不齐全! 即将进入安装过程!")
|
core.LOGGER.Error("config file not integrity, installation will start!")
|
||||||
this.installed = false
|
this.installed = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//使用配置项中的文件路径
|
//use default file location.
|
||||||
if this.item.MatterPath == "" {
|
if this.item.MatterPath == "" {
|
||||||
this.matterPath = util.GetHomePath() + "/matter"
|
this.matterPath = util.GetHomePath() + "/matter"
|
||||||
} else {
|
} else {
|
||||||
@ -149,7 +139,7 @@ func (this *TankConfig) ReadFromConfigFile() {
|
|||||||
}
|
}
|
||||||
util.MakeDirAll(this.matterPath)
|
util.MakeDirAll(this.matterPath)
|
||||||
|
|
||||||
//使用配置项中的端口
|
//use default server port
|
||||||
if this.item.ServerPort != 0 {
|
if this.item.ServerPort != 0 {
|
||||||
this.serverPort = this.item.ServerPort
|
this.serverPort = this.item.ServerPort
|
||||||
}
|
}
|
||||||
@ -157,57 +147,50 @@ func (this *TankConfig) ReadFromConfigFile() {
|
|||||||
this.mysqlUrl = util.GetMysqlUrl(this.item.MysqlPort, this.item.MysqlHost, this.item.MysqlSchema, this.item.MysqlUsername, this.item.MysqlPassword)
|
this.mysqlUrl = util.GetMysqlUrl(this.item.MysqlPort, this.item.MysqlHost, this.item.MysqlSchema, this.item.MysqlUsername, this.item.MysqlPassword)
|
||||||
this.installed = true
|
this.installed = true
|
||||||
|
|
||||||
core.LOGGER.Info("使用配置文件:%s", filePath)
|
core.LOGGER.Info("use config file: %s", filePath)
|
||||||
core.LOGGER.Info("上传文件存放路径:%s", this.matterPath)
|
core.LOGGER.Info("file storage location: %s", this.matterPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//是否已经安装
|
//whether installed.
|
||||||
func (this *TankConfig) Installed() bool {
|
func (this *TankConfig) Installed() bool {
|
||||||
return this.installed
|
return this.installed
|
||||||
}
|
}
|
||||||
|
|
||||||
//启动端口
|
//server port
|
||||||
func (this *TankConfig) ServerPort() int {
|
func (this *TankConfig) ServerPort() int {
|
||||||
return this.serverPort
|
return this.serverPort
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取mysql链接
|
//mysql url
|
||||||
func (this *TankConfig) MysqlUrl() string {
|
func (this *TankConfig) MysqlUrl() string {
|
||||||
return this.mysqlUrl
|
return this.mysqlUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
//文件存放路径
|
//matter path
|
||||||
func (this *TankConfig) MatterPath() string {
|
func (this *TankConfig) MatterPath() string {
|
||||||
|
|
||||||
return this.matterPath
|
return this.matterPath
|
||||||
}
|
}
|
||||||
|
|
||||||
//完成安装过程,主要是要将配置写入到文件中
|
//Finish the installation. Write config to tank.json
|
||||||
func (this *TankConfig) FinishInstall(mysqlPort int, mysqlHost string, mysqlSchema string, mysqlUsername string, mysqlPassword string) {
|
func (this *TankConfig) FinishInstall(mysqlPort int, mysqlHost string, mysqlSchema string, mysqlUsername string, mysqlPassword string) {
|
||||||
|
|
||||||
var configItem = &ConfigItem{
|
var configItem = &ConfigItem{
|
||||||
//默认监听端口号
|
//server port
|
||||||
ServerPort: core.CONFIG.ServerPort(),
|
ServerPort: core.CONFIG.ServerPort(),
|
||||||
//上传的文件路径,要求不以/结尾。如果没有指定,默认在根目录下的matter文件夹中。eg: /var/www/matter
|
//file storage location. eg./var/www/matter
|
||||||
MatterPath: core.CONFIG.MatterPath(),
|
MatterPath: core.CONFIG.MatterPath(),
|
||||||
//mysql相关配置。
|
|
||||||
//数据库端口
|
|
||||||
MysqlPort: mysqlPort,
|
MysqlPort: mysqlPort,
|
||||||
//数据库Host
|
|
||||||
MysqlHost: mysqlHost,
|
MysqlHost: mysqlHost,
|
||||||
//数据库名字
|
|
||||||
MysqlSchema: mysqlSchema,
|
MysqlSchema: mysqlSchema,
|
||||||
//用户名
|
|
||||||
MysqlUsername: mysqlUsername,
|
MysqlUsername: mysqlUsername,
|
||||||
//密码
|
|
||||||
MysqlPassword: mysqlPassword,
|
MysqlPassword: mysqlPassword,
|
||||||
}
|
}
|
||||||
|
|
||||||
//用json的方式输出返回值。为了让格式更好看。
|
//pretty json.
|
||||||
jsonStr, _ := jsoniter.ConfigCompatibleWithStandardLibrary.MarshalIndent(configItem, "", " ")
|
jsonStr, _ := jsoniter.ConfigCompatibleWithStandardLibrary.MarshalIndent(configItem, "", " ")
|
||||||
|
|
||||||
//写入到配置文件中(不能使用os.O_APPEND 否则会追加)
|
//Write to tank.json (cannot use os.O_APPEND or append)
|
||||||
filePath := util.GetConfPath() + "/tank.json"
|
filePath := util.GetConfPath() + "/tank.json"
|
||||||
f, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0777)
|
f, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0777)
|
||||||
core.PanicError(err)
|
core.PanicError(err)
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package support
|
package support
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/eyebluecn/tank/code/core"
|
"github.com/eyebluecn/tank/code/core"
|
||||||
"github.com/eyebluecn/tank/code/rest"
|
"github.com/eyebluecn/tank/code/rest"
|
||||||
"github.com/eyebluecn/tank/code/tool/cache"
|
"github.com/eyebluecn/tank/code/tool/cache"
|
||||||
@ -11,45 +9,42 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
//上下文,管理数据库连接,管理所有路由请求,管理所有的单例component.
|
|
||||||
type TankContext struct {
|
type TankContext struct {
|
||||||
//数据库连接
|
//db connection
|
||||||
db *gorm.DB
|
db *gorm.DB
|
||||||
//session缓存
|
//session cache
|
||||||
SessionCache *cache.Table
|
SessionCache *cache.Table
|
||||||
//各类的Bean Map。这里面是包含ControllerMap中所有元素
|
//bean map.
|
||||||
BeanMap map[string]core.Bean
|
BeanMap map[string]core.Bean
|
||||||
//只包含了Controller的map
|
//controller map
|
||||||
ControllerMap map[string]core.Controller
|
ControllerMap map[string]core.Controller
|
||||||
//处理所有路由请求
|
//router
|
||||||
Router *TankRouter
|
Router *TankRouter
|
||||||
}
|
}
|
||||||
|
|
||||||
//初始化上下文
|
|
||||||
func (this *TankContext) Init() {
|
func (this *TankContext) Init() {
|
||||||
|
|
||||||
//创建一个用于存储session的缓存。
|
//create session cache
|
||||||
this.SessionCache = cache.NewTable()
|
this.SessionCache = cache.NewTable()
|
||||||
|
|
||||||
//初始化Map
|
//init map
|
||||||
this.BeanMap = make(map[string]core.Bean)
|
this.BeanMap = make(map[string]core.Bean)
|
||||||
this.ControllerMap = make(map[string]core.Controller)
|
this.ControllerMap = make(map[string]core.Controller)
|
||||||
|
|
||||||
//注册各类Beans.在这个方法里面顺便把Controller装入ControllerMap中去。
|
//register beans. This method will put Controllers to ControllerMap.
|
||||||
this.registerBeans()
|
this.registerBeans()
|
||||||
|
|
||||||
//初始化每个bean.
|
//init every bean.
|
||||||
this.initBeans()
|
this.initBeans()
|
||||||
|
|
||||||
//初始化Router. 这个方法要在Bean注册好了之后才能。
|
//create and init router.
|
||||||
this.Router = NewRouter()
|
this.Router = NewRouter()
|
||||||
|
|
||||||
//如果数据库信息配置好了,就直接打开数据库连接 同时执行Bean的ConfigPost方法
|
//if the application is installed. Bean's Bootstrap method will be invoked.
|
||||||
this.InstallOk()
|
this.InstallOk()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取数据库对象
|
|
||||||
func (this *TankContext) GetDB() *gorm.DB {
|
func (this *TankContext) GetDB() *gorm.DB {
|
||||||
return this.db
|
return this.db
|
||||||
}
|
}
|
||||||
@ -68,7 +63,7 @@ func (this *TankContext) Cleanup() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//响应http的能力
|
//can serve as http server.
|
||||||
func (this *TankContext) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
func (this *TankContext) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||||
this.Router.ServeHTTP(writer, request)
|
this.Router.ServeHTTP(writer, request)
|
||||||
}
|
}
|
||||||
@ -82,7 +77,7 @@ func (this *TankContext) OpenDb() {
|
|||||||
core.LOGGER.Panic("failed to connect mysql database")
|
core.LOGGER.Panic("failed to connect mysql database")
|
||||||
}
|
}
|
||||||
|
|
||||||
//是否打开sql日志(在调试阶段可以打开,以方便查看执行的SQL)
|
//whether open the db log. (only true when debug)
|
||||||
this.db.LogMode(false)
|
this.db.LogMode(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,12 +86,11 @@ func (this *TankContext) CloseDb() {
|
|||||||
if this.db != nil {
|
if this.db != nil {
|
||||||
err := this.db.Close()
|
err := this.db.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LOGGER.Error("关闭数据库连接出错 %s", err.Error())
|
core.LOGGER.Error("occur error when closing db %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//注册一个Bean
|
|
||||||
func (this *TankContext) registerBean(bean core.Bean) {
|
func (this *TankContext) registerBean(bean core.Bean) {
|
||||||
|
|
||||||
typeOf := reflect.TypeOf(bean)
|
typeOf := reflect.TypeOf(bean)
|
||||||
@ -104,13 +98,12 @@ func (this *TankContext) registerBean(bean core.Bean) {
|
|||||||
|
|
||||||
if element, ok := bean.(core.Bean); ok {
|
if element, ok := bean.(core.Bean); ok {
|
||||||
|
|
||||||
err := fmt.Sprintf("【%s】已经被注册了,跳过。", typeName)
|
|
||||||
if _, ok := this.BeanMap[typeName]; ok {
|
if _, ok := this.BeanMap[typeName]; ok {
|
||||||
core.LOGGER.Error(fmt.Sprintf(err))
|
core.LOGGER.Error("%s has been registerd, skip", typeName)
|
||||||
} else {
|
} else {
|
||||||
this.BeanMap[typeName] = element
|
this.BeanMap[typeName] = element
|
||||||
|
|
||||||
//看看是不是controller类型,如果是,那么单独放在ControllerMap中。
|
//if is controller type, put into ControllerMap
|
||||||
if controller, ok1 := bean.(core.Controller); ok1 {
|
if controller, ok1 := bean.(core.Controller); ok1 {
|
||||||
this.ControllerMap[typeName] = controller
|
this.ControllerMap[typeName] = controller
|
||||||
}
|
}
|
||||||
@ -118,12 +111,11 @@ func (this *TankContext) registerBean(bean core.Bean) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
core.LOGGER.Panic("注册的【%s】不是Bean类型。", typeName)
|
core.LOGGER.Panic("%s is not the Bean type", typeName)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//注册各个Beans
|
|
||||||
func (this *TankContext) registerBeans() {
|
func (this *TankContext) registerBeans() {
|
||||||
|
|
||||||
//alien
|
//alien
|
||||||
@ -188,7 +180,6 @@ func (this *TankContext) registerBeans() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//从Map中获取某个Bean.
|
|
||||||
func (this *TankContext) GetBean(bean core.Bean) core.Bean {
|
func (this *TankContext) GetBean(bean core.Bean) core.Bean {
|
||||||
|
|
||||||
typeOf := reflect.TypeOf(bean)
|
typeOf := reflect.TypeOf(bean)
|
||||||
@ -197,12 +188,11 @@ func (this *TankContext) GetBean(bean core.Bean) core.Bean {
|
|||||||
if val, ok := this.BeanMap[typeName]; ok {
|
if val, ok := this.BeanMap[typeName]; ok {
|
||||||
return val
|
return val
|
||||||
} else {
|
} else {
|
||||||
core.LOGGER.Panic("【%s】没有注册。", typeName)
|
core.LOGGER.Panic("%s not registered", typeName)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//初始化每个Bean
|
|
||||||
func (this *TankContext) initBeans() {
|
func (this *TankContext) initBeans() {
|
||||||
|
|
||||||
for _, bean := range this.BeanMap {
|
for _, bean := range this.BeanMap {
|
||||||
@ -210,7 +200,7 @@ func (this *TankContext) initBeans() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//系统如果安装好了就调用这个方法。
|
//if application installed. invoke this method.
|
||||||
func (this *TankContext) InstallOk() {
|
func (this *TankContext) InstallOk() {
|
||||||
|
|
||||||
if core.CONFIG.Installed() {
|
if core.CONFIG.Installed() {
|
||||||
@ -223,7 +213,6 @@ func (this *TankContext) InstallOk() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//销毁的方法
|
|
||||||
func (this *TankContext) Destroy() {
|
func (this *TankContext) Destroy() {
|
||||||
this.CloseDb()
|
this.CloseDb()
|
||||||
}
|
}
|
||||||
|
@ -12,14 +12,12 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
//在Logger的基础上包装一个全新的Logger.
|
|
||||||
type TankLogger struct {
|
type TankLogger struct {
|
||||||
//加锁,在维护日志期间,禁止写入日志。
|
//lock. when maintaining, cannot write
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
|
//extend logger
|
||||||
//继承logger
|
|
||||||
goLogger *log.Logger
|
goLogger *log.Logger
|
||||||
//日志记录所在的文件
|
//log file.
|
||||||
file *os.File
|
file *os.File
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,13 +25,12 @@ func (this *TankLogger) Init() {
|
|||||||
|
|
||||||
this.openFile()
|
this.openFile()
|
||||||
|
|
||||||
//每日00:00整理日志。
|
this.Info("[cron job] Every day 00:00 maintain log file.")
|
||||||
expression := "0 0 0 * * ?"
|
expression := "0 0 0 * * ?"
|
||||||
cronJob := cron.New()
|
cronJob := cron.New()
|
||||||
err := cronJob.AddFunc(expression, this.maintain)
|
err := cronJob.AddFunc(expression, this.maintain)
|
||||||
core.PanicError(err)
|
core.PanicError(err)
|
||||||
cronJob.Start()
|
cronJob.Start()
|
||||||
this.Info("[cron job] 每日00:00维护日志")
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,12 +38,12 @@ func (this *TankLogger) Destroy() {
|
|||||||
this.closeFile()
|
this.closeFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
//处理日志的统一方法。
|
//uniform log method
|
||||||
func (this *TankLogger) Log(prefix string, format string, v ...interface{}) {
|
func (this *TankLogger) Log(prefix string, format string, v ...interface{}) {
|
||||||
|
|
||||||
content := fmt.Sprintf(format+"\r\n", v...)
|
content := fmt.Sprintf(format+"\r\n", v...)
|
||||||
|
|
||||||
//控制台中打印日志,记录行号。
|
//print to console with line number
|
||||||
_, file, line, ok := runtime.Caller(2)
|
_, file, line, ok := runtime.Caller(2)
|
||||||
if !ok {
|
if !ok {
|
||||||
file = "???"
|
file = "???"
|
||||||
@ -58,14 +55,12 @@ func (this *TankLogger) Log(prefix string, format string, v ...interface{}) {
|
|||||||
|
|
||||||
this.goLogger.SetPrefix(prefix)
|
this.goLogger.SetPrefix(prefix)
|
||||||
|
|
||||||
//每一行我们加上换行符
|
|
||||||
err := this.goLogger.Output(3, content)
|
err := this.goLogger.Output(3, content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("occur error while logging %s \r\n", err.Error())
|
fmt.Printf("occur error while logging %s \r\n", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//处理日志的统一方法。
|
|
||||||
func (this *TankLogger) Debug(format string, v ...interface{}) {
|
func (this *TankLogger) Debug(format string, v ...interface{}) {
|
||||||
this.Log("[DEBUG]", format, v...)
|
this.Log("[DEBUG]", format, v...)
|
||||||
}
|
}
|
||||||
@ -88,59 +83,59 @@ func (this *TankLogger) Panic(format string, v ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//将日志写入到今天的日期中(该方法内必须使用异步方法记录日志,否则会引发死锁)
|
//将日志写入到今天的日期中(该方法内必须使用异步方法记录日志,否则会引发死锁)
|
||||||
|
//rename log file.
|
||||||
func (this *TankLogger) maintain() {
|
func (this *TankLogger) maintain() {
|
||||||
|
|
||||||
this.Info("每日维护日志")
|
this.Info("maintain log")
|
||||||
|
|
||||||
this.Lock()
|
this.Lock()
|
||||||
defer this.Unlock()
|
defer this.Unlock()
|
||||||
|
|
||||||
//首先关闭文件。
|
|
||||||
this.closeFile()
|
this.closeFile()
|
||||||
|
|
||||||
//日志归类到昨天
|
//archive to yesterday
|
||||||
destPath := util.GetLogPath() + "/tank-" + util.ConvertTimeToDateString(util.Yesterday()) + ".log"
|
destPath := util.GetLogPath() + "/tank-" + util.ConvertTimeToDateString(util.Yesterday()) + ".log"
|
||||||
|
|
||||||
//直接重命名文件
|
//rename the log file.
|
||||||
err := os.Rename(this.fileName(), destPath)
|
err := os.Rename(this.fileName(), destPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Error("重命名文件出错", err.Error())
|
this.Error("occur error while renaming log file %s %s", destPath, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
//再次打开文件
|
//reopen
|
||||||
this.openFile()
|
this.openFile()
|
||||||
|
|
||||||
//删除一个月之前的日志文件。
|
//delete log files a month ago
|
||||||
monthAgo := time.Now()
|
monthAgo := time.Now()
|
||||||
monthAgo = monthAgo.AddDate(0, -1, 0)
|
monthAgo = monthAgo.AddDate(0, -1, 0)
|
||||||
oldDestPath := util.GetLogPath() + "/tank-" + util.ConvertTimeToDateString(monthAgo) + ".log"
|
oldDestPath := util.GetLogPath() + "/tank-" + util.ConvertTimeToDateString(monthAgo) + ".log"
|
||||||
this.Log("删除日志文件 %s", oldDestPath)
|
this.Log("try to delete log file %s", oldDestPath)
|
||||||
|
|
||||||
//删除文件
|
//delete log file
|
||||||
exists := util.PathExists(oldDestPath)
|
exists := util.PathExists(oldDestPath)
|
||||||
if exists {
|
if exists {
|
||||||
err = os.Remove(oldDestPath)
|
err = os.Remove(oldDestPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Error("删除磁盘上的文件%s 出错 %s", oldDestPath, err.Error())
|
this.Error("occur error while deleting log file %s %s", oldDestPath, err.Error())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.Error("日志文件 %s 不存在,无需删除", oldDestPath)
|
this.Error("log file %s not exist, skip", oldDestPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//日志名称
|
//log file name
|
||||||
func (this *TankLogger) fileName() string {
|
func (this *TankLogger) fileName() string {
|
||||||
return util.GetLogPath() + "/tank.log"
|
return util.GetLogPath() + "/tank.log"
|
||||||
}
|
}
|
||||||
|
|
||||||
//打开日志文件
|
//open log file
|
||||||
func (this *TankLogger) openFile() {
|
func (this *TankLogger) openFile() {
|
||||||
//日志输出到文件中 文件打开后暂时不关闭
|
// not close log file immediately
|
||||||
fmt.Printf("使用日志文件 %s\r\n", this.fileName())
|
fmt.Printf("use log file %s\r\n", this.fileName())
|
||||||
f, err := os.OpenFile(this.fileName(), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
f, err := os.OpenFile(this.fileName(), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("日志文件无法正常打开: " + err.Error())
|
panic("cannot open log file " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
this.goLogger = log.New(f, "", log.Ltime|log.Lshortfile)
|
this.goLogger = log.New(f, "", log.Ltime|log.Lshortfile)
|
||||||
@ -152,12 +147,12 @@ func (this *TankLogger) openFile() {
|
|||||||
this.file = f
|
this.file = f
|
||||||
}
|
}
|
||||||
|
|
||||||
//关闭日志文件
|
//close log file.
|
||||||
func (this *TankLogger) closeFile() {
|
func (this *TankLogger) closeFile() {
|
||||||
if this.file != nil {
|
if this.file != nil {
|
||||||
err := this.file.Close()
|
err := this.file.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("尝试关闭日志时出错: " + err.Error())
|
panic("occur error while closing log file: " + err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
//用于处理所有前来的请求
|
|
||||||
type TankRouter struct {
|
type TankRouter struct {
|
||||||
installController *rest.InstallController
|
installController *rest.InstallController
|
||||||
footprintService *rest.FootprintService
|
footprintService *rest.FootprintService
|
||||||
@ -24,7 +23,6 @@ type TankRouter struct {
|
|||||||
installRouteMap map[string]func(writer http.ResponseWriter, request *http.Request)
|
installRouteMap map[string]func(writer http.ResponseWriter, request *http.Request)
|
||||||
}
|
}
|
||||||
|
|
||||||
//构造方法
|
|
||||||
func NewRouter() *TankRouter {
|
func NewRouter() *TankRouter {
|
||||||
router := &TankRouter{
|
router := &TankRouter{
|
||||||
routeMap: make(map[string]func(writer http.ResponseWriter, request *http.Request)),
|
routeMap: make(map[string]func(writer http.ResponseWriter, request *http.Request)),
|
||||||
@ -37,19 +35,19 @@ func NewRouter() *TankRouter {
|
|||||||
router.installController = b
|
router.installController = b
|
||||||
}
|
}
|
||||||
|
|
||||||
//装载userService.
|
//load userService
|
||||||
b = core.CONTEXT.GetBean(router.userService)
|
b = core.CONTEXT.GetBean(router.userService)
|
||||||
if b, ok := b.(*rest.UserService); ok {
|
if b, ok := b.(*rest.UserService); ok {
|
||||||
router.userService = b
|
router.userService = b
|
||||||
}
|
}
|
||||||
|
|
||||||
//装载footprintService
|
//load footprintService
|
||||||
b = core.CONTEXT.GetBean(router.footprintService)
|
b = core.CONTEXT.GetBean(router.footprintService)
|
||||||
if b, ok := b.(*rest.FootprintService); ok {
|
if b, ok := b.(*rest.FootprintService); ok {
|
||||||
router.footprintService = b
|
router.footprintService = b
|
||||||
}
|
}
|
||||||
|
|
||||||
//将Controller中的路由规则装载进来,InstallController中的除外
|
//load Controllers except InstallController
|
||||||
for _, controller := range core.CONTEXT.GetControllerMap() {
|
for _, controller := range core.CONTEXT.GetControllerMap() {
|
||||||
|
|
||||||
if controller == router.installController {
|
if controller == router.installController {
|
||||||
@ -69,18 +67,18 @@ func NewRouter() *TankRouter {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//全局的异常捕获
|
//catch global panic.
|
||||||
func (this *TankRouter) GlobalPanicHandler(writer http.ResponseWriter, request *http.Request, startTime time.Time) {
|
func (this *TankRouter) GlobalPanicHandler(writer http.ResponseWriter, request *http.Request, startTime time.Time) {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
|
|
||||||
//控制台中打印日志,记录行号。
|
//get panic file and line number.
|
||||||
_, file, line, ok := runtime.Caller(2)
|
_, file, line, ok := runtime.Caller(2)
|
||||||
if !ok {
|
if !ok {
|
||||||
file = "???"
|
file = "???"
|
||||||
line = 0
|
line = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
//全局未知异常
|
//unkown panic
|
||||||
if strings.HasSuffix(file, "runtime/panic.go") {
|
if strings.HasSuffix(file, "runtime/panic.go") {
|
||||||
_, file, line, ok = runtime.Caller(4)
|
_, file, line, ok = runtime.Caller(4)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -88,7 +86,7 @@ func (this *TankRouter) GlobalPanicHandler(writer http.ResponseWriter, request *
|
|||||||
line = 0
|
line = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//全局方便的异常拦截
|
//async panic
|
||||||
if strings.HasSuffix(file, "core/handler.go") {
|
if strings.HasSuffix(file, "core/handler.go") {
|
||||||
_, file, line, ok = runtime.Caller(4)
|
_, file, line, ok = runtime.Caller(4)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -101,71 +99,69 @@ func (this *TankRouter) GlobalPanicHandler(writer http.ResponseWriter, request *
|
|||||||
|
|
||||||
var webResult *result.WebResult = nil
|
var webResult *result.WebResult = nil
|
||||||
if value, ok := err.(string); ok {
|
if value, ok := err.(string); ok {
|
||||||
//一个字符串,默认是请求错误。
|
//string, default as BadRequest.
|
||||||
webResult = result.CustomWebResult(result.BAD_REQUEST, value)
|
webResult = result.CustomWebResult(result.BAD_REQUEST, value)
|
||||||
} else if value, ok := err.(*result.WebResult); ok {
|
} else if value, ok := err.(*result.WebResult); ok {
|
||||||
//一个WebResult对象
|
//*result.WebResult
|
||||||
webResult = value
|
webResult = value
|
||||||
} else if value, ok := err.(*result.CodeWrapper); ok {
|
} else if value, ok := err.(*result.CodeWrapper); ok {
|
||||||
//一个WebResult对象
|
//*result.CodeWrapper
|
||||||
webResult = result.ConstWebResult(value)
|
webResult = result.ConstWebResult(value)
|
||||||
} else if value, ok := err.(error); ok {
|
} else if value, ok := err.(error); ok {
|
||||||
//一个普通的错误对象
|
//normal error
|
||||||
webResult = result.CustomWebResult(result.UNKNOWN, value.Error())
|
webResult = result.CustomWebResult(result.UNKNOWN, value.Error())
|
||||||
} else {
|
} else {
|
||||||
//其他不能识别的内容
|
//other error
|
||||||
webResult = result.ConstWebResult(result.UNKNOWN)
|
webResult = result.ConstWebResult(result.UNKNOWN)
|
||||||
}
|
}
|
||||||
|
|
||||||
//修改http code码
|
//change the http status.
|
||||||
writer.WriteHeader(result.FetchHttpStatus(webResult.Code))
|
writer.WriteHeader(result.FetchHttpStatus(webResult.Code))
|
||||||
|
|
||||||
//输出的是json格式 返回的内容申明是json,utf-8
|
//if json, set the Content-Type to json.
|
||||||
writer.Header().Set("Content-Type", "application/json;charset=UTF-8")
|
writer.Header().Set("Content-Type", "application/json;charset=UTF-8")
|
||||||
|
|
||||||
//用json的方式输出返回值。
|
//write the response.
|
||||||
b, _ := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(webResult)
|
b, _ := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(webResult)
|
||||||
|
|
||||||
//写到输出流中
|
//write to writer.
|
||||||
_, err := fmt.Fprintf(writer, string(b))
|
_, err := fmt.Fprintf(writer, string(b))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("输出结果时出错了\n")
|
fmt.Printf("occur error while write response %s\r\n", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
//错误情况记录。
|
//log error.
|
||||||
go core.RunWithRecovery(func() {
|
go core.RunWithRecovery(func() {
|
||||||
this.footprintService.Trace(request, time.Now().Sub(startTime), false)
|
this.footprintService.Trace(request, time.Now().Sub(startTime), false)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//让Router具有处理请求的功能。
|
|
||||||
func (this *TankRouter) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
func (this *TankRouter) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
|
||||||
//每个请求的入口在这里
|
//global panic handler
|
||||||
//全局异常处理。
|
|
||||||
defer this.GlobalPanicHandler(writer, request, startTime)
|
defer this.GlobalPanicHandler(writer, request, startTime)
|
||||||
|
|
||||||
path := request.URL.Path
|
path := request.URL.Path
|
||||||
if strings.HasPrefix(path, "/api") {
|
if strings.HasPrefix(path, "/api") {
|
||||||
|
|
||||||
//对于IE浏览器,会自动缓存,因此设置不缓存Header.
|
//IE browser will cache automatically. disable the cache.
|
||||||
writer.Header().Set("Pragma", "No-cache")
|
util.DisableCache(writer)
|
||||||
writer.Header().Set("Cache-Control", "no-cache")
|
|
||||||
writer.Header().Set("Expires", "0")
|
|
||||||
|
|
||||||
if core.CONFIG.Installed() {
|
if core.CONFIG.Installed() {
|
||||||
//已安装的模式
|
|
||||||
|
|
||||||
//统一处理用户的身份信息。
|
//if installed.
|
||||||
|
|
||||||
|
//handler user's auth info.
|
||||||
this.userService.PreHandle(writer, request)
|
this.userService.PreHandle(writer, request)
|
||||||
|
|
||||||
if handler, ok := this.routeMap[path]; ok {
|
if handler, ok := this.routeMap[path]; ok {
|
||||||
handler(writer, request)
|
handler(writer, request)
|
||||||
} else {
|
} else {
|
||||||
//直接将请求扔给每个controller,看看他们能不能处理,如果都不能处理,那就抛出找不到的错误
|
|
||||||
|
//dispatch the request to controller's handler.
|
||||||
canHandle := false
|
canHandle := false
|
||||||
for _, controller := range core.CONTEXT.GetControllerMap() {
|
for _, controller := range core.CONTEXT.GetControllerMap() {
|
||||||
if handler, exist := controller.HandleRoutes(writer, request); exist {
|
if handler, exist := controller.HandleRoutes(writer, request); exist {
|
||||||
@ -176,17 +172,17 @@ func (this *TankRouter) ServeHTTP(writer http.ResponseWriter, request *http.Requ
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !canHandle {
|
if !canHandle {
|
||||||
panic(result.CustomWebResult(result.NOT_FOUND, fmt.Sprintf("没有找到能够处理%s的方法", path)))
|
panic(result.CustomWebResult(result.NOT_FOUND, fmt.Sprintf("cannot handle %s", path)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//正常的访问记录会落到这里。
|
//log the request
|
||||||
go core.RunWithRecovery(func() {
|
go core.RunWithRecovery(func() {
|
||||||
this.footprintService.Trace(request, time.Now().Sub(startTime), true)
|
this.footprintService.Trace(request, time.Now().Sub(startTime), true)
|
||||||
})
|
})
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
//未安装模式
|
//if not installed. try to install.
|
||||||
if handler, ok := this.installRouteMap[path]; ok {
|
if handler, ok := this.installRouteMap[path]; ok {
|
||||||
handler(writer, request)
|
handler(writer, request)
|
||||||
} else {
|
} else {
|
||||||
@ -196,7 +192,7 @@ func (this *TankRouter) ServeHTTP(writer http.ResponseWriter, request *http.Requ
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
//当作静态资源处理。默认从当前文件下面的static文件夹中取东西。
|
//static file.
|
||||||
dir := util.GetHtmlPath()
|
dir := util.GetHtmlPath()
|
||||||
|
|
||||||
requestURI := request.RequestURI
|
requestURI := request.RequestURI
|
||||||
|
@ -2,6 +2,7 @@ package test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/eyebluecn/tank/code/core"
|
||||||
"github.com/eyebluecn/tank/code/tool/util"
|
"github.com/eyebluecn/tank/code/tool/util"
|
||||||
"github.com/robfig/cron"
|
"github.com/robfig/cron"
|
||||||
"log"
|
"log"
|
||||||
@ -17,7 +18,6 @@ func TestHello(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//测试cron表达式
|
|
||||||
func TestCron(t *testing.T) {
|
func TestCron(t *testing.T) {
|
||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
@ -34,12 +34,10 @@ func TestCron(t *testing.T) {
|
|||||||
|
|
||||||
c.Start()
|
c.Start()
|
||||||
|
|
||||||
//当前线程阻塞 20s
|
|
||||||
time.Sleep(3 * time.Second)
|
time.Sleep(3 * time.Second)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//测试 时间
|
|
||||||
func TestDayAgo(t *testing.T) {
|
func TestDayAgo(t *testing.T) {
|
||||||
|
|
||||||
dayAgo := time.Now()
|
dayAgo := time.Now()
|
||||||
@ -50,10 +48,3 @@ func TestDayAgo(t *testing.T) {
|
|||||||
fmt.Printf("%s\n", util.ConvertTimeToDateTimeString(thenDay))
|
fmt.Printf("%s\n", util.ConvertTimeToDateTimeString(thenDay))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//测试 打包
|
|
||||||
func TestZip(t *testing.T) {
|
|
||||||
|
|
||||||
util.Zip("/Users/fusu/d/group/eyeblue/tank/tmp/matter/admin/root/morning", "/Users/fusu/d/group/eyeblue/tank/tmp/log/morning.zip")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
105
code/tool/cache/cache.go
vendored
105
code/tool/cache/cache.go
vendored
@ -8,27 +8,25 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
//缓存项
|
//cache2go https://github.com/muesli/cache2go
|
||||||
//主要借鉴了cache2go https://github.com/muesli/cache2go
|
|
||||||
type Item struct {
|
type Item struct {
|
||||||
sync.RWMutex //读写锁
|
//read write lock
|
||||||
//缓存键
|
sync.RWMutex
|
||||||
key interface{}
|
key interface{}
|
||||||
//缓存值
|
|
||||||
data interface{}
|
data interface{}
|
||||||
// 缓存项的生命期
|
// cache duration.
|
||||||
duration time.Duration
|
duration time.Duration
|
||||||
//创建时间
|
// create time
|
||||||
createTime time.Time
|
createTime time.Time
|
||||||
//最后访问时间
|
//last access time
|
||||||
accessTime time.Time
|
accessTime time.Time
|
||||||
//访问次数
|
//visit times
|
||||||
count int64
|
count int64
|
||||||
// 在删除缓存项之前调用的回调函数
|
// callback after deleting
|
||||||
deleteCallback func(key interface{})
|
deleteCallback func(key interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
//新建一项缓存
|
//create item.
|
||||||
func NewItem(key interface{}, duration time.Duration, data interface{}) *Item {
|
func NewItem(key interface{}, duration time.Duration, data interface{}) *Item {
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
return &Item{
|
return &Item{
|
||||||
@ -42,7 +40,7 @@ func NewItem(key interface{}, duration time.Duration, data interface{}) *Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//手动获取一下,保持该项
|
//keep alive
|
||||||
func (item *Item) KeepAlive() {
|
func (item *Item) KeepAlive() {
|
||||||
item.Lock()
|
item.Lock()
|
||||||
defer item.Unlock()
|
defer item.Unlock()
|
||||||
@ -50,73 +48,63 @@ func (item *Item) KeepAlive() {
|
|||||||
item.count++
|
item.count++
|
||||||
}
|
}
|
||||||
|
|
||||||
//返回生命周期
|
|
||||||
func (item *Item) Duration() time.Duration {
|
func (item *Item) Duration() time.Duration {
|
||||||
return item.duration
|
return item.duration
|
||||||
}
|
}
|
||||||
|
|
||||||
//返回访问时间。可能并发,加锁
|
|
||||||
func (item *Item) AccessTime() time.Time {
|
func (item *Item) AccessTime() time.Time {
|
||||||
item.RLock()
|
item.RLock()
|
||||||
defer item.RUnlock()
|
defer item.RUnlock()
|
||||||
return item.accessTime
|
return item.accessTime
|
||||||
}
|
}
|
||||||
|
|
||||||
//返回创建时间
|
|
||||||
func (item *Item) CreateTime() time.Time {
|
func (item *Item) CreateTime() time.Time {
|
||||||
return item.createTime
|
return item.createTime
|
||||||
}
|
}
|
||||||
|
|
||||||
//返回访问时间。可能并发,加锁
|
|
||||||
func (item *Item) Count() int64 {
|
func (item *Item) Count() int64 {
|
||||||
item.RLock()
|
item.RLock()
|
||||||
defer item.RUnlock()
|
defer item.RUnlock()
|
||||||
return item.count
|
return item.count
|
||||||
}
|
}
|
||||||
|
|
||||||
//返回key值
|
|
||||||
func (item *Item) Key() interface{} {
|
func (item *Item) Key() interface{} {
|
||||||
return item.key
|
return item.key
|
||||||
}
|
}
|
||||||
|
|
||||||
//返回数据
|
|
||||||
func (item *Item) Data() interface{} {
|
func (item *Item) Data() interface{} {
|
||||||
return item.data
|
return item.data
|
||||||
}
|
}
|
||||||
|
|
||||||
//设置回调函数
|
|
||||||
func (item *Item) SetDeleteCallback(f func(interface{})) {
|
func (item *Item) SetDeleteCallback(f func(interface{})) {
|
||||||
item.Lock()
|
item.Lock()
|
||||||
defer item.Unlock()
|
defer item.Unlock()
|
||||||
item.deleteCallback = f
|
item.deleteCallback = f
|
||||||
}
|
}
|
||||||
|
|
||||||
// 统一管理缓存项的表
|
// table for managing cache items
|
||||||
type Table struct {
|
type Table struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
|
|
||||||
//所有缓存项
|
//all cache items
|
||||||
items map[interface{}]*Item
|
items map[interface{}]*Item
|
||||||
// 触发缓存清理的定时器
|
// trigger cleanup
|
||||||
cleanupTimer *time.Timer
|
cleanupTimer *time.Timer
|
||||||
// 缓存清理周期
|
// cleanup interval
|
||||||
cleanupInterval time.Duration
|
cleanupInterval time.Duration
|
||||||
// 获取一个不存在的缓存项时的回调函数
|
|
||||||
loadData func(key interface{}, args ...interface{}) *Item
|
loadData func(key interface{}, args ...interface{}) *Item
|
||||||
// 向缓存表增加缓存项时的回调函数
|
// callback after adding.
|
||||||
addedCallback func(item *Item)
|
addedCallback func(item *Item)
|
||||||
// 从缓存表删除一个缓存项时的回调函数
|
// callback after deleting
|
||||||
deleteCallback func(item *Item)
|
deleteCallback func(item *Item)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回缓存中存储有多少项
|
|
||||||
func (table *Table) Count() int {
|
func (table *Table) Count() int {
|
||||||
table.RLock()
|
table.RLock()
|
||||||
defer table.RUnlock()
|
defer table.RUnlock()
|
||||||
return len(table.items)
|
return len(table.items)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 遍历所有项
|
|
||||||
func (table *Table) Foreach(trans func(key interface{}, item *Item)) {
|
func (table *Table) Foreach(trans func(key interface{}, item *Item)) {
|
||||||
table.RLock()
|
table.RLock()
|
||||||
defer table.RUnlock()
|
defer table.RUnlock()
|
||||||
@ -126,40 +114,34 @@ func (table *Table) Foreach(trans func(key interface{}, item *Item)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDataLoader配置一个数据加载的回调,当尝试去请求一个不存在的key的时候调用
|
|
||||||
func (table *Table) SetDataLoader(f func(interface{}, ...interface{}) *Item) {
|
func (table *Table) SetDataLoader(f func(interface{}, ...interface{}) *Item) {
|
||||||
table.Lock()
|
table.Lock()
|
||||||
defer table.Unlock()
|
defer table.Unlock()
|
||||||
table.loadData = f
|
table.loadData = f
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加时的回调函数
|
|
||||||
func (table *Table) SetAddedCallback(f func(*Item)) {
|
func (table *Table) SetAddedCallback(f func(*Item)) {
|
||||||
table.Lock()
|
table.Lock()
|
||||||
defer table.Unlock()
|
defer table.Unlock()
|
||||||
table.addedCallback = f
|
table.addedCallback = f
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除时的回调函数
|
|
||||||
func (table *Table) SetDeleteCallback(f func(*Item)) {
|
func (table *Table) SetDeleteCallback(f func(*Item)) {
|
||||||
table.Lock()
|
table.Lock()
|
||||||
defer table.Unlock()
|
defer table.Unlock()
|
||||||
table.deleteCallback = f
|
table.deleteCallback = f
|
||||||
}
|
}
|
||||||
|
|
||||||
//带有panic恢复的方法
|
|
||||||
func (table *Table) RunWithRecovery(f func()) {
|
func (table *Table) RunWithRecovery(f func()) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
//core.LOGGER.Error("异步任务错误: %v", err)
|
fmt.Printf("occur error %v \r\n", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
//执行函数
|
|
||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
|
|
||||||
//终结检查,被自调整的时间触发
|
|
||||||
func (table *Table) checkExpire() {
|
func (table *Table) checkExpire() {
|
||||||
table.Lock()
|
table.Lock()
|
||||||
if table.cleanupTimer != nil {
|
if table.cleanupTimer != nil {
|
||||||
@ -171,39 +153,39 @@ func (table *Table) checkExpire() {
|
|||||||
table.log("Expiration check installed for table")
|
table.log("Expiration check installed for table")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 为了不抢占锁,采用临时的items.
|
// in order to not take the lock. use temp items.
|
||||||
items := table.items
|
items := table.items
|
||||||
table.Unlock()
|
table.Unlock()
|
||||||
|
|
||||||
//为了定时器更准确,我们需要在每一个循环中更新‘now’,不确定是否是有效率的。
|
//in order to make timer more precise, update now every loop.
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
smallestDuration := 0 * time.Second
|
smallestDuration := 0 * time.Second
|
||||||
for key, item := range items {
|
for key, item := range items {
|
||||||
// 取出我们需要的东西,为了不抢占锁
|
//take out our things, in order not to take the lock.
|
||||||
item.RLock()
|
item.RLock()
|
||||||
duration := item.duration
|
duration := item.duration
|
||||||
accessTime := item.accessTime
|
accessTime := item.accessTime
|
||||||
item.RUnlock()
|
item.RUnlock()
|
||||||
|
|
||||||
// 0永久有效
|
// 0 means valid.
|
||||||
if duration == 0 {
|
if duration == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if now.Sub(accessTime) >= duration {
|
if now.Sub(accessTime) >= duration {
|
||||||
//缓存项已经过期
|
//cache item expired.
|
||||||
_, e := table.Delete(key)
|
_, e := table.Delete(key)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
table.log("删除缓存项时出错 %v", e.Error())
|
table.log("occur error while deleting %v", e.Error())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//查找最靠近结束生命周期的项目
|
//find the most possible expire item.
|
||||||
if smallestDuration == 0 || duration-now.Sub(accessTime) < smallestDuration {
|
if smallestDuration == 0 || duration-now.Sub(accessTime) < smallestDuration {
|
||||||
smallestDuration = duration - now.Sub(accessTime)
|
smallestDuration = duration - now.Sub(accessTime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 为下次清理设置间隔,自触发机制
|
//trigger next clean
|
||||||
table.Lock()
|
table.Lock()
|
||||||
table.cleanupInterval = smallestDuration
|
table.cleanupInterval = smallestDuration
|
||||||
if smallestDuration > 0 {
|
if smallestDuration > 0 {
|
||||||
@ -214,26 +196,23 @@ func (table *Table) checkExpire() {
|
|||||||
table.Unlock()
|
table.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加缓存项
|
// add item
|
||||||
func (table *Table) Add(key interface{}, duration time.Duration, data interface{}) *Item {
|
func (table *Table) Add(key interface{}, duration time.Duration, data interface{}) *Item {
|
||||||
item := NewItem(key, duration, data)
|
item := NewItem(key, duration, data)
|
||||||
|
|
||||||
// 将缓存项放入表中
|
|
||||||
table.Lock()
|
table.Lock()
|
||||||
table.log("Adding item with key %v and lifespan of %v to table", key, duration)
|
table.log("Adding item with key %v and lifespan of %v to table", key, duration)
|
||||||
table.items[key] = item
|
table.items[key] = item
|
||||||
|
|
||||||
// 取出需要的东西,释放锁
|
|
||||||
expDur := table.cleanupInterval
|
expDur := table.cleanupInterval
|
||||||
addedItem := table.addedCallback
|
addedItem := table.addedCallback
|
||||||
table.Unlock()
|
table.Unlock()
|
||||||
|
|
||||||
// 有回调函数便执行回调
|
|
||||||
if addedItem != nil {
|
if addedItem != nil {
|
||||||
addedItem(item)
|
addedItem(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果我们没有设置任何心跳检查定时器或者找一个即将迫近的项目
|
//find the most possible expire item.
|
||||||
if duration > 0 && (expDur == 0 || duration < expDur) {
|
if duration > 0 && (expDur == 0 || duration < expDur) {
|
||||||
table.checkExpire()
|
table.checkExpire()
|
||||||
}
|
}
|
||||||
@ -241,20 +220,17 @@ func (table *Table) Add(key interface{}, duration time.Duration, data interface{
|
|||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从缓存中删除项
|
|
||||||
func (table *Table) Delete(key interface{}) (*Item, error) {
|
func (table *Table) Delete(key interface{}) (*Item, error) {
|
||||||
table.RLock()
|
table.RLock()
|
||||||
r, ok := table.items[key]
|
r, ok := table.items[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
table.RUnlock()
|
table.RUnlock()
|
||||||
return nil, errors.New(fmt.Sprintf("没有找到%s对应的记录", key))
|
return nil, errors.New(fmt.Sprintf("no item with key %s", key))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 取出要用到的东西,释放锁
|
|
||||||
deleteCallback := table.deleteCallback
|
deleteCallback := table.deleteCallback
|
||||||
table.RUnlock()
|
table.RUnlock()
|
||||||
|
|
||||||
// 调用删除回调函数
|
|
||||||
if deleteCallback != nil {
|
if deleteCallback != nil {
|
||||||
deleteCallback(r)
|
deleteCallback(r)
|
||||||
}
|
}
|
||||||
@ -273,7 +249,7 @@ func (table *Table) Delete(key interface{}) (*Item, error) {
|
|||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//单纯的检查某个键是否存在
|
//check exist.
|
||||||
func (table *Table) Exists(key interface{}) bool {
|
func (table *Table) Exists(key interface{}) bool {
|
||||||
table.RLock()
|
table.RLock()
|
||||||
defer table.RUnlock()
|
defer table.RUnlock()
|
||||||
@ -282,7 +258,7 @@ func (table *Table) Exists(key interface{}) bool {
|
|||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
//如果存在,返回false. 如果不存在,就去添加一个键,并且返回true
|
//if exist, return false. if not exist add a key and return true.
|
||||||
func (table *Table) NotFoundAdd(key interface{}, lifeSpan time.Duration, data interface{}) bool {
|
func (table *Table) NotFoundAdd(key interface{}, lifeSpan time.Duration, data interface{}) bool {
|
||||||
table.Lock()
|
table.Lock()
|
||||||
|
|
||||||
@ -295,24 +271,20 @@ func (table *Table) NotFoundAdd(key interface{}, lifeSpan time.Duration, data in
|
|||||||
table.log("Adding item with key %v and lifespan of %v to table", key, lifeSpan)
|
table.log("Adding item with key %v and lifespan of %v to table", key, lifeSpan)
|
||||||
table.items[key] = item
|
table.items[key] = item
|
||||||
|
|
||||||
// 取出需要的内容,释放锁
|
|
||||||
expDur := table.cleanupInterval
|
expDur := table.cleanupInterval
|
||||||
addedItem := table.addedCallback
|
addedItem := table.addedCallback
|
||||||
table.Unlock()
|
table.Unlock()
|
||||||
|
|
||||||
// 添加回调函数
|
|
||||||
if addedItem != nil {
|
if addedItem != nil {
|
||||||
addedItem(item)
|
addedItem(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 触发过期检查
|
|
||||||
if lifeSpan > 0 && (expDur == 0 || lifeSpan < expDur) {
|
if lifeSpan > 0 && (expDur == 0 || lifeSpan < expDur) {
|
||||||
table.checkExpire()
|
table.checkExpire()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//从缓存中返回一个被标记的并保持活性的值。你可以传附件的参数到DataLoader回调函数
|
|
||||||
func (table *Table) Value(key interface{}, args ...interface{}) (*Item, error) {
|
func (table *Table) Value(key interface{}, args ...interface{}) (*Item, error) {
|
||||||
table.RLock()
|
table.RLock()
|
||||||
r, ok := table.items[key]
|
r, ok := table.items[key]
|
||||||
@ -320,12 +292,11 @@ func (table *Table) Value(key interface{}, args ...interface{}) (*Item, error) {
|
|||||||
table.RUnlock()
|
table.RUnlock()
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
// 更新访问次数和访问时间
|
//update visit count and visit time.
|
||||||
r.KeepAlive()
|
r.KeepAlive()
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 有加载数据的方式,就通过loadData函数去加载进来
|
|
||||||
if loadData != nil {
|
if loadData != nil {
|
||||||
item := loadData(key, args...)
|
item := loadData(key, args...)
|
||||||
if item != nil {
|
if item != nil {
|
||||||
@ -333,14 +304,13 @@ func (table *Table) Value(key interface{}, args ...interface{}) (*Item, error) {
|
|||||||
return item, nil
|
return item, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New("无法加载到缓存值")
|
return nil, errors.New("cannot load item")
|
||||||
}
|
}
|
||||||
|
|
||||||
//没有找到任何东西,返回nil.
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除缓存表中的所有项目
|
// truncate a table.
|
||||||
func (table *Table) Truncate() {
|
func (table *Table) Truncate() {
|
||||||
table.Lock()
|
table.Lock()
|
||||||
defer table.Unlock()
|
defer table.Unlock()
|
||||||
@ -354,7 +324,7 @@ func (table *Table) Truncate() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//辅助table中排序,统计的
|
//support table sort
|
||||||
type ItemPair struct {
|
type ItemPair struct {
|
||||||
Key interface{}
|
Key interface{}
|
||||||
AccessCount int64
|
AccessCount int64
|
||||||
@ -366,7 +336,7 @@ func (p ItemPairList) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
|||||||
func (p ItemPairList) Len() int { return len(p) }
|
func (p ItemPairList) Len() int { return len(p) }
|
||||||
func (p ItemPairList) Less(i, j int) bool { return p[i].AccessCount > p[j].AccessCount }
|
func (p ItemPairList) Less(i, j int) bool { return p[i].AccessCount > p[j].AccessCount }
|
||||||
|
|
||||||
// 返回缓存表中被访问最多的项目
|
//return most visited.
|
||||||
func (table *Table) MostAccessed(count int64) []*Item {
|
func (table *Table) MostAccessed(count int64) []*Item {
|
||||||
table.RLock()
|
table.RLock()
|
||||||
defer table.RUnlock()
|
defer table.RUnlock()
|
||||||
@ -396,12 +366,11 @@ func (table *Table) MostAccessed(count int64) []*Item {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打印日志
|
// print log.
|
||||||
func (table *Table) log(format string, v ...interface{}) {
|
func (table *Table) log(format string, v ...interface{}) {
|
||||||
//core.LOGGER.Info(format, v...)
|
fmt.Printf(format, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
//新建一个缓存Table
|
|
||||||
func NewTable() *Table {
|
func NewTable() *Table {
|
||||||
return &Table{
|
return &Table{
|
||||||
items: make(map[interface{}]*Item),
|
items: make(map[interface{}]*Item),
|
||||||
|
@ -60,7 +60,7 @@ func CheckLastModified(w http.ResponseWriter, r *http.Request, modifyTime time.T
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理ETag标签
|
// handle ETag
|
||||||
// CheckETag implements If-None-Match and If-Range checks.
|
// CheckETag implements If-None-Match and If-Range checks.
|
||||||
//
|
//
|
||||||
// The ETag or modtime must have been previously set in the
|
// The ETag or modtime must have been previously set in the
|
||||||
@ -211,8 +211,7 @@ func PanicError(err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//文件下载。具有进度功能。
|
//file download. https://github.com/Masterminds/go-fileserver
|
||||||
//下载功能参考:https://github.com/Masterminds/go-fileserver
|
|
||||||
func DownloadFile(
|
func DownloadFile(
|
||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
request *http.Request,
|
request *http.Request,
|
||||||
@ -228,16 +227,15 @@ func DownloadFile(
|
|||||||
PanicError(e)
|
PanicError(e)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
//根据参数添加content-disposition。该Header会让浏览器自动下载,而不是预览。
|
//content-disposition tell browser to download rather than preview.
|
||||||
if withContentDisposition {
|
if withContentDisposition {
|
||||||
fileName := url.QueryEscape(filename)
|
fileName := url.QueryEscape(filename)
|
||||||
writer.Header().Set("content-disposition", "attachment; filename=\""+fileName+"\"")
|
writer.Header().Set("content-disposition", "attachment; filename=\""+fileName+"\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
//显示文件大小。
|
|
||||||
fileInfo, err := diskFile.Stat()
|
fileInfo, err := diskFile.Stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("无法从磁盘中获取文件信息")
|
panic("cannot load fileInfo from disk." + filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
modifyTime := fileInfo.ModTime()
|
modifyTime := fileInfo.ModTime()
|
||||||
@ -261,7 +259,7 @@ func DownloadFile(
|
|||||||
ctypes, haveType := writer.Header()["Content-Type"]
|
ctypes, haveType := writer.Header()["Content-Type"]
|
||||||
var ctype string
|
var ctype string
|
||||||
if !haveType {
|
if !haveType {
|
||||||
//使用mimeUtil来获取mime
|
//get mime
|
||||||
ctype = util.GetFallbackMimeType(filename, "")
|
ctype = util.GetFallbackMimeType(filename, "")
|
||||||
if ctype == "" {
|
if ctype == "" {
|
||||||
// read a chunk to decide between utf-8 text and binary
|
// read a chunk to decide between utf-8 text and binary
|
||||||
@ -270,7 +268,7 @@ func DownloadFile(
|
|||||||
ctype = http.DetectContentType(buf[:n])
|
ctype = http.DetectContentType(buf[:n])
|
||||||
_, err := diskFile.Seek(0, os.SEEK_SET) // rewind to output whole file
|
_, err := diskFile.Seek(0, os.SEEK_SET) // rewind to output whole file
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("无法准确定位文件")
|
panic("cannot seek file")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writer.Header().Set("Content-Type", ctype)
|
writer.Header().Set("Content-Type", ctype)
|
||||||
|
@ -26,7 +26,7 @@ var (
|
|||||||
UsernameExist = &Item{English: `username "%s" exists`, Chinese: `用户名"%s"已存在`}
|
UsernameExist = &Item{English: `username "%s" exists`, Chinese: `用户名"%s"已存在`}
|
||||||
UsernameNotExist = &Item{English: `username "%s" not exists`, Chinese: `用户名"%s"不存在`}
|
UsernameNotExist = &Item{English: `username "%s" not exists`, Chinese: `用户名"%s"不存在`}
|
||||||
UsernameIsNotAdmin = &Item{English: `username "%s" is not admin user`, Chinese: `用户名"%s"不是管理员账号`}
|
UsernameIsNotAdmin = &Item{English: `username "%s" is not admin user`, Chinese: `用户名"%s"不是管理员账号`}
|
||||||
UsernameError = &Item{English: `username can only be letters, numbers or _`, Chinese: `用户名必填,且只能包含字母,数字和'_'`}
|
UsernameError = &Item{English: `username can only be lowercase letters, numbers or _`, Chinese: `用户名必填,且只能包含小写字母,数字和'_'`}
|
||||||
UserRegisterNotAllowd = &Item{English: `admin has banned register`, Chinese: `管理员已禁用自主注册`}
|
UserRegisterNotAllowd = &Item{English: `admin has banned register`, Chinese: `管理员已禁用自主注册`}
|
||||||
UserPasswordLengthError = &Item{English: `password at least 6 chars`, Chinese: `密码长度至少为6位`}
|
UserPasswordLengthError = &Item{English: `password at least 6 chars`, Chinese: `密码长度至少为6位`}
|
||||||
UserOldPasswordError = &Item{English: `old password error`, Chinese: `旧密码不正确`}
|
UserOldPasswordError = &Item{English: `old password error`, Chinese: `旧密码不正确`}
|
||||||
@ -36,10 +36,13 @@ var (
|
|||||||
MatterNameLengthExceedLimit = &Item{English: `filename's length exceed the limit %d > %d`, Chinese: `文件名称长度超过限制 %d > %d `}
|
MatterNameLengthExceedLimit = &Item{English: `filename's length exceed the limit %d > %d`, Chinese: `文件名称长度超过限制 %d > %d `}
|
||||||
MatterSelectNumExceedLimit = &Item{English: `selected files' num exceed the limit %d > %d`, Chinese: `选择的文件数量超出限制了 %d > %d `}
|
MatterSelectNumExceedLimit = &Item{English: `selected files' num exceed the limit %d > %d`, Chinese: `选择的文件数量超出限制了 %d > %d `}
|
||||||
MatterSelectSizeExceedLimit = &Item{English: `selected files' size exceed the limit %s > %s`, Chinese: `选择的文件大小超出限制了 %s > %s `}
|
MatterSelectSizeExceedLimit = &Item{English: `selected files' size exceed the limit %s > %s`, Chinese: `选择的文件大小超出限制了 %s > %s `}
|
||||||
|
MatterSizeExceedLimit = &Item{English: `uploaded file's size exceed the size limit %s > %s `, Chinese: `上传的文件超过了限制 %s > %s `}
|
||||||
MatterNameContainSpecialChars = &Item{English: `file name cannot contain special chars \ / : * ? " < > |"`, Chinese: `名称中不能包含以下特殊符号:\ / : * ? " < > |`}
|
MatterNameContainSpecialChars = &Item{English: `file name cannot contain special chars \ / : * ? " < > |"`, Chinese: `名称中不能包含以下特殊符号:\ / : * ? " < > |`}
|
||||||
MatterMoveRecursive = &Item{English: `directory cannot be moved to itself or its children`, Chinese: `文件夹不能把自己移入到自己中,也不可以移入到自己的子文件夹下。`}
|
MatterMoveRecursive = &Item{English: `directory cannot be moved to itself or its children`, Chinese: `文件夹不能把自己移入到自己中,也不可以移入到自己的子文件夹下。`}
|
||||||
MatterNameNoChange = &Item{English: `filename not change, invalid operation`, Chinese: `文件名没有改变,操作无效!`}
|
MatterNameNoChange = &Item{English: `filename not change, invalid operation`, Chinese: `文件名没有改变,操作无效!`}
|
||||||
ShareNumExceedLimit = &Item{English: `sharing files' num exceed the limit %d > %d`, Chinese: `一次分享的文件数量超出限制了 %d > %d `}
|
ShareNumExceedLimit = &Item{English: `sharing files' num exceed the limit %d > %d`, Chinese: `一次分享的文件数量超出限制了 %d > %d `}
|
||||||
|
ShareCodeRequired = &Item{English: `share code required`, Chinese: `提取码必填`}
|
||||||
|
ShareCodeError = &Item{English: `share code error`, Chinese: `提取码错误`}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (this *Item) Message(request *http.Request) string {
|
func (this *Item) Message(request *http.Request) string {
|
||||||
|
@ -37,7 +37,6 @@ var (
|
|||||||
UNKNOWN = &CodeWrapper{Code: "UNKNOWN", HttpStatus: http.StatusInternalServerError, Description: "server unknow error"}
|
UNKNOWN = &CodeWrapper{Code: "UNKNOWN", HttpStatus: http.StatusInternalServerError, Description: "server unknow error"}
|
||||||
)
|
)
|
||||||
|
|
||||||
//根据 CodeWrapper来获取对应的HttpStatus
|
|
||||||
func FetchHttpStatus(code string) int {
|
func FetchHttpStatus(code string) int {
|
||||||
if code == OK.Code {
|
if code == OK.Code {
|
||||||
return OK.HttpStatus
|
return OK.HttpStatus
|
||||||
@ -75,6 +74,12 @@ func ConstWebResult(codeWrapper *CodeWrapper) *WebResult {
|
|||||||
return wr
|
return wr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CustomWebResultI18n(request *http.Request, codeWrapper *CodeWrapper, item *i18n.Item, v ...interface{}) *WebResult {
|
||||||
|
|
||||||
|
return CustomWebResult(codeWrapper, fmt.Sprintf(item.Message(request), v...))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func CustomWebResult(codeWrapper *CodeWrapper, description string) *WebResult {
|
func CustomWebResult(codeWrapper *CodeWrapper, description string) *WebResult {
|
||||||
|
|
||||||
if description == "" {
|
if description == "" {
|
||||||
@ -91,28 +96,25 @@ func BadRequestI18n(request *http.Request, item *i18n.Item, v ...interface{}) *W
|
|||||||
return CustomWebResult(BAD_REQUEST, fmt.Sprintf(item.Message(request), v...))
|
return CustomWebResult(BAD_REQUEST, fmt.Sprintf(item.Message(request), v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
//没有权限
|
|
||||||
func BadRequest(format string, v ...interface{}) *WebResult {
|
func BadRequest(format string, v ...interface{}) *WebResult {
|
||||||
return CustomWebResult(BAD_REQUEST, fmt.Sprintf(format, v...))
|
return CustomWebResult(BAD_REQUEST, fmt.Sprintf(format, v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
//没有权限
|
|
||||||
func Unauthorized(format string, v ...interface{}) *WebResult {
|
func Unauthorized(format string, v ...interface{}) *WebResult {
|
||||||
return CustomWebResult(UNAUTHORIZED, fmt.Sprintf(format, v...))
|
return CustomWebResult(UNAUTHORIZED, fmt.Sprintf(format, v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
//没有找到
|
|
||||||
func NotFound(format string, v ...interface{}) *WebResult {
|
func NotFound(format string, v ...interface{}) *WebResult {
|
||||||
return CustomWebResult(NOT_FOUND, fmt.Sprintf(format, v...))
|
return CustomWebResult(NOT_FOUND, fmt.Sprintf(format, v...))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//服务器内部出问题
|
//sever inner error
|
||||||
func Server(format string, v ...interface{}) *WebResult {
|
func Server(format string, v ...interface{}) *WebResult {
|
||||||
return CustomWebResult(SERVER, fmt.Sprintf(format, v...))
|
return CustomWebResult(SERVER, fmt.Sprintf(format, v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
//所有的数据库错误情况
|
//db error.
|
||||||
var (
|
var (
|
||||||
DB_ERROR_DUPLICATE_KEY = "Error 1062: Duplicate entry"
|
DB_ERROR_DUPLICATE_KEY = "Error 1062: Duplicate entry"
|
||||||
DB_ERROR_NOT_FOUND = "record not found"
|
DB_ERROR_NOT_FOUND = "record not found"
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
//给密码字符串加密
|
//md5
|
||||||
func GetMd5(raw string) string {
|
func GetMd5(raw string) string {
|
||||||
return fmt.Sprintf("%x", md5.Sum([]byte(raw)))
|
return fmt.Sprintf("%x", md5.Sum([]byte(raw)))
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
//是否为win开发环境
|
//whether windows develop environment
|
||||||
func EnvWinDevelopment() bool {
|
func EnvWinDevelopment() bool {
|
||||||
|
|
||||||
ex, err := os.Executable()
|
ex, err := os.Executable()
|
||||||
@ -14,7 +14,7 @@ func EnvWinDevelopment() bool {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//如果exPath中包含了 \\AppData\\Local\\Temp 我们认为是在Win的开发环境中
|
//if exPath contains \\AppData\\Local\\Temp we regard as dev.
|
||||||
systemUser, err := user.Current()
|
systemUser, err := user.Current()
|
||||||
if systemUser != nil {
|
if systemUser != nil {
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ func EnvWinDevelopment() bool {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//是否为mac开发环境
|
//whether mac develop environment
|
||||||
func EnvMacDevelopment() bool {
|
func EnvMacDevelopment() bool {
|
||||||
|
|
||||||
ex, err := os.Executable()
|
ex, err := os.Executable()
|
||||||
@ -38,7 +38,7 @@ func EnvMacDevelopment() bool {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//是否为开发环境 (即是否在IDE中运行)
|
//whether develop environment (whether run in IDE)
|
||||||
func EnvDevelopment() bool {
|
func EnvDevelopment() bool {
|
||||||
|
|
||||||
return EnvWinDevelopment() || EnvMacDevelopment()
|
return EnvWinDevelopment() || EnvMacDevelopment()
|
||||||
|
@ -7,12 +7,12 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
//判断文件或文件夹是否已经存在
|
|
||||||
func PathExists(path string) bool {
|
func PathExists(path string) bool {
|
||||||
_, err := os.Stat(path)
|
_, err := os.Stat(path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -26,14 +26,13 @@ func PathExists(path string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取GOPATH路径
|
|
||||||
func GetGoPath() string {
|
func GetGoPath() string {
|
||||||
|
|
||||||
return build.Default.GOPATH
|
return build.Default.GOPATH
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取开发时的Home目录
|
//get development home path.
|
||||||
func GetDevHomePath() string {
|
func GetDevHomePath() string {
|
||||||
|
|
||||||
_, file, _, ok := runtime.Caller(0)
|
_, file, _, ok := runtime.Caller(0)
|
||||||
@ -50,8 +49,7 @@ func GetDevHomePath() string {
|
|||||||
return dir
|
return dir
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取该应用可执行文件的位置。
|
//get home path for application.
|
||||||
//例如:C:\Users\lishuang\AppData\Local\Temp
|
|
||||||
func GetHomePath() string {
|
func GetHomePath() string {
|
||||||
ex, err := os.Executable()
|
ex, err := os.Executable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -70,8 +68,9 @@ func GetHomePath() string {
|
|||||||
return UniformPath(exPath)
|
return UniformPath(exPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取前端静态资源的位置。如果你在开发模式下,可以将这里直接返回tank/build下面的html路径。
|
//get html path
|
||||||
//例如:C:/Users/lishuang/AppData/Local/Temp/html
|
//dev: return $project/build/html
|
||||||
|
//prod: return $application/html
|
||||||
func GetHtmlPath() string {
|
func GetHtmlPath() string {
|
||||||
|
|
||||||
//开发环境直接使用 build/html 下面的文件
|
//开发环境直接使用 build/html 下面的文件
|
||||||
@ -81,27 +80,27 @@ func GetHtmlPath() string {
|
|||||||
return GetHomePath() + "/html"
|
return GetHomePath() + "/html"
|
||||||
}
|
}
|
||||||
|
|
||||||
//如果文件夹存在就不管,不存在就创建。 例如:/var/www/matter
|
//if directory not exit, create it.
|
||||||
func MakeDirAll(dirPath string) string {
|
func MakeDirAll(dirPath string) string {
|
||||||
|
|
||||||
exists := PathExists(dirPath)
|
exists := PathExists(dirPath)
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
//TODO:文件权限需要进一步考虑
|
|
||||||
err := os.MkdirAll(dirPath, 0777)
|
err := os.MkdirAll(dirPath, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("创建文件夹时出错!")
|
panic("error while creating directory")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dirPath
|
return dirPath
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取到一个Path的文件夹路径,eg /var/www/xx.log -> /var/www
|
//eg /var/www/xx.log -> /var/www
|
||||||
func GetDirOfPath(fullPath string) string {
|
func GetDirOfPath(fullPath string) string {
|
||||||
|
|
||||||
index1 := strings.LastIndex(fullPath, "/")
|
index1 := strings.LastIndex(fullPath, "/")
|
||||||
//可能是windows的环境
|
//maybe windows environment
|
||||||
index2 := strings.LastIndex(fullPath, "\\")
|
index2 := strings.LastIndex(fullPath, "\\")
|
||||||
index := index1
|
index := index1
|
||||||
if index2 > index1 {
|
if index2 > index1 {
|
||||||
@ -111,11 +110,11 @@ func GetDirOfPath(fullPath string) string {
|
|||||||
return fullPath[:index]
|
return fullPath[:index]
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取到一个Path 中的文件名,eg /var/www/xx.log -> xx.log
|
//get filename from path. eg /var/www/xx.log -> xx.log
|
||||||
func GetFilenameOfPath(fullPath string) string {
|
func GetFilenameOfPath(fullPath string) string {
|
||||||
|
|
||||||
index1 := strings.LastIndex(fullPath, "/")
|
index1 := strings.LastIndex(fullPath, "/")
|
||||||
//可能是windows的环境
|
//maybe windows env
|
||||||
index2 := strings.LastIndex(fullPath, "\\")
|
index2 := strings.LastIndex(fullPath, "\\")
|
||||||
index := index1
|
index := index1
|
||||||
if index2 > index1 {
|
if index2 > index1 {
|
||||||
@ -125,17 +124,17 @@ func GetFilenameOfPath(fullPath string) string {
|
|||||||
return fullPath[index+1:]
|
return fullPath[index+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
//尝试删除空文件夹 true表示删掉了一个空文件夹,false表示没有删掉任何东西
|
//try to delete empty dir. true: delete an empty dir, false: delete nothing.
|
||||||
func DeleteEmptyDir(dirPath string) bool {
|
func DeleteEmptyDir(dirPath string) bool {
|
||||||
dir, err := ioutil.ReadDir(dirPath)
|
dir, err := ioutil.ReadDir(dirPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(result.BadRequest("尝试读取目录%s时出错 %s", dirPath, err.Error()))
|
panic(result.BadRequest("occur error while reading %s %s", dirPath, err.Error()))
|
||||||
}
|
}
|
||||||
if len(dir) == 0 {
|
if len(dir) == 0 {
|
||||||
//空文件夹
|
//empty dir
|
||||||
err = os.Remove(dirPath)
|
err = os.Remove(dirPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(result.BadRequest("删除磁盘上的文件夹%s出错 %s", dirPath, err.Error()))
|
panic(result.BadRequest("occur error while deleting %s %s", dirPath, err.Error()))
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -143,39 +142,23 @@ func DeleteEmptyDir(dirPath string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
//递归尝试删除空文件夹,一直空就一直删,直到不空为止
|
//delete empty dir recursive, delete until not empty.
|
||||||
func DeleteEmptyDirRecursive(dirPath string) {
|
func DeleteEmptyDirRecursive(dirPath string) {
|
||||||
|
|
||||||
fmt.Printf("递归删除删 %v \n", dirPath)
|
fmt.Printf("recursive delete %v \n", dirPath)
|
||||||
|
|
||||||
tmpPath := dirPath
|
tmpPath := dirPath
|
||||||
for DeleteEmptyDir(tmpPath) {
|
for DeleteEmptyDir(tmpPath) {
|
||||||
|
|
||||||
dir := GetDirOfPath(tmpPath)
|
dir := GetDirOfPath(tmpPath)
|
||||||
|
|
||||||
fmt.Printf("尝试删除 %v\n", dir)
|
fmt.Printf("try to delete %v\n", dir)
|
||||||
|
|
||||||
tmpPath = dir
|
tmpPath = dir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//移除某个文件夹。
|
//get conf path.
|
||||||
func RemoveDirectory(dirPath string) string {
|
|
||||||
|
|
||||||
exists := PathExists(dirPath)
|
|
||||||
if exists {
|
|
||||||
|
|
||||||
err := os.Remove(dirPath)
|
|
||||||
if err != nil {
|
|
||||||
panic("删除文件夹时出错!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dirPath
|
|
||||||
}
|
|
||||||
|
|
||||||
//获取配置文件存放的位置
|
|
||||||
//例如:C:\Users\lishuang\AppData\Local\Temp/conf
|
|
||||||
func GetConfPath() string {
|
func GetConfPath() string {
|
||||||
|
|
||||||
homePath := GetHomePath()
|
homePath := GetHomePath()
|
||||||
@ -185,15 +168,14 @@ func GetConfPath() string {
|
|||||||
if !exists {
|
if !exists {
|
||||||
err := os.MkdirAll(filePath, 0777)
|
err := os.MkdirAll(filePath, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("创建日志文件夹时出错!")
|
panic("error while mkdir " + err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return filePath
|
return filePath
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取日志的路径
|
//get log path.
|
||||||
//例如:默认存放于 home/log
|
|
||||||
func GetLogPath() string {
|
func GetLogPath() string {
|
||||||
|
|
||||||
homePath := GetHomePath()
|
homePath := GetHomePath()
|
||||||
@ -203,14 +185,14 @@ func GetLogPath() string {
|
|||||||
if !exists {
|
if !exists {
|
||||||
err := os.MkdirAll(filePath, 0777)
|
err := os.MkdirAll(filePath, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("创建日志文件夹时出错!")
|
panic("error while mkdir " + err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return filePath
|
return filePath
|
||||||
}
|
}
|
||||||
|
|
||||||
//复制文件
|
//copy file
|
||||||
func CopyFile(srcPath string, destPath string) (nBytes int64) {
|
func CopyFile(srcPath string, destPath string) (nBytes int64) {
|
||||||
|
|
||||||
srcFileStat, err := os.Stat(srcPath)
|
srcFileStat, err := os.Stat(srcPath)
|
||||||
@ -248,9 +230,12 @@ func CopyFile(srcPath string, destPath string) (nBytes int64) {
|
|||||||
return nBytes
|
return nBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
//路径归一化处理,把\\替换成/
|
//1. replace \\ to /
|
||||||
func UniformPath(path string) string {
|
//2. clean path.
|
||||||
|
//3. trim suffix /
|
||||||
return strings.Replace(path, "\\", "/", -1)
|
func UniformPath(p string) string {
|
||||||
|
p = strings.Replace(p, "\\", "/", -1)
|
||||||
|
p = path.Clean(p)
|
||||||
|
p = strings.TrimSuffix(p, "/")
|
||||||
|
return p
|
||||||
}
|
}
|
||||||
|
@ -618,7 +618,7 @@ var allMimeMap = map[string]string{
|
|||||||
".z": "application/x-compress",
|
".z": "application/x-compress",
|
||||||
".zip": "application/zip"}
|
".zip": "application/zip"}
|
||||||
|
|
||||||
//根据文件名字获取后缀名,均是小写。
|
//get extension by name. lowercase.
|
||||||
func GetExtension(filename string) string {
|
func GetExtension(filename string) string {
|
||||||
|
|
||||||
var extension = filepath.Ext(filename)
|
var extension = filepath.Ext(filename)
|
||||||
@ -627,7 +627,7 @@ func GetExtension(filename string) string {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//根据文件名字获取去除后缀的名称
|
//get filename without extension
|
||||||
func GetSimpleFileName(filename string) string {
|
func GetSimpleFileName(filename string) string {
|
||||||
|
|
||||||
for i := len(filename) - 1; i >= 0 && !os.IsPathSeparator(filename[i]); i-- {
|
for i := len(filename) - 1; i >= 0 && !os.IsPathSeparator(filename[i]); i-- {
|
||||||
@ -639,7 +639,7 @@ func GetSimpleFileName(filename string) string {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//根据一个后缀名获取MimeType,获取不到默认返回 "application/octet-stream"
|
//get MimeType by filename, if not found return "application/octet-stream"
|
||||||
func GetMimeType(filename string) string {
|
func GetMimeType(filename string) string {
|
||||||
|
|
||||||
extension := GetExtension(filename)
|
extension := GetExtension(filename)
|
||||||
@ -651,7 +651,7 @@ func GetMimeType(filename string) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//根据一个后缀名获取MimeType,获取不到默认返回fallback.
|
//get MimeType by filename, if not found return fallback.
|
||||||
func GetFallbackMimeType(filename string, fallback string) string {
|
func GetFallbackMimeType(filename string, fallback string) string {
|
||||||
|
|
||||||
extension := GetExtension(filename)
|
extension := GetExtension(filename)
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
//根据一个请求,获取ip.
|
//get ip from request
|
||||||
func GetIpAddress(r *http.Request) string {
|
func GetIpAddress(r *http.Request) string {
|
||||||
var ipAddress string
|
var ipAddress string
|
||||||
|
|
||||||
@ -25,21 +25,21 @@ func GetIpAddress(r *http.Request) string {
|
|||||||
return ipAddress
|
return ipAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
//根据一个请求,获取host
|
//get host from request
|
||||||
func GetHostFromRequest(r *http.Request) string {
|
func GetHostFromRequest(request *http.Request) string {
|
||||||
|
|
||||||
return r.Host
|
return request.Host
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//根据一个请求,获取authenticationId
|
//get cookieAuthKey from request.
|
||||||
func GetSessionUuidFromRequest(request *http.Request, cookieAuthKey string) string {
|
func GetSessionUuidFromRequest(request *http.Request, cookieAuthKey string) string {
|
||||||
|
|
||||||
//验证用户是否已经登录。
|
//get from cookie
|
||||||
sessionCookie, err := request.Cookie(cookieAuthKey)
|
sessionCookie, err := request.Cookie(cookieAuthKey)
|
||||||
var sessionId string
|
var sessionId string
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//从入参中捞取
|
//try to get from Form
|
||||||
sessionId = request.FormValue(cookieAuthKey)
|
sessionId = request.FormValue(cookieAuthKey)
|
||||||
} else {
|
} else {
|
||||||
sessionId = sessionCookie.Value
|
sessionId = sessionCookie.Value
|
||||||
@ -49,7 +49,7 @@ func GetSessionUuidFromRequest(request *http.Request, cookieAuthKey string) stri
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//允许跨域请求
|
//allow cors.
|
||||||
func AllowCORS(writer http.ResponseWriter) {
|
func AllowCORS(writer http.ResponseWriter) {
|
||||||
writer.Header().Add("Access-Control-Allow-Origin", "*")
|
writer.Header().Add("Access-Control-Allow-Origin", "*")
|
||||||
writer.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
|
writer.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
|
||||||
@ -57,9 +57,9 @@ func AllowCORS(writer http.ResponseWriter) {
|
|||||||
writer.Header().Add("Access-Control-Allow-Headers", "content-type")
|
writer.Header().Add("Access-Control-Allow-Headers", "content-type")
|
||||||
}
|
}
|
||||||
|
|
||||||
//禁用缓存
|
//disable cache.
|
||||||
func DisableCache(writer http.ResponseWriter) {
|
func DisableCache(writer http.ResponseWriter) {
|
||||||
//对于IE浏览器,会自动缓存,因此设置不缓存Header.
|
//IE browser will cache automatically. disable the cache.
|
||||||
writer.Header().Set("Pragma", "No-cache")
|
writer.Header().Set("Pragma", "No-cache")
|
||||||
writer.Header().Set("Cache-Control", "no-cache")
|
writer.Header().Set("Cache-Control", "no-cache")
|
||||||
writer.Header().Set("Expires", "0")
|
writer.Header().Set("Expires", "0")
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
//把一个大小转变成方便读的格式
|
|
||||||
//human readable file size
|
//human readable file size
|
||||||
func HumanFileSize(bytes int64) string {
|
func HumanFileSize(bytes int64) string {
|
||||||
var thresh int64 = 1024
|
var thresh int64 = 1024
|
||||||
@ -33,7 +32,7 @@ func HumanFileSize(bytes int64) string {
|
|||||||
return fmt.Sprintf("%s%s", numStr, units[u])
|
return fmt.Sprintf("%s%s", numStr, units[u])
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取MySQL的URL
|
//get mysql url.
|
||||||
func GetMysqlUrl(
|
func GetMysqlUrl(
|
||||||
mysqlPort int,
|
mysqlPort int,
|
||||||
mysqlHost string,
|
mysqlHost string,
|
||||||
@ -43,15 +42,15 @@ func GetMysqlUrl(
|
|||||||
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local", mysqlUsername, mysqlPassword, mysqlHost, mysqlPort, mysqlSchema)
|
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local", mysqlUsername, mysqlPassword, mysqlHost, mysqlPort, mysqlSchema)
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取四位随机数字
|
//get random number 4.
|
||||||
func RandomNumber4() string {
|
func RandomNumber4() string {
|
||||||
return fmt.Sprintf("%04v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31()%10000)
|
return fmt.Sprintf("%04v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31()%10000)
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取四位随机数字
|
//get random 4 string
|
||||||
func RandomString4() string {
|
func RandomString4() string {
|
||||||
|
|
||||||
//0和o,l和1难以区分,剔除掉
|
//0 and o, 1 and l are not easy to distinguish
|
||||||
var letterRunes = []rune("abcdefghijkmnpqrstuvwxyz23456789")
|
var letterRunes = []rune("abcdefghijkmnpqrstuvwxyz23456789")
|
||||||
|
|
||||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
@ -5,57 +5,54 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
//将一个时间字符串转换成时间对象(yyyy-MM-dd HH:mm:ss)
|
//convert time string(yyyy-MM-dd HH:mm:ss) to Time object
|
||||||
func ConvertDateTimeStringToTime(timeString string) time.Time {
|
func ConvertDateTimeStringToTime(timeString string) time.Time {
|
||||||
local, _ := time.LoadLocation("Local")
|
local, _ := time.LoadLocation("Local")
|
||||||
t, err := time.ParseInLocation("2006-01-02 15:04:05", timeString, local)
|
t, err := time.ParseInLocation("2006-01-02 15:04:05", timeString, local)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("不能将%s转为时间类型", timeString))
|
panic(fmt.Sprintf("cannot convert %s to Time", timeString))
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
//将一个时间字符串转换成日期时间对象(yyyy-MM-dd HH:mm:ss)
|
//convert Time object to string(yyyy-MM-dd HH:mm:ss)
|
||||||
func ConvertTimeToDateTimeString(time time.Time) string {
|
func ConvertTimeToDateTimeString(time time.Time) string {
|
||||||
return time.Local().Format("2006-01-02 15:04:05")
|
return time.Local().Format("2006-01-02 15:04:05")
|
||||||
}
|
}
|
||||||
|
|
||||||
//将一个时间字符串转换成日期时间对象(yyyy-MM-dd HH:mm:ss)
|
//convert Time object to string(HH:mm:ss)
|
||||||
func ConvertTimeToTimeString(time time.Time) string {
|
func ConvertTimeToTimeString(time time.Time) string {
|
||||||
return time.Local().Format("15:04:05")
|
return time.Local().Format("15:04:05")
|
||||||
}
|
}
|
||||||
|
|
||||||
//将一个时间字符串转换成日期对象(yyyy-MM-dd)
|
//convert Time object to string(yyyy-MM-dd)
|
||||||
func ConvertTimeToDateString(time time.Time) string {
|
func ConvertTimeToDateString(time time.Time) string {
|
||||||
return time.Local().Format("2006-01-02")
|
return time.Local().Format("2006-01-02")
|
||||||
}
|
}
|
||||||
|
|
||||||
//一天中的最后一秒钟
|
|
||||||
func LastSecondOfDay(day time.Time) time.Time {
|
func LastSecondOfDay(day time.Time) time.Time {
|
||||||
local, _ := time.LoadLocation("Local")
|
local, _ := time.LoadLocation("Local")
|
||||||
return time.Date(day.Year(), day.Month(), day.Day(), 23, 59, 59, 0, local)
|
return time.Date(day.Year(), day.Month(), day.Day(), 23, 59, 59, 0, local)
|
||||||
}
|
}
|
||||||
|
|
||||||
//一天中的第一秒钟
|
|
||||||
func FirstSecondOfDay(day time.Time) time.Time {
|
func FirstSecondOfDay(day time.Time) time.Time {
|
||||||
local, _ := time.LoadLocation("Local")
|
local, _ := time.LoadLocation("Local")
|
||||||
return time.Date(day.Year(), day.Month(), day.Day(), 0, 0, 0, 0, local)
|
return time.Date(day.Year(), day.Month(), day.Day(), 0, 0, 0, 0, local)
|
||||||
}
|
}
|
||||||
|
|
||||||
//一天中的第一分钟
|
|
||||||
func FirstMinuteOfDay(day time.Time) time.Time {
|
func FirstMinuteOfDay(day time.Time) time.Time {
|
||||||
local, _ := time.LoadLocation("Local")
|
local, _ := time.LoadLocation("Local")
|
||||||
return time.Date(day.Year(), day.Month(), day.Day(), 0, 1, 0, 0, local)
|
return time.Date(day.Year(), day.Month(), day.Day(), 0, 1, 0, 0, local)
|
||||||
}
|
}
|
||||||
|
|
||||||
//明天此刻的时间
|
//Tomorrow right now
|
||||||
func Tomorrow() time.Time {
|
func Tomorrow() time.Time {
|
||||||
tomorrow := time.Now()
|
tomorrow := time.Now()
|
||||||
tomorrow = tomorrow.AddDate(0, 0, 1)
|
tomorrow = tomorrow.AddDate(0, 0, 1)
|
||||||
return tomorrow
|
return tomorrow
|
||||||
}
|
}
|
||||||
|
|
||||||
//昨天此刻的时间
|
//Yesterday right now
|
||||||
func Yesterday() time.Time {
|
func Yesterday() time.Time {
|
||||||
tomorrow := time.Now()
|
tomorrow := time.Now()
|
||||||
tomorrow = tomorrow.AddDate(0, 0, -1)
|
tomorrow = tomorrow.AddDate(0, 0, -1)
|
||||||
|
@ -4,23 +4,20 @@ import (
|
|||||||
"archive/zip"
|
"archive/zip"
|
||||||
"github.com/eyebluecn/tank/code/tool/result"
|
"github.com/eyebluecn/tank/code/tool/result"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
//将srcPath压缩到destPath。
|
//zip srcPath to destPath。
|
||||||
func Zip(srcPath string, destPath string) error {
|
func Zip(srcPath string, destPath string) error {
|
||||||
|
|
||||||
//统一处理\\成/
|
|
||||||
srcPath = UniformPath(srcPath)
|
srcPath = UniformPath(srcPath)
|
||||||
|
|
||||||
if PathExists(destPath) {
|
if PathExists(destPath) {
|
||||||
panic(result.BadRequest("%s 已经存在了", destPath))
|
panic(result.BadRequest("%s exits", destPath))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建准备写入的文件
|
|
||||||
fileWriter, err := os.Create(destPath)
|
fileWriter, err := os.Create(destPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -32,53 +29,44 @@ func Zip(srcPath string, destPath string) error {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// 通过 fileWriter 来创建 zip.Write
|
|
||||||
zipWriter := zip.NewWriter(fileWriter)
|
zipWriter := zip.NewWriter(fileWriter)
|
||||||
defer func() {
|
defer func() {
|
||||||
// 检测一下是否成功关闭
|
|
||||||
if err := zipWriter.Close(); err != nil {
|
if err := zipWriter.Close(); err != nil {
|
||||||
log.Fatalln(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
//上一个文件夹路径
|
|
||||||
baseDirPath := GetDirOfPath(srcPath) + "/"
|
baseDirPath := GetDirOfPath(srcPath) + "/"
|
||||||
// 下面来将文件写入 zipWriter ,因为有可能会有很多个目录及文件,所以递归处理
|
|
||||||
err = filepath.Walk(srcPath, func(path string, fileInfo os.FileInfo, errBack error) (err error) {
|
err = filepath.Walk(srcPath, func(path string, fileInfo os.FileInfo, errBack error) (err error) {
|
||||||
if errBack != nil {
|
if errBack != nil {
|
||||||
return errBack
|
return errBack
|
||||||
}
|
}
|
||||||
|
|
||||||
//统一处理\\成/
|
|
||||||
path = UniformPath(path)
|
path = UniformPath(path)
|
||||||
|
|
||||||
// 通过文件信息,创建 zip 的文件信息
|
|
||||||
fileHeader, err := zip.FileInfoHeader(fileInfo)
|
fileHeader, err := zip.FileInfoHeader(fileInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 替换文件信息中的文件名
|
|
||||||
fileHeader.Name = strings.TrimPrefix(path, baseDirPath)
|
fileHeader.Name = strings.TrimPrefix(path, baseDirPath)
|
||||||
|
|
||||||
// 目录前要加上/
|
// directory need /
|
||||||
if fileInfo.IsDir() {
|
if fileInfo.IsDir() {
|
||||||
fileHeader.Name += "/"
|
fileHeader.Name += "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
// 写入文件信息,并返回一个 Write 结构
|
|
||||||
writer, err := zipWriter.CreateHeader(fileHeader)
|
writer, err := zipWriter.CreateHeader(fileHeader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测,如果不是标准文件就只写入头信息,不写入文件数据到 writer
|
//only regular has things to write.
|
||||||
// 如目录,也没有数据需要写
|
|
||||||
if !fileHeader.Mode().IsRegular() {
|
if !fileHeader.Mode().IsRegular() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打开要压缩的文件
|
|
||||||
fileToBeZip, err := os.Open(path)
|
fileToBeZip, err := os.Open(path)
|
||||||
defer func() {
|
defer func() {
|
||||||
err = fileToBeZip.Close()
|
err = fileToBeZip.Close()
|
||||||
@ -90,7 +78,6 @@ func Zip(srcPath string, destPath string) error {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将打开的文件 Copy 到 writer
|
|
||||||
_, err = io.Copy(writer, fileToBeZip)
|
_, err = io.Copy(writer, fileToBeZip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
Loading…
Reference in New Issue
Block a user