Moved to zerolog, linting fixes, update Drone configuration.
This commit is contained in:
		| @@ -5,14 +5,14 @@ name: build | ||||
|  | ||||
| steps: | ||||
|   - name: lint | ||||
|     image: golangci/golangci-lint:latest | ||||
|     image: golangci/golangci-lint:v1.43.0 | ||||
|     environment: | ||||
|       CGO_ENABLED: 0 | ||||
|     commands: | ||||
|       - golangci-lint run | ||||
|  | ||||
|   - name: test | ||||
|     image: golang:1.13.5-alpine | ||||
|     image: golang:1.17.3-alpine | ||||
|     environment: | ||||
|       CGO_ENABLED: 0 | ||||
|     commands: | ||||
| @@ -21,7 +21,7 @@ steps: | ||||
|   - name: docker | ||||
|     image: plugins/docker | ||||
|     when: | ||||
|       branch: master | ||||
|       branch: ["master"] | ||||
|     settings: | ||||
|       username: | ||||
|         from_secret: dockerhub_user | ||||
|   | ||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,5 @@ | ||||
| .idea | ||||
| .vscode | ||||
| *DS_Store* | ||||
| opensaps.yaml | ||||
| dist | ||||
|   | ||||
| @@ -11,5 +11,12 @@ linters: | ||||
| linters-settings: | ||||
|   lll: | ||||
|     line-length: 128 | ||||
|   gocyclo: | ||||
|     min-complexity: 40 | ||||
|   cyclop: | ||||
|     max-complexity: 40 | ||||
|  | ||||
| issues: | ||||
|   exclude-rules: | ||||
|     # There will be some ToDos. | ||||
|     - linters: | ||||
|         - godox | ||||
|       text: "TODO" | ||||
|   | ||||
| @@ -18,18 +18,13 @@ | ||||
| package config | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os/user" | ||||
| 	"strings" | ||||
|  | ||||
| 	// local | ||||
| 	configstruct "go.dev.pztrn.name/opensaps/config/struct" | ||||
|  | ||||
| 	// other | ||||
| 	"go.dev.pztrn.name/flagger" | ||||
| 	configstruct "go.dev.pztrn.name/opensaps/config/struct" | ||||
| 	"gopkg.in/yaml.v2" | ||||
| ) | ||||
|  | ||||
| @@ -45,6 +40,8 @@ func (conf Configuration) GetConfig() *configstruct.ConfigStruct { | ||||
| func (conf Configuration) GetTempValue(key string) (string, error) { | ||||
| 	value, found := tempconfig[key] | ||||
| 	if !found { | ||||
| 		// ToDo: fix it! | ||||
| 		// nolint:goerr113 | ||||
| 		return "", errors.New("No such key in temporary configuration storage: " + key) | ||||
| 	} | ||||
|  | ||||
| @@ -53,7 +50,7 @@ func (conf Configuration) GetTempValue(key string) (string, error) { | ||||
| 	if value[0] == '~' { | ||||
| 		usr, err := user.Current() | ||||
| 		if err != nil { | ||||
| 			c.Log.Fatalln("Failed to get current user data: " + err.Error()) | ||||
| 			c.Log.Fatal().Err(err).Msg("Failed to get current user data") | ||||
| 		} | ||||
|  | ||||
| 		value = strings.Replace(value, "~", usr.HomeDir, 1) | ||||
| @@ -63,7 +60,7 @@ func (conf Configuration) GetTempValue(key string) (string, error) { | ||||
| } | ||||
|  | ||||
| func (conf Configuration) Initialize() { | ||||
| 	c.Log.Infoln("Initializing configuration storage...") | ||||
| 	c.Log.Info().Msg("Initializing configuration storage...") | ||||
|  | ||||
| 	tempconfig = make(map[string]string) | ||||
|  | ||||
| @@ -79,21 +76,21 @@ func (conf Configuration) Initialize() { | ||||
|  | ||||
| // Initializes configuration root path for later usage. | ||||
| func (conf Configuration) initializeConfigurationFilePath() { | ||||
| 	c.Log.Debugln("Asking flagger about configuration root path supplied by user...") | ||||
| 	c.Log.Debug().Msg("Asking flagger about configuration root path supplied by user...") | ||||
|  | ||||
| 	configpath, err := c.Flagger.GetStringValue("config") | ||||
| 	if err != nil { | ||||
| 		c.Log.Fatalln("Something went wrong - Flagger doesn't know about \"-config\" parameter!") | ||||
| 		c.Log.Fatal().Msg("Something went wrong - Flagger doesn't know about \"-config\" parameter!") | ||||
| 	} | ||||
|  | ||||
| 	c.Log.Infoln("Will use configuration file: '" + configpath + "'") | ||||
| 	c.Log.Info().Msg("Will use configuration file: '" + configpath + "'") | ||||
| 	conf.SetTempValue("CONFIGURATION_FILE", configpath) | ||||
| } | ||||
|  | ||||
| // Asking Flagger about flags, initialize internal variables. | ||||
| // Should be called **after** Flagger.Parse(). | ||||
| func (conf Configuration) InitializeLater() { | ||||
| 	c.Log.Infoln("Completing configuration initialization...") | ||||
| 	c.Log.Info().Msg("Completing configuration initialization...") | ||||
|  | ||||
| 	conf.initializeConfigurationFilePath() | ||||
| } | ||||
| @@ -102,25 +99,26 @@ func (conf Configuration) InitializeLater() { | ||||
| func (conf Configuration) LoadConfigurationFromFile() { | ||||
| 	configpath, err := conf.GetTempValue("CONFIGURATION_FILE") | ||||
| 	if err != nil { | ||||
| 		c.Log.Fatalln("Failed to get configuration file path from internal temporary configuration storage! OpenSAPS is BROKEN!") | ||||
| 		c.Log.Fatal().Msg("Failed to get configuration file path from internal temporary configuration storage! OpenSAPS is BROKEN!") | ||||
| 	} | ||||
|  | ||||
| 	c.Log.Infof("Loading configuration from '%s'...", configpath) | ||||
| 	c.Log.Info().Msgf("Loading configuration from '%s'...", configpath) | ||||
|  | ||||
| 	// Read file into memory. | ||||
| 	configBytes, err1 := ioutil.ReadFile(configpath) | ||||
| 	if err1 != nil { | ||||
| 		c.Log.Fatalf("Error occurred while reading configuration file: %s", err1.Error()) | ||||
| 		c.Log.Fatal().Msgf("Error occurred while reading configuration file: %s", err1.Error()) | ||||
| 	} | ||||
|  | ||||
| 	// nolint:exhaustivestruct | ||||
| 	config = &configstruct.ConfigStruct{} | ||||
| 	// Parse YAML. | ||||
| 	err2 := yaml.Unmarshal(configBytes, config) | ||||
| 	if err2 != nil { | ||||
| 		c.Log.Fatalf("Failed to parse configuration file: %s", err2.Error()) | ||||
| 		c.Log.Fatal().Msgf("Failed to parse configuration file: %s", err2.Error()) | ||||
| 	} | ||||
|  | ||||
| 	c.Log.Debugln("Loaded configuration:", fmt.Sprintf("%+v", config)) | ||||
| 	c.Log.Debug().Msgf("Loaded configuration: %+v", config) | ||||
| } | ||||
|  | ||||
| // Sets value to key in temporary configuration storage. | ||||
|   | ||||
| @@ -18,7 +18,6 @@ | ||||
| package config | ||||
|  | ||||
| import ( | ||||
| 	// local | ||||
| 	configurationinterface "go.dev.pztrn.name/opensaps/config/interface" | ||||
| 	configstruct "go.dev.pztrn.name/opensaps/config/struct" | ||||
| 	"go.dev.pztrn.name/opensaps/context" | ||||
|   | ||||
| @@ -18,7 +18,6 @@ | ||||
| package configurationinterface | ||||
|  | ||||
| import ( | ||||
| 	// local | ||||
| 	configstruct "go.dev.pztrn.name/opensaps/config/struct" | ||||
| ) | ||||
|  | ||||
|   | ||||
| @@ -16,14 +16,15 @@ | ||||
| // You should have received a copy of the GNU General Public License | ||||
| // along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| // nolint:tagliatelle | ||||
| package configstruct | ||||
|  | ||||
| // ConfigStruct is a config's root. | ||||
| type ConfigStruct struct { | ||||
| 	SlackHandler ConfigSlackHandler        `yaml:"slackhandler"` | ||||
| 	Webhooks     map[string]ConfigWebhook  `yaml:"webhooks"` | ||||
| 	Matrix       map[string]ConfigMatrix   `yaml:"matrix"` | ||||
| 	Telegram     map[string]ConfigTelegram `yaml:"telegram"` | ||||
| 	SlackHandler ConfigSlackHandler        `yaml:"slackhandler"` | ||||
| } | ||||
|  | ||||
| // Slack handler configuration. | ||||
| @@ -60,7 +61,7 @@ type ConfigMatrix struct { | ||||
| 	Room     string `yaml:"room"` | ||||
| } | ||||
|  | ||||
| // ConfigTelegram is a telegram pusher configuration | ||||
| // ConfigTelegram is a telegram pusher configuration. | ||||
| type ConfigTelegram struct { | ||||
| 	BotID  string      `yaml:"bot_id"` | ||||
| 	ChatID string      `yaml:"chat_id"` | ||||
| @@ -69,10 +70,9 @@ type ConfigTelegram struct { | ||||
|  | ||||
| // ConfigProxy represents proxy server configuration. | ||||
| type ConfigProxy struct { | ||||
| 	// ProxyType is a proxy type. Currently ignored. | ||||
| 	Enabled   bool   `yaml:"enabled"` | ||||
| 	ProxyType string `yaml:"proxy_type"` | ||||
| 	Address   string `yaml:"address"` | ||||
| 	User      string `yaml:"user"` | ||||
| 	Password  string `yaml:"password"` | ||||
| 	Enabled   bool   `yaml:"enabled"` | ||||
| } | ||||
|   | ||||
| @@ -18,41 +18,65 @@ | ||||
| package context | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	// local | ||||
| 	"github.com/rs/zerolog" | ||||
| 	"go.dev.pztrn.name/flagger" | ||||
| 	configurationinterface "go.dev.pztrn.name/opensaps/config/interface" | ||||
| 	parserinterface "go.dev.pztrn.name/opensaps/parsers/interface" | ||||
| 	pusherinterface "go.dev.pztrn.name/opensaps/pushers/interface" | ||||
| 	slackapiserverinterface "go.dev.pztrn.name/opensaps/slack/apiserverinterface" | ||||
| 	slackmessage "go.dev.pztrn.name/opensaps/slack/message" | ||||
|  | ||||
| 	// other | ||||
| 	"github.com/pztrn/mogrus" | ||||
| 	"go.dev.pztrn.name/flagger" | ||||
| ) | ||||
|  | ||||
| type Context struct { | ||||
| 	Config         configurationinterface.ConfigurationInterface | ||||
| 	SlackAPIServer slackapiserverinterface.SlackAPIServerInterface | ||||
| 	Flagger        *flagger.Flagger | ||||
| 	Log            *mogrus.LoggerHandler | ||||
| 	Parsers        map[string]parserinterface.ParserInterface | ||||
| 	Pushers        map[string]pusherinterface.PusherInterface | ||||
| 	SlackAPIServer slackapiserverinterface.SlackAPIServerInterface | ||||
| 	Log            zerolog.Logger | ||||
| } | ||||
|  | ||||
| func (c *Context) Initialize() { | ||||
| 	c.Parsers = make(map[string]parserinterface.ParserInterface) | ||||
| 	c.Pushers = make(map[string]pusherinterface.PusherInterface) | ||||
|  | ||||
| 	l := mogrus.New() | ||||
| 	l.Initialize() | ||||
| 	c.Log = l.CreateLogger("opensaps") | ||||
| 	c.Log.CreateOutput("stdout", os.Stdout, true, "debug") | ||||
| 	// nolint:exhaustivestruct | ||||
| 	output := zerolog.ConsoleWriter{Out: os.Stdout, NoColor: false, TimeFormat: time.RFC3339} | ||||
| 	output.FormatLevel = func(lvlRaw interface{}) string { | ||||
| 		var v string | ||||
|  | ||||
| 	c.Flagger = flagger.New("opensaps", flagger.LoggerInterface(c.Log)) | ||||
| 		if lvl, ok := lvlRaw.(string); ok { | ||||
| 			lvl = strings.ToUpper(lvl) | ||||
| 			switch lvl { | ||||
| 			case "DEBUG": | ||||
| 				v = fmt.Sprintf("\x1b[30m%-5s\x1b[0m", lvl) | ||||
| 			case "ERROR": | ||||
| 				v = fmt.Sprintf("\x1b[31m%-5s\x1b[0m", lvl) | ||||
| 			case "FATAL": | ||||
| 				v = fmt.Sprintf("\x1b[35m%-5s\x1b[0m", lvl) | ||||
| 			case "INFO": | ||||
| 				v = fmt.Sprintf("\x1b[32m%-5s\x1b[0m", lvl) | ||||
| 			case "PANIC": | ||||
| 				v = fmt.Sprintf("\x1b[36m%-5s\x1b[0m", lvl) | ||||
| 			case "WARN": | ||||
| 				v = fmt.Sprintf("\x1b[33m%-5s\x1b[0m", lvl) | ||||
| 			default: | ||||
| 				v = lvl | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return fmt.Sprintf("| %s |", v) | ||||
| 	} | ||||
|  | ||||
| 	c.Log = zerolog.New(output).With().Timestamp().Logger() | ||||
|  | ||||
| 	flaggerLogger := &FlaggerLogger{log: c.Log} | ||||
| 	c.Flagger = flagger.New("opensaps", flagger.LoggerInterface(flaggerLogger)) | ||||
| 	c.Flagger.Initialize() | ||||
| } | ||||
|  | ||||
| @@ -84,7 +108,8 @@ func (c *Context) RegisterSlackAPIServerInterface(sasi slackapiserverinterface.S | ||||
| func (c *Context) SendToParser(name string, message slackmessage.SlackMessage) map[string]interface{} { | ||||
| 	parser, found := c.Parsers[strings.ToLower(name)] | ||||
| 	if !found { | ||||
| 		c.Log.Errorf("Parser '%s' not found, will use default one!", name) | ||||
| 		c.Log.Error().Msgf("Parser '%s' not found, will use default one!", name) | ||||
|  | ||||
| 		return c.Parsers["default"].ParseMessage(message) | ||||
| 	} | ||||
|  | ||||
| @@ -94,7 +119,7 @@ func (c *Context) SendToParser(name string, message slackmessage.SlackMessage) m | ||||
| func (c *Context) SendToPusher(protocol string, connection string, data slackmessage.SlackMessage) { | ||||
| 	pusher, ok := c.Pushers[protocol] | ||||
| 	if !ok { | ||||
| 		c.Log.Errorf("Pusher not found (or initialized) for protocol '%s'!", protocol) | ||||
| 		c.Log.Error().Msgf("Pusher not found (or initialized) for protocol '%s'!", protocol) | ||||
| 	} | ||||
|  | ||||
| 	pusher.Push(connection, data) | ||||
|   | ||||
| @@ -18,5 +18,6 @@ | ||||
| package context | ||||
|  | ||||
| func New() *Context { | ||||
| 	// nolint:exhaustivestruct | ||||
| 	return &Context{} | ||||
| } | ||||
|   | ||||
							
								
								
									
										40
									
								
								context/flagger_logger.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								context/flagger_logger.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| // OpenSAPS - Open Slack API server for everyone. | ||||
| // | ||||
| // Copyright (c) 2017, Stanislav N. aka pztrn. | ||||
| // All rights reserved. | ||||
| // | ||||
| // This program is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU General Public License as published by | ||||
| // the Free Software Foundation, either version 3 of the License, or | ||||
| // (at your option) any later version. | ||||
| // | ||||
| // This program is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| // GNU General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU General Public License | ||||
| // along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| package context | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/rs/zerolog" | ||||
| ) | ||||
|  | ||||
| // FlaggerLogger is a proxy structure for logging for flagger package. | ||||
| type FlaggerLogger struct { | ||||
| 	log zerolog.Logger | ||||
| } | ||||
|  | ||||
| func (fl *FlaggerLogger) Fatal(v ...interface{}) { | ||||
| 	msg := fmt.Sprint(v...) | ||||
| 	fl.log.Fatal().Msg(msg) | ||||
| } | ||||
|  | ||||
| func (fl *FlaggerLogger) Print(v ...interface{}) { | ||||
| 	msg := fmt.Sprint(v...) | ||||
| 	fl.log.Info().Msg(msg) | ||||
| } | ||||
							
								
								
									
										3
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								go.mod
									
									
									
									
									
								
							| @@ -3,8 +3,7 @@ module go.dev.pztrn.name/opensaps | ||||
| go 1.13 | ||||
|  | ||||
| require ( | ||||
| 	github.com/pztrn/mogrus v0.0.0-20180323033502-2d9bba232129 | ||||
| 	github.com/sirupsen/logrus v1.4.2 // indirect | ||||
| 	github.com/rs/zerolog v1.26.0 | ||||
| 	go.dev.pztrn.name/flagger v0.0.0-20191215171500-5e6aeb0e0620 | ||||
| 	gopkg.in/yaml.v2 v2.2.7 | ||||
| ) | ||||
|   | ||||
							
								
								
									
										38
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								go.sum
									
									
									
									
									
								
							| @@ -1,20 +1,40 @@ | ||||
| github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= | ||||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= | ||||
| github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= | ||||
| github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= | ||||
| github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||
| github.com/pztrn/mogrus v0.0.0-20180323033502-2d9bba232129 h1:Z1Xl0c70du/gU/OTZocpGtlTM0Pic33WfoWEEVBDkUo= | ||||
| github.com/pztrn/mogrus v0.0.0-20180323033502-2d9bba232129/go.mod h1:qUMNhMNokIYOmTn31Ct9i0kyXJVjko9Om6eAEQPJRuE= | ||||
| github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= | ||||
| github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= | ||||
| github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= | ||||
| github.com/rs/zerolog v1.26.0 h1:ORM4ibhEZeTeQlCojCK2kPz1ogAY4bGs4tD+SaAdGaE= | ||||
| github.com/rs/zerolog v1.26.0/go.mod h1:yBiM87lvSqX8h0Ww4sdzNSkVYZ8dL2xjZJG1lAuGZEo= | ||||
| github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= | ||||
| github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||||
| github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= | ||||
| go.dev.pztrn.name/flagger v0.0.0-20191215171500-5e6aeb0e0620 h1:h+Rb4bRhmrKvCdm90Nz0ijCAaGSfDutiFK55yYDmMHo= | ||||
| go.dev.pztrn.name/flagger v0.0.0-20191215171500-5e6aeb0e0620/go.mod h1:Ha9nzrpCBvql342GglqxpP7cMRq9CmJxbz0LVDP7s6Y= | ||||
| golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= | ||||
| golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||||
| golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||
| golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | ||||
| golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||||
| golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||
| golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | ||||
| golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| 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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||||
| golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||
| golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||
| golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
| golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||||
| golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= | ||||
| golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
| golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
| golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= | ||||
|   | ||||
							
								
								
									
										26
									
								
								opensaps.go
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								opensaps.go
									
									
									
									
									
								
							| @@ -18,12 +18,10 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"os" | ||||
| 	"os/signal" | ||||
| 	"syscall" | ||||
|  | ||||
| 	// local | ||||
| 	"go.dev.pztrn.name/opensaps/config" | ||||
| 	"go.dev.pztrn.name/opensaps/context" | ||||
| 	defaultparser "go.dev.pztrn.name/opensaps/parsers/default" | ||||
| @@ -33,25 +31,25 @@ import ( | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	c := context.New() | ||||
| 	c.Initialize() | ||||
| 	ctx := context.New() | ||||
| 	ctx.Initialize() | ||||
|  | ||||
| 	config.New(c) | ||||
| 	config.New(ctx) | ||||
|  | ||||
| 	c.Log.Infoln("Launching OpenSAPS...") | ||||
| 	ctx.Log.Info().Msg("Launching OpenSAPS...") | ||||
|  | ||||
| 	c.Flagger.Parse() | ||||
| 	c.Config.InitializeLater() | ||||
| 	c.Config.LoadConfigurationFromFile() | ||||
| 	ctx.Flagger.Parse() | ||||
| 	ctx.Config.InitializeLater() | ||||
| 	ctx.Config.LoadConfigurationFromFile() | ||||
|  | ||||
| 	slack.New(c) | ||||
| 	slack.New(ctx) | ||||
|  | ||||
| 	// Initialize parsers. | ||||
| 	defaultparser.New(c) | ||||
| 	defaultparser.New(ctx) | ||||
|  | ||||
| 	// Initialize pushers. | ||||
| 	matrixpusher.New(c) | ||||
| 	telegrampusher.New(c) | ||||
| 	matrixpusher.New(ctx) | ||||
| 	telegrampusher.New(ctx) | ||||
|  | ||||
| 	// CTRL+C handler. | ||||
| 	signalHandler := make(chan os.Signal, 1) | ||||
| @@ -61,7 +59,7 @@ func main() { | ||||
|  | ||||
| 	go func() { | ||||
| 		<-signalHandler | ||||
| 		c.Shutdown() | ||||
| 		ctx.Shutdown() | ||||
| 		shutdownDone <- true | ||||
| 	}() | ||||
|  | ||||
|   | ||||
| @@ -18,22 +18,20 @@ | ||||
| package defaultparser | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
|  | ||||
| 	// local | ||||
| 	slackmessage "go.dev.pztrn.name/opensaps/slack/message" | ||||
| ) | ||||
|  | ||||
| type DefaultParser struct{} | ||||
|  | ||||
| func (dp DefaultParser) Initialize() { | ||||
| 	c.Log.Infoln("Initializing default parser...") | ||||
| 	c.Log.Info().Msg("Initializing default parser...") | ||||
| } | ||||
|  | ||||
| func (dp DefaultParser) ParseMessage(message slackmessage.SlackMessage) map[string]interface{} { | ||||
| 	c.Log.Debugln("Parsing default message...") | ||||
| 	c.Log.Debug().Msg("Parsing default message...") | ||||
|  | ||||
| 	msg := message.Text + "\n" | ||||
| 	for _, attachment := range message.Attachments { | ||||
| @@ -42,7 +40,7 @@ func (dp DefaultParser) ParseMessage(message slackmessage.SlackMessage) map[stri | ||||
|  | ||||
| 	// Remove line break in very beginning, if present. | ||||
| 	if strings.Contains(msg[0:3], "\n") { | ||||
| 		c.Log.Debugln("Initial br found, removing") | ||||
| 		c.Log.Debug().Msg("Initial br found, removing") | ||||
|  | ||||
| 		msg = strings.Replace(msg, "\n", "", 1) | ||||
| 	} | ||||
| @@ -50,7 +48,7 @@ func (dp DefaultParser) ParseMessage(message slackmessage.SlackMessage) map[stri | ||||
| 	// Get all links from message. | ||||
| 	r := regexp.MustCompile(`<{1}([\pL\pP\pN]+)\|{1}([\pL\pP\pN\pZs]+)>{1}`) | ||||
| 	foundLinks := r.FindAllStringSubmatch(msg, -1) | ||||
| 	c.Log.Debugln("Found links:", foundLinks) | ||||
| 	c.Log.Debug().Msgf("Found links: %+v", foundLinks) | ||||
|  | ||||
| 	data := make(map[string]interface{}) | ||||
| 	data["message"] = msg | ||||
|   | ||||
| @@ -18,14 +18,11 @@ | ||||
| package defaultparser | ||||
|  | ||||
| import ( | ||||
| 	// local | ||||
| 	"go.dev.pztrn.name/opensaps/context" | ||||
| 	parserinterface "go.dev.pztrn.name/opensaps/parsers/interface" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	c *context.Context | ||||
| ) | ||||
| var c *context.Context | ||||
|  | ||||
| func New(cc *context.Context) { | ||||
| 	c = cc | ||||
|   | ||||
| @@ -18,7 +18,6 @@ | ||||
| package parserinterface | ||||
|  | ||||
| import ( | ||||
| 	// local | ||||
| 	slackmessage "go.dev.pztrn.name/opensaps/slack/message" | ||||
| ) | ||||
|  | ||||
|   | ||||
| @@ -18,7 +18,6 @@ | ||||
| package pusherinterface | ||||
|  | ||||
| import ( | ||||
| 	// local | ||||
| 	slackmessage "go.dev.pztrn.name/opensaps/slack/message" | ||||
| ) | ||||
|  | ||||
|   | ||||
| @@ -18,7 +18,6 @@ | ||||
| package matrixpusher | ||||
|  | ||||
| import ( | ||||
| 	// local | ||||
| 	"go.dev.pztrn.name/opensaps/context" | ||||
| 	pusherinterface "go.dev.pztrn.name/opensaps/pushers/interface" | ||||
| ) | ||||
|   | ||||
| @@ -18,7 +18,6 @@ | ||||
| package matrixpusher | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"bytes" | ||||
| 	crand "crypto/rand" | ||||
| 	"encoding/json" | ||||
| @@ -28,7 +27,6 @@ import ( | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
|  | ||||
| 	// local | ||||
| 	slackmessage "go.dev.pztrn.name/opensaps/slack/message" | ||||
| ) | ||||
|  | ||||
| @@ -40,9 +38,10 @@ const ( | ||||
| ) | ||||
|  | ||||
| type MatrixMessage struct { | ||||
| 	MsgType       string `json:"msgtype"` | ||||
| 	Body          string `json:"body"` | ||||
| 	Format        string `json:"format"` | ||||
| 	MsgType string `json:"msgtype"` | ||||
| 	Body    string `json:"body"` | ||||
| 	Format  string `json:"format"` | ||||
| 	// nolint:tagliatelle | ||||
| 	FormattedBody string `json:"formatted_body"` | ||||
| } | ||||
|  | ||||
| @@ -65,14 +64,14 @@ type MatrixConnection struct { | ||||
|  | ||||
| // nolint | ||||
| func (mxc *MatrixConnection) doPostRequest(endpoint string, data string) ([]byte, error) { | ||||
| 	c.Log.Debugln("Data to send:", data) | ||||
| 	c.Log.Debug().Msgf("Data to send: %+v", data) | ||||
|  | ||||
| 	apiRoot := mxc.apiRoot + endpoint | ||||
| 	if mxc.token != "" { | ||||
| 		apiRoot += fmt.Sprintf("?access_token=%s", mxc.token) | ||||
| 	} | ||||
|  | ||||
| 	c.Log.Debugln("Request URL:", apiRoot) | ||||
| 	c.Log.Debug().Msgf("Request URL: %s", apiRoot) | ||||
|  | ||||
| 	req, _ := http.NewRequest("POST", apiRoot, bytes.NewBuffer([]byte(data))) | ||||
| 	req.Header.Set("Content-Type", "application/json") | ||||
| @@ -98,14 +97,14 @@ func (mxc *MatrixConnection) doPostRequest(endpoint string, data string) ([]byte | ||||
|  | ||||
| // nolint | ||||
| func (mxc *MatrixConnection) doPutRequest(endpoint string, data string) ([]byte, error) { | ||||
| 	c.Log.Debugln("Data to send:", data) | ||||
| 	c.Log.Debug().Msgf("Data to send: %+v", data) | ||||
|  | ||||
| 	apiRoot := mxc.apiRoot + endpoint | ||||
| 	if mxc.token != "" { | ||||
| 		apiRoot += fmt.Sprintf("?access_token=%s", mxc.token) | ||||
| 	} | ||||
|  | ||||
| 	c.Log.Debugln("Request URL:", apiRoot) | ||||
| 	c.Log.Debug().Msgf("Request URL: %s", apiRoot) | ||||
|  | ||||
| 	req, _ := http.NewRequest("PUT", apiRoot, bytes.NewBuffer([]byte(data))) | ||||
| 	req.Header.Set("Content-Type", "application/json") | ||||
| @@ -129,15 +128,19 @@ func (mxc *MatrixConnection) doPutRequest(endpoint string, data string) ([]byte, | ||||
| 	return nil, errors.New("Status: " + resp.Status + ", body: " + string(body)) | ||||
| } | ||||
|  | ||||
| // This function should be rewritten, I think. | ||||
| // nolint | ||||
| func (mxc *MatrixConnection) generateTnxID() string { | ||||
| 	// Random tnxid - 16 chars. | ||||
| 	length := 16 | ||||
|  | ||||
| 	result := make([]byte, length) | ||||
| 	// ToDo: figure out why this was ever needed and fix it. | ||||
| 	bufferSize := int(float64(length) * 1.3) | ||||
|  | ||||
| 	// Making sure that we have only letters and numbers and resulted | ||||
| 	// string will be exactly requested length. | ||||
| 	// I'm sorry for this shitty code. | ||||
| 	for i, j, randomBytes := 0, 0, []byte{}; i < length; j++ { | ||||
| 		if j%bufferSize == 0 { | ||||
| 			randomBytes = mxc.generateTnxIDSecureBytes(bufferSize) | ||||
| @@ -154,11 +157,10 @@ func (mxc *MatrixConnection) generateTnxID() string { | ||||
|  | ||||
| func (mxc *MatrixConnection) generateTnxIDSecureBytes(length int) []byte { | ||||
| 	// Get random bytes. | ||||
| 	var randomBytes = make([]byte, length) | ||||
| 	randomBytes := make([]byte, length) | ||||
|  | ||||
| 	_, err := crand.Read(randomBytes) | ||||
| 	if err != nil { | ||||
| 		c.Log.Fatalln("Unable to generate random bytes for transaction ID!") | ||||
| 	if _, err := crand.Read(randomBytes); err != nil { | ||||
| 		c.Log.Fatal().Msg("Unable to generate random bytes for transaction ID!") | ||||
| 	} | ||||
|  | ||||
| 	return randomBytes | ||||
| @@ -172,15 +174,15 @@ func (mxc *MatrixConnection) Initialize(connName string, apiRoot string, user st | ||||
| 	mxc.roomID = roomID | ||||
| 	mxc.token = "" | ||||
|  | ||||
| 	c.Log.Debugln("Trying to connect to", mxc.connName, "("+apiRoot+")") | ||||
| 	c.Log.Debug().Str("conn", mxc.connName).Str("api_root", apiRoot).Msg("Trying to connect server") | ||||
|  | ||||
| 	loginStr := fmt.Sprintf(`{"type": "m.login.password", "user": "%s", "password": "%s"}`, mxc.username, mxc.password) | ||||
|  | ||||
| 	c.Log.Debugln("Login string:", loginStr) | ||||
| 	c.Log.Debug().Msgf("Login string: %s", loginStr) | ||||
|  | ||||
| 	reply, err := mxc.doPostRequest("/login", loginStr) | ||||
| 	if err != nil { | ||||
| 		c.Log.Fatalf("Failed to login to Matrix with user '%s' (conn %s): '%s'", mxc.username, mxc.connName, err.Error()) | ||||
| 		c.Log.Fatal().Msgf("Failed to login to Matrix with user '%s' (conn %s): '%s'", mxc.username, mxc.connName, err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	// Parse received JSON and get access token. | ||||
| @@ -188,22 +190,24 @@ func (mxc *MatrixConnection) Initialize(connName string, apiRoot string, user st | ||||
|  | ||||
| 	err1 := json.Unmarshal(reply, &data) | ||||
| 	if err1 != nil { | ||||
| 		c.Log.Fatalf("Failed to parse received JSON from Matrix for user '%s' (conn %s): %s (data was: %s)", | ||||
| 			mxc.username, mxc.connName, err1.Error(), reply) | ||||
| 		c.Log.Fatal(). | ||||
| 			Str("username", mxc.username). | ||||
| 			Str("conn", mxc.connName). | ||||
| 			Err(err). | ||||
| 			Msgf("Failed to parse received JSON from Matrix: %s)", reply) | ||||
| 	} | ||||
|  | ||||
| 	mxc.token = data["access_token"].(string) | ||||
| 	mxc.deviceID = data["deviceID"].(string) | ||||
| 	mxc.token, _ = data["access_token"].(string) | ||||
| 	mxc.deviceID, _ = data["deviceID"].(string) | ||||
|  | ||||
| 	c.Log.Debugf("Login successful for conn '%s', access token is '%s', our deviceID is '%s'", | ||||
| 		mxc.connName, mxc.token, mxc.deviceID) | ||||
| 	c.Log.Debug().Str("conn", mxc.connName).Str("access_token", mxc.token).Str("device_id", mxc.deviceID).Msg("Login successful") | ||||
|  | ||||
| 	// We should check if we're already in room and, if not, join it. | ||||
| 	// We will do this by simply trying to join. We don't care about reply | ||||
| 	// here. | ||||
| 	_, err2 := mxc.doPostRequest("/rooms/"+mxc.roomID+"/join", "{}") | ||||
| 	if err2 != nil { | ||||
| 		c.Log.Fatalf("Failed to join room: %s", err2.Error()) | ||||
| 		c.Log.Fatal().Err(err).Msg("Failed to join room") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -213,20 +217,20 @@ func (mxc *MatrixConnection) ProcessMessage(message slackmessage.SlackMessage) { | ||||
| 	// Prepare message body. | ||||
| 	messageData := c.SendToParser(message.Username, message) | ||||
|  | ||||
| 	messageToSend := messageData["message"].(string) | ||||
| 	messageToSend, _ := messageData["message"].(string) | ||||
| 	// We'll use HTML, so reformat links accordingly (if any). | ||||
| 	linksRaw, linksFound := messageData["links"] | ||||
| 	if linksFound { | ||||
| 		links := linksRaw.([][]string) | ||||
| 		links, _ := linksRaw.([][]string) | ||||
| 		for _, link := range links { | ||||
| 			messageToSend = strings.Replace(messageToSend, link[0], `<a href="`+link[1]+`">`+link[2]+`</a>`, -1) | ||||
| 			messageToSend = strings.ReplaceAll(messageToSend, link[0], `<a href="`+link[1]+`">`+link[2]+`</a>`) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// "\n" should be "<br>". | ||||
| 	messageToSend = strings.Replace(messageToSend, "\n", "<br>", -1) | ||||
| 	messageToSend = strings.ReplaceAll(messageToSend, "\n", "<br>") | ||||
|  | ||||
| 	c.Log.Debugln("Crafted message:", messageToSend) | ||||
| 	c.Log.Debug().Msgf("Crafted message: %s", messageToSend) | ||||
|  | ||||
| 	// Send message. | ||||
| 	mxc.SendMessage(messageToSend) | ||||
| @@ -234,19 +238,21 @@ func (mxc *MatrixConnection) ProcessMessage(message slackmessage.SlackMessage) { | ||||
|  | ||||
| // This function sends already prepared message to room. | ||||
| func (mxc *MatrixConnection) SendMessage(message string) { | ||||
| 	c.Log.Debugf("Sending message to connection '%s': '%s'", mxc.connName, message) | ||||
| 	c.Log.Debug().Str("conn", mxc.connName).Msgf("Sending message: '%s'", message) | ||||
|  | ||||
| 	// We should send notices as it is preferred behavior for bots and | ||||
| 	// appservices. | ||||
| 	msg := MatrixMessage{} | ||||
| 	msg.MsgType = "m.notice" | ||||
| 	msg.Body = message | ||||
| 	msg.Format = "org.matrix.custom.html" | ||||
| 	msg.FormattedBody = message | ||||
| 	msg := MatrixMessage{ | ||||
| 		MsgType:       "m.notice", | ||||
| 		Body:          message, | ||||
| 		Format:        "org.matrix.custom.html", | ||||
| 		FormattedBody: message, | ||||
| 	} | ||||
|  | ||||
| 	msgBytes, err := json.Marshal(&msg) | ||||
| 	if err != nil { | ||||
| 		c.Log.Errorln("Failed to marshal message into JSON:", err.Error()) | ||||
| 		c.Log.Error().Err(err).Msg("Failed to marshal message into JSON.") | ||||
|  | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -254,20 +260,20 @@ func (mxc *MatrixConnection) SendMessage(message string) { | ||||
|  | ||||
| 	reply, err := mxc.doPutRequest("/rooms/"+mxc.roomID+"/send/m.room.message/"+mxc.generateTnxID(), msgStr) | ||||
| 	if err != nil { | ||||
| 		c.Log.Fatalf("Failed to send message to room '%s' (conn: '%s'): %s", mxc.roomID, mxc.connName, err.Error()) | ||||
| 		c.Log.Fatal().Str("conn", mxc.connName).Str("room", mxc.roomID).Err(err).Msg("Failed to send message to room") | ||||
| 	} | ||||
|  | ||||
| 	c.Log.Debugf("Message sent, reply: %s", string(reply)) | ||||
| 	c.Log.Debug().Msgf("Message sent, reply: %s", string(reply)) | ||||
| } | ||||
|  | ||||
| func (mxc *MatrixConnection) Shutdown() { | ||||
| 	c.Log.Infof("Shutting down connection '%s'...", mxc.connName) | ||||
| 	c.Log.Info().Str("conn", mxc.connName).Msg("Shutting down connection...") | ||||
|  | ||||
| 	_, err := mxc.doPostRequest("/logout", "{}") | ||||
| 	if err != nil { | ||||
| 		c.Log.Errorf("Error occurred while trying to log out from Matrix (conn %s): %s", mxc.connName, err.Error()) | ||||
| 		c.Log.Error().Err(err).Str("conn", mxc.connName).Msg("Error occurred while trying to log out from Matrix.") | ||||
| 	} | ||||
|  | ||||
| 	mxc.token = "" | ||||
| 	c.Log.Infof("Connection '%s' successfully shutted down", mxc.connName) | ||||
| 	c.Log.Info().Str("conn", mxc.connName).Msg("Connection successfully shutted down") | ||||
| } | ||||
|   | ||||
| @@ -19,18 +19,18 @@ package matrixpusher | ||||
|  | ||||
| import slackmessage "go.dev.pztrn.name/opensaps/slack/message" | ||||
|  | ||||
| // local | ||||
|  | ||||
| type MatrixPusher struct{} | ||||
|  | ||||
| func (mp MatrixPusher) Initialize() { | ||||
| 	c.Log.Infoln("Initializing Matrix protocol pusher...") | ||||
| 	c.Log.Info().Msg("Initializing Matrix protocol pusher...") | ||||
|  | ||||
| 	// Get configuration for pushers and initialize every connection. | ||||
| 	cfg := c.Config.GetConfig() | ||||
| 	for name, config := range cfg.Matrix { | ||||
| 		c.Log.Infof("Initializing connection: '%s'", name) | ||||
| 		c.Log.Info().Str("conn", name).Msg("Initializing connection...") | ||||
|  | ||||
| 		// Fields will be filled with conn.Initialize(). | ||||
| 		// nolint:exhaustivestruct | ||||
| 		conn := MatrixConnection{} | ||||
| 		connections[name] = &conn | ||||
|  | ||||
| @@ -41,16 +41,17 @@ func (mp MatrixPusher) Initialize() { | ||||
| func (mp MatrixPusher) Push(connection string, data slackmessage.SlackMessage) { | ||||
| 	conn, found := connections[connection] | ||||
| 	if !found { | ||||
| 		c.Log.Errorf("Connection not found: '%s'!", connection) | ||||
| 		c.Log.Error().Str("conn", connection).Msg("Connection not found!") | ||||
|  | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	c.Log.Debugf("Pushing data to '%s'", connection) | ||||
| 	c.Log.Debug().Str("conn", connection).Msg("Pushing data to connection") | ||||
| 	conn.ProcessMessage(data) | ||||
| } | ||||
|  | ||||
| func (mp MatrixPusher) Shutdown() { | ||||
| 	c.Log.Infoln("Shutting down Matrix pusher...") | ||||
| 	c.Log.Info().Msg("Shutting down Matrix pusher...") | ||||
|  | ||||
| 	for _, conn := range connections { | ||||
| 		conn.Shutdown() | ||||
|   | ||||
| @@ -18,7 +18,6 @@ | ||||
| package telegrampusher | ||||
|  | ||||
| import ( | ||||
| 	// local | ||||
| 	"go.dev.pztrn.name/opensaps/context" | ||||
| 	pusherinterface "go.dev.pztrn.name/opensaps/pushers/interface" | ||||
| ) | ||||
|   | ||||
| @@ -18,13 +18,11 @@ | ||||
| package telegrampusher | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
|  | ||||
| 	// local | ||||
| 	configstruct "go.dev.pztrn.name/opensaps/config/struct" | ||||
| 	slackmessage "go.dev.pztrn.name/opensaps/slack/message" | ||||
| ) | ||||
| @@ -41,17 +39,17 @@ func (tc *TelegramConnection) ProcessMessage(message slackmessage.SlackMessage) | ||||
| 	// Prepare message body. | ||||
| 	messageData := c.SendToParser(message.Username, message) | ||||
|  | ||||
| 	messageToSend := messageData["message"].(string) | ||||
| 	messageToSend, _ := messageData["message"].(string) | ||||
| 	// We'll use HTML, so reformat links accordingly (if any). | ||||
| 	linksRaw, linksFound := messageData["links"] | ||||
| 	if linksFound { | ||||
| 		links := linksRaw.([][]string) | ||||
| 		links, _ := linksRaw.([][]string) | ||||
| 		for _, link := range links { | ||||
| 			messageToSend = strings.Replace(messageToSend, link[0], `<a href="`+link[1]+`">`+link[2]+`</a>`, -1) | ||||
| 			messageToSend = strings.ReplaceAll(messageToSend, link[0], `<a href="`+link[1]+`">`+link[2]+`</a>`) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	c.Log.Debugln("Crafted message:", messageToSend) | ||||
| 	c.Log.Debug().Msgf("Crafted message: %s", messageToSend) | ||||
|  | ||||
| 	// Send message. | ||||
| 	tc.SendMessage(messageToSend) | ||||
| @@ -64,8 +62,10 @@ func (tc *TelegramConnection) SendMessage(message string) { | ||||
| 	msgdata.Set("parse_mode", "HTML") | ||||
|  | ||||
| 	// Are we should use proxy? | ||||
| 	// nolint:exhaustivestruct | ||||
| 	httpTransport := &http.Transport{} | ||||
|  | ||||
| 	// nolint:nestif | ||||
| 	if tc.config.Proxy.Enabled { | ||||
| 		// Compose proxy URL. | ||||
| 		proxyURL := "http://" | ||||
| @@ -82,27 +82,30 @@ func (tc *TelegramConnection) SendMessage(message string) { | ||||
|  | ||||
| 		proxyURLParsed, err := url.Parse(proxyURL) | ||||
| 		if err != nil { | ||||
| 			c.Log.Errorln("Error while constructing/parsing proxy URL:", err.Error()) | ||||
| 			c.Log.Error().Err(err).Msg("Error while constructing/parsing proxy URL") | ||||
| 		} else { | ||||
| 			httpTransport.Proxy = http.ProxyURL(proxyURLParsed) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// nolint:exhaustivestruct | ||||
| 	client := &http.Client{Transport: httpTransport} | ||||
| 	botURL := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", tc.config.BotID) | ||||
|  | ||||
| 	c.Log.Debugln("Bot URL:", botURL) | ||||
| 	c.Log.Debug().Msgf("Bot URL: %s", botURL) | ||||
|  | ||||
| 	// ToDo: fix it. | ||||
| 	// nolint | ||||
| 	response, err := client.PostForm(botURL, msgdata) | ||||
| 	if err != nil { | ||||
| 		c.Log.Errorln("Error occurred while sending data to Telegram:", err.Error()) | ||||
| 		c.Log.Error().Err(err).Msg("Error occurred while sending data to Telegram") | ||||
| 	} else { | ||||
| 		c.Log.Debugln("Status:", response.Status) | ||||
| 		if response.StatusCode != 200 { | ||||
| 		c.Log.Debug().Msgf("Status: %s", response.Status) | ||||
| 		if response.StatusCode != http.StatusOK { | ||||
| 			body := []byte{} | ||||
| 			_, _ = response.Body.Read(body) | ||||
| 			response.Body.Close() | ||||
| 			c.Log.Debugln(body) | ||||
| 			c.Log.Debug().Msg(string(body)) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -18,20 +18,20 @@ | ||||
| package telegrampusher | ||||
|  | ||||
| import ( | ||||
| 	// local | ||||
| 	slackmessage "go.dev.pztrn.name/opensaps/slack/message" | ||||
| ) | ||||
|  | ||||
| type TelegramPusher struct{} | ||||
|  | ||||
| func (tp TelegramPusher) Initialize() { | ||||
| 	c.Log.Infoln("Initializing Telegram protocol pusher...") | ||||
| 	c.Log.Info().Msg("Initializing Telegram protocol pusher...") | ||||
|  | ||||
| 	// Get configuration for pushers and initialize every connection. | ||||
| 	cfg := c.Config.GetConfig() | ||||
| 	for name, config := range cfg.Telegram { | ||||
| 		c.Log.Infof("Initializing connection: '%s'", name) | ||||
| 		c.Log.Info().Str("conn", name).Msg("Initializing connection...") | ||||
|  | ||||
| 		// nolint:exhaustivestruct | ||||
| 		conn := TelegramConnection{} | ||||
| 		connections[name] = &conn | ||||
|  | ||||
| @@ -42,16 +42,17 @@ func (tp TelegramPusher) Initialize() { | ||||
| func (tp TelegramPusher) Push(connection string, data slackmessage.SlackMessage) { | ||||
| 	conn, found := connections[connection] | ||||
| 	if !found { | ||||
| 		c.Log.Errorf("Connection not found: '%s'!", connection) | ||||
| 		c.Log.Error().Str("conn", connection).Msg("Connection not found") | ||||
|  | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	c.Log.Debugf("Pushing data to '%s'", connection) | ||||
| 	c.Log.Debug().Str("conn", connection).Msg("Pushing data") | ||||
| 	conn.ProcessMessage(data) | ||||
| } | ||||
|  | ||||
| func (tp TelegramPusher) Shutdown() { | ||||
| 	c.Log.Infoln("Shutting down Telegram pusher...") | ||||
| 	c.Log.Info().Msg("Shutting down Telegram pusher...") | ||||
|  | ||||
| 	for _, conn := range connections { | ||||
| 		conn.Shutdown() | ||||
|   | ||||
| @@ -18,10 +18,8 @@ | ||||
| package slack | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"net/http" | ||||
|  | ||||
| 	// local | ||||
| 	"go.dev.pztrn.name/opensaps/context" | ||||
| 	slackapiserverinterface "go.dev.pztrn.name/opensaps/slack/apiserverinterface" | ||||
| ) | ||||
|   | ||||
| @@ -17,14 +17,15 @@ | ||||
| // along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
| package slackmessage | ||||
|  | ||||
| // nolint:tagliatelle | ||||
| type SlackMessage struct { | ||||
| 	Channel     string             `json:"channel"` | ||||
| 	Text        string             `json:"text"` | ||||
| 	Username    string             `json:"username"` | ||||
| 	IconURL     string             `json:"icon_url"` | ||||
| 	Attachments []SlackAttachments `json:"attachments"` | ||||
| 	UnfurlLinks int                `json:"unfurl_links"` | ||||
| 	LinkNames   int                `json:"link_names"` | ||||
| 	Attachments []SlackAttachments `json:"attachments"` | ||||
| } | ||||
|  | ||||
| type SlackAttachments struct { | ||||
|   | ||||
| @@ -29,8 +29,6 @@ package slack | ||||
| // handler for it. | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
|  | ||||
| 	"context" | ||||
| 	"net/http" | ||||
| 	"time" | ||||
| @@ -39,7 +37,7 @@ import ( | ||||
| type APIServer struct{} | ||||
|  | ||||
| func (sh APIServer) Initialize() { | ||||
| 	c.Log.Infoln("Initializing Slack API handler...") | ||||
| 	c.Log.Info().Msg("Initializing Slack API handler...") | ||||
|  | ||||
| 	// Start HTTP server. | ||||
| 	// As OpenSAPS designed to be behind some proxy (nginx, Caddy, etc.) | ||||
| @@ -48,6 +46,7 @@ func (sh APIServer) Initialize() { | ||||
| 	// Don't send pull requests, patches, don't create issues! :) | ||||
| 	cfg := c.Config.GetConfig() | ||||
|  | ||||
| 	// nolint:exhaustivestruct,gomnd | ||||
| 	httpsrv = &http.Server{ | ||||
| 		Addr: cfg.SlackHandler.Listener.Address, | ||||
| 		// This handler will figure out from where request has come and will | ||||
| @@ -63,13 +62,13 @@ func (sh APIServer) Initialize() { | ||||
| 		_ = httpsrv.ListenAndServe() | ||||
| 	}() | ||||
|  | ||||
| 	c.Log.Infof("Slack Webhooks API server starting to listen on %s", cfg.SlackHandler.Listener.Address) | ||||
| 	c.Log.Info().Str("address", cfg.SlackHandler.Listener.Address).Msg("Starting Slack Webhooks API server") | ||||
| } | ||||
|  | ||||
| func (sh APIServer) Shutdown() { | ||||
| 	c.Log.Infoln("Shutting down Slack API handler...") | ||||
| 	c.Log.Info().Msg("Shutting down Slack API handler...") | ||||
|  | ||||
| 	_ = httpsrv.Shutdown(context.TODO()) | ||||
|  | ||||
| 	c.Log.Infoln("Slack API HTTP server shutted down") | ||||
| 	c.Log.Info().Msg("Slack API HTTP server shutted down") | ||||
| } | ||||
|   | ||||
| @@ -18,7 +18,6 @@ | ||||
| package slack | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| @@ -26,19 +25,18 @@ import ( | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
|  | ||||
| 	// local | ||||
| 	slackmessage "go.dev.pztrn.name/opensaps/slack/message" | ||||
| ) | ||||
|  | ||||
| type Handler struct{} | ||||
|  | ||||
| func (sh Handler) ServeHTTP(respwriter http.ResponseWriter, req *http.Request) { | ||||
| 	c.Log.Debugf("Received '%s' (empty = GET) request from %s, URL: '%s'", req.Method, req.Host, req.URL.Path) | ||||
| 	c.Log.Debug().Str("method", req.Method).Str("host", req.Host).Str("path", req.URL.Path).Msg("Received HTTP request") | ||||
|  | ||||
| 	// We should catch only POST requests. Otherwise return HTTP 404. | ||||
| 	if req.Method != "POST" { | ||||
| 		c.Log.Debugln("Not a POST request, returning HTTP 404") | ||||
| 		respwriter.WriteHeader(404) | ||||
| 		c.Log.Debug().Msg("Not a POST request, returning HTTP 404") | ||||
| 		respwriter.WriteHeader(http.StatusNotFound) | ||||
| 		fmt.Fprintf(respwriter, "NOT FOUND") | ||||
|  | ||||
| 		return | ||||
| @@ -47,18 +45,18 @@ func (sh Handler) ServeHTTP(respwriter http.ResponseWriter, req *http.Request) { | ||||
| 	body, _ := ioutil.ReadAll(req.Body) | ||||
| 	req.Body.Close() | ||||
|  | ||||
| 	c.Log.Debugf("Received body: %s", string(body)) | ||||
| 	c.Log.Debug().Msgf("Received body: %s", string(body)) | ||||
|  | ||||
| 	// Try to figure out where we should push received data. | ||||
| 	cfg := c.Config.GetConfig() | ||||
|  | ||||
| 	var sentToPusher bool = false | ||||
| 	var sentToPusher bool | ||||
|  | ||||
| 	for name, config := range cfg.Webhooks { | ||||
| 		if strings.Contains(req.URL.Path, config.Slack.Random1) && | ||||
| 			strings.Contains(req.URL.Path, config.Slack.Random2) && | ||||
| 			strings.Contains(req.URL.Path, config.Slack.LongRandom) { | ||||
| 			c.Log.Debugf("Passed data belongs to '%s' and should go to '%s' pusher, protocol '%s'", | ||||
| 			c.Log.Debug().Msgf("Passed data belongs to '%s' and should go to '%s' pusher, protocol '%s'", | ||||
| 				name, config.Remote.PushTo, config.Remote.Pusher) | ||||
| 			// Parse message into SlackMessage structure. | ||||
| 			if strings.Contains(string(body)[0:7], "payload") { | ||||
| @@ -71,7 +69,8 @@ func (sh Handler) ServeHTTP(respwriter http.ResponseWriter, req *http.Request) { | ||||
| 				// Second - unescape data. | ||||
| 				tempBody, err := url.QueryUnescape(tempBody) | ||||
| 				if err != nil { | ||||
| 					c.Log.Errorln("Failed to decode body into parseable string!") | ||||
| 					c.Log.Error().Msg("Failed to decode body into parseable string!") | ||||
|  | ||||
| 					return | ||||
| 				} | ||||
|  | ||||
| @@ -79,15 +78,17 @@ func (sh Handler) ServeHTTP(respwriter http.ResponseWriter, req *http.Request) { | ||||
| 				body = []byte(tempBody) | ||||
| 			} | ||||
|  | ||||
| 			// nolint:exhaustivestruct | ||||
| 			slackmsg := slackmessage.SlackMessage{} | ||||
|  | ||||
| 			err := json.Unmarshal(body, &slackmsg) | ||||
| 			if err != nil { | ||||
| 				c.Log.Errorf("Failed to decode JSON into SlackMessage struct: '%s'\n", err.Error()) | ||||
| 				c.Log.Error().Err(err).Msg("Failed to decode JSON into SlackMessage struct") | ||||
|  | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			c.Log.Debug("Received message:", fmt.Sprintf("%+v", slackmsg)) | ||||
| 			c.Log.Debug().Msgf("Received message: %+v", slackmsg) | ||||
| 			c.SendToPusher(config.Remote.Pusher, config.Remote.PushTo, slackmsg) | ||||
|  | ||||
| 			sentToPusher = true | ||||
| @@ -95,8 +96,8 @@ func (sh Handler) ServeHTTP(respwriter http.ResponseWriter, req *http.Request) { | ||||
| 	} | ||||
|  | ||||
| 	if !sentToPusher { | ||||
| 		c.Log.Debug("Don't know where to push data. Ignoring with HTTP 404") | ||||
| 		respwriter.WriteHeader(404) | ||||
| 		c.Log.Debug().Msg("Don't know where to push data. Ignoring with HTTP 404") | ||||
| 		respwriter.WriteHeader(http.StatusNotFound) | ||||
| 		fmt.Fprintf(respwriter, "NOT FOUND") | ||||
| 	} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user