init
This commit is contained in:
parent
79a7534428
commit
c8e82d5d43
13 changed files with 921 additions and 0 deletions
177
internal/paste/paste.go
Normal file
177
internal/paste/paste.go
Normal file
|
@ -0,0 +1,177 @@
|
|||
package paste
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"goblin/internal/util"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var logger = log.WithFields(log.Fields{
|
||||
"package": "paste",
|
||||
})
|
||||
|
||||
const idLength = 8
|
||||
|
||||
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
|
||||
var (
|
||||
pasteMap = make(map[string]*Paste)
|
||||
templateDir string
|
||||
pasteDir string
|
||||
pasteTmpl *template.Template // Declare pasteTmpl at the package level
|
||||
)
|
||||
|
||||
func generateUniqueID() string {
|
||||
idRunes := make([]rune, idLength)
|
||||
for i := range idRunes {
|
||||
idRunes[i] = letters[rand.Intn(len(letters))]
|
||||
}
|
||||
|
||||
uniqueID := fmt.Sprintf("%s-%d", string(idRunes), time.Now().UnixNano())
|
||||
|
||||
return uniqueID
|
||||
}
|
||||
|
||||
type Paste struct {
|
||||
ID string
|
||||
Content string
|
||||
CreatedAt time.Time
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
|
||||
func InitializeTemplates() error {
|
||||
templateDir = viper.GetString("TemplateDir")
|
||||
pasteTmpl = template.Must(template.ParseFiles(filepath.Join(templateDir, "paste.html")))
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreatePasteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Parse the request body
|
||||
content, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to read request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the private flag is set
|
||||
private := viper.GetBool("Private")
|
||||
|
||||
// Log the event
|
||||
log.Infof("Received request to create a paste (Private mode: %v)", private)
|
||||
|
||||
// Log the content if private mode is not enabled
|
||||
if !private {
|
||||
log.Infof("Received content: %s", content)
|
||||
}
|
||||
|
||||
// Generate a unique ID for the paste
|
||||
pasteID := generateUniqueID()
|
||||
|
||||
// Save the paste in the map
|
||||
paste := &Paste{
|
||||
ID: pasteID,
|
||||
Content: string(content),
|
||||
CreatedAt: time.Now(),
|
||||
ExpiresAt: time.Now().Add(24 * time.Hour),
|
||||
}
|
||||
|
||||
pasteMap[pasteID] = paste
|
||||
|
||||
// Get the directory path from configuration
|
||||
pasteDir := viper.GetString("PasteDir")
|
||||
|
||||
// Create the paste directory if it doesn't exist
|
||||
if err := util.CreateDirectoryIfNotExists(pasteDir); err != nil {
|
||||
logger.Errorf("Failed to create paste directory: %v", err)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Save the paste content to a file
|
||||
pasteFilePath := filepath.Join(pasteDir, pasteID+".txt")
|
||||
pasteFile, err := os.Create(pasteFilePath)
|
||||
if err != nil {
|
||||
logger.Errorf("Failed to create paste file: %v", err)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer pasteFile.Close()
|
||||
|
||||
// Write the paste content to the file
|
||||
_, err = pasteFile.WriteString(string(content))
|
||||
if err != nil {
|
||||
logger.Errorf("Failed to write paste content to file: %v", err)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Determine the protocol based on the request's TLS connection
|
||||
protocol := "http"
|
||||
if r.TLS != nil {
|
||||
protocol = "https"
|
||||
}
|
||||
|
||||
// Construct the complete paste URL with the protocol
|
||||
pasteURL := fmt.Sprintf("%s://%s/%s", protocol, r.Host, pasteID)
|
||||
|
||||
// Remove any trailing '%' character from the pasteURL
|
||||
if strings.HasSuffix(pasteURL, "%") {
|
||||
pasteURL = pasteURL[:len(pasteURL)-1]
|
||||
}
|
||||
|
||||
// Write the paste URL in the response
|
||||
response := fmt.Sprintf("Paste available at %s", pasteURL)
|
||||
w.Write([]byte(response))
|
||||
}
|
||||
|
||||
func GetPasteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
pasteID := vars["id"]
|
||||
|
||||
p, exists := pasteMap[pasteID]
|
||||
if !exists {
|
||||
http.Error(w, "Paste not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
if time.Now().After(p.ExpiresAt) {
|
||||
delete(pasteMap, pasteID)
|
||||
http.Error(w, "Paste has expired", http.StatusGone)
|
||||
return
|
||||
}
|
||||
|
||||
log.Infof("Template file path: %s", templateDir)
|
||||
|
||||
err := pasteTmpl.Execute(w, p)
|
||||
if err != nil {
|
||||
log.Errorf("Error executing template: %v", err)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func ExpirePastes() {
|
||||
// Read the expiration duration from configuration
|
||||
expirationDuration := viper.GetDuration("ExpirationDuration")
|
||||
|
||||
for {
|
||||
time.Sleep(expirationDuration)
|
||||
|
||||
for pasteID, p := range pasteMap {
|
||||
if time.Now().After(p.ExpiresAt) {
|
||||
delete(pasteMap, pasteID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
15
internal/router/router.go
Normal file
15
internal/router/router.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"goblin/internal/paste"
|
||||
)
|
||||
|
||||
func NewRouter() http.Handler {
|
||||
r := mux.NewRouter()
|
||||
r.HandleFunc("/", paste.CreatePasteHandler).Methods("POST")
|
||||
r.HandleFunc("/{id}", paste.GetPasteHandler).Methods("GET")
|
||||
return r
|
||||
}
|
17
internal/util/util.go
Normal file
17
internal/util/util.go
Normal file
|
@ -0,0 +1,17 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// CreateDirectoryIfNotExists creates the specified directory if it doesn't exist.
|
||||
func CreateDirectoryIfNotExists(directoryPath string) error {
|
||||
// Check if the directory already exists
|
||||
if _, err := os.Stat(directoryPath); os.IsNotExist(err) {
|
||||
// Directory doesn't exist, create it
|
||||
if err := os.MkdirAll(directoryPath, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
Reference in a new issue