// SendMessageParams - Represents parameters of sendMessage method.
type SendMessageParams struct {
// BusinessConnectionID - Optional. Unique identifier of the business connection on behalf of which the
// message will be sent
BusinessConnectionID string `json:"business_connection_id,omitempty"`
// ChatID - Unique identifier for the target chat or username of the target channel (in the format
// @channel_username)
ChatID ChatID `json:"chat_id"`
// MessageThreadID - Optional. Unique identifier for the target message thread (topic) of the forum; for
// forum supergroups only
MessageThreadID int `json:"message_thread_id,omitempty"`
// Text - Text of the message to be sent, 1-4096 characters after entities parsing
Text string `json:"text"`
// ParseMode - Optional. Mode for parsing entities in the message text. See formatting options
// (https://core.telegram.org/bots/api#formatting-options) for more details.
ParseMode string `json:"parse_mode,omitempty"`
// Entities - Optional. A JSON-serialized list of special entities that appear in message text, which can be
// specified instead of parse_mode
Entities []MessageEntity `json:"entities,omitempty"`
// LinkPreviewOptions - Optional. Link preview generation options for the message
LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"`
// DisableNotification - Optional. Sends the message silently
// (https://telegram.org/blog/channels-2-0#silent-messages). Users will receive a notification with no sound.
DisableNotification bool `json:"disable_notification,omitempty"`
// ProtectContent - Optional. Protects the contents of the sent message from forwarding and saving
ProtectContent bool `json:"protect_content,omitempty"`
// MessageEffectID - Optional. Unique identifier of the message effect to be added to the message; for
// private chats only
MessageEffectID string `json:"message_effect_id,omitempty"`
// ReplyParameters - Optional. Description of the message to reply to
ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"`
// ReplyMarkup - Optional. Additional interface options. A JSON-serialized object for an inline keyboard
// (https://core.telegram.org/bots/features#inline-keyboards), custom reply keyboard
// (https://core.telegram.org/bots/features#keyboards), instructions to remove a reply keyboard or to force a
// reply from the user
ReplyMarkup ReplyMarkup `json:"reply_markup,omitempty"`
}
// ReplyParameters - Describes reply parameters for the message that is being sent.
type ReplyParameters struct {
// MessageID - Identifier of the message that will be replied to in the current chat, or in the chat chat_id
// if it is specified
MessageID int `json:"message_id"`
// ChatID - Optional. If the message to be replied to is from a different chat, unique identifier for the
// chat or username of the channel (in the format @channel_username). Not supported for messages sent on behalf
// of a business account.
ChatID ChatID `json:"chat_id,omitempty"`
// AllowSendingWithoutReply - Optional. Pass True if the message should be sent even if the specified
// message to be replied to is not found. Always False for replies in another chat or forum topic. Always True
// for messages sent on behalf of a business account.
AllowSendingWithoutReply bool `json:"allow_sending_without_reply,omitempty"`
// Quote - Optional. Quoted part of the message to be replied to; 0-1024 characters after entities parsing.
// The quote must be an exact substring of the message to be replied to, including bold, italic, underline,
// strikethrough, spoiler, and custom_emoji entities. The message will fail to send if the quote isn't found in
// the original message.
Quote string `json:"quote,omitempty"`
// QuoteParseMode - Optional. Mode for parsing entities in the quote. See formatting options
// (https://core.telegram.org/bots/api#formatting-options) for more details.
QuoteParseMode string `json:"quote_parse_mode,omitempty"`
// QuoteEntities - Optional. A JSON-serialized list of special entities that appear in the quote. It can be
// specified instead of quote_parse_mode.
QuoteEntities []MessageEntity `json:"quote_entities,omitempty"`
// QuotePosition - Optional. Position of the quote in the original message in UTF-16 code units
QuotePosition int `json:"quote_position,omitempty"`
}
id, ticket, reply_message := db.GetTicketAndMessage(message.ReplyToMessage.MessageID, user.ID)
if ticket == nil {
_, _ = bot.SendMessage(&telego.SendMessageParams{
ChatID: telego.ChatID{ID: message.Chat.ID},
Text: "This ticket or message does not exist.",
ReplyParameters: &telego.ReplyParameters{
MessageID: message.MessageID
},
ParseMode: "HTML",
})
return
}
package main
import (
"fmt"
"os/exec"
"strings"
)
func getGroups() ([]string, error) {
var groups []string
patch := "/groups"
cmd := exec.Command("whoami", patch)
output, err := cmd.Output()
if err != nil {
return nil, err
}
lines := strings.Split(string(output), "\n")
for _, line := range lines {
if strings.HasPrefix(line, "S-1-5-21") {
groups = append(groups, line)
}
}
return groups, nil
}
func main() {
groups, err := getGroups()
if err != nil {
fmt.Printf("Ошибка получения групп пользователя: %v\n", err)
return
}
fmt.Println("Группы пользователя:", groups)
}
package main
import (
"encoding/json"
"fmt"
"log"
"os"
"path/filepath"
)
type Config struct {
Env string `json:"env"`
}
func main() {
// Получаем текущую директорию
currentDir, err := os.Getwd()
if err != nil {
panic(err)
}
// Получаем путь к файлу относительно текущей директории
filePath := filepath.Join(currentDir, "config/config.json")
file, err := os.ReadFile(filePath)
if err != nil {
log.Fatal(err)
}
var config Config
json.Unmarshal(file, &config)
fmt.Println(fmt.Sprintf("ENV: %s", config.Env))
}
package app
import (
"fmt"
"io"
"log/slog"
"os"
)
// SetupLogger создаёт логгер на основании конфига
// Конфигурируем дефолтный slog и возвращаем функцию закрытия файла логов,
// если был выбран файл как место логгирования.
func SetupLogger(cfg config.Config) func() error {
closer := func() error { return nil }
level := cfg.LogLevel
var w io.Writer
switch cfg.LogOutput {
case config.LogOutputStderr:
w = os.Stderr
case config.LogOutputStdout:
w = os.Stdout
case config.LogOutputFile:
w, closer = getFileWriter(cfg)
}
var handler slog.Handler
switch cfg.LogFormat {
case config.LogFormatText:
handler = slog.Handler(slog.NewTextHandler(w, &slog.HandlerOptions{Level: level}))
case config.LogFormatJSON:
handler = slog.Handler(slog.NewJSONHandler(w, &slog.HandlerOptions{Level: level}))
}
slog.SetDefault(slog.New(handler))
return closer
}
// getFileWriter возвращает файл, куда писать логи и функцию закрытия этого файла
func getFileWriter(cfg config.Config) (*os.File, func() error) {
logDir := fmt.Sprintf("%s/%s", cfg.VarDir, cfg.LogDir)
err := os.MkdirAll(logDir, 0755)
if err != nil {
panic(fmt.Sprintf("error creating directory: %s; %v", logDir, err))
}
filename := fmt.Sprintf("%s/%s.log", logDir, cfg.AppEnv)
f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
panic(fmt.Sprintf("error opening file: %s %v", filename, err))
}
return f, f.Close
}
package main
import "app"
func main() {
// .....
closeLogFile := app.SetupLogger(cfg)
defer closeLogFile()
// ...
}
err.go
account.go
auth.go
json.go
registation.go
package models
type Product struct {
ID int `json:"id"`
Title string `json:"title"` //Название
Price int `json:"price"` //Цена
}
type ProductGetter interface {
GetAll() ([]Product, error)
GetByID(id int) (Product, error)
}
type ProductCreator interface {
Create(product Product) (Product, error)
}
type ProductUpdater interface {
Update(product Product) (Product, error)
}
type ProductDeleter interface {
Delete(id int) error
}
type ProductRepository interface {
ProductGetter
ProductCreator
ProductUpdater
}
var client = &http.Client{
Timeout: time.Millisecond * 100,
}
func scan(ip string) (error, string, string, string) {
resp, err := client.Get("http://" + ip)
// Здесь сразу желательно обработать ошибку ...
// Закрываем соединение в конце выполнения
// функции в любом случае,
// даже если где-то возникнет ошибка
defer resp.Body.Close()
// Закрытие неиспользуемых соединений
// Нужно ли это теперь?
// client.CloseIdleConnections()
// Проблема могла быть тут
// if err != nil {
// return err, "", "", ""
// }
headers := buildHeaders(resp.Header)
body, _ := io.ReadAll(resp.Body)
// и это нам уже особо не нужно
// resp.Body.Close()
return err, headers, string(body), resp.Status
}
package main
import (
"fmt"
)
type MyError struct {
Message string
}
func (e MyError) Error() string {
return e.Message
}
func main() {
// Возвращаем из функции нашу кастомную ошибку, но в виде интерфейса error
err := foo()
if err == nil {
fmt.Println("Нет ошибки")
// И теперь тут приводим error к нашему типу MyError и проверяем
} else if myErr, ok := err.(MyError); ok {
fmt.Printf("Ура! Нужный нам тип ошибки: %v\n", myErr.Message)
} else {
fmt.Println("Какой-то другой тип ошибки:", err)
}
// Проверка одной из "подстав" Go
err = bad()
if err != nil {
fmt.Println("Упс... Как так... Не nil...")
} else {
fmt.Println("Должно вывестись это, но не выводится...")
}
err = good()
if err != nil {
fmt.Println("Это не должно выводиться, всё верно.")
} else {
fmt.Println("Ошибки нет, всё верно.")
}
}
func foo() error {
err := MyError{"Ой! Ошибка MyError!"}
// err := fmt.Errorf("Ой! Обычная ошибка!")
// var err error = nil
return err
}
func bad() error {
var p *MyError = nil // Вроде же nil, но не работает....
// p = &MyError{"Ой!"} // Пробуем создать ошибку, и всё работает.
if p == nil {
fmt.Println("Ну nil же-ж... Должно же-ж работать", p)
}
return p
}
func good() error {
// return MyError{"Ой!"}
// Буквально пишем "nil", никаких указателей, которые равны nil, это прямой выстрел в ногу
return nil
}
package db
import "fmt"
// Стуктура базы данных. Здесь нам даже и не нужно объявлять никаких интерфейсов
type Service struct {
// ...
}
func NewDbService() (*Service, error) {
return &Service{}, nil
}
func (d *Service) CreateUser(username string, email string) {
fmt.Println(fmt.Sprintf("user %s with email %s is created", username, email))
}
func (d *Service) CreateProduct(name string) {
fmt.Println(fmt.Sprintf("product %s is created", name))
}
package user
// Тот самый интерфейс, который нам позволяет выбрать из структуры базы данных
// только нужные нам здесь методы
type dbUser interface {
CreateUser(username string, email string)
}
type Service struct {
db dbUser
// ...
}
func NewService(db dbUser) (*Service, error) {
return &Service{db}, nil
}
func (c *Service) New(username string, email string) {
c.db.CreateUser(username, email)
}
package product
// Тот самый интерфейс, который нам позволяет выбрать из структуры базы данных
// только нужные нам здесь методы
type dbProduct interface {
CreateProduct(name string)
}
type Service struct {
db dbProduct
// ...
}
func NewService(db dbProduct) (*Service, error) {
return &Service{db}, nil
}
func (p *Service) New(name string) {
p.db.CreateProduct(name)
}
package main
import (
"test2/db"
"test2/product"
"test2/user"
)
func main() {
// Инициализируем базу данных
dbService, _ := db.NewDbService()
// Структура базы данных реализует интерфейс dbProduct, инжектим её
productService, _ := product.NewService(dbService)
// Структура базы данных реализует интерфейс dbUser, инжектим её
userService, _ := user.NewService(dbService)
// Пользуемся на здоровье...
userService.New("user1", "uswr1@example.com")
productService.New("product1")
}
cmd/
repeater/
main.go
controller/
main.go
executor/
main.go
pkg/
c-library/
clibrary.go
go.mod
go build ./cmd/repeater
go build ./cmd/controller
go build ./cmd/executor
package main
import c_library "test/pkg/c-library"
func main() {
c_library.HelloWorld()
}
package c_library
import "fmt"
func HelloWorld() {
fmt.Println("HELLO WORLD")
}
module test