123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- 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, ®istry.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
- }
|