package console import ( "bytes" "context" "encoding/json" "errors" "io" "net/http" "os" "strings" "github.com/superfly/ltx" "github.com/carlosframework/platform/internal/dbdoor" ) // replicaDoer serves the db door's two tails (ListTail, GetTail) from rd in // process, so the console's own --from restore runs through // dbdoor.RestoreToTarget: its retry, its private 0700 directory, its // CheckDB, the same code carlos db pull runs (seeded-instances spec ยง4 // step 6). The listing is the door's own (listReplicaLevel). // // It answers the status codes the client reads and no sentences: a tail // that is not a coordinate, or a file that is not there, is a 404 (the // client's os.ErrNotExist), and a range the door would refuse is a 416. // A failed bucket read is returned as the error it is. func replicaDoer(rd replicaReader) dbdoor.Doer { return func(ctx context.Context, tail string, h http.Header) (*http.Response, error) { rest, ok := strings.CutPrefix(tail, "/ltx/") if !ok { return doerResponse(http.StatusNotFound, nil), nil } parts := strings.Split(rest, "/") level, ok := parseDBLevel(parts[0]) if !ok || len(parts) > 2 { return doerResponse(http.StatusNotFound, nil), nil } if len(parts) == 1 { out, err := listReplicaLevel(ctx, rd, level) if err != nil { return nil, err } body, err := json.Marshal(out) if err != nil { return nil, err } return doerResponse(http.StatusOK, io.NopCloser(bytes.NewReader(body))), nil } lo, hi, err := dbdoor.ParseSpan(parts[1]) if err != nil { return doerResponse(http.StatusNotFound, nil), nil } off, size, err := dbdoor.ParseRange(h.Get("Range")) if err != nil { return doerResponse(http.StatusRequestedRangeNotSatisfiable, nil), nil } rc, err := rd.OpenLTXFile(ctx, level, ltx.TXID(lo), ltx.TXID(hi), off, size) if errors.Is(err, os.ErrNotExist) { return doerResponse(http.StatusNotFound, nil), nil } if err != nil { return nil, err } code := http.StatusOK if h.Get("Range") != "" { code = http.StatusPartialContent } return doerResponse(code, rc), nil } } // doerResponse is one in-process answer. A nil body is an empty one, so // the client can always close what it is handed. func doerResponse(code int, body io.ReadCloser) *http.Response { if body == nil { body = io.NopCloser(strings.NewReader("")) } return &http.Response{StatusCode: code, Header: http.Header{}, Body: body} }