package mongo import ( "context" "fmt" "io" "github.com/gomods/athens/pkg/errors" "github.com/gomods/athens/pkg/observ" "github.com/gomods/athens/pkg/storage" "go.mongodb.org/mongo-driver/mongo/gridfs" "go.mongodb.org/mongo-driver/mongo/options" ) // Save stores a module in mongo storage. func (s *ModuleStore) Save(ctx context.Context, module, version string, mod []byte, zip io.Reader, zipMD5, info []byte) error { const op errors.Op = "mongo.Save" ctx, span := observ.StartSpan(ctx, op.String()) defer span.End() exists, err := s.Exists(ctx, module, version) if err != nil { return errors.E(op, err, errors.M(module), errors.V(version)) } if exists { return errors.E(op, "already exists", errors.M(module), errors.V(version), errors.KindAlreadyExists) } zipName := s.gridFileName(module, version) db := s.client.Database(s.db) bucket, err := gridfs.NewBucket(db, options.GridFSBucket()) if err != nil { return errors.E(op, err, errors.M(module), errors.V(version)) } uStream, err := bucket.OpenUploadStream(zipName, options.GridFSUpload()) if err != nil { return errors.E(op, err, errors.M(module), errors.V(version)) } defer func() { _ = uStream.Close() }() numBytesWritten, err := io.Copy(uStream, zip) if err != nil { return errors.E(op, err, errors.M(module), errors.V(version)) } if numBytesWritten <= 0 { e := fmt.Errorf("copied %d bytes to Mongo GridFS", numBytesWritten) return errors.E(op, e, errors.M(module), errors.V(version)) } m := &storage.Module{ Module: module, Version: version, Mod: mod, Info: info, } c := s.client.Database(s.db).Collection(s.coll) tctx, cancel := context.WithTimeout(ctx, s.timeout) defer cancel() _, err = c.InsertOne(tctx, m, options.InsertOne().SetBypassDocumentValidation(false)) if err != nil { return errors.E(op, err, errors.M(module), errors.V(version)) } return nil }