package main import ( "context" "fmt" "github.com/redis/go-redis/v9" "log" "encoding/json" "net/http" "html/template" "strconv" ) type todo struct { Id int Title string Completed bool } var maxId int = 0 var ctx = context.Background() var rdb = redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password set DB: 0, // use default DB }) func GetTodos() []todo { var cursor uint64 = 0 todosJson, cursor, err := rdb.Scan(ctx, cursor, "todo:*", 20).Result() if err != nil { panic(err) } var todos []todo = make([]todo, len(todosJson)) for idx, todoJson := range todosJson { todoJson := rdb.Get(ctx, todoJson).Val() fmt.Println("Todo: %s", todoJson) err = json.Unmarshal([]byte(todoJson), &todos[idx]) if err != nil { panic(err) } if todos[idx].Id > maxId { maxId = todos[idx].Id } } return todos } func GetTodoById(id int) todo { todoJson, err := rdb.Get(ctx, fmt.Sprintf("todo:%d", id)).Result() if err != nil { panic(err) } var todo todo err = json.Unmarshal([]byte(todoJson), &todo) if err != nil { panic(err) } return todo } func SetTodo(todo todo) { todoJson, err := json.Marshal(todo) if err != nil { panic(err) } key := fmt.Sprintf("todo:%d", todo.Id) err = rdb.Set(ctx, key, string(todoJson), 0).Err() if err != nil { panic(err) } fmt.Println("Set todo: %s", todoJson) } func DeleteTodoById(id int) { err := rdb.Del(ctx, fmt.Sprintf("todo:%d", id)).Err() if err != nil { panic(err) } } func IndexHandler(w http.ResponseWriter, r *http.Request) { t, _ := template.ParseFiles("templates/index.html") t.Execute(w, nil) } func TodosHandler(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { r.ParseForm() todoTitle := r.Form.Get("title") SetTodo(todo{Id: maxId + 1, Title: todoTitle, Completed: false}) } todos := GetTodos() t, _ := template.ParseFiles("templates/todos.html") t.Execute(w, todos) } func ToggleTodoHandler(w http.ResponseWriter, r *http.Request) { todoId, err := strconv.Atoi(r.URL.Path) if err != nil { panic(err) } fmt.Println("Todo Id: %d", todoId) todo := GetTodoById(todoId) todo.Completed = !todo.Completed SetTodo(todo) TodosHandler(w, r) return } func TodoHandler(w http.ResponseWriter, r *http.Request) { if r.Method != "DELETE" { w.WriteHeader(http.StatusMethodNotAllowed) fmt.Fprintf(w, "Method %s not allowed", r.Method) return } todoId, err := strconv.Atoi(r.URL.Path) if err != nil { panic(err) } fmt.Println("Todo Id: %d", todoId) DeleteTodoById(todoId) TodosHandler(w, r) return } func main() { fmt.Println("Starting web server on port 8080") fs := http.FileServer(http.Dir("./static")) http.Handle("/static/", http.StripPrefix("/static/", fs)) http.HandleFunc("/", IndexHandler) http.HandleFunc("/todos", TodosHandler) togglePath := "/toggle-todo/" http.Handle(togglePath, http.StripPrefix(togglePath, http.HandlerFunc(ToggleTodoHandler))) todoPath := "/todo/" http.Handle(todoPath, http.StripPrefix(todoPath, http.HandlerFunc(TodoHandler))) log.Fatal(http.ListenAndServe(":8080", nil)) }