<commit_before>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	_ "net/http/pprof"
	"time"

	"github.com/akrennmair/gouuid"
	"github.com/boltdb/bolt"
	"github.com/julienschmidt/httprouter"
)

func main() {
	var (
		listenAddr = flag.String("listen", "localhost:8080", "listen address")
		dataFile   = flag.String("datafile", "./data.db", "path to data file")
	)

	flag.Parse()

	db, err := bolt.Open(*dataFile, 0600, nil)
	if err != nil {
		log.Fatalf("bolt.Open %s failed: %v", *dataFile, err)
	}

	fh := &fileHandler{DB: db}

	router := httprouter.New()

	router.GET("/:drawer/:file", fh.deliverFile)
	router.DELETE("/:drawer/:file", fh.deleteFile)
	router.POST("/api/upload", fh.uploadFile)

	http.Handle("/", router)

	log.Fatal(http.ListenAndServe(*listenAddr, nil))
}

type fileHandler struct {
	DB *bolt.DB
}

func (h *fileHandler) deliverFile(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	ts := time.Now()
	defer func() {
		duration := time.Since(ts)
		log.Printf("deliverying %s took %s", r.RequestURI, duration)
	}()
	drawer := p.ByName("drawer")
	if drawer == "" {
		http.Error(w, "no drawer specified", http.StatusNotFound)
		return
	}

	filename := p.ByName("file")
	if filename == "" {
		http.Error(w, "no filename specified", http.StatusNotFound)
		return
	}

	err := h.DB.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket([]byte(drawer))
		if bucket == nil {
			return errors.New("unknown bucket")
		}

		fileContent := bucket.Get([]byte(filename))
		mimeType := bucket.Get([]byte("." + filename + ".mimetype"))

		w.Header().Set("Content-Type", string(mimeType))
		w.Write(fileContent)
		return nil
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("delivery failed: %v", err)
		return
	}
}

func (h *fileHandler) deleteFile(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	// TODO: implement
}

func (h *fileHandler) uploadFile(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	if err := r.ParseForm(); err != nil {
		http.Error(w, "parsing multipart form failed: "+err.Error(), http.StatusNotAcceptable)
		return
	}

	drawerName := r.Form.Get("drawer")
	if drawerName == "" {
		http.Error(w, "no drawer name provided", http.StatusNotAcceptable)
		return
	}

	var filenames []string

	err := h.DB.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket([]byte(drawerName))
		if bucket == nil {
			b, err := tx.CreateBucket([]byte(drawerName))
			if err != nil {
				return err
			}
			bucket = b
			// TODO: make bucket creation an explicit operation whenever credentials for file upload are introduced.
		}<commit_msg>implemented deleting files.<commit_after>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	_ "net/http/pprof"
	"time"

	"github.com/akrennmair/gouuid"
	"github.com/boltdb/bolt"
	"github.com/julienschmidt/httprouter"
)

func main() {
	var (
		listenAddr = flag.String("listen", "localhost:8080", "listen address")
		dataFile   = flag.String("datafile", "./data.db", "path to data file")
	)

	flag.Parse()

	db, err := bolt.Open(*dataFile, 0600, nil)
	if err != nil {
		log.Fatalf("bolt.Open %s failed: %v", *dataFile, err)
	}

	fh := &fileHandler{DB: db}

	router := httprouter.New()

	router.GET("/:drawer/:file", fh.deliverFile)
	router.DELETE("/:drawer/:file", fh.deleteFile)
	router.POST("/api/upload", fh.uploadFile)

	http.Handle("/", router)

	log.Fatal(http.ListenAndServe(*listenAddr, nil))
}

type fileHandler struct {
	DB *bolt.DB
}

func (h *fileHandler) deliverFile(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	ts := time.Now()
	defer func() {
		duration := time.Since(ts)
		log.Printf("deliverying %s took %s", r.RequestURI, duration)
	}()
	drawer := p.ByName("drawer")
	if drawer == "" {
		http.Error(w, "no drawer specified", http.StatusNotFound)
		return
	}

	filename := p.ByName("file")
	if filename == "" {
		http.Error(w, "no filename specified", http.StatusNotFound)
		return
	}

	err := h.DB.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket([]byte(drawer))
		if bucket == nil {
			return errors.New("unknown bucket")
		}

		fileContent := bucket.Get([]byte(filename))
		mimeType := bucket.Get([]byte("." + filename + ".mimetype"))

		w.Header().Set("Content-Type", string(mimeType))
		w.Write(fileContent)
		return nil
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("delivery failed: %v", err)
		return
	}
}

func (h *fileHandler) deleteFile(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	drawerName := p.ByName("drawer")
	filename := p.ByName("file")

	if drawerName == "" || filename == "" {
		http.Error(w, "Not found", http.StatusNotAcceptable)
	}

	err := h.DB.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket([]byte(drawerName))
		if bucket == nil {
			return errors.New("unknown drawer")
		}
		if err := bucket.Delete([]byte(filename)); err != nil {
			return err
		}
		if err := bucket.Delete([]byte("." + filename + ".mimetype")); err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		http.Error(w, "Deleting file failed: "+err.Error(), http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}

func (h *fileHandler) uploadFile(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	if err := r.ParseForm(); err != nil {
		http.Error(w, "parsing multipart form failed: "+err.Error(), http.StatusNotAcceptable)
		return
	}

	drawerName := r.Form.Get("drawer")
	if drawerName == "" {
		http.Error(w, "no drawer name provided", http.StatusNotAcceptable)
		return
	}

	var filenames []string

	err := h.DB.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket([]byte(drawerName))
		if bucket == nil {
			b, err := tx.CreateBucket([]byte(drawerName))
			if err != nil {
				return err
			}
			bucket = b
			// TODO: make bucket creation an explicit operation whenever credentials for file upload are introduced.
		}
{'fraction_non_alphanumeric': 0.17151888204957577, 'fraction_numerical': 0.0026617867243387125, 'mean_word_length': 3.993355481727575, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3410473', 'n_tokens_mistral': 2312, 'n_tokens_neox': 2168, 'n_words': 492}