main.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // ipfs-waveform-kit produces waveform plots for audiofiles (using bbcrd/audiowaveform) and stores them in ipfs (ipfs.io)
  2. package main
  3. import (
  4. "encoding/json"
  5. "flag"
  6. "io"
  7. "log"
  8. "net/http"
  9. "os"
  10. "os/exec"
  11. "github.com/cryptix/exp/ipfs-embeddedShell"
  12. "golang.org/x/net/context"
  13. "gopkg.in/errgo.v1"
  14. "github.com/go-kit/kit/endpoint"
  15. httptransport "github.com/go-kit/kit/transport/http"
  16. )
  17. var (
  18. ErrBadRequest = errgo.New("ipfs-waveform-kit: BadRequest")
  19. )
  20. type WaveformService interface {
  21. Analyze(string) (string, error)
  22. }
  23. type waveformService struct {
  24. shell *embeddedShell.Shell
  25. }
  26. func (ws waveformService) Analyze(path string) (string, error) {
  27. rc, err := ws.shell.Cat(path)
  28. if err != nil {
  29. return "", errgo.Notef(err, "Analyze: cat(%q) failed.", path)
  30. }
  31. // throw into bbcrd audiowaveform
  32. // wait for stdio. https://github.com/bbcrd/audiowaveform/issues/13
  33. cmd := exec.Command("audiowaveform", "--input", "-")
  34. cmd.Stdin = rc
  35. outP, err := cmd.StdoutPipe()
  36. if err != nil {
  37. return "", errgo.Notef(err, "Analyze: failed to get output pipe fr audiowaveform tool")
  38. }
  39. logP, err := cmd.StderrPipe()
  40. if err == nil {
  41. go func() {
  42. _, err := io.Copy(os.Stderr, logP)
  43. log.Println("audiowaveform stderr:", err)
  44. }()
  45. }
  46. errc := make(chan error)
  47. go func() {
  48. errc <- cmd.Run()
  49. }()
  50. hash, err := ws.shell.Add(outP)
  51. if err != nil {
  52. return "", errgo.Notef(err, "Analyze: failed to ipfs.Add() waveform data")
  53. }
  54. if err := <-errc; err != nil {
  55. return "", errgo.Notef(err, "Analyze: subprocess failed")
  56. }
  57. if err := rc.Close(); err != nil {
  58. return "", errgo.Notef(err, "Analyze: failed to close cat.")
  59. }
  60. return hash, nil
  61. }
  62. var _ WaveformService = &waveformService{}
  63. var repoPath = flag.String("ipfsrepo", "./ipfsRepo", "where to open the repo (use IPFS_PATH=... ipfs init)")
  64. func main() {
  65. flag.Parse()
  66. _, err := exec.LookPath("audiowaveform")
  67. if err != nil {
  68. log.Fatal(err)
  69. }
  70. ctx := context.Background()
  71. node, err := embeddedShell.NewDefaultNodeWithFSRepo(ctx, *repoPath)
  72. if err != nil {
  73. log.Fatal(err)
  74. }
  75. shell := embeddedShell.NewShellWithContext(node, ctx)
  76. svc := waveformService{shell}
  77. analyzeHandler := httptransport.NewServer(
  78. ctx,
  79. makeAnalyzeEndpoint(svc),
  80. decodeAnalyzeRequest,
  81. encodeResponse,
  82. )
  83. http.Handle("/analyze", analyzeHandler)
  84. log.Fatal(http.ListenAndServe(":9080", nil))
  85. }
  86. func makeAnalyzeEndpoint(svc WaveformService) endpoint.Endpoint {
  87. return func(ctx context.Context, request interface{}) (interface{}, error) {
  88. req, ok := request.(analyzeRequest)
  89. if !ok {
  90. return analyzeResponse{"", ErrBadRequest.Error()}, nil
  91. }
  92. v, err := svc.Analyze(req.S)
  93. if err != nil {
  94. return analyzeResponse{"", err.Error()}, nil
  95. }
  96. return analyzeResponse{v, ""}, nil
  97. }
  98. }
  99. func decodeAnalyzeRequest(r *http.Request) (interface{}, error) {
  100. var request analyzeRequest
  101. if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
  102. return nil, err
  103. }
  104. return request, nil
  105. }
  106. func encodeResponse(w http.ResponseWriter, resp interface{}) error {
  107. return json.NewEncoder(w).Encode(resp)
  108. }
  109. type analyzeRequest struct {
  110. S string `json:"s"`
  111. }
  112. type analyzeResponse struct {
  113. V string `json:"v"`
  114. Err string `json:"err,omitempty"` // errors don't define JSON marshaling
  115. }