diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..91616c3 --- /dev/null +++ b/go.mod @@ -0,0 +1,17 @@ +module miningtcup.me/noteserver + +go 1.24.5 + +require ( + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/ncruces/go-strftime v0.1.9 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect + golang.org/x/sys v0.34.0 // indirect + modernc.org/libc v1.66.3 // indirect + modernc.org/mathutil v1.7.1 // indirect + modernc.org/memory v1.11.0 // indirect + modernc.org/sqlite v1.38.2 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..057de1d --- /dev/null +++ b/go.sum @@ -0,0 +1,23 @@ +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +modernc.org/libc v1.66.3 h1:cfCbjTUcdsKyyZZfEUKfoHcP3S0Wkvz3jgSzByEWVCQ= +modernc.org/libc v1.66.3/go.mod h1:XD9zO8kt59cANKvHPXpx7yS2ELPheAey0vjIuZOhOU8= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= +modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= +modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/sqlite v1.38.2 h1:Aclu7+tgjgcQVShZqim41Bbw9Cho0y/7WzYptXqkEek= +modernc.org/sqlite v1.38.2/go.mod h1:cPTJYSlgg3Sfg046yBShXENNtPrWrDX8bsbAQBzgQ5E= diff --git a/main.go b/main.go new file mode 100644 index 0000000..8a8be63 --- /dev/null +++ b/main.go @@ -0,0 +1,146 @@ +package main + +import ( + "database/sql" + "encoding/json" + "fmt" + "log" + "net/http" + "strconv" + + _ "modernc.org/sqlite" + "github.com/google/uuid" +) + +var ( + db *sql.DB +) + +func main() { + fmt.Println("hello, world!") + var err error + db, err = sql.Open("sqlite", "./db/notes.db") + if err != nil { + log.Fatal(err) + } + defer db.Close() + + http.HandleFunc("/get", func(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + if !r.Form.Has("user") { + w.WriteHeader(400) + fmt.Fprint(w, "This endpoint requires parameters 'user'") + return + } + + limit, err := strconv.Atoi(r.Form.Get("max")) + if err != nil { + limit = 100 + } + + rows := getNotes(r.Form.Get("user"), limit) + jsonString, err := json.Marshal(rows) + if err != nil { + log.Fatal(err) + } + w.Header().Add("Content-Type", "text/json") + fmt.Fprint(w, string(jsonString)) + fmt.Println(string(jsonString)) + }) + + http.HandleFunc("/new", func(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + if !r.Form.Has("user") || !r.Form.Has("data") { + w.WriteHeader(400) + fmt.Fprint(w, "This endpoint requires parameters 'user' and 'data'") + return + } + + uuid, err := uuid.NewUUID() + if err != nil { + log.Fatal(err) + } + + newNote(r.Form.Get("user"), r.Form.Get("data"), uuid.String()) + fmt.Fprint(w, uuid) + }) + + http.HandleFunc("/replace", func(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + if !r.Form.Has("user") || !r.Form.Has("data") || !r.Form.Has("id") { + w.WriteHeader(400) + fmt.Fprint(w, "This endpoint requires parameters 'user' and 'data'") + return + } + + removeNote(r.Form.Get("user"), r.Form.Get("id")) + newNote(r.Form.Get("user"), r.Form.Get("data"), r.Form.Get("id")) + fmt.Fprint(w, http.StatusText(200)) + }) + + http.HandleFunc("/remove", func(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + if !r.Form.Has("user") || !r.Form.Has("id") { + w.WriteHeader(400) + fmt.Fprint(w, "This endpoint requires parameters 'user' and 'id'") + return + } + + removeNote(r.Form.Get("user"), r.Form.Get("id")) + fmt.Fprint(w, http.StatusText(200)) + }) + + log.Fatal(http.ListenAndServe(":3000", nil)) +} + +func getNotes(user string, limit int) [][2]string { + var rowCount int + err := db.QueryRow("SELECT COUNT(*) FROM notes WHERE user = ?", user).Scan(&rowCount) + if err != nil { + log.Fatal(err) + } + if rowCount > limit { + rowCount = limit + } + + rows, err := db.Query("SELECT * FROM notes WHERE user = ? LIMIT ?", user, limit) + if err != nil { + log.Fatal(err) + } + defer rows.Close() + + notes := make([][2]string, rowCount) + var dummy string + + for i := 0; rows.Next(); i++ { + var currentRow [2]string + if err := rows.Scan(¤tRow[0], &dummy, ¤tRow[1]); err != nil { + log.Fatal(err) + } + notes[i] = currentRow + } + + return notes +} + +func newNote(user string, data string, uuid string) { + stmt, err := db.Prepare("INSERT INTO notes VALUES(?, ?, ?)") + if err != nil { + log.Fatal(err) + } + + if _, err := stmt.Exec(uuid, user, data); err != nil { + log.Fatal(err) + } +} + +func removeNote(user string, uuid string) { + stmt, err := db.Prepare("DELETE FROM notes WHERE user = ? AND id = ?") + if err != nil { + log.Fatal(err) + } + + if _, err := stmt.Exec(user, uuid); err != nil { + log.Fatal(err) + } +}