package store import ( "context" "database/sql" "errors" "os" "path/filepath" "time" "g.fc.run/misc/byre/internal/api" ) func (s *Store) CreateBlob(ctx context.Context, contentType string, data []byte, actor string) (api.Blob, error) { b := api.Blob{ Id: NewID(), ContentType: contentType, CreatedBy: actor, CreatedAt: time.Now().UTC(), } rel := filepath.Join("blobs", b.Id) err := os.MkdirAll(filepath.Join(s.dataDir(), "blobs"), 0o755) if err != nil { return b, err } err = os.WriteFile(filepath.Join(s.dataDir(), rel), data, 0o644) if err != nil { return b, err } _, err = s.db.ExecContext(ctx, `INSERT INTO blobs (id, content_type, path, created_by, created_at) VALUES (?, ?, ?, ?, ?)`, b.Id, b.ContentType, rel, b.CreatedBy, formatTime(b.CreatedAt)) return b, err } func (s *Store) GetBlob(ctx context.Context, id string) (api.Blob, string, error) { b := api.Blob{} rel := "" createdAt := "" err := s.db.QueryRowContext(ctx, `SELECT id, content_type, path, created_by, created_at FROM blobs WHERE id = ?`, id). Scan(&b.Id, &b.ContentType, &rel, &b.CreatedBy, &createdAt) if errors.Is(err, sql.ErrNoRows) { return b, "", errors.Join(ErrNotFound, errors.New("no blob "+id)) } if err != nil { return b, "", err } b.CreatedAt, err = parseTime(createdAt) return b, filepath.Join(s.dataDir(), rel), err } func (s *Store) ReadBlob(ctx context.Context, id string) (api.Blob, []byte, error) { b, path, err := s.GetBlob(ctx, id) if err != nil { return b, nil, err } data, err := os.ReadFile(path) return b, data, err } func (s *Store) dataDir() string { return filepath.Dir(s.path) }