diff --git a/pkg/cli/gracefull.go b/pkg/cli/gracefull.go new file mode 100644 index 0000000000000000000000000000000000000000..8fd64a3d612d2e99e3d3d255a29e4dac00ebd8ea --- /dev/null +++ b/pkg/cli/gracefull.go @@ -0,0 +1,40 @@ +package cli + +import ( + "os" + "os/signal" + "syscall" + + "go.uber.org/zap" +) + +func WaitForQuit(logger *zap.Logger, finailizer func()) { + donec := make(chan struct{}) + sigc := make(chan os.Signal, 1) + signal.Notify(sigc, syscall.SIGTERM, os.Interrupt) + var signalsReceived uint + go func() { + for { + select { + case s := <-sigc: + logger.Info("Signal received. Exiting", zap.String("Signal", s.String())) + signalsReceived++ + + if signalsReceived < 2 { + // After first Ctrl+C start quitting the worker gracefully + go func() { + finailizer() + close(donec) + }() + } else { + // Abort the program when user hits Ctrl+C second time in a row + logger.Info("Force exit") + close(donec) + } + } + } + }() + + <-donec + logger.Info("Quit") +} diff --git a/pkg/data/translit.go b/pkg/data/translit.go new file mode 100644 index 0000000000000000000000000000000000000000..654ae90dd305be0ffd20bfcd58c782229a27156b --- /dev/null +++ b/pkg/data/translit.go @@ -0,0 +1,54 @@ +package data + +import ( + "bytes" + "strings" + "unicode" +) + +var mapRuEn = map[rune]string{ + 'а': "a", 'б': "b", 'в': "v", 'г': "g", 'д': "d", 'е': "e", 'ё': "yo", 'ж': "zh", 'з': "z", 'и': "i", 'й': "j", + 'к': "k", 'л': "l", 'м': "m", 'н': "n", 'о': "o", 'п': "p", 'р': "r", 'с': "s", 'т': "t", 'у': "u", 'ф': "f", + 'х': "h", 'ц': "c", 'ч': "ch", 'ш': "sh", 'щ': "shh", 'ъ': "", 'ы': "y", 'ь': "", 'э': "e", 'я': "ya", +} + +func mapSpecial(r rune) rune { + if r <= unicode.MaxASCII && (unicode.IsLetter(r) || unicode.IsNumber(r) || r == ':' || r == '/') { + return r + } + return '-' +} + +func StringTransform(s string, lowercase bool) string { + s = TableEncode(s, mapRuEn) + s = strings.Map(mapSpecial, s) + if lowercase { + s = strings.ToLower(s) + } + return s +} + +func TableEncode(s string, tlm map[rune]string) string { + in := bytes.NewBufferString(s) + out := bytes.NewBuffer(nil) + + for { + r, _, err := in.ReadRune() + if err != nil { + break // EOF + } + + tr, ok := tlm[unicode.ToLower(r)] + if !ok { + out.WriteRune(r) + continue + } + + if unicode.IsUpper(r) { + tr = strings.Title(tr) + } + + out.WriteString(tr) + } + return out.String() +} diff --git a/pkg/data/translit_test.go b/pkg/data/translit_test.go new file mode 100644 index 0000000000000000000000000000000000000000..94b4f426827c56668f75e09da554b1071db9bae6 --- /dev/null +++ b/pkg/data/translit_test.go @@ -0,0 +1,45 @@ +package data + +import ( + "testing" +) + +func TestTranslit(t *testing.T) { + type args struct { + s string + lowercase bool + } + tests := []struct { + name string + args args + want string + }{ + { + name: "test translit cyrillic", + args: args{"Ёжик 2019", true}, + want: "yozhik-2019", + }, + { + name: "test translit cyrillic", + args: args{"Ёжик", false}, + want: "Yozhik", + }, + { + name: "test translit english", + args: args{"Hello world,sample", true}, + want: "hello-world-sample", + }, + { + name: "test translit english", + args: args{"Специальные...символы", true}, + want: "specialnye---simvoly", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := StringTransform(tt.args.s, tt.args.lowercase); got != tt.want { + t.Errorf("Translit() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/files/downloader.go b/pkg/files/downloader.go index 79acfeed5125a755c6908f77a7b66390239cb534..74aa91022906f794d07c314c5104011e4763caa9 100644 --- a/pkg/files/downloader.go +++ b/pkg/files/downloader.go @@ -1,6 +1,7 @@ package files import ( + "encoding/base64" "errors" "io" "net/http" @@ -30,3 +31,26 @@ func (d *downloader) Download(dst io.Writer, file *File) error { _, err = io.Copy(dst, r.Body) return err } + +type noopDownloader struct{} + +func NewNoopDownloader() Downloader { + return &noopDownloader{} +} + +func (d *noopDownloader) Download(dst io.Writer, file *File) error { + return nil +} + +type dummyDownloader struct{} + +func NewDummyDownloader() Downloader { + return &dummyDownloader{} +} + +func (d *dummyDownloader) Download(dst io.Writer, file *File) error { + // png pixel 10x10 + pixel, err := base64.StdEncoding.DecodeString("iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAFUlEQVR42mNkYPhfz0AEYBxVSF+FAP5FDvcfRYWgAAAAAElFTkSuQmCC") + _, err = dst.Write(pixel) + return err +}