Merge pull request #1 from urgentquest/cobra-N-viper

Cobra n viper
This commit is contained in:
idk
2025-04-30 22:18:52 -04:00
committed by GitHub
11 changed files with 432 additions and 303 deletions

View File

@ -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,

View File

@ -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()

108
cmd/build.go Normal file
View File

@ -0,0 +1,108 @@
package cmd
import (
"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) {
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")
serveCmd.Flags().String("samaddr", onramp.SAM_ADDR, "SAMv3 gateway address. Empty string to disable")
viper.BindPFlags(buildCmd.Flags())
}
func defaultFeedURL() string {
if c.SamAddr == "" {
return "http://tc73n4kivdroccekirco7rhgxdg5f3cjvbaapabupeyzrqwv5guq.b32.i2p/news.atom.xml"
}
garlic, _ := onramp.NewGarlic("newsgo", c.SamAddr, onramp.OPT_DEFAULTS)
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 = os.WriteFile(filepath.Join(c.BuildDir, filename), []byte(feed), 0644); err != nil {
panic(err)
}
}
}

65
cmd/root.go Normal file
View File

@ -0,0 +1,65 @@
package cmd
import (
"fmt"
"os"
"strings"
"github.com/go-i2p/newsgo/config"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var cfgFile string
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())
}
}

90
cmd/serve.go Normal file
View File

@ -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, onramp.OPT_DEFAULTS)
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)
}

85
cmd/sign.go Normal file
View File

@ -0,0 +1,85 @@
package cmd
import (
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"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 := os.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)
}

20
config/config.go Normal file
View File

@ -0,0 +1,20 @@
package config
type Conf struct {
NewsDir string
StatsFile string
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
}

15
go.mod
View File

@ -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
)

42
go.sum
View File

@ -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=

298
main.go
View File

@ -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()
}

View File

@ -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{