66 lines
1.7 KiB
Go
66 lines
1.7 KiB
Go
package outboundimage
|
|
|
|
import (
|
|
"context"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
var resourceMarkdownImageRE = regexp.MustCompile(`!\[[^\]]*\]\((resource://[0-9A-Za-z_-]+)\)`)
|
|
|
|
type Fetcher interface {
|
|
Fetch(ctx context.Context, reference string) ([]byte, string, error)
|
|
}
|
|
|
|
type Publisher interface {
|
|
Publish(ctx context.Context, data []byte, contentType string) (string, error)
|
|
}
|
|
|
|
type Rewriter struct {
|
|
fetcher Fetcher
|
|
publisher Publisher
|
|
maxImages int
|
|
}
|
|
|
|
func NewRewriter(fetcher Fetcher, publisher Publisher, maxImages int) *Rewriter {
|
|
return &Rewriter{fetcher: fetcher, publisher: publisher, maxImages: maxImages}
|
|
}
|
|
|
|
func (r *Rewriter) Rewrite(ctx context.Context, markdown string) string {
|
|
if r == nil || r.fetcher == nil || r.publisher == nil || r.maxImages <= 0 {
|
|
return resourceMarkdownImageRE.ReplaceAllString(markdown, "")
|
|
}
|
|
urls := map[string]string{}
|
|
attempted := 0
|
|
return resourceMarkdownImageRE.ReplaceAllStringFunc(markdown, func(image string) string {
|
|
match := resourceMarkdownImageRE.FindStringSubmatch(image)
|
|
if len(match) != 2 {
|
|
return ""
|
|
}
|
|
reference := match[1]
|
|
if signedURL, ok := urls[reference]; ok {
|
|
if signedURL == "" {
|
|
return ""
|
|
}
|
|
return strings.Replace(image, reference, signedURL, 1)
|
|
}
|
|
if attempted >= r.maxImages {
|
|
urls[reference] = ""
|
|
return ""
|
|
}
|
|
attempted++
|
|
data, contentType, err := r.fetcher.Fetch(ctx, reference)
|
|
if err != nil {
|
|
urls[reference] = ""
|
|
return ""
|
|
}
|
|
signedURL, err := r.publisher.Publish(ctx, data, contentType)
|
|
if err != nil || !strings.HasPrefix(signedURL, "https://") {
|
|
urls[reference] = ""
|
|
return ""
|
|
}
|
|
urls[reference] = signedURL
|
|
return strings.Replace(image, reference, signedURL, 1)
|
|
})
|
|
}
|