package main
import (
"io"
"strings"
"encoding/json"
"bufio"
"time"
"log"
"net"
)
// Это наш сервер
type Server struct {
Addr string
IdleTimeout time.Duration
MaxReadBytes int64
}
func (s Server) ListenAndServe() error {
if s.Addr == "" {
s.Addr = ":3000"
}
log.Printf("starting server on %v\n", s.Addr)
listener, err := net.Listen("tcp", s.Addr)
if err != nil {
return err
}
defer listener.Close()
for {
conn, err := listener.Accept()
if err != nil {
log.Printf("error accption connection %v", err)
continue
}
connection := &Conn{
Conn: conn,
IdleTimeout: s.IdleTimeout,
MaxReadBytes: s.MaxReadBytes,
}
connection.SetDeadline(time.Now().Add(connection.IdleTimeout))
log.Printf("accepted connection from %v", conn.RemoteAddr())
connection.Write([]byte("Content-Type: appliaction/json\n action:\n ping - ping\n scream - upper the text\n body - content\n"))
go handle(connection) // запускаем обработчик в новой горутине, чтобы быть готовым принять еще одно соединение
}
}
type Conn struct {
net.Conn
IdleTimeout time.Duration // Ожидание, когда сервер что-нибудь скажет или прочитает
MaxReadBytes int64 // максимальный объем передаваемых данных, чтобы клиент вдруг не захотел передать нам гигабайты данных
}
func (c *Conn) Write(p []byte) (int, error) {
c.updateDeadline()
return c.Conn.Write(p)
}
func (c *Conn) Read(b []byte) (int, error) {
c.updateDeadline()
r := io.LimitReader(c.Conn, c.MaxReadBytes)
return r.Read(b)
}
func (c *Conn) updateDeadline() {
c.Conn.SetDeadline(time.Now().Add(c.IdleTimeout))
}
// Это будет наш запрос
type Request struct {
Action string `json:"action"` // наше действие
Body string `json:"body"` // и само тело запроса
}
func handle(conn *Conn) {
defer func() { // Функция выполнится после return этой функции
log.Printf("closing connection from %v", conn.RemoteAddr())
conn.Close()
}()
r := bufio.NewReader(conn.Conn)
w := bufio.NewWriter(conn.Conn)
scaner := bufio.NewScanner(r)
for {
if !scaner.Scan() { // если произошло что-то неладное
if err := scaner.Err(); err != nil {
log.Printf("%v(%v)", err, conn.RemoteAddr())
return // то выйдем из функции (и, благодаря defer, закроем соединение)
}
}
req := Request{}
scanned := scaner.Text() // читаем текст из сети
log.Println(scanned)
err := json.Unmarshal([]byte(scanned), &req) // парсим json в нашу структуру
if err != nil {
log.Printf("error parsing json: ", err)
}
log.Println("New request. Action:", req.Action, "|", "Message:", req.Body)
response := ""
switch req.Action {
case "ping": // будем отвечать pong
response = "pong"
case "scream": // кричать
response = strings.ToUpper(req.Body)
case "bye": // и прощаться
response = "Bye!"
default: // иначе будем ругаться, что не знаем такого действия
response = "Unknown Action"
}
w.WriteString(response + "\n")
w.Flush()
if req.Action == "bye" { // если клиент попрощался, то закрываем соединение
return
}
}
}
func main() {
srv := Server{":3030", time.Minute, 1024}
srv.ListenAndServe()
}