Join webbapp core modules into single package

This commit is contained in:
eleksir
2025-10-12 16:42:16 +03:00
parent 3932835d47
commit d5c6d5719a
12 changed files with 203 additions and 176 deletions

37
internal/config/types.go Normal file
View File

@@ -0,0 +1,37 @@
// Этот package нужен, чтобы разбить кольцевую зависимость.
package config
import (
"github.com/cockroachdb/pebble"
"github.com/go-redis/redis/v8"
)
// MyConfig структурка, описывающая конфиг.
type MyConfig struct {
Server string `json:"server,omitempty"`
Port int `json:"port,omitempty"`
Timeout int `json:"timeout,omitempty"`
Loglevel string `json:"loglevel,omitempty"`
Log string `json:"log,omitempty"`
Channel string `json:"channel,omitempty"`
DataDir string `json:"datadir,omitempty"`
Csign string `json:"csign,omitempty"`
ForwardsMax int64 `json:"forwards_max,omitempty"`
OpenWeatherMap struct {
Enabled bool `json:"enabled,omitempty"`
Country bool `json:"country,omitempty"`
Appid string `json:"appid,omitempty"`
} `json:"openweathermap,omitempty"`
Flickr struct {
Enabled bool `json:"enabled,omitempty"`
Key string `json:"key,omitempty"`
Secret string `json:"secret,omitempty"`
OAuthToken string `json:"oauth_token,omitempty"`
OAuthTokenSecret string `json:"oauth_token_secret,omitempty"`
} `json:"flickr,omitempty"`
UserAgents []string `json:"user_agents,omitempty"`
PcacheDB map[string]*pebble.DB
RedisClient *redis.Client
}
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -1,4 +1,4 @@
package lib
package webapp
import (
"aleesa-webapp-go/internal/anekdotru"
@@ -13,7 +13,6 @@ import (
"aleesa-webapp-go/internal/prazdnikisegodnyaru"
"aleesa-webapp-go/internal/randomfox"
"aleesa-webapp-go/internal/thecatapi"
"aleesa-webapp-go/internal/types"
"aleesa-webapp-go/internal/xkcdru"
"context"
"encoding/json"
@@ -28,7 +27,7 @@ func MsgParser(cfg *config.MyConfig, ctx context.Context, msg string) {
var (
sendTo string
answer string
j types.RMsg
j RMsg
err error
)
@@ -469,7 +468,7 @@ func MsgParser(cfg *config.MyConfig, ctx context.Context, msg string) {
}
// Настало время формировать json и засылать его в дальше
var message types.SMsg
var message SMsg
message.From = j.From
message.Userid = j.Userid
message.Chatid = j.Chatid
@@ -501,62 +500,4 @@ func MsgParser(cfg *config.MyConfig, ctx context.Context, msg string) {
}
}
// ValidateRmsg валидирует входящее сообщение.
func ValidateRmsg(cfg *config.MyConfig, j types.RMsg, msg string) (types.RMsg, error) {
if exist := j.From; exist == "" {
emsg := fmt.Errorf("incorrect msg from redis, no from field: %s", msg)
return j, emsg
}
if exist := j.Chatid; exist == "" {
emsg := fmt.Errorf("incorrect msg from redis, no chatid field: %s", msg)
return j, emsg
}
if exist := j.Userid; exist == "" {
emsg := fmt.Errorf("incorrect msg from redis, no userid field: %s", msg)
return j, emsg
}
// j.Threadid может быть пустым, значит либо нам его не дали, либо дали пустым. Это нормально.
if exist := j.Message; exist == "" {
emsg := fmt.Errorf("incorrect msg from redis, no message field: %s", msg)
return j, emsg
}
if exist := j.Plugin; exist == "" {
emsg := fmt.Errorf("incorrect msg from redis, no plugin field: %s", msg)
return j, emsg
}
if exist := j.Mode; exist == "" {
emsg := fmt.Errorf("incorrect msg from redis, no mode field: %s", msg)
return j, emsg
}
// j.Misc.Answer может и не быть, тогда ответа на такое сообщение не будет
// j.Misc.Botnick тоже можно не передавать, тогда будет записана пустая строка
// j.Misc.Csign если нам его не передали, возьмём значение из конфига
if exist := j.Misc.Csign; exist == "" {
j.Misc.Csign = cfg.Csign
}
// j.Misc.Fwdcnt если нам его не передали, то будет 0
if exist := j.Misc.Fwdcnt; exist == 0 {
j.Misc.Fwdcnt = 1
}
// j.Misc.GoodMorning может быть быть 1 или 0, по-умолчанию 0
// j.Misc.Msgformat может быть быть 1 или 0, по-умолчанию 0
// j.Misc.Username можно не передавать, тогда будет пустая строка
return j, nil
}
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -1,54 +1,24 @@
package config
package webapp
import (
"aleesa-webapp-go/internal/defaults"
"aleesa-webapp-go/internal/config"
"aleesa-webapp-go/internal/log"
"bufio"
"encoding/json"
"fmt"
"os"
"unsafe"
"github.com/cockroachdb/pebble"
"github.com/go-redis/redis/v8"
"github.com/hjson/hjson-go"
)
// MyConfig структурка, описывающая конфиг.
type MyConfig struct {
Server string `json:"server,omitempty"`
Port int `json:"port,omitempty"`
Timeout int `json:"timeout,omitempty"`
Loglevel string `json:"loglevel,omitempty"`
Log string `json:"log,omitempty"`
Channel string `json:"channel,omitempty"`
DataDir string `json:"datadir,omitempty"`
Csign string `json:"csign,omitempty"`
ForwardsMax int64 `json:"forwards_max,omitempty"`
OpenWeatherMap struct {
Enabled bool `json:"enabled,omitempty"`
Country bool `json:"country,omitempty"`
Appid string `json:"appid,omitempty"`
} `json:"openweathermap,omitempty"`
Flickr struct {
Enabled bool `json:"enabled,omitempty"`
Key string `json:"key,omitempty"`
Secret string `json:"secret,omitempty"`
OAuthToken string `json:"oauth_token,omitempty"`
OAuthTokenSecret string `json:"oauth_token_secret,omitempty"`
} `json:"flickr,omitempty"`
UserAgents []string `json:"user_agents,omitempty"`
PcacheDB map[string]*pebble.DB
RedisClient *redis.Client
}
// ReadConfig читает и валидирует конфиг, а также выставляет некоторые default-ы, если значений для параметров в конфиге
// нет.
func ReadConfig() (*MyConfig, error) {
locations, err := defaults.DefaultConfigFileLocations()
func ReadConfig() error {
locations, err := DefaultConfigFileLocations()
if err != nil {
return &MyConfig{}, err
return err
}
for _, location := range locations {
@@ -60,7 +30,7 @@ func ReadConfig() (*MyConfig, error) {
}
// Конфиг-файл длинноват для конфига, попробуем следующего кандидата
if fileInfo.Size() > defaults.ConfigFileSize {
if fileInfo.Size() > ConfigFileSize {
log.Warnf("Config file %s is too long for config, skipping", location)
continue
@@ -79,7 +49,7 @@ func ReadConfig() (*MyConfig, error) {
// Интереснее на выходе получить структурку: то есть мы вначале конфиг преобразуем в map-ку, затем эту map-ку
// сериализуем в json, а потом json преврщааем в стркутурку. Не очень эффективно, но он и не часто требуется.
var (
sampleConfig *MyConfig
sampleConfig *config.MyConfig
tmp map[string]interface{}
)
@@ -109,19 +79,19 @@ func ReadConfig() (*MyConfig, error) {
// Валидируем значения из конфига
if sampleConfig.Server == "" {
sampleConfig.Server = defaults.Host
sampleConfig.Server = Host
}
if sampleConfig.Port == 0 {
sampleConfig.Port = defaults.RedisPort
sampleConfig.Port = RedisPort
}
if sampleConfig.Timeout == 0 {
sampleConfig.Timeout = defaults.NetworkTimeout
sampleConfig.Timeout = NetworkTimeout
}
if sampleConfig.Loglevel == "" {
sampleConfig.Loglevel = defaults.Loglevel
sampleConfig.Loglevel = Loglevel
}
// sampleConfig.Log = "" if not set
@@ -133,7 +103,7 @@ func ReadConfig() (*MyConfig, error) {
}
if sampleConfig.DataDir == "" {
sampleConfig.DataDir = defaults.DataDir
sampleConfig.DataDir = DataDir
}
if sampleConfig.Csign == "" {
@@ -143,7 +113,7 @@ func ReadConfig() (*MyConfig, error) {
}
if sampleConfig.ForwardsMax == 0 {
sampleConfig.ForwardsMax = defaults.ForwardMax
sampleConfig.ForwardsMax = ForwardMax
}
if unsafe.Sizeof(sampleConfig.OpenWeatherMap) == 0 {
@@ -165,7 +135,7 @@ func ReadConfig() (*MyConfig, error) {
uaList, err := ReadLines(uaFile)
if err != nil {
return &MyConfig{}, fmt.Errorf("unable to read %s: %w", uaFile, err)
return fmt.Errorf("unable to read %s: %w", uaFile, err)
}
sampleConfig.UserAgents = uaList
@@ -174,37 +144,12 @@ func ReadConfig() (*MyConfig, error) {
log.Infof("Using %s as config file", location)
return sampleConfig, nil
Config = sampleConfig
return nil
}
return &MyConfig{}, fmt.Errorf("config was not loaded! Refusing to start")
}
// ReadLines читает даденный файл построчно в массив строк.
func ReadLines(path string) ([]string, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer func(file *os.File) {
err := file.Close()
if err != nil {
log.Errorf("Unable to close file %s:%s", path, err)
}
}(file)
var (
lines []string
scanner = bufio.NewScanner(file)
)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines, scanner.Err()
return fmt.Errorf("config was not loaded! Refusing to start")
}
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -0,0 +1,36 @@
package webapp
import (
"aleesa-webapp-go/internal/log"
"bufio"
"os"
)
// ReadLines читает даденный файл построчно в массив строк.
func ReadLines(path string) ([]string, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer func(file *os.File) {
err := file.Close()
if err != nil {
log.Errorf("Unable to close file %s:%s", path, err)
}
}(file)
var (
lines []string
scanner = bufio.NewScanner(file)
)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines, scanner.Err()
}
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -0,0 +1,66 @@
package webapp
import (
"aleesa-webapp-go/internal/config"
"fmt"
)
// ValidateRmsg валидирует входящее сообщение.
func ValidateRmsg(cfg *config.MyConfig, j RMsg, msg string) (RMsg, error) {
if exist := j.From; exist == "" {
emsg := fmt.Errorf("incorrect msg from redis, no from field: %s", msg)
return j, emsg
}
if exist := j.Chatid; exist == "" {
emsg := fmt.Errorf("incorrect msg from redis, no chatid field: %s", msg)
return j, emsg
}
if exist := j.Userid; exist == "" {
emsg := fmt.Errorf("incorrect msg from redis, no userid field: %s", msg)
return j, emsg
}
// j.Threadid может быть пустым, значит либо нам его не дали, либо дали пустым. Это нормально.
if exist := j.Message; exist == "" {
emsg := fmt.Errorf("incorrect msg from redis, no message field: %s", msg)
return j, emsg
}
if exist := j.Plugin; exist == "" {
emsg := fmt.Errorf("incorrect msg from redis, no plugin field: %s", msg)
return j, emsg
}
if exist := j.Mode; exist == "" {
emsg := fmt.Errorf("incorrect msg from redis, no mode field: %s", msg)
return j, emsg
}
// j.Misc.Answer может и не быть, тогда ответа на такое сообщение не будет
// j.Misc.Botnick тоже можно не передавать, тогда будет записана пустая строка
// j.Misc.Csign если нам его не передали, возьмём значение из конфига
if exist := j.Misc.Csign; exist == "" {
j.Misc.Csign = cfg.Csign
}
// j.Misc.Fwdcnt если нам его не передали, то будет 0
if exist := j.Misc.Fwdcnt; exist == 0 {
j.Misc.Fwdcnt = 1
}
// j.Misc.GoodMorning может быть быть 1 или 0, по-умолчанию 0
// j.Misc.Msgformat может быть быть 1 или 0, по-умолчанию 0
// j.Misc.Username можно не передавать, тогда будет пустая строка
return j, nil
}
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -1,4 +1,4 @@
package defaults
package webapp
import (
"fmt"
@@ -6,14 +6,6 @@ import (
"path/filepath"
)
var ForwardMax int64 = 5
var ConfigFileSize int64 = 65535
var DataDir = "data"
var Host = "localhost"
var Loglevel = "info"
var RedisPort = 6379
var NetworkTimeout = 10
func DefaultConfigFileLocations() ([]string, error) {
var locations []string

View File

@@ -0,0 +1,18 @@
package webapp
import (
"aleesa-webapp-go/internal/config"
)
var (
ForwardMax int64 = 5
ConfigFileSize int64 = 65535
DataDir = "data"
Host = "localhost"
Loglevel = "info"
RedisPort = 6379
NetworkTimeout = 10
Config *config.MyConfig
)
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -1,4 +1,4 @@
package types
package webapp
// RMsg структурка, описывающая входящее сообщение из pubsub-канала redis-ки.
type RMsg struct {