pages - types.go
		
     1  package pages
     2  
     3  import (
     4  	"html/template"
     5  	"net/http"
     6  	"os"
     7  	"sync"
     8  	"time"
     9  )
    10  
    11  const (
    12  	Static         = "-static-"
    13  	StaticTemplate = "{{define \"title\"}}{{.Title}}{{end}}{{define \"style\"}}{{.Style}}{{end}}{{define \"body\"}}\n{{.Body}}{{end}}"
    14  )
    15  
    16  type staticData struct {
    17  	Title, Style string
    18  	Body         template.HTML
    19  }
    20  
    21  type Bytes struct {
    22  	pages      *Pages
    23  	staticData staticData
    24  }
    25  
    26  func (p *Pages) Bytes(title, style string, body template.HTML) *Bytes {
    27  	if _, ok := p.templates[Static]; !ok {
    28  		p.StaticString(StaticTemplate)
    29  	}
    30  
    31  	return &Bytes{
    32  		pages: p,
    33  		staticData: staticData{
    34  			Title: title,
    35  			Style: style,
    36  			Body:  body,
    37  		},
    38  	}
    39  }
    40  
    41  func (b *Bytes) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    42  	b.pages.Write(w, r, Static, &b.staticData)
    43  }
    44  
    45  type File struct {
    46  	pages    *Pages
    47  	Filename string
    48  
    49  	mu           sync.RWMutex
    50  	staticData   *staticData
    51  	LastModified time.Time
    52  }
    53  
    54  func (p *Pages) File(title, style, filename string) *File {
    55  	if _, ok := p.templates[Static]; !ok {
    56  		p.StaticString(StaticTemplate)
    57  	}
    58  
    59  	return &File{
    60  		pages:    p,
    61  		Filename: filename,
    62  		staticData: &staticData{
    63  			Title: title,
    64  			Style: style,
    65  		},
    66  	}
    67  }
    68  
    69  func (f *File) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    70  	stats, err := os.Stat(f.Filename)
    71  	if err != nil {
    72  		w.WriteHeader(http.StatusInternalServerError)
    73  
    74  		return
    75  	}
    76  
    77  	if modtime := stats.ModTime(); modtime.After(f.LastModified) {
    78  		f.mu.Lock()
    79  
    80  		stats, err = os.Stat(f.Filename)
    81  		if err != nil {
    82  			f.mu.Unlock()
    83  			w.WriteHeader(http.StatusInternalServerError)
    84  
    85  			return
    86  		}
    87  
    88  		if modtime = stats.ModTime(); modtime.After(f.LastModified) { // in case another goroutine has changed it already
    89  			if data, err := os.ReadFile(f.Filename); err != nil {
    90  				f.mu.Unlock()
    91  				w.WriteHeader(http.StatusInternalServerError)
    92  
    93  				return
    94  			} else {
    95  				f.staticData = &staticData{
    96  					Title: f.staticData.Title,
    97  					Style: f.staticData.Style,
    98  					Body:  template.HTML(data),
    99  				}
   100  				f.LastModified = modtime
   101  			}
   102  		}
   103  
   104  		f.mu.Unlock()
   105  	}
   106  
   107  	f.mu.RLock()
   108  	staticData := f.staticData
   109  	f.mu.RUnlock()
   110  
   111  	f.pages.Write(w, r, Static, staticData)
   112  }
   113