From 2fd20db19b908e5cb8da28d993238cc62391b057 Mon Sep 17 00:00:00 2001 From: ungrentquest Date: Sat, 19 Apr 2025 23:11:19 +0000 Subject: [PATCH] Adopt cobra & viper. Define build sign and serve subcommands --- builder/build.go | 4 +- builder/feed/feed.go | 4 +- cmd/build.go | 120 +++++++++++++++++ cmd/root.go | 66 ++++++++++ cmd/serve.go | 90 +++++++++++++ cmd/sign.go | 86 +++++++++++++ config/config.go | 21 +++ go.mod | 15 +++ go.sum | 42 +++++- main.go | 298 +------------------------------------------ server/serve.go | 4 +- 11 files changed, 447 insertions(+), 303 deletions(-) create mode 100644 cmd/build.go create mode 100644 cmd/root.go create mode 100644 cmd/serve.go create mode 100644 cmd/sign.go create mode 100644 config/config.go diff --git a/builder/build.go b/builder/build.go index 8040d30..d9b7716 100644 --- a/builder/build.go +++ b/builder/build.go @@ -6,9 +6,9 @@ import ( "io/ioutil" "time" + newsfeed "github.com/go-i2p/newsgo/builder/feed" "github.com/google/uuid" "github.com/yosssi/gohtml" - newsfeed "github.com/go-i2p/newsgo/builder/feed" ) type NewsBuilder struct { @@ -101,7 +101,7 @@ func (nb *NewsBuilder) Build() (string, error) { return gohtml.Format(str), nil } -func Builder(newsFile, releasesJson, blocklistXML string) *NewsBuilder { +func Builder(newsFile string, releasesJson string, blocklistXML string) *NewsBuilder { nb := &NewsBuilder{ Feed: newsfeed.Feed{ EntriesHTMLPath: newsFile, diff --git a/builder/feed/feed.go b/builder/feed/feed.go index ed64a62..bc2f55f 100644 --- a/builder/feed/feed.go +++ b/builder/feed/feed.go @@ -18,7 +18,7 @@ type Feed struct { func (f *Feed) LoadHTML() error { data, err := ioutil.ReadFile(f.EntriesHTMLPath) if err != nil { - return fmt.Errorf("LoadHTML: error", err) + return fmt.Errorf("loadHTML: error %s", err) } f.doc = soup.HTMLParse(string(data)) f.HeaderTitle = f.doc.Find("header").FullText() @@ -29,7 +29,7 @@ func (f *Feed) LoadHTML() error { if f.BaseEntriesHTMLPath != "" { data, err := ioutil.ReadFile(f.BaseEntriesHTMLPath) if err != nil { - return fmt.Errorf("LoadHTML: error", err) + return fmt.Errorf("loadHTML: error %s", err) } f.doc = soup.HTMLParse(string(data)) f.HeaderTitle = f.doc.Find("header").FullText() diff --git a/cmd/build.go b/cmd/build.go new file mode 100644 index 0000000..e03cf54 --- /dev/null +++ b/cmd/build.go @@ -0,0 +1,120 @@ +package cmd + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "os" + "path/filepath" + "strings" + + builder "github.com/go-i2p/newsgo/builder" + "github.com/go-i2p/onramp" + "github.com/google/uuid" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// buildCmd represents the build command +var buildCmd = &cobra.Command{ + Use: "build", + Short: "Build newsfeeds from XML", + Run: func(cmd *cobra.Command, args []string) { + // For some reason this is the only way passing booleans from cobra to viper works + viper.GetViper().Set("i2p", i2p) + + viper.WriteConfigTo(os.Stdout) + viper.Unmarshal(c) + data, _ := json.MarshalIndent(&c, " ", "") + fmt.Print(string(data[:])) + + os.Exit(0) + + f, e := os.Stat(c.NewsFile) + if e != nil { + panic(e) + } + if f.IsDir() { + err := filepath.Walk(c.NewsFile, + func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + ext := filepath.Ext(path) + if ext == ".html" { + build(path) + } + return nil + }) + if err != nil { + log.Println(err) + } + } else { + build(c.NewsFile) + } + + }, +} + +func init() { + rootCmd.AddCommand(buildCmd) + buildCmd.Flags().String("newsfile", "data", "entries to pass to news generator. If passed a directory, all 'entries.html' files in the directory will be processed") + buildCmd.Flags().String("blocklist", "data/blocklist.xml", "block list file to pass to news generator") + buildCmd.Flags().String("releasejson", "data/releases.json", "json file describing an update to pass to news generator") + buildCmd.Flags().String("feedtitle", "I2P News", "title to use for the RSS feed to pass to news generator") + buildCmd.Flags().String("feedsubtitle", "News feed, and router updates", "subtitle to use for the RSS feed to pass to news generator") + buildCmd.Flags().String("feedsite", "http://i2p-projekt.i2p", "site for the RSS feed to pass to news generator") + buildCmd.Flags().String("feedmain", defaultFeedURL(), "Primary newsfeed for updates to pass to news generator") + buildCmd.Flags().String("feedbackup", "http://dn3tvalnjz432qkqsvpfdqrwpqkw3ye4n4i2uyfr4jexvo3sp5ka.b32.i2p/news/news.atom.xml", "Backup newsfeed for updates to pass to news generator") + buildCmd.Flags().String("feeduid", "", "UUID to use for the RSS feed to pass to news generator. Random if omitted") + buildCmd.Flags().String("builddir", "build", "Build directory to output feeds to") + buildCmd.Flags().BoolVar(&i2p, "i2p", false, "Enable I2P support") + + viper.BindPFlags(buildCmd.Flags()) + +} + +func defaultFeedURL() string { + if !c.I2P { + return "http://tc73n4kivdroccekirco7rhgxdg5f3cjvbaapabupeyzrqwv5guq.b32.i2p/news.atom.xml" + } + garlic := &onramp.Garlic{} + defer garlic.Close() + ln, err := garlic.Listen() + if err != nil { + return "http://tc73n4kivdroccekirco7rhgxdg5f3cjvbaapabupeyzrqwv5guq.b32.i2p/news.atom.xml" + } + defer ln.Close() + return "http://" + ln.Addr().String() + "/news.atom.xml" +} + +func build(newsFile string) { + news := builder.Builder(newsFile, c.ReleaseJsonFile, c.BlockList) + news.TITLE = c.FeedTitle + news.SITEURL = c.FeedSite + news.MAINFEED = c.FeedMain + news.BACKUPFEED = c.FeedBackup + news.SUBTITLE = c.FeedSubtitle + if c.FeedUuid == "" { + news.URNID = c.FeedUuid + } else { + news.URNID = uuid.NewString() + } + + base := filepath.Join(newsFile, "entries.html") + if newsFile != base { + news.Feed.BaseEntriesHTMLPath = base + } + if feed, err := news.Build(); err != nil { + log.Printf("Build error: %s", err) + } else { + filename := strings.Replace(strings.Replace(strings.Replace(strings.Replace(c.NewsFile, ".html", ".atom.xml", -1), "entries.", "news_", -1), "translations", "", -1), "news_atom", "news.atom", -1) + if err := os.MkdirAll(filepath.Join(c.BuildDir, filepath.Dir(filename)), 0755); err != nil { + panic(err) + } + if err = ioutil.WriteFile(filepath.Join(c.BuildDir, filename), []byte(feed), 0644); err != nil { + panic(err) + } + } +} diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..a61e947 --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,66 @@ +package cmd + +import ( + "fmt" + "os" + "strings" + + "github.com/go-i2p/newsgo/config" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var cfgFile string +var i2p bool +var c *config.Conf = &config.Conf{} + +// rootCmd represents the base command when called without any subcommands +var rootCmd = &cobra.Command{ + Use: "newsgo", + Short: "I2P News Server Tool/Library. A whole lot faster than the python one. Otherwise compatible", +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} + +func init() { + cobra.OnInitialize(initConfig) + + // Cobra supports persistent flags, which, if defined here, + // will be global for your application. + + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.newsgo.yaml)") +} + +// initConfig reads in config file and ENV variables if set. +func initConfig() { + if cfgFile != "" { + // Use config file from the flag. + viper.SetConfigFile(cfgFile) + } else { + // Find home directory. + home, err := os.UserHomeDir() + cobra.CheckErr(err) + + // Search config in home directory with name ".newsgo" (without extension). + viper.AddConfigPath(home) + viper.SetConfigType("yaml") + viper.SetConfigName(".newsgo") + } + + viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) + + viper.AutomaticEnv() // read in environment variables that match + + // If a config file is found, read it in. + if err := viper.ReadInConfig(); err == nil { + fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) + } + +} diff --git a/cmd/serve.go b/cmd/serve.go new file mode 100644 index 0000000..34b7976 --- /dev/null +++ b/cmd/serve.go @@ -0,0 +1,90 @@ +package cmd + +import ( + "log" + "net" + "net/http" + "os" + "os/signal" + "time" + + server "github.com/go-i2p/newsgo/server" + "github.com/go-i2p/onramp" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// serveCmd represents the serve command +var serveCmd = &cobra.Command{ + Use: "serve", + Short: "Serve newsfeeds from a directory", + Run: func(cmd *cobra.Command, args []string) { + + viper.Unmarshal(c) + s := server.Serve(c.NewsDir, c.StatsFile) + if c.Http != "" { + go func() { + if err := serve(s); err != nil { + panic(err) + } + }() + } + if c.SamAddr != "" { + go func() { + if err := serveI2P(s); err != nil { + panic(err) + } + }() + } + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + go func() { + for sig := range c { + log.Println("captured: ", sig) + s.Stats.Save() + os.Exit(0) + } + }() + i := 0 + for { + time.Sleep(time.Minute) + log.Printf("Running for %d minutes.", i) + i++ + } + + }, +} + +func init() { + rootCmd.AddCommand(serveCmd) + + serveCmd.Flags().String("newsdir", "build", "directory to serve news from") + serveCmd.Flags().String("statsfile", "build/stats.json", "file to store stats in") + serveCmd.Flags().String("http", "127.0.0.1:9696", "listen for HTTP requests. Empty string to disable") + serveCmd.Flags().String("samaddr", onramp.SAM_ADDR, "SAMv3 gateway address. Empty string to disable") + + viper.BindPFlags(serveCmd.Flags()) + +} + +func serveI2P(s *server.NewsServer) error { + garlic, err := onramp.NewGarlic("newsgo", c.SamAddr, make([]string, 0)) + if err != nil { + return err + } + defer garlic.Close() + ln, err := garlic.Listen() + if err != nil { + return err + } + defer ln.Close() + return http.Serve(ln, s) +} + +func serve(s *server.NewsServer) error { + ln, err := net.Listen("tcp", c.Http) + if err != nil { + return err + } + return http.Serve(ln, s) +} diff --git a/cmd/sign.go b/cmd/sign.go new file mode 100644 index 0000000..c4e257a --- /dev/null +++ b/cmd/sign.go @@ -0,0 +1,86 @@ +package cmd + +import ( + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "io/ioutil" + "log" + "os" + "path/filepath" + + signer "github.com/go-i2p/newsgo/signer" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// signCmd represents the sign command +var signCmd = &cobra.Command{ + Use: "sign", + Short: "Sign newsfeeds with local keys", + Run: func(cmd *cobra.Command, args []string) { + viper.Unmarshal(c) + + f, e := os.Stat(c.NewsFile) + if e != nil { + panic(e) + } + if f.IsDir() { + err := filepath.Walk(c.NewsFile, + func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + ext := filepath.Ext(path) + if ext == ".html" { + Sign(path) + } + return nil + }) + if err != nil { + log.Println(err) + } + } else { + Sign(c.NewsFile) + } + + }, +} + +func init() { + rootCmd.AddCommand(signCmd) + + // Here you will define your flags and configuration settings. + + signCmd.Flags().String("signerid", "null@example.i2p", "ID to use when signing the news") + signCmd.Flags().String("signingkey", "signing_key.pem", "Path to a signing key") + + viper.BindPFlags(signCmd.Flags()) +} + +func loadPrivateKey(path string) (*rsa.PrivateKey, error) { + privPem, err := ioutil.ReadFile(path) + if nil != err { + return nil, err + } + + privDer, _ := pem.Decode(privPem) + privKey, err := x509.ParsePKCS1PrivateKey(privDer.Bytes) + if nil != err { + return nil, err + } + + return privKey, nil +} + +func Sign(xmlfeed string) error { + sk, err := loadPrivateKey(c.SigningKey) + if err != nil { + return err + } + signer := signer.NewsSigner{ + SignerID: c.SignerId, + SigningKey: sk, + } + return signer.CreateSu3(xmlfeed) +} diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..e960cf1 --- /dev/null +++ b/config/config.go @@ -0,0 +1,21 @@ +package config + +type Conf struct { + NewsDir string + StatsFile string + I2P bool + Http string + SamAddr string + NewsFile string + BlockList string + ReleaseJsonFile string + FeedTitle string + FeedSubtitle string + FeedSite string + FeedMain string + FeedBackup string + FeedUuid string + BuildDir string + SignerId string + SigningKey string +} diff --git a/go.mod b/go.mod index 728356c..9903b41 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,8 @@ require ( github.com/anaskhan96/soup v1.2.5 github.com/go-i2p/onramp v0.33.92 github.com/google/uuid v1.6.0 + github.com/spf13/cobra v1.9.1 + github.com/spf13/viper v1.20.1 github.com/wcharczuk/go-chart/v2 v2.1.2 github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4 gitlab.com/golang-commonmark/markdown v0.0.0-20211110145824-bf3e522c626a @@ -16,17 +18,30 @@ require ( require ( github.com/cretz/bine v0.2.0 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/go-i2p/i2pkeys v0.33.92 // indirect github.com/go-i2p/sam3 v0.33.92 // indirect + github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/sagikazarmark/locafero v0.7.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.12.0 // indirect + github.com/spf13/cast v1.7.1 // indirect + github.com/spf13/pflag v1.0.6 // indirect + github.com/subosito/gotenv v1.6.0 // indirect gitlab.com/golang-commonmark/html v0.0.0-20191124015941-a22733972181 // indirect gitlab.com/golang-commonmark/linkify v0.0.0-20200225224916-64bca66f6ad3 // indirect gitlab.com/golang-commonmark/mdurl v0.0.0-20191124015652-932350d1cb84 // indirect gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect golang.org/x/crypto v0.36.0 // indirect golang.org/x/image v0.25.0 // indirect golang.org/x/net v0.37.0 // indirect golang.org/x/sys v0.31.0 // indirect golang.org/x/text v0.23.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index c4ac832..da202ce 100644 --- a/go.sum +++ b/go.sum @@ -81,6 +81,7 @@ github.com/cpu/goacmedns v0.1.1/go.mod h1:MuaouqEhPAHxsbqjgnck5zeghuwBP1dLnPoobe github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo= github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= @@ -116,8 +117,12 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8= github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw= github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY= @@ -151,6 +156,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -189,6 +196,7 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -248,6 +256,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jarcoal/httpmock v1.0.6/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= @@ -272,8 +282,12 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA= github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= @@ -344,6 +358,8 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -381,6 +397,8 @@ github.com/riobard/go-x25519 v0.0.0-20190716001027-10cc4d8d0b33/go.mod h1:BjmVxz github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday v2.0.0+incompatible h1:cBXrhZNUf9C+La9/YpS+UHpUT8YD6Td9ZMSU9APFcsk= github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -388,6 +406,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sacloud/libsacloud v1.36.2/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg= +github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= +github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -399,18 +419,30 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= +github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= +github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -424,9 +456,12 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/throttled/throttled/v2 v2.7.1/go.mod h1:fuOeyK9fmnA+LQnsBbfT/mmPHjmkdogRBQxaD8YsgZ8= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/transip/gotransip/v6 v6.6.0/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g= @@ -473,7 +508,11 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -784,6 +823,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= diff --git a/main.go b/main.go index 4125997..5af95e5 100644 --- a/main.go +++ b/main.go @@ -1,301 +1,7 @@ package main -import ( - "crypto/rsa" - "crypto/x509" - "encoding/pem" - "flag" - "fmt" - "io/ioutil" - "log" - "net" - "net/http" - "os" - "os/signal" - "path/filepath" - "strconv" - "strings" - "time" - - "github.com/go-i2p/onramp" - "github.com/google/uuid" - builder "github.com/go-i2p/newsgo/builder" - server "github.com/go-i2p/newsgo/server" - signer "github.com/go-i2p/newsgo/signer" -) - -func loadPrivateKey(path string) (*rsa.PrivateKey, error) { - privPem, err := ioutil.ReadFile(path) - if nil != err { - return nil, err - } - - privDer, _ := pem.Decode(privPem) - privKey, err := x509.ParsePKCS1PrivateKey(privDer.Bytes) - if nil != err { - return nil, err - } - - return privKey, nil -} - -func Sign(xmlfeed string) error { - sk, err := loadPrivateKey(*signingkey) - if err != nil { - return err - } - signer := signer.NewsSigner{ - SignerID: *signerid, - SigningKey: sk, - } - return signer.CreateSu3(xmlfeed) -} - -var ( - serve = flag.String("command", "help", "command to run(may be `serve`,`build`,`sign`, or `help`(default)") - dir = flag.String("newsdir", "build", "directory to serve news from") - statsfile = flag.String("statsfile", "build/stats.json", "file to store stats in") - host = flag.String("host", "127.0.0.1", "host to serve on") - port = flag.String("port", "9696", "port to serve on") - i2p = flag.Bool("i2p", isSamAround(), "automatically co-host on an I2P service using SAMv3") - tcp = flag.Bool("http", true, "host on an HTTP service at host:port") - //newsfile = flag.String("newsfile", "data/entries.html", "entries to pass to news generator. If passed a directory, all `entries.html` files in the directory will be processed") - newsfile = flag.String("newsfile", "data", "entries to pass to news generator. If passed a directory, all `entries.html` files in the directory will be processed") - bloclist = flag.String("blocklist", "data/blocklist.xml", "block list file to pass to news generator") - releasejson = flag.String("releasejson", "data/releases.json", "json file describing an update to pass to news generator") - title = flag.String("feedtitle", "I2P News", "title to use for the RSS feed to pass to news generator") - subtitle = flag.String("feedsubtitle", "News feed, and router updates", "subtitle to use for the RSS feed to pass to news generator") - site = flag.String("feedsite", "http://i2p-projekt.i2p", "site for the RSS feed to pass to news generator") - mainurl = flag.String("feedmain", DefaultFeedURL(), "Primary newsfeed for updates to pass to news generator") - backupurl = flag.String("feedbackup", "http://dn3tvalnjz432qkqsvpfdqrwpqkw3ye4n4i2uyfr4jexvo3sp5ka.b32.i2p/news/news.atom.xml", "Backup newsfeed for updates to pass to news generator") - urn = flag.String("feeduid", uuid.New().String(), "UUID to use for the RSS feed to pass to news generator") - builddir = flag.String("builddir", "build", "Build directory to output feeds to.") - signerid = flag.String("signerid", "null@example.i2p", "ID to use when signing the news") - signingkey = flag.String("signingkey", "signing_key.pem", "Path to a signing key") -) - -func validatePort(s *string) { - _, err := strconv.Atoi(*s) - if err != nil { - log.Println("Port is invalid") - os.Exit(1) - } -} - -func validateCommand(s *string) string { - switch *s { - case "serve": - return "serve" - case "build": - return "build" - case "sign": - return "sign" - default: - return "help" - } -} - -func Help() { - fmt.Println("newsgo") - fmt.Println("======") - fmt.Println("") - fmt.Println("I2P News Server Tool/Library. A whole lot faster than the python one. Otherwise compatible.") - fmt.Println("") - fmt.Println("Usage") - fmt.Println("-----") - fmt.Println("") - fmt.Println("./newsgo -command $command -newsdir $news_directory -statsfile $news_stats_file") - fmt.Println("") - fmt.Println("### Commands") - fmt.Println("") - fmt.Println(" - serve: Serve newsfeeds from a directory") - fmt.Println(" - build: Build newsfeeds from XML") - fmt.Println(" - sign: Sign newsfeeds with local keys") - fmt.Println("") - fmt.Println("### Options") - fmt.Println("") - fmt.Println("Use these options to configure the software") - fmt.Println("") - fmt.Println("#### Server Options(use with `serve`)") - fmt.Println("") - fmt.Println(" - `-newsdir`: directory to serve newsfeed from") - fmt.Println(" - `-statsfile`: file to store the stats in, in json format") - fmt.Println(" - `-host`: host to serve news files on") - fmt.Println(" - `-port`: port to serve news files on") - fmt.Println(" - `-http`: serve news on host:port using HTTP") - fmt.Println(" - `-i2p`: serve news files directly to I2P using SAMv3") - fmt.Println("") - fmt.Println("#### Builder Options(use with `build`)") - fmt.Println("") - fmt.Println(" - `-newsfile`: entries to pass to news generator. If passed a directory, all `entries.html` files in the directory will be processed") - fmt.Println(" - `-blockfile`: block list file to pass to news generator") - fmt.Println(" - `-releasejson`: json file describing an update to pass to news generator") - fmt.Println(" - `-feedtitle`: title to use for the RSS feed to pass to news generator") - fmt.Println(" - `-feedsubtitle`: subtitle to use for the RSS feed to pass to news generator") - fmt.Println(" - `-feedsite`: site for the RSS feed to pass to news generator") - fmt.Println(" - `-feedmain`: Primary newsfeed for updates to pass to news generator") - fmt.Println(" - `-feedbackup`: Backup newsfeed for updates to pass to news generator") - fmt.Println(" - `-feeduri`: UUID to use for the RSS feed to pass to news generator") - fmt.Println(" - `-builddir`: directory to output XML files in") - fmt.Println("") - fmt.Println("#### Signer Options(use with `sign`)") - fmt.Println("") - fmt.Println(" - `-signerid`: ID of the news signer") - fmt.Println(" - `-signingkey`: path to the signing key") -} - -func Serve(host, port string, s *server.NewsServer) error { - ln, err := net.Listen("tcp", net.JoinHostPort(host, port)) - if err != nil { - return err - } - return http.Serve(ln, s) -} - -func ServeI2P(s *server.NewsServer) error { - garlic := &onramp.Garlic{} - defer garlic.Close() - ln, err := garlic.Listen() - if err != nil { - return err - } - defer ln.Close() - return http.Serve(ln, s) -} - -func isSamAround() bool { - ln, err := net.Listen("tcp", "127.0.0.1:7656") - if err != nil { - return true - } - ln.Close() - return false -} - -func DefaultFeedURL() string { - if !isSamAround() { - return "http://tc73n4kivdroccekirco7rhgxdg5f3cjvbaapabupeyzrqwv5guq.b32.i2p/news.atom.xml" - } - garlic := &onramp.Garlic{} - defer garlic.Close() - ln, err := garlic.Listen() - if err != nil { - return "http://tc73n4kivdroccekirco7rhgxdg5f3cjvbaapabupeyzrqwv5guq.b32.i2p/news.atom.xml" - } - defer ln.Close() - return "http://" + ln.Addr().String() + "/news.atom.xml" -} - -func Build(newsFile string) { - news := builder.Builder(newsFile, *releasejson, *bloclist) - news.TITLE = *title - news.SITEURL = *site - news.MAINFEED = *mainurl - news.BACKUPFEED = *backupurl - news.SUBTITLE = *subtitle - news.URNID = *urn - base := filepath.Join(*newsfile, "entries.html") - if newsFile != base { - news.Feed.BaseEntriesHTMLPath = base - } - if feed, err := news.Build(); err != nil { - log.Printf("Build error: %s", err) - } else { - filename := strings.Replace(strings.Replace(strings.Replace(strings.Replace(newsFile, ".html", ".atom.xml", -1), "entries.", "news_", -1), "translations", "", -1), "news_atom", "news.atom", -1) - if err := os.MkdirAll(filepath.Join(*builddir, filepath.Dir(filename)), 0755); err != nil { - panic(err) - } - if err = ioutil.WriteFile(filepath.Join(*builddir, filename), []byte(feed), 0644); err != nil { - panic(err) - } - } -} +import "github.com/go-i2p/newsgo/cmd" func main() { - flag.Parse() - command := validateCommand(serve) - validatePort(port) - switch command { - case "serve": - s := server.Serve(*dir, *statsfile) - if *tcp { - go func() { - if err := Serve(*host, *port, s); err != nil { - panic(err) - } - }() - } - if *i2p { - go func() { - if err := ServeI2P(s); err != nil { - panic(err) - } - }() - } - c := make(chan os.Signal, 1) - signal.Notify(c, os.Interrupt) - go func() { - for sig := range c { - log.Println("captured: ", sig) - s.Stats.Save() - os.Exit(0) - } - }() - i := 0 - for { - time.Sleep(time.Minute) - log.Printf("Running for %d minutes.", i) - i++ - } - case "build": - f, e := os.Stat(*newsfile) - if e != nil { - panic(e) - } - if f.IsDir() { - err := filepath.Walk(*newsfile, - func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - ext := filepath.Ext(path) - if ext == ".html" { - Build(path) - } - return nil - }) - if err != nil { - log.Println(err) - } - } else { - Build(*newsfile) - } - case "sign": - f, e := os.Stat(*newsfile) - if e != nil { - panic(e) - } - if f.IsDir() { - err := filepath.Walk(*newsfile, - func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - ext := filepath.Ext(path) - if ext == ".html" { - Sign(path) - } - return nil - }) - if err != nil { - log.Println(err) - } - } else { - Sign(*newsfile) - } - case "help": - Help() - default: - Help() - } + cmd.Execute() } diff --git a/server/serve.go b/server/serve.go index 0fd5b5b..056ee0a 100644 --- a/server/serve.go +++ b/server/serve.go @@ -10,8 +10,8 @@ import ( "path/filepath" "strings" - "gitlab.com/golang-commonmark/markdown" stats "github.com/go-i2p/newsgo/server/stats" + "gitlab.com/golang-commonmark/markdown" ) type NewsServer struct { @@ -144,7 +144,7 @@ func (n *NewsServer) ServeFile(file string, rq *http.Request, rw http.ResponseWr return nil } -func Serve(newsDir, newsStats string) *NewsServer { +func Serve(newsDir string, newsStats string) *NewsServer { s := &NewsServer{ NewsDir: newsDir, Stats: stats.NewsStats{