Skip to content
This repository has been archived by the owner on Mar 19, 2021. It is now read-only.

Commit

Permalink
Merge pull request #1 from gaius-qi/feat/stock
Browse files Browse the repository at this point in the history
Feat/stock
  • Loading branch information
gaius-qi authored Mar 15, 2021
2 parents 3af9983 + e3121c6 commit e15f20d
Show file tree
Hide file tree
Showing 9 changed files with 456 additions and 298 deletions.
45 changes: 37 additions & 8 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package cmd

import (
"context"
"fmt"
"log"
"os"

"github.com/gaius-qi/honk/internal/config"
"github.com/gaius-qi/honk/pkg/stock"
"github.com/jedib0t/go-pretty/v6/table"

"github.com/pkg/errors"
"github.com/sirupsen/logrus"
Expand All @@ -22,19 +23,31 @@ var rootCmd = &cobra.Command{
information and analysis results.
Complete documentation is available at https://github.com/gaius-qi/honk`,
SilenceUsage: true,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

fmt.Println(ctx)
cfg.Number = args[0]
logrus.Debugf("load config success: %#v", cfg)

s := stock.NewStockContext(ctx, cfg.Platform, cfg)
data, err := s.Get()
logrus.Debugf("get stock data success: %#v", data)
if err != nil {
logrus.Errorf("get stock data failed: %#v", err)
return err
}

prettyPrint(data)
return nil
},
}

// Execute is the entry point of the command.
func Execute() {
if err := rootCmd.Execute(); err != nil {
log.Fatal(err)
logrus.Fatal(err)
}
}

Expand All @@ -55,21 +68,21 @@ func initConfig() {

for _, e := range []string{"index", "platform"} {
if err := viper.BindEnv(e); err != nil {
log.Fatalf(errors.Wrap(err, "cannot bind environment variable").Error())
logrus.Fatalf(errors.Wrap(err, "cannot bind environment variable").Error())
}
}

if err := viper.Unmarshal(&cfg); err != nil {
log.Fatalf(errors.Wrap(err, "cannot unmarshal config").Error())
logrus.Fatalf(errors.Wrap(err, "cannot unmarshal config").Error())
}

// config logger
logConfig(cfg)
}

func addFlags(cmd *cobra.Command, cfg *config.Config) {
rootCmd.PersistentFlags().StringVarP(&cfg.Platform, "platform", "p", config.DefaultIndex, "set the source platform for stock data")
rootCmd.PersistentFlags().StringVarP(&cfg.Index, "index", "i", config.DefaultPlatform, "set the stock market index")
rootCmd.PersistentFlags().VarP(&cfg.Platform, "platform", "p", "set the source platform for stock data")
rootCmd.PersistentFlags().VarP(&cfg.Index, "index", "i", "set the stock market index")
}

func logConfig(cfg *config.Config) {
Expand All @@ -88,3 +101,19 @@ func logConfig(cfg *config.Config) {
logrus.SetLevel(level)
}
}

func prettyPrint(s *stock.Stock) {
timeLayout := "2006-01-02 15:04:05"

t := table.NewWriter()
t.SetOutputMirror(os.Stdout)
t.SetStyle(table.StyleColoredBlackOnMagentaWhite)

t.AppendHeader(table.Row{"Number", "Current Price", "Opening Price", "Previous Closing Price", "High Price", "Low Price", "Date"})
t.AppendRows([]table.Row{
{s.Number, s.CurrentPrice, s.OpeningPrice, s.PreviousClosingPrice, s.HighPrice, s.LowPrice, s.Date.Format(timeLayout)},
})
t.AppendSeparator()

t.Render()
}
9 changes: 6 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ module github.com/gaius-qi/honk
go 1.15

require (
github.com/aws/aws-lambda-go v1.17.0
github.com/aws/aws-sdk-go v1.31.7
github.com/awslabs/ssosync v0.0.2
github.com/jarcoal/httpmock v1.0.8
github.com/jedib0t/go-pretty/v6 v6.1.0
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.2.0
github.com/spf13/cobra v1.0.0
github.com/spf13/viper v1.4.0
github.com/stretchr/testify v1.5.1
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 // indirect
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect
golang.org/x/text v0.3.2 // indirect
)
293 changes: 10 additions & 283 deletions go.sum

