예제 #1
0
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)
	}
}
예제 #2
0
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
}
예제 #3
0
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)
	}
}
예제 #4
0
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
}
예제 #5
0
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)
	}
}
예제 #6
0
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)
}
예제 #7
0
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()
}