ollama/x/api/api.go

117 lines
2.4 KiB
Go

package api
import (
"errors"
"fmt"
"net/http"
"os"
"github.com/ollama/ollama/x/build"
"github.com/ollama/ollama/x/client/ollama/apitype"
"github.com/ollama/ollama/x/oweb"
"github.com/ollama/ollama/x/registry"
regtype "github.com/ollama/ollama/x/registry"
)
// Common API Errors
var (
errUnqualifiedRef = oweb.Invalid("invalid", "name", "must be fully qualified")
errRefNotFound = oweb.Invalid("not_found", "name", "no such model")
)
type Server struct {
Build *build.Server
}
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
oweb.Serve(s.serveHTTP, w, r)
}
func (s *Server) serveHTTP(w http.ResponseWriter, r *http.Request) error {
switch r.URL.Path {
case "/v1/push":
return s.handlePush(w, r)
default:
return oweb.ErrNotFound
}
}
func want(r *http.Request, method, path string) bool {
return r.Method == method && r.URL.Path == path
}
func (s *Server) handlePush(_ http.ResponseWriter, r *http.Request) error {
if r.Method != "POST" {
return oweb.ErrMethodNotAllowed
}
params, err := oweb.DecodeJSON[apitype.PushRequest](r.Body)
if err != nil {
return err
}
if params.Name == "" {
return oweb.Missing("name")
}
const registryURLTODO = "http://localhost:8888"
man, err := s.Build.ManifestData(params.Name)
if err != nil {
if errors.Is(err, build.ErrNotFound) {
return errRefNotFound
}
return err
}
c := registry.Client{BaseURL: registryURLTODO}
requirements, err := c.Push(r.Context(), params.Name, man, nil)
if err != nil {
return err
}
var uploads []regtype.CompletePart
for _, rq := range requirements {
l, err := s.Build.LayerFile(rq.Digest)
if err != nil {
return err
}
err = func() error {
f, err := os.Open(l)
if err != nil {
return err
}
defer f.Close()
etag, err := registry.PushLayer(r.Context(), rq.URL, rq.Offset, rq.Size, f)
if err != nil {
return err
}
uploads = append(uploads, regtype.CompletePart{
URL: rq.URL,
ETag: etag,
})
return nil
}()
if err != nil {
return err
}
}
// commit the manifest to the registry
requirements, err = c.Push(r.Context(), params.Name, man, &registry.PushParams{
CompleteParts: uploads,
})
if err != nil {
return err
}
for _, r := range requirements {
err = errors.Join(err, fmt.Errorf("push failed for %q", r.Digest))
}
return err
}
func (s *Server) handlePull(w http.ResponseWriter, r *http.Request) error {
return oweb.ErrNotFound
}