Skip to content
Permalink
Browse files

Small refactoring

- use of `new(struct)` is discouraged in modern Go - use `&struct{}`
- extract some important strings into consts (feel free to remove/add more if required)
- wrap errors with `fmt.Errorf("%w", err)` - this adds context to the error, passing it further to the main caller, allowing it to see the whole chain
- `defer response.Body.Close()` is usually placed right after the initial error check, there's no need to delay it
- add more error checks
  • Loading branch information
nezorflame authored and deletescape committed Oct 18, 2019
1 parent 8210528 commit cb15fb15ba70b57cb4c678bfcea89e748a2df8d2
Showing with 97 additions and 68 deletions.
  1. +2 −1 .gitignore
  2. +47 −24 dogbin/dogbin.go
  3. +48 −43 inu.go
@@ -1,4 +1,5 @@
.idea
.vscode
*.iml
out
gen
@@ -9,4 +10,4 @@ gen
*.dylib
*.test
*.out
inu
inu
@@ -10,6 +10,12 @@ import (
"net/url"
)

// Public consts
const (
DogbinServerURL = "del.dog"
HastebinServerURL = "hastebin.com"
)

// Server defines the dogbin or hastebin server to communicate with
type Server struct {
server string
@@ -49,13 +55,27 @@ type Document struct {
ViewCount int `json:"viewCount"`
}

func newDocument(w *Wrapper) *Document {
d := &Document{
Slug: w.Slug,
Content: w.Content,
}

if w.Document != nil {
d.IsUrl = w.Document.IsUrl
d.ViewCount = w.Document.ViewCount
}
return d
}

// Put uploads content to the server,
// if a slug is supplied it is assumed that the server supports
// the extended api used by dogbin.
func (d Server) Put(slug string, content string) (*UploadResult, error) {
if content == "" {
return nil, errors.New("no content was provided")
}

u, err := d.putUrl()
if err != nil {
return nil, err
@@ -102,43 +122,43 @@ func (d Server) Get(slug string) (*Document, error) {
if err != nil {
return nil, err
}

r, err := http.Get(u)
if err != nil {
return nil, err
}
defer r.Body.Close()

if r.StatusCode != http.StatusOK {
message := &Message{}
if err = json.NewDecoder(r.Body).Decode(message); err != nil {
return nil, fmt.Errorf("unable to make request (%s) and decode response: %w", r.Status, err)
}

if r.StatusCode != 200 {
message := new(Message)
defer r.Body.Close()
_ = json.NewDecoder(r.Body).Decode(message)
if message.Message == "" {
message.Message = r.Status
}
return nil, errors.New(message.Message)
return nil, fmt.Errorf("unable to make request: %s", message.Message)
}

wrapper := new(Wrapper)
defer r.Body.Close()
err = json.NewDecoder(r.Body).Decode(wrapper)

document := Document{
Slug: wrapper.Slug,
Content: wrapper.Content,
wrapper := &Wrapper{}
if err = json.NewDecoder(r.Body).Decode(wrapper); err != nil {
return nil, fmt.Errorf("unable to decode response: %w", err)
}
if wrapper.Document != nil {
document.IsUrl = wrapper.Document.IsUrl
document.ViewCount = wrapper.Document.ViewCount
if wrapper == nil {
return nil, errors.New("unable to decode response: document is empty")
}

return &document, err
return newDocument(wrapper), err
}

// baseUrl returns the base Url for the server, assuming https if no scheme has been supplied
func (d Server) baseUrl() (string, error) {
srv, err := url.Parse(d.server)
if err != nil {
return "", err
return "", fmt.Errorf("unable to parse server URL: %w", err)
}

if srv.Scheme == "" {
srv.Scheme = "https"
}
@@ -149,26 +169,29 @@ func (d Server) baseUrl() (string, error) {
func (d Server) slugUrl(slug string) (string, error) {
base, err := d.baseUrl()
if err != nil {
return "", nil
return "", fmt.Errorf("unable to get base URL: %w", err)
}

return fmt.Sprintf("%s/%s", base, slug), nil
}

// getUrl returns the Url to get details about the document with the supplied slug
func (d Server) getUrl(slug string) (string, error) {
base, err := d.baseUrl()
if err != nil {
return "", nil
return "", fmt.Errorf("unable to get base URL: %w", err)
}

return fmt.Sprintf("%s/documents/%s", base, slug), nil
}

// putUrl returns the Url of the upload endpoint
func (d Server) putUrl() (string, error) {
base, err := d.baseUrl()
if err != nil {
return "", nil
return "", fmt.Errorf("unable to get base URL: %w", err)
}

return fmt.Sprintf("%s/documents", base), nil
}

@@ -177,12 +200,12 @@ func NewServer(server string) Server {
return Server{server: server}
}

// Dogbin returns a Server instance configured for the public del.dog dogbin instance
// Dogbin returns a Server instance configured for the public 'del.dog' dogbin instance
func Dogbin() Server {
return Server{server: "del.dog"}
return Server{server: DogbinServerURL}
}

// Hastebin returns a Server instance configured for the public hastebin.com hastebin instance
// Hastebin returns a Server instance configured for the public 'hastebin.com' hastebin instance
func Hastebin() Server {
return Server{server: "hastebin.com"}
return Server{server: HastebinServerURL}
}
91 inu.go
@@ -4,7 +4,6 @@ import (
"bufio"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/url"
"os"
@@ -16,13 +15,29 @@ import (
"github.com/urfave/cli"
)

var server string
var slug string
var file string
var jsonOutput bool
var clipboardOutput bool
const (
appAuthorName = "Till Kottmann"
appAuthorEmail = "me@deletescape.ch"
appCopyright = "(c) 2019 " + appAuthorName
appName = "inu"
appVersion = "v0.1.2"
)

var (
file string
server string
slug string
clipboardOutput bool
jsonOutput bool
)

func main() {
fileFlag := cli.StringFlag{
Name: "file, f",
Usage: "A file to upload to dogbin",
TakesFile: true,
Destination: &file,
}
serverFlag := cli.StringFlag{
Name: "server, r",
Usage: "The dogbin/hastebin server to use",
@@ -36,12 +51,6 @@ func main() {
Usage: "The slug to use instead of the server generated one [haste doesn't support this]",
Destination: &slug,
}
fileFlag := cli.StringFlag{
Name: "file, f",
Usage: "A file to upload to dogbin",
TakesFile: true,
Destination: &file,
}
jsonFlag := cli.BoolFlag{
Name: "json, j",
Usage: "Outputs the result as JSON",
@@ -54,16 +63,16 @@ func main() {
}

app := cli.NewApp()
app.Name = "inu"
app.Name = appName
app.Usage = "Use dogbin/hastebin right from your terminal"
app.Copyright = "(c) 2019 Till Kottmann"
app.Copyright = appCopyright
app.Authors = []cli.Author{
{
Name: "Till Kottmann",
Email: "me@deletescape.ch",
Name: appAuthorName,
Email: appAuthorEmail,
},
}
app.Version = "v0.1.2"
app.Version = appVersion
app.EnableBashCompletion = true
app.Action = put
app.Flags = []cli.Flag{
@@ -116,7 +125,10 @@ func main() {
}

func put(c *cli.Context) error {
info, _ := os.Stdin.Stat()
info, err := os.Stdin.Stat()
if err != nil {
return fmt.Errorf("unable to stat os.Stdin: %w", err)
}

var content string
if info.Mode()&os.ModeNamedPipe != 0 {
@@ -127,8 +139,9 @@ func put(c *cli.Context) error {
} else if file != "" {
buf, err := ioutil.ReadFile(file)
if err != nil {
return err
return fmt.Errorf("unable to read the file '%s': %w", file, err)
}

content = string(buf)
if c.NArg() == 1 {
slug = c.Args()[0]
@@ -144,19 +157,18 @@ func put(c *cli.Context) error {

result, err := dogbin.NewServer(server).Put(slug, content)
if err != nil {
return cli.NewExitError(err.Error(), 1)
return cli.NewExitError(err, 1)
}

if clipboardOutput {
if err := clipboard.WriteAll(result.Url); err != nil {
return err
if err = clipboard.WriteAll(result.Url); err != nil {
return fmt.Errorf("unable to write the output into the clipboard: %w", err)
}
}

if jsonOutput {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")

return enc.Encode(result)
}

@@ -165,7 +177,6 @@ func put(c *cli.Context) error {
}

func get(c *cli.Context) error {

if c.NArg() == 1 {
slug = c.Args()[0]
}
@@ -174,17 +185,16 @@ func get(c *cli.Context) error {
return cli.ShowCommandHelp(c, "get")
}

var tmp = slug

if strings.ContainsRune(tmp, '/') {
pasteURL := slug
if strings.ContainsRune(pasteURL, '/') {
// convert slug to url to attempt to extract path + server from it
if !strings.HasPrefix(tmp, "http") && !strings.HasPrefix(tmp, "/") {
tmp = "https://" + tmp
if !strings.HasPrefix(pasteURL, "http") && !strings.HasPrefix(pasteURL, "/") {
pasteURL = "https://" + pasteURL
}
u, err := url.Parse(tmp)
u, err := url.Parse(pasteURL)
if err == nil {
if path := u.Path[1:]; path != "" {
tmp = path
pasteURL = path
}
u.Path = ""
u.RawQuery = ""
@@ -197,11 +207,11 @@ func get(c *cli.Context) error {
}
}

if strings.ContainsRune(tmp, '.') {
tmp = strings.SplitN(tmp, ".", 2)[0]
if strings.ContainsRune(pasteURL, '.') {
pasteURL = strings.SplitN(pasteURL, ".", 2)[0]
}

doc, err := dogbin.NewServer(server).Get(tmp)
doc, err := dogbin.NewServer(server).Get(pasteURL)
if err != nil {
return cli.NewExitError(err.Error(), 1)
}
@@ -224,15 +234,10 @@ func get(c *cli.Context) error {
}

func readStdin() string {
reader := bufio.NewReader(os.Stdin)
var input []rune

for {
ch, _, err := reader.ReadRune()
if err != nil && err == io.EOF {
break
}
input = append(input, ch)
var input []byte
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
input = append(input, scanner.Bytes()...)
}

return string(input)

0 comments on commit cb15fb1

Please sign in to comment.
You can’t perform that action at this time.