github.com/ethersphere/bee/v2@v2.2.0/pkg/api/tag.go (about)

     1  // Copyright 2020 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package api
     6  
     7  import (
     8  	"encoding/json"
     9  	"errors"
    10  	"io"
    11  	"net/http"
    12  	"time"
    13  
    14  	"github.com/ethersphere/bee/v2/pkg/jsonhttp"
    15  	storage "github.com/ethersphere/bee/v2/pkg/storage"
    16  	storer "github.com/ethersphere/bee/v2/pkg/storer"
    17  	"github.com/ethersphere/bee/v2/pkg/swarm"
    18  	"github.com/gorilla/mux"
    19  )
    20  
    21  type tagRequest struct {
    22  	Address swarm.Address `json:"address,omitempty"`
    23  }
    24  
    25  type tagResponse struct {
    26  	Split     uint64        `json:"split"`
    27  	Seen      uint64        `json:"seen"`
    28  	Stored    uint64        `json:"stored"`
    29  	Sent      uint64        `json:"sent"`
    30  	Synced    uint64        `json:"synced"`
    31  	Uid       uint64        `json:"uid"`
    32  	Address   swarm.Address `json:"address"`
    33  	StartedAt time.Time     `json:"startedAt"`
    34  }
    35  
    36  func newTagResponse(tag storer.SessionInfo) tagResponse {
    37  	return tagResponse{
    38  		Split:     tag.Split,
    39  		Seen:      tag.Seen,
    40  		Stored:    tag.Stored,
    41  		Sent:      tag.Sent,
    42  		Synced:    tag.Synced,
    43  		Uid:       tag.TagID,
    44  		Address:   tag.Address,
    45  		StartedAt: time.Unix(0, tag.StartedAt),
    46  	}
    47  }
    48  
    49  type listTagsResponse struct {
    50  	Tags []tagResponse `json:"tags"`
    51  }
    52  
    53  func (s *Service) createTagHandler(w http.ResponseWriter, r *http.Request) {
    54  	logger := s.logger.WithName("post_tag").Build()
    55  
    56  	tag, err := s.storer.NewSession()
    57  	if err != nil {
    58  		logger.Debug("create tag failed", "error", err)
    59  		logger.Error(nil, "create tag failed")
    60  		jsonhttp.InternalServerError(w, "cannot create tag")
    61  		return
    62  	}
    63  	w.Header().Set("Cache-Control", "no-cache, private, max-age=0")
    64  	jsonhttp.Created(w, newTagResponse(tag))
    65  }
    66  
    67  func (s *Service) getTagHandler(w http.ResponseWriter, r *http.Request) {
    68  	logger := s.logger.WithName("get_tag").Build()
    69  
    70  	paths := struct {
    71  		TagID uint64 `map:"id" validate:"required"`
    72  	}{}
    73  	if response := s.mapStructure(mux.Vars(r), &paths); response != nil {
    74  		response("invalid path params", logger, w)
    75  		return
    76  	}
    77  
    78  	tag, err := s.storer.Session(paths.TagID)
    79  	if err != nil {
    80  		if errors.Is(err, storage.ErrNotFound) {
    81  			logger.Debug("tag not found", "tag_id", paths.TagID)
    82  			logger.Error(nil, "tag not found")
    83  			jsonhttp.NotFound(w, "tag not present")
    84  			return
    85  		}
    86  		logger.Debug("get tag failed", "tag_id", paths.TagID, "error", err)
    87  		logger.Error(nil, "get tag failed", "tag_id", paths.TagID)
    88  		jsonhttp.InternalServerError(w, "cannot get tag")
    89  		return
    90  	}
    91  
    92  	w.Header().Set("Cache-Control", "no-cache, private, max-age=0")
    93  	jsonhttp.OK(w, newTagResponse(tag))
    94  }
    95  
    96  func (s *Service) deleteTagHandler(w http.ResponseWriter, r *http.Request) {
    97  	logger := s.logger.WithName("delete_tag").Build()
    98  
    99  	paths := struct {
   100  		TagID uint64 `map:"id" validate:"required"`
   101  	}{}
   102  	if response := s.mapStructure(mux.Vars(r), &paths); response != nil {
   103  		response("invalid path params", logger, w)
   104  		return
   105  	}
   106  
   107  	if err := s.storer.DeleteSession(paths.TagID); err != nil {
   108  		if errors.Is(err, storage.ErrNotFound) {
   109  			logger.Debug("tag not found", "tag_id", paths.TagID)
   110  			logger.Error(nil, "tag not found")
   111  			jsonhttp.NotFound(w, "tag not present")
   112  			return
   113  		}
   114  		logger.Debug("get tag failed", "tag_id", paths.TagID, "error", err)
   115  		logger.Error(nil, "get tag failed", "tag_id", paths.TagID)
   116  		jsonhttp.InternalServerError(w, "cannot get tag")
   117  		return
   118  	}
   119  
   120  	jsonhttp.NoContent(w)
   121  }
   122  
   123  func (s *Service) doneSplitHandler(w http.ResponseWriter, r *http.Request) {
   124  	logger := s.logger.WithName("patch_tag").Build()
   125  
   126  	paths := struct {
   127  		TagID uint64 `map:"id" validate:"required"`
   128  	}{}
   129  	if response := s.mapStructure(mux.Vars(r), &paths); response != nil {
   130  		response("invalid path params", logger, w)
   131  		return
   132  	}
   133  
   134  	body, err := io.ReadAll(r.Body)
   135  	if err != nil {
   136  		if jsonhttp.HandleBodyReadError(err, w) {
   137  			return
   138  		}
   139  		logger.Debug("read request body failed", "error", err)
   140  		logger.Error(nil, "read request body failed")
   141  		jsonhttp.InternalServerError(w, "cannot read request")
   142  		return
   143  	}
   144  
   145  	tagr := tagRequest{}
   146  	if len(body) > 0 {
   147  		err = json.Unmarshal(body, &tagr)
   148  		if err != nil {
   149  			logger.Debug("unmarshal tag name failed", "error", err)
   150  			logger.Error(nil, "unmarshal tag name failed")
   151  			jsonhttp.InternalServerError(w, "error unmarshaling metadata")
   152  			return
   153  		}
   154  	}
   155  
   156  	tag, err := s.storer.Session(paths.TagID)
   157  	if err != nil {
   158  		if errors.Is(err, storage.ErrNotFound) {
   159  			logger.Debug("tag not found", "tag_id", paths.TagID)
   160  			logger.Error(nil, "tag not found")
   161  			jsonhttp.NotFound(w, "tag not present")
   162  			return
   163  		}
   164  		logger.Debug("get tag failed", "tag_id", paths.TagID, "error", err)
   165  		logger.Error(nil, "get tag failed", "tag_id", paths.TagID)
   166  		jsonhttp.InternalServerError(w, "cannot get tag")
   167  		return
   168  	}
   169  
   170  	putter, err := s.storer.Upload(r.Context(), false, tag.TagID)
   171  	if err != nil {
   172  		logger.Debug("get tag failed", "tag_id", paths.TagID, "error", err)
   173  		logger.Error(nil, "get tag failed", "tag_id", paths.TagID)
   174  		jsonhttp.InternalServerError(w, "cannot get tag")
   175  		return
   176  	}
   177  
   178  	err = putter.Done(tagr.Address)
   179  	if err != nil {
   180  		logger.Debug("done split failed", "address", tagr.Address, "error", err)
   181  		logger.Error(nil, "done split failed", "address", tagr.Address)
   182  		jsonhttp.InternalServerError(w, "done split: failed")
   183  		return
   184  	}
   185  	jsonhttp.OK(w, "ok")
   186  }
   187  
   188  func (s *Service) listTagsHandler(w http.ResponseWriter, r *http.Request) {
   189  	logger := s.logger.WithName("get_tags").Build()
   190  
   191  	queries := struct {
   192  		Offset int `map:"offset"`
   193  		Limit  int `map:"limit"`
   194  	}{
   195  		Limit: 100, // Default limit.
   196  	}
   197  	if response := s.mapStructure(r.URL.Query(), &queries); response != nil {
   198  		response("invalid query params", logger, w)
   199  		return
   200  	}
   201  
   202  	tagList, err := s.storer.ListSessions(queries.Offset, queries.Limit)
   203  	if err != nil {
   204  		logger.Debug("listing failed", "offset", queries.Offset, "limit", queries.Limit, "error", err)
   205  		logger.Error(nil, "listing failed")
   206  		jsonhttp.InternalServerError(w, err)
   207  		return
   208  	}
   209  
   210  	tags := make([]tagResponse, len(tagList))
   211  	for i, t := range tagList {
   212  		tags[i] = newTagResponse(t)
   213  	}
   214  
   215  	jsonhttp.OK(w, listTagsResponse{
   216  		Tags: tags,
   217  	})
   218  }