package service import ( "encoding/json" "fmt" "io" "io/fs" "net/http" "os" "path/filepath" makeshift "git.towk2.me/towk/makeshift/pkg" "github.com/go-chi/chi/v5" "github.com/tidwall/sjson" ) func (s *Service) ListProfiles() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var ( path = s.RootPath + RELPATH_PROFILES profiles []*makeshift.Profile contents []byte err error ) // walk profiles directory to load all profiles err = filepath.Walk(path, func(path string, info fs.FileInfo, err error) error { if err != nil { return err } // skip directories if info.IsDir() { return nil } // read file contents var profile *makeshift.Profile profile, err = LoadProfileFromFile(path) if err != nil { return err } profiles = append(profiles, profile) fmt.Println(path, info.Size()) return nil }) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } // marshal and send all the profiles contents, err = json.Marshal(profiles) if err != nil { http.Error(w, fmt.Sprintf("failed to marshal profiles: %v", err), http.StatusInternalServerError) } _, err = w.Write(contents) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } } // func (s *Service) CreateProfiles() http.HandlerFunc { // return func(w http.ResponseWriter, r *http.Request) { // var ( // path = chi.URLParam(r, "path") // err error // ) // } // } func (s *Service) GetProfile() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var ( id = chi.URLParam(r, "id") path = s.PathForProfileWithID(id) contents []byte err error ) contents, err = loadProfileContents(path) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } _, err = w.Write(contents) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } } func (s *Service) CreateProfile() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { type input struct { Path string `json:"path"` Profile *makeshift.Profile `json:"profile"` } var ( body, contents []byte in input err error ) body, err = io.ReadAll(r.Body) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // use the request info to build profile err = json.Unmarshal(body, &in) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // serialize just the profile part contents, err = json.Marshal(in.Profile) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // create a new profile on disk err = os.WriteFile(in.Path, contents, os.ModePerm) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } w.WriteHeader(http.StatusOK) } } func (s *Service) SetProfileData() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var ( body, contents []byte newContents string profile *makeshift.Profile path string err error ) body, err = io.ReadAll(r.Body) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } err = json.Unmarshal(body, &profile) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // make sure the request data sets an ID if profile.ID == "" { http.Error(w, "ID must be set to a non-empty value", http.StatusBadRequest) return } // read the contents the file with profile ID path = s.PathForProfileWithID(profile.ID) contents, err = os.ReadFile(path) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // modify the data of the profile's contents newContents, err = sjson.Set(string(contents), "data", profile.Data) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // write only the data to the file with ID err = os.WriteFile(path, []byte(newContents), os.ModePerm) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } } func (s *Service) DeleteProfileData() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var ( id = chi.URLParam(r, "id") path = s.PathForProfileWithID(id) profile *makeshift.Profile err error ) // get the profile profile, err = LoadProfileFromFile(path) if err != nil { http.Error(w, err.Error(), http.StatusBadGateway) return } // delete the profile data profile.Data = map[string]any{} // save the profile back to the file to update SaveProfileToFile(path, profile) } } func (s *Service) GetProfileData() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var ( id = chi.URLParam(r, "id") path = s.PathForProfileWithID(id) profile *makeshift.Profile body []byte err error ) profile, err = LoadProfileFromFile(path) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // only marshal the profile data and not entire profile body, err = json.Marshal(profile.Data) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // write body to response _, err = w.Write(body) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } } // func (s *Service) CreateProfilePath() http.HandlerFunc { // return func(w http.ResponseWriter, r *http.Request) { // w.WriteHeader(http.StatusOK) // } // } // func (s *Service) DeleteProfilePath() http.HandlerFunc { // return func(w http.ResponseWriter, r *http.Request) {} // } // func (s *Service) GetProfilePath() http.HandlerFunc { // return func(w http.ResponseWriter, r *http.Request) {} // } func loadProfileContents(path string) ([]byte, error) { var ( contents []byte profile *makeshift.Profile err error ) profile, err = LoadProfileFromFile(path) if err != nil { return nil, fmt.Errorf("failed to load profile from file: %v", err) } contents, err = json.Marshal(profile) if err != nil { return nil, fmt.Errorf("failed to marshal profile: %v", err) } return contents, nil }