Skip to content

Commit 7daa141

Browse files
authored
Embed files into one package
1 parent dbf6752 commit 7daa141

File tree

1 file changed

+48
-25
lines changed

1 file changed

+48
-25
lines changed

main.go

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
package main
22

33
import (
4+
"embed"
45
"encoding/json"
56
"fmt"
67
"html/template"
8+
"io/fs"
79
"net/http"
810
"os"
11+
"path/filepath"
912
"strconv"
1013
"time"
1114
)
1215

16+
//go:embed static templates
17+
var content embed.FS
18+
1319
// Fast represents a fasting record
1420
type Fast struct {
1521
StartTime time.Time `json:"start_time"`
@@ -42,27 +48,34 @@ func loadData() (*AppData, error) {
4248
}
4349
file, err := os.Open(dataFile)
4450
if err != nil {
45-
return nil, err
51+
return nil, fmt.Errorf("opening data file: %w", err)
4652
}
4753
defer file.Close()
4854
var data AppData
4955
err = json.NewDecoder(file).Decode(&data)
5056
if err != nil {
51-
return nil, err
57+
return nil, fmt.Errorf("decoding data file: %w", err)
5258
}
5359
return &data, nil
5460
}
5561

5662
// saveData writes the application data to the JSON file
5763
func saveData(data *AppData) error {
64+
dir := filepath.Dir(dataFile)
65+
if err := os.MkdirAll(dir, 0755); err != nil {
66+
return fmt.Errorf("creating data directory: %w", err)
67+
}
5868
file, err := os.Create(dataFile)
5969
if err != nil {
60-
return err
70+
return fmt.Errorf("creating data file: %w", err)
6171
}
6272
defer file.Close()
6373
encoder := json.NewEncoder(file)
6474
encoder.SetIndent("", " ")
65-
return encoder.Encode(data)
75+
if err := encoder.Encode(data); err != nil {
76+
return fmt.Errorf("encoding data: %w", err)
77+
}
78+
return nil
6679
}
6780

