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-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"
|
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{}
|
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-01 14:41:57 +08:00
|
|
|
CONST_CONF_FILE_NAME = CONF_DIR + "/cfg.json"
|
|
|
|
|
2018-12-30 17:17:40 +08:00
|
|
|
Md5_ERROR_FILE_NAME = "errors.md5"
|
|
|
|
FILE_Md5_FILE_NAME = "files.md5"
|
|
|
|
|
|
|
|
cfgJson = `
|
2019-01-01 14:41:57 +08:00
|
|
|
{
|
|
|
|
"addr": ":8080",
|
|
|
|
"peers":["%s"],
|
2019-01-01 23:31:14 +08:00
|
|
|
"group":"group1",
|
|
|
|
"use_file_rename":false,
|
|
|
|
"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
|
|
|
|
Peers []string
|
2018-12-30 17:17:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
type GloablConfig struct {
|
2019-01-01 23:31:14 +08:00
|
|
|
Addr string `json:"addr"`
|
|
|
|
Peers []string `json:"peers"`
|
|
|
|
Group string `json:"group"`
|
|
|
|
UseFileRename bool `json:"use_file_rename"`
|
|
|
|
ShowDir bool `json:"show_dir"`
|
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
|
|
|
|
}
|
|
|
|
}
|
2018-12-31 17:46:24 +08:00
|
|
|
func (this *Common) RemoveEmptyDir(pathname string) {
|
|
|
|
|
|
|
|
handlefunc := func(file_path string, f os.FileInfo, err error) error {
|
|
|
|
|
|
|
|
if f.IsDir() {
|
|
|
|
|
|
|
|
files, _ := ioutil.ReadDir(file_path)
|
|
|
|
if len(files) == 0 {
|
|
|
|
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
|
|
|
|
|
|
|
|
}
|
|
|
|
|
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 (
|
|
|
|
err error
|
|
|
|
info os.FileInfo
|
|
|
|
)
|
|
|
|
fullpath := r.RequestURI[len(Config().Group)+2 : len(r.RequestURI)]
|
|
|
|
if info, err = os.Stat(fullpath); err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
pathMd5 := this.util.MD5(fullpath)
|
|
|
|
for _, peer := range Config().Peers {
|
|
|
|
if fileInfo, _ := this.checkPeerFileExist(peer, pathMd5); fileInfo != nil && fileInfo.Md5 != "" {
|
|
|
|
if fileInfo.ReName != "" {
|
|
|
|
http.Redirect(w, r, peer+r.RequestURI, 302)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if !Config().ShowDir && info.IsDir() {
|
|
|
|
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 == "" {
|
|
|
|
filename = STORE_DIR + "/" + time.Now().Format("20060102") + "/" + Md5_ERROR_FILE_NAME
|
|
|
|
}
|
|
|
|
|
|
|
|
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-01 14:41:57 +08:00
|
|
|
for _, u := range Config().Peers {
|
2018-12-30 17:17:40 +08:00
|
|
|
peer := ""
|
|
|
|
if !strings.HasPrefix(u, "http://") {
|
|
|
|
u = "http://" + u
|
|
|
|
}
|
|
|
|
peer = u
|
|
|
|
if fileInfo.Peers == nil {
|
|
|
|
fileInfo.Peers = []string{}
|
|
|
|
}
|
|
|
|
if this.util.Contains(peer, fileInfo.Peers) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if !this.util.FileExists(fileInfo.Path + "/" + fileInfo.Name) {
|
|
|
|
continue
|
|
|
|
}
|
2018-12-30 23:31:42 +08:00
|
|
|
|
|
|
|
if info, _ := this.checkPeerFileExist(peer, fileInfo.Md5); info.Md5 != "" {
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2018-12-30 17:17:40 +08:00
|
|
|
u = fmt.Sprintf("%s/%s", u, "upload")
|
|
|
|
b := httplib.Post(u)
|
|
|
|
b.SetTimeout(time.Second*5, time.Second*5)
|
|
|
|
b.Header("path", fileInfo.Path)
|
|
|
|
b.Param("name", fileInfo.Name)
|
|
|
|
b.Param("md5", fileInfo.Md5)
|
|
|
|
b.PostFile("file", fileInfo.Path+"/"+fileInfo.Name)
|
|
|
|
str, err := b.String()
|
|
|
|
|
|
|
|
if !strings.HasPrefix(str, "http://") {
|
2018-12-30 23:31:42 +08:00
|
|
|
if write_log {
|
|
|
|
msg := fmt.Sprintf("%s|%s\n", fileInfo.Md5, fileInfo.Path+"/"+fileInfo.Name)
|
|
|
|
fd, _ := os.OpenFile(STORE_DIR+"/"+time.Now().Format("20060102")+"/"+Md5_ERROR_FILE_NAME, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
|
|
|
|
defer fd.Close()
|
|
|
|
fd.WriteString(msg)
|
|
|
|
}
|
2018-12-30 17:17:40 +08:00
|
|
|
} else {
|
|
|
|
|
|
|
|
if !this.util.Contains(peer, fileInfo.Peers) {
|
|
|
|
fileInfo.Peers = append(fileInfo.Peers, peer)
|
|
|
|
if data, err := json.Marshal(fileInfo); err == nil {
|
|
|
|
this.db.Put([]byte(fileInfo.Md5), data, nil)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
log.Info(str)
|
|
|
|
if err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
filename := STORE_DIR + "/" + date + "/" + Md5_ERROR_FILE_NAME
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
filename = STORE_DIR + "/" + date + "/" + FILE_Md5_FILE_NAME
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-05-10 18:19:04 +08:00
|
|
|
func (this *Server) Upload(w http.ResponseWriter, r *http.Request) {
|
2017-09-09 16:40:55 +08:00
|
|
|
if r.Method == "POST" {
|
2019-01-01 23:31:14 +08:00
|
|
|
// name := r.PostFormValue("name")
|
|
|
|
name := ""
|
|
|
|
pathname := r.Header.Get("Path")
|
2018-05-10 18:19:04 +08:00
|
|
|
md5sum := r.PostFormValue("md5")
|
2017-09-09 16:40:55 +08:00
|
|
|
file, header, err := r.FormFile("file")
|
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-01 23:31:14 +08:00
|
|
|
SaveUploadFile := func(file multipart.File, header *multipart.FileHeader, pathname string, name string) (*os.File, string, string, string, error) {
|
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
|
|
|
if name == "" {
|
|
|
|
name = header.Filename
|
|
|
|
|
2019-01-01 23:31:14 +08:00
|
|
|
}
|
|
|
|
rename := ""
|
|
|
|
if Config().UseFileRename {
|
|
|
|
rename = this.util.MD5(this.util.GetUUID()) + path.Ext(name)
|
|
|
|
}
|
2018-12-30 17:17:40 +08:00
|
|
|
ns := strings.Split(name, "/")
|
|
|
|
if len(ns) > 1 {
|
|
|
|
if strings.TrimSpace(ns[len(ns)-1]) != "" {
|
|
|
|
name = ns[len(ns)-1]
|
|
|
|
} else {
|
2019-01-01 23:31:14 +08:00
|
|
|
return nil, "", "", "", errors.New("(error) filename is error")
|
2018-12-30 17:17:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
folder := time.Now().Format("20060102/15/04")
|
|
|
|
|
|
|
|
folder = fmt.Sprintf(STORE_DIR+"/%s", folder)
|
|
|
|
|
2019-01-01 23:31:14 +08:00
|
|
|
if pathname != "" && strings.HasPrefix(pathname, STORE_DIR) {
|
|
|
|
folder = pathname
|
2018-12-29 20:31:29 +08:00
|
|
|
}
|
|
|
|
|
2018-12-30 17:17:40 +08:00
|
|
|
if !util.FileExists(folder) {
|
|
|
|
os.MkdirAll(folder, 0777)
|
|
|
|
}
|
|
|
|
|
|
|
|
outPath := fmt.Sprintf(folder+"/%s", name)
|
|
|
|
|
2019-01-01 23:31:14 +08:00
|
|
|
if this.util.FileExists(outPath) {
|
|
|
|
for i := 0; i < 10000; i++ {
|
|
|
|
outPath = fmt.Sprintf(folder+"/%d%s", i, name)
|
|
|
|
if !this.util.FileExists(outPath) {
|
|
|
|
name = fmt.Sprintf("%d%s", i, name)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-12-30 17:17:40 +08:00
|
|
|
log.Info(fmt.Sprintf("upload: %s", outPath))
|
2018-05-10 13:31:34 +08:00
|
|
|
|
2018-12-30 17:17:40 +08:00
|
|
|
outFile, err := os.Create(outPath)
|
2018-12-31 17:46:24 +08:00
|
|
|
|
2018-12-30 17:17:40 +08:00
|
|
|
if err != nil {
|
|
|
|
log.Error(err)
|
2019-01-01 23:31:14 +08:00
|
|
|
return nil, "", "", "", errors.New("(error)fail," + err.Error())
|
2018-12-30 17:17:40 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := io.Copy(outFile, file); err != nil {
|
|
|
|
log.Error(err)
|
2019-01-01 23:31:14 +08:00
|
|
|
return nil, "", "", "", errors.New("(error)fail," + err.Error())
|
2018-12-30 17:17:40 +08:00
|
|
|
}
|
|
|
|
|
2019-01-01 23:31:14 +08:00
|
|
|
return outFile, folder, name, rename, nil
|
2018-05-10 13:31:34 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-12-30 17:17:40 +08:00
|
|
|
var uploadFile *os.File
|
|
|
|
var folder string
|
2019-01-01 23:31:14 +08:00
|
|
|
var rename string
|
2018-05-10 13:31:34 +08:00
|
|
|
|
2018-12-31 17:46:24 +08:00
|
|
|
defer uploadFile.Close()
|
|
|
|
|
2019-01-01 23:31:14 +08:00
|
|
|
if uploadFile, folder, name, rename, err = SaveUploadFile(file, header, pathname, name); uploadFile != nil {
|
2017-09-09 16:40:55 +08:00
|
|
|
|
2018-12-30 17:17:40 +08:00
|
|
|
if md5sum == "" {
|
|
|
|
|
|
|
|
md5sum = util.GetFileMd5(uploadFile)
|
|
|
|
|
2018-12-31 11:26:51 +08:00
|
|
|
if info, _ := this.GetFileInfoByMd5(md5sum); info != nil && info.Path != "" && info.Path != folder {
|
2018-12-31 17:46:24 +08:00
|
|
|
uploadFile.Close()
|
2018-12-31 11:26:51 +08:00
|
|
|
os.Remove(folder + "/" + name)
|
2019-01-01 14:41:57 +08:00
|
|
|
download_url := fmt.Sprintf("http://%s/%s", r.Host, Config().Group+"/"+info.Path+"/"+info.Name)
|
2018-12-31 11:26:51 +08:00
|
|
|
w.Write([]byte(download_url))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-12-30 17:17:40 +08:00
|
|
|
} else {
|
|
|
|
|
|
|
|
v := util.GetFileMd5(uploadFile)
|
|
|
|
if v != md5sum {
|
|
|
|
w.Write([]byte("(error)fail,md5sum error"))
|
|
|
|
os.Remove(folder + "/" + name)
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-12-30 18:18:42 +08:00
|
|
|
} else {
|
|
|
|
w.Write([]byte("(error)" + err.Error()))
|
|
|
|
log.Error(err)
|
|
|
|
return
|
|
|
|
|
2018-12-30 17:17:40 +08:00
|
|
|
}
|
|
|
|
|
2018-12-31 18:00:13 +08:00
|
|
|
CheckFileExist := func(md5sum string) (*FileInfo, error) {
|
|
|
|
if md5sum != "" {
|
|
|
|
if data, err := this.db.Get([]byte(md5sum), nil); err == nil {
|
|
|
|
var fileInfo FileInfo
|
|
|
|
if err := json.Unmarshal(data, &fileInfo); err == nil {
|
|
|
|
return &fileInfo, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, errors.New("File Not found")
|
|
|
|
}
|
|
|
|
|
|
|
|
if info, err := CheckFileExist(md5sum); err == nil {
|
2019-01-01 14:41:57 +08:00
|
|
|
download_url := fmt.Sprintf("http://%s/%s", r.Host, Config().Group+"/"+info.Path+"/"+info.Name)
|
2018-12-31 18:00:13 +08:00
|
|
|
w.Write([]byte(download_url))
|
|
|
|
return
|
|
|
|
}
|
2018-05-10 13:31:34 +08:00
|
|
|
|
2018-12-30 17:17:40 +08:00
|
|
|
UploadToPeer := func(md5sum string, name string, path string) {
|
|
|
|
|
|
|
|
fileInfo := FileInfo{
|
2019-01-01 23:31:14 +08:00
|
|
|
Name: name,
|
|
|
|
ReName: rename,
|
|
|
|
Md5: md5sum,
|
|
|
|
Path: path,
|
|
|
|
Peers: []string{this.GetServerURI(r)},
|
2018-12-30 17:17:40 +08:00
|
|
|
}
|
|
|
|
if v, err := json.Marshal(fileInfo); err == nil {
|
|
|
|
|
2019-01-01 23:31:14 +08:00
|
|
|
if err := this.db.Put([]byte(md5sum), v, nil); err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
}
|
|
|
|
pathMd5 := ""
|
|
|
|
|
|
|
|
fullpath := path + "/" + name
|
|
|
|
|
|
|
|
if Config().UseFileRename {
|
|
|
|
fullpath = path + "/" + rename
|
|
|
|
}
|
|
|
|
pathMd5 = this.util.MD5(fullpath)
|
|
|
|
|
|
|
|
if err := this.db.Put([]byte(pathMd5), v, nil); err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
}
|
2018-05-10 18:19:04 +08:00
|
|
|
|
2018-12-30 17:17:40 +08:00
|
|
|
} else {
|
|
|
|
log.Error(err)
|
2018-05-10 18:19:04 +08:00
|
|
|
}
|
2018-12-30 17:17:40 +08:00
|
|
|
|
2018-12-30 23:31:42 +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
|
|
|
|
2018-12-30 17:17:40 +08:00
|
|
|
UploadToPeer(md5sum, name, folder)
|
|
|
|
|
|
|
|
msg := fmt.Sprintf("%s|%s\n", md5sum, folder+"/"+name)
|
|
|
|
fd, _ := os.OpenFile(STORE_DIR+"/"+time.Now().Format("20060102")+"/"+FILE_Md5_FILE_NAME, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
|
|
|
|
defer fd.Close()
|
|
|
|
fd.WriteString(msg)
|
|
|
|
|
2019-01-01 14:41:57 +08:00
|
|
|
download_url := fmt.Sprintf("http://%s/%s", r.Host, Config().Group+"/"+folder+"/"+name)
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
useragent := r.Header.Get("User-Agent")
|
|
|
|
|
|
|
|
if useragent != "" && (strings.Contains(useragent, "curl") || strings.Contains(useragent, "wget")) {
|
|
|
|
|
|
|
|
} else {
|
|
|
|
http.Redirect(w, r, "/", http.StatusMovedPermanently)
|
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) {
|
2018-05-10 13:31:34 +08:00
|
|
|
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>`)
|
|
|
|
}
|
|
|
|
|
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() {
|
|
|
|
ip := util.GetPulicIP()
|
|
|
|
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
|
|
|
|
2018-12-30 17:17:40 +08:00
|
|
|
db, err := leveldb.OpenFile(CONST_LEVELDB_FILE_NAME, nil)
|
|
|
|
if err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
server.db = db
|
|
|
|
|
|
|
|
}
|
|
|
|
|
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)
|
2018-12-30 17:17:40 +08:00
|
|
|
time.Sleep(time.Second * 60)
|
2018-12-31 17:46:24 +08:00
|
|
|
util.RemoveEmptyDir(STORE_DIR)
|
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-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
|
|
|
}
|