From 70b03d35d09dd98620bec16efb73e41861bd652a Mon Sep 17 00:00:00 2001
From: FishGoddess <1149062639@qq.com>
Date: Mon, 6 Sep 2021 23:55:14 +0800
Subject: [PATCH 01/27] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=BB=98=E8=AE=A4?=
=?UTF-8?q?=E9=85=8D=E7=BD=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
_examples/config/postar.ini | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/_examples/config/postar.ini b/_examples/config/postar.ini
index 73292e8..cd8b8ba 100644
--- a/_examples/config/postar.ini
+++ b/_examples/config/postar.ini
@@ -47,6 +47,6 @@
[server]
#address = ":5897"
#use_http2 = false
-#tls_cert = "../conf/postar_cert.pem"
-#tls_cert_key = "../conf/postar_cert.key"
+#tls_cert = "/opt/postar/conf/postar_cert.pem"
+#tls_cert_key = "/opt/postar/conf/postar_cert.key"
#wait_for_closing = 30
\ No newline at end of file
From d7912fddef79b58cfd9aa54dac02bb2de545fa39 Mon Sep 17 00:00:00 2001
From: FishGoddess <1149062639@qq.com>
Date: Thu, 16 Sep 2021 02:06:42 +0800
Subject: [PATCH 02/27] =?UTF-8?q?=E5=B7=A5=E7=A8=8B=E5=8C=96=E5=AE=9E?=
=?UTF-8?q?=E8=B7=B5=E9=87=8D=E6=9E=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
_examples/config/postar.ini | 52 -----------
api/postard/postard.proto | 8 ++
base/model/response.go | 42 ---------
build.sh | 40 ---------
cmd/postard/main.go | 13 +++
internal/postard/server/grpc.go | 9 ++
internal/postard/server/http.go | 9 ++
internal/postard/service/smtp.go | 9 ++
main.go | 80 -----------------
module/basic.go | 34 -------
module/config.go | 110 -----------------------
module/logger.go | 76 ----------------
module/sender/basic.go | 63 -------------
module/sender/smtp.go | 116 ------------------------
module/server/basic.go | 53 -----------
module/server/http.go | 147 -------------------------------
postar.go | 61 -------------
17 files changed, 48 insertions(+), 874 deletions(-)
delete mode 100644 _examples/config/postar.ini
create mode 100644 api/postard/postard.proto
delete mode 100644 base/model/response.go
delete mode 100644 build.sh
create mode 100644 cmd/postard/main.go
create mode 100644 internal/postard/server/grpc.go
create mode 100644 internal/postard/server/http.go
create mode 100644 internal/postard/service/smtp.go
delete mode 100644 main.go
delete mode 100644 module/basic.go
delete mode 100644 module/config.go
delete mode 100644 module/logger.go
delete mode 100644 module/sender/basic.go
delete mode 100644 module/sender/smtp.go
delete mode 100644 module/server/basic.go
delete mode 100644 module/server/http.go
delete mode 100644 postar.go
diff --git a/_examples/config/postar.ini b/_examples/config/postar.ini
deleted file mode 100644
index cd8b8ba..0000000
--- a/_examples/config/postar.ini
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright 2021 Ye Zi Jie. All rights reserved.
-# Use of this source code is governed by a MIT style
-# license that can be found in the LICENSE file.
-#
-# Postar 配置文件案例
-# Author: FishGoddess
-
-# Global 是全局配置区块,主要用于配置整体的运行状态。
-# sender_type 配置邮件发送器的类型,可选项为 smtp。默认是 smtp。
-# server_type 配置网络服务器的类型,可选项为 http。默认是 http。
-[global]
-#sender_type = "smtp"
-#server_type = "http"
-
-# Logger 是日志配置区块,主要用于配置日志的运行状态。
-# level 配置日志记录的级别,可选项为 debug/info/warn/error/off,其中 off 表示关闭日志记录。默认是 info。
-# time_format 配置日志记录的时间格式化模板,若配置为 "",则将时间记录为 unix 秒级时间戳。默认为 2006-01-02 15:04:05.000。
-# output_file 配置非错误日志的输出文件路径。windows 默认是 ../log/postar.log,其他系统默认是 /opt/postar/log/postar.log。
-# error_output_file 配置错误日志的输出文件路径。windows 默认是 ../log/postar.error.log,其他系统默认是 /opt/postar/log/postar.error.log。
-[logger]
-#level = "info"
-#time_format = "2006-01-02 15:04:05.000"
-#output_file = "/opt/postar/log/postar.log"
-#error_output_file = "/opt/postar/log/postar.error.log"
-
-# Sender 是邮件发送器配置区块,主要用于配置邮件发送器的运行状态。
-# smtp_host 配置 smtp 服务器的主机名。默认从环境变量中取 POSTAR_SMTP_HOST 的值。
-# smtp_port 配置 smtp 服务器的端口号。默认为 587。
-# smtp_user 配置 smtp 服务器的用户名。默认从环境变量中取 POSTAR_SMTP_USER 的值。
-# smtp_password 配置 smtp 服务器的密码。默认从环境变量中取 POSTAR_SMTP_PASSWORD 的值。
-# worker_number 配置邮件发送器的异步工作协程数,仅在 sender_type 为 smtp 时有效。默认为 64。
-# request_channel_size 配置发送请求任务队列的最大大小,若任务堆积导致队列满了,则新的发送请求会被阻塞。默认为 65536。
-[sender]
-#smtp_host = "smtp.xxx.com"
-#smtp_port = 587
-#smtp_user = "xxx@xxx.com"
-#smtp_password = "xxx"
-#worker_number = 64
-#request_channel_size = 65536
-
-# Server 是网络服务器配置区块,主要用于配置网络服务器的运行状态。
-# address 配置网络服务器的绑定地址,包括 IP 和端口号。默认为 :5897。
-# use_http2 选择是否使用 http2(建议使用 h2 标准配置证书),可选项为 true/false。默认为 false。
-# tls_cert 配置 TLS 证书文件的路径,只有 use_http2 = true,该选项才会生效。windows 默认为 ../conf/postar_cert.pem,其它系统默认是 /opt/postar/conf/postar_cert.pem。
-# tls_cert_key 配置 TLS 证书 key 文件的路径,只有 use_http2 = true,该选项才会生效。windows 默认为 ../conf/postar_cert.key,其它系统默认是 /opt/postar/conf/postar_cert.key。
-# wait_for_closing 配置服务器关闭等待时间,服务关闭时会等待请求处理完成,若等待超过改时间,服务会强制退出。单位为秒,默认是 30 秒。
-[server]
-#address = ":5897"
-#use_http2 = false
-#tls_cert = "/opt/postar/conf/postar_cert.pem"
-#tls_cert_key = "/opt/postar/conf/postar_cert.key"
-#wait_for_closing = 30
\ No newline at end of file
diff --git a/api/postard/postard.proto b/api/postard/postard.proto
new file mode 100644
index 0000000..d04834e
--- /dev/null
+++ b/api/postard/postard.proto
@@ -0,0 +1,8 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/16 01:42:33
+syntax = "proto3";
\ No newline at end of file
diff --git a/base/model/response.go b/base/model/response.go
deleted file mode 100644
index 4543f54..0000000
--- a/base/model/response.go
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/08/16 02:19:43
-
-package model
-
-var (
- SuccessfulResponse = &Response{Code: 0, Msg: "ok"}
- RequestMethodNotAllowedResponse = &Response{Code: -1001, Msg: "request method not allowed"}
-)
-
-var (
- GetSendRequestFailedResponse = &Response{Code: -10001, Msg: "get send request failed"}
- SendEmailTimeoutResponse = &Response{Code: -10002, Msg: "send email timeout"}
- SendEmailFailedResponse = &Response{Code: -10003, Msg: "send email failed"}
-)
-
-type Response struct {
- Code int `json:"code"`
- Msg string `json:"msg"`
- Data interface{} `json:"data"`
-}
-
-func NewResponse(code int, msg string, data interface{}) *Response {
- return &Response{
- Code: code,
- Msg: msg,
- Data: data,
- }
-}
-
-func NewSuccessfulResponse(data interface{}) *Response {
- return &Response{
- Code: SuccessfulResponse.Code,
- Msg: SuccessfulResponse.Msg,
- Data: data,
- }
-}
diff --git a/build.sh b/build.sh
deleted file mode 100644
index 854d1b8..0000000
--- a/build.sh
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright 2021 Ye Zi Jie. All rights reserved.
-# Use of this source code is governed by a MIT style
-# license that can be found in the LICENSE file.
-#
-# Postar build script
-# Author: fishgoddess
-VERSION=v0.2.3-alpha
-BUILD_TARGET=target
-CONFIG_FILE=_examples/config/postar.ini
-
-# Before building
-echo "Start building to: $BUILD_TARGET"
-mkdir $BUILD_TARGET
-rm -r ${BUILD_TARGET:?}/bin ${BUILD_TARGET:?}/conf ${BUILD_TARGET:?}/log
-
-# Go build: windows, linux and darwin
-echo "Building windows version..."
-CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o $BUILD_TARGET/bin/postar-$VERSION-windows.exe
-
-echo "Building linux version..."
-CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o $BUILD_TARGET/bin/postar-$VERSION-linux
-chmod +x $BUILD_TARGET/bin/postar-$VERSION-linux
-
-echo "Building darwin version..."
-CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o $BUILD_TARGET/bin/postar-$VERSION-darwin
-chmod +x $BUILD_TARGET/bin/postar-$VERSION-darwin
-
-# Before packaging
-echo "Before packaging..."
-mkdir -p $BUILD_TARGET/conf
-mkdir -p $BUILD_TARGET/log
-cp $CONFIG_FILE $BUILD_TARGET/conf/
-
-# Packaging to one
-echo "Packaging to one: postar-$VERSION.tar.gz"
-cd $BUILD_TARGET || exit
-tar -czf postar-$VERSION.tar.gz bin conf log
-
-# Done
-echo "Done."
diff --git a/cmd/postard/main.go b/cmd/postard/main.go
new file mode 100644
index 0000000..5688188
--- /dev/null
+++ b/cmd/postard/main.go
@@ -0,0 +1,13 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/16 01:33:43
+
+package main
+
+func main() {
+
+}
diff --git a/internal/postard/server/grpc.go b/internal/postard/server/grpc.go
new file mode 100644
index 0000000..217f6b5
--- /dev/null
+++ b/internal/postard/server/grpc.go
@@ -0,0 +1,9 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/16 02:05:02
+
+package server
diff --git a/internal/postard/server/http.go b/internal/postard/server/http.go
new file mode 100644
index 0000000..3665780
--- /dev/null
+++ b/internal/postard/server/http.go
@@ -0,0 +1,9 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/16 02:04:54
+
+package server
diff --git a/internal/postard/service/smtp.go b/internal/postard/service/smtp.go
new file mode 100644
index 0000000..273d09d
--- /dev/null
+++ b/internal/postard/service/smtp.go
@@ -0,0 +1,9 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/16 02:05:37
+
+package service
diff --git a/main.go b/main.go
deleted file mode 100644
index 8718042..0000000
--- a/main.go
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/08/11 00:22:42
-
-package main
-
-import (
- "flag"
- "fmt"
- "io/ioutil"
- "runtime"
- "strings"
- "time"
-
- "github.com/avino-plan/postar/module"
- "github.com/go-ini/ini"
-)
-
-func configFile() *module.Config {
-
- defaultConfigFile := "/opt/postar/conf/postar.ini"
- if strings.Contains(runtime.GOOS, "windows") {
- defaultConfigFile = "../conf/postar.ini"
- }
-
- configFile := flag.String("conf", defaultConfigFile, "The file path of Postar configuration.")
- flag.Parse()
- fmt.Printf("Postar got config file: %s\n", *configFile)
-
- config := module.DefaultConfig()
- if *configFile == "" {
- return config
- }
-
- err := ini.MapTo(config, *configFile)
- if err != nil {
- panic(err)
- }
-
- fmt.Printf("Postar's config:\n%+v\n", config)
- return config
-}
-
-func recordStartError(msg string, err error) {
- msg = fmt.Sprintf("[%s] [%s] %+v\n", time.Now().Format("2006-01-02 15:04:05.000"), msg, err)
- ioutil.WriteFile("./start_error.log", []byte(msg), 0644)
-}
-
-func main() {
-
- beginTime := time.Now()
-
- postar := newPostar()
- err := postar.Initialize(configFile())
- if err != nil {
- recordStartError("Initialize error", err)
- panic(err)
- }
-
- endTime := time.Now()
- fmt.Printf("Postar initialized successfully! It took %dms.\n", endTime.Sub(beginTime).Milliseconds())
-
- go func() {
- err = postar.Run()
- if err != nil {
- recordStartError("Run error", err)
- panic(err)
- }
- }()
-
- err = postar.WaitForShutdown()
- if err != nil {
- recordStartError("Shutdown error", err)
- panic(err)
- }
-}
diff --git a/module/basic.go b/module/basic.go
deleted file mode 100644
index ade4d97..0000000
--- a/module/basic.go
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/08/12 23:00:43
-
-package module
-
-const (
- Version = "v0.2.3-alpha"
-)
-
-var (
- initializations = []func(config *Config) error{
- initLogger,
- }
-)
-
-func Initialize(config *Config) error {
-
- if config == nil {
- config = DefaultConfig()
- }
-
- for _, initialize := range initializations {
- err := initialize(config)
- if err != nil {
- return err
- }
- }
- return nil
-}
diff --git a/module/config.go b/module/config.go
deleted file mode 100644
index 52c404f..0000000
--- a/module/config.go
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/08/12 22:59:05
-
-package module
-
-import (
- "fmt"
- "os"
- "runtime"
- "strconv"
- "strings"
-)
-
-type GlobalConfig struct {
- SenderType string `ini:"sender_type"`
- ServerType string `ini:"server_type"`
-}
-
-type LoggerConfig struct {
- Level string `ini:"level"`
- TimeFormat string `ini:"time_format"`
- OutputFile string `ini:"output_file"`
- ErrorOutputFile string `ini:"error_output_file"`
-}
-
-type SenderConfig struct {
- SmtpHost string `ini:"smtp_host"`
- SmtpPort int `ini:"smtp_port"`
- SmtpUser string `ini:"smtp_user"`
- SmtpPassword string `ini:"smtp_password"`
- WorkerNumber int `ini:"worker_number"`
- RequestChannelSize int `ini:"request_channel_size"`
-}
-
-type ServerConfig struct {
- Address string `ini:"address"`
- UseHttp2 bool `ini:"use_http2"`
- TLSCert string `ini:"tls_cert"`
- TLSCertKey string `ini:"tls_cert_key"`
- WaitForClosing int `int:"wait_for_closing"`
-}
-
-type Config struct {
- Global *GlobalConfig `ini:"global"`
- Logger *LoggerConfig `ini:"logger"`
- Sender *SenderConfig `ini:"sender"`
- Server *ServerConfig `ini:"server"`
-}
-
-func (c *Config) String() string {
- return fmt.Sprintf("- GlobalConfig is %+v\n- LoggerConfig is %+v\n- SenderConfig is %+v\n- ServerConfig is %+v\n", *c.Global, *c.Logger, *c.Sender, *c.Server)
-}
-
-func DefaultConfig() *Config {
-
- logFile := "/opt/postar/log/postar.log"
- errorLogFile := "/opt/postar/log/postar.error.log"
- if strings.Contains(runtime.GOOS, "windows") {
- logFile = "../log/postar.log"
- errorLogFile = "../log/postar.error.log"
- }
-
- tlsCert := "/opt/postar/conf/postar_cert.pem"
- tlsCertKey := "/opt/postar/conf/postar_cert.key"
- if strings.Contains(runtime.GOOS, "windows") {
- tlsCert = "../conf/postar_cert.pem"
- tlsCertKey = "../conf/postar_cert.key"
- }
-
- port, err := strconv.Atoi(os.Getenv("POSTAR_SMTP_PORT"))
- if err != nil {
- port = 587
- }
- return &Config{
- Global: &GlobalConfig{
- SenderType: "smtp",
- ServerType: "http",
- },
- Logger: &LoggerConfig{
- Level: "info",
- TimeFormat: "2006-01-02 15:04:05.000",
- OutputFile: logFile,
- ErrorOutputFile: errorLogFile,
- },
- Sender: &SenderConfig{
- SmtpHost: os.Getenv("POSTAR_SMTP_HOST"),
- SmtpPort: port,
- SmtpUser: os.Getenv("POSTAR_SMTP_USER"),
- SmtpPassword: os.Getenv("POSTAR_SMTP_PASSWORD"),
- WorkerNumber: 64,
- RequestChannelSize: 65536,
- },
- Server: &ServerConfig{
- Address: ":5897",
- UseHttp2: false,
- TLSCert: tlsCert,
- TLSCertKey: tlsCertKey,
- WaitForClosing: 30, // 30s
- },
- }
-}
-
-type Configurer interface {
- Configure(config *Config) error
-}
diff --git a/module/logger.go b/module/logger.go
deleted file mode 100644
index 87297d2..0000000
--- a/module/logger.go
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/08/16 00:57:03
-
-package module
-
-import (
- "io"
- "os"
-
- "github.com/FishGoddess/logit"
-)
-
-var (
- globalLogger *logit.Logger
-)
-
-func loggerLevelOptionFrom(config *Config) logit.Option {
-
- options := logit.Options()
- if config.Logger.Level == "off" {
- // TODO 替换为 OffLevel
- return options.WithErrorLevel()
- }
-
- if config.Logger.Level == "error" {
- return options.WithErrorLevel()
- }
-
- if config.Logger.Level == "warn" {
- return options.WithWarnLevel()
- }
-
- if config.Logger.Level == "info" {
- return options.WithInfoLevel()
- }
- return options.WithDebugLevel()
-}
-
-func outputFilesFrom(config *Config) (io.Writer, io.Writer, error) {
-
- outputFile, err := os.OpenFile(config.Logger.OutputFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
- if err != nil {
- return nil, nil, err
- }
-
- errorOutputFile, err := os.OpenFile(config.Logger.ErrorOutputFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
- if err != nil {
- return nil, nil, err
- }
- return outputFile, errorOutputFile, nil
-}
-
-func initLogger(config *Config) error {
-
- options := logit.Options()
- outputFile, errorOutputFile, err := outputFilesFrom(config)
- if err != nil {
- return err
- }
- globalLogger = logit.NewLogger(
- loggerLevelOptionFrom(config),
- options.WithTimeFormat(config.Logger.TimeFormat),
- options.WithWriter(outputFile, true),
- options.WithErrorWriter(errorOutputFile, false),
- )
- return nil
-}
-
-func Logger() *logit.Logger {
- return globalLogger
-}
diff --git a/module/sender/basic.go b/module/sender/basic.go
deleted file mode 100644
index ce50a53..0000000
--- a/module/sender/basic.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/08/12 23:20:22
-
-package sender
-
-import (
- "errors"
- "fmt"
-
- "github.com/avino-plan/postar/module"
-)
-
-var (
- timeoutErr = errors.New("timeout")
-
- senders = map[string]func() Sender{
- "smtp": newSmtpSender,
- }
-)
-
-type Email struct {
- To []string `json:"to"`
- Subject string `json:"subject"`
- Content string `json:"content"`
-}
-
-type SendOptions struct {
- Async bool `json:"async"`
- Timeout int `json:"timeout"` // 发送超时,单位为 ms
-}
-
-func DefaultSendOptions() SendOptions {
- return SendOptions{
- Async: false,
- Timeout: 10000,
- }
-}
-
-type Sender interface {
- module.Configurer
- SendEmail(email *Email, options *SendOptions) error
- Close() error
-}
-
-func Initialize(config *module.Config) (Sender, error) {
-
- newSender, ok := senders[config.Global.SenderType]
- if !ok {
- return nil, fmt.Errorf("sender type %s not found", config.Global.SenderType)
- }
-
- sender := newSender()
- return sender, sender.Configure(config)
-}
-
-func IsTimeout(err error) bool {
- return err == timeoutErr
-}
diff --git a/module/sender/smtp.go b/module/sender/smtp.go
deleted file mode 100644
index fb346bc..0000000
--- a/module/sender/smtp.go
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/08/11 23:34:02
-
-package sender
-
-import (
- "sync"
- "time"
-
- "github.com/avino-plan/postar/module"
- "gopkg.in/gomail.v2"
-)
-
-type smtpRequest struct {
- message *gomail.Message
- errorCh chan error
-}
-
-func (sr *smtpRequest) reset() {
- sr.message.Reset()
- sr.errorCh = make(chan error, 1)
-}
-
-type SmtpSender struct {
- host string
- port int
- user string
- dialer *gomail.Dialer
- requestCh chan *smtpRequest
- requestPool *sync.Pool
-}
-
-func newSmtpSender() Sender {
- return &SmtpSender{
- requestPool: &sync.Pool{
- New: func() interface{} {
- return &smtpRequest{
- message: gomail.NewMessage(),
- errorCh: make(chan error, 1),
- }
- },
- },
- }
-}
-
-func (sms *SmtpSender) newRequest() *smtpRequest {
- return sms.requestPool.Get().(*smtpRequest)
-}
-
-func (sms *SmtpSender) releaseRequest(request *smtpRequest) {
- request.reset()
- sms.requestPool.Put(request)
-}
-
-func (sms *SmtpSender) Configure(config *module.Config) error {
-
- sms.host = config.Sender.SmtpHost
- sms.port = config.Sender.SmtpPort
- sms.user = config.Sender.SmtpUser
- sms.dialer = gomail.NewDialer(sms.host, sms.port, sms.user, config.Sender.SmtpPassword)
- sms.requestCh = make(chan *smtpRequest, config.Sender.RequestChannelSize)
-
- for i := 0; i < config.Sender.WorkerNumber; i++ {
- go func() {
- for request := range sms.requestCh {
- request.errorCh <- sms.dialer.DialAndSend(request.message)
- sms.releaseRequest(request)
- }
- }()
- }
- return nil
-}
-
-func (sms *SmtpSender) SendEmail(email *Email, options *SendOptions) error {
-
- if email == nil {
- return nil
- }
-
- if options == nil {
- opts := DefaultSendOptions()
- options = &opts
- }
-
- request := sms.newRequest()
- request.message.SetHeader("From", sms.user)
- request.message.SetHeader("To", email.To...)
- request.message.SetHeader("Subject", email.Subject)
- request.message.SetBody("text/plain;charset=utf-8", email.Content)
- module.Logger().Debug("before sending email").Any("email", email).Any("options", options).End()
-
- sms.requestCh <- request
- if options.Async {
- return nil
- }
-
- select {
- case err := <-request.errorCh:
- return err
- case <-time.After(time.Duration(options.Timeout) * time.Millisecond):
- return timeoutErr
- }
-}
-
-func (sms *SmtpSender) Close() error {
- for len(sms.requestCh) > 0 {
- time.Sleep(100 * time.Millisecond)
- }
- close(sms.requestCh)
- return nil
-}
diff --git a/module/server/basic.go b/module/server/basic.go
deleted file mode 100644
index 285483f..0000000
--- a/module/server/basic.go
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/08/12 23:27:54
-
-package server
-
-import (
- "fmt"
-
- "github.com/avino-plan/postar/module"
- "github.com/avino-plan/postar/module/sender"
-)
-
-var (
- servers = map[string]func() Server{
- "http": newHttpServer,
- }
-)
-
-type SendRequest struct {
- Email *sender.Email `json:"email"`
- Options *sender.SendOptions `json:"options"`
-}
-
-func newSendRequest() *SendRequest {
- sendOptions := sender.DefaultSendOptions()
- return &SendRequest{
- Email: nil,
- Options: &sendOptions,
- }
-}
-
-type Server interface {
- module.Configurer
- ConfigureSender(sender sender.Sender)
- Serve() error
- Close() error
-}
-
-func Initialize(config *module.Config) (Server, error) {
-
- newServer, ok := servers[config.Global.ServerType]
- if !ok {
- return nil, fmt.Errorf("server type %s not found", config.Global.ServerType)
- }
-
- server := newServer()
- return server, server.Configure(config)
-}
diff --git a/module/server/http.go b/module/server/http.go
deleted file mode 100644
index 74507af..0000000
--- a/module/server/http.go
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/08/12 00:26:28
-
-package server
-
-import (
- "context"
- "encoding/json"
- "net/http"
- "time"
-
- "github.com/avino-plan/postar/base/model"
- "github.com/avino-plan/postar/module"
- "github.com/avino-plan/postar/module/sender"
-)
-
-type HttpServer struct {
- address string
- useHttp2 bool
- tlsCert string
- tlsCertKey string
- waitForClosing int
- sender sender.Sender
- server *http.Server
-}
-
-func newHttpServer() Server {
- return &HttpServer{}
-}
-
-func (hs *HttpServer) Configure(config *module.Config) error {
- hs.address = config.Server.Address
- hs.useHttp2 = config.Server.UseHttp2
- hs.waitForClosing = config.Server.WaitForClosing
- hs.tlsCert = config.Server.TLSCert
- hs.tlsCertKey = config.Server.TLSCertKey
- return nil
-}
-
-func (hs *HttpServer) ConfigureSender(sender sender.Sender) {
- hs.sender = sender
-}
-
-func (hs *HttpServer) writeResponse(writer http.ResponseWriter, statusCode int, response *model.Response) {
-
- writer.Header().Set("Content-Type", "application/json; charset=utf-8")
-
- marshaled, err := json.Marshal(response)
- if err != nil {
- module.Logger().Error("marshal response to Json failed").Error("err", err).End()
- writer.WriteHeader(http.StatusInternalServerError)
- writer.Write([]byte(`{"code": -1, "msg": "marshal response to Json failed", "data": null}`))
- return
- }
-
- writer.WriteHeader(statusCode)
- writer.Write(marshaled)
-}
-
-func (hs *HttpServer) rootHandler(writer http.ResponseWriter, request *http.Request) {
-
- if request.Method != "GET" {
- module.Logger().Error("request method not allowed").String("request.Method", request.Method).End()
- hs.writeResponse(writer, http.StatusMethodNotAllowed, model.RequestMethodNotAllowedResponse)
- return
- }
- hs.writeResponse(writer, http.StatusOK, model.NewSuccessfulResponse(map[string]interface{}{
- "service": "postar",
- "introduction": "You know, for sending emails!",
- "version": module.Version,
- "protocol": request.Proto,
- }))
-}
-
-func (hs *HttpServer) getSendRequestFrom(request *http.Request) (*SendRequest, error) {
- defer request.Body.Close()
- sendRequest := newSendRequest()
- return sendRequest, json.NewDecoder(request.Body).Decode(sendRequest)
-}
-
-func (hs *HttpServer) sendEmailHandler(writer http.ResponseWriter, request *http.Request) {
-
- if request.Method != "PUT" {
- module.Logger().Error("request method not allowed").String("request.Method", request.Method).End()
- hs.writeResponse(writer, http.StatusMethodNotAllowed, model.RequestMethodNotAllowedResponse)
- return
- }
-
- sendRequest, err := hs.getSendRequestFrom(request)
- if err != nil {
- module.Logger().Error("get send request failed").Error("err", err).End()
- hs.writeResponse(writer, http.StatusBadRequest, model.GetSendRequestFailedResponse)
- return
- }
-
- err = hs.sender.SendEmail(sendRequest.Email, sendRequest.Options)
- if sender.IsTimeout(err) {
- module.Logger().Error("send timeout").Error("err", err).Any("email", sendRequest.Email).Any("options", sendRequest.Options).End()
- hs.writeResponse(writer, http.StatusInternalServerError, model.SendEmailTimeoutResponse)
- return
- }
-
- if err != nil {
- module.Logger().Error("send email failed").Error("err", err).Any("email", sendRequest.Email).Any("options", sendRequest.Options).End()
- hs.writeResponse(writer, http.StatusInternalServerError, model.SendEmailFailedResponse)
- return
- }
-
- hs.writeResponse(writer, http.StatusOK, model.SuccessfulResponse)
-}
-
-func (hs *HttpServer) Serve() error {
-
- handlers := http.NewServeMux()
- handlers.HandleFunc("/", hs.rootHandler)
- handlers.HandleFunc("/send", hs.sendEmailHandler)
- hs.server = &http.Server{Addr: hs.address, Handler: handlers}
-
- var err error
- if hs.useHttp2 {
- err = hs.server.ListenAndServeTLS(hs.tlsCert, hs.tlsCertKey)
- } else {
- err = hs.server.ListenAndServe()
- }
-
- if err == http.ErrServerClosed {
- return nil
- }
- return err
-}
-
-func (hs *HttpServer) Close() error {
-
- ctx, cancel := context.WithTimeout(context.Background(), time.Duration(hs.waitForClosing)*time.Second)
- defer cancel()
-
- err := hs.server.Shutdown(ctx)
- if err != nil {
- return err
- }
- return hs.sender.Close()
-}
diff --git a/postar.go b/postar.go
deleted file mode 100644
index 385e580..0000000
--- a/postar.go
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/08/14 15:00:07
-
-package main
-
-import (
- "fmt"
- "os"
- "os/signal"
- "syscall"
-
- "github.com/avino-plan/postar/module"
- "github.com/avino-plan/postar/module/sender"
- "github.com/avino-plan/postar/module/server"
-)
-
-type Postar struct {
- svr server.Server
-}
-
-func newPostar() *Postar {
- return &Postar{}
-}
-
-func (p *Postar) Initialize(config *module.Config) error {
-
- err := module.Initialize(config)
- if err != nil {
- return err
- }
-
- sdr, err := sender.Initialize(config)
- if err != nil {
- return err
- }
-
- p.svr, err = server.Initialize(config)
- if err != nil {
- return err
- }
-
- p.svr.ConfigureSender(sdr)
- return nil
-}
-
-func (p *Postar) Run() error {
- return p.svr.Serve()
-}
-
-func (p *Postar) WaitForShutdown() error {
- signalCh := make(chan os.Signal, 1)
- signal.Notify(signalCh, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
- <-signalCh
- fmt.Println("Postar is shutdown gracefully...")
- return p.svr.Close()
-}
From d3275e1e344f416b3e47cb8f084a9f3563375b86 Mon Sep 17 00:00:00 2001
From: FishGoddess <1149062639@qq.com>
Date: Fri, 17 Sep 2021 01:55:52 +0800
Subject: [PATCH 03/27] =?UTF-8?q?=E9=82=AE=E4=BB=B6=E5=8F=91=E9=80=81?=
=?UTF-8?q?=E9=87=8D=E6=9E=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
internal/postard/server/server.go | 18 ++++
internal/postard/service/error.go | 9 ++
internal/postard/service/service.go | 34 +++++++
internal/postard/service/smtp.go | 64 +++++++++++++
pkg/concurrency/error.go | 20 ++++
pkg/concurrency/error_test.go | 25 +++++
pkg/concurrency/pool.go | 137 ++++++++++++++++++++++++++++
pkg/concurrency/pool_test.go | 39 ++++++++
8 files changed, 346 insertions(+)
create mode 100644 internal/postard/server/server.go
create mode 100644 internal/postard/service/error.go
create mode 100644 internal/postard/service/service.go
create mode 100644 pkg/concurrency/error.go
create mode 100644 pkg/concurrency/error_test.go
create mode 100644 pkg/concurrency/pool.go
create mode 100644 pkg/concurrency/pool_test.go
diff --git a/internal/postard/server/server.go b/internal/postard/server/server.go
new file mode 100644
index 0000000..83f937a
--- /dev/null
+++ b/internal/postard/server/server.go
@@ -0,0 +1,18 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/17 00:15:34
+
+package server
+
+import "github.com/avino-plan/postar/internal/postard/service"
+
+func DefaultSendOptions() *service.SendEmailOptions {
+ return &service.SendEmailOptions{
+ Async: false,
+ Timeout: 10000,
+ }
+}
diff --git a/internal/postard/service/error.go b/internal/postard/service/error.go
new file mode 100644
index 0000000..8421697
--- /dev/null
+++ b/internal/postard/service/error.go
@@ -0,0 +1,9 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/17 01:38:30
+
+package service
diff --git a/internal/postard/service/service.go b/internal/postard/service/service.go
new file mode 100644
index 0000000..7fbb706
--- /dev/null
+++ b/internal/postard/service/service.go
@@ -0,0 +1,34 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/17 00:06:09
+
+package service
+
+import (
+ "context"
+ "time"
+)
+
+// Email is an email.
+type Email struct {
+ To []string // The receivers of one email.
+ Subject string // The subject of one email.
+ BodyType string // The content type of body.
+ Body string // The body of one email.
+}
+
+// SendEmailOptions is the options of sending one email.
+type SendEmailOptions struct {
+ Async bool // The mode of sending one email.
+ Timeout time.Duration // The timeout of sending one email.
+}
+
+// SmtpService is the service of smtp.
+type SmtpService interface {
+ // SendEmail sends email with options and returns an error if something wrong happens.
+ SendEmail(ctx context.Context, email *Email, options *SendEmailOptions) error
+}
diff --git a/internal/postard/service/smtp.go b/internal/postard/service/smtp.go
index 273d09d..b87d20a 100644
--- a/internal/postard/service/smtp.go
+++ b/internal/postard/service/smtp.go
@@ -7,3 +7,67 @@
// Created at 2021/09/16 02:05:37
package service
+
+import (
+ "context"
+ "time"
+
+ "github.com/avino-plan/postar/pkg/concurrency"
+ "gopkg.in/gomail.v2"
+)
+
+// smtpService is the service of smtp.
+type smtpService struct {
+ host string // The host of smtp server.
+ port int // The port of smtp server.
+ user string // The user of smtp server.
+ password string // The password of smtp server.
+ pool *concurrency.Pool // The pool of workers.
+}
+
+// NewSmtpService returns a new SmtpServer.
+func NewSmtpService(host string, port int, user string, password string, pool *concurrency.Pool) SmtpService {
+ return &smtpService{
+ host: host,
+ port: port,
+ user: user,
+ password: password,
+ pool: pool,
+ }
+}
+
+// sendEmail sends email and returns an error if something wrong happens.
+func (ss *smtpService) sendEmail(email *Email) error {
+ msg := gomail.NewMessage()
+ msg.SetHeader("From", ss.user)
+ msg.SetHeader("To", email.To...)
+ msg.SetHeader("Subject", email.Subject)
+ msg.SetBody(email.BodyType, email.Body)
+ return gomail.NewDialer(ss.host, ss.port, ss.user, ss.password).DialAndSend(msg)
+}
+
+// SendEmail send
+func (ss *smtpService) SendEmail(ctx context.Context, email *Email, options *SendEmailOptions) error {
+
+ done := make(chan error, 1)
+ err := ss.pool.Go(ctx, func(ctx context.Context) {
+ done <- ss.sendEmail(email)
+ })
+ if err != nil && concurrency.IsEnqueueTimeout(err) {
+ // TODO wraps err
+ return err
+ }
+
+ if options.Async {
+ return nil
+ }
+
+ timer := time.NewTimer(options.Timeout)
+ select {
+ case err = <-done:
+ return err
+ case <-timer.C:
+ // TODO timeout error
+ return nil
+ }
+}
diff --git a/pkg/concurrency/error.go b/pkg/concurrency/error.go
new file mode 100644
index 0000000..5282efd
--- /dev/null
+++ b/pkg/concurrency/error.go
@@ -0,0 +1,20 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/17 01:35:47
+
+package concurrency
+
+import "errors"
+
+var (
+ ErrEnqueueTimeout = errors.New("pool: enqueue a task to pool timeout") // An error: enqueue a task to pool timeout.
+)
+
+// IsEnqueueTimeout returns if the err is ErrEnqueueTimeout.
+func IsEnqueueTimeout(err error) bool {
+ return err == ErrEnqueueTimeout
+}
diff --git a/pkg/concurrency/error_test.go b/pkg/concurrency/error_test.go
new file mode 100644
index 0000000..28ea0d6
--- /dev/null
+++ b/pkg/concurrency/error_test.go
@@ -0,0 +1,25 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/17 01:36:24
+
+package concurrency
+
+import "testing"
+
+// go test -v -cover -run=^TestIsEnqueueTimeout$
+func TestIsEnqueueTimeout(t *testing.T) {
+
+ err := ErrEnqueueTimeout
+ if !IsEnqueueTimeout(err) {
+ t.Error("err should be ErrEnqueueTimeout")
+ }
+
+ err = nil
+ if IsEnqueueTimeout(err) {
+ t.Error("err should not be ErrEnqueueTimeout")
+ }
+}
diff --git a/pkg/concurrency/pool.go b/pkg/concurrency/pool.go
new file mode 100644
index 0000000..c978af3
--- /dev/null
+++ b/pkg/concurrency/pool.go
@@ -0,0 +1,137 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/16 22:05:23
+
+package concurrency
+
+import (
+ "context"
+ "sync"
+ "sync/atomic"
+)
+
+// PoolOptions is the options of Pool.
+type PoolOptions func(pool *Pool)
+
+// WithMaxWorkers sets maxWorkers of pool.
+func WithMaxWorkers(maxWorkers int) PoolOptions {
+ return func(pool *Pool) {
+ pool.maxWorkers = maxWorkers
+ pool.taskQueues = make([]chan func(), maxWorkers)
+ }
+}
+
+// WithMaxWorkerTasks sets maxWorkerTasks of pool.
+func WithMaxWorkerTasks(maxWorkerTasks int) PoolOptions {
+ return func(pool *Pool) {
+ pool.maxWorkerTasks = maxWorkerTasks
+ }
+}
+
+// Pool is a set of goroutines.
+// This is for controlling the number of goroutines and managing their lifecycles.
+type Pool struct {
+ // maxWorkers is the max number of workers.
+ maxWorkers int
+
+ // maxWorkerTasks is the max number of one task queue.
+ // The Go() method will block until the task queue has enough capacity.
+ maxWorkerTasks int
+
+ // currentQueue records the current sequence of task queues.
+ currentQueue int64
+
+ // taskQueues stores all task queues.
+ // Every worker has its own task queue.
+ taskQueues []chan func()
+
+ // onRecover is a function which will call in defer after finishing task.
+ onRecover func(cause interface{})
+
+ // wg is for managing all goroutines.
+ wg *sync.WaitGroup
+}
+
+// NewPool returns a new Pool holder.
+func NewPool(options ...PoolOptions) *Pool {
+ pool := &Pool{
+ maxWorkers: 64,
+ maxWorkerTasks: 1024,
+ taskQueues: make([]chan func(), 64),
+ currentQueue: -1,
+ wg: &sync.WaitGroup{},
+ }
+
+ for _, option := range options {
+ option(pool)
+ }
+ return pool
+}
+
+// OnRecover sets onRecover to p.
+func (p *Pool) OnRecover(onRecover func(cause interface{})) {
+ p.onRecover = onRecover
+}
+
+// Start starts all workers in pool and starts receiving tasks.
+func (p *Pool) Start() *Pool {
+ for i := 0; i < p.maxWorkers; i++ {
+ taskQueue := make(chan func(), p.maxWorkerTasks)
+ p.taskQueues[i] = taskQueue
+
+ p.wg.Add(1)
+ go func() {
+ defer p.wg.Done()
+
+ for task := range taskQueue {
+ task()
+ }
+ }()
+ }
+ return p
+}
+
+// nextTaskQueue returns next task queue.
+func (p *Pool) nextTaskQueue() chan<- func() {
+ currentQueue := atomic.AddInt64(&p.currentQueue, 1)
+ if currentQueue >= int64(p.maxWorkers)-1 {
+ atomic.StoreInt64(&p.currentQueue, -1)
+ }
+ return p.taskQueues[currentQueue]
+}
+
+// wrapTask wraps task to a complete task of pool.
+func (p *Pool) wrapTask(ctx context.Context, task func(ctx context.Context)) func() {
+ return func() {
+ defer func() {
+ if cause := recover(); p.onRecover != nil {
+ p.onRecover(cause) // Notice: Just do some simple records which don't panic...
+ }
+ }()
+ task(ctx)
+ }
+}
+
+// Go sends the task to task queue and waits for executing.
+func (p *Pool) Go(ctx context.Context, task func(ctx context.Context)) error {
+ taskQueue := p.nextTaskQueue()
+ select {
+ case taskQueue <- p.wrapTask(ctx, task):
+ return nil
+ case <-ctx.Done():
+ // TODO wraps ctx.Err()
+ return ErrEnqueueTimeout
+ }
+}
+
+// Stop closes all task queues and waits for all workers to be shutdown.
+func (p *Pool) Stop() {
+ for _, taskQueue := range p.taskQueues {
+ close(taskQueue)
+ }
+ p.wg.Wait()
+}
diff --git a/pkg/concurrency/pool_test.go b/pkg/concurrency/pool_test.go
new file mode 100644
index 0000000..8017c6a
--- /dev/null
+++ b/pkg/concurrency/pool_test.go
@@ -0,0 +1,39 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/16 23:07:51
+
+package concurrency
+
+import (
+ "context"
+ "testing"
+ "time"
+)
+
+// go test -v -cover -run=^TestNewPool$
+func TestNewPool(t *testing.T) {
+
+ ctx := context.Background()
+ pool := NewPool(WithMaxWorkers(4), WithMaxWorkerTasks(16)).Start()
+
+ numbers := [1000]int{}
+ for i := 0; i < 1000; i++ {
+ no := i
+ pool.Go(ctx, func(ctx context.Context) {
+ numbers[no] = no
+ })
+ }
+
+ time.Sleep(time.Second)
+ pool.Stop()
+
+ for i, num := range numbers {
+ if i != num {
+ t.Errorf("i %d != num %d", i, num)
+ }
+ }
+}
From 10f1b0f168181afa1c66e03b082ee258326b4858 Mon Sep 17 00:00:00 2001
From: FishGoddess <1149062639@qq.com>
Date: Wed, 22 Sep 2021 01:08:21 +0800
Subject: [PATCH 04/27] =?UTF-8?q?=E4=B8=9A=E5=8A=A1=E5=B1=82=E9=87=8D?=
=?UTF-8?q?=E6=9E=84=E5=AE=8C=E6=88=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
go.mod | 1 +
go.sum | 2 +
{pkg => internal/pkg}/concurrency/pool.go | 17 ++++---
.../pkg}/concurrency/pool_test.go | 7 ++-
internal/postard/service/service.go | 8 +++
.../service/{error.go => service_test.go} | 9 +++-
internal/postard/service/smtp.go | 36 +++++++-------
internal/postard/service/smtp_test.go | 49 +++++++++++++++++++
pkg/concurrency/error.go | 20 --------
pkg/concurrency/error_test.go | 25 ----------
10 files changed, 100 insertions(+), 74 deletions(-)
rename {pkg => internal/pkg}/concurrency/pool.go (89%)
rename {pkg => internal/pkg}/concurrency/pool_test.go (84%)
rename internal/postard/service/{error.go => service_test.go} (59%)
create mode 100644 internal/postard/service/smtp_test.go
delete mode 100644 pkg/concurrency/error.go
delete mode 100644 pkg/concurrency/error_test.go
diff --git a/go.mod b/go.mod
index e6fbedb..cce3e64 100644
--- a/go.mod
+++ b/go.mod
@@ -5,6 +5,7 @@ go 1.15
require (
github.com/FishGoddess/logit v0.4.4-alpha
github.com/go-ini/ini v1.62.0
+ github.com/pkg/errors v0.9.1
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
)
diff --git a/go.sum b/go.sum
index a919aff..1c63154 100644
--- a/go.sum
+++ b/go.sum
@@ -4,6 +4,8 @@ github.com/FishGoddess/logit v0.4.4-alpha h1:eKe9XUslcU0QPVVhm+29N3OCnyXeii16Q5b
github.com/FishGoddess/logit v0.4.4-alpha/go.mod h1:a2dFSibwfZXNNZ/V1jMOQBImPoySaxdPFThbsm17ZdY=
github.com/go-ini/ini v1.62.0 h1:7VJT/ZXjzqSrvtraFp4ONq80hTcRQth1c9ZnQ3uNQvU=
github.com/go-ini/ini v1.62.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
diff --git a/pkg/concurrency/pool.go b/internal/pkg/concurrency/pool.go
similarity index 89%
rename from pkg/concurrency/pool.go
rename to internal/pkg/concurrency/pool.go
index c978af3..7603f22 100644
--- a/pkg/concurrency/pool.go
+++ b/internal/pkg/concurrency/pool.go
@@ -105,27 +105,30 @@ func (p *Pool) nextTaskQueue() chan<- func() {
}
// wrapTask wraps task to a complete task of pool.
-func (p *Pool) wrapTask(ctx context.Context, task func(ctx context.Context)) func() {
+func (p *Pool) wrapTask(ctx context.Context, fn func(ctx context.Context) error, errorCh chan<- error) func() {
return func() {
+ var err error
defer func() {
+ errorCh <- err
if cause := recover(); p.onRecover != nil {
p.onRecover(cause) // Notice: Just do some simple records which don't panic...
}
}()
- task(ctx)
+ err = fn(ctx)
}
}
// Go sends the task to task queue and waits for executing.
-func (p *Pool) Go(ctx context.Context, task func(ctx context.Context)) error {
+func (p *Pool) Go(ctx context.Context, fn func(ctx context.Context) error) <-chan error {
+ errorCh := make(chan error, 1)
+
taskQueue := p.nextTaskQueue()
select {
- case taskQueue <- p.wrapTask(ctx, task):
- return nil
+ case taskQueue <- p.wrapTask(ctx, fn, errorCh):
case <-ctx.Done():
- // TODO wraps ctx.Err()
- return ErrEnqueueTimeout
+ errorCh <- ctx.Err()
}
+ return errorCh
}
// Stop closes all task queues and waits for all workers to be shutdown.
diff --git a/pkg/concurrency/pool_test.go b/internal/pkg/concurrency/pool_test.go
similarity index 84%
rename from pkg/concurrency/pool_test.go
rename to internal/pkg/concurrency/pool_test.go
index 8017c6a..4e51c5a 100644
--- a/pkg/concurrency/pool_test.go
+++ b/internal/pkg/concurrency/pool_test.go
@@ -16,16 +16,19 @@ import (
// go test -v -cover -run=^TestNewPool$
func TestNewPool(t *testing.T) {
-
ctx := context.Background()
pool := NewPool(WithMaxWorkers(4), WithMaxWorkerTasks(16)).Start()
numbers := [1000]int{}
for i := 0; i < 1000; i++ {
no := i
- pool.Go(ctx, func(ctx context.Context) {
+ errorCh := pool.Go(ctx, func(ctx context.Context) error {
numbers[no] = no
+ return nil
})
+ if err := <-errorCh; err != nil {
+ t.Error(err)
+ }
}
time.Sleep(time.Second)
diff --git a/internal/postard/service/service.go b/internal/postard/service/service.go
index 7fbb706..d564c87 100644
--- a/internal/postard/service/service.go
+++ b/internal/postard/service/service.go
@@ -27,6 +27,14 @@ type SendEmailOptions struct {
Timeout time.Duration // The timeout of sending one email.
}
+// DefaultSendEmailOptions returns a default options for sending emails.
+func DefaultSendEmailOptions() *SendEmailOptions {
+ return &SendEmailOptions{
+ Async: false,
+ Timeout: 5 * time.Second,
+ }
+}
+
// SmtpService is the service of smtp.
type SmtpService interface {
// SendEmail sends email with options and returns an error if something wrong happens.
diff --git a/internal/postard/service/error.go b/internal/postard/service/service_test.go
similarity index 59%
rename from internal/postard/service/error.go
rename to internal/postard/service/service_test.go
index 8421697..c87815e 100644
--- a/internal/postard/service/error.go
+++ b/internal/postard/service/service_test.go
@@ -4,6 +4,13 @@
//
// Author: FishGoddess
// Email: fishgoddess@qq.com
-// Created at 2021/09/17 01:38:30
+// Created at 2021/09/22 00:22:39
package service
+
+import "testing"
+
+// go test -v -cover -run=^TestSmtpService$
+func TestSmtpService(t *testing.T) {
+ // do nothing...
+}
diff --git a/internal/postard/service/smtp.go b/internal/postard/service/smtp.go
index b87d20a..a553641 100644
--- a/internal/postard/service/smtp.go
+++ b/internal/postard/service/smtp.go
@@ -12,12 +12,13 @@ import (
"context"
"time"
- "github.com/avino-plan/postar/pkg/concurrency"
+ "github.com/avino-plan/postar/internal/pkg/concurrency"
+ "github.com/pkg/errors"
"gopkg.in/gomail.v2"
)
-// smtpService is the service of smtp.
-type smtpService struct {
+// SmtpServiceImpl is the service of smtp.
+type SmtpServiceImpl struct {
host string // The host of smtp server.
port int // The port of smtp server.
user string // The user of smtp server.
@@ -27,7 +28,7 @@ type smtpService struct {
// NewSmtpService returns a new SmtpServer.
func NewSmtpService(host string, port int, user string, password string, pool *concurrency.Pool) SmtpService {
- return &smtpService{
+ return &SmtpServiceImpl{
host: host,
port: port,
user: user,
@@ -37,7 +38,7 @@ func NewSmtpService(host string, port int, user string, password string, pool *c
}
// sendEmail sends email and returns an error if something wrong happens.
-func (ss *smtpService) sendEmail(email *Email) error {
+func (ss *SmtpServiceImpl) sendEmail(email *Email) error {
msg := gomail.NewMessage()
msg.SetHeader("From", ss.user)
msg.SetHeader("To", email.To...)
@@ -46,28 +47,25 @@ func (ss *smtpService) sendEmail(email *Email) error {
return gomail.NewDialer(ss.host, ss.port, ss.user, ss.password).DialAndSend(msg)
}
-// SendEmail send
-func (ss *smtpService) SendEmail(ctx context.Context, email *Email, options *SendEmailOptions) error {
-
- done := make(chan error, 1)
- err := ss.pool.Go(ctx, func(ctx context.Context) {
- done <- ss.sendEmail(email)
- })
- if err != nil && concurrency.IsEnqueueTimeout(err) {
- // TODO wraps err
- return err
+// SendEmail sends email to somewhere.
+func (ss *SmtpServiceImpl) SendEmail(ctx context.Context, email *Email, options *SendEmailOptions) error {
+ if options == nil {
+ options = DefaultSendEmailOptions()
}
+ errorCh := ss.pool.Go(ctx, func(ctx context.Context) error {
+ return ss.sendEmail(email)
+ })
if options.Async {
return nil
}
timer := time.NewTimer(options.Timeout)
select {
- case err = <-done:
- return err
+ case err := <-errorCh:
+ timer.Stop()
+ return errors.Wrap(err, "send email failed")
case <-timer.C:
- // TODO timeout error
- return nil
+ return errors.New("send email timeout")
}
}
diff --git a/internal/postard/service/smtp_test.go b/internal/postard/service/smtp_test.go
new file mode 100644
index 0000000..16c5b6f
--- /dev/null
+++ b/internal/postard/service/smtp_test.go
@@ -0,0 +1,49 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/22 00:24:19
+
+package service
+
+import (
+ "context"
+ "os"
+ "strconv"
+ "testing"
+ "time"
+
+ "github.com/avino-plan/postar/internal/pkg/concurrency"
+)
+
+// go test -v -cover -run=^TestNewSmtpService$
+func TestNewSmtpService(t *testing.T) {
+ host := os.Getenv("POSTAR_SMTP_HOST")
+ user := os.Getenv("POSTAR_SMTP_USER")
+ password := os.Getenv("POSTAR_SMTP_PASSWORD")
+ to := os.Getenv("POSTAR_SMTP_TO")
+ if host == "" || user == "" || password == "" || to == "" {
+ t.Skipf("smtp host %s or user %s or password %s or to %s is empty", host, user, password, to)
+ }
+
+ port, err := strconv.ParseInt(os.Getenv("POSTAR_SMTP_PORT"), 10, 64)
+ if err != nil {
+ port = 587
+ }
+
+ pool := concurrency.NewPool().Start()
+ defer pool.Stop()
+
+ smtpService := NewSmtpService(host, int(port), user, password, pool)
+ err = smtpService.SendEmail(context.Background(), &Email{
+ To: []string{to},
+ Subject: t.Name(),
+ BodyType: "text/html;charset=utf-8",
+ Body: t.Name() + time.Now().Format("20060102150405.000"),
+ }, DefaultSendEmailOptions())
+ if err != nil {
+ t.Error(err)
+ }
+}
diff --git a/pkg/concurrency/error.go b/pkg/concurrency/error.go
deleted file mode 100644
index 5282efd..0000000
--- a/pkg/concurrency/error.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/09/17 01:35:47
-
-package concurrency
-
-import "errors"
-
-var (
- ErrEnqueueTimeout = errors.New("pool: enqueue a task to pool timeout") // An error: enqueue a task to pool timeout.
-)
-
-// IsEnqueueTimeout returns if the err is ErrEnqueueTimeout.
-func IsEnqueueTimeout(err error) bool {
- return err == ErrEnqueueTimeout
-}
diff --git a/pkg/concurrency/error_test.go b/pkg/concurrency/error_test.go
deleted file mode 100644
index 28ea0d6..0000000
--- a/pkg/concurrency/error_test.go
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/09/17 01:36:24
-
-package concurrency
-
-import "testing"
-
-// go test -v -cover -run=^TestIsEnqueueTimeout$
-func TestIsEnqueueTimeout(t *testing.T) {
-
- err := ErrEnqueueTimeout
- if !IsEnqueueTimeout(err) {
- t.Error("err should be ErrEnqueueTimeout")
- }
-
- err = nil
- if IsEnqueueTimeout(err) {
- t.Error("err should not be ErrEnqueueTimeout")
- }
-}
From de2e0c0870418e9e46314da3036411e0144ffb4f Mon Sep 17 00:00:00 2001
From: FishGoddess <1149062639@qq.com>
Date: Wed, 22 Sep 2021 01:48:26 +0800
Subject: [PATCH 05/27] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20proto=20=E5=8D=8F?=
=?UTF-8?q?=E8=AE=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
api/pkg/status.pb.go | 161 ++++++++++++
api/pkg/status.proto | 17 ++
api/postard/postard.pb.go | 407 ++++++++++++++++++++++++++++++
api/postard/postard.proto | 37 ++-
api/postard/postard_grpc.pb.go | 101 ++++++++
go.mod | 4 +-
go.sum | 122 ++++++++-
internal/postard/server/server.go | 9 -
8 files changed, 840 insertions(+), 18 deletions(-)
create mode 100644 api/pkg/status.pb.go
create mode 100644 api/pkg/status.proto
create mode 100644 api/postard/postard.pb.go
create mode 100644 api/postard/postard_grpc.pb.go
diff --git a/api/pkg/status.pb.go b/api/pkg/status.pb.go
new file mode 100644
index 0000000..34f194e
--- /dev/null
+++ b/api/pkg/status.pb.go
@@ -0,0 +1,161 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/22 01:18:01
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.27.1
+// protoc v3.18.0
+// source: status.proto
+
+package pkg
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// Status is the status of responses.
+type Status struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Code int64 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` // Globally unique.
+ Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` // The description of responses.
+}
+
+func (x *Status) Reset() {
+ *x = Status{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_status_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Status) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Status) ProtoMessage() {}
+
+func (x *Status) ProtoReflect() protoreflect.Message {
+ mi := &file_status_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Status.ProtoReflect.Descriptor instead.
+func (*Status) Descriptor() ([]byte, []int) {
+ return file_status_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Status) GetCode() int64 {
+ if x != nil {
+ return x.Code
+ }
+ return 0
+}
+
+func (x *Status) GetMsg() string {
+ if x != nil {
+ return x.Msg
+ }
+ return ""
+}
+
+var File_status_proto protoreflect.FileDescriptor
+
+var file_status_proto_rawDesc = []byte{
+ 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03,
+ 0x70, 0x6b, 0x67, 0x22, 0x2e, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a,
+ 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x63, 0x6f, 0x64,
+ 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
+ 0x6d, 0x73, 0x67, 0x42, 0x26, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x2f, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x2d, 0x70, 0x6c, 0x61, 0x6e, 0x2f, 0x70, 0x6f, 0x73,
+ 0x74, 0x61, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6b, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_status_proto_rawDescOnce sync.Once
+ file_status_proto_rawDescData = file_status_proto_rawDesc
+)
+
+func file_status_proto_rawDescGZIP() []byte {
+ file_status_proto_rawDescOnce.Do(func() {
+ file_status_proto_rawDescData = protoimpl.X.CompressGZIP(file_status_proto_rawDescData)
+ })
+ return file_status_proto_rawDescData
+}
+
+var file_status_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_status_proto_goTypes = []interface{}{
+ (*Status)(nil), // 0: pkg.Status
+}
+var file_status_proto_depIdxs = []int32{
+ 0, // [0:0] is the sub-list for method output_type
+ 0, // [0:0] is the sub-list for method input_type
+ 0, // [0:0] is the sub-list for extension type_name
+ 0, // [0:0] is the sub-list for extension extendee
+ 0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_status_proto_init() }
+func file_status_proto_init() {
+ if File_status_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_status_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Status); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_status_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 1,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_status_proto_goTypes,
+ DependencyIndexes: file_status_proto_depIdxs,
+ MessageInfos: file_status_proto_msgTypes,
+ }.Build()
+ File_status_proto = out.File
+ file_status_proto_rawDesc = nil
+ file_status_proto_goTypes = nil
+ file_status_proto_depIdxs = nil
+}
diff --git a/api/pkg/status.proto b/api/pkg/status.proto
new file mode 100644
index 0000000..4c03e09
--- /dev/null
+++ b/api/pkg/status.proto
@@ -0,0 +1,17 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/22 01:18:01
+syntax = "proto3";
+package pkg;
+
+option go_package = "github.com/avino-plan/postar/api/pkg";
+
+// Status is the status of responses.
+message Status {
+ int64 code = 1; // Globally unique.
+ string msg = 2; // The description of responses.
+}
\ No newline at end of file
diff --git a/api/postard/postard.pb.go b/api/postard/postard.pb.go
new file mode 100644
index 0000000..55339c0
--- /dev/null
+++ b/api/postard/postard.pb.go
@@ -0,0 +1,407 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/16 01:42:33
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.27.1
+// protoc v3.18.0
+// source: postard.proto
+
+package postard
+
+import (
+ pkg "github.com/avino-plan/postar/api/pkg"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// Email wraps all information of using smtp service.
+type Email struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ To []string `protobuf:"bytes,1,rep,name=to,proto3" json:"to,omitempty"` // The receivers of one email.
+ Subject string `protobuf:"bytes,2,opt,name=subject,proto3" json:"subject,omitempty"` // The subject of one email.
+ BodyType string `protobuf:"bytes,3,opt,name=BodyType,proto3" json:"BodyType,omitempty"` // The content type of body.
+ Body string `protobuf:"bytes,4,opt,name=Body,proto3" json:"Body,omitempty"` // The body of one email.
+}
+
+func (x *Email) Reset() {
+ *x = Email{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_postard_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Email) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Email) ProtoMessage() {}
+
+func (x *Email) ProtoReflect() protoreflect.Message {
+ mi := &file_postard_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Email.ProtoReflect.Descriptor instead.
+func (*Email) Descriptor() ([]byte, []int) {
+ return file_postard_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Email) GetTo() []string {
+ if x != nil {
+ return x.To
+ }
+ return nil
+}
+
+func (x *Email) GetSubject() string {
+ if x != nil {
+ return x.Subject
+ }
+ return ""
+}
+
+func (x *Email) GetBodyType() string {
+ if x != nil {
+ return x.BodyType
+ }
+ return ""
+}
+
+func (x *Email) GetBody() string {
+ if x != nil {
+ return x.Body
+ }
+ return ""
+}
+
+// SendEmailOptions is the options of sending emails.
+type SendEmailOptions struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Async bool `protobuf:"varint,1,opt,name=async,proto3" json:"async,omitempty"` // If need sending emails asynchronously.
+ Timeout int64 `protobuf:"varint,2,opt,name=timeout,proto3" json:"timeout,omitempty"` // Sending timeout.
+}
+
+func (x *SendEmailOptions) Reset() {
+ *x = SendEmailOptions{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_postard_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SendEmailOptions) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SendEmailOptions) ProtoMessage() {}
+
+func (x *SendEmailOptions) ProtoReflect() protoreflect.Message {
+ mi := &file_postard_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SendEmailOptions.ProtoReflect.Descriptor instead.
+func (*SendEmailOptions) Descriptor() ([]byte, []int) {
+ return file_postard_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *SendEmailOptions) GetAsync() bool {
+ if x != nil {
+ return x.Async
+ }
+ return false
+}
+
+func (x *SendEmailOptions) GetTimeout() int64 {
+ if x != nil {
+ return x.Timeout
+ }
+ return 0
+}
+
+// SendEmailRequest is the request of SendEmail.
+type SendEmailRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Email *Email `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` // Sending email.
+ Options *SendEmailOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` // Sending options.
+}
+
+func (x *SendEmailRequest) Reset() {
+ *x = SendEmailRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_postard_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SendEmailRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SendEmailRequest) ProtoMessage() {}
+
+func (x *SendEmailRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_postard_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SendEmailRequest.ProtoReflect.Descriptor instead.
+func (*SendEmailRequest) Descriptor() ([]byte, []int) {
+ return file_postard_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *SendEmailRequest) GetEmail() *Email {
+ if x != nil {
+ return x.Email
+ }
+ return nil
+}
+
+func (x *SendEmailRequest) GetOptions() *SendEmailOptions {
+ if x != nil {
+ return x.Options
+ }
+ return nil
+}
+
+// SendEmailResponse is the response of SendEmail.
+type SendEmailResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Status *pkg.Status `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` // The status of response.
+}
+
+func (x *SendEmailResponse) Reset() {
+ *x = SendEmailResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_postard_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SendEmailResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SendEmailResponse) ProtoMessage() {}
+
+func (x *SendEmailResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_postard_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SendEmailResponse.ProtoReflect.Descriptor instead.
+func (*SendEmailResponse) Descriptor() ([]byte, []int) {
+ return file_postard_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *SendEmailResponse) GetStatus() *pkg.Status {
+ if x != nil {
+ return x.Status
+ }
+ return nil
+}
+
+var File_postard_proto protoreflect.FileDescriptor
+
+var file_postard_proto_rawDesc = []byte{
+ 0x0a, 0x0d, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
+ 0x07, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x1a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x61, 0x0a, 0x05, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12,
+ 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x12,
+ 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x6f, 0x64,
+ 0x79, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x42, 0x6f, 0x64,
+ 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x04, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x42, 0x0a, 0x10, 0x53, 0x65, 0x6e,
+ 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a,
+ 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x73,
+ 0x79, 0x6e, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0x6d, 0x0a,
+ 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x12, 0x24, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x61, 0x69, 0x6c,
+ 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x33, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f,
+ 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61,
+ 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x4f, 0x70, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x38, 0x0a, 0x11,
+ 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x12, 0x23, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x6b, 0x67, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06,
+ 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, 0x4d, 0x0a, 0x07, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x72,
+ 0x64, 0x12, 0x42, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x19,
+ 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61,
+ 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x6f, 0x73, 0x74,
+ 0x61, 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x2d, 0x70, 0x6c, 0x61, 0x6e, 0x2f, 0x70,
+ 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72,
+ 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_postard_proto_rawDescOnce sync.Once
+ file_postard_proto_rawDescData = file_postard_proto_rawDesc
+)
+
+func file_postard_proto_rawDescGZIP() []byte {
+ file_postard_proto_rawDescOnce.Do(func() {
+ file_postard_proto_rawDescData = protoimpl.X.CompressGZIP(file_postard_proto_rawDescData)
+ })
+ return file_postard_proto_rawDescData
+}
+
+var file_postard_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
+var file_postard_proto_goTypes = []interface{}{
+ (*Email)(nil), // 0: postard.Email
+ (*SendEmailOptions)(nil), // 1: postard.SendEmailOptions
+ (*SendEmailRequest)(nil), // 2: postard.SendEmailRequest
+ (*SendEmailResponse)(nil), // 3: postard.SendEmailResponse
+ (*pkg.Status)(nil), // 4: pkg.Status
+}
+var file_postard_proto_depIdxs = []int32{
+ 0, // 0: postard.SendEmailRequest.email:type_name -> postard.Email
+ 1, // 1: postard.SendEmailRequest.options:type_name -> postard.SendEmailOptions
+ 4, // 2: postard.SendEmailResponse.status:type_name -> pkg.Status
+ 2, // 3: postard.Postard.SendEmail:input_type -> postard.SendEmailRequest
+ 3, // 4: postard.Postard.SendEmail:output_type -> postard.SendEmailResponse
+ 4, // [4:5] is the sub-list for method output_type
+ 3, // [3:4] is the sub-list for method input_type
+ 3, // [3:3] is the sub-list for extension type_name
+ 3, // [3:3] is the sub-list for extension extendee
+ 0, // [0:3] is the sub-list for field type_name
+}
+
+func init() { file_postard_proto_init() }
+func file_postard_proto_init() {
+ if File_postard_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_postard_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Email); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_postard_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SendEmailOptions); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_postard_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SendEmailRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_postard_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SendEmailResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_postard_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 4,
+ NumExtensions: 0,
+ NumServices: 1,
+ },
+ GoTypes: file_postard_proto_goTypes,
+ DependencyIndexes: file_postard_proto_depIdxs,
+ MessageInfos: file_postard_proto_msgTypes,
+ }.Build()
+ File_postard_proto = out.File
+ file_postard_proto_rawDesc = nil
+ file_postard_proto_goTypes = nil
+ file_postard_proto_depIdxs = nil
+}
diff --git a/api/postard/postard.proto b/api/postard/postard.proto
index d04834e..f54a976 100644
--- a/api/postard/postard.proto
+++ b/api/postard/postard.proto
@@ -5,4 +5,39 @@
// Author: FishGoddess
// Email: fishgoddess@qq.com
// Created at 2021/09/16 01:42:33
-syntax = "proto3";
\ No newline at end of file
+syntax = "proto3";
+package postard;
+import "status.proto";
+
+// protoc --proto_path=../pkg --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative postard.proto
+option go_package = "github.com/avino-plan/postar/api/postard";
+
+// Email wraps all information of using smtp service.
+message Email {
+ repeated string to = 1; // The receivers of one email.
+ string subject = 2; // The subject of one email.
+ string BodyType = 3; // The content type of body.
+ string Body = 4; // The body of one email.
+}
+
+// SendEmailOptions is the options of sending emails.
+message SendEmailOptions {
+ bool async = 1; // If need sending emails asynchronously.
+ int64 timeout = 2; // Sending timeout.
+}
+
+// SendEmailRequest is the request of SendEmail.
+message SendEmailRequest {
+ Email email = 1; // Sending email.
+ SendEmailOptions options = 2; // Sending options.
+}
+
+// SendEmailResponse is the response of SendEmail.
+message SendEmailResponse {
+ pkg.Status status = 1; // The status of response.
+}
+
+// Postard is the core service of postar.
+service Postard {
+ rpc SendEmail(SendEmailRequest) returns (SendEmailResponse); // For sending emails.
+}
\ No newline at end of file
diff --git a/api/postard/postard_grpc.pb.go b/api/postard/postard_grpc.pb.go
new file mode 100644
index 0000000..8e2b601
--- /dev/null
+++ b/api/postard/postard_grpc.pb.go
@@ -0,0 +1,101 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+
+package postard
+
+import (
+ context "context"
+ grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// PostardClient is the client API for Postard service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type PostardClient interface {
+ SendEmail(ctx context.Context, in *SendEmailRequest, opts ...grpc.CallOption) (*SendEmailResponse, error)
+}
+
+type postardClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewPostardClient(cc grpc.ClientConnInterface) PostardClient {
+ return &postardClient{cc}
+}
+
+func (c *postardClient) SendEmail(ctx context.Context, in *SendEmailRequest, opts ...grpc.CallOption) (*SendEmailResponse, error) {
+ out := new(SendEmailResponse)
+ err := c.cc.Invoke(ctx, "/postard.Postard/SendEmail", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// PostardServer is the server API for Postard service.
+// All implementations must embed UnimplementedPostardServer
+// for forward compatibility
+type PostardServer interface {
+ SendEmail(context.Context, *SendEmailRequest) (*SendEmailResponse, error)
+ mustEmbedUnimplementedPostardServer()
+}
+
+// UnimplementedPostardServer must be embedded to have forward compatible implementations.
+type UnimplementedPostardServer struct {
+}
+
+func (UnimplementedPostardServer) SendEmail(context.Context, *SendEmailRequest) (*SendEmailResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method SendEmail not implemented")
+}
+func (UnimplementedPostardServer) mustEmbedUnimplementedPostardServer() {}
+
+// UnsafePostardServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to PostardServer will
+// result in compilation errors.
+type UnsafePostardServer interface {
+ mustEmbedUnimplementedPostardServer()
+}
+
+func RegisterPostardServer(s grpc.ServiceRegistrar, srv PostardServer) {
+ s.RegisterService(&Postard_ServiceDesc, srv)
+}
+
+func _Postard_SendEmail_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(SendEmailRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(PostardServer).SendEmail(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/postard.Postard/SendEmail",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(PostardServer).SendEmail(ctx, req.(*SendEmailRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// Postard_ServiceDesc is the grpc.ServiceDesc for Postard service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var Postard_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "postard.Postard",
+ HandlerType: (*PostardServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "SendEmail",
+ Handler: _Postard_SendEmail_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "postard.proto",
+}
diff --git a/go.mod b/go.mod
index cce3e64..a8cb922 100644
--- a/go.mod
+++ b/go.mod
@@ -3,9 +3,9 @@ module github.com/avino-plan/postar
go 1.15
require (
- github.com/FishGoddess/logit v0.4.4-alpha
- github.com/go-ini/ini v1.62.0
github.com/pkg/errors v0.9.1
+ google.golang.org/grpc v1.40.0
+ google.golang.org/protobuf v1.27.1
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
)
diff --git a/go.sum b/go.sum
index 1c63154..4baad21 100644
--- a/go.sum
+++ b/go.sum
@@ -1,12 +1,122 @@
-github.com/FishGoddess/logit v0.3.3 h1:qnxPIvq8YXGwG9y59Sk0hjoArOzWukQQqIsPT3dh3Xw=
-github.com/FishGoddess/logit v0.3.3/go.mod h1:a2dFSibwfZXNNZ/V1jMOQBImPoySaxdPFThbsm17ZdY=
-github.com/FishGoddess/logit v0.4.4-alpha h1:eKe9XUslcU0QPVVhm+29N3OCnyXeii16Q5bYQ6OinSE=
-github.com/FishGoddess/logit v0.4.4-alpha/go.mod h1:a2dFSibwfZXNNZ/V1jMOQBImPoySaxdPFThbsm17ZdY=
-github.com/go-ini/ini v1.62.0 h1:7VJT/ZXjzqSrvtraFp4ONq80hTcRQth1c9ZnQ3uNQvU=
-github.com/go-ini/ini v1.62.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+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.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
+google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q=
+google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
+google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/internal/postard/server/server.go b/internal/postard/server/server.go
index 83f937a..bd90671 100644
--- a/internal/postard/server/server.go
+++ b/internal/postard/server/server.go
@@ -7,12 +7,3 @@
// Created at 2021/09/17 00:15:34
package server
-
-import "github.com/avino-plan/postar/internal/postard/service"
-
-func DefaultSendOptions() *service.SendEmailOptions {
- return &service.SendEmailOptions{
- Async: false,
- Timeout: 10000,
- }
-}
From cefc5b319abb991c3a565d1db53b287b71396557 Mon Sep 17 00:00:00 2001
From: FishGoddess <1149062639@qq.com>
Date: Fri, 24 Sep 2021 00:04:39 +0800
Subject: [PATCH 06/27] =?UTF-8?q?=E5=AE=8C=E5=96=84=E4=BB=A3=E7=A0=81?=
=?UTF-8?q?=E7=BB=93=E6=9E=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
api/pkg/status.pb.go | 6 ++-
api/pkg/status.proto | 3 +-
api/postard/postard.pb.go | 74 ++++++++++++++++-----------
api/postard/postard.proto | 4 +-
api/postard/postard_grpc.pb.go | 6 +--
internal/postard/server/server.go | 9 ----
internal/postard/service/smtp.go | 27 +++++-----
internal/postard/service/smtp_test.go | 2 +-
8 files changed, 68 insertions(+), 63 deletions(-)
delete mode 100644 internal/postard/server/server.go
diff --git a/api/pkg/status.pb.go b/api/pkg/status.pb.go
index 34f194e..9564874 100644
--- a/api/pkg/status.pb.go
+++ b/api/pkg/status.pb.go
@@ -87,7 +87,9 @@ func (x *Status) GetMsg() string {
var File_status_proto protoreflect.FileDescriptor
var file_status_proto_rawDesc = []byte{
- 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03,
+ 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x23,
+ 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f,
+ 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x70, 0x6b, 0x67, 0x22, 0x2e, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a,
0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x63, 0x6f, 0x64,
0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
@@ -111,7 +113,7 @@ func file_status_proto_rawDescGZIP() []byte {
var file_status_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_status_proto_goTypes = []interface{}{
- (*Status)(nil), // 0: pkg.Status
+ (*Status)(nil), // 0: github.com.avinoplan.postar.api.pkg.Status
}
var file_status_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
diff --git a/api/pkg/status.proto b/api/pkg/status.proto
index 4c03e09..479e805 100644
--- a/api/pkg/status.proto
+++ b/api/pkg/status.proto
@@ -6,8 +6,9 @@
// Email: fishgoddess@qq.com
// Created at 2021/09/22 01:18:01
syntax = "proto3";
-package pkg;
+package github.com.avinoplan.postar.api.pkg;
+// protoc -I=. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative status.proto
option go_package = "github.com/avino-plan/postar/api/pkg";
// Status is the status of responses.
diff --git a/api/postard/postard.pb.go b/api/postard/postard.pb.go
index 55339c0..45db3f5 100644
--- a/api/postard/postard.pb.go
+++ b/api/postard/postard.pb.go
@@ -265,7 +265,9 @@ var File_postard_proto protoreflect.FileDescriptor
var file_postard_proto_rawDesc = []byte{
0x0a, 0x0d, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
- 0x07, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x1a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
+ 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e,
+ 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69,
+ 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x1a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x61, 0x0a, 0x05, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12,
0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x12,
0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
@@ -276,26 +278,36 @@ var file_postard_proto_rawDesc = []byte{
0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a,
0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x73,
0x79, 0x6e, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02,
- 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0x6d, 0x0a,
- 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
- 0x74, 0x12, 0x24, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x61, 0x69, 0x6c,
- 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x33, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f,
- 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61,
- 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x4f, 0x70, 0x74, 0x69,
- 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x38, 0x0a, 0x11,
- 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
- 0x65, 0x12, 0x23, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x6b, 0x67, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06,
- 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, 0x4d, 0x0a, 0x07, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x72,
- 0x64, 0x12, 0x42, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x19,
- 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61,
- 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x6f, 0x73, 0x74,
- 0x61, 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73,
- 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
- 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x2d, 0x70, 0x6c, 0x61, 0x6e, 0x2f, 0x70,
- 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72,
- 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0xad, 0x01,
+ 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x12, 0x44, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x2e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
+ 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e,
+ 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x61, 0x69,
+ 0x6c, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x53, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x67, 0x69, 0x74, 0x68,
+ 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e,
+ 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f, 0x73, 0x74,
+ 0x61, 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x4f, 0x70, 0x74,
+ 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x58, 0x0a,
+ 0x11, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x12, 0x43, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e,
+ 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72,
+ 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6b, 0x67, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52,
+ 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, 0x8e, 0x01, 0x0a, 0x07, 0x50, 0x6f, 0x73, 0x74,
+ 0x61, 0x72, 0x64, 0x12, 0x82, 0x01, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69,
+ 0x6c, 0x12, 0x39, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
+ 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e,
+ 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64,
+ 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e, 0x67,
+ 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70,
+ 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70,
+ 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c,
+ 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68,
+ 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x2d, 0x70, 0x6c, 0x61,
+ 0x6e, 0x2f, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6f, 0x73,
+ 0x74, 0x61, 0x72, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -312,18 +324,18 @@ func file_postard_proto_rawDescGZIP() []byte {
var file_postard_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_postard_proto_goTypes = []interface{}{
- (*Email)(nil), // 0: postard.Email
- (*SendEmailOptions)(nil), // 1: postard.SendEmailOptions
- (*SendEmailRequest)(nil), // 2: postard.SendEmailRequest
- (*SendEmailResponse)(nil), // 3: postard.SendEmailResponse
- (*pkg.Status)(nil), // 4: pkg.Status
+ (*Email)(nil), // 0: github.com.avinoplan.postar.api.postard.Email
+ (*SendEmailOptions)(nil), // 1: github.com.avinoplan.postar.api.postard.SendEmailOptions
+ (*SendEmailRequest)(nil), // 2: github.com.avinoplan.postar.api.postard.SendEmailRequest
+ (*SendEmailResponse)(nil), // 3: github.com.avinoplan.postar.api.postard.SendEmailResponse
+ (*pkg.Status)(nil), // 4: github.com.avinoplan.postar.api.pkg.Status
}
var file_postard_proto_depIdxs = []int32{
- 0, // 0: postard.SendEmailRequest.email:type_name -> postard.Email
- 1, // 1: postard.SendEmailRequest.options:type_name -> postard.SendEmailOptions
- 4, // 2: postard.SendEmailResponse.status:type_name -> pkg.Status
- 2, // 3: postard.Postard.SendEmail:input_type -> postard.SendEmailRequest
- 3, // 4: postard.Postard.SendEmail:output_type -> postard.SendEmailResponse
+ 0, // 0: github.com.avinoplan.postar.api.postard.SendEmailRequest.email:type_name -> github.com.avinoplan.postar.api.postard.Email
+ 1, // 1: github.com.avinoplan.postar.api.postard.SendEmailRequest.options:type_name -> github.com.avinoplan.postar.api.postard.SendEmailOptions
+ 4, // 2: github.com.avinoplan.postar.api.postard.SendEmailResponse.status:type_name -> github.com.avinoplan.postar.api.pkg.Status
+ 2, // 3: github.com.avinoplan.postar.api.postard.Postard.SendEmail:input_type -> github.com.avinoplan.postar.api.postard.SendEmailRequest
+ 3, // 4: github.com.avinoplan.postar.api.postard.Postard.SendEmail:output_type -> github.com.avinoplan.postar.api.postard.SendEmailResponse
4, // [4:5] is the sub-list for method output_type
3, // [3:4] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
diff --git a/api/postard/postard.proto b/api/postard/postard.proto
index f54a976..87f3d86 100644
--- a/api/postard/postard.proto
+++ b/api/postard/postard.proto
@@ -6,10 +6,10 @@
// Email: fishgoddess@qq.com
// Created at 2021/09/16 01:42:33
syntax = "proto3";
-package postard;
+package github.com.avinoplan.postar.api.postard;
import "status.proto";
-// protoc --proto_path=../pkg --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative postard.proto
+// protoc -I=../pkg -I=. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative postard.proto
option go_package = "github.com/avino-plan/postar/api/postard";
// Email wraps all information of using smtp service.
diff --git a/api/postard/postard_grpc.pb.go b/api/postard/postard_grpc.pb.go
index 8e2b601..846c27b 100644
--- a/api/postard/postard_grpc.pb.go
+++ b/api/postard/postard_grpc.pb.go
@@ -31,7 +31,7 @@ func NewPostardClient(cc grpc.ClientConnInterface) PostardClient {
func (c *postardClient) SendEmail(ctx context.Context, in *SendEmailRequest, opts ...grpc.CallOption) (*SendEmailResponse, error) {
out := new(SendEmailResponse)
- err := c.cc.Invoke(ctx, "/postard.Postard/SendEmail", in, out, opts...)
+ err := c.cc.Invoke(ctx, "/github.com.avinoplan.postar.api.postard.Postard/SendEmail", in, out, opts...)
if err != nil {
return nil, err
}
@@ -76,7 +76,7 @@ func _Postard_SendEmail_Handler(srv interface{}, ctx context.Context, dec func(i
}
info := &grpc.UnaryServerInfo{
Server: srv,
- FullMethod: "/postard.Postard/SendEmail",
+ FullMethod: "/github.com.avinoplan.postar.api.postard.Postard/SendEmail",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(PostardServer).SendEmail(ctx, req.(*SendEmailRequest))
@@ -88,7 +88,7 @@ func _Postard_SendEmail_Handler(srv interface{}, ctx context.Context, dec func(i
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Postard_ServiceDesc = grpc.ServiceDesc{
- ServiceName: "postard.Postard",
+ ServiceName: "github.com.avinoplan.postar.api.postard.Postard",
HandlerType: (*PostardServer)(nil),
Methods: []grpc.MethodDesc{
{
diff --git a/internal/postard/server/server.go b/internal/postard/server/server.go
deleted file mode 100644
index bd90671..0000000
--- a/internal/postard/server/server.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/09/17 00:15:34
-
-package server
diff --git a/internal/postard/service/smtp.go b/internal/postard/service/smtp.go
index a553641..3f9464e 100644
--- a/internal/postard/service/smtp.go
+++ b/internal/postard/service/smtp.go
@@ -10,7 +10,6 @@ package service
import (
"context"
- "time"
"github.com/avino-plan/postar/internal/pkg/concurrency"
"github.com/pkg/errors"
@@ -19,21 +18,21 @@ import (
// SmtpServiceImpl is the service of smtp.
type SmtpServiceImpl struct {
+ pool *concurrency.Pool // The pool of workers.
host string // The host of smtp server.
port int // The port of smtp server.
user string // The user of smtp server.
password string // The password of smtp server.
- pool *concurrency.Pool // The pool of workers.
}
// NewSmtpService returns a new SmtpServer.
-func NewSmtpService(host string, port int, user string, password string, pool *concurrency.Pool) SmtpService {
+func NewSmtpService(pool *concurrency.Pool, host string, port int, user string, password string) SmtpService {
return &SmtpServiceImpl{
+ pool: pool,
host: host,
port: port,
user: user,
password: password,
- pool: pool,
}
}
@@ -48,24 +47,24 @@ func (ss *SmtpServiceImpl) sendEmail(email *Email) error {
}
// SendEmail sends email to somewhere.
-func (ss *SmtpServiceImpl) SendEmail(ctx context.Context, email *Email, options *SendEmailOptions) error {
+func (ss *SmtpServiceImpl) SendEmail(pCtx context.Context, email *Email, options *SendEmailOptions) error {
if options == nil {
options = DefaultSendEmailOptions()
}
- errorCh := ss.pool.Go(ctx, func(ctx context.Context) error {
- return ss.sendEmail(email)
- })
+ ctx, cancel := context.WithTimeout(pCtx, options.Timeout)
+ defer cancel()
+
+ errorCh := ss.pool.Go(ctx, func(ctx context.Context) error { return ss.sendEmail(email) })
if options.Async {
return nil
}
- timer := time.NewTimer(options.Timeout)
+ var err error
select {
- case err := <-errorCh:
- timer.Stop()
- return errors.Wrap(err, "send email failed")
- case <-timer.C:
- return errors.New("send email timeout")
+ case err = <-errorCh:
+ case <-ctx.Done():
+ err = ctx.Err()
}
+ return errors.Wrap(err, "send email failed")
}
diff --git a/internal/postard/service/smtp_test.go b/internal/postard/service/smtp_test.go
index 16c5b6f..e4a2615 100644
--- a/internal/postard/service/smtp_test.go
+++ b/internal/postard/service/smtp_test.go
@@ -36,7 +36,7 @@ func TestNewSmtpService(t *testing.T) {
pool := concurrency.NewPool().Start()
defer pool.Stop()
- smtpService := NewSmtpService(host, int(port), user, password, pool)
+ smtpService := NewSmtpService(pool, host, int(port), user, password)
err = smtpService.SendEmail(context.Background(), &Email{
To: []string{to},
Subject: t.Name(),
From 72a4a3d381bb559b2fc81893e00f6d2790efea10 Mon Sep 17 00:00:00 2001
From: FishGoddess <1149062639@qq.com>
Date: Sat, 25 Sep 2021 23:48:30 +0800
Subject: [PATCH 07/27] =?UTF-8?q?=E5=AE=8C=E5=96=84=20trace?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
api/pkg/status.pb.go | 163 -------------------------
api/pkg/status.proto | 18 ---
api/postard/postard.pb.go | 108 ++++++++--------
api/postard/postard.proto | 9 +-
go.mod | 1 -
internal/pkg/trace/encode.go | 57 +++++++++
internal/pkg/trace/encode_test.go | 36 ++++++
internal/pkg/trace/trace.go | 35 ++++++
internal/pkg/trace/trace_test.go | 41 +++++++
internal/postard/server/grpc.go | 33 +++++
internal/postard/service/error.go | 26 ++++
internal/postard/service/error_test.go | 50 ++++++++
internal/postard/service/smtp.go | 14 ++-
13 files changed, 342 insertions(+), 249 deletions(-)
delete mode 100644 api/pkg/status.pb.go
delete mode 100644 api/pkg/status.proto
create mode 100644 internal/pkg/trace/encode.go
create mode 100644 internal/pkg/trace/encode_test.go
create mode 100644 internal/pkg/trace/trace.go
create mode 100644 internal/pkg/trace/trace_test.go
create mode 100644 internal/postard/service/error.go
create mode 100644 internal/postard/service/error_test.go
diff --git a/api/pkg/status.pb.go b/api/pkg/status.pb.go
deleted file mode 100644
index 9564874..0000000
--- a/api/pkg/status.pb.go
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/09/22 01:18:01
-
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.27.1
-// protoc v3.18.0
-// source: status.proto
-
-package pkg
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-// Status is the status of responses.
-type Status struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- Code int64 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` // Globally unique.
- Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` // The description of responses.
-}
-
-func (x *Status) Reset() {
- *x = Status{}
- if protoimpl.UnsafeEnabled {
- mi := &file_status_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *Status) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*Status) ProtoMessage() {}
-
-func (x *Status) ProtoReflect() protoreflect.Message {
- mi := &file_status_proto_msgTypes[0]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use Status.ProtoReflect.Descriptor instead.
-func (*Status) Descriptor() ([]byte, []int) {
- return file_status_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *Status) GetCode() int64 {
- if x != nil {
- return x.Code
- }
- return 0
-}
-
-func (x *Status) GetMsg() string {
- if x != nil {
- return x.Msg
- }
- return ""
-}
-
-var File_status_proto protoreflect.FileDescriptor
-
-var file_status_proto_rawDesc = []byte{
- 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x23,
- 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f,
- 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
- 0x70, 0x6b, 0x67, 0x22, 0x2e, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a,
- 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x63, 0x6f, 0x64,
- 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
- 0x6d, 0x73, 0x67, 0x42, 0x26, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
- 0x6d, 0x2f, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x2d, 0x70, 0x6c, 0x61, 0x6e, 0x2f, 0x70, 0x6f, 0x73,
- 0x74, 0x61, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6b, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x33,
-}
-
-var (
- file_status_proto_rawDescOnce sync.Once
- file_status_proto_rawDescData = file_status_proto_rawDesc
-)
-
-func file_status_proto_rawDescGZIP() []byte {
- file_status_proto_rawDescOnce.Do(func() {
- file_status_proto_rawDescData = protoimpl.X.CompressGZIP(file_status_proto_rawDescData)
- })
- return file_status_proto_rawDescData
-}
-
-var file_status_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
-var file_status_proto_goTypes = []interface{}{
- (*Status)(nil), // 0: github.com.avinoplan.postar.api.pkg.Status
-}
-var file_status_proto_depIdxs = []int32{
- 0, // [0:0] is the sub-list for method output_type
- 0, // [0:0] is the sub-list for method input_type
- 0, // [0:0] is the sub-list for extension type_name
- 0, // [0:0] is the sub-list for extension extendee
- 0, // [0:0] is the sub-list for field type_name
-}
-
-func init() { file_status_proto_init() }
-func file_status_proto_init() {
- if File_status_proto != nil {
- return
- }
- if !protoimpl.UnsafeEnabled {
- file_status_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*Status); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: file_status_proto_rawDesc,
- NumEnums: 0,
- NumMessages: 1,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_status_proto_goTypes,
- DependencyIndexes: file_status_proto_depIdxs,
- MessageInfos: file_status_proto_msgTypes,
- }.Build()
- File_status_proto = out.File
- file_status_proto_rawDesc = nil
- file_status_proto_goTypes = nil
- file_status_proto_depIdxs = nil
-}
diff --git a/api/pkg/status.proto b/api/pkg/status.proto
deleted file mode 100644
index 479e805..0000000
--- a/api/pkg/status.proto
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/09/22 01:18:01
-syntax = "proto3";
-package github.com.avinoplan.postar.api.pkg;
-
-// protoc -I=. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative status.proto
-option go_package = "github.com/avino-plan/postar/api/pkg";
-
-// Status is the status of responses.
-message Status {
- int64 code = 1; // Globally unique.
- string msg = 2; // The description of responses.
-}
\ No newline at end of file
diff --git a/api/postard/postard.pb.go b/api/postard/postard.pb.go
index 45db3f5..a7cfefa 100644
--- a/api/postard/postard.pb.go
+++ b/api/postard/postard.pb.go
@@ -15,7 +15,6 @@
package postard
import (
- pkg "github.com/avino-plan/postar/api/pkg"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
@@ -37,8 +36,8 @@ type Email struct {
To []string `protobuf:"bytes,1,rep,name=to,proto3" json:"to,omitempty"` // The receivers of one email.
Subject string `protobuf:"bytes,2,opt,name=subject,proto3" json:"subject,omitempty"` // The subject of one email.
- BodyType string `protobuf:"bytes,3,opt,name=BodyType,proto3" json:"BodyType,omitempty"` // The content type of body.
- Body string `protobuf:"bytes,4,opt,name=Body,proto3" json:"Body,omitempty"` // The body of one email.
+ BodyType string `protobuf:"bytes,3,opt,name=bodyType,proto3" json:"bodyType,omitempty"` // The content type of body.
+ Body string `protobuf:"bytes,4,opt,name=body,proto3" json:"body,omitempty"` // The body of one email.
}
func (x *Email) Reset() {
@@ -219,7 +218,7 @@ type SendEmailResponse struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- Status *pkg.Status `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` // The status of response.
+ TraceId string `protobuf:"bytes,1,opt,name=traceId,proto3" json:"traceId,omitempty"` // For tracing.
}
func (x *SendEmailResponse) Reset() {
@@ -254,11 +253,11 @@ func (*SendEmailResponse) Descriptor() ([]byte, []int) {
return file_postard_proto_rawDescGZIP(), []int{3}
}
-func (x *SendEmailResponse) GetStatus() *pkg.Status {
+func (x *SendEmailResponse) GetTraceId() string {
if x != nil {
- return x.Status
+ return x.TraceId
}
- return nil
+ return ""
}
var File_postard_proto protoreflect.FileDescriptor
@@ -267,47 +266,44 @@ var file_postard_proto_rawDesc = []byte{
0x0a, 0x0d, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e,
0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69,
- 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x1a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
- 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x61, 0x0a, 0x05, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12,
- 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x12,
- 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x6f, 0x64,
- 0x79, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x42, 0x6f, 0x64,
- 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x04, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x42, 0x0a, 0x10, 0x53, 0x65, 0x6e,
- 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a,
- 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x73,
- 0x79, 0x6e, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02,
- 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0xad, 0x01,
- 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65,
- 0x73, 0x74, 0x12, 0x44, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x0b, 0x32, 0x2e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
- 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e,
- 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x61, 0x69,
- 0x6c, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x53, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69,
- 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x67, 0x69, 0x74, 0x68,
- 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e,
- 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f, 0x73, 0x74,
- 0x61, 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x4f, 0x70, 0x74,
- 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x58, 0x0a,
- 0x11, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
- 0x73, 0x65, 0x12, 0x43, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e,
- 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72,
- 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6b, 0x67, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52,
- 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, 0x8e, 0x01, 0x0a, 0x07, 0x50, 0x6f, 0x73, 0x74,
- 0x61, 0x72, 0x64, 0x12, 0x82, 0x01, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69,
- 0x6c, 0x12, 0x39, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
- 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e,
- 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64,
- 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e, 0x67,
- 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70,
- 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70,
- 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c,
- 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68,
- 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x2d, 0x70, 0x6c, 0x61,
- 0x6e, 0x2f, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6f, 0x73,
- 0x74, 0x61, 0x72, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x22, 0x61, 0x0a, 0x05, 0x45, 0x6d, 0x61, 0x69,
+ 0x6c, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x02, 0x74,
+ 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x62,
+ 0x6f, 0x64, 0x79, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x62,
+ 0x6f, 0x64, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18,
+ 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x42, 0x0a, 0x10, 0x53,
+ 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12,
+ 0x14, 0x0a, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05,
+ 0x61, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22,
+ 0xad, 0x01, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61,
+ 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x45, 0x6d,
+ 0x61, 0x69, 0x6c, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x53, 0x0a, 0x07, 0x6f, 0x70,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x67, 0x69,
+ 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c,
+ 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f,
+ 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x4f,
+ 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22,
+ 0x2d, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x61, 0x63, 0x65, 0x49, 0x64, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x72, 0x61, 0x63, 0x65, 0x49, 0x64, 0x32, 0x8e,
+ 0x01, 0x0a, 0x07, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x12, 0x82, 0x01, 0x0a, 0x09, 0x53,
+ 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x39, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75,
+ 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e,
+ 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61,
+ 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61,
+ 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x53, 0x65,
+ 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42,
+ 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x76,
+ 0x69, 0x6e, 0x6f, 0x2d, 0x70, 0x6c, 0x61, 0x6e, 0x2f, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2f,
+ 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x33,
}
var (
@@ -328,19 +324,17 @@ var file_postard_proto_goTypes = []interface{}{
(*SendEmailOptions)(nil), // 1: github.com.avinoplan.postar.api.postard.SendEmailOptions
(*SendEmailRequest)(nil), // 2: github.com.avinoplan.postar.api.postard.SendEmailRequest
(*SendEmailResponse)(nil), // 3: github.com.avinoplan.postar.api.postard.SendEmailResponse
- (*pkg.Status)(nil), // 4: github.com.avinoplan.postar.api.pkg.Status
}
var file_postard_proto_depIdxs = []int32{
0, // 0: github.com.avinoplan.postar.api.postard.SendEmailRequest.email:type_name -> github.com.avinoplan.postar.api.postard.Email
1, // 1: github.com.avinoplan.postar.api.postard.SendEmailRequest.options:type_name -> github.com.avinoplan.postar.api.postard.SendEmailOptions
- 4, // 2: github.com.avinoplan.postar.api.postard.SendEmailResponse.status:type_name -> github.com.avinoplan.postar.api.pkg.Status
- 2, // 3: github.com.avinoplan.postar.api.postard.Postard.SendEmail:input_type -> github.com.avinoplan.postar.api.postard.SendEmailRequest
- 3, // 4: github.com.avinoplan.postar.api.postard.Postard.SendEmail:output_type -> github.com.avinoplan.postar.api.postard.SendEmailResponse
- 4, // [4:5] is the sub-list for method output_type
- 3, // [3:4] is the sub-list for method input_type
- 3, // [3:3] is the sub-list for extension type_name
- 3, // [3:3] is the sub-list for extension extendee
- 0, // [0:3] is the sub-list for field type_name
+ 2, // 2: github.com.avinoplan.postar.api.postard.Postard.SendEmail:input_type -> github.com.avinoplan.postar.api.postard.SendEmailRequest
+ 3, // 3: github.com.avinoplan.postar.api.postard.Postard.SendEmail:output_type -> github.com.avinoplan.postar.api.postard.SendEmailResponse
+ 3, // [3:4] is the sub-list for method output_type
+ 2, // [2:3] is the sub-list for method input_type
+ 2, // [2:2] is the sub-list for extension type_name
+ 2, // [2:2] is the sub-list for extension extendee
+ 0, // [0:2] is the sub-list for field type_name
}
func init() { file_postard_proto_init() }
diff --git a/api/postard/postard.proto b/api/postard/postard.proto
index 87f3d86..adcbe8a 100644
--- a/api/postard/postard.proto
+++ b/api/postard/postard.proto
@@ -7,17 +7,16 @@
// Created at 2021/09/16 01:42:33
syntax = "proto3";
package github.com.avinoplan.postar.api.postard;
-import "status.proto";
-// protoc -I=../pkg -I=. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative postard.proto
+// protoc -I=. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative postard.proto
option go_package = "github.com/avino-plan/postar/api/postard";
// Email wraps all information of using smtp service.
message Email {
repeated string to = 1; // The receivers of one email.
string subject = 2; // The subject of one email.
- string BodyType = 3; // The content type of body.
- string Body = 4; // The body of one email.
+ string bodyType = 3; // The content type of body.
+ string body = 4; // The body of one email.
}
// SendEmailOptions is the options of sending emails.
@@ -34,7 +33,7 @@ message SendEmailRequest {
// SendEmailResponse is the response of SendEmail.
message SendEmailResponse {
- pkg.Status status = 1; // The status of response.
+ string traceId = 1; // For tracing.
}
// Postard is the core service of postar.
diff --git a/go.mod b/go.mod
index a8cb922..b02f1cb 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,6 @@ module github.com/avino-plan/postar
go 1.15
require (
- github.com/pkg/errors v0.9.1
google.golang.org/grpc v1.40.0
google.golang.org/protobuf v1.27.1
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
diff --git a/internal/pkg/trace/encode.go b/internal/pkg/trace/encode.go
new file mode 100644
index 0000000..8c14333
--- /dev/null
+++ b/internal/pkg/trace/encode.go
@@ -0,0 +1,57 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/25 22:39:17
+
+package trace
+
+import (
+ "encoding/binary"
+ "fmt"
+ "math/rand"
+ "os"
+ "time"
+)
+
+var (
+ // letters includes 0-9 a-z A-Z.
+ letters = [62]byte{
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ }
+
+ // random 用于生成随机数
+ random = rand.New(rand.NewSource(time.Now().Unix()))
+
+ // pid 是程序的 pid
+ pid = uint64(os.Getpid())
+)
+
+// TimeHex returns now time in hex.
+func TimeHex() string {
+ b := make([]byte, 8)
+ binary.BigEndian.PutUint64(b, uint64(time.Now().Unix()))
+ return fmt.Sprintf("%x", b[4:])
+}
+
+// PidHex returns pid in hex.
+func PidHex() string {
+ b := make([]byte, 8)
+ binary.BigEndian.PutUint64(b, pid)
+ return fmt.Sprintf("%x", b[4:])
+}
+
+// RandomString returns a string including 0-9/a-z/A-Z not longer than length.
+func RandomString(length int) string {
+ b := make([]byte, length)
+ for i := 0; i < length; i++ {
+ b[i] = letters[random.Intn(62)]
+ }
+ return string(b)
+}
diff --git a/internal/pkg/trace/encode_test.go b/internal/pkg/trace/encode_test.go
new file mode 100644
index 0000000..6cebf36
--- /dev/null
+++ b/internal/pkg/trace/encode_test.go
@@ -0,0 +1,36 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/25 22:58:39
+
+package trace
+
+import "testing"
+
+// go test -v -cover -run=^TestTimeHex$
+func TestTimeHex(t *testing.T) {
+ timeHex := TimeHex()
+ if len(timeHex) != 8 {
+ t.Errorf("length of TimeHex is wrong with %s, %d", timeHex, len(timeHex))
+ }
+}
+
+// go test -v -cover -run=^TestPidHex$
+func TestPidHex(t *testing.T) {
+ pidHex := PidHex()
+ if len(pidHex) != 8 {
+ t.Errorf("length of PidHex is wrong with %s, %d", pidHex, len(pidHex))
+ }
+}
+
+// go test -v -cover -run=^TestRandomString$
+func TestRandomString(t *testing.T) {
+ length := 16
+ str := RandomString(length)
+ if len(str) != length {
+ t.Errorf("length of RandomString is wrong with %d", len(str))
+ }
+}
diff --git a/internal/pkg/trace/trace.go b/internal/pkg/trace/trace.go
new file mode 100644
index 0000000..1f82838
--- /dev/null
+++ b/internal/pkg/trace/trace.go
@@ -0,0 +1,35 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/25 22:44:59
+
+package trace
+
+import "context"
+
+var (
+ traceIdKey struct{} // The key of trace id in context.
+)
+
+// WithContext returns a context with a trace id inside.
+func WithContext(ctx context.Context) context.Context {
+ traceId := RandomString(4) + TimeHex() + PidHex() + RandomString(4)
+ return context.WithValue(ctx, traceIdKey, traceId)
+}
+
+// FromContext gets the trace id from context.
+func FromContext(ctx context.Context) string {
+ value := ctx.Value(traceIdKey)
+ if value == nil {
+ return ""
+ }
+
+ traceId, ok := value.(string)
+ if !ok {
+ return ""
+ }
+ return traceId
+}
diff --git a/internal/pkg/trace/trace_test.go b/internal/pkg/trace/trace_test.go
new file mode 100644
index 0000000..2675c6a
--- /dev/null
+++ b/internal/pkg/trace/trace_test.go
@@ -0,0 +1,41 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/25 23:07:54
+
+package trace
+
+import (
+ "context"
+ "testing"
+)
+
+// go test -v -cover -run=^TestWithContext$
+func TestWithContext(t *testing.T) {
+ ctx := WithContext(context.Background())
+
+ value := ctx.Value(traceIdKey)
+ if value == nil {
+ t.Error("ctx.Value returns nil")
+ }
+
+ traceId, ok := value.(string)
+ if !ok {
+ t.Errorf("value %+v isn't string", value)
+ }
+ t.Log("traceId:", traceId)
+}
+
+// go test -v -cover -run=^TestFromContext$
+func TestFromContext(t *testing.T) {
+ traceId := RandomString(4) + TimeHex() + PidHex() + RandomString(4)
+ ctx := context.WithValue(context.Background(), traceIdKey, traceId)
+
+ traceIdInCtx := FromContext(ctx)
+ if traceIdInCtx != traceId {
+ t.Errorf("traceIdInCtx %s != traceId %s", traceIdInCtx, traceId)
+ }
+}
diff --git a/internal/postard/server/grpc.go b/internal/postard/server/grpc.go
index 217f6b5..969878f 100644
--- a/internal/postard/server/grpc.go
+++ b/internal/postard/server/grpc.go
@@ -7,3 +7,36 @@
// Created at 2021/09/16 02:05:02
package server
+
+import (
+ "context"
+
+ "github.com/avino-plan/postar/api/postard"
+ "github.com/avino-plan/postar/internal/pkg/trace"
+ "github.com/avino-plan/postar/internal/postard/service"
+)
+
+type PostardServerGrpcImpl struct {
+ postard.UnimplementedPostardServer
+ service service.SmtpService
+}
+
+func NewPostardServerGrpcImpl(service service.SmtpService) *PostardServerGrpcImpl {
+ return &PostardServerGrpcImpl{
+ service: service,
+ }
+}
+
+func (psgi *PostardServerGrpcImpl) SendEmail(pCtx context.Context, request *postard.SendEmailRequest) (*postard.SendEmailResponse, error) {
+ ctx := trace.WithContext(pCtx)
+
+ err := psgi.service.SendEmail(ctx, nil, nil)
+ if service.IsSendTimeout(err) {
+
+ }
+
+ if err != nil {
+
+ }
+ return &postard.SendEmailResponse{TraceId: trace.FromContext(ctx)}, nil
+}
diff --git a/internal/postard/service/error.go b/internal/postard/service/error.go
new file mode 100644
index 0000000..ee1d22f
--- /dev/null
+++ b/internal/postard/service/error.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/25 21:58:02
+
+package service
+
+import "errors"
+
+var (
+ errSendTimeout = errors.New("postard/service: send timeout") // Send timeout
+ errSendEmailFailed = errors.New("postard/service: send email failed") // Send email failed
+)
+
+// IsSendTimeout returns if err equals to errSendTimeout.
+func IsSendTimeout(err error) bool {
+ return errors.Is(err, errSendTimeout)
+}
+
+// IsSendEmailFailed returns if err equals to errSendEmailFailed.
+func IsSendEmailFailed(err error) bool {
+ return errors.Is(err, errSendEmailFailed)
+}
diff --git a/internal/postard/service/error_test.go b/internal/postard/service/error_test.go
new file mode 100644
index 0000000..ddcfbe9
--- /dev/null
+++ b/internal/postard/service/error_test.go
@@ -0,0 +1,50 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/25 22:06:36
+
+package service
+
+import (
+ "errors"
+ "testing"
+)
+
+// go test -v -cover -run=^TestIsSendTimeout$
+func TestIsSendTimeout(t *testing.T) {
+ testCases := []struct {
+ err error
+ result bool
+ }{
+ {errSendTimeout, true},
+ {errSendEmailFailed, false},
+ {errors.New("unknown error"), false},
+ }
+
+ for i, testCase := range testCases {
+ if IsSendTimeout(testCase.err) != testCase.result {
+ t.Errorf("testCase %d failed with err %+v, result %+v", i, testCase.err, testCase.result)
+ }
+ }
+}
+
+// go test -v -cover -run=^TestIsSendEmailFailed$
+func TestIsSendEmailFailed(t *testing.T) {
+ testCases := []struct {
+ err error
+ result bool
+ }{
+ {errSendTimeout, false},
+ {errSendEmailFailed, true},
+ {errors.New("unknown error"), false},
+ }
+
+ for i, testCase := range testCases {
+ if IsSendEmailFailed(testCase.err) != testCase.result {
+ t.Errorf("testCase %d failed with err %+v, result %+v", i, testCase.err, testCase.result)
+ }
+ }
+}
diff --git a/internal/postard/service/smtp.go b/internal/postard/service/smtp.go
index 3f9464e..63b12cb 100644
--- a/internal/postard/service/smtp.go
+++ b/internal/postard/service/smtp.go
@@ -12,7 +12,6 @@ import (
"context"
"github.com/avino-plan/postar/internal/pkg/concurrency"
- "github.com/pkg/errors"
"gopkg.in/gomail.v2"
)
@@ -60,11 +59,16 @@ func (ss *SmtpServiceImpl) SendEmail(pCtx context.Context, email *Email, options
return nil
}
- var err error
select {
- case err = <-errorCh:
+ case e := <-errorCh:
+ if e != nil {
+ return errSendEmailFailed
+ }
case <-ctx.Done():
- err = ctx.Err()
+ e := ctx.Err()
+ if e != nil {
+ return errSendTimeout
+ }
}
- return errors.Wrap(err, "send email failed")
+ return nil
}
From 2c794fc046d22c311f422d728800cec8938276f5 Mon Sep 17 00:00:00 2001
From: FishGoddess <1149062639@qq.com>
Date: Tue, 28 Sep 2021 00:01:01 +0800
Subject: [PATCH 08/27] =?UTF-8?q?=E5=AE=8C=E5=96=84=20GRPC=20=E6=9C=8D?=
=?UTF-8?q?=E5=8A=A1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
api/postard/postard.pb.go | 321 +++++++++++++++--------
api/postard/postard.proto | 24 +-
api/postard/postard_grpc.pb.go | 10 +-
cmd/postard/main.go | 25 ++
go.mod | 1 +
go.sum | 2 +
internal/postard/server/grpc.go | 55 +++-
internal/postard/service/context.go | 32 +++
internal/postard/service/context_test.go | 35 +++
internal/postard/service/service.go | 18 +-
internal/postard/service/service_test.go | 5 +
internal/postard/service/smtp.go | 20 +-
12 files changed, 400 insertions(+), 148 deletions(-)
create mode 100644 internal/postard/service/context.go
create mode 100644 internal/postard/service/context_test.go
diff --git a/api/postard/postard.pb.go b/api/postard/postard.pb.go
index a7cfefa..d6ce25b 100644
--- a/api/postard/postard.pb.go
+++ b/api/postard/postard.pb.go
@@ -17,6 +17,7 @@ package postard
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ anypb "google.golang.org/protobuf/types/known/anypb"
reflect "reflect"
sync "sync"
)
@@ -28,6 +29,128 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
+// ResponseCodes is all codes of response.
+type ResponseCodes int32
+
+const (
+ ResponseCodes_OK ResponseCodes = 0
+ ResponseCodes_InternalServerError ResponseCodes = 50000
+ ResponseCodes_TimeoutError ResponseCodes = 50001
+)
+
+// Enum value maps for ResponseCodes.
+var (
+ ResponseCodes_name = map[int32]string{
+ 0: "OK",
+ 50000: "InternalServerError",
+ 50001: "TimeoutError",
+ }
+ ResponseCodes_value = map[string]int32{
+ "OK": 0,
+ "InternalServerError": 50000,
+ "TimeoutError": 50001,
+ }
+)
+
+func (x ResponseCodes) Enum() *ResponseCodes {
+ p := new(ResponseCodes)
+ *p = x
+ return p
+}
+
+func (x ResponseCodes) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (ResponseCodes) Descriptor() protoreflect.EnumDescriptor {
+ return file_postard_proto_enumTypes[0].Descriptor()
+}
+
+func (ResponseCodes) Type() protoreflect.EnumType {
+ return &file_postard_proto_enumTypes[0]
+}
+
+func (x ResponseCodes) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use ResponseCodes.Descriptor instead.
+func (ResponseCodes) EnumDescriptor() ([]byte, []int) {
+ return file_postard_proto_rawDescGZIP(), []int{0}
+}
+
+// PostardResponse is the response of Postard.
+type PostardResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Code ResponseCodes `protobuf:"varint,1,opt,name=code,proto3,enum=github.com.avinoplan.postar.api.postard.ResponseCodes" json:"code,omitempty"` // 0 is ok.
+ Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` // For messaging.
+ TraceId string `protobuf:"bytes,3,opt,name=traceId,proto3" json:"traceId,omitempty"` // For tracing.
+ Data *anypb.Any `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"` // Any data.
+}
+
+func (x *PostardResponse) Reset() {
+ *x = PostardResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_postard_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *PostardResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PostardResponse) ProtoMessage() {}
+
+func (x *PostardResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_postard_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use PostardResponse.ProtoReflect.Descriptor instead.
+func (*PostardResponse) Descriptor() ([]byte, []int) {
+ return file_postard_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *PostardResponse) GetCode() ResponseCodes {
+ if x != nil {
+ return x.Code
+ }
+ return ResponseCodes_OK
+}
+
+func (x *PostardResponse) GetMsg() string {
+ if x != nil {
+ return x.Msg
+ }
+ return ""
+}
+
+func (x *PostardResponse) GetTraceId() string {
+ if x != nil {
+ return x.TraceId
+ }
+ return ""
+}
+
+func (x *PostardResponse) GetData() *anypb.Any {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
// Email wraps all information of using smtp service.
type Email struct {
state protoimpl.MessageState
@@ -43,7 +166,7 @@ type Email struct {
func (x *Email) Reset() {
*x = Email{}
if protoimpl.UnsafeEnabled {
- mi := &file_postard_proto_msgTypes[0]
+ mi := &file_postard_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -56,7 +179,7 @@ func (x *Email) String() string {
func (*Email) ProtoMessage() {}
func (x *Email) ProtoReflect() protoreflect.Message {
- mi := &file_postard_proto_msgTypes[0]
+ mi := &file_postard_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -69,7 +192,7 @@ func (x *Email) ProtoReflect() protoreflect.Message {
// Deprecated: Use Email.ProtoReflect.Descriptor instead.
func (*Email) Descriptor() ([]byte, []int) {
- return file_postard_proto_rawDescGZIP(), []int{0}
+ return file_postard_proto_rawDescGZIP(), []int{1}
}
func (x *Email) GetTo() []string {
@@ -113,7 +236,7 @@ type SendEmailOptions struct {
func (x *SendEmailOptions) Reset() {
*x = SendEmailOptions{}
if protoimpl.UnsafeEnabled {
- mi := &file_postard_proto_msgTypes[1]
+ mi := &file_postard_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -126,7 +249,7 @@ func (x *SendEmailOptions) String() string {
func (*SendEmailOptions) ProtoMessage() {}
func (x *SendEmailOptions) ProtoReflect() protoreflect.Message {
- mi := &file_postard_proto_msgTypes[1]
+ mi := &file_postard_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -139,7 +262,7 @@ func (x *SendEmailOptions) ProtoReflect() protoreflect.Message {
// Deprecated: Use SendEmailOptions.ProtoReflect.Descriptor instead.
func (*SendEmailOptions) Descriptor() ([]byte, []int) {
- return file_postard_proto_rawDescGZIP(), []int{1}
+ return file_postard_proto_rawDescGZIP(), []int{2}
}
func (x *SendEmailOptions) GetAsync() bool {
@@ -169,7 +292,7 @@ type SendEmailRequest struct {
func (x *SendEmailRequest) Reset() {
*x = SendEmailRequest{}
if protoimpl.UnsafeEnabled {
- mi := &file_postard_proto_msgTypes[2]
+ mi := &file_postard_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -182,7 +305,7 @@ func (x *SendEmailRequest) String() string {
func (*SendEmailRequest) ProtoMessage() {}
func (x *SendEmailRequest) ProtoReflect() protoreflect.Message {
- mi := &file_postard_proto_msgTypes[2]
+ mi := &file_postard_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -195,7 +318,7 @@ func (x *SendEmailRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use SendEmailRequest.ProtoReflect.Descriptor instead.
func (*SendEmailRequest) Descriptor() ([]byte, []int) {
- return file_postard_proto_rawDescGZIP(), []int{2}
+ return file_postard_proto_rawDescGZIP(), []int{3}
}
func (x *SendEmailRequest) GetEmail() *Email {
@@ -212,98 +335,64 @@ func (x *SendEmailRequest) GetOptions() *SendEmailOptions {
return nil
}
-// SendEmailResponse is the response of SendEmail.
-type SendEmailResponse struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- TraceId string `protobuf:"bytes,1,opt,name=traceId,proto3" json:"traceId,omitempty"` // For tracing.
-}
-
-func (x *SendEmailResponse) Reset() {
- *x = SendEmailResponse{}
- if protoimpl.UnsafeEnabled {
- mi := &file_postard_proto_msgTypes[3]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *SendEmailResponse) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SendEmailResponse) ProtoMessage() {}
-
-func (x *SendEmailResponse) ProtoReflect() protoreflect.Message {
- mi := &file_postard_proto_msgTypes[3]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SendEmailResponse.ProtoReflect.Descriptor instead.
-func (*SendEmailResponse) Descriptor() ([]byte, []int) {
- return file_postard_proto_rawDescGZIP(), []int{3}
-}
-
-func (x *SendEmailResponse) GetTraceId() string {
- if x != nil {
- return x.TraceId
- }
- return ""
-}
-
var File_postard_proto protoreflect.FileDescriptor
var file_postard_proto_rawDesc = []byte{
0x0a, 0x0d, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e,
0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69,
- 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x22, 0x61, 0x0a, 0x05, 0x45, 0x6d, 0x61, 0x69,
- 0x6c, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x02, 0x74,
- 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x62,
- 0x6f, 0x64, 0x79, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x62,
- 0x6f, 0x64, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18,
- 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x42, 0x0a, 0x10, 0x53,
- 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12,
- 0x14, 0x0a, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05,
- 0x61, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
- 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22,
- 0xad, 0x01, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71,
- 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
- 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61,
- 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x45, 0x6d,
- 0x61, 0x69, 0x6c, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x53, 0x0a, 0x07, 0x6f, 0x70,
- 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x67, 0x69,
- 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c,
- 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f,
- 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x4f,
- 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22,
- 0x2d, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x61, 0x63, 0x65, 0x49, 0x64, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x72, 0x61, 0x63, 0x65, 0x49, 0x64, 0x32, 0x8e,
- 0x01, 0x0a, 0x07, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x12, 0x82, 0x01, 0x0a, 0x09, 0x53,
- 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x39, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75,
- 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e,
- 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61,
- 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75,
- 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
- 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61,
- 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x53, 0x65,
- 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42,
- 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x76,
- 0x69, 0x6e, 0x6f, 0x2d, 0x70, 0x6c, 0x61, 0x6e, 0x2f, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2f,
- 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x33,
+ 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x22, 0xb3, 0x01, 0x0a, 0x0f, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73,
+ 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e,
+ 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x04, 0x63,
+ 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x61, 0x63, 0x65, 0x49, 0x64,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x72, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12,
+ 0x28, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
+ 0x41, 0x6e, 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x61, 0x0a, 0x05, 0x45, 0x6d, 0x61,
+ 0x69, 0x6c, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x02,
+ 0x74, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08,
+ 0x62, 0x6f, 0x64, 0x79, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+ 0x62, 0x6f, 0x64, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79,
+ 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x42, 0x0a, 0x10,
+ 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x12, 0x14, 0x0a, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
+ 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75,
+ 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
+ 0x22, 0xad, 0x01, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74,
+ 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x45,
+ 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x53, 0x0a, 0x07, 0x6f,
+ 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x67,
+ 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70,
+ 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70,
+ 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c,
+ 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x2a, 0x46, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x64, 0x65,
+ 0x73, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x13, 0x49, 0x6e, 0x74,
+ 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x72, 0x72, 0x6f, 0x72,
+ 0x10, 0xd0, 0x86, 0x03, 0x12, 0x12, 0x0a, 0x0c, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x45,
+ 0x72, 0x72, 0x6f, 0x72, 0x10, 0xd1, 0x86, 0x03, 0x32, 0x8c, 0x01, 0x0a, 0x07, 0x50, 0x6f, 0x73,
+ 0x74, 0x61, 0x72, 0x64, 0x12, 0x80, 0x01, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61,
+ 0x69, 0x6c, 0x12, 0x39, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e,
+ 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72,
+ 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e,
+ 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e,
+ 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f,
+ 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
+ 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75,
+ 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x2d, 0x70, 0x6c, 0x61, 0x6e,
+ 0x2f, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6f, 0x73, 0x74,
+ 0x61, 0x72, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -318,23 +407,28 @@ func file_postard_proto_rawDescGZIP() []byte {
return file_postard_proto_rawDescData
}
+var file_postard_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_postard_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_postard_proto_goTypes = []interface{}{
- (*Email)(nil), // 0: github.com.avinoplan.postar.api.postard.Email
- (*SendEmailOptions)(nil), // 1: github.com.avinoplan.postar.api.postard.SendEmailOptions
- (*SendEmailRequest)(nil), // 2: github.com.avinoplan.postar.api.postard.SendEmailRequest
- (*SendEmailResponse)(nil), // 3: github.com.avinoplan.postar.api.postard.SendEmailResponse
+ (ResponseCodes)(0), // 0: github.com.avinoplan.postar.api.postard.ResponseCodes
+ (*PostardResponse)(nil), // 1: github.com.avinoplan.postar.api.postard.PostardResponse
+ (*Email)(nil), // 2: github.com.avinoplan.postar.api.postard.Email
+ (*SendEmailOptions)(nil), // 3: github.com.avinoplan.postar.api.postard.SendEmailOptions
+ (*SendEmailRequest)(nil), // 4: github.com.avinoplan.postar.api.postard.SendEmailRequest
+ (*anypb.Any)(nil), // 5: google.protobuf.Any
}
var file_postard_proto_depIdxs = []int32{
- 0, // 0: github.com.avinoplan.postar.api.postard.SendEmailRequest.email:type_name -> github.com.avinoplan.postar.api.postard.Email
- 1, // 1: github.com.avinoplan.postar.api.postard.SendEmailRequest.options:type_name -> github.com.avinoplan.postar.api.postard.SendEmailOptions
- 2, // 2: github.com.avinoplan.postar.api.postard.Postard.SendEmail:input_type -> github.com.avinoplan.postar.api.postard.SendEmailRequest
- 3, // 3: github.com.avinoplan.postar.api.postard.Postard.SendEmail:output_type -> github.com.avinoplan.postar.api.postard.SendEmailResponse
- 3, // [3:4] is the sub-list for method output_type
- 2, // [2:3] is the sub-list for method input_type
- 2, // [2:2] is the sub-list for extension type_name
- 2, // [2:2] is the sub-list for extension extendee
- 0, // [0:2] is the sub-list for field type_name
+ 0, // 0: github.com.avinoplan.postar.api.postard.PostardResponse.code:type_name -> github.com.avinoplan.postar.api.postard.ResponseCodes
+ 5, // 1: github.com.avinoplan.postar.api.postard.PostardResponse.data:type_name -> google.protobuf.Any
+ 2, // 2: github.com.avinoplan.postar.api.postard.SendEmailRequest.email:type_name -> github.com.avinoplan.postar.api.postard.Email
+ 3, // 3: github.com.avinoplan.postar.api.postard.SendEmailRequest.options:type_name -> github.com.avinoplan.postar.api.postard.SendEmailOptions
+ 4, // 4: github.com.avinoplan.postar.api.postard.Postard.SendEmail:input_type -> github.com.avinoplan.postar.api.postard.SendEmailRequest
+ 1, // 5: github.com.avinoplan.postar.api.postard.Postard.SendEmail:output_type -> github.com.avinoplan.postar.api.postard.PostardResponse
+ 5, // [5:6] is the sub-list for method output_type
+ 4, // [4:5] is the sub-list for method input_type
+ 4, // [4:4] is the sub-list for extension type_name
+ 4, // [4:4] is the sub-list for extension extendee
+ 0, // [0:4] is the sub-list for field type_name
}
func init() { file_postard_proto_init() }
@@ -344,7 +438,7 @@ func file_postard_proto_init() {
}
if !protoimpl.UnsafeEnabled {
file_postard_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*Email); i {
+ switch v := v.(*PostardResponse); i {
case 0:
return &v.state
case 1:
@@ -356,7 +450,7 @@ func file_postard_proto_init() {
}
}
file_postard_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*SendEmailOptions); i {
+ switch v := v.(*Email); i {
case 0:
return &v.state
case 1:
@@ -368,7 +462,7 @@ func file_postard_proto_init() {
}
}
file_postard_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*SendEmailRequest); i {
+ switch v := v.(*SendEmailOptions); i {
case 0:
return &v.state
case 1:
@@ -380,7 +474,7 @@ func file_postard_proto_init() {
}
}
file_postard_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*SendEmailResponse); i {
+ switch v := v.(*SendEmailRequest); i {
case 0:
return &v.state
case 1:
@@ -397,13 +491,14 @@ func file_postard_proto_init() {
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_postard_proto_rawDesc,
- NumEnums: 0,
+ NumEnums: 1,
NumMessages: 4,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_postard_proto_goTypes,
DependencyIndexes: file_postard_proto_depIdxs,
+ EnumInfos: file_postard_proto_enumTypes,
MessageInfos: file_postard_proto_msgTypes,
}.Build()
File_postard_proto = out.File
diff --git a/api/postard/postard.proto b/api/postard/postard.proto
index adcbe8a..7159e48 100644
--- a/api/postard/postard.proto
+++ b/api/postard/postard.proto
@@ -11,6 +11,23 @@ package github.com.avinoplan.postar.api.postard;
// protoc -I=. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative postard.proto
option go_package = "github.com/avino-plan/postar/api/postard";
+import "google/protobuf/any.proto";
+
+// ResponseCodes is all codes of response.
+enum ResponseCodes {
+ OK = 0;
+ InternalServerError = 50000;
+ TimeoutError = 50001;
+}
+
+// PostardResponse is the response of Postard.
+message PostardResponse {
+ ResponseCodes code = 1; // 0 is ok.
+ string msg = 2; // For messaging.
+ string traceId = 3; // For tracing.
+ google.protobuf.Any data = 4; // Any data.
+}
+
// Email wraps all information of using smtp service.
message Email {
repeated string to = 1; // The receivers of one email.
@@ -31,12 +48,7 @@ message SendEmailRequest {
SendEmailOptions options = 2; // Sending options.
}
-// SendEmailResponse is the response of SendEmail.
-message SendEmailResponse {
- string traceId = 1; // For tracing.
-}
-
// Postard is the core service of postar.
service Postard {
- rpc SendEmail(SendEmailRequest) returns (SendEmailResponse); // For sending emails.
+ rpc SendEmail(SendEmailRequest) returns (PostardResponse); // For sending emails.
}
\ No newline at end of file
diff --git a/api/postard/postard_grpc.pb.go b/api/postard/postard_grpc.pb.go
index 846c27b..235c9ae 100644
--- a/api/postard/postard_grpc.pb.go
+++ b/api/postard/postard_grpc.pb.go
@@ -18,7 +18,7 @@ const _ = grpc.SupportPackageIsVersion7
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type PostardClient interface {
- SendEmail(ctx context.Context, in *SendEmailRequest, opts ...grpc.CallOption) (*SendEmailResponse, error)
+ SendEmail(ctx context.Context, in *SendEmailRequest, opts ...grpc.CallOption) (*PostardResponse, error)
}
type postardClient struct {
@@ -29,8 +29,8 @@ func NewPostardClient(cc grpc.ClientConnInterface) PostardClient {
return &postardClient{cc}
}
-func (c *postardClient) SendEmail(ctx context.Context, in *SendEmailRequest, opts ...grpc.CallOption) (*SendEmailResponse, error) {
- out := new(SendEmailResponse)
+func (c *postardClient) SendEmail(ctx context.Context, in *SendEmailRequest, opts ...grpc.CallOption) (*PostardResponse, error) {
+ out := new(PostardResponse)
err := c.cc.Invoke(ctx, "/github.com.avinoplan.postar.api.postard.Postard/SendEmail", in, out, opts...)
if err != nil {
return nil, err
@@ -42,7 +42,7 @@ func (c *postardClient) SendEmail(ctx context.Context, in *SendEmailRequest, opt
// All implementations must embed UnimplementedPostardServer
// for forward compatibility
type PostardServer interface {
- SendEmail(context.Context, *SendEmailRequest) (*SendEmailResponse, error)
+ SendEmail(context.Context, *SendEmailRequest) (*PostardResponse, error)
mustEmbedUnimplementedPostardServer()
}
@@ -50,7 +50,7 @@ type PostardServer interface {
type UnimplementedPostardServer struct {
}
-func (UnimplementedPostardServer) SendEmail(context.Context, *SendEmailRequest) (*SendEmailResponse, error) {
+func (UnimplementedPostardServer) SendEmail(context.Context, *SendEmailRequest) (*PostardResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method SendEmail not implemented")
}
func (UnimplementedPostardServer) mustEmbedUnimplementedPostardServer() {}
diff --git a/cmd/postard/main.go b/cmd/postard/main.go
index 5688188..2155d67 100644
--- a/cmd/postard/main.go
+++ b/cmd/postard/main.go
@@ -8,6 +8,31 @@
package main
+import (
+ "net"
+
+ "github.com/FishGoddess/logit"
+ "github.com/avino-plan/postar/internal/pkg/concurrency"
+ "github.com/avino-plan/postar/internal/postard/server"
+ "github.com/avino-plan/postar/internal/postard/service"
+)
+
func main() {
+ logger := logit.NewLogger()
+ contextService := service.NewContextService(logger)
+
+ pool := concurrency.NewPool()
+ smtpService := service.NewSmtpService(pool, "", 0, "", "")
+
+ svr := server.NewPostardGrpcServer(contextService, smtpService)
+
+ listener, err := net.Listen("tcp", ":5897")
+ if err != nil {
+ panic(err)
+ }
+ err = svr.Run(listener)
+ if err != nil {
+ panic(err)
+ }
}
diff --git a/go.mod b/go.mod
index b02f1cb..4fd2fcf 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@ module github.com/avino-plan/postar
go 1.15
require (
+ github.com/FishGoddess/logit v0.4.7-alpha
google.golang.org/grpc v1.40.0
google.golang.org/protobuf v1.27.1
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
diff --git a/go.sum b/go.sum
index 4baad21..3bcf639 100644
--- a/go.sum
+++ b/go.sum
@@ -1,6 +1,8 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/FishGoddess/logit v0.4.7-alpha h1:6pYVA+Qp+KFr/vB7Z4ad9JIhq7Nm9QMWBMcES9QYtvU=
+github.com/FishGoddess/logit v0.4.7-alpha/go.mod h1:a2dFSibwfZXNNZ/V1jMOQBImPoySaxdPFThbsm17ZdY=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
diff --git a/internal/postard/server/grpc.go b/internal/postard/server/grpc.go
index 969878f..409f0e8 100644
--- a/internal/postard/server/grpc.go
+++ b/internal/postard/server/grpc.go
@@ -10,33 +10,66 @@ package server
import (
"context"
+ "net"
"github.com/avino-plan/postar/api/postard"
"github.com/avino-plan/postar/internal/pkg/trace"
"github.com/avino-plan/postar/internal/postard/service"
+ "google.golang.org/grpc"
)
-type PostardServerGrpcImpl struct {
+// PostardGrpcServer is a grpc implement of PostardServer.
+type PostardGrpcServer struct {
postard.UnimplementedPostardServer
- service service.SmtpService
+ server *grpc.Server
+ contextService service.ContextService
+ smtpService service.SmtpService
}
-func NewPostardServerGrpcImpl(service service.SmtpService) *PostardServerGrpcImpl {
- return &PostardServerGrpcImpl{
- service: service,
+// NewPostardGrpcServer returns a new PostardGrpcServer.
+func NewPostardGrpcServer(contextService service.ContextService, smtpService service.SmtpService) *PostardGrpcServer {
+ return &PostardGrpcServer{
+ contextService: contextService,
+ smtpService: smtpService,
}
}
-func (psgi *PostardServerGrpcImpl) SendEmail(pCtx context.Context, request *postard.SendEmailRequest) (*postard.SendEmailResponse, error) {
- ctx := trace.WithContext(pCtx)
+// SendEmail sends emails.
+func (pgs *PostardGrpcServer) SendEmail(ctx context.Context, request *postard.SendEmailRequest) (*postard.PostardResponse, error) {
+ ctx = pgs.contextService.WrapContext(ctx)
+ traceId := trace.FromContext(ctx)
- err := psgi.service.SendEmail(ctx, nil, nil)
+ err := pgs.smtpService.SendEmail(ctx, nil, nil)
if service.IsSendTimeout(err) {
-
+ return &postard.PostardResponse{
+ Code: postard.ResponseCodes_TimeoutError,
+ Msg: "send email timeout",
+ TraceId: traceId,
+ }, nil
}
if err != nil {
-
+ return &postard.PostardResponse{
+ Code: postard.ResponseCodes_InternalServerError,
+ Msg: "send email failed",
+ TraceId: traceId,
+ }, nil
}
- return &postard.SendEmailResponse{TraceId: trace.FromContext(ctx)}, nil
+
+ return &postard.PostardResponse{
+ Code: postard.ResponseCodes_OK,
+ TraceId: traceId,
+ }, nil
+}
+
+// Run runs PostardGrpcServer with listener.
+func (pgs *PostardGrpcServer) Run(listener net.Listener) error {
+ pgs.server = grpc.NewServer()
+ postard.RegisterPostardServer(pgs.server, pgs)
+ return pgs.server.Serve(listener)
+}
+
+// Shutdown shutdowns PostardGrpcServer gracefully.
+func (pgs *PostardGrpcServer) Shutdown() {
+ pgs.server.GracefulStop()
}
diff --git a/internal/postard/service/context.go b/internal/postard/service/context.go
new file mode 100644
index 0000000..1b85ac6
--- /dev/null
+++ b/internal/postard/service/context.go
@@ -0,0 +1,32 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/27 22:40:58
+
+package service
+
+import (
+ "context"
+
+ "github.com/FishGoddess/logit"
+ "github.com/avino-plan/postar/internal/pkg/trace"
+)
+
+// contextServiceImpl is the service of context.
+type contextServiceImpl struct {
+ logger *logit.Logger
+}
+
+// NewContextService returns a new ContextService.
+func NewContextService(logger *logit.Logger) ContextService {
+ return &contextServiceImpl{logger: logger}
+}
+
+// WrapContext wraps context with something and returns a new context.
+func (csi *contextServiceImpl) WrapContext(ctx context.Context) context.Context {
+ ctx = logit.NewContext(ctx, csi.logger)
+ return trace.WithContext(ctx)
+}
diff --git a/internal/postard/service/context_test.go b/internal/postard/service/context_test.go
new file mode 100644
index 0000000..1067e6b
--- /dev/null
+++ b/internal/postard/service/context_test.go
@@ -0,0 +1,35 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/27 22:50:56
+
+package service
+
+import (
+ "context"
+ "testing"
+
+ "github.com/FishGoddess/logit"
+ "github.com/avino-plan/postar/internal/pkg/trace"
+)
+
+// go test -v -cover -run=^TestNewContextService$
+func TestNewContextService(t *testing.T) {
+ logger := logit.NewLogger()
+
+ service := NewContextService(logger)
+ ctx := service.WrapContext(context.Background())
+
+ contextLogger := logit.FromContext(ctx)
+ if contextLogger != logger {
+ t.Errorf("contextLogger %+v != logger %+v", contextLogger, logger)
+ }
+
+ traceId := trace.FromContext(ctx)
+ if traceId == "" {
+ t.Error("traceId == ''")
+ }
+}
diff --git a/internal/postard/service/service.go b/internal/postard/service/service.go
index d564c87..63bf45f 100644
--- a/internal/postard/service/service.go
+++ b/internal/postard/service/service.go
@@ -27,12 +27,10 @@ type SendEmailOptions struct {
Timeout time.Duration // The timeout of sending one email.
}
-// DefaultSendEmailOptions returns a default options for sending emails.
-func DefaultSendEmailOptions() *SendEmailOptions {
- return &SendEmailOptions{
- Async: false,
- Timeout: 5 * time.Second,
- }
+// ContextService is the service of context
+type ContextService interface {
+ // WrapContext wraps context with something and returns a new context.
+ WrapContext(ctx context.Context) context.Context
}
// SmtpService is the service of smtp.
@@ -40,3 +38,11 @@ type SmtpService interface {
// SendEmail sends email with options and returns an error if something wrong happens.
SendEmail(ctx context.Context, email *Email, options *SendEmailOptions) error
}
+
+// DefaultSendEmailOptions returns a default options for sending emails.
+func DefaultSendEmailOptions() *SendEmailOptions {
+ return &SendEmailOptions{
+ Async: false,
+ Timeout: 5 * time.Second,
+ }
+}
diff --git a/internal/postard/service/service_test.go b/internal/postard/service/service_test.go
index c87815e..a5dab9f 100644
--- a/internal/postard/service/service_test.go
+++ b/internal/postard/service/service_test.go
@@ -10,6 +10,11 @@ package service
import "testing"
+// go test -v -cover -run=^TestContextService$
+func TestContextService(t *testing.T) {
+ // do nothing...
+}
+
// go test -v -cover -run=^TestSmtpService$
func TestSmtpService(t *testing.T) {
// do nothing...
diff --git a/internal/postard/service/smtp.go b/internal/postard/service/smtp.go
index 63b12cb..f72f7f6 100644
--- a/internal/postard/service/smtp.go
+++ b/internal/postard/service/smtp.go
@@ -11,12 +11,13 @@ package service
import (
"context"
+ "github.com/FishGoddess/logit"
"github.com/avino-plan/postar/internal/pkg/concurrency"
"gopkg.in/gomail.v2"
)
-// SmtpServiceImpl is the service of smtp.
-type SmtpServiceImpl struct {
+// smtpServiceImpl is the service of smtp.
+type smtpServiceImpl struct {
pool *concurrency.Pool // The pool of workers.
host string // The host of smtp server.
port int // The port of smtp server.
@@ -24,9 +25,9 @@ type SmtpServiceImpl struct {
password string // The password of smtp server.
}
-// NewSmtpService returns a new SmtpServer.
+// NewSmtpService returns a new SmtpService.
func NewSmtpService(pool *concurrency.Pool, host string, port int, user string, password string) SmtpService {
- return &SmtpServiceImpl{
+ return &smtpServiceImpl{
pool: pool,
host: host,
port: port,
@@ -36,7 +37,7 @@ func NewSmtpService(pool *concurrency.Pool, host string, port int, user string,
}
// sendEmail sends email and returns an error if something wrong happens.
-func (ss *SmtpServiceImpl) sendEmail(email *Email) error {
+func (ss *smtpServiceImpl) sendEmail(email *Email) error {
msg := gomail.NewMessage()
msg.SetHeader("From", ss.user)
msg.SetHeader("To", email.To...)
@@ -46,12 +47,15 @@ func (ss *SmtpServiceImpl) sendEmail(email *Email) error {
}
// SendEmail sends email to somewhere.
-func (ss *SmtpServiceImpl) SendEmail(pCtx context.Context, email *Email, options *SendEmailOptions) error {
+func (ss *smtpServiceImpl) SendEmail(ctx context.Context, email *Email, options *SendEmailOptions) error {
+ logger := logit.FromContext(ctx)
+
if options == nil {
options = DefaultSendEmailOptions()
+ logger.Debug("options is nil, using DefaultSendEmailOptions()").Any("options", options).End()
}
- ctx, cancel := context.WithTimeout(pCtx, options.Timeout)
+ ctx, cancel := context.WithTimeout(ctx, options.Timeout)
defer cancel()
errorCh := ss.pool.Go(ctx, func(ctx context.Context) error { return ss.sendEmail(email) })
@@ -62,11 +66,13 @@ func (ss *SmtpServiceImpl) SendEmail(pCtx context.Context, email *Email, options
select {
case e := <-errorCh:
if e != nil {
+ logger.Error("send email failed").Error("e", e).End()
return errSendEmailFailed
}
case <-ctx.Done():
e := ctx.Err()
if e != nil {
+ logger.Error("send email timeout").Error("e", e).End()
return errSendTimeout
}
}
From 913e6313d8dcb98ba99a19ca31a5d70ce33ad6e5 Mon Sep 17 00:00:00 2001
From: FishGoddess <1149062639@qq.com>
Date: Mon, 17 Jan 2022 01:12:14 +0800
Subject: [PATCH 09/27] =?UTF-8?q?=E9=87=8D=E6=9E=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
api/{postard => }/postard.pb.go | 91 +++++++-------
api/{postard => }/postard.proto | 4 +-
api/{postard => }/postard_grpc.pb.go | 16 +--
cmd/postard/main.go | 12 +-
internal/pkg/trace/trace.go | 35 ------
internal/pkg/trace/trace_test.go | 41 -------
internal/postard/{service => biz}/smtp.go | 32 ++---
.../postard/{service => biz}/smtp_test.go | 13 +-
.../{service/service.go => model/smtp.go} | 19 +--
internal/postard/server/grpc.go | 75 ++++++------
internal/postard/server/http.go | 2 +
internal/postard/server/udp.go | 11 ++
internal/postard/server/vex.go | 11 ++
internal/postard/service/context.go | 32 -----
internal/postard/service/error.go | 26 ----
internal/postard/service/service_test.go | 21 ----
{internal/pkg => pkg}/concurrency/pool.go | 0
.../pkg => pkg}/concurrency/pool_test.go | 0
pkg/context/context.go | 29 +++++
.../service => pkg/context}/context_test.go | 17 +--
{internal/pkg/trace => pkg/encode}/encode.go | 43 ++++---
.../pkg/trace => pkg/encode}/encode_test.go | 12 +-
pkg/errors/errors.go | 114 ++++++++++++++++++
.../errors/errors_test.go | 2 +-
pkg/trace/trace.go | 39 ++++++
pkg/trace/trace_test.go | 57 +++++++++
26 files changed, 430 insertions(+), 324 deletions(-)
rename api/{postard => }/postard.pb.go (79%)
rename api/{postard => }/postard.proto (93%)
rename api/{postard => }/postard_grpc.pb.go (86%)
delete mode 100644 internal/pkg/trace/trace.go
delete mode 100644 internal/pkg/trace/trace_test.go
rename internal/postard/{service => biz}/smtp.go (63%)
rename internal/postard/{service => biz}/smtp_test.go (78%)
rename internal/postard/{service/service.go => model/smtp.go} (64%)
create mode 100644 internal/postard/server/udp.go
create mode 100644 internal/postard/server/vex.go
delete mode 100644 internal/postard/service/context.go
delete mode 100644 internal/postard/service/error.go
delete mode 100644 internal/postard/service/service_test.go
rename {internal/pkg => pkg}/concurrency/pool.go (100%)
rename {internal/pkg => pkg}/concurrency/pool_test.go (100%)
create mode 100644 pkg/context/context.go
rename {internal/postard/service => pkg/context}/context_test.go (64%)
rename {internal/pkg/trace => pkg/encode}/encode.go (60%)
rename {internal/pkg/trace => pkg/encode}/encode_test.go (77%)
create mode 100644 pkg/errors/errors.go
rename internal/postard/service/error_test.go => pkg/errors/errors_test.go (98%)
create mode 100644 pkg/trace/trace.go
create mode 100644 pkg/trace/trace_test.go
diff --git a/api/postard/postard.pb.go b/api/postard.pb.go
similarity index 79%
rename from api/postard/postard.pb.go
rename to api/postard.pb.go
index d6ce25b..5bb79f1 100644
--- a/api/postard/postard.pb.go
+++ b/api/postard.pb.go
@@ -12,7 +12,7 @@
// protoc v3.18.0
// source: postard.proto
-package postard
+package api
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
@@ -85,10 +85,10 @@ type PostardResponse struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- Code ResponseCodes `protobuf:"varint,1,opt,name=code,proto3,enum=github.com.avinoplan.postar.api.postard.ResponseCodes" json:"code,omitempty"` // 0 is ok.
- Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` // For messaging.
- TraceId string `protobuf:"bytes,3,opt,name=traceId,proto3" json:"traceId,omitempty"` // For tracing.
- Data *anypb.Any `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"` // Any data.
+ Code ResponseCodes `protobuf:"varint,1,opt,name=code,proto3,enum=github.com.avinoplan.postar.api.ResponseCodes" json:"code,omitempty"` // 0 is ok.
+ Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` // For messaging.
+ TraceId string `protobuf:"bytes,3,opt,name=traceId,proto3" json:"traceId,omitempty"` // For tracing.
+ Data *anypb.Any `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"` // Any data.
}
func (x *PostardResponse) Reset() {
@@ -151,7 +151,7 @@ func (x *PostardResponse) GetData() *anypb.Any {
return nil
}
-// Email wraps all information of using smtp service.
+// Email wraps all information of using smtp biz.
type Email struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -339,15 +339,14 @@ var File_postard_proto protoreflect.FileDescriptor
var file_postard_proto_rawDesc = []byte{
0x0a, 0x0d, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
- 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e,
+ 0x1f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e,
0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69,
- 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
- 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x22, 0xb3, 0x01, 0x0a, 0x0f, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
- 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73,
- 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e,
+ 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
+ 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xab, 0x01, 0x0a, 0x0f,
+ 0x50, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
+ 0x42, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e,
+ 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f,
+ 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x04, 0x63,
0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x61, 0x63, 0x65, 0x49, 0x64,
@@ -365,34 +364,32 @@ var file_postard_proto_rawDesc = []byte{
0x12, 0x14, 0x0a, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75,
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
- 0x22, 0xad, 0x01, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65,
- 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01,
- 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
+ 0x22, 0x9d, 0x01, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74,
+ 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x05, 0x65, 0x6d,
+ 0x61, 0x69, 0x6c, 0x12, 0x4b, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74,
- 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x45,
- 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x53, 0x0a, 0x07, 0x6f,
- 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x67,
- 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70,
- 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70,
- 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c,
+ 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c,
0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x2a, 0x46, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x64, 0x65,
0x73, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x13, 0x49, 0x6e, 0x74,
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x72, 0x72, 0x6f, 0x72,
0x10, 0xd0, 0x86, 0x03, 0x12, 0x12, 0x0a, 0x0c, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x45,
- 0x72, 0x72, 0x6f, 0x72, 0x10, 0xd1, 0x86, 0x03, 0x32, 0x8c, 0x01, 0x0a, 0x07, 0x50, 0x6f, 0x73,
- 0x74, 0x61, 0x72, 0x64, 0x12, 0x80, 0x01, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61,
- 0x69, 0x6c, 0x12, 0x39, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e,
- 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72,
- 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x53, 0x65, 0x6e,
- 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e,
- 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f,
- 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
- 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75,
- 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x2d, 0x70, 0x6c, 0x61, 0x6e,
- 0x2f, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6f, 0x73, 0x74,
- 0x61, 0x72, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x72, 0x72, 0x6f, 0x72, 0x10, 0xd1, 0x86, 0x03, 0x32, 0x7b, 0x0a, 0x07, 0x50, 0x6f, 0x73, 0x74,
+ 0x61, 0x72, 0x64, 0x12, 0x70, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c,
+ 0x12, 0x31, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76,
+ 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61,
+ 0x70, 0x69, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61,
+ 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x22, 0x5a, 0x20, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x2d, 0x70, 0x6c, 0x61, 0x6e, 0x2f, 0x70,
+ 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x33,
}
var (
@@ -410,20 +407,20 @@ func file_postard_proto_rawDescGZIP() []byte {
var file_postard_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_postard_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_postard_proto_goTypes = []interface{}{
- (ResponseCodes)(0), // 0: github.com.avinoplan.postar.api.postard.ResponseCodes
- (*PostardResponse)(nil), // 1: github.com.avinoplan.postar.api.postard.PostardResponse
- (*Email)(nil), // 2: github.com.avinoplan.postar.api.postard.Email
- (*SendEmailOptions)(nil), // 3: github.com.avinoplan.postar.api.postard.SendEmailOptions
- (*SendEmailRequest)(nil), // 4: github.com.avinoplan.postar.api.postard.SendEmailRequest
+ (ResponseCodes)(0), // 0: github.com.avinoplan.postar.api.ResponseCodes
+ (*PostardResponse)(nil), // 1: github.com.avinoplan.postar.api.PostardResponse
+ (*Email)(nil), // 2: github.com.avinoplan.postar.api.Email
+ (*SendEmailOptions)(nil), // 3: github.com.avinoplan.postar.api.SendEmailOptions
+ (*SendEmailRequest)(nil), // 4: github.com.avinoplan.postar.api.SendEmailRequest
(*anypb.Any)(nil), // 5: google.protobuf.Any
}
var file_postard_proto_depIdxs = []int32{
- 0, // 0: github.com.avinoplan.postar.api.postard.PostardResponse.code:type_name -> github.com.avinoplan.postar.api.postard.ResponseCodes
- 5, // 1: github.com.avinoplan.postar.api.postard.PostardResponse.data:type_name -> google.protobuf.Any
- 2, // 2: github.com.avinoplan.postar.api.postard.SendEmailRequest.email:type_name -> github.com.avinoplan.postar.api.postard.Email
- 3, // 3: github.com.avinoplan.postar.api.postard.SendEmailRequest.options:type_name -> github.com.avinoplan.postar.api.postard.SendEmailOptions
- 4, // 4: github.com.avinoplan.postar.api.postard.Postard.SendEmail:input_type -> github.com.avinoplan.postar.api.postard.SendEmailRequest
- 1, // 5: github.com.avinoplan.postar.api.postard.Postard.SendEmail:output_type -> github.com.avinoplan.postar.api.postard.PostardResponse
+ 0, // 0: github.com.avinoplan.postar.api.PostardResponse.code:type_name -> github.com.avinoplan.postar.api.ResponseCodes
+ 5, // 1: github.com.avinoplan.postar.api.PostardResponse.data:type_name -> google.protobuf.Any
+ 2, // 2: github.com.avinoplan.postar.api.SendEmailRequest.email:type_name -> github.com.avinoplan.postar.api.Email
+ 3, // 3: github.com.avinoplan.postar.api.SendEmailRequest.options:type_name -> github.com.avinoplan.postar.api.SendEmailOptions
+ 4, // 4: github.com.avinoplan.postar.api.Postard.SendEmail:input_type -> github.com.avinoplan.postar.api.SendEmailRequest
+ 1, // 5: github.com.avinoplan.postar.api.Postard.SendEmail:output_type -> github.com.avinoplan.postar.api.PostardResponse
5, // [5:6] is the sub-list for method output_type
4, // [4:5] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
diff --git a/api/postard/postard.proto b/api/postard.proto
similarity index 93%
rename from api/postard/postard.proto
rename to api/postard.proto
index 7159e48..dce3bae 100644
--- a/api/postard/postard.proto
+++ b/api/postard.proto
@@ -6,10 +6,10 @@
// Email: fishgoddess@qq.com
// Created at 2021/09/16 01:42:33
syntax = "proto3";
-package github.com.avinoplan.postar.api.postard;
+package github.com.avinoplan.postar.api;
// protoc -I=. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative postard.proto
-option go_package = "github.com/avino-plan/postar/api/postard";
+option go_package = "github.com/avino-plan/postar/api";
import "google/protobuf/any.proto";
diff --git a/api/postard/postard_grpc.pb.go b/api/postard_grpc.pb.go
similarity index 86%
rename from api/postard/postard_grpc.pb.go
rename to api/postard_grpc.pb.go
index 235c9ae..05b575f 100644
--- a/api/postard/postard_grpc.pb.go
+++ b/api/postard_grpc.pb.go
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
-package postard
+package api
import (
context "context"
@@ -14,7 +14,7 @@ import (
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
-// PostardClient is the client API for Postard service.
+// PostardClient is the client API for Postard biz.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type PostardClient interface {
@@ -31,14 +31,14 @@ func NewPostardClient(cc grpc.ClientConnInterface) PostardClient {
func (c *postardClient) SendEmail(ctx context.Context, in *SendEmailRequest, opts ...grpc.CallOption) (*PostardResponse, error) {
out := new(PostardResponse)
- err := c.cc.Invoke(ctx, "/github.com.avinoplan.postar.api.postard.Postard/SendEmail", in, out, opts...)
+ err := c.cc.Invoke(ctx, "/github.com.avinoplan.postar.api.Postard/SendEmail", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
-// PostardServer is the server API for Postard service.
+// PostardServer is the server API for Postard biz.
// All implementations must embed UnimplementedPostardServer
// for forward compatibility
type PostardServer interface {
@@ -55,7 +55,7 @@ func (UnimplementedPostardServer) SendEmail(context.Context, *SendEmailRequest)
}
func (UnimplementedPostardServer) mustEmbedUnimplementedPostardServer() {}
-// UnsafePostardServer may be embedded to opt out of forward compatibility for this service.
+// UnsafePostardServer may be embedded to opt out of forward compatibility for this biz.
// Use of this interface is not recommended, as added methods to PostardServer will
// result in compilation errors.
type UnsafePostardServer interface {
@@ -76,7 +76,7 @@ func _Postard_SendEmail_Handler(srv interface{}, ctx context.Context, dec func(i
}
info := &grpc.UnaryServerInfo{
Server: srv,
- FullMethod: "/github.com.avinoplan.postar.api.postard.Postard/SendEmail",
+ FullMethod: "/github.com.avinoplan.postar.api.Postard/SendEmail",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(PostardServer).SendEmail(ctx, req.(*SendEmailRequest))
@@ -84,11 +84,11 @@ func _Postard_SendEmail_Handler(srv interface{}, ctx context.Context, dec func(i
return interceptor(ctx, in, info, handler)
}
-// Postard_ServiceDesc is the grpc.ServiceDesc for Postard service.
+// Postard_ServiceDesc is the grpc.ServiceDesc for Postard biz.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Postard_ServiceDesc = grpc.ServiceDesc{
- ServiceName: "github.com.avinoplan.postar.api.postard.Postard",
+ ServiceName: "github.com.avinoplan.postar.api.Postard",
HandlerType: (*PostardServer)(nil),
Methods: []grpc.MethodDesc{
{
diff --git a/cmd/postard/main.go b/cmd/postard/main.go
index 2155d67..c915b42 100644
--- a/cmd/postard/main.go
+++ b/cmd/postard/main.go
@@ -12,19 +12,17 @@ import (
"net"
"github.com/FishGoddess/logit"
- "github.com/avino-plan/postar/internal/pkg/concurrency"
+ "github.com/avino-plan/postar/internal/postard/biz"
"github.com/avino-plan/postar/internal/postard/server"
- "github.com/avino-plan/postar/internal/postard/service"
+ "github.com/avino-plan/postar/pkg/concurrency"
)
func main() {
logger := logit.NewLogger()
- contextService := service.NewContextService(logger)
-
pool := concurrency.NewPool()
- smtpService := service.NewSmtpService(pool, "", 0, "", "")
-
- svr := server.NewPostardGrpcServer(contextService, smtpService)
+
+ smtpBiz := biz.NewSmtpBiz(pool, "", 0, "", "")
+ svr := server.NewGrpcServer(logger, smtpBiz)
listener, err := net.Listen("tcp", ":5897")
if err != nil {
diff --git a/internal/pkg/trace/trace.go b/internal/pkg/trace/trace.go
deleted file mode 100644
index 1f82838..0000000
--- a/internal/pkg/trace/trace.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/09/25 22:44:59
-
-package trace
-
-import "context"
-
-var (
- traceIdKey struct{} // The key of trace id in context.
-)
-
-// WithContext returns a context with a trace id inside.
-func WithContext(ctx context.Context) context.Context {
- traceId := RandomString(4) + TimeHex() + PidHex() + RandomString(4)
- return context.WithValue(ctx, traceIdKey, traceId)
-}
-
-// FromContext gets the trace id from context.
-func FromContext(ctx context.Context) string {
- value := ctx.Value(traceIdKey)
- if value == nil {
- return ""
- }
-
- traceId, ok := value.(string)
- if !ok {
- return ""
- }
- return traceId
-}
diff --git a/internal/pkg/trace/trace_test.go b/internal/pkg/trace/trace_test.go
deleted file mode 100644
index 2675c6a..0000000
--- a/internal/pkg/trace/trace_test.go
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/09/25 23:07:54
-
-package trace
-
-import (
- "context"
- "testing"
-)
-
-// go test -v -cover -run=^TestWithContext$
-func TestWithContext(t *testing.T) {
- ctx := WithContext(context.Background())
-
- value := ctx.Value(traceIdKey)
- if value == nil {
- t.Error("ctx.Value returns nil")
- }
-
- traceId, ok := value.(string)
- if !ok {
- t.Errorf("value %+v isn't string", value)
- }
- t.Log("traceId:", traceId)
-}
-
-// go test -v -cover -run=^TestFromContext$
-func TestFromContext(t *testing.T) {
- traceId := RandomString(4) + TimeHex() + PidHex() + RandomString(4)
- ctx := context.WithValue(context.Background(), traceIdKey, traceId)
-
- traceIdInCtx := FromContext(ctx)
- if traceIdInCtx != traceId {
- t.Errorf("traceIdInCtx %s != traceId %s", traceIdInCtx, traceId)
- }
-}
diff --git a/internal/postard/service/smtp.go b/internal/postard/biz/smtp.go
similarity index 63%
rename from internal/postard/service/smtp.go
rename to internal/postard/biz/smtp.go
index f72f7f6..6a35130 100644
--- a/internal/postard/service/smtp.go
+++ b/internal/postard/biz/smtp.go
@@ -6,18 +6,20 @@
// Email: fishgoddess@qq.com
// Created at 2021/09/16 02:05:37
-package service
+package biz
import (
"context"
"github.com/FishGoddess/logit"
- "github.com/avino-plan/postar/internal/pkg/concurrency"
+ "github.com/avino-plan/postar/internal/postard/model"
+ "github.com/avino-plan/postar/pkg/concurrency"
+ "github.com/avino-plan/postar/pkg/errors"
"gopkg.in/gomail.v2"
)
-// smtpServiceImpl is the service of smtp.
-type smtpServiceImpl struct {
+// SmtpBiz is the biz of smtp.
+type SmtpBiz struct {
pool *concurrency.Pool // The pool of workers.
host string // The host of smtp server.
port int // The port of smtp server.
@@ -25,9 +27,9 @@ type smtpServiceImpl struct {
password string // The password of smtp server.
}
-// NewSmtpService returns a new SmtpService.
-func NewSmtpService(pool *concurrency.Pool, host string, port int, user string, password string) SmtpService {
- return &smtpServiceImpl{
+// NewSmtpBiz returns a new SmtpBiz.
+func NewSmtpBiz(pool *concurrency.Pool, host string, port int, user string, password string) *SmtpBiz {
+ return &SmtpBiz{
pool: pool,
host: host,
port: port,
@@ -37,28 +39,28 @@ func NewSmtpService(pool *concurrency.Pool, host string, port int, user string,
}
// sendEmail sends email and returns an error if something wrong happens.
-func (ss *smtpServiceImpl) sendEmail(email *Email) error {
+func (sb *SmtpBiz) sendEmail(email *model.Email) error {
msg := gomail.NewMessage()
- msg.SetHeader("From", ss.user)
+ msg.SetHeader("From", sb.user)
msg.SetHeader("To", email.To...)
msg.SetHeader("Subject", email.Subject)
msg.SetBody(email.BodyType, email.Body)
- return gomail.NewDialer(ss.host, ss.port, ss.user, ss.password).DialAndSend(msg)
+ return gomail.NewDialer(sb.host, sb.port, sb.user, sb.password).DialAndSend(msg)
}
// SendEmail sends email to somewhere.
-func (ss *smtpServiceImpl) SendEmail(ctx context.Context, email *Email, options *SendEmailOptions) error {
+func (sb *SmtpBiz) SendEmail(ctx context.Context, email *model.Email, options *model.SendEmailOptions) error {
logger := logit.FromContext(ctx)
if options == nil {
- options = DefaultSendEmailOptions()
+ options = model.DefaultSendEmailOptions()
logger.Debug("options is nil, using DefaultSendEmailOptions()").Any("options", options).End()
}
ctx, cancel := context.WithTimeout(ctx, options.Timeout)
defer cancel()
- errorCh := ss.pool.Go(ctx, func(ctx context.Context) error { return ss.sendEmail(email) })
+ errorCh := sb.pool.Go(ctx, func(ctx context.Context) error { return sb.sendEmail(email) })
if options.Async {
return nil
}
@@ -67,13 +69,13 @@ func (ss *smtpServiceImpl) SendEmail(ctx context.Context, email *Email, options
case e := <-errorCh:
if e != nil {
logger.Error("send email failed").Error("e", e).End()
- return errSendEmailFailed
+ return errors.SendEmailFailedErr(e)
}
case <-ctx.Done():
e := ctx.Err()
if e != nil {
logger.Error("send email timeout").Error("e", e).End()
- return errSendTimeout
+ return errors.SendTimeoutErr(e)
}
}
return nil
diff --git a/internal/postard/service/smtp_test.go b/internal/postard/biz/smtp_test.go
similarity index 78%
rename from internal/postard/service/smtp_test.go
rename to internal/postard/biz/smtp_test.go
index e4a2615..d4c7677 100644
--- a/internal/postard/service/smtp_test.go
+++ b/internal/postard/biz/smtp_test.go
@@ -6,7 +6,7 @@
// Email: fishgoddess@qq.com
// Created at 2021/09/22 00:24:19
-package service
+package biz
import (
"context"
@@ -15,11 +15,12 @@ import (
"testing"
"time"
- "github.com/avino-plan/postar/internal/pkg/concurrency"
+ "github.com/avino-plan/postar/internal/postard/model"
+ "github.com/avino-plan/postar/pkg/concurrency"
)
-// go test -v -cover -run=^TestNewSmtpService$
-func TestNewSmtpService(t *testing.T) {
+// go test -v -cover -run=^TestSmtpBiz$
+func TestSmtpBiz(t *testing.T) {
host := os.Getenv("POSTAR_SMTP_HOST")
user := os.Getenv("POSTAR_SMTP_USER")
password := os.Getenv("POSTAR_SMTP_PASSWORD")
@@ -37,12 +38,12 @@ func TestNewSmtpService(t *testing.T) {
defer pool.Stop()
smtpService := NewSmtpService(pool, host, int(port), user, password)
- err = smtpService.SendEmail(context.Background(), &Email{
+ err = smtpService.SendEmail(context.Background(), &model.Email{
To: []string{to},
Subject: t.Name(),
BodyType: "text/html;charset=utf-8",
Body: t.Name() + time.Now().Format("20060102150405.000"),
- }, DefaultSendEmailOptions())
+ }, model.DefaultSendEmailOptions())
if err != nil {
t.Error(err)
}
diff --git a/internal/postard/service/service.go b/internal/postard/model/smtp.go
similarity index 64%
rename from internal/postard/service/service.go
rename to internal/postard/model/smtp.go
index 63bf45f..d783b32 100644
--- a/internal/postard/service/service.go
+++ b/internal/postard/model/smtp.go
@@ -6,12 +6,9 @@
// Email: fishgoddess@qq.com
// Created at 2021/09/17 00:06:09
-package service
+package model
-import (
- "context"
- "time"
-)
+import "time"
// Email is an email.
type Email struct {
@@ -27,18 +24,6 @@ type SendEmailOptions struct {
Timeout time.Duration // The timeout of sending one email.
}
-// ContextService is the service of context
-type ContextService interface {
- // WrapContext wraps context with something and returns a new context.
- WrapContext(ctx context.Context) context.Context
-}
-
-// SmtpService is the service of smtp.
-type SmtpService interface {
- // SendEmail sends email with options and returns an error if something wrong happens.
- SendEmail(ctx context.Context, email *Email, options *SendEmailOptions) error
-}
-
// DefaultSendEmailOptions returns a default options for sending emails.
func DefaultSendEmailOptions() *SendEmailOptions {
return &SendEmailOptions{
diff --git a/internal/postard/server/grpc.go b/internal/postard/server/grpc.go
index 409f0e8..4204179 100644
--- a/internal/postard/server/grpc.go
+++ b/internal/postard/server/grpc.go
@@ -12,64 +12,67 @@ import (
"context"
"net"
- "github.com/avino-plan/postar/api/postard"
- "github.com/avino-plan/postar/internal/pkg/trace"
- "github.com/avino-plan/postar/internal/postard/service"
+ "github.com/FishGoddess/logit"
+ "github.com/avino-plan/postar/api"
+ "github.com/avino-plan/postar/internal/postard/biz"
+ "github.com/avino-plan/postar/pkg/errors"
+ "github.com/avino-plan/postar/pkg/trace"
"google.golang.org/grpc"
)
-// PostardGrpcServer is a grpc implement of PostardServer.
-type PostardGrpcServer struct {
- postard.UnimplementedPostardServer
- server *grpc.Server
- contextService service.ContextService
- smtpService service.SmtpService
+// GRPCServer is a grpc implement of PostardServer.
+type GRPCServer struct {
+ api.UnimplementedPostardServer
+ server *grpc.Server
+ logger *logit.Logger
+ smtpBiz *biz.SmtpBiz
}
-// NewPostardGrpcServer returns a new PostardGrpcServer.
-func NewPostardGrpcServer(contextService service.ContextService, smtpService service.SmtpService) *PostardGrpcServer {
- return &PostardGrpcServer{
- contextService: contextService,
- smtpService: smtpService,
+// NewGrpcServer returns a new GRPCServer.
+func NewGrpcServer(logger *logit.Logger, smtpBiz *biz.SmtpBiz) *GRPCServer {
+ return &GRPCServer{
+ logger: logger,
+ smtpBiz: smtpBiz,
}
}
// SendEmail sends emails.
-func (pgs *PostardGrpcServer) SendEmail(ctx context.Context, request *postard.SendEmailRequest) (*postard.PostardResponse, error) {
- ctx = pgs.contextService.WrapContext(ctx)
- traceId := trace.FromContext(ctx)
+func (gs *GRPCServer) SendEmail(ctx context.Context, request *api.SendEmailRequest) (*api.PostardResponse, error) {
+ traceID := trace.NewTraceID()
+ ctx = trace.NewContext(ctx, traceID)
+ ctx = logit.NewContext(ctx, gs.logger)
- err := pgs.smtpService.SendEmail(ctx, nil, nil)
- if service.IsSendTimeout(err) {
- return &postard.PostardResponse{
- Code: postard.ResponseCodes_TimeoutError,
+ err := gs.smtpBiz.SendEmail(ctx, nil, nil)
+ if errors.IsSendTimeout(err) {
+ return &api.PostardResponse{
+ Code: api.ResponseCodes_TimeoutError,
Msg: "send email timeout",
- TraceId: traceId,
+ TraceId: traceID,
}, nil
}
if err != nil {
- return &postard.PostardResponse{
- Code: postard.ResponseCodes_InternalServerError,
+ return &api.PostardResponse{
+ Code: api.ResponseCodes_InternalServerError,
Msg: "send email failed",
- TraceId: traceId,
+ TraceId: traceID,
}, nil
}
- return &postard.PostardResponse{
- Code: postard.ResponseCodes_OK,
- TraceId: traceId,
+ return &api.PostardResponse{
+ Code: api.ResponseCodes_OK,
+ TraceId: traceID,
}, nil
}
-// Run runs PostardGrpcServer with listener.
-func (pgs *PostardGrpcServer) Run(listener net.Listener) error {
- pgs.server = grpc.NewServer()
- postard.RegisterPostardServer(pgs.server, pgs)
- return pgs.server.Serve(listener)
+// Run runs GRPCServer with listener.
+func (gs *GRPCServer) Run(listener net.Listener) error {
+ gs.server = grpc.NewServer()
+ api.RegisterPostardServer(gs.server, gs)
+ return gs.server.Serve(listener)
}
-// Shutdown shutdowns PostardGrpcServer gracefully.
-func (pgs *PostardGrpcServer) Shutdown() {
- pgs.server.GracefulStop()
+// Shutdown shutdowns GRPCServer gracefully.
+func (gs *GRPCServer) Shutdown() {
+ gs.server.GracefulStop()
}
diff --git a/internal/postard/server/http.go b/internal/postard/server/http.go
index 3665780..ebe1a1a 100644
--- a/internal/postard/server/http.go
+++ b/internal/postard/server/http.go
@@ -7,3 +7,5 @@
// Created at 2021/09/16 02:04:54
package server
+
+// TODO http server
diff --git a/internal/postard/server/udp.go b/internal/postard/server/udp.go
new file mode 100644
index 0000000..a58f00c
--- /dev/null
+++ b/internal/postard/server/udp.go
@@ -0,0 +1,11 @@
+// Copyright 2022 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2022/01/17 00:59:20
+
+package server
+
+// TODO udp server
diff --git a/internal/postard/server/vex.go b/internal/postard/server/vex.go
new file mode 100644
index 0000000..9a4e973
--- /dev/null
+++ b/internal/postard/server/vex.go
@@ -0,0 +1,11 @@
+// Copyright 2022 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2022/01/17 00:56:29
+
+package server
+
+// TODO vex server
diff --git a/internal/postard/service/context.go b/internal/postard/service/context.go
deleted file mode 100644
index 1b85ac6..0000000
--- a/internal/postard/service/context.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/09/27 22:40:58
-
-package service
-
-import (
- "context"
-
- "github.com/FishGoddess/logit"
- "github.com/avino-plan/postar/internal/pkg/trace"
-)
-
-// contextServiceImpl is the service of context.
-type contextServiceImpl struct {
- logger *logit.Logger
-}
-
-// NewContextService returns a new ContextService.
-func NewContextService(logger *logit.Logger) ContextService {
- return &contextServiceImpl{logger: logger}
-}
-
-// WrapContext wraps context with something and returns a new context.
-func (csi *contextServiceImpl) WrapContext(ctx context.Context) context.Context {
- ctx = logit.NewContext(ctx, csi.logger)
- return trace.WithContext(ctx)
-}
diff --git a/internal/postard/service/error.go b/internal/postard/service/error.go
deleted file mode 100644
index ee1d22f..0000000
--- a/internal/postard/service/error.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/09/25 21:58:02
-
-package service
-
-import "errors"
-
-var (
- errSendTimeout = errors.New("postard/service: send timeout") // Send timeout
- errSendEmailFailed = errors.New("postard/service: send email failed") // Send email failed
-)
-
-// IsSendTimeout returns if err equals to errSendTimeout.
-func IsSendTimeout(err error) bool {
- return errors.Is(err, errSendTimeout)
-}
-
-// IsSendEmailFailed returns if err equals to errSendEmailFailed.
-func IsSendEmailFailed(err error) bool {
- return errors.Is(err, errSendEmailFailed)
-}
diff --git a/internal/postard/service/service_test.go b/internal/postard/service/service_test.go
deleted file mode 100644
index a5dab9f..0000000
--- a/internal/postard/service/service_test.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/09/22 00:22:39
-
-package service
-
-import "testing"
-
-// go test -v -cover -run=^TestContextService$
-func TestContextService(t *testing.T) {
- // do nothing...
-}
-
-// go test -v -cover -run=^TestSmtpService$
-func TestSmtpService(t *testing.T) {
- // do nothing...
-}
diff --git a/internal/pkg/concurrency/pool.go b/pkg/concurrency/pool.go
similarity index 100%
rename from internal/pkg/concurrency/pool.go
rename to pkg/concurrency/pool.go
diff --git a/internal/pkg/concurrency/pool_test.go b/pkg/concurrency/pool_test.go
similarity index 100%
rename from internal/pkg/concurrency/pool_test.go
rename to pkg/concurrency/pool_test.go
diff --git a/pkg/context/context.go b/pkg/context/context.go
new file mode 100644
index 0000000..b0aa994
--- /dev/null
+++ b/pkg/context/context.go
@@ -0,0 +1,29 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/27 22:40:58
+
+package context
+
+import (
+ "context"
+
+ "github.com/FishGoddess/logit"
+ "github.com/avino-plan/postar/pkg/trace"
+)
+
+// WithLogger wraps ctx with logger.
+func WithLogger(ctx context.Context, logger *logit.Logger) context.Context {
+ return logit.NewContext(ctx, logger)
+}
+
+// WithTraceID wraps ctx with traceID.
+func WithTraceID(ctx context.Context, traceID string) context.Context {
+ if traceID == "" {
+ traceID = trace.NewTraceID()
+ }
+ return trace.NewContext(ctx, traceID)
+}
diff --git a/internal/postard/service/context_test.go b/pkg/context/context_test.go
similarity index 64%
rename from internal/postard/service/context_test.go
rename to pkg/context/context_test.go
index 1067e6b..cad2cdc 100644
--- a/internal/postard/service/context_test.go
+++ b/pkg/context/context_test.go
@@ -6,28 +6,29 @@
// Email: fishgoddess@qq.com
// Created at 2021/09/27 22:50:56
-package service
+package context
import (
"context"
"testing"
"github.com/FishGoddess/logit"
- "github.com/avino-plan/postar/internal/pkg/trace"
+ "github.com/avino-plan/postar/pkg/trace"
)
-// go test -v -cover -run=^TestNewContextService$
-func TestNewContextService(t *testing.T) {
+// go test -v -cover -run=^TestWithLogger$
+func TestWithLogger(t *testing.T) {
logger := logit.NewLogger()
-
- service := NewContextService(logger)
- ctx := service.WrapContext(context.Background())
-
+ ctx := WithLogger(context.Background(), logger)
contextLogger := logit.FromContext(ctx)
if contextLogger != logger {
t.Errorf("contextLogger %+v != logger %+v", contextLogger, logger)
}
+}
+// go test -v -cover -run=^TestWithTraceID$
+func TestWithTraceID(t *testing.T) {
+ ctx := WithTraceID(context.Background())
traceId := trace.FromContext(ctx)
if traceId == "" {
t.Error("traceId == ''")
diff --git a/internal/pkg/trace/encode.go b/pkg/encode/encode.go
similarity index 60%
rename from internal/pkg/trace/encode.go
rename to pkg/encode/encode.go
index 8c14333..f6e8609 100644
--- a/internal/pkg/trace/encode.go
+++ b/pkg/encode/encode.go
@@ -6,18 +6,19 @@
// Email: fishgoddess@qq.com
// Created at 2021/09/25 22:39:17
-package trace
+package encode
import (
"encoding/binary"
"fmt"
"math/rand"
"os"
+ "strconv"
"time"
)
var (
- // letters includes 0-9 a-z A-Z.
+ // letters includes 0-9, a-z, A-Z.
letters = [62]byte{
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
@@ -26,25 +27,35 @@ var (
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
}
- // random 用于生成随机数
+ pid = strconv.Itoa(os.Getpid())
random = rand.New(rand.NewSource(time.Now().Unix()))
-
- // pid 是程序的 pid
- pid = uint64(os.Getpid())
)
-// TimeHex returns now time in hex.
-func TimeHex() string {
- b := make([]byte, 8)
- binary.BigEndian.PutUint64(b, uint64(time.Now().Unix()))
- return fmt.Sprintf("%x", b[4:])
+// numberHex returns num in hex string.
+// The hex string will be cut with start and end.
+func numberHex(num uint64, start int, end int) string {
+ size := 8
+ if start < 0 || start > size {
+ start = 0
+ }
+
+ if end <= 0 || end > size {
+ end = size
+ }
+
+ b := make([]byte, size)
+ binary.BigEndian.PutUint64(b, num)
+ return fmt.Sprintf("%x", b[start:end])
+}
+
+// Now returns in current time in hex string.
+func Now() string {
+ return numberHex(uint64(time.Now().Unix()), 4, 0)
}
-// PidHex returns pid in hex.
-func PidHex() string {
- b := make([]byte, 8)
- binary.BigEndian.PutUint64(b, pid)
- return fmt.Sprintf("%x", b[4:])
+// PID returns pid in string.
+func PID() string {
+ return pid
}
// RandomString returns a string including 0-9/a-z/A-Z not longer than length.
diff --git a/internal/pkg/trace/encode_test.go b/pkg/encode/encode_test.go
similarity index 77%
rename from internal/pkg/trace/encode_test.go
rename to pkg/encode/encode_test.go
index 6cebf36..9d23ef0 100644
--- a/internal/pkg/trace/encode_test.go
+++ b/pkg/encode/encode_test.go
@@ -6,13 +6,13 @@
// Email: fishgoddess@qq.com
// Created at 2021/09/25 22:58:39
-package trace
+package encode
import "testing"
-// go test -v -cover -run=^TestTimeHex$
-func TestTimeHex(t *testing.T) {
- timeHex := TimeHex()
+// go test -v -cover -run=^NowTimeHex$
+func TestNowTimeHex(t *testing.T) {
+ timeHex := Now()
if len(timeHex) != 8 {
t.Errorf("length of TimeHex is wrong with %s, %d", timeHex, len(timeHex))
}
@@ -20,9 +20,9 @@ func TestTimeHex(t *testing.T) {
// go test -v -cover -run=^TestPidHex$
func TestPidHex(t *testing.T) {
- pidHex := PidHex()
+ pidHex := PID()
if len(pidHex) != 8 {
- t.Errorf("length of PidHex is wrong with %s, %d", pidHex, len(pidHex))
+ t.Errorf("length of PID is wrong with %s, %d", pidHex, len(pidHex))
}
}
diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go
new file mode 100644
index 0000000..3986fac
--- /dev/null
+++ b/pkg/errors/errors.go
@@ -0,0 +1,114 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/25 21:58:02
+
+package errors
+
+import (
+ "errors"
+ "fmt"
+ "net/http"
+)
+
+const (
+ codeBadRequest = http.StatusBadRequest
+ codeSendTimeout = 1100
+ codeSendEmailFailed = 11000
+)
+
+// Error is error with code.
+type Error struct {
+ err error
+ code int32
+}
+
+// Error returns error message.
+func (e *Error) Error() string {
+ if e == nil || e.err == nil {
+ return ""
+ }
+ return fmt.Sprintf("%d (%s)", e.code, e.err.Error())
+}
+
+// Is returns if e is the target's type.
+func (e *Error) Is(target error) bool {
+ if e == nil {
+ return e == target
+ }
+
+ err, ok := target.(*Error)
+ if !ok {
+ return e.err == target
+ }
+
+ return e.code == err.code
+}
+
+// Unwrap unwraps e.
+func (e *Error) Unwrap() error {
+ if e == nil {
+ return nil
+ }
+ return e.err
+}
+
+// WithCode wraps err with code.
+func WithCode(err error, code int32) error {
+ if err == nil {
+ return nil
+ }
+ return &Error{err: err, code: code}
+}
+
+// Is returns if err has a code and its code equals to code.
+func Is(err error, code int32) bool {
+ for {
+ if err == nil {
+ return false
+ }
+
+ e, ok := err.(*Error)
+ if !ok {
+ return false
+ }
+
+ if e.code == code {
+ return true
+ }
+ err = errors.Unwrap(err)
+ }
+}
+
+// BadRequest returns a bad request error.
+func BadRequest(err error) error {
+ return WithCode(err, codeBadRequest)
+}
+
+// IsBadRequest returns if err is bad request.
+func IsBadRequest(err error) bool {
+ return Is(err, codeBadRequest)
+}
+
+// SendTimeoutErr returns a send timeout error.
+func SendTimeoutErr(err error) error {
+ return WithCode(err, codeSendTimeout)
+}
+
+// IsSendTimeout returns if err is send timeout.
+func IsSendTimeout(err error) bool {
+ return Is(err, codeSendTimeout)
+}
+
+// SendEmailFailedErr returns a send email failed error.
+func SendEmailFailedErr(err error) error {
+ return WithCode(err, codeSendEmailFailed)
+}
+
+// IsSendEmailFailed returns if err is send email failed.
+func IsSendEmailFailed(err error) bool {
+ return Is(err, codeSendEmailFailed)
+}
diff --git a/internal/postard/service/error_test.go b/pkg/errors/errors_test.go
similarity index 98%
rename from internal/postard/service/error_test.go
rename to pkg/errors/errors_test.go
index ddcfbe9..e435dc0 100644
--- a/internal/postard/service/error_test.go
+++ b/pkg/errors/errors_test.go
@@ -6,7 +6,7 @@
// Email: fishgoddess@qq.com
// Created at 2021/09/25 22:06:36
-package service
+package errors
import (
"errors"
diff --git a/pkg/trace/trace.go b/pkg/trace/trace.go
new file mode 100644
index 0000000..525c84c
--- /dev/null
+++ b/pkg/trace/trace.go
@@ -0,0 +1,39 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/25 22:44:59
+
+package trace
+
+import (
+ "context"
+
+ "github.com/avino-plan/postar/pkg/encode"
+)
+
+var (
+ traceIDKey struct{} // The context key of trace id.
+)
+
+// NewTraceID returns a new trace id.
+func NewTraceID() string {
+ salt := encode.RandomString(6)
+ return encode.Now() + salt[:3] + encode.PID() + salt[3:]
+}
+
+// NewContext wraps ctx with a trace id.
+func NewContext(ctx context.Context, traceID string) context.Context {
+ return context.WithValue(ctx, traceIDKey, traceID)
+}
+
+// FromContext gets the trace id from context.
+func FromContext(ctx context.Context) string {
+ traceID, ok := ctx.Value(traceIDKey).(string)
+ if !ok && traceID == "" {
+ return NewTraceID()
+ }
+ return traceID
+}
diff --git a/pkg/trace/trace_test.go b/pkg/trace/trace_test.go
new file mode 100644
index 0000000..06d193d
--- /dev/null
+++ b/pkg/trace/trace_test.go
@@ -0,0 +1,57 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/25 23:07:54
+
+package trace
+
+import (
+ "context"
+ "testing"
+)
+
+// go test -v -cover -run=^TestNewTraceID$
+func TestNewTraceID(t *testing.T) {
+ traceID := NewTraceID()
+ if traceID == "" {
+ t.Error("traceID == ''")
+ }
+
+ t.Log("traceID:", traceID)
+}
+
+// go test -v -cover -run=^TestWithContext$
+func TestWithContext(t *testing.T) {
+ ctx := NewContext(context.Background(), NewTraceID())
+
+ value := ctx.Value(traceIDKey)
+ if value == nil {
+ t.Error("ctx.Value returns nil")
+ }
+
+ traceID, ok := value.(string)
+ if !ok {
+ t.Errorf("value %+v isn't string", value)
+ }
+ t.Log("traceID:", traceID)
+}
+
+// go test -v -cover -run=^TestFromContext$
+func TestFromContext(t *testing.T) {
+ ctx := context.Background()
+ traceIDInCtx := FromContext(ctx)
+ if traceIDInCtx == "" {
+ t.Error("traceIDInCtx == ''")
+ }
+
+ traceID := NewTraceID()
+ ctx = context.WithValue(ctx, traceIDKey, traceID)
+
+ traceIDInCtx = FromContext(ctx)
+ if traceIDInCtx != traceID {
+ t.Errorf("traceIDInCtx %s != traceId %s", traceIDInCtx, traceID)
+ }
+}
From 0d24c88868648ad9c34861c6bd6a3259b2e8f415 Mon Sep 17 00:00:00 2001
From: FishGoddess <1149062639@qq.com>
Date: Sun, 23 Jan 2022 00:52:38 +0800
Subject: [PATCH 10/27] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A4=A7=E9=87=8F?=
=?UTF-8?q?=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
FUTURE.md | 22 +-
README.en.md | 6 +-
README.md | 4 +-
api/api.pb.go | 143 ++++++++++
api/api.proto | 20 ++
api/postard.pb.go | 352 ++++++++++--------------
api/postard.proto | 45 ++-
api/postard_grpc.pb.go | 20 +-
cmd/postard/main.go | 14 +-
go.mod | 6 +-
go.sum | 13 +-
internal/{postard => }/biz/smtp.go | 49 ++--
internal/{postard => }/biz/smtp_test.go | 10 +-
internal/{postard => }/model/smtp.go | 8 +-
internal/{postard => }/server/grpc.go | 24 +-
internal/{postard => }/server/http.go | 0
internal/{postard => }/server/udp.go | 0
internal/{postard => }/server/vex.go | 0
pkg/concurrency/pool.go | 140 ----------
pkg/concurrency/pool_test.go | 42 ---
pkg/context/context.go | 29 --
pkg/context/context_test.go | 36 ---
pkg/encode/encode.go | 14 +-
pkg/encode/encode_test.go | 2 +-
pkg/errors/errors.go | 97 +------
pkg/errors/errors_test.go | 21 +-
pkg/trace/trace.go | 4 +-
27 files changed, 450 insertions(+), 671 deletions(-)
create mode 100644 api/api.pb.go
create mode 100644 api/api.proto
rename internal/{postard => }/biz/smtp.go (55%)
rename internal/{postard => }/biz/smtp_test.go (82%)
rename internal/{postard => }/model/smtp.go (79%)
rename internal/{postard => }/server/grpc.go (75%)
rename internal/{postard => }/server/http.go (100%)
rename internal/{postard => }/server/udp.go (100%)
rename internal/{postard => }/server/vex.go (100%)
delete mode 100644 pkg/concurrency/pool.go
delete mode 100644 pkg/concurrency/pool_test.go
delete mode 100644 pkg/context/context.go
delete mode 100644 pkg/context/context_test.go
diff --git a/FUTURE.md b/FUTURE.md
index 90d7a7c..3614cc7 100644
--- a/FUTURE.md
+++ b/FUTURE.md
@@ -2,10 +2,18 @@
### Future versions
-* 支持邮件中携带附件 (P0)
-* dialer 对象池或连接池优化 (P1)
-* 邮件发送信息监控平台 (P2)
-* 增加 Vex 远程调用接口 (P3)
-* 增加 JsonRPC 远程调用接口 (P3)
-* 增加 UDP 远程调用接口 (P3)
-* 增加 WebSocket 远程调用接口 (P3)
+* [ ] dialer 对象池或连接池优化 (P0)
+* [ ] 增加 net/rpc 远程调用接口 (P1)
+
+### v0.2.x
+
+* [ ] 支持邮件中携带附件 (P0)
+* [ ] 接入监控平台 (P0)
+* [ ] 增加 http 远程调用接口 (P0)
+* [x] 增加 grpc 远程调用接口 (P0)
+* [ ] 增加 vex 远程调用接口 (P1)
+* [ ] 增加 udp 远程调用接口 (P2)
+
+### v0.1.x
+
+* [x] 邮件发送功能
diff --git a/README.en.md b/README.en.md
index c5914e5..f190ee8 100644
--- a/README.en.md
+++ b/README.en.md
@@ -43,6 +43,6 @@ If you find that something is not working as expected please open an _**issue**_
### 📦 Projects postar used
-| Project | Author | Description | link |
-| -----------|--------|-------------|------------------|
-| logit | FishGoddess | A high-performance and easy-to-use logging foundation | [Gitee](https://gitee.com/FishGoddess/logit) / [GitHub](https://github.com/FishGoddess/logit) |
+| Project | Author | Description | link |
+|---------|-------------|-------------------------------------------------------|-----------------------------------------------------------------------------------------------|
+| logit | FishGoddess | A high-performance and easy-to-use logging foundation | [Gitee](https://gitee.com/FishGoddess/logit) / [GitHub](https://github.com/FishGoddess/logit) |
diff --git a/README.md b/README.md
index 377032d..112cd74 100644
--- a/README.md
+++ b/README.md
@@ -43,7 +43,7 @@ _注意:默认的配置文件路径是 `/opt/postar/conf/postar.ini`,默认
### 📦 postar 使用的技术
-| 项目 | 作者 | 描述 | 链接 |
-| -----------|--------|-------------|-------------------|
+| 项目 | 作者 | 描述 | 链接 |
+|-------|-------------|---------------------|--------------------------------------------------------------------------------------------|
| logit | FishGoddess | 一个高性能、功能强大且极易上手的日志库 | [码云](https://gitee.com/FishGoddess/logit) / [GitHub](https://github.com/FishGoddess/logit) |
diff --git a/api/api.pb.go b/api/api.pb.go
new file mode 100644
index 0000000..9de5b13
--- /dev/null
+++ b/api/api.pb.go
@@ -0,0 +1,143 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/16 01:42:33
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.27.1
+// protoc v3.18.0
+// source: api.proto
+
+package api
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// ResponseCodes is all codes of response.
+type ServerCode int32
+
+const (
+ ServerCode_OK ServerCode = 0
+ ServerCode_TIMEOUT ServerCode = 429
+ ServerCode_SEND_EMAIL_FAILED ServerCode = 11000
+)
+
+// Enum value maps for ServerCode.
+var (
+ ServerCode_name = map[int32]string{
+ 0: "OK",
+ 429: "TIMEOUT",
+ 11000: "SEND_EMAIL_FAILED",
+ }
+ ServerCode_value = map[string]int32{
+ "OK": 0,
+ "TIMEOUT": 429,
+ "SEND_EMAIL_FAILED": 11000,
+ }
+)
+
+func (x ServerCode) Enum() *ServerCode {
+ p := new(ServerCode)
+ *p = x
+ return p
+}
+
+func (x ServerCode) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (ServerCode) Descriptor() protoreflect.EnumDescriptor {
+ return file_api_proto_enumTypes[0].Descriptor()
+}
+
+func (ServerCode) Type() protoreflect.EnumType {
+ return &file_api_proto_enumTypes[0]
+}
+
+func (x ServerCode) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use ServerCode.Descriptor instead.
+func (ServerCode) EnumDescriptor() ([]byte, []int) {
+ return file_api_proto_rawDescGZIP(), []int{0}
+}
+
+var File_api_proto protoreflect.FileDescriptor
+
+var file_api_proto_rawDesc = []byte{
+ 0x0a, 0x09, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1f, 0x67, 0x69, 0x74,
+ 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61,
+ 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2a, 0x3a, 0x0a, 0x0a,
+ 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b,
+ 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x07, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0xad, 0x03,
+ 0x12, 0x16, 0x0a, 0x11, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x45, 0x4d, 0x41, 0x49, 0x4c, 0x5f, 0x46,
+ 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0xf8, 0x55, 0x42, 0x21, 0x5a, 0x1f, 0x67, 0x69, 0x74, 0x68,
+ 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e,
+ 0x2f, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_api_proto_rawDescOnce sync.Once
+ file_api_proto_rawDescData = file_api_proto_rawDesc
+)
+
+func file_api_proto_rawDescGZIP() []byte {
+ file_api_proto_rawDescOnce.Do(func() {
+ file_api_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_proto_rawDescData)
+ })
+ return file_api_proto_rawDescData
+}
+
+var file_api_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_api_proto_goTypes = []interface{}{
+ (ServerCode)(0), // 0: github.com.avinoplan.postar.api.ServerCode
+}
+var file_api_proto_depIdxs = []int32{
+ 0, // [0:0] is the sub-list for method output_type
+ 0, // [0:0] is the sub-list for method input_type
+ 0, // [0:0] is the sub-list for extension type_name
+ 0, // [0:0] is the sub-list for extension extendee
+ 0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_api_proto_init() }
+func file_api_proto_init() {
+ if File_api_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_api_proto_rawDesc,
+ NumEnums: 1,
+ NumMessages: 0,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_api_proto_goTypes,
+ DependencyIndexes: file_api_proto_depIdxs,
+ EnumInfos: file_api_proto_enumTypes,
+ }.Build()
+ File_api_proto = out.File
+ file_api_proto_rawDesc = nil
+ file_api_proto_goTypes = nil
+ file_api_proto_depIdxs = nil
+}
diff --git a/api/api.proto b/api/api.proto
new file mode 100644
index 0000000..be567c5
--- /dev/null
+++ b/api/api.proto
@@ -0,0 +1,20 @@
+// Copyright 2021 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2021/09/16 01:42:33
+
+syntax = "proto3";
+package github.com.avinoplan.postar.api;
+
+// protoc -I=. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative api.proto
+option go_package = "github.com/avinoplan/postar/api";
+
+// ResponseCodes is all codes of response.
+enum ServerCode {
+ OK = 0;
+ TIMEOUT = 429;
+ SEND_EMAIL_FAILED = 11000;
+}
diff --git a/api/postard.pb.go b/api/postard.pb.go
index 5bb79f1..86d17ff 100644
--- a/api/postard.pb.go
+++ b/api/postard.pb.go
@@ -17,7 +17,6 @@ package api
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- anypb "google.golang.org/protobuf/types/known/anypb"
reflect "reflect"
sync "sync"
)
@@ -29,70 +28,20 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
-// ResponseCodes is all codes of response.
-type ResponseCodes int32
-
-const (
- ResponseCodes_OK ResponseCodes = 0
- ResponseCodes_InternalServerError ResponseCodes = 50000
- ResponseCodes_TimeoutError ResponseCodes = 50001
-)
-
-// Enum value maps for ResponseCodes.
-var (
- ResponseCodes_name = map[int32]string{
- 0: "OK",
- 50000: "InternalServerError",
- 50001: "TimeoutError",
- }
- ResponseCodes_value = map[string]int32{
- "OK": 0,
- "InternalServerError": 50000,
- "TimeoutError": 50001,
- }
-)
-
-func (x ResponseCodes) Enum() *ResponseCodes {
- p := new(ResponseCodes)
- *p = x
- return p
-}
-
-func (x ResponseCodes) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (ResponseCodes) Descriptor() protoreflect.EnumDescriptor {
- return file_postard_proto_enumTypes[0].Descriptor()
-}
-
-func (ResponseCodes) Type() protoreflect.EnumType {
- return &file_postard_proto_enumTypes[0]
-}
-
-func (x ResponseCodes) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Use ResponseCodes.Descriptor instead.
-func (ResponseCodes) EnumDescriptor() ([]byte, []int) {
- return file_postard_proto_rawDescGZIP(), []int{0}
-}
-
-// PostardResponse is the response of Postard.
-type PostardResponse struct {
+// Email wraps all information of using smtp service.
+type Email struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- Code ResponseCodes `protobuf:"varint,1,opt,name=code,proto3,enum=github.com.avinoplan.postar.api.ResponseCodes" json:"code,omitempty"` // 0 is ok.
- Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` // For messaging.
- TraceId string `protobuf:"bytes,3,opt,name=traceId,proto3" json:"traceId,omitempty"` // For tracing.
- Data *anypb.Any `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"` // Any data.
+ Receivers []string `protobuf:"bytes,1,rep,name=receivers,proto3" json:"receivers,omitempty"` // Receivers.
+ Subject string `protobuf:"bytes,2,opt,name=subject,proto3" json:"subject,omitempty"` // Subject.
+ BodyType string `protobuf:"bytes,3,opt,name=body_type,json=bodyType,proto3" json:"body_type,omitempty"` // Body type.
+ Body string `protobuf:"bytes,4,opt,name=body,proto3" json:"body,omitempty"` // Body.
}
-func (x *PostardResponse) Reset() {
- *x = PostardResponse{}
+func (x *Email) Reset() {
+ *x = Email{}
if protoimpl.UnsafeEnabled {
mi := &file_postard_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -100,13 +49,13 @@ func (x *PostardResponse) Reset() {
}
}
-func (x *PostardResponse) String() string {
+func (x *Email) String() string {
return protoimpl.X.MessageStringOf(x)
}
-func (*PostardResponse) ProtoMessage() {}
+func (*Email) ProtoMessage() {}
-func (x *PostardResponse) ProtoReflect() protoreflect.Message {
+func (x *Email) ProtoReflect() protoreflect.Message {
mi := &file_postard_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -118,53 +67,51 @@ func (x *PostardResponse) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x)
}
-// Deprecated: Use PostardResponse.ProtoReflect.Descriptor instead.
-func (*PostardResponse) Descriptor() ([]byte, []int) {
+// Deprecated: Use Email.ProtoReflect.Descriptor instead.
+func (*Email) Descriptor() ([]byte, []int) {
return file_postard_proto_rawDescGZIP(), []int{0}
}
-func (x *PostardResponse) GetCode() ResponseCodes {
+func (x *Email) GetReceivers() []string {
if x != nil {
- return x.Code
+ return x.Receivers
}
- return ResponseCodes_OK
+ return nil
}
-func (x *PostardResponse) GetMsg() string {
+func (x *Email) GetSubject() string {
if x != nil {
- return x.Msg
+ return x.Subject
}
return ""
}
-func (x *PostardResponse) GetTraceId() string {
+func (x *Email) GetBodyType() string {
if x != nil {
- return x.TraceId
+ return x.BodyType
}
return ""
}
-func (x *PostardResponse) GetData() *anypb.Any {
+func (x *Email) GetBody() string {
if x != nil {
- return x.Data
+ return x.Body
}
- return nil
+ return ""
}
-// Email wraps all information of using smtp biz.
-type Email struct {
+// SendEmailOptions is the options of sending emails.
+type SendEmailOptions struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- To []string `protobuf:"bytes,1,rep,name=to,proto3" json:"to,omitempty"` // The receivers of one email.
- Subject string `protobuf:"bytes,2,opt,name=subject,proto3" json:"subject,omitempty"` // The subject of one email.
- BodyType string `protobuf:"bytes,3,opt,name=bodyType,proto3" json:"bodyType,omitempty"` // The content type of body.
- Body string `protobuf:"bytes,4,opt,name=body,proto3" json:"body,omitempty"` // The body of one email.
+ Async bool `protobuf:"varint,1,opt,name=async,proto3" json:"async,omitempty"` // Sending this email asynchronously.
+ Timeout int32 `protobuf:"varint,2,opt,name=timeout,proto3" json:"timeout,omitempty"` // Sending timeout in seconds.
}
-func (x *Email) Reset() {
- *x = Email{}
+func (x *SendEmailOptions) Reset() {
+ *x = SendEmailOptions{}
if protoimpl.UnsafeEnabled {
mi := &file_postard_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -172,13 +119,13 @@ func (x *Email) Reset() {
}
}
-func (x *Email) String() string {
+func (x *SendEmailOptions) String() string {
return protoimpl.X.MessageStringOf(x)
}
-func (*Email) ProtoMessage() {}
+func (*SendEmailOptions) ProtoMessage() {}
-func (x *Email) ProtoReflect() protoreflect.Message {
+func (x *SendEmailOptions) ProtoReflect() protoreflect.Message {
mi := &file_postard_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -190,51 +137,37 @@ func (x *Email) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x)
}
-// Deprecated: Use Email.ProtoReflect.Descriptor instead.
-func (*Email) Descriptor() ([]byte, []int) {
+// Deprecated: Use SendEmailOptions.ProtoReflect.Descriptor instead.
+func (*SendEmailOptions) Descriptor() ([]byte, []int) {
return file_postard_proto_rawDescGZIP(), []int{1}
}
-func (x *Email) GetTo() []string {
- if x != nil {
- return x.To
- }
- return nil
-}
-
-func (x *Email) GetSubject() string {
- if x != nil {
- return x.Subject
- }
- return ""
-}
-
-func (x *Email) GetBodyType() string {
+func (x *SendEmailOptions) GetAsync() bool {
if x != nil {
- return x.BodyType
+ return x.Async
}
- return ""
+ return false
}
-func (x *Email) GetBody() string {
+func (x *SendEmailOptions) GetTimeout() int32 {
if x != nil {
- return x.Body
+ return x.Timeout
}
- return ""
+ return 0
}
-// SendEmailOptions is the options of sending emails.
-type SendEmailOptions struct {
+// SendEmailRequest is the request of SendEmail.
+type SendEmailRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- Async bool `protobuf:"varint,1,opt,name=async,proto3" json:"async,omitempty"` // If need sending emails asynchronously.
- Timeout int64 `protobuf:"varint,2,opt,name=timeout,proto3" json:"timeout,omitempty"` // Sending timeout.
+ Email *Email `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` // Sending email.
+ Options *SendEmailOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` // Sending options.
}
-func (x *SendEmailOptions) Reset() {
- *x = SendEmailOptions{}
+func (x *SendEmailRequest) Reset() {
+ *x = SendEmailRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_postard_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -242,13 +175,13 @@ func (x *SendEmailOptions) Reset() {
}
}
-func (x *SendEmailOptions) String() string {
+func (x *SendEmailRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
-func (*SendEmailOptions) ProtoMessage() {}
+func (*SendEmailRequest) ProtoMessage() {}
-func (x *SendEmailOptions) ProtoReflect() protoreflect.Message {
+func (x *SendEmailRequest) ProtoReflect() protoreflect.Message {
mi := &file_postard_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -260,37 +193,38 @@ func (x *SendEmailOptions) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x)
}
-// Deprecated: Use SendEmailOptions.ProtoReflect.Descriptor instead.
-func (*SendEmailOptions) Descriptor() ([]byte, []int) {
+// Deprecated: Use SendEmailRequest.ProtoReflect.Descriptor instead.
+func (*SendEmailRequest) Descriptor() ([]byte, []int) {
return file_postard_proto_rawDescGZIP(), []int{2}
}
-func (x *SendEmailOptions) GetAsync() bool {
+func (x *SendEmailRequest) GetEmail() *Email {
if x != nil {
- return x.Async
+ return x.Email
}
- return false
+ return nil
}
-func (x *SendEmailOptions) GetTimeout() int64 {
+func (x *SendEmailRequest) GetOptions() *SendEmailOptions {
if x != nil {
- return x.Timeout
+ return x.Options
}
- return 0
+ return nil
}
-// SendEmailRequest is the request of SendEmail.
-type SendEmailRequest struct {
+// SendEmailResponse is the response of SendEmail.
+type SendEmailResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- Email *Email `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` // Sending email.
- Options *SendEmailOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` // Sending options.
+ Code ServerCode `protobuf:"varint,1,opt,name=code,proto3,enum=github.com.avinoplan.postar.api.ServerCode" json:"code,omitempty"` // 0 is ok.
+ Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` // For messaging.
+ TraceId string `protobuf:"bytes,3,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"` // For tracing.
}
-func (x *SendEmailRequest) Reset() {
- *x = SendEmailRequest{}
+func (x *SendEmailResponse) Reset() {
+ *x = SendEmailResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_postard_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -298,13 +232,13 @@ func (x *SendEmailRequest) Reset() {
}
}
-func (x *SendEmailRequest) String() string {
+func (x *SendEmailResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
-func (*SendEmailRequest) ProtoMessage() {}
+func (*SendEmailResponse) ProtoMessage() {}
-func (x *SendEmailRequest) ProtoReflect() protoreflect.Message {
+func (x *SendEmailResponse) ProtoReflect() protoreflect.Message {
mi := &file_postard_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -316,23 +250,30 @@ func (x *SendEmailRequest) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x)
}
-// Deprecated: Use SendEmailRequest.ProtoReflect.Descriptor instead.
-func (*SendEmailRequest) Descriptor() ([]byte, []int) {
+// Deprecated: Use SendEmailResponse.ProtoReflect.Descriptor instead.
+func (*SendEmailResponse) Descriptor() ([]byte, []int) {
return file_postard_proto_rawDescGZIP(), []int{3}
}
-func (x *SendEmailRequest) GetEmail() *Email {
+func (x *SendEmailResponse) GetCode() ServerCode {
if x != nil {
- return x.Email
+ return x.Code
}
- return nil
+ return ServerCode_OK
}
-func (x *SendEmailRequest) GetOptions() *SendEmailOptions {
+func (x *SendEmailResponse) GetMsg() string {
if x != nil {
- return x.Options
+ return x.Msg
}
- return nil
+ return ""
+}
+
+func (x *SendEmailResponse) GetTraceId() string {
+ if x != nil {
+ return x.TraceId
+ }
+ return ""
}
var File_postard_proto protoreflect.FileDescriptor
@@ -341,55 +282,47 @@ var file_postard_proto_rawDesc = []byte{
0x0a, 0x0d, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
0x1f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e,
0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69,
- 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
- 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xab, 0x01, 0x0a, 0x0f,
- 0x50, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
- 0x42, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e,
+ 0x1a, 0x09, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x70, 0x0a, 0x05, 0x45,
+ 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72,
+ 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
+ 0x72, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1b, 0x0a, 0x09,
+ 0x62, 0x6f, 0x64, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x08, 0x62, 0x6f, 0x64, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64,
+ 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x42, 0x0a,
+ 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f,
+ 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75,
+ 0x74, 0x22, 0x9d, 0x01, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73,
+ 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x05, 0x65,
+ 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x4b, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73,
+ 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69,
+ 0x6c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x22, 0x81, 0x01, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73,
+ 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f,
+ 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x72,
+ 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x72,
+ 0x61, 0x63, 0x65, 0x49, 0x64, 0x32, 0x7d, 0x0a, 0x07, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64,
+ 0x12, 0x72, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x31, 0x2e,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f,
0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
- 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x04, 0x63,
- 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x61, 0x63, 0x65, 0x49, 0x64,
- 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x72, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12,
- 0x28, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e,
- 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
- 0x41, 0x6e, 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x61, 0x0a, 0x05, 0x45, 0x6d, 0x61,
- 0x69, 0x6c, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x02,
- 0x74, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08,
- 0x62, 0x6f, 0x64, 0x79, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
- 0x62, 0x6f, 0x64, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79,
- 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x42, 0x0a, 0x10,
- 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
- 0x12, 0x14, 0x0a, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
- 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75,
- 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
- 0x22, 0x9d, 0x01, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65,
- 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01,
- 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
- 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74,
- 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x05, 0x65, 0x6d,
- 0x61, 0x69, 0x6c, 0x12, 0x4b, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02,
- 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
- 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74,
- 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c,
- 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
- 0x2a, 0x46, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x64, 0x65,
- 0x73, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x13, 0x49, 0x6e, 0x74,
- 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x72, 0x72, 0x6f, 0x72,
- 0x10, 0xd0, 0x86, 0x03, 0x12, 0x12, 0x0a, 0x0c, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x45,
- 0x72, 0x72, 0x6f, 0x72, 0x10, 0xd1, 0x86, 0x03, 0x32, 0x7b, 0x0a, 0x07, 0x50, 0x6f, 0x73, 0x74,
- 0x61, 0x72, 0x64, 0x12, 0x70, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c,
- 0x12, 0x31, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76,
+ 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x1a, 0x32, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76,
0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61,
- 0x70, 0x69, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75,
- 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
- 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61,
- 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73,
- 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x22, 0x5a, 0x20, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
- 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x2d, 0x70, 0x6c, 0x61, 0x6e, 0x2f, 0x70,
- 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
- 0x33,
+ 0x70, 0x69, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x21, 0x5a, 0x1f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2f, 0x70, 0x6f, 0x73,
+ 0x74, 0x61, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -404,28 +337,25 @@ func file_postard_proto_rawDescGZIP() []byte {
return file_postard_proto_rawDescData
}
-var file_postard_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_postard_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_postard_proto_goTypes = []interface{}{
- (ResponseCodes)(0), // 0: github.com.avinoplan.postar.api.ResponseCodes
- (*PostardResponse)(nil), // 1: github.com.avinoplan.postar.api.PostardResponse
- (*Email)(nil), // 2: github.com.avinoplan.postar.api.Email
- (*SendEmailOptions)(nil), // 3: github.com.avinoplan.postar.api.SendEmailOptions
- (*SendEmailRequest)(nil), // 4: github.com.avinoplan.postar.api.SendEmailRequest
- (*anypb.Any)(nil), // 5: google.protobuf.Any
+ (*Email)(nil), // 0: github.com.avinoplan.postar.api.Email
+ (*SendEmailOptions)(nil), // 1: github.com.avinoplan.postar.api.SendEmailOptions
+ (*SendEmailRequest)(nil), // 2: github.com.avinoplan.postar.api.SendEmailRequest
+ (*SendEmailResponse)(nil), // 3: github.com.avinoplan.postar.api.SendEmailResponse
+ (ServerCode)(0), // 4: github.com.avinoplan.postar.api.ServerCode
}
var file_postard_proto_depIdxs = []int32{
- 0, // 0: github.com.avinoplan.postar.api.PostardResponse.code:type_name -> github.com.avinoplan.postar.api.ResponseCodes
- 5, // 1: github.com.avinoplan.postar.api.PostardResponse.data:type_name -> google.protobuf.Any
- 2, // 2: github.com.avinoplan.postar.api.SendEmailRequest.email:type_name -> github.com.avinoplan.postar.api.Email
- 3, // 3: github.com.avinoplan.postar.api.SendEmailRequest.options:type_name -> github.com.avinoplan.postar.api.SendEmailOptions
- 4, // 4: github.com.avinoplan.postar.api.Postard.SendEmail:input_type -> github.com.avinoplan.postar.api.SendEmailRequest
- 1, // 5: github.com.avinoplan.postar.api.Postard.SendEmail:output_type -> github.com.avinoplan.postar.api.PostardResponse
- 5, // [5:6] is the sub-list for method output_type
- 4, // [4:5] is the sub-list for method input_type
- 4, // [4:4] is the sub-list for extension type_name
- 4, // [4:4] is the sub-list for extension extendee
- 0, // [0:4] is the sub-list for field type_name
+ 0, // 0: github.com.avinoplan.postar.api.SendEmailRequest.email:type_name -> github.com.avinoplan.postar.api.Email
+ 1, // 1: github.com.avinoplan.postar.api.SendEmailRequest.options:type_name -> github.com.avinoplan.postar.api.SendEmailOptions
+ 4, // 2: github.com.avinoplan.postar.api.SendEmailResponse.code:type_name -> github.com.avinoplan.postar.api.ServerCode
+ 2, // 3: github.com.avinoplan.postar.api.Postard.SendEmail:input_type -> github.com.avinoplan.postar.api.SendEmailRequest
+ 3, // 4: github.com.avinoplan.postar.api.Postard.SendEmail:output_type -> github.com.avinoplan.postar.api.SendEmailResponse
+ 4, // [4:5] is the sub-list for method output_type
+ 3, // [3:4] is the sub-list for method input_type
+ 3, // [3:3] is the sub-list for extension type_name
+ 3, // [3:3] is the sub-list for extension extendee
+ 0, // [0:3] is the sub-list for field type_name
}
func init() { file_postard_proto_init() }
@@ -433,9 +363,10 @@ func file_postard_proto_init() {
if File_postard_proto != nil {
return
}
+ file_api_proto_init()
if !protoimpl.UnsafeEnabled {
file_postard_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*PostardResponse); i {
+ switch v := v.(*Email); i {
case 0:
return &v.state
case 1:
@@ -447,7 +378,7 @@ func file_postard_proto_init() {
}
}
file_postard_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*Email); i {
+ switch v := v.(*SendEmailOptions); i {
case 0:
return &v.state
case 1:
@@ -459,7 +390,7 @@ func file_postard_proto_init() {
}
}
file_postard_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*SendEmailOptions); i {
+ switch v := v.(*SendEmailRequest); i {
case 0:
return &v.state
case 1:
@@ -471,7 +402,7 @@ func file_postard_proto_init() {
}
}
file_postard_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*SendEmailRequest); i {
+ switch v := v.(*SendEmailResponse); i {
case 0:
return &v.state
case 1:
@@ -488,14 +419,13 @@ func file_postard_proto_init() {
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_postard_proto_rawDesc,
- NumEnums: 1,
+ NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_postard_proto_goTypes,
DependencyIndexes: file_postard_proto_depIdxs,
- EnumInfos: file_postard_proto_enumTypes,
MessageInfos: file_postard_proto_msgTypes,
}.Build()
File_postard_proto = out.File
diff --git a/api/postard.proto b/api/postard.proto
index dce3bae..3a153f3 100644
--- a/api/postard.proto
+++ b/api/postard.proto
@@ -5,41 +5,28 @@
// Author: FishGoddess
// Email: fishgoddess@qq.com
// Created at 2021/09/16 01:42:33
-syntax = "proto3";
-package github.com.avinoplan.postar.api;
-// protoc -I=. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative postard.proto
-option go_package = "github.com/avino-plan/postar/api";
+syntax = "proto3";
-import "google/protobuf/any.proto";
+package github.com.avinoplan.postar.api;
-// ResponseCodes is all codes of response.
-enum ResponseCodes {
- OK = 0;
- InternalServerError = 50000;
- TimeoutError = 50001;
-}
+import "api.proto";
-// PostardResponse is the response of Postard.
-message PostardResponse {
- ResponseCodes code = 1; // 0 is ok.
- string msg = 2; // For messaging.
- string traceId = 3; // For tracing.
- google.protobuf.Any data = 4; // Any data.
-}
+// protoc -I=. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative postard.proto
+option go_package = "github.com/avinoplan/postar/api";
// Email wraps all information of using smtp service.
message Email {
- repeated string to = 1; // The receivers of one email.
- string subject = 2; // The subject of one email.
- string bodyType = 3; // The content type of body.
- string body = 4; // The body of one email.
+ repeated string receivers = 1; // Receivers.
+ string subject = 2; // Subject.
+ string body_type = 3; // Body type.
+ string body = 4; // Body.
}
// SendEmailOptions is the options of sending emails.
message SendEmailOptions {
- bool async = 1; // If need sending emails asynchronously.
- int64 timeout = 2; // Sending timeout.
+ bool async = 1; // Sending this email asynchronously.
+ int32 timeout = 2; // Sending timeout in seconds.
}
// SendEmailRequest is the request of SendEmail.
@@ -48,7 +35,15 @@ message SendEmailRequest {
SendEmailOptions options = 2; // Sending options.
}
+// SendEmailResponse is the response of SendEmail.
+message SendEmailResponse {
+ ServerCode code = 1; // 0 is ok.
+ string msg = 2; // For messaging.
+ string trace_id = 3; // For tracing.
+}
+
// Postard is the core service of postar.
service Postard {
- rpc SendEmail(SendEmailRequest) returns (PostardResponse); // For sending emails.
+ // SendEmail send one email.
+ rpc SendEmail(SendEmailRequest) returns (SendEmailResponse);
}
\ No newline at end of file
diff --git a/api/postard_grpc.pb.go b/api/postard_grpc.pb.go
index 05b575f..7a9da98 100644
--- a/api/postard_grpc.pb.go
+++ b/api/postard_grpc.pb.go
@@ -14,11 +14,12 @@ import (
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
-// PostardClient is the client API for Postard biz.
+// PostardClient is the client API for Postard service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type PostardClient interface {
- SendEmail(ctx context.Context, in *SendEmailRequest, opts ...grpc.CallOption) (*PostardResponse, error)
+ // SendEmail send one email.
+ SendEmail(ctx context.Context, in *SendEmailRequest, opts ...grpc.CallOption) (*SendEmailResponse, error)
}
type postardClient struct {
@@ -29,8 +30,8 @@ func NewPostardClient(cc grpc.ClientConnInterface) PostardClient {
return &postardClient{cc}
}
-func (c *postardClient) SendEmail(ctx context.Context, in *SendEmailRequest, opts ...grpc.CallOption) (*PostardResponse, error) {
- out := new(PostardResponse)
+func (c *postardClient) SendEmail(ctx context.Context, in *SendEmailRequest, opts ...grpc.CallOption) (*SendEmailResponse, error) {
+ out := new(SendEmailResponse)
err := c.cc.Invoke(ctx, "/github.com.avinoplan.postar.api.Postard/SendEmail", in, out, opts...)
if err != nil {
return nil, err
@@ -38,11 +39,12 @@ func (c *postardClient) SendEmail(ctx context.Context, in *SendEmailRequest, opt
return out, nil
}
-// PostardServer is the server API for Postard biz.
+// PostardServer is the server API for Postard service.
// All implementations must embed UnimplementedPostardServer
// for forward compatibility
type PostardServer interface {
- SendEmail(context.Context, *SendEmailRequest) (*PostardResponse, error)
+ // SendEmail send one email.
+ SendEmail(context.Context, *SendEmailRequest) (*SendEmailResponse, error)
mustEmbedUnimplementedPostardServer()
}
@@ -50,12 +52,12 @@ type PostardServer interface {
type UnimplementedPostardServer struct {
}
-func (UnimplementedPostardServer) SendEmail(context.Context, *SendEmailRequest) (*PostardResponse, error) {
+func (UnimplementedPostardServer) SendEmail(context.Context, *SendEmailRequest) (*SendEmailResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method SendEmail not implemented")
}
func (UnimplementedPostardServer) mustEmbedUnimplementedPostardServer() {}
-// UnsafePostardServer may be embedded to opt out of forward compatibility for this biz.
+// UnsafePostardServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to PostardServer will
// result in compilation errors.
type UnsafePostardServer interface {
@@ -84,7 +86,7 @@ func _Postard_SendEmail_Handler(srv interface{}, ctx context.Context, dec func(i
return interceptor(ctx, in, info, handler)
}
-// Postard_ServiceDesc is the grpc.ServiceDesc for Postard biz.
+// Postard_ServiceDesc is the grpc.ServiceDesc for Postard service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Postard_ServiceDesc = grpc.ServiceDesc{
diff --git a/cmd/postard/main.go b/cmd/postard/main.go
index c915b42..9ff1bf7 100644
--- a/cmd/postard/main.go
+++ b/cmd/postard/main.go
@@ -12,15 +12,19 @@ import (
"net"
"github.com/FishGoddess/logit"
- "github.com/avino-plan/postar/internal/postard/biz"
- "github.com/avino-plan/postar/internal/postard/server"
- "github.com/avino-plan/postar/pkg/concurrency"
+ "github.com/avinoplan/postar/internal/biz"
+ "github.com/avinoplan/postar/internal/server"
+ "github.com/panjf2000/ants/v2"
)
func main() {
logger := logit.NewLogger()
- pool := concurrency.NewPool()
-
+ pool, err := ants.NewPool(64)
+ if err != nil {
+ panic(err)
+ }
+ defer pool.Release()
+
smtpBiz := biz.NewSmtpBiz(pool, "", 0, "", "")
svr := server.NewGrpcServer(logger, smtpBiz)
diff --git a/go.mod b/go.mod
index 4fd2fcf..aa6fdc3 100644
--- a/go.mod
+++ b/go.mod
@@ -1,9 +1,11 @@
-module github.com/avino-plan/postar
+module github.com/avinoplan/postar
go 1.15
require (
- github.com/FishGoddess/logit v0.4.7-alpha
+ github.com/FishGoddess/errors v0.0.2
+ github.com/FishGoddess/logit v0.4.11
+ github.com/panjf2000/ants/v2 v2.4.7
google.golang.org/grpc v1.40.0
google.golang.org/protobuf v1.27.1
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
diff --git a/go.sum b/go.sum
index 3bcf639..8077208 100644
--- a/go.sum
+++ b/go.sum
@@ -1,10 +1,15 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/FishGoddess/errors v0.0.2 h1:g1S1HDrnjSuMS0sl92lyE+tXsfTn7Dp/lKlOvAPN5DA=
+github.com/FishGoddess/errors v0.0.2/go.mod h1:2YWw8ijAMQIfs4FyOFjvahUPQWhgS6lFTkBG++n61+Y=
github.com/FishGoddess/logit v0.4.7-alpha h1:6pYVA+Qp+KFr/vB7Z4ad9JIhq7Nm9QMWBMcES9QYtvU=
github.com/FishGoddess/logit v0.4.7-alpha/go.mod h1:a2dFSibwfZXNNZ/V1jMOQBImPoySaxdPFThbsm17ZdY=
+github.com/FishGoddess/logit v0.4.11 h1:d/KQf4eONmuTg1EVGJ+yQaK+Q/oANsE0G+BEI6hzZC4=
+github.com/FishGoddess/logit v0.4.11/go.mod h1:a2dFSibwfZXNNZ/V1jMOQBImPoySaxdPFThbsm17ZdY=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/avino-plan/postar v0.2.3-alpha h1:4q/OiQl6qJBBfkQbo8S2b2aLtEKAikJ6+rILCt9DQ+s=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
@@ -12,6 +17,7 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -43,13 +49,15 @@ github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
-github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/panjf2000/ants v1.3.0 h1:8pQ+8leaLc9lys2viEEr8md0U4RN6uOSUCE9bOYjQ9M=
+github.com/panjf2000/ants/v2 v2.4.7 h1:MZnw2JRyTJxFwtaMtUJcwE618wKD04POWk2gwwP4E2M=
+github.com/panjf2000/ants/v2 v2.4.7/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -120,5 +128,6 @@ gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AW
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/internal/postard/biz/smtp.go b/internal/biz/smtp.go
similarity index 55%
rename from internal/postard/biz/smtp.go
rename to internal/biz/smtp.go
index 6a35130..c977261 100644
--- a/internal/postard/biz/smtp.go
+++ b/internal/biz/smtp.go
@@ -12,23 +12,23 @@ import (
"context"
"github.com/FishGoddess/logit"
- "github.com/avino-plan/postar/internal/postard/model"
- "github.com/avino-plan/postar/pkg/concurrency"
- "github.com/avino-plan/postar/pkg/errors"
+ "github.com/avinoplan/postar/internal/model"
+ "github.com/avinoplan/postar/pkg/errors"
+ "github.com/panjf2000/ants/v2"
"gopkg.in/gomail.v2"
)
// SmtpBiz is the biz of smtp.
type SmtpBiz struct {
- pool *concurrency.Pool // The pool of workers.
- host string // The host of smtp server.
- port int // The port of smtp server.
- user string // The user of smtp server.
- password string // The password of smtp server.
+ pool *ants.Pool // The pool of workers.
+ host string // The host of smtp server.
+ port int // The port of smtp server.
+ user string // The user of smtp server.
+ password string // The password of smtp server.
}
// NewSmtpBiz returns a new SmtpBiz.
-func NewSmtpBiz(pool *concurrency.Pool, host string, port int, user string, password string) *SmtpBiz {
+func NewSmtpBiz(pool *ants.Pool, host string, port int, user string, password string) *SmtpBiz {
return &SmtpBiz{
pool: pool,
host: host,
@@ -54,29 +54,40 @@ func (sb *SmtpBiz) SendEmail(ctx context.Context, email *model.Email, options *m
if options == nil {
options = model.DefaultSendEmailOptions()
- logger.Debug("options is nil, using DefaultSendEmailOptions()").Any("options", options).End()
+ logger.Debug("options is nil, using default options").Any("options", options).End()
}
ctx, cancel := context.WithTimeout(ctx, options.Timeout)
defer cancel()
- errorCh := sb.pool.Go(ctx, func(ctx context.Context) error { return sb.sendEmail(email) })
+ errorCh := make(chan error, 1)
+ err := sb.pool.Submit(func() {
+ defer close(errorCh)
+ errorCh <- sb.sendEmail(email)
+ })
+
+ if err != nil {
+ logger.Error("submit email sending task to pool failed").Error("err", err).End()
+ return errors.SendEmailFailedErr(err)
+ }
+
if options.Async {
return nil
}
select {
- case e := <-errorCh:
- if e != nil {
- logger.Error("send email failed").Error("e", e).End()
- return errors.SendEmailFailedErr(e)
+ case err = <-errorCh:
+ if err != nil {
+ logger.Error("send email failed").Error("err", err).End()
+ return errors.SendEmailFailedErr(err)
}
case <-ctx.Done():
- e := ctx.Err()
- if e != nil {
- logger.Error("send email timeout").Error("e", e).End()
- return errors.SendTimeoutErr(e)
+ err = ctx.Err()
+ if err != nil {
+ logger.Error("send email timeout").Error("err", err).End()
+ return errors.TimeoutErr(err)
}
}
+
return nil
}
diff --git a/internal/postard/biz/smtp_test.go b/internal/biz/smtp_test.go
similarity index 82%
rename from internal/postard/biz/smtp_test.go
rename to internal/biz/smtp_test.go
index d4c7677..2b57558 100644
--- a/internal/postard/biz/smtp_test.go
+++ b/internal/biz/smtp_test.go
@@ -15,8 +15,8 @@ import (
"testing"
"time"
- "github.com/avino-plan/postar/internal/postard/model"
- "github.com/avino-plan/postar/pkg/concurrency"
+ "github.com/avinoplan/postar/internal/model"
+ "github.com/panjf2000/ants/v2"
)
// go test -v -cover -run=^TestSmtpBiz$
@@ -34,10 +34,10 @@ func TestSmtpBiz(t *testing.T) {
port = 587
}
- pool := concurrency.NewPool().Start()
- defer pool.Stop()
+ pool, _ := ants.NewPool(64)
+ defer pool.Release()
- smtpService := NewSmtpService(pool, host, int(port), user, password)
+ smtpService := NewSmtpBiz(pool, host, int(port), user, password)
err = smtpService.SendEmail(context.Background(), &model.Email{
To: []string{to},
Subject: t.Name(),
diff --git a/internal/postard/model/smtp.go b/internal/model/smtp.go
similarity index 79%
rename from internal/postard/model/smtp.go
rename to internal/model/smtp.go
index d783b32..46d40f6 100644
--- a/internal/postard/model/smtp.go
+++ b/internal/model/smtp.go
@@ -12,10 +12,10 @@ import "time"
// Email is an email.
type Email struct {
- To []string // The receivers of one email.
- Subject string // The subject of one email.
- BodyType string // The content type of body.
- Body string // The body of one email.
+ To []string // Receivers.
+ Subject string // Subject.
+ BodyType string // Body type.
+ Body string // Body.
}
// SendEmailOptions is the options of sending one email.
diff --git a/internal/postard/server/grpc.go b/internal/server/grpc.go
similarity index 75%
rename from internal/postard/server/grpc.go
rename to internal/server/grpc.go
index 4204179..c67f742 100644
--- a/internal/postard/server/grpc.go
+++ b/internal/server/grpc.go
@@ -13,10 +13,10 @@ import (
"net"
"github.com/FishGoddess/logit"
- "github.com/avino-plan/postar/api"
- "github.com/avino-plan/postar/internal/postard/biz"
- "github.com/avino-plan/postar/pkg/errors"
- "github.com/avino-plan/postar/pkg/trace"
+ "github.com/avinoplan/postar/api"
+ "github.com/avinoplan/postar/internal/biz"
+ "github.com/avinoplan/postar/pkg/errors"
+ "github.com/avinoplan/postar/pkg/trace"
"google.golang.org/grpc"
)
@@ -37,30 +37,30 @@ func NewGrpcServer(logger *logit.Logger, smtpBiz *biz.SmtpBiz) *GRPCServer {
}
// SendEmail sends emails.
-func (gs *GRPCServer) SendEmail(ctx context.Context, request *api.SendEmailRequest) (*api.PostardResponse, error) {
+func (gs *GRPCServer) SendEmail(ctx context.Context, request *api.SendEmailRequest) (*api.SendEmailResponse, error) {
traceID := trace.NewTraceID()
ctx = trace.NewContext(ctx, traceID)
ctx = logit.NewContext(ctx, gs.logger)
err := gs.smtpBiz.SendEmail(ctx, nil, nil)
- if errors.IsSendTimeout(err) {
- return &api.PostardResponse{
- Code: api.ResponseCodes_TimeoutError,
+ if errors.IsTimeout(err) {
+ return &api.SendEmailResponse{
+ Code: api.ServerCode_TIMEOUT,
Msg: "send email timeout",
TraceId: traceID,
}, nil
}
if err != nil {
- return &api.PostardResponse{
- Code: api.ResponseCodes_InternalServerError,
+ return &api.SendEmailResponse{
+ Code: api.ServerCode_SEND_EMAIL_FAILED,
Msg: "send email failed",
TraceId: traceID,
}, nil
}
- return &api.PostardResponse{
- Code: api.ResponseCodes_OK,
+ return &api.SendEmailResponse{
+ Code: api.ServerCode_OK,
TraceId: traceID,
}, nil
}
diff --git a/internal/postard/server/http.go b/internal/server/http.go
similarity index 100%
rename from internal/postard/server/http.go
rename to internal/server/http.go
diff --git a/internal/postard/server/udp.go b/internal/server/udp.go
similarity index 100%
rename from internal/postard/server/udp.go
rename to internal/server/udp.go
diff --git a/internal/postard/server/vex.go b/internal/server/vex.go
similarity index 100%
rename from internal/postard/server/vex.go
rename to internal/server/vex.go
diff --git a/pkg/concurrency/pool.go b/pkg/concurrency/pool.go
deleted file mode 100644
index 7603f22..0000000
--- a/pkg/concurrency/pool.go
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/09/16 22:05:23
-
-package concurrency
-
-import (
- "context"
- "sync"
- "sync/atomic"
-)
-
-// PoolOptions is the options of Pool.
-type PoolOptions func(pool *Pool)
-
-// WithMaxWorkers sets maxWorkers of pool.
-func WithMaxWorkers(maxWorkers int) PoolOptions {
- return func(pool *Pool) {
- pool.maxWorkers = maxWorkers
- pool.taskQueues = make([]chan func(), maxWorkers)
- }
-}
-
-// WithMaxWorkerTasks sets maxWorkerTasks of pool.
-func WithMaxWorkerTasks(maxWorkerTasks int) PoolOptions {
- return func(pool *Pool) {
- pool.maxWorkerTasks = maxWorkerTasks
- }
-}
-
-// Pool is a set of goroutines.
-// This is for controlling the number of goroutines and managing their lifecycles.
-type Pool struct {
- // maxWorkers is the max number of workers.
- maxWorkers int
-
- // maxWorkerTasks is the max number of one task queue.
- // The Go() method will block until the task queue has enough capacity.
- maxWorkerTasks int
-
- // currentQueue records the current sequence of task queues.
- currentQueue int64
-
- // taskQueues stores all task queues.
- // Every worker has its own task queue.
- taskQueues []chan func()
-
- // onRecover is a function which will call in defer after finishing task.
- onRecover func(cause interface{})
-
- // wg is for managing all goroutines.
- wg *sync.WaitGroup
-}
-
-// NewPool returns a new Pool holder.
-func NewPool(options ...PoolOptions) *Pool {
- pool := &Pool{
- maxWorkers: 64,
- maxWorkerTasks: 1024,
- taskQueues: make([]chan func(), 64),
- currentQueue: -1,
- wg: &sync.WaitGroup{},
- }
-
- for _, option := range options {
- option(pool)
- }
- return pool
-}
-
-// OnRecover sets onRecover to p.
-func (p *Pool) OnRecover(onRecover func(cause interface{})) {
- p.onRecover = onRecover
-}
-
-// Start starts all workers in pool and starts receiving tasks.
-func (p *Pool) Start() *Pool {
- for i := 0; i < p.maxWorkers; i++ {
- taskQueue := make(chan func(), p.maxWorkerTasks)
- p.taskQueues[i] = taskQueue
-
- p.wg.Add(1)
- go func() {
- defer p.wg.Done()
-
- for task := range taskQueue {
- task()
- }
- }()
- }
- return p
-}
-
-// nextTaskQueue returns next task queue.
-func (p *Pool) nextTaskQueue() chan<- func() {
- currentQueue := atomic.AddInt64(&p.currentQueue, 1)
- if currentQueue >= int64(p.maxWorkers)-1 {
- atomic.StoreInt64(&p.currentQueue, -1)
- }
- return p.taskQueues[currentQueue]
-}
-
-// wrapTask wraps task to a complete task of pool.
-func (p *Pool) wrapTask(ctx context.Context, fn func(ctx context.Context) error, errorCh chan<- error) func() {
- return func() {
- var err error
- defer func() {
- errorCh <- err
- if cause := recover(); p.onRecover != nil {
- p.onRecover(cause) // Notice: Just do some simple records which don't panic...
- }
- }()
- err = fn(ctx)
- }
-}
-
-// Go sends the task to task queue and waits for executing.
-func (p *Pool) Go(ctx context.Context, fn func(ctx context.Context) error) <-chan error {
- errorCh := make(chan error, 1)
-
- taskQueue := p.nextTaskQueue()
- select {
- case taskQueue <- p.wrapTask(ctx, fn, errorCh):
- case <-ctx.Done():
- errorCh <- ctx.Err()
- }
- return errorCh
-}
-
-// Stop closes all task queues and waits for all workers to be shutdown.
-func (p *Pool) Stop() {
- for _, taskQueue := range p.taskQueues {
- close(taskQueue)
- }
- p.wg.Wait()
-}
diff --git a/pkg/concurrency/pool_test.go b/pkg/concurrency/pool_test.go
deleted file mode 100644
index 4e51c5a..0000000
--- a/pkg/concurrency/pool_test.go
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/09/16 23:07:51
-
-package concurrency
-
-import (
- "context"
- "testing"
- "time"
-)
-
-// go test -v -cover -run=^TestNewPool$
-func TestNewPool(t *testing.T) {
- ctx := context.Background()
- pool := NewPool(WithMaxWorkers(4), WithMaxWorkerTasks(16)).Start()
-
- numbers := [1000]int{}
- for i := 0; i < 1000; i++ {
- no := i
- errorCh := pool.Go(ctx, func(ctx context.Context) error {
- numbers[no] = no
- return nil
- })
- if err := <-errorCh; err != nil {
- t.Error(err)
- }
- }
-
- time.Sleep(time.Second)
- pool.Stop()
-
- for i, num := range numbers {
- if i != num {
- t.Errorf("i %d != num %d", i, num)
- }
- }
-}
diff --git a/pkg/context/context.go b/pkg/context/context.go
deleted file mode 100644
index b0aa994..0000000
--- a/pkg/context/context.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/09/27 22:40:58
-
-package context
-
-import (
- "context"
-
- "github.com/FishGoddess/logit"
- "github.com/avino-plan/postar/pkg/trace"
-)
-
-// WithLogger wraps ctx with logger.
-func WithLogger(ctx context.Context, logger *logit.Logger) context.Context {
- return logit.NewContext(ctx, logger)
-}
-
-// WithTraceID wraps ctx with traceID.
-func WithTraceID(ctx context.Context, traceID string) context.Context {
- if traceID == "" {
- traceID = trace.NewTraceID()
- }
- return trace.NewContext(ctx, traceID)
-}
diff --git a/pkg/context/context_test.go b/pkg/context/context_test.go
deleted file mode 100644
index cad2cdc..0000000
--- a/pkg/context/context_test.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2021 Ye Zi Jie. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-//
-// Author: FishGoddess
-// Email: fishgoddess@qq.com
-// Created at 2021/09/27 22:50:56
-
-package context
-
-import (
- "context"
- "testing"
-
- "github.com/FishGoddess/logit"
- "github.com/avino-plan/postar/pkg/trace"
-)
-
-// go test -v -cover -run=^TestWithLogger$
-func TestWithLogger(t *testing.T) {
- logger := logit.NewLogger()
- ctx := WithLogger(context.Background(), logger)
- contextLogger := logit.FromContext(ctx)
- if contextLogger != logger {
- t.Errorf("contextLogger %+v != logger %+v", contextLogger, logger)
- }
-}
-
-// go test -v -cover -run=^TestWithTraceID$
-func TestWithTraceID(t *testing.T) {
- ctx := WithTraceID(context.Background())
- traceId := trace.FromContext(ctx)
- if traceId == "" {
- t.Error("traceId == ''")
- }
-}
diff --git a/pkg/encode/encode.go b/pkg/encode/encode.go
index f6e8609..851d529 100644
--- a/pkg/encode/encode.go
+++ b/pkg/encode/encode.go
@@ -31,6 +31,11 @@ var (
random = rand.New(rand.NewSource(time.Now().Unix()))
)
+// PID returns pid in string.
+func PID() string {
+ return pid
+}
+
// numberHex returns num in hex string.
// The hex string will be cut with start and end.
func numberHex(num uint64, start int, end int) string {
@@ -48,16 +53,11 @@ func numberHex(num uint64, start int, end int) string {
return fmt.Sprintf("%x", b[start:end])
}
-// Now returns in current time in hex string.
-func Now() string {
+// NowHex returns in current time in hex string.
+func NowHex() string {
return numberHex(uint64(time.Now().Unix()), 4, 0)
}
-// PID returns pid in string.
-func PID() string {
- return pid
-}
-
// RandomString returns a string including 0-9/a-z/A-Z not longer than length.
func RandomString(length int) string {
b := make([]byte, length)
diff --git a/pkg/encode/encode_test.go b/pkg/encode/encode_test.go
index 9d23ef0..554b9bd 100644
--- a/pkg/encode/encode_test.go
+++ b/pkg/encode/encode_test.go
@@ -12,7 +12,7 @@ import "testing"
// go test -v -cover -run=^NowTimeHex$
func TestNowTimeHex(t *testing.T) {
- timeHex := Now()
+ timeHex := NowHex()
if len(timeHex) != 8 {
t.Errorf("length of TimeHex is wrong with %s, %d", timeHex, len(timeHex))
}
diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go
index 3986fac..6cb9a55 100644
--- a/pkg/errors/errors.go
+++ b/pkg/errors/errors.go
@@ -8,107 +8,28 @@
package errors
-import (
- "errors"
- "fmt"
- "net/http"
-)
+import "github.com/FishGoddess/errors"
const (
- codeBadRequest = http.StatusBadRequest
- codeSendTimeout = 1100
codeSendEmailFailed = 11000
)
-// Error is error with code.
-type Error struct {
- err error
- code int32
-}
-
-// Error returns error message.
-func (e *Error) Error() string {
- if e == nil || e.err == nil {
- return ""
- }
- return fmt.Sprintf("%d (%s)", e.code, e.err.Error())
-}
-
-// Is returns if e is the target's type.
-func (e *Error) Is(target error) bool {
- if e == nil {
- return e == target
- }
-
- err, ok := target.(*Error)
- if !ok {
- return e.err == target
- }
-
- return e.code == err.code
-}
-
-// Unwrap unwraps e.
-func (e *Error) Unwrap() error {
- if e == nil {
- return nil
- }
- return e.err
-}
-
-// WithCode wraps err with code.
-func WithCode(err error, code int32) error {
- if err == nil {
- return nil
- }
- return &Error{err: err, code: code}
-}
-
-// Is returns if err has a code and its code equals to code.
-func Is(err error, code int32) bool {
- for {
- if err == nil {
- return false
- }
-
- e, ok := err.(*Error)
- if !ok {
- return false
- }
-
- if e.code == code {
- return true
- }
- err = errors.Unwrap(err)
- }
-}
-
-// BadRequest returns a bad request error.
-func BadRequest(err error) error {
- return WithCode(err, codeBadRequest)
-}
-
-// IsBadRequest returns if err is bad request.
-func IsBadRequest(err error) bool {
- return Is(err, codeBadRequest)
-}
-
-// SendTimeoutErr returns a send timeout error.
-func SendTimeoutErr(err error) error {
- return WithCode(err, codeSendTimeout)
+// TimeoutErr returns a timeout error.
+func TimeoutErr(err error) error {
+ return errors.Timeout(err)
}
-// IsSendTimeout returns if err is send timeout.
-func IsSendTimeout(err error) bool {
- return Is(err, codeSendTimeout)
+// IsTimeout returns if err is timeout.
+func IsTimeout(err error) bool {
+ return errors.IsTimeout(err)
}
// SendEmailFailedErr returns a send email failed error.
func SendEmailFailedErr(err error) error {
- return WithCode(err, codeSendEmailFailed)
+ return errors.Wrap(err, codeSendEmailFailed)
}
// IsSendEmailFailed returns if err is send email failed.
func IsSendEmailFailed(err error) bool {
- return Is(err, codeSendEmailFailed)
+ return errors.Is(err, codeSendEmailFailed)
}
diff --git a/pkg/errors/errors_test.go b/pkg/errors/errors_test.go
index e435dc0..a46ec1f 100644
--- a/pkg/errors/errors_test.go
+++ b/pkg/errors/errors_test.go
@@ -13,32 +13,13 @@ import (
"testing"
)
-// go test -v -cover -run=^TestIsSendTimeout$
-func TestIsSendTimeout(t *testing.T) {
- testCases := []struct {
- err error
- result bool
- }{
- {errSendTimeout, true},
- {errSendEmailFailed, false},
- {errors.New("unknown error"), false},
- }
-
- for i, testCase := range testCases {
- if IsSendTimeout(testCase.err) != testCase.result {
- t.Errorf("testCase %d failed with err %+v, result %+v", i, testCase.err, testCase.result)
- }
- }
-}
-
// go test -v -cover -run=^TestIsSendEmailFailed$
func TestIsSendEmailFailed(t *testing.T) {
testCases := []struct {
err error
result bool
}{
- {errSendTimeout, false},
- {errSendEmailFailed, true},
+ {SendEmailFailedErr(errors.New("send email failed")), true},
{errors.New("unknown error"), false},
}
diff --git a/pkg/trace/trace.go b/pkg/trace/trace.go
index 525c84c..69d1aa7 100644
--- a/pkg/trace/trace.go
+++ b/pkg/trace/trace.go
@@ -11,7 +11,7 @@ package trace
import (
"context"
- "github.com/avino-plan/postar/pkg/encode"
+ "github.com/avinoplan/postar/pkg/encode"
)
var (
@@ -21,7 +21,7 @@ var (
// NewTraceID returns a new trace id.
func NewTraceID() string {
salt := encode.RandomString(6)
- return encode.Now() + salt[:3] + encode.PID() + salt[3:]
+ return encode.NowHex() + salt[:3] + encode.PID() + salt[3:]
}
// NewContext wraps ctx with a trace id.
From 29b524df32db343822b253bcbe2aa14c50a7743a Mon Sep 17 00:00:00 2001
From: FishGoddess <1149062639@qq.com>
Date: Sun, 23 Jan 2022 02:21:56 +0800
Subject: [PATCH 11/27] =?UTF-8?q?=E5=A4=A7=E9=87=8F=E9=87=8D=E6=9E=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
api/{postard.pb.go => postar.pb.go} | 171 ++++++++++++++--------------
api/{postard.proto => postar.proto} | 6 +-
api/postar_grpc.pb.go | 103 +++++++++++++++++
api/postard_grpc.pb.go | 103 -----------------
cmd/{postard => postar}/main.go | 31 +++--
configs/config.go | 41 +++++++
internal/biz/smtp.go | 37 +++---
internal/biz/smtp_test.go | 44 ++++---
internal/model/smtp.go | 8 +-
internal/server/grpc.go | 27 +++--
internal/server/server.go | 26 +++++
11 files changed, 346 insertions(+), 251 deletions(-)
rename api/{postard.pb.go => postar.pb.go} (59%)
rename api/{postard.proto => postar.proto} (91%)
create mode 100644 api/postar_grpc.pb.go
delete mode 100644 api/postard_grpc.pb.go
rename cmd/{postard => postar}/main.go (55%)
create mode 100644 configs/config.go
create mode 100644 internal/server/server.go
diff --git a/api/postard.pb.go b/api/postar.pb.go
similarity index 59%
rename from api/postard.pb.go
rename to api/postar.pb.go
index 86d17ff..ccd78fd 100644
--- a/api/postard.pb.go
+++ b/api/postar.pb.go
@@ -10,7 +10,7 @@
// versions:
// protoc-gen-go v1.27.1
// protoc v3.18.0
-// source: postard.proto
+// source: postar.proto
package api
@@ -43,7 +43,7 @@ type Email struct {
func (x *Email) Reset() {
*x = Email{}
if protoimpl.UnsafeEnabled {
- mi := &file_postard_proto_msgTypes[0]
+ mi := &file_postar_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -56,7 +56,7 @@ func (x *Email) String() string {
func (*Email) ProtoMessage() {}
func (x *Email) ProtoReflect() protoreflect.Message {
- mi := &file_postard_proto_msgTypes[0]
+ mi := &file_postar_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -69,7 +69,7 @@ func (x *Email) ProtoReflect() protoreflect.Message {
// Deprecated: Use Email.ProtoReflect.Descriptor instead.
func (*Email) Descriptor() ([]byte, []int) {
- return file_postard_proto_rawDescGZIP(), []int{0}
+ return file_postar_proto_rawDescGZIP(), []int{0}
}
func (x *Email) GetReceivers() []string {
@@ -113,7 +113,7 @@ type SendEmailOptions struct {
func (x *SendEmailOptions) Reset() {
*x = SendEmailOptions{}
if protoimpl.UnsafeEnabled {
- mi := &file_postard_proto_msgTypes[1]
+ mi := &file_postar_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -126,7 +126,7 @@ func (x *SendEmailOptions) String() string {
func (*SendEmailOptions) ProtoMessage() {}
func (x *SendEmailOptions) ProtoReflect() protoreflect.Message {
- mi := &file_postard_proto_msgTypes[1]
+ mi := &file_postar_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -139,7 +139,7 @@ func (x *SendEmailOptions) ProtoReflect() protoreflect.Message {
// Deprecated: Use SendEmailOptions.ProtoReflect.Descriptor instead.
func (*SendEmailOptions) Descriptor() ([]byte, []int) {
- return file_postard_proto_rawDescGZIP(), []int{1}
+ return file_postar_proto_rawDescGZIP(), []int{1}
}
func (x *SendEmailOptions) GetAsync() bool {
@@ -169,7 +169,7 @@ type SendEmailRequest struct {
func (x *SendEmailRequest) Reset() {
*x = SendEmailRequest{}
if protoimpl.UnsafeEnabled {
- mi := &file_postard_proto_msgTypes[2]
+ mi := &file_postar_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -182,7 +182,7 @@ func (x *SendEmailRequest) String() string {
func (*SendEmailRequest) ProtoMessage() {}
func (x *SendEmailRequest) ProtoReflect() protoreflect.Message {
- mi := &file_postard_proto_msgTypes[2]
+ mi := &file_postar_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -195,7 +195,7 @@ func (x *SendEmailRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use SendEmailRequest.ProtoReflect.Descriptor instead.
func (*SendEmailRequest) Descriptor() ([]byte, []int) {
- return file_postard_proto_rawDescGZIP(), []int{2}
+ return file_postar_proto_rawDescGZIP(), []int{2}
}
func (x *SendEmailRequest) GetEmail() *Email {
@@ -226,7 +226,7 @@ type SendEmailResponse struct {
func (x *SendEmailResponse) Reset() {
*x = SendEmailResponse{}
if protoimpl.UnsafeEnabled {
- mi := &file_postard_proto_msgTypes[3]
+ mi := &file_postar_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -239,7 +239,7 @@ func (x *SendEmailResponse) String() string {
func (*SendEmailResponse) ProtoMessage() {}
func (x *SendEmailResponse) ProtoReflect() protoreflect.Message {
- mi := &file_postard_proto_msgTypes[3]
+ mi := &file_postar_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -252,7 +252,7 @@ func (x *SendEmailResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use SendEmailResponse.ProtoReflect.Descriptor instead.
func (*SendEmailResponse) Descriptor() ([]byte, []int) {
- return file_postard_proto_rawDescGZIP(), []int{3}
+ return file_postar_proto_rawDescGZIP(), []int{3}
}
func (x *SendEmailResponse) GetCode() ServerCode {
@@ -276,81 +276,82 @@ func (x *SendEmailResponse) GetTraceId() string {
return ""
}
-var File_postard_proto protoreflect.FileDescriptor
-
-var file_postard_proto_rawDesc = []byte{
- 0x0a, 0x0d, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
- 0x1f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e,
- 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69,
- 0x1a, 0x09, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x70, 0x0a, 0x05, 0x45,
- 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72,
- 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
- 0x72, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1b, 0x0a, 0x09,
- 0x62, 0x6f, 0x64, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x08, 0x62, 0x6f, 0x64, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64,
- 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x42, 0x0a,
- 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
- 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
- 0x52, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f,
- 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75,
- 0x74, 0x22, 0x9d, 0x01, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52,
- 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
- 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73,
- 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x05, 0x65,
- 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x4b, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18,
- 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
- 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73,
- 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69,
- 0x6c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
- 0x73, 0x22, 0x81, 0x01, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
- 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73,
- 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f,
- 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18,
- 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x72,
- 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x72,
- 0x61, 0x63, 0x65, 0x49, 0x64, 0x32, 0x7d, 0x0a, 0x07, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x64,
- 0x12, 0x72, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x31, 0x2e,
+var File_postar_proto protoreflect.FileDescriptor
+
+var file_postar_proto_rawDesc = []byte{
+ 0x0a, 0x0c, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1f,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f,
- 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
- 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
- 0x1a, 0x32, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76,
- 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61,
- 0x70, 0x69, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x21, 0x5a, 0x1f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
- 0x6f, 0x6d, 0x2f, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2f, 0x70, 0x6f, 0x73,
- 0x74, 0x61, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x1a,
+ 0x09, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x70, 0x0a, 0x05, 0x45, 0x6d,
+ 0x61, 0x69, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x73,
+ 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72,
+ 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x62,
+ 0x6f, 0x64, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+ 0x62, 0x6f, 0x64, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79,
+ 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x42, 0x0a, 0x10,
+ 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x12, 0x14, 0x0a, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
+ 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75,
+ 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
+ 0x22, 0x9d, 0x01, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74,
+ 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x05, 0x65, 0x6d,
+ 0x61, 0x69, 0x6c, 0x12, 0x4b, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74,
+ 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c,
+ 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x22, 0x81, 0x01, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74,
+ 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x64,
+ 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x72, 0x61,
+ 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x72, 0x61,
+ 0x63, 0x65, 0x49, 0x64, 0x32, 0x83, 0x01, 0x0a, 0x0d, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x53,
+ 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x72, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d,
+ 0x61, 0x69, 0x6c, 0x12, 0x31, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x61,
+ 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x70, 0x6f,
+ 0x73, 0x74, 0x61, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6d, 0x61,
+ 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x21, 0x5a, 0x1f, 0x67, 0x69,
+ 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x76, 0x69, 0x6e, 0x6f, 0x70, 0x6c,
+ 0x61, 0x6e, 0x2f, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
- file_postard_proto_rawDescOnce sync.Once
- file_postard_proto_rawDescData = file_postard_proto_rawDesc
+ file_postar_proto_rawDescOnce sync.Once
+ file_postar_proto_rawDescData = file_postar_proto_rawDesc
)
-func file_postard_proto_rawDescGZIP() []byte {
- file_postard_proto_rawDescOnce.Do(func() {
- file_postard_proto_rawDescData = protoimpl.X.CompressGZIP(file_postard_proto_rawDescData)
+func file_postar_proto_rawDescGZIP() []byte {
+ file_postar_proto_rawDescOnce.Do(func() {
+ file_postar_proto_rawDescData = protoimpl.X.CompressGZIP(file_postar_proto_rawDescData)
})
- return file_postard_proto_rawDescData
+ return file_postar_proto_rawDescData
}
-var file_postard_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
-var file_postard_proto_goTypes = []interface{}{
+var file_postar_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
+var file_postar_proto_goTypes = []interface{}{
(*Email)(nil), // 0: github.com.avinoplan.postar.api.Email
(*SendEmailOptions)(nil), // 1: github.com.avinoplan.postar.api.SendEmailOptions
(*SendEmailRequest)(nil), // 2: github.com.avinoplan.postar.api.SendEmailRequest
(*SendEmailResponse)(nil), // 3: github.com.avinoplan.postar.api.SendEmailResponse
(ServerCode)(0), // 4: github.com.avinoplan.postar.api.ServerCode
}
-var file_postard_proto_depIdxs = []int32{
+var file_postar_proto_depIdxs = []int32{
0, // 0: github.com.avinoplan.postar.api.SendEmailRequest.email:type_name -> github.com.avinoplan.postar.api.Email
1, // 1: github.com.avinoplan.postar.api.SendEmailRequest.options:type_name -> github.com.avinoplan.postar.api.SendEmailOptions
4, // 2: github.com.avinoplan.postar.api.SendEmailResponse.code:type_name -> github.com.avinoplan.postar.api.ServerCode
- 2, // 3: github.com.avinoplan.postar.api.Postard.SendEmail:input_type -> github.com.avinoplan.postar.api.SendEmailRequest
- 3, // 4: github.com.avinoplan.postar.api.Postard.SendEmail:output_type -> github.com.avinoplan.postar.api.SendEmailResponse
+ 2, // 3: github.com.avinoplan.postar.api.PostarService.SendEmail:input_type -> github.com.avinoplan.postar.api.SendEmailRequest
+ 3, // 4: github.com.avinoplan.postar.api.PostarService.SendEmail:output_type -> github.com.avinoplan.postar.api.SendEmailResponse
4, // [4:5] is the sub-list for method output_type
3, // [3:4] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
@@ -358,14 +359,14 @@ var file_postard_proto_depIdxs = []int32{
0, // [0:3] is the sub-list for field type_name
}
-func init() { file_postard_proto_init() }
-func file_postard_proto_init() {
- if File_postard_proto != nil {
+func init() { file_postar_proto_init() }
+func file_postar_proto_init() {
+ if File_postar_proto != nil {
return
}
file_api_proto_init()
if !protoimpl.UnsafeEnabled {
- file_postard_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ file_postar_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Email); i {
case 0:
return &v.state
@@ -377,7 +378,7 @@ func file_postard_proto_init() {
return nil
}
}
- file_postard_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ file_postar_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SendEmailOptions); i {
case 0:
return &v.state
@@ -389,7 +390,7 @@ func file_postard_proto_init() {
return nil
}
}
- file_postard_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ file_postar_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SendEmailRequest); i {
case 0:
return &v.state
@@ -401,7 +402,7 @@ func file_postard_proto_init() {
return nil
}
}
- file_postard_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+ file_postar_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SendEmailResponse); i {
case 0:
return &v.state
@@ -418,18 +419,18 @@ func file_postard_proto_init() {
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: file_postard_proto_rawDesc,
+ RawDescriptor: file_postar_proto_rawDesc,
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 1,
},
- GoTypes: file_postard_proto_goTypes,
- DependencyIndexes: file_postard_proto_depIdxs,
- MessageInfos: file_postard_proto_msgTypes,
+ GoTypes: file_postar_proto_goTypes,
+ DependencyIndexes: file_postar_proto_depIdxs,
+ MessageInfos: file_postar_proto_msgTypes,
}.Build()
- File_postard_proto = out.File
- file_postard_proto_rawDesc = nil
- file_postard_proto_goTypes = nil
- file_postard_proto_depIdxs = nil
+ File_postar_proto = out.File
+ file_postar_proto_rawDesc = nil
+ file_postar_proto_goTypes = nil
+ file_postar_proto_depIdxs = nil
}
diff --git a/api/postard.proto b/api/postar.proto
similarity index 91%
rename from api/postard.proto
rename to api/postar.proto
index 3a153f3..7be89f8 100644
--- a/api/postard.proto
+++ b/api/postar.proto
@@ -12,7 +12,7 @@ package github.com.avinoplan.postar.api;
import "api.proto";
-// protoc -I=. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative postard.proto
+// protoc -I=. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative postar.proto
option go_package = "github.com/avinoplan/postar/api";
// Email wraps all information of using smtp service.
@@ -42,8 +42,8 @@ message SendEmailResponse {
string trace_id = 3; // For tracing.
}
-// Postard is the core service of postar.
-service Postard {
+// PostarService is the service of postar.
+service PostarService {
// SendEmail send one email.
rpc SendEmail(SendEmailRequest) returns (SendEmailResponse);
}
\ No newline at end of file
diff --git a/api/postar_grpc.pb.go b/api/postar_grpc.pb.go
new file mode 100644
index 0000000..5c3ede4
--- /dev/null
+++ b/api/postar_grpc.pb.go
@@ -0,0 +1,103 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+
+package api
+
+import (
+ context "context"
+ grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// PostarServiceClient is the client API for PostarService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type PostarServiceClient interface {
+ // SendEmail send one email.
+ SendEmail(ctx context.Context, in *SendEmailRequest, opts ...grpc.CallOption) (*SendEmailResponse, error)
+}
+
+type postarServiceClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewPostarServiceClient(cc grpc.ClientConnInterface) PostarServiceClient {
+ return &postarServiceClient{cc}
+}
+
+func (c *postarServiceClient) SendEmail(ctx context.Context, in *SendEmailRequest, opts ...grpc.CallOption) (*SendEmailResponse, error) {
+ out := new(SendEmailResponse)
+ err := c.cc.Invoke(ctx, "/github.com.avinoplan.postar.api.PostarService/SendEmail", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// PostarServiceServer is the server API for PostarService service.
+// All implementations must embed UnimplementedPostarServiceServer
+// for forward compatibility
+type PostarServiceServer interface {
+ // SendEmail send one email.
+ SendEmail(context.Context, *SendEmailRequest) (*SendEmailResponse, error)
+ mustEmbedUnimplementedPostarServiceServer()
+}
+
+// UnimplementedPostarServiceServer must be embedded to have forward compatible implementations.
+type UnimplementedPostarServiceServer struct {
+}
+
+func (UnimplementedPostarServiceServer) SendEmail(context.Context, *SendEmailRequest) (*SendEmailResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method SendEmail not implemented")
+}
+func (UnimplementedPostarServiceServer) mustEmbedUnimplementedPostarServiceServer() {}
+
+// UnsafePostarServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to PostarServiceServer will
+// result in compilation errors.
+type UnsafePostarServiceServer interface {
+ mustEmbedUnimplementedPostarServiceServer()
+}
+
+func RegisterPostarServiceServer(s grpc.ServiceRegistrar, srv PostarServiceServer) {
+ s.RegisterService(&PostarService_ServiceDesc, srv)
+}
+
+func _PostarService_SendEmail_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(SendEmailRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(PostarServiceServer).SendEmail(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/github.com.avinoplan.postar.api.PostarService/SendEmail",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(PostarServiceServer).SendEmail(ctx, req.(*SendEmailRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// PostarService_ServiceDesc is the grpc.ServiceDesc for PostarService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var PostarService_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "github.com.avinoplan.postar.api.PostarService",
+ HandlerType: (*PostarServiceServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "SendEmail",
+ Handler: _PostarService_SendEmail_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "postar.proto",
+}
diff --git a/api/postard_grpc.pb.go b/api/postard_grpc.pb.go
deleted file mode 100644
index 7a9da98..0000000
--- a/api/postard_grpc.pb.go
+++ /dev/null
@@ -1,103 +0,0 @@
-// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
-
-package api
-
-import (
- context "context"
- grpc "google.golang.org/grpc"
- codes "google.golang.org/grpc/codes"
- status "google.golang.org/grpc/status"
-)
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the grpc package it is being compiled against.
-// Requires gRPC-Go v1.32.0 or later.
-const _ = grpc.SupportPackageIsVersion7
-
-// PostardClient is the client API for Postard service.
-//
-// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
-type PostardClient interface {
- // SendEmail send one email.
- SendEmail(ctx context.Context, in *SendEmailRequest, opts ...grpc.CallOption) (*SendEmailResponse, error)
-}
-
-type postardClient struct {
- cc grpc.ClientConnInterface
-}
-
-func NewPostardClient(cc grpc.ClientConnInterface) PostardClient {
- return &postardClient{cc}
-}
-
-func (c *postardClient) SendEmail(ctx context.Context, in *SendEmailRequest, opts ...grpc.CallOption) (*SendEmailResponse, error) {
- out := new(SendEmailResponse)
- err := c.cc.Invoke(ctx, "/github.com.avinoplan.postar.api.Postard/SendEmail", in, out, opts...)
- if err != nil {
- return nil, err
- }
- return out, nil
-}
-
-// PostardServer is the server API for Postard service.
-// All implementations must embed UnimplementedPostardServer
-// for forward compatibility
-type PostardServer interface {
- // SendEmail send one email.
- SendEmail(context.Context, *SendEmailRequest) (*SendEmailResponse, error)
- mustEmbedUnimplementedPostardServer()
-}
-
-// UnimplementedPostardServer must be embedded to have forward compatible implementations.
-type UnimplementedPostardServer struct {
-}
-
-func (UnimplementedPostardServer) SendEmail(context.Context, *SendEmailRequest) (*SendEmailResponse, error) {
- return nil, status.Errorf(codes.Unimplemented, "method SendEmail not implemented")
-}
-func (UnimplementedPostardServer) mustEmbedUnimplementedPostardServer() {}
-
-// UnsafePostardServer may be embedded to opt out of forward compatibility for this service.
-// Use of this interface is not recommended, as added methods to PostardServer will
-// result in compilation errors.
-type UnsafePostardServer interface {
- mustEmbedUnimplementedPostardServer()
-}
-
-func RegisterPostardServer(s grpc.ServiceRegistrar, srv PostardServer) {
- s.RegisterService(&Postard_ServiceDesc, srv)
-}
-
-func _Postard_SendEmail_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(SendEmailRequest)
- if err := dec(in); err != nil {
- return nil, err
- }
- if interceptor == nil {
- return srv.(PostardServer).SendEmail(ctx, in)
- }
- info := &grpc.UnaryServerInfo{
- Server: srv,
- FullMethod: "/github.com.avinoplan.postar.api.Postard/SendEmail",
- }
- handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(PostardServer).SendEmail(ctx, req.(*SendEmailRequest))
- }
- return interceptor(ctx, in, info, handler)
-}
-
-// Postard_ServiceDesc is the grpc.ServiceDesc for Postard service.
-// It's only intended for direct use with grpc.RegisterService,
-// and not to be introspected or modified (even as a copy)
-var Postard_ServiceDesc = grpc.ServiceDesc{
- ServiceName: "github.com.avinoplan.postar.api.Postard",
- HandlerType: (*PostardServer)(nil),
- Methods: []grpc.MethodDesc{
- {
- MethodName: "SendEmail",
- Handler: _Postard_SendEmail_Handler,
- },
- },
- Streams: []grpc.StreamDesc{},
- Metadata: "postard.proto",
-}
diff --git a/cmd/postard/main.go b/cmd/postar/main.go
similarity index 55%
rename from cmd/postard/main.go
rename to cmd/postar/main.go
index 9ff1bf7..0f7c8e0 100644
--- a/cmd/postard/main.go
+++ b/cmd/postar/main.go
@@ -9,31 +9,42 @@
package main
import (
- "net"
-
"github.com/FishGoddess/logit"
+ "github.com/avinoplan/postar/configs"
"github.com/avinoplan/postar/internal/biz"
"github.com/avinoplan/postar/internal/server"
"github.com/panjf2000/ants/v2"
)
-func main() {
- logger := logit.NewLogger()
+func loadConfig() (*configs.Config, error) {
+ // TODO 加载配置文件初始化配置
+ return configs.NewDefaultConfig(), nil
+}
+
+func initLogger(c *configs.Config) *logit.Logger {
+ return logit.NewLogger()
+}
+
+func initPool(c *configs.Config) *ants.Pool {
pool, err := ants.NewPool(64)
if err != nil {
panic(err)
}
- defer pool.Release()
-
- smtpBiz := biz.NewSmtpBiz(pool, "", 0, "", "")
- svr := server.NewGrpcServer(logger, smtpBiz)
+ return pool
+}
- listener, err := net.Listen("tcp", ":5897")
+func main() {
+ c, err := loadConfig()
if err != nil {
panic(err)
}
- err = svr.Run(listener)
+ logger := initLogger(c)
+ pool := initPool(c)
+ defer pool.Release()
+
+ smtpBiz := biz.NewSMTPBiz(c, logger, pool)
+ err = server.NewGRPCServer(c, logger, smtpBiz).Start()
if err != nil {
panic(err)
}
diff --git a/configs/config.go b/configs/config.go
new file mode 100644
index 0000000..67e27db
--- /dev/null
+++ b/configs/config.go
@@ -0,0 +1,41 @@
+// Copyright 2022 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2022/01/23 01:28:36
+
+package configs
+
+type ServerConfig struct {
+ Type string `int:"type"` // The type of server.
+ Address string `ini:"address"` // The address(including ip and port) of server.
+}
+type SMTPConfig struct {
+ Host string `int:"host"` // The host of smtp server.
+ Port int `int:"port"` // The port of smtp server.
+ User string `int:"user"` // The user of smtp server.
+ Password string `int:"password"` // The password of smtp server.
+}
+
+// Config stores all configurations of postar.
+type Config struct {
+ Server ServerConfig `int:"server"`
+ SMTP SMTPConfig `int:"smtp"`
+}
+
+// NewDefaultConfig returns a new config.
+func NewDefaultConfig() *Config {
+ return &Config{
+ Server: ServerConfig{
+ Type: "http",
+ Address: ":5897",
+ },
+ SMTP: SMTPConfig{
+ Port: 587,
+ },
+ }
+}
+
+// TODO 封装配置查询方法
diff --git a/internal/biz/smtp.go b/internal/biz/smtp.go
index c977261..0db0638 100644
--- a/internal/biz/smtp.go
+++ b/internal/biz/smtp.go
@@ -12,44 +12,41 @@ import (
"context"
"github.com/FishGoddess/logit"
+ "github.com/avinoplan/postar/configs"
"github.com/avinoplan/postar/internal/model"
"github.com/avinoplan/postar/pkg/errors"
"github.com/panjf2000/ants/v2"
"gopkg.in/gomail.v2"
)
-// SmtpBiz is the biz of smtp.
-type SmtpBiz struct {
- pool *ants.Pool // The pool of workers.
- host string // The host of smtp server.
- port int // The port of smtp server.
- user string // The user of smtp server.
- password string // The password of smtp server.
+// SMTPBiz is the biz of smtp.
+type SMTPBiz struct {
+ c *configs.Config
+ logger *logit.Logger
+ pool *ants.Pool // The pool of workers.
}
-// NewSmtpBiz returns a new SmtpBiz.
-func NewSmtpBiz(pool *ants.Pool, host string, port int, user string, password string) *SmtpBiz {
- return &SmtpBiz{
- pool: pool,
- host: host,
- port: port,
- user: user,
- password: password,
+// NewSMTPBiz returns a new SMTPBiz.
+func NewSMTPBiz(c *configs.Config, logger *logit.Logger, pool *ants.Pool) *SMTPBiz {
+ return &SMTPBiz{
+ c: c,
+ logger: logger,
+ pool: pool,
}
}
// sendEmail sends email and returns an error if something wrong happens.
-func (sb *SmtpBiz) sendEmail(email *model.Email) error {
+func (sb *SMTPBiz) sendEmail(email *model.Email) error {
msg := gomail.NewMessage()
- msg.SetHeader("From", sb.user)
- msg.SetHeader("To", email.To...)
msg.SetHeader("Subject", email.Subject)
+ msg.SetHeader("From", sb.c.SMTP.User)
+ msg.SetHeader("To", email.Receivers...)
msg.SetBody(email.BodyType, email.Body)
- return gomail.NewDialer(sb.host, sb.port, sb.user, sb.password).DialAndSend(msg)
+ return gomail.NewDialer(sb.c.SMTP.Host, sb.c.SMTP.Port, sb.c.SMTP.User, sb.c.SMTP.Password).DialAndSend(msg)
}
// SendEmail sends email to somewhere.
-func (sb *SmtpBiz) SendEmail(ctx context.Context, email *model.Email, options *model.SendEmailOptions) error {
+func (sb *SMTPBiz) SendEmail(ctx context.Context, email *model.Email, options *model.SendEmailOptions) error {
logger := logit.FromContext(ctx)
if options == nil {
diff --git a/internal/biz/smtp_test.go b/internal/biz/smtp_test.go
index 2b57558..bd0c83d 100644
--- a/internal/biz/smtp_test.go
+++ b/internal/biz/smtp_test.go
@@ -15,35 +15,45 @@ import (
"testing"
"time"
+ "github.com/FishGoddess/logit"
+ "github.com/avinoplan/postar/configs"
"github.com/avinoplan/postar/internal/model"
"github.com/panjf2000/ants/v2"
)
-// go test -v -cover -run=^TestSmtpBiz$
-func TestSmtpBiz(t *testing.T) {
- host := os.Getenv("POSTAR_SMTP_HOST")
- user := os.Getenv("POSTAR_SMTP_USER")
- password := os.Getenv("POSTAR_SMTP_PASSWORD")
- to := os.Getenv("POSTAR_SMTP_TO")
- if host == "" || user == "" || password == "" || to == "" {
- t.Skipf("smtp host %s or user %s or password %s or to %s is empty", host, user, password, to)
- }
-
+func newConfig() *configs.Config {
port, err := strconv.ParseInt(os.Getenv("POSTAR_SMTP_PORT"), 10, 64)
if err != nil {
port = 587
}
+ c := configs.NewDefaultConfig()
+ c.SMTP.Host = os.Getenv("POSTAR_SMTP_HOST")
+ c.SMTP.Port = int(port)
+ c.SMTP.User = os.Getenv("POSTAR_SMTP_USER")
+ c.SMTP.Password = os.Getenv("POSTAR_SMTP_PASSWORD")
+ return c
+}
+
+// go test -v -cover -run=^TestSMTPBiz$
+func TestSMTPBiz(t *testing.T) {
+ c := newConfig()
+ receiver := os.Getenv("POSTAR_SMTP_RECEIVER")
+ if c.SMTP.Host == "" || c.SMTP.User == "" || c.SMTP.Password == "" || receiver == "" {
+ t.Skipf("smtp host %s or user %s or password %s or receiver %s is empty", c.SMTP.Host, c.SMTP.User, c.SMTP.Password, receiver)
+ }
+
pool, _ := ants.NewPool(64)
defer pool.Release()
-
- smtpService := NewSmtpBiz(pool, host, int(port), user, password)
- err = smtpService.SendEmail(context.Background(), &model.Email{
- To: []string{to},
- Subject: t.Name(),
- BodyType: "text/html;charset=utf-8",
- Body: t.Name() + time.Now().Format("20060102150405.000"),
+
+ smtpService := NewSMTPBiz(c, logit.NewLogger(), pool)
+ err := smtpService.SendEmail(context.Background(), &model.Email{
+ Subject: t.Name(),
+ Receivers: []string{receiver},
+ BodyType: "text/html;charset=utf-8",
+ Body: t.Name() + time.Now().Format("20060102150405.000"),
}, model.DefaultSendEmailOptions())
+
if err != nil {
t.Error(err)
}
diff --git a/internal/model/smtp.go b/internal/model/smtp.go
index 46d40f6..8333571 100644
--- a/internal/model/smtp.go
+++ b/internal/model/smtp.go
@@ -12,10 +12,10 @@ import "time"
// Email is an email.
type Email struct {
- To []string // Receivers.
- Subject string // Subject.
- BodyType string // Body type.
- Body string // Body.
+ Subject string // Subject.
+ Receivers []string // Receivers.
+ BodyType string // Body type.
+ Body string // Body.
}
// SendEmailOptions is the options of sending one email.
diff --git a/internal/server/grpc.go b/internal/server/grpc.go
index c67f742..72eb9f8 100644
--- a/internal/server/grpc.go
+++ b/internal/server/grpc.go
@@ -14,6 +14,7 @@ import (
"github.com/FishGoddess/logit"
"github.com/avinoplan/postar/api"
+ "github.com/avinoplan/postar/configs"
"github.com/avinoplan/postar/internal/biz"
"github.com/avinoplan/postar/pkg/errors"
"github.com/avinoplan/postar/pkg/trace"
@@ -22,15 +23,17 @@ import (
// GRPCServer is a grpc implement of PostardServer.
type GRPCServer struct {
- api.UnimplementedPostardServer
+ api.UnimplementedPostarServiceServer
server *grpc.Server
+ c *configs.Config
logger *logit.Logger
- smtpBiz *biz.SmtpBiz
+ smtpBiz *biz.SMTPBiz
}
-// NewGrpcServer returns a new GRPCServer.
-func NewGrpcServer(logger *logit.Logger, smtpBiz *biz.SmtpBiz) *GRPCServer {
+// NewGRPCServer returns a new GRPCServer.
+func NewGRPCServer(c *configs.Config, logger *logit.Logger, smtpBiz *biz.SMTPBiz) Server {
return &GRPCServer{
+ c: c,
logger: logger,
smtpBiz: smtpBiz,
}
@@ -65,14 +68,20 @@ func (gs *GRPCServer) SendEmail(ctx context.Context, request *api.SendEmailReque
}, nil
}
-// Run runs GRPCServer with listener.
-func (gs *GRPCServer) Run(listener net.Listener) error {
+// Start starts GRPCServer.
+func (gs *GRPCServer) Start() error {
+ listener, err := net.Listen("tcp", gs.c.Server.Address)
+ if err != nil {
+ return err
+ }
+
gs.server = grpc.NewServer()
- api.RegisterPostardServer(gs.server, gs)
+ api.RegisterPostarServiceServer(gs.server, gs)
return gs.server.Serve(listener)
}
-// Shutdown shutdowns GRPCServer gracefully.
-func (gs *GRPCServer) Shutdown() {
+// Stop stops GRPCServer gracefully.
+func (gs *GRPCServer) Stop() error {
gs.server.GracefulStop()
+ return nil
}
diff --git a/internal/server/server.go b/internal/server/server.go
new file mode 100644
index 0000000..6df80b6
--- /dev/null
+++ b/internal/server/server.go
@@ -0,0 +1,26 @@
+// Copyright 2022 Ye Zi Jie. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+//
+// Author: FishGoddess
+// Email: fishgoddess@qq.com
+// Created at 2022/01/23 02:18:24
+
+package server
+
+import (
+ "github.com/FishGoddess/logit"
+ "github.com/avinoplan/postar/configs"
+ "github.com/avinoplan/postar/internal/biz"
+)
+
+var (
+ servers = map[string]func(c *configs.Config, logger *logit.Logger, smtpBiz *biz.SMTPBiz) Server{
+ "grpc": NewGRPCServer,
+ }
+)
+
+type Server interface {
+ Start() error
+ Stop() error
+}
From f580ce9f0b8e2c2fc3e80cdb526c5192766adfce Mon Sep 17 00:00:00 2001
From: FishGoddess <1149062639@qq.com>
Date: Mon, 24 Jan 2022 02:10:53 +0800
Subject: [PATCH 12/27] =?UTF-8?q?=E9=87=8D=E6=9E=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 22 ++++++--------
LICENSE | 20 -------------
build.sh | 62 +++++++++++++++++++++++++++++++++++++++
cmd/postar/main.go | 50 +++++++++++++++++++++++++++----
go.mod | 1 +
go.sum | 4 +++
internal/server/server.go | 10 +++++++
7 files changed, 130 insertions(+), 39 deletions(-)
delete mode 100644 LICENSE
create mode 100644 build.sh
diff --git a/.gitignore b/.gitignore
index 475809f..a201e7f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,22 +1,18 @@
-# Binaries for programs and plugins
+# OS
*.exe
*.exe~
*.dll
*.so
*.dylib
-*.tar.gz
-target/
-# Test binary, built with `go test -c`
-*.test
+# IDE
+.idea/
+*.iml
+.vscode/
-# Output of the go coverage tool, specifically when used with LiteIDE
+# Program
+*.test
*.out
-
-# logs
+target/
+*.tar.gz
*.log
-
-# ide
-.idea/
-*.iml
-.vscode/*
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 41c001c..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2021 Ye Zi Jie
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-the rights to use, copy, modify, merge, publish, distribute, sublicense,
-and/or sell copies of the Software, and to permit persons to whom the Software
-is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
-INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
-FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/build.sh b/build.sh
new file mode 100644
index 0000000..017ad5d
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+VERSION=v0.3.0-alpha
+echo "VERSION: $VERSION"
+echo "----------------------------------------------------------------------"
+
+# Check
+WORKDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
+echo "WORKDIR: $WORKDIR"
+TARGET=$WORKDIR/target
+echo "TARGET: $TARGET"
+CONFIG_FILE=$WORKDIR/_examples/config/postar.ini
+echo "CONFIG_FILE: $CONFIG_FILE"
+LICENSE_FILE=$WORKDIR/LICENSE
+echo "LICENSE_FILE: $LICENSE_FILE"
+echo "----------------------------------------------------------------------"
+
+echo "Please check the paths above! It's right? (y/n)"
+read -r right
+if [ -z "$right" ]; then
+ echo "Input y or n to continue..."
+ exit
+fi
+
+if [ "$right" == "n" ]; then
+ echo "Fix the wrong paths to continue..."
+ exit
+fi
+echo "----------------------------------------------------------------------"
+
+# Start building
+echo "Start building..."
+rm -r "${TARGET:?}" && mkdir -p "$TARGET"
+cd "$WORKDIR"/cmd/postar || exit
+
+# Go build: windows, linux and darwin
+echo "Building windows version..."
+CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o "$TARGET"/postar-windows.exe
+
+echo "Building linux version..."
+CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o "$TARGET"/postar-linux
+chmod +x "$TARGET"/postar-linux
+
+echo "Building darwin version..."
+CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o "$TARGET"/postar-darwin
+chmod +x "$TARGET"/postar-darwin
+
+# Before packaging
+echo "Start packaging..."
+cd "$TARGET" || exit
+cp "$CONFIG_FILE" "$TARGET"/
+cp "$LICENSE_FILE" "$TARGET"/
+
+# Start Packaging
+echo "Packaging windows version..."
+tar -czf postar-$VERSION-windows.tar.gz "$TARGET"/postar-windows.exe "$CONFIG_FILE" "$LICENSE_FILE"
+tar -czf postar-$VERSION-linux.tar.gz "$TARGET"/postar-linux "$CONFIG_FILE" "$LICENSE_FILE"
+tar -czf postar-$VERSION-darwin.tar.gz "$TARGET"/postar-darwin "$CONFIG_FILE" "$LICENSE_FILE"
+
+# Done
+echo "Done."
+rm "$TARGET"/postar-windows.exe "$TARGET"/postar-linux "$TARGET"/postar-darwin "$CONFIG_FILE" "$LICENSE_FILE"
diff --git a/cmd/postar/main.go b/cmd/postar/main.go
index 0f7c8e0..4cad744 100644
--- a/cmd/postar/main.go
+++ b/cmd/postar/main.go
@@ -9,16 +9,38 @@
package main
import (
+ "flag"
+ "fmt"
+ "os"
+ "os/signal"
+ "runtime"
+ "syscall"
+
"github.com/FishGoddess/logit"
"github.com/avinoplan/postar/configs"
"github.com/avinoplan/postar/internal/biz"
"github.com/avinoplan/postar/internal/server"
+ "github.com/go-ini/ini"
"github.com/panjf2000/ants/v2"
)
+const (
+ version = "postar-v0.3.0-alpha"
+)
+
func loadConfig() (*configs.Config, error) {
- // TODO 加载配置文件初始化配置
- return configs.NewDefaultConfig(), nil
+ configFile := flag.String("config.file", "postar.ini", "The configuration file of postar.")
+ showVersion := flag.Bool("version", false, "Check version of postar.")
+ flag.Parse()
+
+ if *showVersion {
+ fmt.Printf("%s (%s, %s, %s)\n", version, runtime.GOOS, runtime.GOARCH, runtime.Version())
+ os.Exit(0)
+ }
+
+ c := configs.NewDefaultConfig()
+ err := ini.MapTo(c, *configFile)
+ return c, err
}
func initLogger(c *configs.Config) *logit.Logger {
@@ -33,6 +55,23 @@ func initPool(c *configs.Config) *ants.Pool {
return pool
}
+func runServer(c *configs.Config, logger *logit.Logger, smtpBiz *biz.SMTPBiz) {
+ svr := server.NewServer(c, logger, smtpBiz)
+
+ go func() {
+ err := svr.Start()
+ if err != nil {
+ panic(err)
+ }
+ }()
+
+ signalCh := make(chan os.Signal, 1)
+ signal.Notify(signalCh, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
+ <-signalCh
+ fmt.Println("Postar is shutdown gracefully...")
+ svr.Stop()
+}
+
func main() {
c, err := loadConfig()
if err != nil {
@@ -40,12 +79,11 @@ func main() {
}
logger := initLogger(c)
+ defer logger.Close()
+
pool := initPool(c)
defer pool.Release()
smtpBiz := biz.NewSMTPBiz(c, logger, pool)
- err = server.NewGRPCServer(c, logger, smtpBiz).Start()
- if err != nil {
- panic(err)
- }
+ runServer(c, logger, smtpBiz)
}
diff --git a/go.mod b/go.mod
index aa6fdc3..523085d 100644
--- a/go.mod
+++ b/go.mod
@@ -5,6 +5,7 @@ go 1.15
require (
github.com/FishGoddess/errors v0.0.2
github.com/FishGoddess/logit v0.4.11
+ github.com/go-ini/ini v1.66.3
github.com/panjf2000/ants/v2 v2.4.7
google.golang.org/grpc v1.40.0
google.golang.org/protobuf v1.27.1
diff --git a/go.sum b/go.sum
index 8077208..268e58b 100644
--- a/go.sum
+++ b/go.sum
@@ -25,6 +25,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-ini/ini v1.66.3 h1:Ftrhd6NNIEu4LdPoqP7fyXRFu/I3vRnY8GWpHa/Xsz4=
+github.com/go-ini/ini v1.66.3/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -126,6 +128,8 @@ gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
+gopkg.in/ini.v1 v1.66.3 h1:jRskFVxYaMGAMUbN0UZ7niA9gzL9B49DOqE78vg0k3w=
+gopkg.in/ini.v1 v1.66.3/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/internal/server/server.go b/internal/server/server.go
index 6df80b6..4bf4dd2 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -9,6 +9,8 @@
package server
import (
+ "fmt"
+
"github.com/FishGoddess/logit"
"github.com/avinoplan/postar/configs"
"github.com/avinoplan/postar/internal/biz"
@@ -24,3 +26,11 @@ type Server interface {
Start() error
Stop() error
}
+
+func NewServer(c *configs.Config, logger *logit.Logger, smtpBiz *biz.SMTPBiz) Server {
+ newServer, ok := servers[c.Server.Type]
+ if !ok {
+ panic(fmt.Errorf("server: type %s not found", c.Server.Type))
+ }
+ return newServer(c, logger, smtpBiz)
+}
From 392f0fba92ef427bab8e657c8de0dd8487703cb7 Mon Sep 17 00:00:00 2001
From: FishGoddess <1149062639@qq.com>
Date: Mon, 24 Jan 2022 23:54:09 +0800
Subject: [PATCH 13/27] =?UTF-8?q?=E6=9E=84=E5=BB=BA=E8=84=9A=E6=9C=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
LICENSE | 20 ++++++++++++++++
README.en.md | 15 ++++++------
README.md | 14 +++++------
_examples/config/postar.ini | 0
build.sh | 47 +++++++++++++++++--------------------
pkg/encode/encode.go | 17 +++++++-------
pkg/encode/encode_test.go | 34 +++++++++++++++++----------
pkg/trace/trace.go | 4 ++--
8 files changed, 89 insertions(+), 62 deletions(-)
create mode 100644 LICENSE
create mode 100644 _examples/config/postar.ini
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..41c001c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2021 Ye Zi Jie
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/README.en.md b/README.en.md
index f190ee8..7c71d72 100644
--- a/README.en.md
+++ b/README.en.md
@@ -12,8 +12,8 @@
* Plain and Html form email supports
* Synchronous/Asynchronous mode supports, and timeout is available in synchronous mode
-* HTTP api supports, and use http2 is ok
-* Gracefully shutdown with signal mechanism supports
+* Support http/http2/grpc/vex/udp protocol
+* Gracefully shutdown with signal mechanism
_Check [HISTORY.md](./HISTORY.md) and [FUTURE.md](./FUTURE.md) to know about more information._
@@ -31,9 +31,9 @@ Postar has two ways to get binary:
1. Invoking `./build.sh` in the root of source code will generate target directory, which contains all binary files.
-2. Build by `go` command, see `go build`.
+2. Building by `go build` (or running by `go run`) in `cmd/postar`, see `go`.
-_Notice: Default config file is `/opt/postar/conf/postar.ini`, default log output directory is `/opt/postar/log/`, and you need them to start service._
+_Notice: Default config file is `./postar.ini`, default log output directory is `./log/service.log`._
> Want to know how to use? See [_examples](_examples).
@@ -43,6 +43,7 @@ If you find that something is not working as expected please open an _**issue**_
### 📦 Projects postar used
-| Project | Author | Description | link |
-|---------|-------------|-------------------------------------------------------|-----------------------------------------------------------------------------------------------|
-| logit | FishGoddess | A high-performance and easy-to-use logging foundation | [Gitee](https://gitee.com/FishGoddess/logit) / [GitHub](https://github.com/FishGoddess/logit) |
+| Project | Author | Description | link |
+|---------|-------------|-------------------------------------------------------|-------------------------------------------------------------------------------------------------|
+| logit | FishGoddess | A high-performance and easy-to-use logging foundation | [Gitee](https://gitee.com/FishGoddess/logit) / [GitHub](https://github.com/FishGoddess/logit) |
+| errors | FishGoddess | A lib for handling error gracefully in Go | [Gitee](https://gitee.com/FishGoddess/errors) / [GitHub](https://github.com/FishGoddess/errors) |
diff --git a/README.md b/README.md
index 112cd74..945baa1 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@
* 支持发送文本邮件和 HTML 邮件
* 支持同步、异步邮件发送,同步模式可配置超时
-* 支持 http 请求调用接口,可配置 http2 协议
+* 支持 http/http2/grpc/vex/udp 等网络协议
* 支持 signal 通知的平滑下线
_历史版本的特性请查看 [HISTORY.md](./HISTORY.md)。未来版本的新特性和计划请查看 [FUTURE.md](./FUTURE.md)。_
@@ -31,9 +31,9 @@ Postar 的二进制执行包可以通过源码进行编译得到,一共有两
1. 在源码根目录执行 `./build.sh` 会生成 target 目录,所有的二进制包都在里面
-2. 通过 `go` 命令构建或启动服务,参考 `go build`。
+2. 在 `cmd/postar` 目录下使用 `go build` 构建服务(或 `go run` 启动服务),参考 `go` 命令。
-_注意:默认的配置文件路径是 `/opt/postar/conf/postar.ini`,默认的日志输出路径是 `/opt/postar/log/`,需要有对应的文件和文件夹才可以启动。_
+_注意:默认的配置文件路径是 `./postar.ini`,默认的日志输出是 `./log/service.log`。_
> 想知道怎么使用?查看 [_examples](_examples)。
@@ -43,7 +43,7 @@ _注意:默认的配置文件路径是 `/opt/postar/conf/postar.ini`,默认
### 📦 postar 使用的技术
-| 项目 | 作者 | 描述 | 链接 |
-|-------|-------------|---------------------|--------------------------------------------------------------------------------------------|
-| logit | FishGoddess | 一个高性能、功能强大且极易上手的日志库 | [码云](https://gitee.com/FishGoddess/logit) / [GitHub](https://github.com/FishGoddess/logit) |
-
+| 项目 | 作者 | 描述 | 链接 |
+|--------|-------------|---------------------|----------------------------------------------------------------------------------------------|
+| logit | FishGoddess | 一个高性能、功能强大且极易上手的日志库 | [码云](https://gitee.com/FishGoddess/logit) / [GitHub](https://github.com/FishGoddess/logit) |
+| errors | FishGoddess | 一个用于优雅地处理 Go 中错误的库 | [码云](https://gitee.com/FishGoddess/errors) / [GitHub](https://github.com/FishGoddess/errors) |
diff --git a/_examples/config/postar.ini b/_examples/config/postar.ini
new file mode 100644
index 0000000..e69de29
diff --git a/build.sh b/build.sh
index 017ad5d..ec1f57b 100644
--- a/build.sh
+++ b/build.sh
@@ -15,7 +15,7 @@ LICENSE_FILE=$WORKDIR/LICENSE
echo "LICENSE_FILE: $LICENSE_FILE"
echo "----------------------------------------------------------------------"
-echo "Please check the paths above! It's right? (y/n)"
+echo "Want to continue? (y/n)"
read -r right
if [ -z "$right" ]; then
echo "Input y or n to continue..."
@@ -23,40 +23,37 @@ if [ -z "$right" ]; then
fi
if [ "$right" == "n" ]; then
- echo "Fix the wrong paths to continue..."
+ echo "Fix the problems to continue..."
exit
fi
echo "----------------------------------------------------------------------"
-# Start building
-echo "Start building..."
-rm -r "${TARGET:?}" && mkdir -p "$TARGET"
+# Prepare
+echo "Preparing..."
+mkdir -p "$TARGET" && rm -rf "${TARGET:?}"/*.tar.gz
cd "$WORKDIR"/cmd/postar || exit
-# Go build: windows, linux and darwin
-echo "Building windows version..."
-CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o "$TARGET"/postar-windows.exe
+# build builds the target os and arch version package
+function build() {
+ local GOOS=$1
+ local GOARCH=$2
+ local BINARY_FILE=$3
+ local PKG_FILE="$TARGET"/postar-$VERSION-$GOOS-$GOARCH.tar.gz
-echo "Building linux version..."
-CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o "$TARGET"/postar-linux
-chmod +x "$TARGET"/postar-linux
+ CGO_ENABLED=0 GOOS=$GOOS GOARCH=$GOARCH go build -o "$BINARY_FILE"
+ tar -czPf "$PKG_FILE" "$BINARY_FILE" "$CONFIG_FILE" "$LICENSE_FILE"
+ echo "The $GOOS-$GOARCH package can be found in $PKG_FILE"
+ rm "$BINARY_FILE"
+}
-echo "Building darwin version..."
-CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o "$TARGET"/postar-darwin
-chmod +x "$TARGET"/postar-darwin
+echo "Building windows-amd64 version..."
+build windows amd64 "$TARGET"/postar.exe
-# Before packaging
-echo "Start packaging..."
-cd "$TARGET" || exit
-cp "$CONFIG_FILE" "$TARGET"/
-cp "$LICENSE_FILE" "$TARGET"/
+echo "Building linux-amd64 version..."
+build linux amd64 "$TARGET"/postar
-# Start Packaging
-echo "Packaging windows version..."
-tar -czf postar-$VERSION-windows.tar.gz "$TARGET"/postar-windows.exe "$CONFIG_FILE" "$LICENSE_FILE"
-tar -czf postar-$VERSION-linux.tar.gz "$TARGET"/postar-linux "$CONFIG_FILE" "$LICENSE_FILE"
-tar -czf postar-$VERSION-darwin.tar.gz "$TARGET"/postar-darwin "$CONFIG_FILE" "$LICENSE_FILE"
+echo "Building darwin-amd64 version..."
+build darwin amd64 "$TARGET"/postar
# Done
echo "Done."
-rm "$TARGET"/postar-windows.exe "$TARGET"/postar-linux "$TARGET"/postar-darwin "$CONFIG_FILE" "$LICENSE_FILE"
diff --git a/pkg/encode/encode.go b/pkg/encode/encode.go
index 851d529..3ce70ce 100644
--- a/pkg/encode/encode.go
+++ b/pkg/encode/encode.go
@@ -13,7 +13,6 @@ import (
"fmt"
"math/rand"
"os"
- "strconv"
"time"
)
@@ -27,15 +26,10 @@ var (
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
}
- pid = strconv.Itoa(os.Getpid())
+ pidHex = numberHex(uint64(os.Getpid()), 6, 0)
random = rand.New(rand.NewSource(time.Now().Unix()))
)
-// PID returns pid in string.
-func PID() string {
- return pid
-}
-
// numberHex returns num in hex string.
// The hex string will be cut with start and end.
func numberHex(num uint64, start int, end int) string {
@@ -53,13 +47,18 @@ func numberHex(num uint64, start int, end int) string {
return fmt.Sprintf("%x", b[start:end])
}
+// PIDHex returns pid in string.
+func PIDHex() string {
+ return pidHex
+}
+
// NowHex returns in current time in hex string.
func NowHex() string {
return numberHex(uint64(time.Now().Unix()), 4, 0)
}
-// RandomString returns a string including 0-9/a-z/A-Z not longer than length.
-func RandomString(length int) string {
+// StringHex returns a string including 0-9/a-z/A-Z not longer than length.
+func StringHex(length int) string {
b := make([]byte, length)
for i := 0; i < length; i++ {
b[i] = letters[random.Intn(62)]
diff --git a/pkg/encode/encode_test.go b/pkg/encode/encode_test.go
index 554b9bd..08be21d 100644
--- a/pkg/encode/encode_test.go
+++ b/pkg/encode/encode_test.go
@@ -8,7 +8,22 @@
package encode
-import "testing"
+import (
+ "os"
+ "testing"
+ "time"
+)
+
+// go test -v -cover -run=^TestPidHex$
+func TestPidHex(t *testing.T) {
+ pidHex := PIDHex()
+ if len(pidHex) != 4 {
+ t.Errorf("length of PIDHex is wrong with %s, %d", pidHex, len(pidHex))
+ }
+
+ pid := uint64(os.Getpid())
+ t.Log(pid, numberHex(pid, 0, 0), pidHex)
+}
// go test -v -cover -run=^NowTimeHex$
func TestNowTimeHex(t *testing.T) {
@@ -16,21 +31,16 @@ func TestNowTimeHex(t *testing.T) {
if len(timeHex) != 8 {
t.Errorf("length of TimeHex is wrong with %s, %d", timeHex, len(timeHex))
}
-}
-// go test -v -cover -run=^TestPidHex$
-func TestPidHex(t *testing.T) {
- pidHex := PID()
- if len(pidHex) != 8 {
- t.Errorf("length of PID is wrong with %s, %d", pidHex, len(pidHex))
- }
+ now := uint64(time.Now().Unix())
+ t.Log(now, numberHex(now, 0, 0), timeHex)
}
-// go test -v -cover -run=^TestRandomString$
-func TestRandomString(t *testing.T) {
+// go test -v -cover -run=^TestStringHex$
+func TestStringHex(t *testing.T) {
length := 16
- str := RandomString(length)
+ str := StringHex(length)
if len(str) != length {
- t.Errorf("length of RandomString is wrong with %d", len(str))
+ t.Errorf("length of StringHex is wrong with %d", len(str))
}
}
diff --git a/pkg/trace/trace.go b/pkg/trace/trace.go
index 69d1aa7..f617f77 100644
--- a/pkg/trace/trace.go
+++ b/pkg/trace/trace.go
@@ -20,8 +20,8 @@ var (
// NewTraceID returns a new trace id.
func NewTraceID() string {
- salt := encode.RandomString(6)
- return encode.NowHex() + salt[:3] + encode.PID() + salt[3:]
+ salt := encode.StringHex(6)
+ return encode.NowHex() + salt[:3] + encode.PIDHex() + salt[3:]
}
// NewContext wraps ctx with a trace id.
From 21be669bab3ae84b11d36a2428c842e9c3c11d74 Mon Sep 17 00:00:00 2001
From: FishGoddess <1149062639@qq.com>
Date: Tue, 25 Jan 2022 01:26:29 +0800
Subject: [PATCH 14/27] =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=85=8D=E7=BD=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
_examples/config/postar.ini | 10 ++++++++++
_icons/coverage.svg | 4 ++--
cmd/postar/main.go | 2 +-
configs/config.go | 37 ++++++++++++++++++++++++++++++++++++-
internal/biz/smtp.go | 4 ++--
internal/biz/smtp_test.go | 2 +-
internal/server/grpc.go | 2 +-
internal/server/server.go | 4 ++--
8 files changed, 55 insertions(+), 10 deletions(-)
diff --git a/_examples/config/postar.ini b/_examples/config/postar.ini
index e69de29..3573613 100644
--- a/_examples/config/postar.ini
+++ b/_examples/config/postar.ini
@@ -0,0 +1,10 @@
+[worker]
+number = 64
+[server]
+type = "http"
+address = ":5897"
+[smtp]
+host = ""
+port = 587
+user = ""
+password = ""
\ No newline at end of file
diff --git a/_icons/coverage.svg b/_icons/coverage.svg
index 27f053e..303f691 100644
--- a/_icons/coverage.svg
+++ b/_icons/coverage.svg
@@ -10,7 +10,7 @@
邮件内容
", + }, + Options: nil, + } + fmt.Printf("client req: %+v\n", req) + + client := api.NewPostarServiceClient(conn) + rsp, err := client.SendEmail(context.Background(), req) + if err != nil { + panic(err) + } + + fmt.Printf("server rsp: %+v\n", rsp) +} diff --git a/_examples/http.go b/_examples/http.go new file mode 100644 index 0000000..8443c5d --- /dev/null +++ b/_examples/http.go @@ -0,0 +1,49 @@ +package main + +import ( + "bytes" + "fmt" + "github.com/avinoplan/postar/api" + "google.golang.org/protobuf/proto" + "io/ioutil" + "net/http" +) + +func main() { + url := "http://127.0.0.1:5897/sendEmail" + + emailReq := &api.SendEmailRequest{ + Email: &api.Email{ + Receivers: nil, + Subject: "测试邮件", + BodyType: "text/html", + Body: "邮件内容
", + }, + Options: nil, + } + fmt.Printf("client req: %+v\n", emailReq) + + marshaled, err := proto.Marshal(emailReq) + if err != nil { + panic(err) + } + + resp, err := http.Post(url, "application/octet-stream", bytes.NewReader(marshaled)) + if err != nil { + panic(err) + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + panic(err) + } + + emailRsp := new(api.SendEmailResponse) + err = proto.Unmarshal(body, emailRsp) + if err != nil { + panic(err) + } + + fmt.Printf("server rsp: %+v\n", emailRsp) +} diff --git a/internal/biz/smtp.go b/internal/biz/smtp.go index e8ffd83..d81b1ff 100644 --- a/internal/biz/smtp.go +++ b/internal/biz/smtp.go @@ -11,6 +11,7 @@ package biz import ( "context" "github.com/avinoplan/postar/pkg/log" + "github.com/avinoplan/postar/pkg/trace" liberrors "github.com/FishGoddess/errors" "github.com/avinoplan/postar/configs" @@ -46,13 +47,17 @@ func (sb *SMTPBiz) sendEmail(email *model.Email) error { // SendEmail sends email to somewhere. func (sb *SMTPBiz) SendEmail(ctx context.Context, email *model.Email, options *model.SendEmailOptions) error { + traceID := trace.FromContext(ctx) + if email == nil { - return errors.BadRequestErr(liberrors.New("email == nil")) + err := liberrors.New("email is nil") + log.Error(err, "email is nil").String("traceID", traceID).End() + return errors.BadRequest(err) } if options == nil { options = model.DefaultSendEmailOptions(sb.c) - log.Debug("options is nil, using default options").Any("options", options).End() + log.Debug("options is nil, using default options").String("traceID", traceID).Any("options", options).End() } ctx, cancel := context.WithTimeout(ctx, options.Timeout) @@ -65,7 +70,7 @@ func (sb *SMTPBiz) SendEmail(ctx context.Context, email *model.Email, options *m }) if err != nil { - log.Error(err, "submit email sending task to pool failed").End() + log.Error(err, "submit email sending task to pool failed").String("traceID", traceID).Any("email", email).End() return errors.SendEmailFailedErr(err) } @@ -76,14 +81,14 @@ func (sb *SMTPBiz) SendEmail(ctx context.Context, email *model.Email, options *m select { case err = <-errorCh: if err != nil { - log.Error(err, "send email failed").End() + log.Error(err, "send email failed").String("traceID", traceID).Any("email", email).End() return errors.SendEmailFailedErr(err) } case <-ctx.Done(): err = ctx.Err() if err != nil { - log.Error(err, "send email timeout").End() - return errors.TimeoutErr(err) + log.Error(err, "send email timeout").String("traceID", traceID).Any("email", email).End() + return errors.Timeout(err) } } diff --git a/internal/server/grpc.go b/internal/server/grpc.go index fc0f060..577f5fb 100644 --- a/internal/server/grpc.go +++ b/internal/server/grpc.go @@ -17,7 +17,6 @@ import ( "github.com/avinoplan/postar/pkg/trace" "google.golang.org/grpc" "net" - "time" ) // GRPCServer is a grpc implement of PostardServer. @@ -46,6 +45,14 @@ func (gs *GRPCServer) SendEmail(ctx context.Context, request *api.SendEmailReque ctx = trace.NewContext(ctx, traceID) err := gs.smtpBiz.SendEmail(ctx, toModelEmail(request.Email), toModelSendEmailOptions(gs.c, request.Options)) + if errors.IsBadRequest(err) { + return &api.SendEmailResponse{ + Code: api.ServerCode_BAD_REQUEST, + Msg: err.Error(), + TraceId: traceID, + }, nil + } + if errors.IsTimeout(err) { return &api.SendEmailResponse{ Code: api.ServerCode_TIMEOUT, @@ -84,7 +91,6 @@ func (gs *GRPCServer) Stop() error { go func() { gs.server.GracefulStop() - time.Sleep(time.Minute) stopCh <- struct{}{} }() diff --git a/internal/server/http.go b/internal/server/http.go index 7fe07eb..8bff95b 100644 --- a/internal/server/http.go +++ b/internal/server/http.go @@ -10,7 +10,6 @@ package server import ( "context" - liberrors "github.com/FishGoddess/errors" "github.com/avinoplan/postar/api" "github.com/avinoplan/postar/configs" "github.com/avinoplan/postar/internal/biz" @@ -57,10 +56,6 @@ func (hs *HTTPServer) unmarshalSendEmailRequest(reader io.Reader) (*api.SendEmai if err != nil { return nil, err } - - if request.Email == nil { - return nil, errors.BadRequestErr(liberrors.New("request.Email == nil")) - } return request, nil } @@ -86,25 +81,25 @@ func (hs *HTTPServer) sendEmail(writer http.ResponseWriter, request *http.Reques ctx := trace.NewContext(request.Context(), traceID) req, err := hs.unmarshalSendEmailRequest(request.Body) - if errors.IsBadRequest(err) { + if err != nil { hs.writeSendEmailResponse(writer, http.StatusBadRequest, &api.SendEmailResponse{ Code: api.ServerCode_BAD_REQUEST, - Msg: err.Error(), + Msg: "unmarshal send email request failed", TraceId: traceID, }) return } - if err != nil { + err = hs.smtpBiz.SendEmail(ctx, toModelEmail(req.Email), toModelSendEmailOptions(hs.c, req.Options)) + if errors.IsBadRequest(err) { hs.writeSendEmailResponse(writer, http.StatusBadRequest, &api.SendEmailResponse{ Code: api.ServerCode_BAD_REQUEST, - Msg: "unmarshal send email request failed", + Msg: err.Error(), TraceId: traceID, }) return } - err = hs.smtpBiz.SendEmail(ctx, toModelEmail(req.Email), toModelSendEmailOptions(hs.c, req.Options)) if errors.IsTimeout(err) { hs.writeSendEmailResponse(writer, http.StatusRequestTimeout, &api.SendEmailResponse{ Code: api.ServerCode_TIMEOUT, diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go index c2ed7d5..9e71cd6 100644 --- a/pkg/errors/errors.go +++ b/pkg/errors/errors.go @@ -15,8 +15,8 @@ const ( codeSendEmailFailed = 11000 ) -// TimeoutErr returns a timeout error. -func TimeoutErr(err error) error { +// Timeout returns a timeout error. +func Timeout(err error) error { return errors.Timeout(err) } @@ -25,8 +25,8 @@ func IsTimeout(err error) bool { return errors.IsTimeout(err) } -// BadRequestErr returns a bad request error. -func BadRequestErr(err error) error { +// BadRequest returns a bad request error. +func BadRequest(err error) error { return errors.Wrap(err, codeBadRequest) } diff --git a/pkg/errors/errors_test.go b/pkg/errors/errors_test.go index 18b91e7..44ccdd1 100644 --- a/pkg/errors/errors_test.go +++ b/pkg/errors/errors_test.go @@ -19,7 +19,7 @@ func TestIsBadRequest(t *testing.T) { err error result bool }{ - {BadRequestErr(errors.New("bad request")), true}, + {BadRequest(errors.New("bad request")), true}, {errors.New("unknown error"), false}, } From d234cafe5c99f6dd71835d79df3bdf39974f2e62 Mon Sep 17 00:00:00 2001 From: FishGoddess <1149062639@qq.com> Date: Sun, 30 Jan 2022 19:46:30 +0800 Subject: [PATCH 27/27] =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FUTURE.md | 9 +++++---- HISTORY.md | 6 ++++++ README.en.md | 4 ++++ README.md | 6 +++++- _examples/grpc.go | 3 ++- _examples/http.go | 3 ++- 6 files changed, 24 insertions(+), 7 deletions(-) diff --git a/FUTURE.md b/FUTURE.md index 3614cc7..d64dd7e 100644 --- a/FUTURE.md +++ b/FUTURE.md @@ -5,15 +5,16 @@ * [ ] dialer 对象池或连接池优化 (P0) * [ ] 增加 net/rpc 远程调用接口 (P1) -### v0.2.x +### v0.3.x * [ ] 支持邮件中携带附件 (P0) -* [ ] 接入监控平台 (P0) -* [ ] 增加 http 远程调用接口 (P0) +* [ ] 接入监控平台 (P1) +* [ ] TLS 证书支持 (P1) +* [x] 增加 http 远程调用接口 (P0) * [x] 增加 grpc 远程调用接口 (P0) * [ ] 增加 vex 远程调用接口 (P1) * [ ] 增加 udp 远程调用接口 (P2) -### v0.1.x +### v0.1.x - v0.2.x * [x] 邮件发送功能 diff --git a/HISTORY.md b/HISTORY.md index c4d8b27..3c1d0df 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,11 @@ ## ✒ 历史版本的特性介绍 (Features in old versions) +### v0.3.0-alpha + +> 此版本发布于 2022-01-30 + +* 全新重构版本!!! + ### v0.2.3-alpha > 此版本发布于 2021-09-03 diff --git a/README.en.md b/README.en.md index 7c71d72..edc0d05 100644 --- a/README.en.md +++ b/README.en.md @@ -47,3 +47,7 @@ If you find that something is not working as expected please open an _**issue**_ |---------|-------------|-------------------------------------------------------|-------------------------------------------------------------------------------------------------| | logit | FishGoddess | A high-performance and easy-to-use logging foundation | [Gitee](https://gitee.com/FishGoddess/logit) / [GitHub](https://github.com/FishGoddess/logit) | | errors | FishGoddess | A lib for handling error gracefully in Go | [Gitee](https://gitee.com/FishGoddess/errors) / [GitHub](https://github.com/FishGoddess/errors) | +| ants | panjf2000 | A high-performance and low-cost goroutine pool | [GitHub](https://github.com/panjf2000/ants) | +| gomail | alexcesaro | The best way to send emails in Go | [GitHub](https://github.com/go-gomail/gomail/tree/v2) | +| ini | unknwon | Provides INI file read and write functionality in Go | [GitHub](https://github.com/go-ini/ini) | +| httprouter | julienschmidt | A high performance HTTP request router | [GitHub](https://github.com/julienschmidt/httprouter) | diff --git a/README.md b/README.md index 945baa1..3046dcf 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,13 @@ _注意:默认的配置文件路径是 `./postar.ini`,默认的日志输出 如果您觉得 **postar** 缺少您需要的功能,请不要犹豫,马上参与进来,发起一个 _**issue**_。 -### 📦 postar 使用的技术 +### 📦 Postar 使用的技术 | 项目 | 作者 | 描述 | 链接 | |--------|-------------|---------------------|----------------------------------------------------------------------------------------------| | logit | FishGoddess | 一个高性能、功能强大且极易上手的日志库 | [码云](https://gitee.com/FishGoddess/logit) / [GitHub](https://github.com/FishGoddess/logit) | | errors | FishGoddess | 一个用于优雅地处理 Go 中错误的库 | [码云](https://gitee.com/FishGoddess/errors) / [GitHub](https://github.com/FishGoddess/errors) | +| ants | panjf2000 | 一个高性能且低损耗的 goroutine 池 | [GitHub](https://github.com/panjf2000/ants) | +| gomail | alexcesaro | 一个用于在 Go 中发送邮件的库 | [GitHub](https://github.com/go-gomail/gomail/tree/v2) | +| ini | unknwon | 一个操作 ini 配置的库 | [GitHub](https://github.com/go-ini/ini) | +| httprouter | julienschmidt | 一个高性能的 http 路由库 | [GitHub](https://github.com/julienschmidt/httprouter) | diff --git a/_examples/grpc.go b/_examples/grpc.go index 84a68cd..d0e03ca 100644 --- a/_examples/grpc.go +++ b/_examples/grpc.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/avinoplan/postar/api" "google.golang.org/grpc" + "os" ) func main() { @@ -16,7 +17,7 @@ func main() { req := &api.SendEmailRequest{ Email: &api.Email{ - Receivers: nil, + Receivers: []string{os.Getenv("POSTAR_RECEIVER")}, Subject: "测试邮件", BodyType: "text/html", Body: "邮件内容
", diff --git a/_examples/http.go b/_examples/http.go index 8443c5d..2038ef2 100644 --- a/_examples/http.go +++ b/_examples/http.go @@ -7,6 +7,7 @@ import ( "google.golang.org/protobuf/proto" "io/ioutil" "net/http" + "os" ) func main() { @@ -14,7 +15,7 @@ func main() { emailReq := &api.SendEmailRequest{ Email: &api.Email{ - Receivers: nil, + Receivers: []string{os.Getenv("POSTAR_RECEIVER")}, Subject: "测试邮件", BodyType: "text/html", Body: "邮件内容
",