6881
// homeHandler redirects to the profile page
@@ -74,11 +87,10 @@ func homeHandler(w http.ResponseWriter, r *http.Request) {
7487
func profileHandler(w http.ResponseWriter, r *http.Request) {
7588
data, err := loadData()
7689
if err != nil {
77-
http.Error(w, "Error loading data", http.StatusInternalServerError)
90+
http.Error(w, fmt.Sprintf("Error loading data: %v", err), http.StatusInternalServerError)
7891
return
7992
}
8093

81-
// Pagination logic
8294
const itemsPerPage = 5
8395
pageStr := r.URL.Query().Get("page")
8496
page, err := strconv.Atoi(pageStr)
@@ -109,45 +121,49 @@ func profileHandler(w http.ResponseWriter, r *http.Request) {
109121
HasNext: page < totalPages,
110122
}
111123

112-
tmpl := template.New("profile.html").Funcs(template.FuncMap{
124+
tmpl, err := template.New("profile.html").Funcs(template.FuncMap{
113125
"seq": func(start, end int) []int {
126+
if end < start {
127+
return []int{}
128+
}
114129
s := make([]int, end-start+1)
115130
for i := range s {
116131
s[i] = start + i
117132
}
118133
return s
119134
},
120135
"mod": func(a, b int) int {
136+
if b == 0 {
137+
return 0
138+
}
121139
return a % b
122140
},
123141
"add": func(a, b int) int {
124142
return a + b
125143
},
126-
})
127-
tmpl, err = tmpl.ParseFiles("templates/profile.html")
144+
}).ParseFS(content, "templates/profile.html")
128145
if err != nil {
129-
http.Error(w, "Error parsing template", http.StatusInternalServerError)
146+
http.Error(w, fmt.Sprintf("Error parsing template: %v", err), http.StatusInternalServerError)
130147
return
131148
}
132149
err = tmpl.Execute(w, templateData)
133150
if err != nil {
134-
http.Error(w, "Error executing template", http.StatusInternalServerError)
151+
http.Error(w, fmt.Sprintf("Error executing template: %v", err), http.StatusInternalServerError)
135152
}
136153
}
137154

138155
// fastingHandler renders the Fasting tab
139156
func fastingHandler(w http.ResponseWriter, r *http.Request) {
140157
data, err := loadData()
141158
if err != nil {
142-
http.Error(w, "Error loading data", http.StatusInternalServerError)
159+
http.Error(w, fmt.Sprintf("Error loading data: %v", err), http.StatusInternalServerError)
143160
return
144161
}
145-
t, err := template.ParseFiles("templates/fasting.html")
162+
t, err := template.ParseFS(content, "templates/fasting.html")
146163
if err != nil {
147-
http.Error(w, "Error parsing template", http.StatusInternalServerError)
164+
http.Error(w, fmt.Sprintf("Error parsing template: %v", err), http.StatusInternalServerError)
148165
return
149166
}
150-
// Pass error message from query parameter, if any
151167
type FastingTemplateData struct {
152168
*AppData
153169
ErrorMessage string
@@ -158,7 +174,7 @@ func fastingHandler(w http.ResponseWriter, r *http.Request) {
158174
}
159175
err = t.Execute(w, templateData)
160176
if err != nil {
161-
http.Error(w, "Error executing template", http.StatusInternalServerError)
177+
http.Error(w, fmt.Sprintf("Error executing template: %v", err), http.StatusInternalServerError)
162178
}
163179
}
164180

@@ -176,7 +192,7 @@ func startFastHandler(w http.ResponseWriter, r *http.Request) {
176192
goalStr := r.FormValue("goal")
177193
var goal int
178194
if goalStr == "" {
179-
goal = 0 // Allow empty input as 0
195+
goal = 0
180196
} else {
181197
goal, err = strconv.Atoi(goalStr)
182198
if err != nil || goal < 0 {
@@ -199,7 +215,7 @@ func startFastHandler(w http.ResponseWriter, r *http.Request) {
199215
}
200216
err = saveData(data)
201217
if err != nil {
202-
http.Redirect(w, r, "/fasting?error=Error saving data", http.StatusSeeOther)
218+
http.Redirect(w, r, fmt.Sprintf("/fasting?error=Error saving data: %v", err), http.StatusSeeOther)
203219
return
204220
}
205221
http.Redirect(w, r, "/fasting", http.StatusSeeOther)
@@ -213,30 +229,37 @@ func endFastHandler(w http.ResponseWriter, r *http.Request) {
213229
}
214230
data, err := loadData()
215231
if err != nil {
216-
http.Error(w, "Error loading data", http.StatusInternalServerError)
232+
http.Error(w, fmt.Sprintf("Error loading data: %v", err), http.StatusInternalServerError)
217233
return
218234
}
219235
if data.CurrentFast == nil {
220236
http.Error(w, "No fast in progress", http.StatusBadRequest)
221237
return
222238
}
223239
duration := time.Since(data.CurrentFast.StartTime).Hours()
224-
data.FastingHistory = append(data.FastingHistory, Fast{
240+
completedFast := Fast{
225241
StartTime: data.CurrentFast.StartTime,
242+
GoalHours: data.CurrentFast.GoalHours,
226243
DurationHours: duration,
227-
})
244+
}
245+
data.FastingHistory = append([]Fast{completedFast}, data.FastingHistory...)
228246
data.CurrentFast = nil
229247
err = saveData(data)
230248
if err != nil {
231-
http.Error(w, "Error saving data", http.StatusInternalServerError)
249+
http.Error(w, fmt.Sprintf("Error saving data: %v", err), http.StatusInternalServerError)
232250
return
233251
}
234252
http.Redirect(w, r, "/fasting", http.StatusSeeOther)
235253
}
236254

237255
func main() {
238-
// Serve static files
239-
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
256+
// Serve static files from embedded FS
257+
staticFS, err := fs.Sub(content, "static")
258+
if err != nil {
259+
fmt.Println("Error creating static FS:", err)
260+
os.Exit(1)
261+
}
262+
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(staticFS))))
240263

241264
// Define routes
242265
http.HandleFunc("/", homeHandler)
@@ -247,7 +270,7 @@ func main() {
247270

248271
// Start the server
249272
fmt.Println("Xerophagon starting on :5000...")
250-
err := http.ListenAndServe(":5000", nil)
273+
err = http.ListenAndServe(":5000", nil)
251274
if err != nil {
252275
fmt.Printf("Server failed: %v\n", err)
253276
}

0 commit comments

Comments
 (0)