From 97900240910c9cc51c389ab80088e89485667e89 Mon Sep 17 00:00:00 2001 From: "Terry.Mao" <83873308@qq.com> Date: Fri, 13 May 2016 00:20:23 +0800 Subject: [PATCH] refactor proxy --- proxy/auth/auth.go | 121 ++++------------ proxy/auth/bucket.go | 30 ---- proxy/bfs/bfs.go | 8 +- proxy/bucket/bucket.go | 77 +++++++++++ proxy/conf/config.go | 23 +-- proxy/http_api.go | 307 ++++++++++++++++++++++++----------------- proxy/http_api_test.go | 47 +++++++ proxy/main.go | 2 +- proxy/proxy.toml | 7 +- 9 files changed, 355 insertions(+), 267 deletions(-) delete mode 100644 proxy/auth/bucket.go create mode 100644 proxy/bucket/bucket.go diff --git a/proxy/auth/auth.go b/proxy/auth/auth.go index 816ec97..1d3f782 100644 --- a/proxy/auth/auth.go +++ b/proxy/auth/auth.go @@ -2,33 +2,24 @@ package auth import ( "bfs/libs/errors" + ibucket "bfs/proxy/bucket" "bfs/proxy/conf" "crypto/hmac" "crypto/sha1" "encoding/base64" "fmt" - log "github.com/golang/glog" "hash" - "net/http" "strconv" "strings" "time" ) const ( - // bucket acl - _statusReadBit = 0 - _statusWriteBit = 1 - // - _statusRead = 1 << _statusReadBit - _statusWrite = 1 << _statusWriteBit - // - _authExpire = 900 // s + _authExpire = 900 // 15min _template = "%s\n%s\n%s\n%d\n" // method bucket filename expire ) type Auth struct { - b map[string]Bucket c *conf.Config } @@ -36,116 +27,52 @@ type Auth struct { func NewAuth(c *conf.Config) (a *Auth, err error) { a = &Auth{} a.c = c - a.b, err = InitBucket() return } -// CheckAuth -func (a *Auth) CheckAuth(r *http.Request) (err error) { +func (a *Auth) Authorize(item *ibucket.Item, method, bucket, file, token string) (err error) { + // token keyid:sign:time var ( - params = r.URL.Query() - ss []string - bucket string - filename string - token string - exist bool + expire int64 + delta int64 + now int64 + keyId string + ss = strings.Split(token, ":") ) - if r.Method == "PUT" || r.Method == "DELETE" { - ss = strings.Split(r.URL.Path[1:], "/") - } else { - ss = strings.Split(strings.TrimPrefix(r.URL.Path, "/bfs")[1:], "/") - } - bucket = ss[0] - if _, exist = a.b[bucket]; !exist { - err = errors.ErrBucketNotExist - return - } - if !a.bucketNeedAuth(r.Method, bucket) { - return - } - filename = ss[len(ss)-1] - token = params.Get("token") - if token == "" { - token = r.Header.Get("Authorization") - } - if !a.reqAuth(r.Method, bucket, filename, token) { - log.Errorf("CheckAuth failed method: %s, bucket: %s, token: %s", r.Method, bucket, token) - err = errors.ErrAuthFailed - } - return -} - -// Bucket need check authorization -func (a *Auth) bucketNeedAuth(method, bucket string) bool { - var ( - property int - ) - property = a.b[bucket].Property - if method == "GET" || method == "HEAD" { - if property&_statusRead == 0 { - return false - } - } else { // POST DELETE - if property&_statusWrite == 0 { - return false - } - } - return true -} - -// auth -func (a *Auth) reqAuth(method, bucket, filename, token string) bool { - var ( - err error - now int64 - keyId string - keySecret string - expire int64 - auth string - realAuth string - ss []string - ) - ss = strings.Split(token, ":") if len(ss) != 3 { - return false + return errors.ErrAuthFailed } keyId = ss[0] - if keyId != a.b[bucket].KeyId { - return false + if keyId != item.KeyId { + return errors.ErrAuthFailed } - keySecret = a.b[bucket].KeySecret - auth = ss[1] if expire, err = strconv.ParseInt(ss[2], 10, 64); err != nil { - return false + return errors.ErrAuthFailed } now = time.Now().Unix() // > ±15 min is forbidden if expire > now { - if expire-now > _authExpire { - return false - } + delta = expire - now } else { - if now-expire > _authExpire { - return false - } + delta = now - expire } - realAuth = a.createAuthorization(method, bucket, filename, expire, keySecret) - if auth != realAuth { - log.Errorf("auth failed: auth: %s realAuth: %s ", auth, realAuth) - return false + if delta > _authExpire { + return errors.ErrAuthFailed } - return true + err = a.sign(ss[1], method, bucket, file, item.KeySecret, expire) + return } -// createAuthorization -func (a *Auth) createAuthorization(method, bucket, filename string, expire int64, keySecret string) (auth string) { +func (a *Auth) sign(src, method, bucket, file, keySecret string, expire int64) (err error) { var ( content string mac hash.Hash ) - content = fmt.Sprintf(_template, method, bucket, filename, expire) + content = fmt.Sprintf(_template, method, bucket, file, expire) mac = hmac.New(sha1.New, []byte(keySecret)) mac.Write([]byte(content)) - auth = base64.StdEncoding.EncodeToString(mac.Sum(nil)) + if base64.StdEncoding.EncodeToString(mac.Sum(nil)) != src { + return errors.ErrAuthFailed + } return } diff --git a/proxy/auth/bucket.go b/proxy/auth/bucket.go deleted file mode 100644 index 29c32bc..0000000 --- a/proxy/auth/bucket.go +++ /dev/null @@ -1,30 +0,0 @@ -package auth - -// bucket_name property key_id key_secret -// property 第0位:读 (0表示共有,1表示私有) 第1位:写 (0表示共有,1表示私有) - -// todo -> db - -type Bucket struct { - BucketName string - Property int - KeyId string - KeySecret string -} - -// InitBucket -// todo get data from db -func InitBucket() (b map[string]Bucket, err error) { - var ( - item Bucket - ) - b = make(map[string]Bucket) - // bucket test - item.BucketName = "test" - item.Property = 2 - item.KeyId = "121bce6492eba701" - item.KeySecret = "1eb80603e85842542f9736eb13b7e1" - b["test"] = item - - return -} diff --git a/proxy/bfs/bfs.go b/proxy/bfs/bfs.go index 702f2ef..e7b056f 100644 --- a/proxy/bfs/bfs.go +++ b/proxy/bfs/bfs.go @@ -39,6 +39,7 @@ var ( } return c, nil }, + DisableCompression: true, } _client = &http.Client{ Transport: _transport, @@ -153,6 +154,7 @@ func (b *Bfs) Upload(bucket, filename, mine, sha1 string, buf []byte) (err error if res.Ret == errors.RetNeedleExist { err = errors.ErrNeedleExist } + log.Infof("bfs.upload bucket:%s filename:%s key:%d cookie:%d vid:%d", bucket, filename, res.Key, res.Cookie, res.Vid) return } @@ -216,6 +218,7 @@ func Http(method, uri string, params url.Values, buf []byte, res interface{}) (e resp *http.Response ru string enc string + ctype string ) enc = params.Encode() if enc != "" { @@ -236,19 +239,20 @@ func Http(method, uri string, params url.Values, buf []byte, res interface{}) (e if bw, err = w.CreateFormFile("file", "1.jpg"); err != nil { return } - if _, err = io.WriteString(bw, string(buf)); err != nil { + if _, err = bw.Write(buf); err != nil { return } for key, _ := range params { w.WriteField(key, params.Get(key)) } + ctype = w.FormDataContentType() if err = w.Close(); err != nil { return } if req, err = http.NewRequest("POST", uri, bufdata); err != nil { return } - req.Header.Set("Content-Type", w.FormDataContentType()) + req.Header.Set("Content-Type", ctype) } } td := _timer.Start(5*time.Second, func() { diff --git a/proxy/bucket/bucket.go b/proxy/bucket/bucket.go new file mode 100644 index 0000000..61bc7aa --- /dev/null +++ b/proxy/bucket/bucket.go @@ -0,0 +1,77 @@ +package bucket + +import ( + "bfs/libs/errors" + "fmt" +) + +const ( + // status bit + _privateReadBit = 0 + _privateWriteBit = 1 + // status + _public = int(0) + _privateRead = int(1 << _privateReadBit) + _privateWrite = int(1 << _privateWriteBit) + _privateReadWrite = int(_privateRead | _privateWrite) +) + +// bucket_name property key_id key_secret +type Bucket struct { + data map[string]*Item +} + +type Item struct { + Name string + KeyId string + KeySecret string + PurgeCDN bool + + // property 第0位:读 (0表示共有,1表示私有) 第1位:写 (0表示共有,1表示私有) + property int +} + +func (i *Item) String() string { + return fmt.Sprintf("{name: %s, purge: %s, property: %d}", i.Name, i.PurgeCDN, i.property) +} + +func (i *Item) writePublic() bool { + return i.property&_privateWrite == 0 +} + +func (i *Item) readPublic() bool { + return i.property&_privateRead == 0 +} + +// Public check the item is public or not. +func (i *Item) Public(read bool) bool { + if read { + return i.readPublic() + } + return i.writePublic() +} + +// NewBucket +func NewBucket() (b *Bucket, err error) { + var item *Item + b = new(Bucket) + b.data = make(map[string]*Item) + // bucket test + item = new(Item) + item.Name = "test" + item.property = _privateWrite + item.KeyId = "221bce6492eba70f" + item.KeySecret = "6eb80603e85842542f9736eb13b7e3" + item.PurgeCDN = false + b.data[item.Name] = item + return +} + +// Get get a bucket, if not exist then error. +func (b *Bucket) Get(name string) (item *Item, err error) { + var ok bool + if item, ok = b.data[name]; !ok { + err = errors.ErrBucketNotExist + } + return +} diff --git a/proxy/conf/config.go b/proxy/conf/config.go index decb6eb..c5006ea 100644 --- a/proxy/conf/config.go +++ b/proxy/conf/config.go @@ -1,10 +1,13 @@ package conf import ( - "github.com/BurntSushi/toml" "io/ioutil" "os" + "path" + "strings" "time" + + "github.com/BurntSushi/toml" ) type Config struct { @@ -17,14 +20,10 @@ type Config struct { BfsAddr string // download domain Domain string + // location prefix + Prefix string // file MaxFileSize int - // aliyun - AliyunKeyId string - AliyunKeySecret string - // netcenter - NetUserName string - NetPasswd string // purge channel PurgeMaxSize int } @@ -53,6 +52,14 @@ func NewConfig(conf string) (c *Config, err error) { if blob, err = ioutil.ReadAll(file); err != nil { return } - err = toml.Unmarshal(blob, c) + if err = toml.Unmarshal(blob, c); err != nil { + return + } + // http://domain/ covert to http://domain + c.Domain = strings.TrimRight(c.Domain, "/") + // bfs,/bfs,/bfs/ convert to /bfs/ + if c.Prefix != "" { + c.Prefix = path.Join("/", c.Prefix) + "/" + } return } diff --git a/proxy/http_api.go b/proxy/http_api.go index 318300d..73f3a0e 100644 --- a/proxy/http_api.go +++ b/proxy/http_api.go @@ -4,11 +4,11 @@ import ( "bfs/libs/errors" "bfs/proxy/auth" "bfs/proxy/bfs" + ibucket "bfs/proxy/bucket" "bfs/proxy/conf" "crypto/sha1" "encoding/hex" "encoding/json" - log "github.com/golang/glog" "io/ioutil" "net/http" "os" @@ -16,6 +16,8 @@ import ( "strconv" "strings" "time" + + log "github.com/golang/glog" ) const ( @@ -23,27 +25,34 @@ const ( _httpServerWriteTimeout = 2 * time.Second ) -// Server http_server -type Server struct { +type server struct { bfs *bfs.Bfs + bucket *ibucket.Bucket auth *auth.Auth - config *conf.Config + c *conf.Config } -// Init init the http module. -func Init(config *conf.Config) (s *Server, err error) { - s = &Server{} - s.config = config - s.bfs = bfs.NewBfs(config) - if s.auth, err = auth.NewAuth(config); err != nil { +// StartApi init the http module. +func StartApi(c *conf.Config) (err error) { + var s = &server{} + s.c = c + s.bfs = bfs.NewBfs(c) + if s.bucket, err = ibucket.NewBucket(); err != nil { + return + } + if s.auth, err = auth.NewAuth(c); err != nil { return } go func() { mux := http.NewServeMux() - mux.HandleFunc("/", s.httpDo) + mux.HandleFunc("/", s.do) mux.HandleFunc("/ping", s.ping) - server := &http.Server{Addr: config.HttpAddr, Handler: mux, - ReadTimeout: _httpServerReadTimeout, WriteTimeout: _httpServerWriteTimeout} + server := &http.Server{ + Addr: c.HttpAddr, + Handler: mux, + ReadTimeout: _httpServerReadTimeout, + WriteTimeout: _httpServerWriteTimeout, + } if err := server.ListenAndServe(); err != nil { return } @@ -51,178 +60,222 @@ func Init(config *conf.Config) (s *Server, err error) { return } -func (s *Server) httpDo(wr http.ResponseWriter, r *http.Request) { +type handler func(*ibucket.Item, string, string, http.ResponseWriter, *http.Request) + +func (s *server) do(wr http.ResponseWriter, r *http.Request) { var ( - err error + bucket string + file string + token string + status int + err error + h handler + item *ibucket.Item + upload = false + read = false ) - if err = s.auth.CheckAuth(r); err != nil { - if uerr, ok := (err).(errors.Error); ok { - http.Error(wr, "auth failed", int(uerr)) - } - return - } switch r.Method { - case "HEAD": - s.download(wr, r) - case "GET": - s.download(wr, r) + case "HEAD", "GET": + h = s.download + read = true case "PUT": - s.upload(wr, r) + h = s.upload + upload = true case "DELETE": - s.delete(wr, r) + h = s.delete + default: + http.Error(wr, "", http.StatusMethodNotAllowed) + return } - return -} - -// download -func (s *Server) download(wr http.ResponseWriter, r *http.Request) { - var ( - content []byte - bucket string - filename string - ss []string - start time.Time - err error - ) - start = time.Now() - log.Infof("download url: %s", r.URL.String()) - if !strings.HasPrefix(r.URL.Path, "/bfs") { - http.Error(wr, "bad request", http.StatusBadRequest) + if bucket, file, status = s.parseURI(r, upload); status != http.StatusOK { + http.Error(wr, "", status) return } - ss = strings.Split(strings.TrimPrefix(r.URL.Path, "/bfs")[1:], "/") - if bucket = ss[0]; bucket == "" { - http.Error(wr, "bad request", http.StatusBadRequest) + if item, err = s.bucket.Get(bucket); err != nil { + log.Errorf("bucket.Get(%s) error(%v)", bucket, err) + http.Error(wr, "", http.StatusNotFound) return } - if len(ss) >= 2 { - filename = r.URL.Path[len(bucket)+len("/bfs")+2:] - if filename == "" { - http.Error(wr, "bad request", http.StatusBadRequest) + // item not public must use authorize + if !item.Public(read) { + token = r.URL.Query().Get("token") + if token == "" { + token = r.Header.Get("Authorization") + } + if err = s.auth.Authorize(item, r.Method, bucket, file, token); err != nil { + log.Errorf("authorize(%s, %s, %s, %s) by item: %v error(%v)", r.Method, bucket, file, token, item, err) + http.Error(wr, "", http.StatusUnauthorized) return } } - if content, err = s.bfs.Get(bucket, filename); err != nil { - log.Errorf("s.bfs.Get error(%v), bucket: %s, filename: %s, time long:%f", err, bucket, filename, time.Now().Sub(start).Seconds()) - if err == errors.ErrNeedleNotExist { - http.Error(wr, "404", http.StatusNotFound) + h(item, bucket, file, wr, r) + return +} + +func httpLog(method, uri string, bucket, file *string, start time.Time, status *int, err *error) { + log.Infof("%s: %s, bucket: %s, file: %s, time: %f, status: %d, error(%v)", + method, uri, *bucket, *file, time.Now().Sub(start).Seconds(), *status, *err) +} + +// set reponse header. +func setCode(wr http.ResponseWriter, status *int) { + wr.Header().Set("Code", strconv.Itoa(*status)) +} + +// parseURI get uri's bucket and filename. +func (s *server) parseURI(r *http.Request, upload bool) (bucket, file string, status int) { + var b, e int + status = http.StatusOK + if s.c.Prefix == "" { + // uri: /bucket/file... + // [1: + b = 1 + } else { + // uri: /prefix/bucket/file... + // [len(prefix): + if !strings.HasPrefix(r.URL.Path, s.c.Prefix) { + log.Errorf("parseURI(%s) error, no prefix: %s", r.URL.Path, s.c.Prefix) + status = http.StatusBadRequest return } - http.Error(wr, "Internal Server error", http.StatusInternalServerError) - return + b = len(s.c.Prefix) } - ss = strings.Split(filename, ".") - wr.Header().Set("Content-Type", http.DetectContentType(content)) - wr.Header().Set("Content-Length", strconv.Itoa(len(content))) - wr.Header().Set("Server", "Bfs") - if r.Method == "GET" { - wr.Write(content) + if e = strings.Index(r.URL.Path[b:], "/"); e < 1 { + bucket = r.URL.Path[b:] + file = "" + } else { + bucket = r.URL.Path[b : b+e] + file = r.URL.Path[b+e+1:] // skip "/" + } + if bucket == "" || (file == "" && !upload) { + log.Errorf("parseURI(%s) error, bucket: %s or file: %s empty", r.URL.Path, bucket, file) + status = http.StatusBadRequest + } + return +} + +// gentRI get uri by bucket and file. +func (s *server) getURI(bucket, file string) (uri string) { + // http://domain/prefix/bucket/file + uri = s.c.Domain + path.Join(s.c.Prefix, bucket, file) + return +} + +// download. +func (s *server) download(item *ibucket.Item, bucket, file string, wr http.ResponseWriter, r *http.Request) { + var ( + data []byte + err error + start = time.Now() + status = http.StatusOK + ) + defer httpLog("download", r.URL.Path, &bucket, &file, start, &status, &err) + if data, err = s.bfs.Get(bucket, file); err != nil { + if err == errors.ErrNeedleNotExist { + status = http.StatusNotFound + } else { + status = http.StatusInternalServerError + } + http.Error(wr, "", status) + } else { + wr.Header().Set("Content-Type", http.DetectContentType(data)) + wr.Header().Set("Content-Length", strconv.Itoa(len(data))) + wr.Header().Set("Server", "bfs") + if r.Method == "GET" { + _, err = wr.Write(data) + } } - log.Infof("download url:%s, time long:%f", r.URL.String(), time.Now().Sub(start).Seconds()) return } +// ret reponse header. +func retCode(wr http.ResponseWriter, status *int) { + wr.Header().Set("Code", strconv.Itoa(*status)) +} + // upload upload file. -func (s *Server) upload(wr http.ResponseWriter, r *http.Request) { +func (s *server) upload(item *ibucket.Item, bucket, file string, wr http.ResponseWriter, r *http.Request) { var ( + ok bool body []byte - ss []string - start time.Time mine string - bucket string - filename string location string sha1sum string + ext string sha [sha1.Size]byte err error + uerr errors.Error + status = http.StatusOK + start = time.Now() ) - start = time.Now() - log.Infof("upload url:%s", r.URL.String()) - mine = r.Header.Get("Content-Type") - if mine == "" { - wr.Header().Set("Code", strconv.Itoa(http.StatusBadRequest)) + defer httpLog("upload", r.URL.Path, &bucket, &file, start, &status, &err) + defer retCode(wr, &status) + if mine = r.Header.Get("Content-Type"); mine == "" { + status = http.StatusBadRequest return } + if ext = path.Base(mine); ext == "jpeg" { + ext = "jpg" + } if body, err = ioutil.ReadAll(r.Body); err != nil { + status = http.StatusBadRequest log.Errorf("ioutil.ReadAll(r.Body) error(%s)", err) - wr.Header().Set("Code", strconv.Itoa(http.StatusBadRequest)) return } r.Body.Close() - // check content length - if len(body) > s.config.MaxFileSize { - wr.Header().Set("Code", strconv.Itoa(http.StatusRequestEntityTooLarge)) + if len(body) > s.c.MaxFileSize { + status = http.StatusRequestEntityTooLarge return } sha = sha1.Sum(body) sha1sum = hex.EncodeToString(sha[:]) - ss = strings.Split(r.URL.Path[1:], "/") - if bucket = ss[0]; bucket == "" { - wr.Header().Set("Code", strconv.Itoa(http.StatusBadRequest)) - return - } - if len(ss) >= 2 { - filename = r.URL.Path[len(bucket)+2:] + // if empty filename or endwith "/": dir + if file == "" || strings.HasSuffix(file, "/") { + file += sha1sum + "." + ext } - if filename == "" { - ext := mine[strings.IndexByte(mine, '/')+1:] - if ext == "jpeg" { - ext = "jpg" + if err = s.bfs.Upload(bucket, file, mine, sha1sum, body); err != nil && err != errors.ErrNeedleExist { + if uerr, ok = (err).(errors.Error); ok { + status = int(uerr) + } else { + status = http.StatusInternalServerError } - filename = sha1sum + "." + ext - } - if err = s.bfs.Upload(bucket, filename, mine, sha1sum, body); err != nil && err != errors.ErrNeedleExist { - log.Errorf("s.bfs.Upload error(%v), bucket: %s, filename: %s, time long:%f", err, bucket, filename, time.Now().Sub(start).Seconds()) - wr.Header().Set("Code", strconv.Itoa(http.StatusInternalServerError)) return } - location = s.config.Domain + path.Join(bucket, filename) - wr.Header().Set("Code", strconv.Itoa(http.StatusOK)) + location = s.getURI(bucket, file) wr.Header().Set("Location", location) wr.Header().Set("ETag", sha1sum) - log.Infof("upload url:%s, location: %s , time long:%f", r.URL.String(), location, time.Now().Sub(start).Seconds()) return } // delete -func (s *Server) delete(wr http.ResponseWriter, r *http.Request) { +func (s *server) delete(item *ibucket.Item, bucket, file string, wr http.ResponseWriter, r *http.Request) { var ( - bucket string - filename string - ss []string - start time.Time - err error + ok bool + err error + uerr errors.Error + status = http.StatusOK + start = time.Now() ) - start = time.Now() - log.Infof("delete url:%s", r.URL.String()) - ss = strings.Split(r.URL.Path[1:], "/") - if bucket = ss[0]; bucket == "" { - wr.Header().Set("Code", strconv.Itoa(http.StatusRequestEntityTooLarge)) - return - } - if len(ss) >= 2 { - filename = r.URL.Path[len(bucket)+2:] - if filename == "" { - wr.Header().Set("Code", strconv.Itoa(http.StatusBadRequest)) - return - } - } - if err = s.bfs.Delete(bucket, filename); err != nil { - log.Errorf("s.bfs.Delete error(%v), bucket: %s, filename: %s, time long:%f", err, bucket, filename, time.Now().Sub(start).Seconds()) + defer httpLog("delete", r.URL.Path, &bucket, &file, start, &status, &err) + if err = s.bfs.Delete(bucket, file); err != nil { if err == errors.ErrNeedleNotExist { - http.Error(wr, "404", http.StatusNotFound) - return + status = http.StatusNotFound + http.Error(wr, "", status) + } else { + if uerr, ok = (err).(errors.Error); ok { + status = int(uerr) + } else { + status = http.StatusInternalServerError + } } - wr.Header().Set("Code", strconv.Itoa(http.StatusInternalServerError)) - return + } else { + wr.Header().Set("Code", strconv.Itoa(status)) } - wr.Header().Set("Code", strconv.Itoa(http.StatusOK)) - log.Infof("delete url:%s, time long:%f", r.URL.String(), time.Now().Sub(start).Seconds()) return } // monitorPing sure program now runs correctly, when return http status 200. -func (s *Server) ping(wr http.ResponseWriter, r *http.Request) { +func (s *server) ping(wr http.ResponseWriter, r *http.Request) { var ( byteJson []byte f *os.File @@ -235,7 +288,7 @@ func (s *Server) ping(wr http.ResponseWriter, r *http.Request) { f.Close() } if err = s.bfs.Ping(); err != nil { - http.Error(wr, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + http.Error(wr, "", http.StatusInternalServerError) res["code"] = http.StatusInternalServerError } if byteJson, err = json.Marshal(res); err != nil { diff --git a/proxy/http_api_test.go b/proxy/http_api_test.go index f189a27..9656680 100644 --- a/proxy/http_api_test.go +++ b/proxy/http_api_test.go @@ -1 +1,48 @@ package main + +import ( + "flag" + "strings" +) + +func dfs_recur(bucket, dirname string) { + var ( + exit bool + dir string + file string + files []string + dirs []string + ) + + dirs, files, _ = scanDir(bucket, dirname) + for _, dir = range dirs { + dir = dirname + dir + dfs_recur(bucket, dir) + } + for _, file = range files { + delFile(bucket, file) + } + return +} + +func delFile(bucket, filename string) (err error) { + if strings.HasSufix(filename, "/") { + s.bfs.Delete(bucket, filename) + } +} + +func scanDir(bucket, filename string) (keys []string, err error) { + +} + +func main() { + var ( + bucket string + filename string + ) + flag.Parse() + bucket = "test" + filename = "aaaa" + + dfs(bucket, filename, delFile, scanDir) +} diff --git a/proxy/main.go b/proxy/main.go index b017456..f9fd3a3 100644 --- a/proxy/main.go +++ b/proxy/main.go @@ -36,7 +36,7 @@ func main() { } runtime.GOMAXPROCS(runtime.NumCPU()) // init http - if _, err = Init(c); err != nil { + if err = StartApi(c); err != nil { log.Error("http.Init() error(%v)", err) panic(err) } diff --git a/proxy/proxy.toml b/proxy/proxy.toml index 7774677..997f353 100644 --- a/proxy/proxy.toml +++ b/proxy/proxy.toml @@ -4,9 +4,12 @@ PprofListen = "localhost:2231" HttpAddr = "localhost:2232" -BfsAddr = "localhost:6065" +BfsAddr = "localhost:2235" -Domain = "http://localhost:2232/bfs/" +Domain = "http://localhost:2232/" + +Prefix = "/bfs/" MaxFileSize = 20971520 +PurgeMaxSize = 100000