~kota/pcf

pcf/main.go -rw-r--r-- 2.8 KiB
273b271dDakota Walsh bump version 20 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// pcf - A powerful paste.cf command line client
// Copyright (C) 2019 Dakota Walsh
// GPL3+ See LICENSE in this repo for details.
package main

import (
	"bytes"
	"crypto/sha1"
	"fmt"
	"io"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"time"

	"github.com/jlaffaye/ftp"
)

func main() {
	addr := os.Getenv("PCFSERVER")
	if addr == "" {
		fmt.Println("pcf: you must set the PCFSERVER environment variable!")
		os.Exit(1)
	}

	// parse the ftpURL
	ftpURL, err := url.Parse(addr)
	if err != nil {
		fmt.Fprintf(os.Stderr, "pcf: url configuration wrong: %v\n", err)
	}
	args := os.Args[1:]

	if len(args) == 0 {
		// use stdin data
		inBytes, err := io.ReadAll(os.Stdin)
		if err != nil {
			fmt.Fprintf(os.Stderr, "pcf: failed reading stdin: %v\n", err)
			os.Exit(1)
		}
		// create reader (that supports seek) from stdinBytes
		in := bytes.NewReader(inBytes)
		connection := login(ftpURL)
		store(ftpURL, in, connection, "file")
		exit(connection)
		// calculate the hash (setting the reader to byte 0 first)
		if _, err := in.Seek(0, 0); err != nil {
			fmt.Fprintf(os.Stderr, "pcf: failed to read: %v\n", err)
			os.Exit(1)
		}
		h := hash(in)
		webURL := *ftpURL
		webURL.Host = ftpURL.Hostname()
		webURL.Path = h
		fmt.Println(&webURL)
	} else {
		// loop through and use all arguments
		connection := login(ftpURL)
		for _, arg := range args {
			file, err := os.Open(arg)
			if err != nil {
				fmt.Fprintf(os.Stderr, "pcf: open: %v\n", err)
				continue
			}
			defer file.Close()

			// store the file
			store(ftpURL, file, connection, filepath.Base(arg))

			// calculate the hash (setting the reader to byte 0 first)
			if _, err := file.Seek(0, 0); err != nil {
				fmt.Fprintf(os.Stderr, "pcf: failed to read: %v\n", err)
				os.Exit(1)
			}
			h := hash(file)

			// print the URL
			webURL := *ftpURL
			webURL.Host = ftpURL.Hostname()
			webURL.Path = h + filepath.Ext(arg)
			fmt.Println(&webURL)
		}
		exit(connection)
	}
}

// create the ftp connection
func login(u *url.URL) *ftp.ServerConn {
	c, err := ftp.Dial(u.Host, ftp.DialWithTimeout(10*time.Second))
	if err != nil {
		fmt.Fprintf(os.Stderr, "pcf: %v\n", err)
	}
	err = c.Login("anonymous", "anonymous")
	if err != nil {
		fmt.Fprintf(os.Stderr, "pcf: login: %v\n", err)
	}
	return c
}

// store the file in the connection
func store(u *url.URL, r io.Reader, c *ftp.ServerConn, n string) {
	err := c.Stor(path.Join(u.Path, n), r)
	if err != nil {
		fmt.Fprintf(os.Stderr, "pcf: put: %v\n", err)
	}
}

// calculate and print the hash
func hash(f io.Reader) string {
	h := sha1.New()
	if _, err := io.Copy(h, f); err != nil {
		fmt.Fprintf(os.Stderr, "pcf: failed to hash: %v\n", err)
	}
	return fmt.Sprintf("%x", h.Sum(nil))
}

// close the ftp connection
func exit(c *ftp.ServerConn) {
	err := c.Quit()
	if err != nil {
		fmt.Fprintf(os.Stderr, "pcf: quit: %v\n", err)
	}
}