2020-03-23 11:40:02 +00:00
|
|
|
package stores
|
|
|
|
|
|
|
|
import (
|
2020-03-23 22:43:38 +00:00
|
|
|
"encoding/json"
|
2020-03-23 11:40:02 +00:00
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
|
|
|
|
"github.com/gorilla/mux"
|
|
|
|
logging "github.com/ipfs/go-log/v2"
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
|
2020-09-30 17:32:19 +00:00
|
|
|
"github.com/filecoin-project/lotus/extern/sector-storage/storiface"
|
2020-08-17 13:26:18 +00:00
|
|
|
"github.com/filecoin-project/lotus/extern/sector-storage/tarutil"
|
2020-11-16 18:20:18 +00:00
|
|
|
|
|
|
|
"github.com/filecoin-project/specs-storage/storage"
|
2020-03-23 11:40:02 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var log = logging.Logger("stores")
|
|
|
|
|
|
|
|
type FetchHandler struct {
|
|
|
|
*Local
|
|
|
|
}
|
|
|
|
|
|
|
|
func (handler *FetchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // /remote/
|
|
|
|
mux := mux.NewRouter()
|
|
|
|
|
2020-03-23 22:43:38 +00:00
|
|
|
mux.HandleFunc("/remote/stat/{id}", handler.remoteStatFs).Methods("GET")
|
2020-03-23 11:40:02 +00:00
|
|
|
mux.HandleFunc("/remote/{type}/{id}", handler.remoteGetSector).Methods("GET")
|
|
|
|
mux.HandleFunc("/remote/{type}/{id}", handler.remoteDeleteSector).Methods("DELETE")
|
|
|
|
|
|
|
|
mux.ServeHTTP(w, r)
|
|
|
|
}
|
|
|
|
|
2020-03-23 22:43:38 +00:00
|
|
|
func (handler *FetchHandler) remoteStatFs(w http.ResponseWriter, r *http.Request) {
|
|
|
|
vars := mux.Vars(r)
|
|
|
|
id := ID(vars["id"])
|
|
|
|
|
2020-03-24 20:28:07 +00:00
|
|
|
st, err := handler.Local.FsStat(r.Context(), id)
|
2020-03-23 22:43:38 +00:00
|
|
|
switch err {
|
|
|
|
case errPathNotFound:
|
|
|
|
w.WriteHeader(404)
|
|
|
|
return
|
|
|
|
case nil:
|
|
|
|
break
|
|
|
|
default:
|
|
|
|
w.WriteHeader(500)
|
|
|
|
log.Errorf("%+v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := json.NewEncoder(w).Encode(&st); err != nil {
|
|
|
|
log.Warnf("error writing stat response: %+v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-23 11:40:02 +00:00
|
|
|
func (handler *FetchHandler) remoteGetSector(w http.ResponseWriter, r *http.Request) {
|
|
|
|
log.Infof("SERVE GET %s", r.URL)
|
|
|
|
vars := mux.Vars(r)
|
|
|
|
|
2020-09-06 16:54:00 +00:00
|
|
|
id, err := storiface.ParseSectorID(vars["id"])
|
2020-03-23 11:40:02 +00:00
|
|
|
if err != nil {
|
2020-09-28 20:05:51 +00:00
|
|
|
log.Errorf("%+v", err)
|
2020-03-23 11:40:02 +00:00
|
|
|
w.WriteHeader(500)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ft, err := ftFromString(vars["type"])
|
|
|
|
if err != nil {
|
2020-09-28 20:05:51 +00:00
|
|
|
log.Errorf("%+v", err)
|
2020-03-24 23:37:40 +00:00
|
|
|
w.WriteHeader(500)
|
2020-03-23 11:40:02 +00:00
|
|
|
return
|
|
|
|
}
|
2020-05-08 16:54:06 +00:00
|
|
|
|
2020-06-04 19:00:16 +00:00
|
|
|
// The caller has a lock on this sector already, no need to get one here
|
|
|
|
|
2020-05-08 16:54:06 +00:00
|
|
|
// passing 0 spt because we don't allocate anything
|
2020-11-04 20:29:08 +00:00
|
|
|
si := storage.SectorRef{
|
|
|
|
ID: id,
|
|
|
|
ProofType: 0,
|
|
|
|
}
|
|
|
|
|
|
|
|
paths, _, err := handler.Local.AcquireSector(r.Context(), si, ft, storiface.FTNone, storiface.PathStorage, storiface.AcquireMove)
|
2020-03-23 11:40:02 +00:00
|
|
|
if err != nil {
|
2020-09-28 20:05:51 +00:00
|
|
|
log.Errorf("%+v", err)
|
2020-03-24 23:37:40 +00:00
|
|
|
w.WriteHeader(500)
|
2020-03-23 11:40:02 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-07-06 16:36:44 +00:00
|
|
|
// TODO: reserve local storage here
|
|
|
|
|
2020-09-06 16:54:00 +00:00
|
|
|
path := storiface.PathByType(paths, ft)
|
2020-03-23 11:40:02 +00:00
|
|
|
if path == "" {
|
|
|
|
log.Error("acquired path was empty")
|
|
|
|
w.WriteHeader(500)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
stat, err := os.Stat(path)
|
|
|
|
if err != nil {
|
2020-09-28 20:05:51 +00:00
|
|
|
log.Errorf("%+v", err)
|
2020-03-23 11:40:02 +00:00
|
|
|
w.WriteHeader(500)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var rd io.Reader
|
|
|
|
if stat.IsDir() {
|
|
|
|
rd, err = tarutil.TarDirectory(path)
|
|
|
|
w.Header().Set("Content-Type", "application/x-tar")
|
|
|
|
} else {
|
2020-08-16 10:40:35 +00:00
|
|
|
rd, err = os.OpenFile(path, os.O_RDONLY, 0644) // nolint
|
2020-03-23 11:40:02 +00:00
|
|
|
w.Header().Set("Content-Type", "application/octet-stream")
|
|
|
|
}
|
|
|
|
if err != nil {
|
2020-09-28 20:05:51 +00:00
|
|
|
log.Errorf("%+v", err)
|
2020-03-23 11:40:02 +00:00
|
|
|
w.WriteHeader(500)
|
|
|
|
return
|
|
|
|
}
|
2020-12-29 02:07:28 +00:00
|
|
|
if !stat.IsDir() {
|
2021-04-01 14:40:11 +00:00
|
|
|
defer func() {
|
|
|
|
if err := rd.(*os.File).Close(); err != nil {
|
|
|
|
log.Errorf("closing source file: %+v", err)
|
|
|
|
}
|
|
|
|
}()
|
2020-12-29 02:07:28 +00:00
|
|
|
}
|
2020-03-23 11:40:02 +00:00
|
|
|
|
|
|
|
w.WriteHeader(200)
|
2020-12-29 02:07:28 +00:00
|
|
|
if _, err := io.CopyBuffer(w, rd, make([]byte, CopyBuf)); err != nil {
|
2020-09-28 20:05:51 +00:00
|
|
|
log.Errorf("%+v", err)
|
2020-03-23 11:40:02 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (handler *FetchHandler) remoteDeleteSector(w http.ResponseWriter, r *http.Request) {
|
|
|
|
log.Infof("SERVE DELETE %s", r.URL)
|
|
|
|
vars := mux.Vars(r)
|
|
|
|
|
2020-09-06 16:54:00 +00:00
|
|
|
id, err := storiface.ParseSectorID(vars["id"])
|
2020-03-23 11:40:02 +00:00
|
|
|
if err != nil {
|
2020-09-28 20:05:51 +00:00
|
|
|
log.Errorf("%+v", err)
|
2020-03-23 11:40:02 +00:00
|
|
|
w.WriteHeader(500)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ft, err := ftFromString(vars["type"])
|
|
|
|
if err != nil {
|
2020-09-28 20:05:51 +00:00
|
|
|
log.Errorf("%+v", err)
|
2020-03-24 23:37:40 +00:00
|
|
|
w.WriteHeader(500)
|
2020-03-23 11:40:02 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-05-13 18:45:14 +00:00
|
|
|
if err := handler.Remove(r.Context(), id, ft, false); err != nil {
|
2020-09-28 20:05:51 +00:00
|
|
|
log.Errorf("%+v", err)
|
2020-03-23 11:40:02 +00:00
|
|
|
w.WriteHeader(500)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-06 16:54:00 +00:00
|
|
|
func ftFromString(t string) (storiface.SectorFileType, error) {
|
2020-03-23 11:40:02 +00:00
|
|
|
switch t {
|
2020-09-06 16:54:00 +00:00
|
|
|
case storiface.FTUnsealed.String():
|
|
|
|
return storiface.FTUnsealed, nil
|
|
|
|
case storiface.FTSealed.String():
|
|
|
|
return storiface.FTSealed, nil
|
|
|
|
case storiface.FTCache.String():
|
|
|
|
return storiface.FTCache, nil
|
2020-03-23 11:40:02 +00:00
|
|
|
default:
|
|
|
|
return 0, xerrors.Errorf("unknown sector file type: '%s'", t)
|
|
|
|
}
|
|
|
|
}
|