Finish all the i18n things of code.
This commit is contained in:
109
code/tool/cache/cache.go
vendored
109
code/tool/cache/cache.go
vendored
@ -8,27 +8,25 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
//缓存项
|
||||
//主要借鉴了cache2go https://github.com/muesli/cache2go
|
||||
//cache2go https://github.com/muesli/cache2go
|
||||
type Item struct {
|
||||
sync.RWMutex //读写锁
|
||||
//缓存键
|
||||
key interface{}
|
||||
//缓存值
|
||||
//read write lock
|
||||
sync.RWMutex
|
||||
key interface{}
|
||||
data interface{}
|
||||
// 缓存项的生命期
|
||||
// cache duration.
|
||||
duration time.Duration
|
||||
//创建时间
|
||||
// create time
|
||||
createTime time.Time
|
||||
//最后访问时间
|
||||
//last access time
|
||||
accessTime time.Time
|
||||
//访问次数
|
||||
//visit times
|
||||
count int64
|
||||
// 在删除缓存项之前调用的回调函数
|
||||
// callback after deleting
|
||||
deleteCallback func(key interface{})
|
||||
}
|
||||
|
||||
//新建一项缓存
|
||||
//create item.
|
||||
func NewItem(key interface{}, duration time.Duration, data interface{}) *Item {
|
||||
t := time.Now()
|
||||
return &Item{
|
||||
@ -42,7 +40,7 @@ func NewItem(key interface{}, duration time.Duration, data interface{}) *Item {
|
||||
}
|
||||
}
|
||||
|
||||
//手动获取一下,保持该项
|
||||
//keep alive
|
||||
func (item *Item) KeepAlive() {
|
||||
item.Lock()
|
||||
defer item.Unlock()
|
||||
@ -50,73 +48,63 @@ func (item *Item) KeepAlive() {
|
||||
item.count++
|
||||
}
|
||||
|
||||
//返回生命周期
|
||||
func (item *Item) Duration() time.Duration {
|
||||
return item.duration
|
||||
}
|
||||
|
||||
//返回访问时间。可能并发,加锁
|
||||
func (item *Item) AccessTime() time.Time {
|
||||
item.RLock()
|
||||
defer item.RUnlock()
|
||||
return item.accessTime
|
||||
}
|
||||
|
||||
//返回创建时间
|
||||
func (item *Item) CreateTime() time.Time {
|
||||
return item.createTime
|
||||
}
|
||||
|
||||
//返回访问时间。可能并发,加锁
|
||||
func (item *Item) Count() int64 {
|
||||
item.RLock()
|
||||
defer item.RUnlock()
|
||||
return item.count
|
||||
}
|
||||
|
||||
//返回key值
|
||||
func (item *Item) Key() interface{} {
|
||||
return item.key
|
||||
}
|
||||
|
||||
//返回数据
|
||||
func (item *Item) Data() interface{} {
|
||||
return item.data
|
||||
}
|
||||
|
||||
//设置回调函数
|
||||
func (item *Item) SetDeleteCallback(f func(interface{})) {
|
||||
item.Lock()
|
||||
defer item.Unlock()
|
||||
item.deleteCallback = f
|
||||
}
|
||||
|
||||
// 统一管理缓存项的表
|
||||
// table for managing cache items
|
||||
type Table struct {
|
||||
sync.RWMutex
|
||||
|
||||
//所有缓存项
|
||||
//all cache items
|
||||
items map[interface{}]*Item
|
||||
// 触发缓存清理的定时器
|
||||
// trigger cleanup
|
||||
cleanupTimer *time.Timer
|
||||
// 缓存清理周期
|
||||
// cleanup interval
|
||||
cleanupInterval time.Duration
|
||||
// 获取一个不存在的缓存项时的回调函数
|
||||
loadData func(key interface{}, args ...interface{}) *Item
|
||||
// 向缓存表增加缓存项时的回调函数
|
||||
loadData func(key interface{}, args ...interface{}) *Item
|
||||
// callback after adding.
|
||||
addedCallback func(item *Item)
|
||||
// 从缓存表删除一个缓存项时的回调函数
|
||||
// callback after deleting
|
||||
deleteCallback func(item *Item)
|
||||
}
|
||||
|
||||
// 返回缓存中存储有多少项
|
||||
func (table *Table) Count() int {
|
||||
table.RLock()
|
||||
defer table.RUnlock()
|
||||
return len(table.items)
|
||||
}
|
||||
|
||||
// 遍历所有项
|
||||
func (table *Table) Foreach(trans func(key interface{}, item *Item)) {
|
||||
table.RLock()
|
||||
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) {
|
||||
table.Lock()
|
||||
defer table.Unlock()
|
||||
table.loadData = f
|
||||
}
|
||||
|
||||
// 添加时的回调函数
|
||||
func (table *Table) SetAddedCallback(f func(*Item)) {
|
||||
table.Lock()
|
||||
defer table.Unlock()
|
||||
table.addedCallback = f
|
||||
}
|
||||
|
||||
// 删除时的回调函数
|
||||
func (table *Table) SetDeleteCallback(f func(*Item)) {
|
||||
table.Lock()
|
||||
defer table.Unlock()
|
||||
table.deleteCallback = f
|
||||
}
|
||||
|
||||
//带有panic恢复的方法
|
||||
func (table *Table) RunWithRecovery(f func()) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
//core.LOGGER.Error("异步任务错误: %v", err)
|
||||
fmt.Printf("occur error %v \r\n", err)
|
||||
}
|
||||
}()
|
||||
|
||||
//执行函数
|
||||
f()
|
||||
}
|
||||
|
||||
//终结检查,被自调整的时间触发
|
||||
func (table *Table) checkExpire() {
|
||||
table.Lock()
|
||||
if table.cleanupTimer != nil {
|
||||
@ -171,39 +153,39 @@ func (table *Table) checkExpire() {
|
||||
table.log("Expiration check installed for table")
|
||||
}
|
||||
|
||||
// 为了不抢占锁,采用临时的items.
|
||||
// in order to not take the lock. use temp items.
|
||||
items := table.items
|
||||
table.Unlock()
|
||||
|
||||
//为了定时器更准确,我们需要在每一个循环中更新‘now’,不确定是否是有效率的。
|
||||
//in order to make timer more precise, update now every loop.
|
||||
now := time.Now()
|
||||
smallestDuration := 0 * time.Second
|
||||
for key, item := range items {
|
||||
// 取出我们需要的东西,为了不抢占锁
|
||||
//take out our things, in order not to take the lock.
|
||||
item.RLock()
|
||||
duration := item.duration
|
||||
accessTime := item.accessTime
|
||||
item.RUnlock()
|
||||
|
||||
// 0永久有效
|
||||
// 0 means valid.
|
||||
if duration == 0 {
|
||||
continue
|
||||
}
|
||||
if now.Sub(accessTime) >= duration {
|
||||
//缓存项已经过期
|
||||
//cache item expired.
|
||||
_, e := table.Delete(key)
|
||||
if e != nil {
|
||||
table.log("删除缓存项时出错 %v", e.Error())
|
||||
table.log("occur error while deleting %v", e.Error())
|
||||
}
|
||||
} else {
|
||||
//查找最靠近结束生命周期的项目
|
||||
//find the most possible expire item.
|
||||
if smallestDuration == 0 || duration-now.Sub(accessTime) < smallestDuration {
|
||||
smallestDuration = duration - now.Sub(accessTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 为下次清理设置间隔,自触发机制
|
||||
//trigger next clean
|
||||
table.Lock()
|
||||
table.cleanupInterval = smallestDuration
|
||||
if smallestDuration > 0 {
|
||||
@ -214,26 +196,23 @@ func (table *Table) checkExpire() {
|
||||
table.Unlock()
|
||||
}
|
||||
|
||||
// 添加缓存项
|
||||
// add item
|
||||
func (table *Table) Add(key interface{}, duration time.Duration, data interface{}) *Item {
|
||||
item := NewItem(key, duration, data)
|
||||
|
||||
// 将缓存项放入表中
|
||||
table.Lock()
|
||||
table.log("Adding item with key %v and lifespan of %v to table", key, duration)
|
||||
table.items[key] = item
|
||||
|
||||
// 取出需要的东西,释放锁
|
||||
expDur := table.cleanupInterval
|
||||
addedItem := table.addedCallback
|
||||
table.Unlock()
|
||||
|
||||
// 有回调函数便执行回调
|
||||
if addedItem != nil {
|
||||
addedItem(item)
|
||||
}
|
||||
|
||||
// 如果我们没有设置任何心跳检查定时器或者找一个即将迫近的项目
|
||||
//find the most possible expire item.
|
||||
if duration > 0 && (expDur == 0 || duration < expDur) {
|
||||
table.checkExpire()
|
||||
}
|
||||
@ -241,20 +220,17 @@ func (table *Table) Add(key interface{}, duration time.Duration, data interface{
|
||||
return item
|
||||
}
|
||||
|
||||
// 从缓存中删除项
|
||||
func (table *Table) Delete(key interface{}) (*Item, error) {
|
||||
table.RLock()
|
||||
r, ok := table.items[key]
|
||||
if !ok {
|
||||
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
|
||||
table.RUnlock()
|
||||
|
||||
// 调用删除回调函数
|
||||
if deleteCallback != nil {
|
||||
deleteCallback(r)
|
||||
}
|
||||
@ -273,7 +249,7 @@ func (table *Table) Delete(key interface{}) (*Item, error) {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
//单纯的检查某个键是否存在
|
||||
//check exist.
|
||||
func (table *Table) Exists(key interface{}) bool {
|
||||
table.RLock()
|
||||
defer table.RUnlock()
|
||||
@ -282,7 +258,7 @@ func (table *Table) Exists(key interface{}) bool {
|
||||
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 {
|
||||
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.items[key] = item
|
||||
|
||||
// 取出需要的内容,释放锁
|
||||
expDur := table.cleanupInterval
|
||||
addedItem := table.addedCallback
|
||||
table.Unlock()
|
||||
|
||||
// 添加回调函数
|
||||
if addedItem != nil {
|
||||
addedItem(item)
|
||||
}
|
||||
|
||||
// 触发过期检查
|
||||
if lifeSpan > 0 && (expDur == 0 || lifeSpan < expDur) {
|
||||
table.checkExpire()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
//从缓存中返回一个被标记的并保持活性的值。你可以传附件的参数到DataLoader回调函数
|
||||
func (table *Table) Value(key interface{}, args ...interface{}) (*Item, error) {
|
||||
table.RLock()
|
||||
r, ok := table.items[key]
|
||||
@ -320,12 +292,11 @@ func (table *Table) Value(key interface{}, args ...interface{}) (*Item, error) {
|
||||
table.RUnlock()
|
||||
|
||||
if ok {
|
||||
// 更新访问次数和访问时间
|
||||
//update visit count and visit time.
|
||||
r.KeepAlive()
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// 有加载数据的方式,就通过loadData函数去加载进来
|
||||
if loadData != nil {
|
||||
item := loadData(key, args...)
|
||||
if item != nil {
|
||||
@ -333,14 +304,13 @@ func (table *Table) Value(key interface{}, args ...interface{}) (*Item, error) {
|
||||
return item, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("无法加载到缓存值")
|
||||
return nil, errors.New("cannot load item")
|
||||
}
|
||||
|
||||
//没有找到任何东西,返回nil.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 删除缓存表中的所有项目
|
||||
// truncate a table.
|
||||
func (table *Table) Truncate() {
|
||||
table.Lock()
|
||||
defer table.Unlock()
|
||||
@ -354,7 +324,7 @@ func (table *Table) Truncate() {
|
||||
}
|
||||
}
|
||||
|
||||
//辅助table中排序,统计的
|
||||
//support table sort
|
||||
type ItemPair struct {
|
||||
Key interface{}
|
||||
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) Less(i, j int) bool { return p[i].AccessCount > p[j].AccessCount }
|
||||
|
||||
// 返回缓存表中被访问最多的项目
|
||||
//return most visited.
|
||||
func (table *Table) MostAccessed(count int64) []*Item {
|
||||
table.RLock()
|
||||
defer table.RUnlock()
|
||||
@ -396,12 +366,11 @@ func (table *Table) MostAccessed(count int64) []*Item {
|
||||
return r
|
||||
}
|
||||
|
||||
// 打印日志
|
||||
// print log.
|
||||
func (table *Table) log(format string, v ...interface{}) {
|
||||
//core.LOGGER.Info(format, v...)
|
||||
fmt.Printf(format, v)
|
||||
}
|
||||
|
||||
//新建一个缓存Table
|
||||
func NewTable() *Table {
|
||||
return &Table{
|
||||
items: make(map[interface{}]*Item),
|
||||
|
@ -60,7 +60,7 @@ func CheckLastModified(w http.ResponseWriter, r *http.Request, modifyTime time.T
|
||||
return false
|
||||
}
|
||||
|
||||
// 处理ETag标签
|
||||
// handle ETag
|
||||
// CheckETag implements If-None-Match and If-Range checks.
|
||||
//
|
||||
// The ETag or modtime must have been previously set in the
|
||||
@ -211,8 +211,7 @@ func PanicError(err error) {
|
||||
}
|
||||
}
|
||||
|
||||
//文件下载。具有进度功能。
|
||||
//下载功能参考:https://github.com/Masterminds/go-fileserver
|
||||
//file download. https://github.com/Masterminds/go-fileserver
|
||||
func DownloadFile(
|
||||
writer http.ResponseWriter,
|
||||
request *http.Request,
|
||||
@ -228,16 +227,15 @@ func DownloadFile(
|
||||
PanicError(e)
|
||||
}()
|
||||
|
||||
//根据参数添加content-disposition。该Header会让浏览器自动下载,而不是预览。
|
||||
//content-disposition tell browser to download rather than preview.
|
||||
if withContentDisposition {
|
||||
fileName := url.QueryEscape(filename)
|
||||
writer.Header().Set("content-disposition", "attachment; filename=\""+fileName+"\"")
|
||||
}
|
||||
|
||||
//显示文件大小。
|
||||
fileInfo, err := diskFile.Stat()
|
||||
if err != nil {
|
||||
panic("无法从磁盘中获取文件信息")
|
||||
panic("cannot load fileInfo from disk." + filePath)
|
||||
}
|
||||
|
||||
modifyTime := fileInfo.ModTime()
|
||||
@ -261,7 +259,7 @@ func DownloadFile(
|
||||
ctypes, haveType := writer.Header()["Content-Type"]
|
||||
var ctype string
|
||||
if !haveType {
|
||||
//使用mimeUtil来获取mime
|
||||
//get mime
|
||||
ctype = util.GetFallbackMimeType(filename, "")
|
||||
if ctype == "" {
|
||||
// read a chunk to decide between utf-8 text and binary
|
||||
@ -270,7 +268,7 @@ func DownloadFile(
|
||||
ctype = http.DetectContentType(buf[:n])
|
||||
_, err := diskFile.Seek(0, os.SEEK_SET) // rewind to output whole file
|
||||
if err != nil {
|
||||
panic("无法准确定位文件")
|
||||
panic("cannot seek file")
|
||||
}
|
||||
}
|
||||
writer.Header().Set("Content-Type", ctype)
|
||||
|
@ -26,7 +26,7 @@ var (
|
||||
UsernameExist = &Item{English: `username "%s" exists`, Chinese: `用户名"%s"已存在`}
|
||||
UsernameNotExist = &Item{English: `username "%s" not exists`, 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: `管理员已禁用自主注册`}
|
||||
UserPasswordLengthError = &Item{English: `password at least 6 chars`, Chinese: `密码长度至少为6位`}
|
||||
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 `}
|
||||
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 `}
|
||||
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: `名称中不能包含以下特殊符号:\ / : * ? " < > |`}
|
||||
MatterMoveRecursive = &Item{English: `directory cannot be moved to itself or its children`, Chinese: `文件夹不能把自己移入到自己中,也不可以移入到自己的子文件夹下。`}
|
||||
MatterNameNoChange = &Item{English: `filename not change, invalid operation`, Chinese: `文件名没有改变,操作无效!`}
|
||||
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 {
|
||||
|
@ -37,7 +37,6 @@ var (
|
||||
UNKNOWN = &CodeWrapper{Code: "UNKNOWN", HttpStatus: http.StatusInternalServerError, Description: "server unknow error"}
|
||||
)
|
||||
|
||||
//根据 CodeWrapper来获取对应的HttpStatus
|
||||
func FetchHttpStatus(code string) int {
|
||||
if code == OK.Code {
|
||||
return OK.HttpStatus
|
||||
@ -75,6 +74,12 @@ func ConstWebResult(codeWrapper *CodeWrapper) *WebResult {
|
||||
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 {
|
||||
|
||||
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...))
|
||||
}
|
||||
|
||||
//没有权限
|
||||
func BadRequest(format string, v ...interface{}) *WebResult {
|
||||
return CustomWebResult(BAD_REQUEST, fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
//没有权限
|
||||
func Unauthorized(format string, v ...interface{}) *WebResult {
|
||||
return CustomWebResult(UNAUTHORIZED, fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
//没有找到
|
||||
func NotFound(format string, v ...interface{}) *WebResult {
|
||||
return CustomWebResult(NOT_FOUND, fmt.Sprintf(format, v...))
|
||||
|
||||
}
|
||||
|
||||
//服务器内部出问题
|
||||
//sever inner error
|
||||
func Server(format string, v ...interface{}) *WebResult {
|
||||
return CustomWebResult(SERVER, fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
//所有的数据库错误情况
|
||||
//db error.
|
||||
var (
|
||||
DB_ERROR_DUPLICATE_KEY = "Error 1062: Duplicate entry"
|
||||
DB_ERROR_NOT_FOUND = "record not found"
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
//给密码字符串加密
|
||||
//md5
|
||||
func GetMd5(raw string) string {
|
||||
return fmt.Sprintf("%x", md5.Sum([]byte(raw)))
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
//是否为win开发环境
|
||||
//whether windows develop environment
|
||||
func EnvWinDevelopment() bool {
|
||||
|
||||
ex, err := os.Executable()
|
||||
@ -14,7 +14,7 @@ func EnvWinDevelopment() bool {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
//如果exPath中包含了 \\AppData\\Local\\Temp 我们认为是在Win的开发环境中
|
||||
//if exPath contains \\AppData\\Local\\Temp we regard as dev.
|
||||
systemUser, err := user.Current()
|
||||
if systemUser != nil {
|
||||
|
||||
@ -26,7 +26,7 @@ func EnvWinDevelopment() bool {
|
||||
|
||||
}
|
||||
|
||||
//是否为mac开发环境
|
||||
//whether mac develop environment
|
||||
func EnvMacDevelopment() bool {
|
||||
|
||||
ex, err := os.Executable()
|
||||
@ -38,7 +38,7 @@ func EnvMacDevelopment() bool {
|
||||
|
||||
}
|
||||
|
||||
//是否为开发环境 (即是否在IDE中运行)
|
||||
//whether develop environment (whether run in IDE)
|
||||
func EnvDevelopment() bool {
|
||||
|
||||
return EnvWinDevelopment() || EnvMacDevelopment()
|
||||
|
@ -7,12 +7,12 @@ import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//判断文件或文件夹是否已经存在
|
||||
func PathExists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
@ -26,14 +26,13 @@ func PathExists(path string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
//获取GOPATH路径
|
||||
func GetGoPath() string {
|
||||
|
||||
return build.Default.GOPATH
|
||||
|
||||
}
|
||||
|
||||
//获取开发时的Home目录
|
||||
//get development home path.
|
||||
func GetDevHomePath() string {
|
||||
|
||||
_, file, _, ok := runtime.Caller(0)
|
||||
@ -50,8 +49,7 @@ func GetDevHomePath() string {
|
||||
return dir
|
||||
}
|
||||
|
||||
//获取该应用可执行文件的位置。
|
||||
//例如:C:\Users\lishuang\AppData\Local\Temp
|
||||
//get home path for application.
|
||||
func GetHomePath() string {
|
||||
ex, err := os.Executable()
|
||||
if err != nil {
|
||||
@ -70,8 +68,9 @@ func GetHomePath() string {
|
||||
return UniformPath(exPath)
|
||||
}
|
||||
|
||||
//获取前端静态资源的位置。如果你在开发模式下,可以将这里直接返回tank/build下面的html路径。
|
||||
//例如:C:/Users/lishuang/AppData/Local/Temp/html
|
||||
//get html path
|
||||
//dev: return $project/build/html
|
||||
//prod: return $application/html
|
||||
func GetHtmlPath() string {
|
||||
|
||||
//开发环境直接使用 build/html 下面的文件
|
||||
@ -81,27 +80,27 @@ func GetHtmlPath() string {
|
||||
return GetHomePath() + "/html"
|
||||
}
|
||||
|
||||
//如果文件夹存在就不管,不存在就创建。 例如:/var/www/matter
|
||||
//if directory not exit, create it.
|
||||
func MakeDirAll(dirPath string) string {
|
||||
|
||||
exists := PathExists(dirPath)
|
||||
|
||||
if !exists {
|
||||
//TODO:文件权限需要进一步考虑
|
||||
|
||||
err := os.MkdirAll(dirPath, 0777)
|
||||
if err != nil {
|
||||
panic("创建文件夹时出错!")
|
||||
panic("error while creating directory")
|
||||
}
|
||||
}
|
||||
|
||||
return dirPath
|
||||
}
|
||||
|
||||
//获取到一个Path的文件夹路径,eg /var/www/xx.log -> /var/www
|
||||
//eg /var/www/xx.log -> /var/www
|
||||
func GetDirOfPath(fullPath string) string {
|
||||
|
||||
index1 := strings.LastIndex(fullPath, "/")
|
||||
//可能是windows的环境
|
||||
//maybe windows environment
|
||||
index2 := strings.LastIndex(fullPath, "\\")
|
||||
index := index1
|
||||
if index2 > index1 {
|
||||
@ -111,11 +110,11 @@ func GetDirOfPath(fullPath string) string {
|
||||
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 {
|
||||
|
||||
index1 := strings.LastIndex(fullPath, "/")
|
||||
//可能是windows的环境
|
||||
//maybe windows env
|
||||
index2 := strings.LastIndex(fullPath, "\\")
|
||||
index := index1
|
||||
if index2 > index1 {
|
||||
@ -125,17 +124,17 @@ func GetFilenameOfPath(fullPath string) string {
|
||||
return fullPath[index+1:]
|
||||
}
|
||||
|
||||
//尝试删除空文件夹 true表示删掉了一个空文件夹,false表示没有删掉任何东西
|
||||
//try to delete empty dir. true: delete an empty dir, false: delete nothing.
|
||||
func DeleteEmptyDir(dirPath string) bool {
|
||||
dir, err := ioutil.ReadDir(dirPath)
|
||||
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 {
|
||||
//空文件夹
|
||||
//empty dir
|
||||
err = os.Remove(dirPath)
|
||||
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
|
||||
}
|
||||
@ -143,39 +142,23 @@ func DeleteEmptyDir(dirPath string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
//递归尝试删除空文件夹,一直空就一直删,直到不空为止
|
||||
//delete empty dir recursive, delete until not empty.
|
||||
func DeleteEmptyDirRecursive(dirPath string) {
|
||||
|
||||
fmt.Printf("递归删除删 %v \n", dirPath)
|
||||
fmt.Printf("recursive delete %v \n", dirPath)
|
||||
|
||||
tmpPath := dirPath
|
||||
for DeleteEmptyDir(tmpPath) {
|
||||
|
||||
dir := GetDirOfPath(tmpPath)
|
||||
|
||||
fmt.Printf("尝试删除 %v\n", dir)
|
||||
fmt.Printf("try to delete %v\n", dir)
|
||||
|
||||
tmpPath = dir
|
||||
}
|
||||
}
|
||||
|
||||
//移除某个文件夹。
|
||||
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
|
||||
//get conf path.
|
||||
func GetConfPath() string {
|
||||
|
||||
homePath := GetHomePath()
|
||||
@ -185,15 +168,14 @@ func GetConfPath() string {
|
||||
if !exists {
|
||||
err := os.MkdirAll(filePath, 0777)
|
||||
if err != nil {
|
||||
panic("创建日志文件夹时出错!")
|
||||
panic("error while mkdir " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return filePath
|
||||
}
|
||||
|
||||
//获取日志的路径
|
||||
//例如:默认存放于 home/log
|
||||
//get log path.
|
||||
func GetLogPath() string {
|
||||
|
||||
homePath := GetHomePath()
|
||||
@ -203,14 +185,14 @@ func GetLogPath() string {
|
||||
if !exists {
|
||||
err := os.MkdirAll(filePath, 0777)
|
||||
if err != nil {
|
||||
panic("创建日志文件夹时出错!")
|
||||
panic("error while mkdir " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return filePath
|
||||
}
|
||||
|
||||
//复制文件
|
||||
//copy file
|
||||
func CopyFile(srcPath string, destPath string) (nBytes int64) {
|
||||
|
||||
srcFileStat, err := os.Stat(srcPath)
|
||||
@ -248,9 +230,12 @@ func CopyFile(srcPath string, destPath string) (nBytes int64) {
|
||||
return nBytes
|
||||
}
|
||||
|
||||
//路径归一化处理,把\\替换成/
|
||||
func UniformPath(path string) string {
|
||||
|
||||
return strings.Replace(path, "\\", "/", -1)
|
||||
|
||||
//1. replace \\ to /
|
||||
//2. clean path.
|
||||
//3. trim suffix /
|
||||
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",
|
||||
".zip": "application/zip"}
|
||||
|
||||
//根据文件名字获取后缀名,均是小写。
|
||||
//get extension by name. lowercase.
|
||||
func GetExtension(filename string) string {
|
||||
|
||||
var extension = filepath.Ext(filename)
|
||||
@ -627,7 +627,7 @@ func GetExtension(filename string) string {
|
||||
|
||||
}
|
||||
|
||||
//根据文件名字获取去除后缀的名称
|
||||
//get filename without extension
|
||||
func GetSimpleFileName(filename string) string {
|
||||
|
||||
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 {
|
||||
|
||||
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 {
|
||||
|
||||
extension := GetExtension(filename)
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
//根据一个请求,获取ip.
|
||||
//get ip from request
|
||||
func GetIpAddress(r *http.Request) string {
|
||||
var ipAddress string
|
||||
|
||||
@ -25,21 +25,21 @@ func GetIpAddress(r *http.Request) string {
|
||||
return ipAddress
|
||||
}
|
||||
|
||||
//根据一个请求,获取host
|
||||
func GetHostFromRequest(r *http.Request) string {
|
||||
//get host from request
|
||||
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 {
|
||||
|
||||
//验证用户是否已经登录。
|
||||
//get from cookie
|
||||
sessionCookie, err := request.Cookie(cookieAuthKey)
|
||||
var sessionId string
|
||||
if err != nil {
|
||||
//从入参中捞取
|
||||
//try to get from Form
|
||||
sessionId = request.FormValue(cookieAuthKey)
|
||||
} else {
|
||||
sessionId = sessionCookie.Value
|
||||
@ -49,7 +49,7 @@ func GetSessionUuidFromRequest(request *http.Request, cookieAuthKey string) stri
|
||||
|
||||
}
|
||||
|
||||
//允许跨域请求
|
||||
//allow cors.
|
||||
func AllowCORS(writer http.ResponseWriter) {
|
||||
writer.Header().Add("Access-Control-Allow-Origin", "*")
|
||||
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")
|
||||
}
|
||||
|
||||
//禁用缓存
|
||||
//disable cache.
|
||||
func DisableCache(writer http.ResponseWriter) {
|
||||
//对于IE浏览器,会自动缓存,因此设置不缓存Header.
|
||||
//IE browser will cache automatically. disable the cache.
|
||||
writer.Header().Set("Pragma", "No-cache")
|
||||
writer.Header().Set("Cache-Control", "no-cache")
|
||||
writer.Header().Set("Expires", "0")
|
||||
|
@ -7,7 +7,6 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
//把一个大小转变成方便读的格式
|
||||
//human readable file size
|
||||
func HumanFileSize(bytes int64) string {
|
||||
var thresh int64 = 1024
|
||||
@ -33,7 +32,7 @@ func HumanFileSize(bytes int64) string {
|
||||
return fmt.Sprintf("%s%s", numStr, units[u])
|
||||
}
|
||||
|
||||
//获取MySQL的URL
|
||||
//get mysql url.
|
||||
func GetMysqlUrl(
|
||||
mysqlPort int,
|
||||
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)
|
||||
}
|
||||
|
||||
//获取四位随机数字
|
||||
//get random number 4.
|
||||
func RandomNumber4() string {
|
||||
return fmt.Sprintf("%04v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31()%10000)
|
||||
}
|
||||
|
||||
//获取四位随机数字
|
||||
//get random 4 string
|
||||
func RandomString4() string {
|
||||
|
||||
//0和o,l和1难以区分,剔除掉
|
||||
//0 and o, 1 and l are not easy to distinguish
|
||||
var letterRunes = []rune("abcdefghijkmnpqrstuvwxyz23456789")
|
||||
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
@ -5,57 +5,54 @@ import (
|
||||
"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 {
|
||||
local, _ := time.LoadLocation("Local")
|
||||
t, err := time.ParseInLocation("2006-01-02 15:04:05", timeString, local)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("不能将%s转为时间类型", timeString))
|
||||
panic(fmt.Sprintf("cannot convert %s to Time", timeString))
|
||||
}
|
||||
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 {
|
||||
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 {
|
||||
return time.Local().Format("15:04:05")
|
||||
}
|
||||
|
||||
//将一个时间字符串转换成日期对象(yyyy-MM-dd)
|
||||
//convert Time object to string(yyyy-MM-dd)
|
||||
func ConvertTimeToDateString(time time.Time) string {
|
||||
return time.Local().Format("2006-01-02")
|
||||
}
|
||||
|
||||
//一天中的最后一秒钟
|
||||
func LastSecondOfDay(day time.Time) time.Time {
|
||||
local, _ := time.LoadLocation("Local")
|
||||
return time.Date(day.Year(), day.Month(), day.Day(), 23, 59, 59, 0, local)
|
||||
}
|
||||
|
||||
//一天中的第一秒钟
|
||||
func FirstSecondOfDay(day time.Time) time.Time {
|
||||
local, _ := time.LoadLocation("Local")
|
||||
return time.Date(day.Year(), day.Month(), day.Day(), 0, 0, 0, 0, local)
|
||||
}
|
||||
|
||||
//一天中的第一分钟
|
||||
func FirstMinuteOfDay(day time.Time) time.Time {
|
||||
local, _ := time.LoadLocation("Local")
|
||||
return time.Date(day.Year(), day.Month(), day.Day(), 0, 1, 0, 0, local)
|
||||
}
|
||||
|
||||
//明天此刻的时间
|
||||
//Tomorrow right now
|
||||
func Tomorrow() time.Time {
|
||||
tomorrow := time.Now()
|
||||
tomorrow = tomorrow.AddDate(0, 0, 1)
|
||||
return tomorrow
|
||||
}
|
||||
|
||||
//昨天此刻的时间
|
||||
//Yesterday right now
|
||||
func Yesterday() time.Time {
|
||||
tomorrow := time.Now()
|
||||
tomorrow = tomorrow.AddDate(0, 0, -1)
|
||||
|
@ -4,23 +4,20 @@ import (
|
||||
"archive/zip"
|
||||
"github.com/eyebluecn/tank/code/tool/result"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//将srcPath压缩到destPath。
|
||||
//zip srcPath to destPath。
|
||||
func Zip(srcPath string, destPath string) error {
|
||||
|
||||
//统一处理\\成/
|
||||
srcPath = UniformPath(srcPath)
|
||||
|
||||
if PathExists(destPath) {
|
||||
panic(result.BadRequest("%s 已经存在了", destPath))
|
||||
panic(result.BadRequest("%s exits", destPath))
|
||||
}
|
||||
|
||||
// 创建准备写入的文件
|
||||
fileWriter, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -32,53 +29,44 @@ func Zip(srcPath string, destPath string) error {
|
||||
}
|
||||
}()
|
||||
|
||||
// 通过 fileWriter 来创建 zip.Write
|
||||
zipWriter := zip.NewWriter(fileWriter)
|
||||
defer func() {
|
||||
// 检测一下是否成功关闭
|
||||
|
||||
if err := zipWriter.Close(); err != nil {
|
||||
log.Fatalln(err)
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
//上一个文件夹路径
|
||||
baseDirPath := GetDirOfPath(srcPath) + "/"
|
||||
// 下面来将文件写入 zipWriter ,因为有可能会有很多个目录及文件,所以递归处理
|
||||
err = filepath.Walk(srcPath, func(path string, fileInfo os.FileInfo, errBack error) (err error) {
|
||||
if errBack != nil {
|
||||
return errBack
|
||||
}
|
||||
|
||||
//统一处理\\成/
|
||||
path = UniformPath(path)
|
||||
|
||||
// 通过文件信息,创建 zip 的文件信息
|
||||
fileHeader, err := zip.FileInfoHeader(fileInfo)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 替换文件信息中的文件名
|
||||
fileHeader.Name = strings.TrimPrefix(path, baseDirPath)
|
||||
|
||||
// 目录前要加上/
|
||||
// directory need /
|
||||
if fileInfo.IsDir() {
|
||||
fileHeader.Name += "/"
|
||||
}
|
||||
|
||||
// 写入文件信息,并返回一个 Write 结构
|
||||
writer, err := zipWriter.CreateHeader(fileHeader)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 检测,如果不是标准文件就只写入头信息,不写入文件数据到 writer
|
||||
// 如目录,也没有数据需要写
|
||||
//only regular has things to write.
|
||||
if !fileHeader.Mode().IsRegular() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 打开要压缩的文件
|
||||
fileToBeZip, err := os.Open(path)
|
||||
defer func() {
|
||||
err = fileToBeZip.Close()
|
||||
@ -90,7 +78,6 @@ func Zip(srcPath string, destPath string) error {
|
||||
return
|
||||
}
|
||||
|
||||
// 将打开的文件 Copy 到 writer
|
||||
_, err = io.Copy(writer, fileToBeZip)
|
||||
if err != nil {
|
||||
return
|
||||
|
Reference in New Issue
Block a user