2018-10-22 23:55:29 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
2018-10-26 22:31:39 +02:00
|
|
|
"github.com/iancoleman/strcase"
|
2018-10-22 23:55:29 +02:00
|
|
|
"github.com/mrahbar/my-bloody-hetzner-sb-notifier/client"
|
2018-10-26 22:31:39 +02:00
|
|
|
"github.com/mrahbar/my-bloody-hetzner-sb-notifier/crawler"
|
2018-10-22 23:55:29 +02:00
|
|
|
"github.com/mrahbar/my-bloody-hetzner-sb-notifier/hetzner"
|
2018-10-26 22:31:39 +02:00
|
|
|
"github.com/mrahbar/my-bloody-hetzner-sb-notifier/writer"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"net/http/httputil"
|
|
|
|
"os"
|
|
|
|
"strconv"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
flagMinPrice = "min-price"
|
|
|
|
flagMaxPrice = "max-price"
|
|
|
|
flagMinRam = "min-ram"
|
|
|
|
flagMaxRam = "max-ram"
|
|
|
|
flagMinHddSize = "min-hdd-size"
|
|
|
|
flagMaxHddSize = "max-hdd-size"
|
|
|
|
flagMinHddCount = "min-hdd-count"
|
|
|
|
flagMaxHddCount = "max-hdd-count"
|
|
|
|
flagMinBenchmark = "min-cpu-benchmark"
|
|
|
|
flagMaxBenchmark = "max-cpu-benchmark"
|
|
|
|
|
|
|
|
flagOutput = "output"
|
|
|
|
flagServeHttpPort = "serve-http-port"
|
|
|
|
flagServeHttp = "serve-http"
|
2018-10-22 23:55:29 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2018-10-26 22:31:39 +02:00
|
|
|
zeroIntValue = int64(0)
|
|
|
|
zeroFloatValue = float64(0)
|
|
|
|
|
|
|
|
defaultMaxPriceValue = float64(297)
|
|
|
|
defaultMaxRamValue = int64(256)
|
|
|
|
defaultMaxHddSizeValue = int64(6144)
|
|
|
|
defaultMaxHddCountValue = int64(15)
|
|
|
|
defaultMaxCpuBenchmarkValue = int64(20000)
|
|
|
|
|
2018-10-22 23:55:29 +02:00
|
|
|
minPrice = flag.Float64(
|
2018-10-26 22:31:39 +02:00
|
|
|
flagMinPrice,
|
2018-10-22 23:55:29 +02:00
|
|
|
0,
|
|
|
|
"set min price",
|
|
|
|
)
|
|
|
|
maxPrice = flag.Float64(
|
2018-10-26 22:31:39 +02:00
|
|
|
flagMaxPrice,
|
2018-10-22 23:55:29 +02:00
|
|
|
297,
|
|
|
|
"set max price",
|
|
|
|
)
|
|
|
|
|
2018-10-26 22:31:39 +02:00
|
|
|
minRam = flag.Int64(
|
|
|
|
flagMinRam,
|
2018-10-22 23:55:29 +02:00
|
|
|
0,
|
|
|
|
"set min ram",
|
|
|
|
)
|
2018-10-26 22:31:39 +02:00
|
|
|
maxRam = flag.Int64(
|
|
|
|
flagMaxRam,
|
2018-10-22 23:55:29 +02:00
|
|
|
256,
|
|
|
|
"set max ram",
|
|
|
|
)
|
|
|
|
|
2018-10-26 22:31:39 +02:00
|
|
|
minHddSize = flag.Int64(
|
|
|
|
flagMinHddSize,
|
2018-10-22 23:55:29 +02:00
|
|
|
0,
|
|
|
|
"set min hdd size",
|
|
|
|
)
|
2018-10-26 22:31:39 +02:00
|
|
|
maxHddSize = flag.Int64(
|
|
|
|
flagMaxHddSize,
|
2018-10-22 23:55:29 +02:00
|
|
|
6144,
|
|
|
|
"set max hdd size",
|
|
|
|
)
|
|
|
|
|
2018-10-26 22:31:39 +02:00
|
|
|
minHddCount = flag.Int64(
|
|
|
|
flagMinHddCount,
|
2018-10-22 23:55:29 +02:00
|
|
|
0,
|
|
|
|
"set min hdd count",
|
|
|
|
)
|
2018-10-26 22:31:39 +02:00
|
|
|
maxHddCount = flag.Int64(
|
|
|
|
flagMaxHddCount,
|
2018-10-22 23:55:29 +02:00
|
|
|
15,
|
|
|
|
"set max hdd count",
|
|
|
|
)
|
|
|
|
|
2018-10-26 22:31:39 +02:00
|
|
|
minBenchmark = flag.Int64(
|
|
|
|
flagMinBenchmark,
|
2018-10-22 23:55:29 +02:00
|
|
|
0,
|
|
|
|
"set min benchmark",
|
|
|
|
)
|
2018-10-26 22:31:39 +02:00
|
|
|
maxBenchmark = flag.Int64(
|
|
|
|
flagMaxBenchmark,
|
2018-10-22 23:55:29 +02:00
|
|
|
20000,
|
|
|
|
"set max benchmark",
|
|
|
|
)
|
|
|
|
|
2018-10-26 22:31:39 +02:00
|
|
|
serveHttp = flag.Bool(
|
|
|
|
flagServeHttp,
|
|
|
|
false,
|
|
|
|
"set serve http",
|
|
|
|
)
|
|
|
|
|
|
|
|
serveHttpPort = flag.Int(
|
|
|
|
flagServeHttpPort,
|
|
|
|
8080,
|
|
|
|
"set serve http port",
|
|
|
|
)
|
|
|
|
|
|
|
|
output = flag.String(
|
|
|
|
flagOutput,
|
|
|
|
"table",
|
|
|
|
"set output: one of table, json",
|
2018-10-22 23:55:29 +02:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
flag.Parse()
|
|
|
|
|
2018-10-26 22:31:39 +02:00
|
|
|
if *serveHttp {
|
|
|
|
runHttp()
|
|
|
|
} else {
|
|
|
|
p := crawler.Parameter{
|
|
|
|
MinPrice: *minPrice,
|
|
|
|
MaxPrice: *maxPrice,
|
|
|
|
MinRam: *minRam,
|
|
|
|
MaxRam: *maxRam,
|
|
|
|
MinHddSize: *minHddSize,
|
|
|
|
MaxHddSize: *maxHddSize,
|
|
|
|
MinHddCount: *minHddCount,
|
|
|
|
MaxHddCount: *maxHddCount,
|
|
|
|
MinBenchmark: *minBenchmark,
|
|
|
|
MaxBenchmark: *maxBenchmark,
|
|
|
|
}
|
|
|
|
|
|
|
|
run(os.Stdout, p, *output)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func runHttp() {
|
|
|
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
b, err := httputil.DumpRequest(r, false)
|
|
|
|
if err == nil {
|
|
|
|
fmt.Printf("Got request: %s", string(b))
|
|
|
|
}
|
|
|
|
parameter := crawler.Parameter{
|
|
|
|
MinPrice: zeroFloatValue,
|
|
|
|
MaxPrice: defaultMaxPriceValue,
|
|
|
|
MinRam: zeroIntValue,
|
|
|
|
MaxRam: defaultMaxRamValue,
|
|
|
|
MinHddSize: zeroIntValue,
|
|
|
|
MaxHddSize: defaultMaxHddSizeValue,
|
|
|
|
MinHddCount: zeroIntValue,
|
|
|
|
MaxHddCount: defaultMaxHddCountValue,
|
|
|
|
MinBenchmark: zeroIntValue,
|
|
|
|
MaxBenchmark: defaultMaxCpuBenchmarkValue,
|
|
|
|
}
|
|
|
|
output := "table"
|
|
|
|
values := r.URL.Query()
|
|
|
|
for k, v := range values {
|
|
|
|
value := v[0]
|
|
|
|
|
|
|
|
switch k {
|
|
|
|
case strcase.ToLowerCamel(flagMinPrice):
|
|
|
|
parameter.MinPrice = parseFloatFlag(w, strcase.ToLowerCamel(flagMinPrice), value)
|
|
|
|
break
|
|
|
|
case strcase.ToLowerCamel(flagMaxPrice):
|
|
|
|
parameter.MaxPrice = parseFloatFlag(w, strcase.ToLowerCamel(flagMaxPrice), value)
|
|
|
|
break
|
|
|
|
case strcase.ToLowerCamel(flagMinRam):
|
|
|
|
parameter.MinRam = parseIntFlag(w, strcase.ToLowerCamel(flagMinRam), value)
|
|
|
|
break
|
|
|
|
case strcase.ToLowerCamel(flagMaxRam):
|
|
|
|
parameter.MaxRam = parseIntFlag(w, strcase.ToLowerCamel(flagMaxRam), value)
|
|
|
|
break
|
|
|
|
case strcase.ToLowerCamel(flagMinHddSize):
|
|
|
|
parameter.MinHddSize = parseIntFlag(w, strcase.ToLowerCamel(flagMinHddSize), value)
|
|
|
|
break
|
|
|
|
case strcase.ToLowerCamel(flagMaxHddSize):
|
|
|
|
parameter.MaxHddSize = parseIntFlag(w, strcase.ToLowerCamel(flagMaxHddSize), value)
|
|
|
|
break
|
|
|
|
case strcase.ToLowerCamel(flagMinHddCount):
|
|
|
|
parameter.MinHddCount = parseIntFlag(w, strcase.ToLowerCamel(flagMinHddCount), value)
|
|
|
|
break
|
|
|
|
case strcase.ToLowerCamel(flagMaxHddCount):
|
|
|
|
parameter.MaxHddCount = parseIntFlag(w, strcase.ToLowerCamel(flagMaxHddCount), value)
|
|
|
|
break
|
|
|
|
case strcase.ToLowerCamel(flagMinBenchmark):
|
|
|
|
parameter.MinBenchmark = parseIntFlag(w, strcase.ToLowerCamel(flagMinBenchmark), value)
|
|
|
|
break
|
|
|
|
case strcase.ToLowerCamel(flagMaxBenchmark):
|
|
|
|
parameter.MaxBenchmark = parseIntFlag(w, strcase.ToLowerCamel(flagMaxBenchmark), value)
|
|
|
|
break
|
|
|
|
case strcase.ToLowerCamel(flagOutput):
|
|
|
|
output = value
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
run(w, parameter, output)
|
|
|
|
})
|
|
|
|
address := fmt.Sprintf(":%d", *serveHttpPort)
|
|
|
|
fmt.Printf("Running http server on address %s\n", address)
|
|
|
|
fmt.Println(http.ListenAndServe(address, nil))
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseFloatFlag(w http.ResponseWriter, flag string, value string) float64 {
|
|
|
|
parseValue, err := strconv.ParseFloat(value, 32)
|
|
|
|
if err == nil {
|
|
|
|
return parseValue
|
|
|
|
} else {
|
|
|
|
writeBadRequestResponseForQueryParameter(w, flag, err)
|
|
|
|
return zeroFloatValue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseIntFlag(w http.ResponseWriter, flag string, value string) int64 {
|
|
|
|
parseValue, err := strconv.ParseInt(value, 10, 32)
|
|
|
|
if err == nil {
|
|
|
|
return parseValue
|
|
|
|
} else {
|
|
|
|
writeBadRequestResponseForQueryParameter(w, flag, err)
|
|
|
|
return zeroIntValue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func writeBadRequestResponseForQueryParameter(w http.ResponseWriter, parameter string, err error) {
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
w.Write([]byte(fmt.Sprintf("Error parsing query parameter %s: %s", parameter, err)))
|
|
|
|
}
|
|
|
|
|
|
|
|
func run(w io.Writer, parameter crawler.Parameter, output string) error {
|
2018-10-22 23:55:29 +02:00
|
|
|
offers := &hetzner.Offers{}
|
2018-10-25 21:18:45 +02:00
|
|
|
err := client.NewClient().DoRequest(hetzner.MakeURL(), offers)
|
2018-10-22 23:55:29 +02:00
|
|
|
if err != nil {
|
2018-10-26 22:31:39 +02:00
|
|
|
return fmt.Errorf("failed to get hetzner live data: %s", err)
|
2018-10-22 23:55:29 +02:00
|
|
|
}
|
|
|
|
if len(offers.Server) > 0 {
|
2018-10-26 22:31:39 +02:00
|
|
|
c := crawler.NewCrawler(parameter)
|
|
|
|
deals := c.Filter(offers.Server)
|
2018-10-23 13:32:15 +02:00
|
|
|
|
2018-10-26 22:31:39 +02:00
|
|
|
switch output {
|
|
|
|
case "json":
|
|
|
|
writer.NewJsonWriter(w).Print(deals)
|
|
|
|
break
|
|
|
|
default:
|
|
|
|
case "table":
|
|
|
|
writer.NewTableWriter(w).Print(deals)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
return nil
|
2018-10-22 23:55:29 +02:00
|
|
|
} else {
|
2018-10-26 22:31:39 +02:00
|
|
|
return fmt.Errorf("got no offers.")
|
2018-10-22 23:55:29 +02:00
|
|
|
}
|
|
|
|
}
|