func handleFile(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } var key *cafs.SKey if k, err := cafs.ParseKey(r.URL.Path[6:]); err != nil { http.NotFound(w, r) log.Printf("Error parsing key from URL %v: %v", r.URL, err) return } else { key = k } var reader io.ReadCloser if f, err := client.GetActivityManager().GetStorage().Get(key); err != nil { http.NotFound(w, r) log.Printf("Error retrieving key %v: %v", key, err) return } else { reader = f.Open() f.Dispose() } defer func() { if err := reader.Close(); err != nil { log.Printf("Error closing file: %v", err) } }() if _, err := io.Copy(w, reader); err != nil { log.Printf("Error sending file contents to client: %v", err) } }
func handleRevokeMandate(r *http.Request) error { if key, err := strconv.ParseInt(r.FormValue("key"), 10, 64); err != nil { return err } else { client.GetActivityManager().UnregisterMandate(client.ActivityKey(key)) } return nil }
func handleActivities(w http.ResponseWriter, r *http.Request) { activities := client.GetActivityManager().GetActivitiesSorted() infos := make([]activityInfo, len(activities)) w.Header().Set("Content-Type", "application/json") for k, v := range activities { infos[k] = activityInfo{v.GetKey(), v.GetState()} } if err := json.NewEncoder(w).Encode(infos); err != nil { panic(err) } }
func handleGrantMandate(r *http.Request) error { var mandate client.Mandate mandate.Identity = BitcoinIdentity if r.FormValue("type") == "BUY" { mandate.BidType = bitwrk.Buy } else if r.FormValue("type") == "SELL" { mandate.BidType = bitwrk.Sell } else { return fmt.Errorf("Illegal trade type: %v", r.FormValue("type")) } mandate.Article = bitwrk.ArticleId(r.FormValue("articleid")) if err := mandate.Price.Parse(r.FormValue("price")); err != nil { return err } mandate.UseTradesLeft = "on" == r.FormValue("usetradesleft") mandate.UseUntil = "on" == r.FormValue("usevaliduntil") if n, err := strconv.ParseInt(r.FormValue("tradesleft"), 10, 32); err != nil { return fmt.Errorf("Illegal value for trades left: %v", err) } else if n <= 0 { return fmt.Errorf("Number of trades left must be positive, but is: %v", n) } else { mandate.TradesLeft = int(n) } if n, err := strconv.ParseInt(r.FormValue("validminutes"), 10, 32); err != nil { return fmt.Errorf("Illegal value for minutes left: %v", err) } else if n <= 0 { return fmt.Errorf("Number of minutes left must be positive, but is: %v", n) } else { mandate.Until = time.Now().Add(time.Duration(n) * time.Minute) } if !mandate.UseTradesLeft && !mandate.UseUntil { mandate.UseTradesLeft = true mandate.TradesLeft = 1 } key := client.GetActivityManager().NewKey() client.GetActivityManager().RegisterMandate(key, &mandate) return nil }
func main() { protocol.BitwrkUserAgent = "BitWrkGoClient/" + ClientVersion flags := flag.NewFlagSet("bitwrk-client", flag.ExitOnError) flags.StringVar(&ExternalAddress, "extaddr", "auto", "IP address or name this host can be reached under from the internet") flags.IntVar(&ExternalPort, "extport", -1, "Port that can be reached from the Internet (-1 disables incoming connections)") flags.IntVar(&InternalPort, "intport", 8081, "Maintenance port for admin interface") flags.StringVar(&InternalIface, "intiface", "127.0.0.1", "Network interface for admin interface") flags.StringVar(&ResourceDir, "resourcedir", "auto", "Directory where the bitwrk client loads resources from") flags.StringVar(&BitwrkUrl, "bitwrkurl", "http://bitwrk.appspot.com/", "URL to contact the bitwrk service at") flags.BoolVar(&cafs.LoggingEnabled, "log-cafs", cafs.LoggingEnabled, "Enable logging for content-addressable file storage") flags.IntVar(&client.NumUnmatchedBids, "num-unmatched-bids", client.NumUnmatchedBids, "Mamimum number of unmatched bids for an article on server") flags.StringVar(&TrustedAccount, "trusted-account", "1TrsjuCvBch1D9h6nRkadGKakv9KyaiP6", "Account to trust when verifying deposit information.") err := flags.Parse(os.Args[1:]) if err == flag.ErrHelp { flags.Usage() } else if err != nil { log.Fatalf("Error parsing command line: %v", err) os.Exit(1) } if ResourceDir == "auto" { if dir, err := AutoFindResourceDir("bitwrk-client", ClientVersion); err != nil { log.Fatalf("Error finding resource directory: %v", err) } else { ResourceDir = dir } } else { if err := TestResourceDir(ResourceDir, "bitwrk-client", ClientVersion); err != nil { log.Fatalf("Directory [%v] is not a valid resource directory: %v", err) } } BitcoinIdentity = LoadOrCreateIdentity("bitwrk-client", bitcoin.AddrVersionBitcoin) if !strings.HasSuffix(BitwrkUrl, "/") { BitwrkUrl = BitwrkUrl + "/" } log.Printf("Bitwrk URL: %v", BitwrkUrl) protocol.BitwrkUrl = BitwrkUrl log.Printf("Resource directory: %v\n", ResourceDir) initTemplates() receiveManager := startReceiveManager() log.Printf("Internal port: %v\n", InternalPort) log.Printf("Own BitWrk account: %v\n", BitcoinIdentity.GetAddress()) log.Printf("Trusted account: %v", TrustedAccount) workerManager := client.NewWorkerManager(client.GetActivityManager(), receiveManager) exit := make(chan error) if InternalPort > 0 { go serveInternal(workerManager, exit) } if ExternalPort > 0 { go serveExternal(receiveManager, exit) } err = <-exit if err != nil { log.Fatalf("Exiting because of: %v", err) os.Exit(1) } }
func handleBuy(w http.ResponseWriter, r *http.Request) { article := r.URL.Path[5:] log.Printf("Handling buy for %#v from %v", article, r.RemoteAddr) if r.Method != "POST" { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } var buy *client.BuyActivity if _buy, err := client.GetActivityManager().NewBuy(bitwrk.ArticleId(article)); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) log.Printf("Error creating buy activity: %v", err) return } else { buy = _buy } defer buy.Dispose() log := bitwrk.Root().Newf("Buy #%v", buy.GetKey()) var reader io.Reader if multipart, err := r.MultipartReader(); err != nil { // read directly from body reader = r.Body } else { // Iterate through parts of multipart body, find the one called "data" for { if part, err := multipart.NextPart(); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) log.Printf("Error iterating through multipart content: %v", err) return } else { if part.FormName() == "data" { reader = part break } else { log.Printf("Skipping form part %v", part) } } } } workTemp := client.GetActivityManager().GetStorage().Create(fmt.Sprintf("buy #%v: work", buy.GetKey())) defer workTemp.Dispose() if _, err := io.Copy(workTemp, reader); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) log.Printf("Error receiving work data from client: %v", err) return } else { if err := workTemp.Close(); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) log.Printf("Error writing work data to storage: %v", err) return } } // Listen for close notfications interrupt := w.(http.CloseNotifier).CloseNotify() workFile := workTemp.File() defer workFile.Dispose() var result cafs.File if res, err := buy.PerformBuy(log, interrupt, workFile); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) log.Printf("Error receiving result from BitWrk network: %v", err) return } else { result = res } http.Redirect(w, r, "/file/"+result.Key().String(), http.StatusSeeOther) }
func serveInternal(workerManager *client.WorkerManager, exit chan<- error) { mux := http.NewServeMux() s := &http.Server{ Addr: fmt.Sprintf("%v:%v", InternalIface, InternalPort), Handler: mux, // No timeouts! } relay := NewHttpRelay("/", protocol.BitwrkUrl, protocol.NewClient(&http.Transport{})) mux.Handle("/account/", relay) mux.Handle("/bid/", relay) mux.Handle("/deposit/", relay) mux.Handle("/tx/", relay) mux.Handle("/motd", relay) accountFilter := func(data []byte) ([]byte, error) { var account bitwrk.ParticipantAccount if err := json.Unmarshal(data, &account); err != nil { return data, nil } else { // Pass data about validation results into the template so it doesn't // have to be done in JavaScript. type result struct { Account bitwrk.ParticipantAccount Updated time.Time TrustedAccount string DepositAddress string DepositAddressValid bool } r := result{account, time.Now(), TrustedAccount, "", false} if v, err := url.ParseQuery(account.DepositInfo); err == nil { m := bitwrk.DepositAddressMessage{} m.FromValues(v) if m.VerifyWith(TrustedAccount) == nil { r.DepositAddress = m.DepositAddress r.DepositAddressValid = true } } return json.Marshal(r) } } myAccountUrl := fmt.Sprintf("%saccount/%s", protocol.BitwrkUrl, BitcoinIdentity.GetAddress()) myAccountRelay := NewHttpRelay("/myaccount", myAccountUrl, relay.client).WithFilterFunc(accountFilter) mux.Handle("/myaccount", myAccountRelay) resource := http.FileServer(http.Dir(path.Join(ResourceDir, "htroot"))) mux.Handle("/js/", resource) mux.Handle("/css/", resource) mux.Handle("/img/", resource) mux.HandleFunc("/buy/", handleBuy) mux.HandleFunc("/file/", handleFile) mux.HandleFunc("/", handleHome) mux.HandleFunc("/ui/", handleHome) mux.HandleFunc("/activities", handleActivities) if ExternalPort > 0 { mux.HandleFunc("/registerworker", func(w http.ResponseWriter, r *http.Request) { handleRegisterWorker(workerManager, w, r) }) } else { mux.HandleFunc("/registerworker", http.NotFound) } mux.HandleFunc("/unregisterworker", func(w http.ResponseWriter, r *http.Request) { handleUnregisterWorker(workerManager, w, r) }) mux.HandleFunc("/workers", func(w http.ResponseWriter, r *http.Request) { handleWorkers(workerManager, w, r) }) mux.HandleFunc("/mandates", func(w http.ResponseWriter, r *http.Request) { handleMandates(client.GetActivityManager(), w, r) }) mux.HandleFunc("/revokemandate", func(w http.ResponseWriter, r *http.Request) { if err := handleRevokeMandate(r); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }) mux.HandleFunc("/requestdepositaddress", func(w http.ResponseWriter, r *http.Request) { if err := handleRequestDepositAddress(r); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { // Account information is now stale myAccountRelay.InvalidateCache() } }) mux.HandleFunc("/id", handleId) mux.HandleFunc("/version", handleVersion) mux.HandleFunc("/cafsdebug", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html") client.GetActivityManager().GetStorage().DumpStatistics(cafs.NewWriterPrinter(w)) }) mux.HandleFunc("/stackdump", func(w http.ResponseWriter, r *http.Request) { name := r.FormValue("name") if len(name) == 0 { name = "goroutine" } profile := pprof.Lookup(name) if profile == nil { w.Write([]byte("No such profile")) return } err := profile.WriteTo(w, 1) if err != nil { log.Printf("Error in profile.WriteTo: %v\n", err) } }) exit <- s.ListenAndServe() }