mermaid-server/internal/diagram.go

101 lines
2.8 KiB
Go
Raw Permalink Normal View History

package internal
import (
"crypto/md5"
"encoding/base64"
"encoding/hex"
2025-05-24 11:45:48 +02:00
"fmt"
"strings"
2020-08-09 11:59:05 +02:00
"sync"
"time"
)
// NewDiagram returns a new diagram.
func NewDiagram(description []byte, imgType string) *Diagram {
2025-05-24 11:45:48 +02:00
// Debug: Log what we received
fmt.Printf("DEBUG: Received %d bytes\n", len(description))
fmt.Printf("DEBUG: Raw bytes: %q\n", string(description))
fmt.Printf("DEBUG: Contains newlines: %t\n", strings.Contains(string(description), "\n"))
trimmed := strings.TrimSpace(string(description))
fmt.Printf("DEBUG: After TrimSpace: %q\n", trimmed)
fmt.Printf("DEBUG: Still contains newlines: %t\n", strings.Contains(trimmed, "\n"))
2025-05-24 11:59:34 +02:00
// Decode NEWLINE markers back to actual newlines for complex diagrams
if strings.Contains(trimmed, " NEWLINE ") {
trimmed = strings.ReplaceAll(trimmed, " NEWLINE ", "\n")
fmt.Printf("DEBUG: After NEWLINE decoding: %q\n", trimmed)
fmt.Printf("DEBUG: Now contains newlines: %t\n", strings.Contains(trimmed, "\n"))
}
2025-05-24 12:08:37 +02:00
// Decode pipe separators back to newlines for quadrant charts
if strings.Contains(trimmed, " | ") {
trimmed = strings.ReplaceAll(trimmed, " | ", "\n")
fmt.Printf("DEBUG: After pipe decoding: %q\n", trimmed)
fmt.Printf("DEBUG: Now contains newlines: %t\n", strings.Contains(trimmed, "\n"))
}
return &Diagram{
2025-05-24 11:45:48 +02:00
description: []byte(trimmed),
2020-08-09 11:59:05 +02:00
lastTouched: time.Now(),
mu: &sync.RWMutex{},
imgType: imgType,
}
}
2020-08-09 11:59:05 +02:00
// Diagram represents a single diagram.
type Diagram struct {
2020-08-09 11:59:05 +02:00
// id is the ID of the Diagram
id string
// description is the description of the diagram.
description []byte
// Output is the filepath to the output file.
Output string
2020-08-09 11:59:05 +02:00
// mu is a mutex to protect the last touched value.
mu *sync.RWMutex
// lastTouched is the time that the diagram was last used.
lastTouched time.Time
// the type of image to generate svg or png
imgType string
2020-08-09 11:59:05 +02:00
}
// Touch updates the last touched time of the diagram.
func (d *Diagram) Touch() {
d.mu.Lock()
defer d.mu.Unlock()
d.lastTouched = time.Now()
}
// TouchedInDuration returns true if the diagram has been touched in the given duration.
func (d *Diagram) TouchedInDuration(duration time.Duration) bool {
d.mu.Lock()
defer d.mu.Unlock()
return time.Now().Add(-duration).Before(d.lastTouched)
}
// ID returns an ID for the diagram.
// The ID is set from the diagram description.
func (d *Diagram) ID() (string, error) {
if d.id != "" {
return d.id, nil
}
encoded := base64.StdEncoding.EncodeToString(d.description)
hash := md5.Sum([]byte(encoded))
d.id = hex.EncodeToString(hash[:]) + d.imgType
return d.id, nil
}
// Description returns the diagram description.
func (d *Diagram) Description() []byte {
return d.description
}
// Description returns the diagram description.
func (d *Diagram) WithDescription(description []byte) *Diagram {
d.description = description
d.id = ""
return d
}