From 977eb4a82d00f14cb6d3f965841a4d8f9bab0702 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 10 Feb 2023 11:57:09 +0800 Subject: [PATCH] Create a command line tool and add file and server commands --- Dockerfile | 2 +- cmd/file.go | 48 ++++++++++++++++++++++++++ cmd/root.go | 19 +++++++++++ cmd/server.go | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 71 ++------------------------------------- 5 files changed, 163 insertions(+), 70 deletions(-) create mode 100644 cmd/file.go create mode 100644 cmd/root.go create mode 100644 cmd/server.go diff --git a/Dockerfile b/Dockerfile index 89f2036..edf9edd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,4 +17,4 @@ RUN go build -o app . EXPOSE 8080 # Command to run the executable -CMD ["./app"] +CMD ["./app", "server"] diff --git a/cmd/file.go b/cmd/file.go new file mode 100644 index 0000000..b2b6606 --- /dev/null +++ b/cmd/file.go @@ -0,0 +1,48 @@ +/* +Copyright © 2023 NAME HERE +*/ +package cmd + +import ( + "fmt" + "os" + + "github.com/go-shiori/dom" + "github.com/omnivore-app/go-domdistiller/distiller" + "github.com/spf13/cobra" +) + +// fileCmd represents the file command +var fileCmd = &cobra.Command{ + Use: "file", + Short: "Extracts the main content from a file", + Run: func(cmd *cobra.Command, args []string) { + extractFromFile(cmd.Flag("input").Value.String(), cmd.Flag("output").Value.String()) + }, +} + +func extractFromFile(inputPath string, outputPath string) { + // Apply distiller + result, err := distiller.ApplyForFile(inputPath, nil) + if err != nil { + panic(err) + } + + // Print result + rawHTML := dom.OuterHTML(result.Node) + + file, err := os.Create(outputPath) + if err != nil { + panic(err) + } + fmt.Fprint(file, rawHTML) +} + +func init() { + rootCmd.AddCommand(fileCmd) + + fileCmd.Flags().StringP("input", "i", "", "Path to the file to extract the main content from") + fileCmd.MarkFlagRequired("input") + fileCmd.Flags().StringP("output", "o", "", "Path to the file to write the extracted content to") + fileCmd.MarkFlagRequired("output") +} diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..dd1a424 --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,19 @@ +package cmd + +import ( + "os" + + "github.com/spf13/cobra" +) + +var rootCmd = &cobra.Command{ + Use: "go-domdistiller", + Short: "go-domdistiller is a CLI tool for extracting the main content of a web page", +} + +func Execute() { + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} diff --git a/cmd/server.go b/cmd/server.go new file mode 100644 index 0000000..94a930c --- /dev/null +++ b/cmd/server.go @@ -0,0 +1,93 @@ +/* +Copyright © 2023 NAME HERE +*/ +package cmd + +import ( + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "strings" + + "github.com/go-shiori/dom" + "github.com/golang-jwt/jwt" + "github.com/omnivore-app/go-domdistiller/distiller" + "github.com/spf13/cobra" +) + +// serverCmd represents the server command +var serverCmd = &cobra.Command{ + Use: "server", + Short: "Starts a server that accepts HTML and returns the main content", + Run: func(cmd *cobra.Command, args []string) { + start() + }, +} + +func start() { + log.Print("starting server...") + http.HandleFunc("/", handler) + + // Determine port for HTTP service. + port := os.Getenv("PORT") + if port == "" { + port = "8080" + log.Printf("defaulting to port %s", port) + } + + // Start HTTP server. + log.Printf("listening on port %s", port) + if err := http.ListenAndServe(":"+port, nil); err != nil { + log.Fatal(err) + } +} + +func handler(w http.ResponseWriter, r *http.Request) { + // decode JWT token and check if it's valid + token, err := jwt.Parse(r.Header.Get("Authorization"), func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) + } + return []byte(os.Getenv("JWT_SECRET")), nil + }) + if err != nil { + w.WriteHeader(http.StatusUnauthorized) + fmt.Fprint(w, "Unauthorized") + return + } + if !token.Valid { + w.WriteHeader(http.StatusUnauthorized) + fmt.Fprint(w, "Unauthorized") + return + } + + // Parse request body + body, err := ioutil.ReadAll(r.Body) + if err != nil { + log.Println("Failed to read request body:", err) + w.WriteHeader(http.StatusBadRequest) + fmt.Fprint(w, "Failed to read request body") + return + } + + // Apply distiller + result, err := distiller.ApplyForReader(strings.NewReader(string(body)), nil) + if err != nil { + fmt.Println("Failed to apply distiller:", err) + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprint(w, "Failed to apply distiller") + return + } + + // Print result + rawHTML := dom.OuterHTML(result.Node) + fmt.Fprint(w, rawHTML) +} + +func init() { + rootCmd.AddCommand(serverCmd) + + serverCmd.Flags().StringP("port", "p", "8080", "Port to listen on") +} diff --git a/main.go b/main.go index 6fb20d9..fc3aa31 100644 --- a/main.go +++ b/main.go @@ -1,74 +1,7 @@ package main -import ( - "fmt" - "io/ioutil" - "log" - "net/http" - "os" - "strings" - - "github.com/go-shiori/dom" - "github.com/omnivore-app/go-domdistiller/distiller" - "github.com/golang-jwt/jwt" -) +import "github.com/omnivore-app/go-domdistiller/cmd" func main() { - log.Print("starting server...") - http.HandleFunc("/", handler) - - // Determine port for HTTP service. - port := os.Getenv("PORT") - if port == "" { - port = "8080" - log.Printf("defaulting to port %s", port) - } - - // Start HTTP server. - log.Printf("listening on port %s", port) - if err := http.ListenAndServe(":"+port, nil); err != nil { - log.Fatal(err) - } -} - -func handler(w http.ResponseWriter, r *http.Request) { - // decode JWT token and check if it's valid - token, err := jwt.Parse(r.Header.Get("Authorization"), func(token *jwt.Token) (interface{}, error) { - if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { - return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) - } - return []byte(os.Getenv("JWT_SECRET")), nil - }) - if err != nil { - w.WriteHeader(http.StatusUnauthorized) - fmt.Fprint(w, "Unauthorized") - return - } - if !token.Valid { - w.WriteHeader(http.StatusUnauthorized) - fmt.Fprint(w, "Unauthorized") - return - } - - // Parse request body - body, err := ioutil.ReadAll(r.Body) - if err != nil { - log.Println("Failed to read request body:", err) - w.WriteHeader(http.StatusBadRequest) - fmt.Fprint(w, "Failed to read request body") - return - } - - // Apply distiller - result, err := distiller.ApplyForReader(strings.NewReader(string(body)), nil) - if err != nil { - fmt.Println("Failed to apply distiller:", err) - w.WriteHeader(http.StatusInternalServerError) - fmt.Fprint(w, "Failed to apply distiller") - return - } - - // Print result - rawHTML := dom.OuterHTML(result.Node) - fmt.Fprint(w, rawHTML) + cmd.Execute() }