go-fastdfs/fileserver.go

1332 lines
27 KiB
Go
Raw Normal View History

2017-09-09 16:40:55 +08:00
package main
import (
2018-05-10 13:31:34 +08:00
"crypto/md5"
"crypto/rand"
"encoding/base64"
2018-12-30 17:17:40 +08:00
"encoding/json"
"errors"
2018-05-10 18:19:04 +08:00
"flag"
2017-09-09 16:40:55 +08:00
"fmt"
"io"
2018-12-30 17:17:40 +08:00
"io/ioutil"
"mime/multipart"
"net"
2018-05-10 13:31:34 +08:00
"net/http"
2019-01-02 20:37:50 +08:00
"net/url"
2019-01-01 23:31:14 +08:00
"path"
2018-12-31 17:46:24 +08:00
"path/filepath"
2018-12-30 17:17:40 +08:00
"reflect"
2018-12-30 18:18:42 +08:00
"runtime/debug"
2019-01-02 17:46:30 +08:00
"strconv"
// "strconv"
"sync"
2018-12-30 17:17:40 +08:00
2017-09-09 16:40:55 +08:00
"os"
2018-12-30 17:17:40 +08:00
"regexp"
2018-05-10 13:31:34 +08:00
"strings"
2018-12-30 17:17:40 +08:00
"sync/atomic"
2018-05-10 13:31:34 +08:00
"time"
2018-12-30 17:17:40 +08:00
"unsafe"
"github.com/astaxie/beego/httplib"
"github.com/syndtr/goleveldb/leveldb"
2018-05-10 13:31:34 +08:00
log "github.com/sjqzhang/seelog"
)
2018-05-10 18:19:04 +08:00
var staticHandler http.Handler
var util = &Common{}
var server = &Server{}
2019-01-02 17:46:30 +08:00
var statMap = &CommonMap{m: make(map[string]interface{})}
2018-12-30 17:17:40 +08:00
2018-12-30 18:18:42 +08:00
var logacc log.LoggerInterface
2019-01-01 14:41:57 +08:00
var FOLDERS = []string{DATA_DIR, STORE_DIR, CONF_DIR}
2018-12-30 17:17:40 +08:00
var (
FileName string
ptr unsafe.Pointer
)
2018-05-10 13:31:34 +08:00
const (
2018-05-10 18:19:04 +08:00
STORE_DIR = "files"
2018-12-30 17:17:40 +08:00
CONF_DIR = "conf"
DATA_DIR = "data"
CONST_LEVELDB_FILE_NAME = DATA_DIR + "/fileserver.db"
2019-01-02 17:46:30 +08:00
CONST_STAT_FILE_NAME = DATA_DIR + "/stat.json"
2019-01-01 14:41:57 +08:00
CONST_CONF_FILE_NAME = CONF_DIR + "/cfg.json"
2019-01-02 17:46:30 +08:00
CONST_STAT_FILE_COUNT_KEY = "fileCount"
CONST_STAT_FILE_TOTAL_SIZE_KEY = "totalSize"
2019-01-03 10:08:01 +08:00
CONST_Md5_ERROR_FILE_NAME = "errors.md5"
CONST_FILE_Md5_FILE_NAME = "files.md5"
2018-12-30 17:17:40 +08:00
cfgJson = `
2019-01-01 14:41:57 +08:00
{
2019-01-03 10:14:42 +08:00
"绑定端号":"端口",
2019-01-01 14:41:57 +08:00
"addr": ":8080",
2019-01-03 10:14:42 +08:00
"集群":"集群列表",
2019-01-01 14:41:57 +08:00
"peers":["%s"],
2019-01-03 10:14:42 +08:00
"组号":"组号",
2019-01-01 23:31:14 +08:00
"group":"group1",
2019-01-02 17:51:08 +08:00
"refresh_interval":120,
2019-01-03 10:14:42 +08:00
"是否自动重命名":"真假",
2019-01-02 00:03:48 +08:00
"rename_file":false,
2019-01-03 10:14:42 +08:00
"是否支持WEB上专":"真假",
2019-01-03 10:08:01 +08:00
"enable_web_upload":true,
2019-01-03 11:20:11 +08:00
"下载域名":"",
 "download_domain ":"",
2019-01-03 10:14:42 +08:00
"是否显示目录":"真假",
2019-01-01 23:31:14 +08:00
"show_dir":true
2019-01-01 14:41:57 +08:00
}
2018-12-30 17:17:40 +08:00
`
2018-05-10 13:31:34 +08:00
logConfigStr = `
<seelog type="asynctimer" asyncinterval="1000" minlevel="trace" maxlevel="error">
<outputs formatid="common">
<buffered formatid="common" size="1048576" flushperiod="1000">
<rollingfile type="size" filename="./log/fileserver.log" maxsize="104857600" maxrolls="10"/>
</buffered>
</outputs>
<formats>
<format id="common" format="%Date %Time [%LEV] [%File:%Line] [%Func] %Msg%n" />
</formats>
</seelog>
2018-12-30 18:18:42 +08:00
`
logAccessConfigStr = `
<seelog type="asynctimer" asyncinterval="1000" minlevel="trace" maxlevel="error">
<outputs formatid="common">
<buffered formatid="common" size="1048576" flushperiod="1000">
<rollingfile type="size" filename="./log/access.log" maxsize="104857600" maxrolls="10"/>
</buffered>
</outputs>
<formats>
<format id="common" format="%Date %Time [%LEV] [%File:%Line] [%Func] %Msg%n" />
</formats>
</seelog>
2018-05-10 13:31:34 +08:00
`
2017-09-09 16:40:55 +08:00
)
2018-05-10 13:31:34 +08:00
type Common struct {
}
2018-05-10 18:19:04 +08:00
type Server struct {
2018-12-30 17:17:40 +08:00
db *leveldb.DB
util *Common
}
type FileInfo struct {
2019-01-01 23:31:14 +08:00
Name string
ReName string
Path string
Md5 string
2019-01-02 17:46:30 +08:00
Size int64
2019-01-01 23:31:14 +08:00
Peers []string
2018-12-30 17:17:40 +08:00
}
type GloablConfig struct {
2019-01-02 17:51:08 +08:00
Addr string `json:"addr"`
Peers []string `json:"peers"`
Group string `json:"group"`
RenameFile bool `json:"rename_file"`
ShowDir bool `json:"show_dir"`
RefreshInterval int `json:"refresh_interval"`
2019-01-03 10:08:01 +08:00
EnableWebUpload bool `json:"enable_web_upload"`
2019-01-03 11:20:11 +08:00
DownloadDomain string `json:"download_domain"`
2019-01-01 14:41:57 +08:00
}
2019-01-02 17:46:30 +08:00
type CommonMap struct {
sync.Mutex
m map[string]interface{}
}
func (s *CommonMap) GetValue(k string) (interface{}, bool) {
s.Lock()
defer s.Unlock()
v, ok := s.m[k]
return v, ok
}
func (s *CommonMap) Put(k string, v interface{}) {
s.Lock()
defer s.Unlock()
s.m[k] = v
}
func (s *CommonMap) AddCount(key string, count int) {
s.Lock()
defer s.Unlock()
if _v, ok := s.m[key]; ok {
v := _v.(int)
v = v + count
s.m[key] = v
} else {
s.m[key] = 1
}
}
func (s *CommonMap) AddCountInt64(key string, count int64) {
s.Lock()
defer s.Unlock()
if _v, ok := s.m[key]; ok {
v := _v.(int64)
v = v + count
s.m[key] = v
} else {
s.m[key] = count
}
}
func (s *CommonMap) Add(key string) {
s.Lock()
defer s.Unlock()
if _v, ok := s.m[key]; ok {
v := _v.(int)
v = v + 1
s.m[key] = v
} else {
s.m[key] = 1
}
}
func (s *CommonMap) Zero() {
s.Lock()
defer s.Unlock()
for k, _ := range s.m {
s.m[k] = 0
}
}
func (s *CommonMap) Get() map[string]interface{} {
s.Lock()
defer s.Unlock()
m := make(map[string]interface{})
for k, v := range s.m {
m[k] = v
}
return m
}
2019-01-01 14:41:57 +08:00
func Config() *GloablConfig {
return (*GloablConfig)(atomic.LoadPointer(&ptr))
2018-12-30 17:17:40 +08:00
}
func ParseConfig(filePath string) {
var (
data []byte
)
if filePath == "" {
data = []byte(strings.TrimSpace(cfgJson))
} else {
file, err := os.Open(filePath)
if err != nil {
panic(fmt.Sprintln("open file path:", filePath, "error:", err))
}
defer file.Close()
FileName = filePath
data, err = ioutil.ReadAll(file)
if err != nil {
panic(fmt.Sprintln("file path:", filePath, " read all error:", err))
}
}
var c GloablConfig
if err := json.Unmarshal(data, &c); err != nil {
panic(fmt.Sprintln("file path:", filePath, "json unmarshal error:", err))
}
log.Info(c)
atomic.StorePointer(&ptr, unsafe.Pointer(&c))
log.Info("config parse success")
2018-05-10 18:19:04 +08:00
}
2018-05-10 13:31:34 +08:00
func (this *Common) GetUUID() string {
b := make([]byte, 48)
if _, err := io.ReadFull(rand.Reader, b); err != nil {
return ""
}
id := this.MD5(base64.URLEncoding.EncodeToString(b))
return fmt.Sprintf("%s-%s-%s-%s-%s", id[0:8], id[8:12], id[12:16], id[16:20], id[20:])
}
2018-12-30 17:17:40 +08:00
func (this *Common) GetPulicIP() string {
conn, _ := net.Dial("udp", "8.8.8.8:80")
defer conn.Close()
localAddr := conn.LocalAddr().String()
idx := strings.LastIndex(localAddr, ":")
return localAddr[0:idx]
}
2018-05-10 13:31:34 +08:00
func (this *Common) MD5(str string) string {
md := md5.New()
md.Write([]byte(str))
return fmt.Sprintf("%x", md.Sum(nil))
}
2018-12-30 17:17:40 +08:00
func (this *Common) GetFileMd5(file *os.File) string {
file.Seek(0, 0)
md5h := md5.New()
io.Copy(md5h, file)
sum := fmt.Sprintf("%x", md5h.Sum(nil))
return sum
}
func (this *Common) Contains(obj interface{}, arrayobj interface{}) bool {
targetValue := reflect.ValueOf(arrayobj)
switch reflect.TypeOf(arrayobj).Kind() {
case reflect.Slice, reflect.Array:
for i := 0; i < targetValue.Len(); i++ {
if targetValue.Index(i).Interface() == obj {
return true
}
}
case reflect.Map:
if targetValue.MapIndex(reflect.ValueOf(obj)).IsValid() {
return true
}
}
return false
}
2018-05-10 18:19:04 +08:00
func (this *Common) FileExists(fileName string) bool {
_, err := os.Stat(fileName)
return err == nil
}
2019-01-01 14:41:57 +08:00
func (this *Common) WriteFile(path string, data string) bool {
if err := ioutil.WriteFile(path, []byte(data), 0666); err == nil {
return true
} else {
return false
}
}
func (this *Common) WriteBinFile(path string, data []byte) bool {
if err := ioutil.WriteFile(path, data, 0666); err == nil {
return true
} else {
return false
}
}
2019-01-02 17:46:30 +08:00
func (this *Common) IsExist(filename string) bool {
_, err := os.Stat(filename)
return err == nil || os.IsExist(err)
}
func (this *Common) ReadBinFile(path string) ([]byte, error) {
if this.IsExist(path) {
fi, err := os.Open(path)
if err != nil {
return nil, err
}
defer fi.Close()
return ioutil.ReadAll(fi)
} else {
return nil, errors.New("not found")
}
}
2018-12-31 17:46:24 +08:00
func (this *Common) RemoveEmptyDir(pathname string) {
2019-01-02 17:46:30 +08:00
defer func() {
if re := recover(); re != nil {
buffer := debug.Stack()
log.Error("postFileToPeer")
log.Error(re)
log.Error(string(buffer))
}
}()
2018-12-31 17:46:24 +08:00
handlefunc := func(file_path string, f os.FileInfo, err error) error {
if f.IsDir() {
files, _ := ioutil.ReadDir(file_path)
2019-01-02 17:46:30 +08:00
if len(files) == 0 && file_path != pathname {
2018-12-31 17:46:24 +08:00
os.Remove(file_path)
}
}
return nil
}
fi, _ := os.Stat(pathname)
if fi.IsDir() {
filepath.Walk(pathname, handlefunc)
}
}
2018-12-30 18:18:42 +08:00
func (this *Common) GetClientIp(r *http.Request) string {
client_ip := ""
headers := []string{"X_Forwarded_For", "X-Forwarded-For", "X-Real-Ip",
"X_Real_Ip", "Remote_Addr", "Remote-Addr"}
for _, v := range headers {
if _v, ok := r.Header[v]; ok {
if len(_v) > 0 {
client_ip = _v[0]
break
}
}
}
if client_ip == "" {
clients := strings.Split(r.RemoteAddr, ":")
client_ip = clients[0]
}
return client_ip
}
2019-01-02 17:46:30 +08:00
func (this *Server) DownloadFromPeer(peer string, fileInfo *FileInfo) {
var (
err error
filename string
)
if _, err = os.Stat(fileInfo.Path); err != nil {
os.MkdirAll(fileInfo.Path, 0777)
}
filename = fileInfo.Name
if fileInfo.ReName != "" {
filename = fileInfo.ReName
}
req := httplib.Get(peer + "/" + Config().Group + "/" + fileInfo.Path + "/" + filename)
req.SetTimeout(time.Second*5, time.Second*5)
if err = req.ToFile(fileInfo.Path + "/" + filename); err != nil {
log.Error(err)
}
}
2018-05-10 18:19:04 +08:00
func (this *Server) Download(w http.ResponseWriter, r *http.Request) {
2019-01-01 23:31:14 +08:00
var (
2019-01-02 17:46:30 +08:00
err error
pathMd5 string
info os.FileInfo
peer string
fileInfo *FileInfo
fullpath string
2019-01-02 20:37:50 +08:00
pathval url.Values
2019-01-01 23:31:14 +08:00
)
2019-01-02 17:46:30 +08:00
fullpath = r.RequestURI[len(Config().Group)+2 : len(r.RequestURI)]
2019-01-02 20:37:50 +08:00
if pathval, err = url.ParseQuery(fullpath); err != nil {
log.Error(err)
} else {
for k, _ := range pathval {
if k != "" {
fullpath = k
break
}
}
}
2019-01-01 23:31:14 +08:00
if info, err = os.Stat(fullpath); err != nil {
log.Error(err)
2019-01-02 17:46:30 +08:00
pathMd5 = this.util.MD5(fullpath)
for _, peer = range Config().Peers {
2019-01-02 18:09:02 +08:00
2019-01-02 17:46:30 +08:00
if fileInfo, err = this.checkPeerFileExist(peer, pathMd5); err != nil {
log.Error(err)
continue
}
if fileInfo.Md5 != "" {
go this.DownloadFromPeer(peer, fileInfo)
http.Redirect(w, r, peer+r.RequestURI, 302)
break
2019-01-01 23:31:14 +08:00
}
2019-01-02 17:46:30 +08:00
2019-01-01 23:31:14 +08:00
}
return
}
if !Config().ShowDir && info.IsDir() {
2019-01-03 10:08:01 +08:00
w.Write([]byte("list dir deny"))
2019-01-01 23:31:14 +08:00
return
}
2018-05-10 18:19:04 +08:00
log.Info("download:" + r.RequestURI)
staticHandler.ServeHTTP(w, r)
}
2018-12-30 17:17:40 +08:00
func (this *Server) GetServerURI(r *http.Request) string {
return fmt.Sprintf("http://%s/", r.Host)
}
2018-12-30 23:31:42 +08:00
func (this *Server) CheckFileAndSendToPeer(filename string, is_force_upload bool) {
2018-12-30 17:17:40 +08:00
2018-12-30 18:18:42 +08:00
defer func() {
if re := recover(); re != nil {
buffer := debug.Stack()
log.Error("CheckFileAndSendToPeer")
log.Error(re)
log.Error(string(buffer))
}
}()
2018-12-30 17:17:40 +08:00
if filename == "" {
2019-01-03 10:08:01 +08:00
filename = DATA_DIR + "/" + time.Now().Format("20060102") + "/" + CONST_Md5_ERROR_FILE_NAME
2018-12-30 17:17:40 +08:00
}
if data, err := ioutil.ReadFile(filename); err == nil {
content := string(data)
2018-12-30 23:31:42 +08:00
2018-12-30 17:17:40 +08:00
lines := strings.Split(content, "\n")
for _, line := range lines {
cols := strings.Split(line, "|")
2018-12-30 23:31:42 +08:00
if fileInfo, _ := this.GetFileInfoByMd5(cols[0]); fileInfo != nil && fileInfo.Md5 != "" {
if is_force_upload {
fileInfo.Peers = []string{}
}
this.postFileToPeer(fileInfo, false)
2018-12-30 17:17:40 +08:00
}
}
}
}
2018-12-30 23:31:42 +08:00
func (this *Server) postFileToPeer(fileInfo *FileInfo, write_log bool) {
2018-12-30 17:17:40 +08:00
2019-01-02 17:46:30 +08:00
var (
err error
peer string
filename string
info *FileInfo
postURL string
result string
data []byte
2019-01-02 18:09:02 +08:00
fi os.FileInfo
2019-01-02 17:46:30 +08:00
)
defer func() {
if re := recover(); re != nil {
buffer := debug.Stack()
log.Error("postFileToPeer")
log.Error(re)
log.Error(string(buffer))
2018-12-30 17:17:40 +08:00
}
2019-01-02 17:46:30 +08:00
}()
for _, peer = range Config().Peers {
2018-12-30 17:17:40 +08:00
if fileInfo.Peers == nil {
fileInfo.Peers = []string{}
}
if this.util.Contains(peer, fileInfo.Peers) {
continue
}
2019-01-02 00:03:48 +08:00
2019-01-02 17:46:30 +08:00
filename = fileInfo.Name
2019-01-02 00:03:48 +08:00
if Config().RenameFile {
2019-01-02 17:46:30 +08:00
filename = fileInfo.ReName
2019-01-02 00:03:48 +08:00
}
2019-01-02 17:46:30 +08:00
if !this.util.FileExists(fileInfo.Path + "/" + filename) {
2018-12-30 17:17:40 +08:00
continue
2019-01-02 18:09:02 +08:00
} else {
if fileInfo.Size == 0 {
if fi, err = os.Stat(fileInfo.Path + "/" + filename); err != nil {
log.Error(err)
} else {
fileInfo.Size = fi.Size()
}
}
2018-12-30 17:17:40 +08:00
}
2018-12-30 23:31:42 +08:00
2019-01-02 17:46:30 +08:00
if info, _ = this.checkPeerFileExist(peer, fileInfo.Md5); info.Md5 != "" {
2018-12-30 23:31:42 +08:00
continue
}
2019-01-02 17:46:30 +08:00
postURL = fmt.Sprintf("%s/%s", peer, "syncfile")
b := httplib.Post(postURL)
2018-12-30 17:17:40 +08:00
b.SetTimeout(time.Second*5, time.Second*5)
2019-01-02 17:46:30 +08:00
b.Header("Sync-Path", fileInfo.Path)
b.Param("name", filename)
2018-12-30 17:17:40 +08:00
b.Param("md5", fileInfo.Md5)
2019-01-02 17:46:30 +08:00
b.PostFile("file", fileInfo.Path+"/"+filename)
result, err = b.String()
if err != nil {
log.Error(err, result)
}
2018-12-30 17:17:40 +08:00
2019-01-02 17:46:30 +08:00
if !strings.HasPrefix(result, "http://") {
2018-12-30 23:31:42 +08:00
if write_log {
2019-01-03 10:08:01 +08:00
this.SaveFileMd5Log(fileInfo, CONST_Md5_ERROR_FILE_NAME)
2018-12-30 23:31:42 +08:00
}
2018-12-30 17:17:40 +08:00
} else {
2019-01-02 17:46:30 +08:00
log.Info(result)
2018-12-30 17:17:40 +08:00
if !this.util.Contains(peer, fileInfo.Peers) {
fileInfo.Peers = append(fileInfo.Peers, peer)
2019-01-02 17:46:30 +08:00
if data, err = json.Marshal(fileInfo); err != nil {
log.Error(err)
return
2018-12-30 17:17:40 +08:00
}
2019-01-02 17:46:30 +08:00
this.db.Put([]byte(fileInfo.Md5), data, nil)
2018-12-30 17:17:40 +08:00
}
}
if err != nil {
log.Error(err)
}
}
}
2019-01-03 10:08:01 +08:00
func (this *Server) SaveFileMd5Log(fileInfo *FileInfo, filename string) {
var (
err error
msg string
tmpFile *os.File
logpath string
outname string
)
outname = fileInfo.Name
if fileInfo.ReName != "" {
outname = fileInfo.ReName
}
logpath = DATA_DIR + "/" + time.Now().Format("20060102")
if _, err = os.Stat(logpath); err != nil {
os.MkdirAll(logpath, 0777)
}
msg = fmt.Sprintf("%s|%d|%s\n", fileInfo.Md5, fileInfo.Size, fileInfo.Path+"/"+outname)
if tmpFile, err = os.OpenFile(DATA_DIR+"/"+time.Now().Format("20060102")+"/"+filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644); err != nil {
log.Error(err)
return
}
defer tmpFile.Close()
tmpFile.WriteString(msg)
}
2018-12-30 17:17:40 +08:00
func (this *Server) GetFileInfoByMd5(md5sum string) (*FileInfo, error) {
var (
data []byte
err error
fileInfo FileInfo
)
if data, err = this.db.Get([]byte(md5sum), nil); err != nil {
return nil, err
} else {
if err = json.Unmarshal(data, &fileInfo); err == nil {
return &fileInfo, nil
} else {
return nil, err
}
}
}
2018-12-30 23:31:42 +08:00
func (this *Server) checkPeerFileExist(peer string, md5sum string) (*FileInfo, error) {
var (
err error
)
req := httplib.Get(peer + fmt.Sprintf("/check_file_exist?md5=%s", md5sum))
req.SetTimeout(time.Second*5, time.Second*5)
var fileInfo FileInfo
if err = req.ToJSON(&fileInfo); err == nil {
if fileInfo.Md5 == "" {
return &FileInfo{}, nil
2019-01-01 23:31:14 +08:00
} else {
return &fileInfo, nil
2018-12-30 23:31:42 +08:00
}
}
return &FileInfo{}, errors.New("file not found")
}
2018-12-30 17:17:40 +08:00
func (this *Server) CheckFileExist(w http.ResponseWriter, r *http.Request) {
var (
2018-12-30 23:31:42 +08:00
data []byte
2018-12-30 17:17:40 +08:00
err error
fileInfo *FileInfo
)
r.ParseForm()
md5sum := ""
if len(r.Form["md5"]) > 0 {
md5sum = r.Form["md5"][0]
} else {
return
}
if fileInfo, err = this.GetFileInfoByMd5(md5sum); fileInfo != nil {
2018-12-30 23:31:42 +08:00
if data, err = json.Marshal(fileInfo); err == nil {
w.Write(data)
return
}
2018-12-30 17:17:40 +08:00
}
2018-12-30 23:31:42 +08:00
data, _ = json.Marshal(FileInfo{})
w.Write(data)
2018-12-30 17:17:40 +08:00
}
func (this *Server) Sync(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
date := ""
2018-12-30 23:31:42 +08:00
force := ""
is_force_upload := false
if len(r.Form["force"]) > 0 {
force = r.Form["force"][0]
}
if force != "" {
is_force_upload = true
}
2018-12-30 17:17:40 +08:00
if len(r.Form["date"]) > 0 {
date = r.Form["date"][0]
} else {
w.Write([]byte("require paramete date , date?=20181230"))
return
}
date = strings.Replace(date, ".", "", -1)
2019-01-03 10:08:01 +08:00
filename := DATA_DIR + "/" + date + "/" + CONST_Md5_ERROR_FILE_NAME
2018-12-30 17:17:40 +08:00
if this.util.FileExists(filename) {
2018-12-30 23:31:42 +08:00
go this.CheckFileAndSendToPeer(filename, is_force_upload)
2018-12-30 17:17:40 +08:00
}
2019-01-03 10:08:01 +08:00
filename = DATA_DIR + "/" + date + "/" + CONST_FILE_Md5_FILE_NAME
2018-12-30 17:17:40 +08:00
if this.util.FileExists(filename) {
2018-12-30 23:31:42 +08:00
go this.CheckFileAndSendToPeer(filename, is_force_upload)
2018-12-30 17:17:40 +08:00
}
w.Write([]byte("job is running"))
}
2019-01-01 23:31:14 +08:00
func (this *Server) GetFileInfoFromLevelDB(key string) (*FileInfo, error) {
var (
err error
data []byte
fileInfo FileInfo
)
if data, err = this.db.Get([]byte(key), nil); err != nil {
return nil, err
}
if err = json.Unmarshal(data, &fileInfo); err != nil {
return nil, err
}
return &fileInfo, nil
}
2019-01-02 17:46:30 +08:00
func (this *Server) SaveStat() {
stat := statMap.Get()
if v, ok := stat[CONST_STAT_FILE_TOTAL_SIZE_KEY]; ok {
switch v.(type) {
case int64:
if v.(int64) > 0 {
if data, err := json.Marshal(stat); err != nil {
log.Error(err)
} else {
this.util.WriteBinFile(CONST_STAT_FILE_NAME, data)
}
}
}
}
}
2019-01-01 23:31:14 +08:00
func (this *Server) SaveFileInfoToLevelDB(key string, fileInfo *FileInfo) (*FileInfo, error) {
var (
err error
data []byte
)
if data, err = json.Marshal(fileInfo); err != nil {
return fileInfo, err
}
if err = this.db.Put([]byte(key), data, nil); err != nil {
return fileInfo, err
}
return fileInfo, nil
}
2019-01-03 10:08:01 +08:00
func (this *Server) IsPeer(r *http.Request) bool {
var (
ip string
peer string
bflag bool
)
ip = this.util.GetClientIp(r)
ip = "http://" + ip
bflag = false
for _, peer = range Config().Peers {
if strings.HasPrefix(peer, ip) {
bflag = true
break
}
}
return bflag
}
2019-01-02 17:46:30 +08:00
func (this *Server) SyncFile(w http.ResponseWriter, r *http.Request) {
var (
err error
outPath string
outname string
fileInfo FileInfo
tmpFile *os.File
fi os.FileInfo
uploadFile multipart.File
)
2019-01-03 10:08:01 +08:00
if !this.IsPeer(r) {
log.Error(fmt.Sprintf(" not is peer,ip:%s", this.util.GetClientIp(r)))
return
}
2019-01-02 17:46:30 +08:00
if r.Method == "POST" {
fileInfo.Path = r.Header.Get("Sync-Path")
fileInfo.Md5 = r.PostFormValue("md5")
fileInfo.Name = r.PostFormValue("name")
2019-01-02 18:49:02 +08:00
if uploadFile, _, err = r.FormFile("file"); err != nil {
w.Write([]byte(err.Error()))
log.Error(err)
return
}
2019-01-02 17:46:30 +08:00
fileInfo.Peers = []string{}
defer uploadFile.Close()
if v, _ := this.GetFileInfoFromLevelDB(fileInfo.Md5); v != nil && v.Md5 != "" {
outname = v.Name
if v.ReName != "" {
outname = v.ReName
}
download_url := fmt.Sprintf("http://%s/%s", r.Host, Config().Group+"/"+v.Path+"/"+outname)
w.Write([]byte(download_url))
return
}
os.MkdirAll(fileInfo.Path, 0777)
outPath = fileInfo.Path + "/" + fileInfo.Name
if this.util.FileExists(outPath) {
if tmpFile, err = os.Open(outPath); err != nil {
log.Error(err)
w.Write([]byte(err.Error()))
return
}
if this.util.GetFileMd5(tmpFile) != fileInfo.Md5 {
tmpFile.Close()
log.Error("md5 !=fileInfo.Md5 ")
w.Write([]byte("md5 !=fileInfo.Md5 "))
return
}
}
if tmpFile, err = os.Create(outPath); err != nil {
log.Error(err)
w.Write([]byte(err.Error()))
return
}
defer tmpFile.Close()
if _, err = io.Copy(tmpFile, uploadFile); err != nil {
w.Write([]byte(err.Error()))
log.Error(err)
return
}
if this.util.GetFileMd5(tmpFile) != fileInfo.Md5 {
w.Write([]byte("md5 error"))
tmpFile.Close()
os.Remove(outPath)
return
}
if fi, err = os.Stat(outPath); err != nil {
log.Error(err)
} else {
2019-01-03 10:08:01 +08:00
fileInfo.Size = fi.Size()
2019-01-02 17:46:30 +08:00
statMap.AddCountInt64(CONST_STAT_FILE_TOTAL_SIZE_KEY, fi.Size())
statMap.AddCountInt64(CONST_STAT_FILE_COUNT_KEY, 1)
}
if fileInfo.Peers == nil {
fileInfo.Peers = []string{fmt.Sprintf("http://%s", r.Host)}
}
if _, err = this.SaveFileInfoToLevelDB(this.util.MD5(outPath), &fileInfo); err != nil {
log.Error(err)
}
if _, err = this.SaveFileInfoToLevelDB(fileInfo.Md5, &fileInfo); err != nil {
log.Error(err)
}
2019-01-03 10:08:01 +08:00
this.SaveFileMd5Log(&fileInfo, CONST_FILE_Md5_FILE_NAME)
2019-01-02 17:46:30 +08:00
download_url := fmt.Sprintf("http://%s/%s", r.Host, Config().Group+"/"+fileInfo.Path+"/"+fileInfo.Name)
w.Write([]byte(download_url))
}
}
2018-05-10 18:19:04 +08:00
func (this *Server) Upload(w http.ResponseWriter, r *http.Request) {
2019-01-02 17:46:30 +08:00
var (
err error
// pathname string
outname string
md5sum string
fileInfo FileInfo
uploadFile multipart.File
uploadHeader *multipart.FileHeader
)
2017-09-09 16:40:55 +08:00
if r.Method == "POST" {
2019-01-01 23:31:14 +08:00
// name := r.PostFormValue("name")
2019-01-02 17:46:30 +08:00
fileInfo.Path = r.Header.Get("Sync-Path")
md5sum = r.PostFormValue("md5")
fileInfo.Md5 = r.PostFormValue("md5")
fileInfo.Name = r.PostFormValue("name")
uploadFile, uploadHeader, err = r.FormFile("file")
fileInfo.Peers = []string{}
2018-12-30 17:17:40 +08:00
2017-09-09 16:40:55 +08:00
if err != nil {
2018-05-10 13:31:34 +08:00
log.Error(err)
2017-09-09 16:40:55 +08:00
fmt.Printf("FromFileErr")
http.Redirect(w, r, "/", http.StatusMovedPermanently)
return
}
2019-01-02 17:46:30 +08:00
SaveUploadFile := func(file multipart.File, header *multipart.FileHeader, fileInfo *FileInfo) (*FileInfo, error) {
var (
err error
outFile *os.File
folder string
)
2018-05-10 13:31:34 +08:00
2018-12-31 17:46:24 +08:00
defer file.Close()
2018-12-30 17:17:40 +08:00
2019-01-02 17:46:30 +08:00
fileInfo.Name = header.Filename
2019-01-02 00:03:48 +08:00
if Config().RenameFile {
2019-01-02 17:46:30 +08:00
fileInfo.ReName = this.util.MD5(this.util.GetUUID()) + path.Ext(fileInfo.Name)
2018-12-30 17:17:40 +08:00
}
2019-01-02 17:46:30 +08:00
folder = time.Now().Format("20060102/15/04")
2018-12-30 17:17:40 +08:00
folder = fmt.Sprintf(STORE_DIR+"/%s", folder)
2019-01-02 17:46:30 +08:00
if fileInfo.Path != "" && strings.HasPrefix(fileInfo.Path, STORE_DIR) {
folder = fileInfo.Path
2018-12-29 20:31:29 +08:00
}
2018-12-30 17:17:40 +08:00
if !util.FileExists(folder) {
os.MkdirAll(folder, 0777)
}
2019-01-02 17:46:30 +08:00
outPath := fmt.Sprintf(folder+"/%s", fileInfo.Name)
2019-01-02 00:03:48 +08:00
if Config().RenameFile {
2019-01-02 17:46:30 +08:00
outPath = fmt.Sprintf(folder+"/%s", fileInfo.ReName)
2019-01-02 00:03:48 +08:00
}
2018-12-30 17:17:40 +08:00
2019-01-01 23:31:14 +08:00
if this.util.FileExists(outPath) {
for i := 0; i < 10000; i++ {
2019-01-02 17:46:30 +08:00
outPath = fmt.Sprintf(folder+"/%d_%s", i, header.Filename)
fileInfo.Name = fmt.Sprintf("%d_%s", i, header.Filename)
2019-01-01 23:31:14 +08:00
if !this.util.FileExists(outPath) {
break
}
}
}
2018-12-30 17:17:40 +08:00
log.Info(fmt.Sprintf("upload: %s", outPath))
2018-05-10 13:31:34 +08:00
2019-01-02 17:46:30 +08:00
if outFile, err = os.Create(outPath); err != nil {
return fileInfo, err
}
defer outFile.Close()
2018-12-31 17:46:24 +08:00
2018-12-30 17:17:40 +08:00
if err != nil {
log.Error(err)
2019-01-02 17:46:30 +08:00
return fileInfo, errors.New("(error)fail," + err.Error())
2018-12-30 17:17:40 +08:00
}
2019-01-02 17:46:30 +08:00
if _, err = io.Copy(outFile, file); err != nil {
2018-12-30 17:17:40 +08:00
log.Error(err)
2019-01-02 17:46:30 +08:00
return fileInfo, errors.New("(error)fail," + err.Error())
2018-12-30 17:17:40 +08:00
}
2019-01-02 17:46:30 +08:00
v := util.GetFileMd5(outFile)
fileInfo.Md5 = v
fileInfo.Path = folder
2018-05-10 13:31:34 +08:00
2019-01-02 17:46:30 +08:00
fileInfo.Peers = append(fileInfo.Peers, fmt.Sprintf("http://%s", r.Host))
2018-12-31 17:46:24 +08:00
2019-01-02 17:46:30 +08:00
return fileInfo, nil
2017-09-09 16:40:55 +08:00
2019-01-02 17:46:30 +08:00
}
2018-12-30 17:17:40 +08:00
2019-01-02 17:46:30 +08:00
SaveUploadFile(uploadFile, uploadHeader, &fileInfo)
2018-12-30 17:17:40 +08:00
2019-01-02 17:46:30 +08:00
if v, _ := this.GetFileInfoFromLevelDB(fileInfo.Md5); v != nil && v.Md5 != "" {
2018-12-31 11:26:51 +08:00
2019-01-02 17:46:30 +08:00
if Config().RenameFile {
os.Remove(fileInfo.Path + "/" + fileInfo.ReName)
2018-12-30 17:17:40 +08:00
} else {
2019-01-02 17:46:30 +08:00
os.Remove(fileInfo.Path + "/" + fileInfo.Name)
}
outname = v.Name
if v.ReName != "" {
outname = v.ReName
2018-12-30 17:17:40 +08:00
}
2019-01-02 17:46:30 +08:00
download_url := fmt.Sprintf("http://%s/%s", r.Host, Config().Group+"/"+v.Path+"/"+outname)
2019-01-03 11:20:11 +08:00
if Config().DownloadDomain != "" {
download_url = fmt.Sprintf("http://%s/%s", Config().DownloadDomain, Config().Group+"/"+v.Path+"/"+outname)
}
2019-01-02 17:46:30 +08:00
w.Write([]byte(download_url))
2018-12-30 18:18:42 +08:00
2019-01-02 17:46:30 +08:00
return
2018-12-30 17:17:40 +08:00
}
2019-01-02 17:46:30 +08:00
if fileInfo.Md5 == "" {
log.Warn(" fileInfo.Md5 is null")
return
2018-12-31 18:00:13 +08:00
}
2019-01-02 17:46:30 +08:00
if md5sum != "" && fileInfo.Md5 != md5sum {
log.Warn(" fileInfo.Md5 and md5sum !=")
2018-12-31 18:00:13 +08:00
return
}
2018-05-10 13:31:34 +08:00
2019-01-02 17:46:30 +08:00
UploadToPeer := func(fileInfo *FileInfo) {
var (
err error
pathMd5 string
fullpath string
data []byte
)
if data, err = json.Marshal(fileInfo); err != nil {
log.Error(err)
log.Error(fmt.Sprintf("UploadToPeer fail: %v", fileInfo))
return
2018-12-30 17:17:40 +08:00
}
2019-01-02 17:46:30 +08:00
if err = this.db.Put([]byte(fileInfo.Md5), data, nil); err != nil {
log.Error(err)
}
2019-01-01 23:31:14 +08:00
2019-01-02 17:46:30 +08:00
fullpath = fileInfo.Path + "/" + fileInfo.Name
2019-01-01 23:31:14 +08:00
2019-01-02 17:46:30 +08:00
if Config().RenameFile {
fullpath = fileInfo.Path + "/" + fileInfo.ReName
}
2019-01-01 23:31:14 +08:00
2019-01-02 17:46:30 +08:00
pathMd5 = this.util.MD5(fullpath)
2018-05-10 18:19:04 +08:00
2019-01-02 17:46:30 +08:00
if err = this.db.Put([]byte(pathMd5), data, nil); err != nil {
2018-12-30 17:17:40 +08:00
log.Error(err)
2018-05-10 18:19:04 +08:00
}
2018-12-30 17:17:40 +08:00
2019-01-02 17:46:30 +08:00
go this.postFileToPeer(fileInfo, true)
2018-12-30 17:17:40 +08:00
2018-05-10 18:19:04 +08:00
}
2018-05-10 13:31:34 +08:00
2019-01-02 17:46:30 +08:00
UploadToPeer(&fileInfo)
outname = fileInfo.Name
2018-12-30 17:17:40 +08:00
2019-01-02 00:03:48 +08:00
if Config().RenameFile {
2019-01-02 17:46:30 +08:00
outname = fileInfo.ReName
2019-01-02 00:03:48 +08:00
}
2019-01-02 17:46:30 +08:00
if fi, err := os.Stat(fileInfo.Path + "/" + outname); err != nil {
log.Error(err)
} else {
2019-01-02 18:09:02 +08:00
fileInfo.Size = fi.Size()
2019-01-02 17:46:30 +08:00
statMap.AddCountInt64(CONST_STAT_FILE_TOTAL_SIZE_KEY, fi.Size())
2019-01-02 18:09:02 +08:00
statMap.AddCountInt64(CONST_STAT_FILE_COUNT_KEY, 1)
2019-01-02 17:46:30 +08:00
}
this.SaveStat()
2019-01-03 10:08:01 +08:00
this.SaveFileMd5Log(&fileInfo, CONST_FILE_Md5_FILE_NAME)
2019-01-02 17:46:30 +08:00
download_url := fmt.Sprintf("http://%s/%s", r.Host, Config().Group+"/"+fileInfo.Path+"/"+outname)
2019-01-03 11:20:11 +08:00
if Config().DownloadDomain != "" {
download_url = fmt.Sprintf("http://%s/%s", Config().DownloadDomain, Config().Group+"/"+fileInfo.Path+"/"+outname)
}
2018-05-10 13:31:34 +08:00
w.Write([]byte(download_url))
2018-12-31 17:46:24 +08:00
return
2018-05-10 13:31:34 +08:00
} else {
2018-12-29 20:31:29 +08:00
w.Write([]byte("(error)fail,please use post method"))
2018-05-10 13:31:34 +08:00
return
}
2019-01-02 17:46:30 +08:00
}
2018-05-10 13:31:34 +08:00
2019-01-02 17:46:30 +08:00
func (this *Server) Stat(w http.ResponseWriter, r *http.Request) {
2018-05-10 13:31:34 +08:00
2019-01-02 17:46:30 +08:00
if this.util.FileExists(CONST_STAT_FILE_NAME) {
if data, err := this.util.ReadBinFile(CONST_STAT_FILE_NAME); err != nil {
w.Write([]byte(err.Error()))
} else {
w.Write(data)
}
2017-09-09 16:40:55 +08:00
}
2019-01-02 17:46:30 +08:00
2017-09-09 16:40:55 +08:00
}
2018-05-10 18:19:04 +08:00
func (this *Server) Index(w http.ResponseWriter, r *http.Request) {
2019-01-03 10:08:01 +08:00
if Config().EnableWebUpload {
fmt.Fprintf(w,
`<html>
2017-09-09 16:40:55 +08:00
<head>
<meta charset="utf-8"></meta>
<title>Uploader</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" id="file" name="file">
<input type="submit" name="submit" value="upload">
</form>
</body>
</html>`)
2019-01-03 10:08:01 +08:00
} else {
w.Write([]byte("web upload deny"))
}
2017-09-09 16:40:55 +08:00
}
2018-05-10 18:19:04 +08:00
func init() {
2018-12-30 17:17:40 +08:00
server.util = util
for _, folder := range FOLDERS {
os.Mkdir(folder, 0777)
}
flag.Parse()
2019-01-01 14:41:57 +08:00
if !util.FileExists(CONST_CONF_FILE_NAME) {
peer := "http://" + util.GetPulicIP() + ":8080"
cfg := fmt.Sprintf(cfgJson, peer)
util.WriteFile(CONST_CONF_FILE_NAME, cfg)
}
2018-12-30 18:18:42 +08:00
if logger, err := log.LoggerFromConfigAsBytes([]byte(logConfigStr)); err != nil {
panic(err)
} else {
log.ReplaceLogger(logger)
}
if _logacc, err := log.LoggerFromConfigAsBytes([]byte(logAccessConfigStr)); err == nil {
logacc = _logacc
log.Info("succes init log access")
} else {
log.Error(err.Error())
}
2019-01-01 14:41:57 +08:00
ParseConfig(CONST_CONF_FILE_NAME)
staticHandler = http.StripPrefix("/"+Config().Group+"/"+STORE_DIR+"/", http.FileServer(http.Dir(STORE_DIR)))
2018-12-30 17:17:40 +08:00
initComponent()
2017-09-09 16:40:55 +08:00
}
2018-12-30 17:17:40 +08:00
func initComponent() {
2019-01-02 17:46:30 +08:00
var (
err error
db *leveldb.DB
ip string
stat map[string]interface{}
data []byte
count int64
)
ip = util.GetPulicIP()
2018-12-30 17:17:40 +08:00
ex, _ := regexp.Compile("\\d+\\.\\d+\\.\\d+\\.\\d+")
2019-01-01 14:41:57 +08:00
var peers []string
for _, peer := range Config().Peers {
if util.Contains(ip, ex.FindAllString(peer, -1)) {
continue
}
if strings.HasPrefix(peer, "http") {
peers = append(peers, peer)
} else {
peers = append(peers, "http://"+peer)
2018-12-30 17:17:40 +08:00
}
}
2019-01-01 14:41:57 +08:00
Config().Peers = peers
2018-05-10 13:31:34 +08:00
2019-01-02 17:46:30 +08:00
db, err = leveldb.OpenFile(CONST_LEVELDB_FILE_NAME, nil)
2018-12-30 17:17:40 +08:00
if err != nil {
log.Error(err)
panic(err)
}
server.db = db
2019-01-02 17:46:30 +08:00
if util.FileExists(CONST_STAT_FILE_NAME) {
if data, err = util.ReadBinFile(CONST_STAT_FILE_NAME); err != nil {
log.Error(err)
} else {
if err = json.Unmarshal(data, &stat); err != nil {
log.Error(err)
} else {
for k, v := range stat {
switch v.(type) {
case float64:
vv := strings.Split(fmt.Sprintf("%f", v), ".")[0]
if count, err = strconv.ParseInt(vv, 10, 64); err != nil {
log.Error(err)
} else {
statMap.Put(k, count)
}
default:
statMap.Put(k, v)
}
}
}
}
}
2018-12-30 17:17:40 +08:00
}
2018-12-30 18:18:42 +08:00
type HttpHandler struct {
}
2018-05-10 18:19:04 +08:00
2018-12-30 18:18:42 +08:00
func (HttpHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
status_code := "200"
defer func(t time.Time) {
logStr := fmt.Sprintf("[Access] %s | %v | %s | %s | %s | %s |%s",
time.Now().Format("2006/01/02 - 15:04:05"),
res.Header(),
time.Since(t).String(),
util.GetClientIp(req),
req.Method,
status_code,
req.RequestURI,
)
logacc.Info(logStr)
}(time.Now())
defer func() {
if err := recover(); err != nil {
status_code = "500"
res.WriteHeader(500)
print(err)
buff := debug.Stack()
log.Error(err)
log.Error(string(buff))
2018-05-10 13:31:34 +08:00
2018-12-30 18:18:42 +08:00
}
}()
http.DefaultServeMux.ServeHTTP(res, req)
}
func main() {
2018-05-10 13:31:34 +08:00
2018-05-10 18:19:04 +08:00
if !util.FileExists(STORE_DIR) {
2018-05-10 13:31:34 +08:00
os.Mkdir(STORE_DIR, 0777)
}
2017-09-09 16:40:55 +08:00
2018-12-30 17:17:40 +08:00
go func() {
for {
2018-12-30 23:31:42 +08:00
server.CheckFileAndSendToPeer("", false)
2019-01-02 17:51:08 +08:00
time.Sleep(time.Second * time.Duration(Config().RefreshInterval))
2018-12-31 17:46:24 +08:00
util.RemoveEmptyDir(STORE_DIR)
2019-01-02 17:46:30 +08:00
server.SaveStat()
2018-12-30 17:17:40 +08:00
}
}()
2018-05-10 18:19:04 +08:00
http.HandleFunc("/", server.Index)
2018-12-30 17:17:40 +08:00
http.HandleFunc("/check_file_exist", server.CheckFileExist)
2018-05-10 18:19:04 +08:00
http.HandleFunc("/upload", server.Upload)
2018-12-30 17:17:40 +08:00
http.HandleFunc("/sync", server.Sync)
2019-01-02 17:46:30 +08:00
http.HandleFunc("/stat", server.Stat)
http.HandleFunc("/syncfile", server.SyncFile)
2019-01-01 14:41:57 +08:00
http.HandleFunc("/"+Config().Group+"/"+STORE_DIR+"/", server.Download)
fmt.Println("Listen on " + Config().Addr)
panic(http.ListenAndServe(Config().Addr, new(HttpHandler)))
2018-12-30 17:17:40 +08:00
2017-09-09 16:40:55 +08:00
}