Large diffs are not rendered by default.

53 changes: 49 additions & 4 deletions internal/config/config.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package config

import (
"fmt"
"reflect"
)

// Config holds all the runtime config information.
type Config struct {
// Stock number
Number string `mapstructure:"number"`
// Stock market index
Index string `mapstructure:"index"`
Index IndexType `mapstructure:"index"`
// Source platform for stock data
Platform string `mapstructure:"platform"`
Platform PlatformType `mapstructure:"platform"`
// Verbose toggles the verbosity
Debug bool
// LogLevel is the level with with to log for this config
Expand All @@ -14,11 +21,49 @@ type Config struct {
LogFormat string `mapstructure:"log_format"`
}

type PlatformType string

const (
SinaPlatformType PlatformType = "sina"
)

func (p *PlatformType) String() string {
return fmt.Sprint(*p)
}

func (p *PlatformType) Set(value string) error {
*p = PlatformType(value)
return nil
}

func (p *PlatformType) Type() string {
return reflect.TypeOf(p).String()
}

type IndexType string

const (
ShangHaiIndexType IndexType = "sh"
)

func (i *IndexType) String() string {
return fmt.Sprint(*i)
}

func (i *IndexType) Set(value string) error {
*i = IndexType(value)
return nil
}

func (i *IndexType) Type() string {
return reflect.TypeOf(i).String()
}

const (
// DefaultIndex is the default stock market index.
DefaultIndex = "sina"
DefaultIndex = ShangHaiIndexType
// DefaultPlatform is the default source platform.
DefaultPlatform = "sina"
DefaultPlatform = SinaPlatformType
// DefaultLogLevel is the default logging level.
DefaultLogLevel = "warn"
// DefaultLogFormat is the default format of the logger
Expand Down
21 changes: 21 additions & 0 deletions internal/config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package config

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestConfig(t *testing.T) {
assert := assert.New(t)

cfg := New()

assert.NotNil(cfg)

assert.Equal(cfg.LogLevel, DefaultLogLevel)
assert.Equal(cfg.LogFormat, DefaultLogFormat)
assert.Equal(cfg.Debug, DefaultDebug)
assert.Equal(cfg.Index, DefaultIndex)
assert.Equal(cfg.Platform, DefaultPlatform)
}
83 changes: 83 additions & 0 deletions pkg/stock/sina.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package stock

import (
"errors"
"fmt"
"io/ioutil"
"net/http"
"regexp"
"time"

"github.com/gaius-qi/honk/internal/config"
)

const (
defaultSinaHost = "hq.sinajs.cn"
defaultSinaProtocol = "https:"
sinaTimeLayout = "2006-01-02 15:04:05"
)

type sinaStock struct {
number string
index config.IndexType
}

func newSinaStock(cfg *config.Config) sinaStock {
return sinaStock{
number: cfg.Number,
index: cfg.Index,
}
}

func (s sinaStock) Get() (*Stock, error) {
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s//%s", defaultSinaProtocol, defaultSinaHost), nil)
if err != nil {
return nil, err
}

// Add query params
q := req.URL.Query()
q.Add("list", fmt.Sprintf("%s%s", s.index, s.number))
req.URL.RawQuery = q.Encode()

resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()

statusCode := resp.StatusCode
if statusCode >= http.StatusInternalServerError {
return nil, fmt.Errorf("Sina Server Error, status: %d", statusCode)
} else if statusCode >= http.StatusBadRequest {
return nil, fmt.Errorf("Honk Client Error, status: %d", statusCode)
}

body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}

// Match useful data
data := regexp.MustCompile(`[\\"\\,]+`).Split(string(body), -1)
if len(data) < 35 {
return nil, errors.New("Sina platform returns wrong data")
}

// Time parse
t, err := time.Parse(sinaTimeLayout, fmt.Sprintf("%s %s", data[31], data[32]))
if err != nil {
return nil, err
}

return &Stock{
Name: data[1],
Number: s.number,
OpeningPrice: data[2],
PreviousClosingPrice: data[3],
CurrentPrice: data[4],
HighPrice: data[5],
LowPrice: data[6],
Date: t,
}, nil
}
Loading

0 comments on commit e15f20d

Please sign in to comment.