ref: 3a49d4e373f8e2887bea84ee3d2fca14bbc6f7fa
author: halfwit <michaelmisch1985@gmail.com>
date: Thu Jan 24 17:02:57 PST 2019
First commit
--- /dev/null
+++ b/plumb.go
@@ -1,0 +1,158 @@
+package main
+
+import (
+ "flag"
+ "log"
+ "mime"
+ "net/http"
+ "net/url"
+ "os"
+ "strings"
+
+ "9fans.net/go/plumb"
+)
+
+var (
+ plumbfile = flag.String("p", "/mnt/plumb/send", "write the message to plumbfile (default /mnt/plumb/send)")
+ attributes = flag.String("a", "", "set the attr field of the message (default is empty), expects key=value")
+ source = flag.String("s", "", "set the src field of the message (default is store)")
+ destination = flag.String("d", "", "set the dst filed of the message (default is store)")
+ directory = flag.String("w", "", "set the wdir field of the message (default is current directory)")
+)
+
+type storeMsg struct {
+ src string
+ dst string
+ wdir string
+ msgtype string
+ attr *plumb.Attribute
+ ndata int
+ data string
+}
+
+func (s storeMsg) send() error {
+ fd, err := os.OpenFile(*plumbfile, os.O_WRONLY, 0644)
+ if err != nil {
+ return err
+ }
+ message := &plumb.Message{
+ Src: s.src,
+ Dst: s.dst,
+ Dir: s.wdir,
+ Type: s.msgtype,
+ Attr: s.attr,
+ Data: []byte(s.data),
+ }
+ return message.Send(fd)
+}
+
+func newStoreMsg(mediaType, wdir, arg string, attr *plumb.Attribute) *storeMsg {
+ sf := &storeMsg{
+ src: os.Args[0],
+ dst: "",
+ wdir: wdir,
+ msgtype: mediaType,
+ attr: attr,
+ ndata: len(arg),
+ data: arg,
+ }
+ if *source != "" {
+ sf.src = *source
+ }
+ if *destination != "" {
+ sf.dst = *destination
+ }
+ return sf
+}
+
+func paramsToAttr(params map[string]string) *plumb.Attribute {
+ // Attribute is a linked list - we only get one from content-type, the encoding
+ attr := &plumb.Attribute{Name: "", Value: ""}
+ for key, value := range params {
+ if (attr.Name == "" || attr.Value == "") {
+ continue
+ }
+ attr.Name = key
+ attr.Value = value
+ }
+ if *attributes != "" {
+ attr.Name = strings.TrimLeft(*attributes, "=")
+ attr.Value = strings.TrimRight(*attributes, "=")
+ }
+ return attr
+}
+
+func contentTypeUrl(arg string) (string, error) {
+ // We read in 512 bytes
+ buf := make([]byte, 512)
+ u, err := url.ParseRequestURI(arg)
+ if err != nil {
+ return "text", nil
+ }
+ r, err := http.Get(u.String())
+ if err != nil {
+ return "", err
+ }
+ defer r.Body.Close()
+ n, err := r.Body.Read(buf)
+ if err != nil {
+ return "", err
+ }
+ return http.DetectContentType(buf[:n]), nil
+}
+
+func contentTypeFile(arg string) (string, error) {
+ buf := make([]byte, 512)
+ fd, err := os.Open(arg)
+ if err != nil {
+ return "", err
+ }
+ defer fd.Close()
+ n, err := fd.Read(buf)
+ if err != nil {
+ return "", err
+ }
+ return http.DetectContentType(buf[:n]), nil
+}
+
+func content(arg string) (string, error) {
+ if _, err := os.Stat(arg); os.IsNotExist(err) {
+ return contentTypeUrl(arg)
+ }
+ return contentTypeFile(arg)
+}
+
+func getMediaType(ct string) (string, *plumb.Attribute) {
+ if ct == "text" {
+ return ct, nil
+ }
+ mediaType, params, err := mime.ParseMediaType(ct)
+ if err != nil {
+ log.Fatal(err)
+ }
+ return mediaType, paramsToAttr(params)
+}
+
+func main() {
+ flag.Parse()
+ if flag.Lookup("h") != nil {
+ flag.Usage()
+ os.Exit(1)
+ }
+ wdir, err := os.Getwd()
+ if err != nil {
+ log.Fatal(err)
+ }
+ for _, arg := range os.Args[1:] {
+ ct, err := content(arg)
+ if err != nil {
+ log.Fatal(err)
+ }
+ mediaType, params := getMediaType(ct)
+ storeMsg := newStoreMsg(mediaType, wdir, arg, params)
+ err = storeMsg.send()
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+}