bump to go 1.20 + fix some code issues
This commit is contained in:
		
							parent
							
								
									c1551be07f
								
							
						
					
					
						commit
						2bc22b637d
					
				
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1 +1,4 @@ | ||||
| mailsrv | ||||
| builds | ||||
| outbox | ||||
| 
 | ||||
| *.ini | ||||
|  | ||||
							
								
								
									
										32
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								Makefile
									
									
									
									
									
								
							| @ -1,26 +1,20 @@ | ||||
| .DEFAULT_GOAL := build | ||||
| 
 | ||||
| fmt: | ||||
| .DEFAULT_GOAL := run | ||||
| 
 | ||||
| BIN_NAME := mailsrv | ||||
| ROOT_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST)))) | ||||
| BUILD_DIR := $(ROOT_DIR)builds | ||||
| 
 | ||||
| build: format lint | ||||
| 	@mkdir -p $(BUILD_DIR) | ||||
| 	@go build -o $(BUILD_DIR)/$(BIN_NAME) main.go | ||||
| 
 | ||||
| format: | ||||
| 	go fmt ./... | ||||
| .PHONY:fmt | ||||
| 
 | ||||
| lint: fmt | ||||
| 	golint ./... | ||||
| .PHONY:lint | ||||
| 
 | ||||
| vet: fmt | ||||
| 	go vet ./... | ||||
| 	shadow ./... | ||||
| .PHONY:vet | ||||
| 
 | ||||
| build: | ||||
| 	go build -o mailsrv | ||||
| .PHONY:build | ||||
| 
 | ||||
| build-check: vet | ||||
| 	go build -o mailsrv | ||||
| .PHONY:build | ||||
| lint: | ||||
| 	golangci-lint run --fix | ||||
| 
 | ||||
| test: | ||||
| 	go test ./... | ||||
| .PHONY:test | ||||
|  | ||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							| @ -1,6 +1,6 @@ | ||||
| module mailsrv | ||||
| 
 | ||||
| go 1.17 | ||||
| go 1.20 | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/alecthomas/kingpin/v2 v2.3.2 | ||||
|  | ||||
							
								
								
									
										8
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								go.sum
									
									
									
									
									
								
							| @ -5,7 +5,6 @@ github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8V | ||||
| github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= | ||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= | ||||
| github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= | ||||
| github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= | ||||
| @ -18,13 +17,8 @@ github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= | ||||
| github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= | ||||
| github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= | ||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | ||||
| github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | ||||
| github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | ||||
| 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.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= | ||||
| github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= | ||||
| github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= | ||||
| github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= | ||||
| golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| @ -34,6 +28,4 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 | ||||
| gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= | ||||
| gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | ||||
| gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||
| gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
| gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||||
| gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
|  | ||||
| @ -3,11 +3,12 @@ package mail | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| type Email struct { | ||||
| 	Path      string | ||||
| 	Sender    string   `json:"sender"` | ||||
| 	Receivers []string `json:"receivers"` | ||||
| 	Subject   string   `json:"subject"` | ||||
| @ -26,9 +27,9 @@ func NewEmail(sender string, receivers []string, subject, content string) Email | ||||
| func FromJSON(path string) (Email, error) { | ||||
| 	var mail Email | ||||
| 
 | ||||
| 	content, err := ioutil.ReadFile(path) | ||||
| 	content, err := os.ReadFile(path) | ||||
| 	if err != nil { | ||||
| 		return mail, err | ||||
| 		return mail, fmt.Errorf("%w, unable to read the file: %s", err, path) | ||||
| 	} | ||||
| 
 | ||||
| 	if err := json.Unmarshal(content, &mail); err != nil { | ||||
|  | ||||
| @ -51,14 +51,14 @@ func (s Sender) SendMail(email mail.Email) error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // watchOutbox reads the `outbox` directory every `TickInterval` and put JSON format e-mail in the queue | ||||
| // watchOutbox reads the `outbox` directory every `TickInterval` and put JSON format e-mail in the queue. | ||||
| func (s Sender) watchOutbox() { | ||||
| 	log.Info().Str("outbox", s.outboxPath).Msg("start watching outbox directory") | ||||
| 
 | ||||
| 	ticker := time.NewTicker(TickerInterval) | ||||
| 
 | ||||
| 	go func() { | ||||
| 		for _ = range ticker.C { | ||||
| 		for range ticker.C { | ||||
| 			log.Debug().Str("action", "retrieving json e-mail format...").Str("path", s.outboxPath) | ||||
| 
 | ||||
| 			files, err := os.ReadDir(s.outboxPath) | ||||
| @ -69,18 +69,34 @@ func (s Sender) watchOutbox() { | ||||
| 
 | ||||
| 			for _, file := range files { | ||||
| 				filename := file.Name() | ||||
| 				if strings.HasSuffix(filename, JSONSuffix) { | ||||
| 					s.queue.Add(path.Join(s.outboxPath, filename)) | ||||
| 				if !strings.HasSuffix(filename, JSONSuffix) { | ||||
| 					log.Debug().Str("filename", filename).Msg("incorrect suffix") | ||||
| 					continue | ||||
| 				} | ||||
| 
 | ||||
| 				log.Debug().Str("filename", filename).Msg("incorrect suffix") | ||||
| 				path := path.Join(s.outboxPath, filename) | ||||
| 				email, err := mail.FromJSON(path) | ||||
| 
 | ||||
| 				if err != nil { | ||||
| 					log.Err(err).Str("path", path).Msg("unable to parse JSON email") | ||||
| 
 | ||||
| 					// if JSON parsing failed the `path` is renamed with an error suffix to not watch it again | ||||
| 					newPath := fmt.Sprintf("%s%s", path, ErrorSuffix) | ||||
| 					if err := os.Rename(path, newPath); err != nil { | ||||
| 						log.Err(err).Str("path", path).Str("new path", newPath).Msg("unable to rename bad JSON email path") | ||||
| 					} | ||||
| 
 | ||||
| 					continue | ||||
| 				} | ||||
| 
 | ||||
| 				email.Path = path | ||||
| 				s.queue.Add(email) | ||||
| 			} | ||||
| 		} | ||||
| 	}() | ||||
| } | ||||
| 
 | ||||
| // processNextEmail loops over the queue and send email | ||||
| // processNextEmail iterates over the queue and send email. | ||||
| func (s Sender) processNextEmail() bool { | ||||
| 	item, quit := s.queue.Get() | ||||
| 	if quit { | ||||
| @ -88,66 +104,56 @@ func (s Sender) processNextEmail() bool { | ||||
| 	} | ||||
| 	defer s.queue.Done(item) | ||||
| 
 | ||||
| 	path, ok := item.(string) | ||||
| 	email, ok := item.(mail.Email) | ||||
| 	if !ok { | ||||
| 		log.Error().Any("item", item).Msg("unable to cast queue item into mail.Email") | ||||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| 	email, err := mail.FromJSON(path) | ||||
| 	if err != nil { | ||||
| 		log.Err(err).Str("path", path).Msg("unable to parse JSON email") | ||||
| 
 | ||||
| 		// if JSON parsing failed the `path` is renamed with an error suffix to avoid enqueued it again | ||||
| 		newPath := fmt.Sprintf("%s%s", path, ErrorSuffix) | ||||
| 		if err := os.Rename(path, newPath); err != nil { | ||||
| 			log.Err(err).Str("path", path).Str("new path", newPath).Msg("unable to rename bad JSON email path") | ||||
| 			s.queue.Shutdown() | ||||
| 		} | ||||
| 		return true | ||||
| 	if err := s.SendMail(email); err != nil { | ||||
| 		log.Err(err).Msg("unable to send the email") | ||||
| 	} | ||||
| 
 | ||||
| 	// whatever the return, the email will be not enqueued again | ||||
| 	s.SendMail(email) | ||||
| 
 | ||||
| 	if err := os.Remove(path); err != nil { | ||||
| 		// this is a fatal error, can't send same e-mail indefinitely | ||||
| 		if !os.IsExist(err) { | ||||
| 			log.Err(err).Str("path", path).Msg("unable to remove the JSON email") | ||||
| 			s.queue.Shutdown() | ||||
| 	if path := email.Path; path != "" { | ||||
| 		if err := os.Remove(path); err != nil { | ||||
| 			// this is a fatal error, can't send same e-mail indefinitely | ||||
| 			if !os.IsExist(err) { | ||||
| 				log.Err(err).Str("path", path).Msg("unable to remove the JSON email") | ||||
| 				s.queue.Shutdown() | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // run starts processing the queue | ||||
| // run starts processing the queue. | ||||
| func (s Sender) run() <-chan struct{} { | ||||
| 	queueCh := make(chan struct{}) | ||||
| 	chQueue := make(chan struct{}) | ||||
| 	go func() { | ||||
| 		for s.processNextEmail() { | ||||
| 		} | ||||
| 		queueCh <- struct{}{} | ||||
| 		chQueue <- struct{}{} | ||||
| 	}() | ||||
| 	return queueCh | ||||
| 	return chQueue | ||||
| } | ||||
| 
 | ||||
| // Run launches the queue processing and the outbox watcher | ||||
| // catches `SIGINT` and `SIGTERM` to properly stopped the queue | ||||
| // Run launches the queue processing and the outbox watcher. | ||||
| // It catches `SIGINT` and `SIGTERM` to properly stopped the queue. | ||||
| func (s Sender) Run() { | ||||
| 	log.Info().Msg("sender service is running") | ||||
| 
 | ||||
| 	sigCh := make(chan os.Signal, 1) | ||||
| 	signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) | ||||
| 	chSignal := make(chan os.Signal, 1) | ||||
| 	signal.Notify(chSignal, os.Interrupt, syscall.SIGTERM) | ||||
| 
 | ||||
| 	s.watchOutbox() | ||||
| 	queueCh := s.run() | ||||
| 	chQueue := s.run() | ||||
| 
 | ||||
| 	select { | ||||
| 	case <-sigCh: | ||||
| 	case <-chSignal: | ||||
| 		log.Warn().Msg("stop signal received, stopping e-mail queue...") | ||||
| 		s.queue.Shutdown() | ||||
| 	case <-queueCh: | ||||
| 	case <-chQueue: | ||||
| 		log.Info().Msg("e-mail queue stopped successfully") | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user