Pug_coder

server

Sep 10th, 2021
101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 5.46 KB | None | 0 0
  1. package main
  2.  
  3. import (
  4.     "encoding/base64"
  5.     "encoding/json"
  6.     "flag"
  7.     "fmt"
  8.     "github.com/mgutz/logxi/v1"
  9.     "net"
  10.     "image"
  11.     _ "image/jpeg"
  12.     "proto"
  13.     "strings"
  14. )
  15.  
  16. // Client - состояние клиента.
  17. type Client struct {
  18.     logger log.Logger    // Объект для печати логов
  19.     conn   *net.TCPConn  // Объект TCP-соединения
  20.     enc    *json.Encoder // Объект для кодирования и отправки сообщений
  21.     image image.Image
  22. }
  23.  
  24. // NewClient - конструктор клиента, принимает в качестве параметра
  25. // объект TCP-соединения.
  26. func NewClient(conn *net.TCPConn) *Client {
  27.     return &Client{
  28.         logger: log.New(fmt.Sprintf("client %s", conn.RemoteAddr().String())),
  29.         conn:   conn,
  30.         enc:    json.NewEncoder(conn),
  31.     }
  32. }
  33.  
  34. // serve - метод, в котором реализован цикл взаимодействия с клиентом.
  35. // Подразумевается, что метод serve будет вызаваться в отдельной go-программе.
  36. func (client *Client) serve() {
  37.     defer client.conn.Close()
  38.     decoder := json.NewDecoder(client.conn)
  39.     for {
  40.         var req proto.Request
  41.         if err := decoder.Decode(&req); err != nil {
  42.             client.logger.Error("cannot decode message", "reason", err)
  43.             break
  44.         } else {
  45.             client.logger.Info("received command", "command", req.Command)
  46.             if client.handleRequest(&req) {
  47.                 client.logger.Info("shutting down connection")
  48.                 break
  49.             }
  50.         }
  51.     }
  52. }
  53.  
  54. // handleRequest - метод обработки запроса от клиента. Он возвращает true,
  55. // если клиент передал команду "quit" и хочет завершить общение.
  56. func (client *Client) handleRequest(req *proto.Request) bool {
  57.     switch req.Command {
  58.     case "quit":
  59.         client.respond("ok", nil)
  60.         return true
  61.     case "loadImage":
  62.         errorMsg := ""
  63.         if req.Data == nil {
  64.             errorMsg = "data field is absent"
  65.         } else {
  66.             var imageSchema proto.Image
  67.             if err := json.Unmarshal(*req.Data, &imageSchema); err != nil {
  68.                 errorMsg = "malformed data field"
  69.             } else {
  70.                 if image, _, err := image.Decode(base64.NewDecoder(base64.StdEncoding, strings.NewReader(imageSchema.Encoded))); err != nil {
  71.                     errorMsg = "malformed data field"
  72.                 } else {
  73.                     client.logger.Info("Saving image")
  74.                     client.image = image
  75.                 }
  76.             }
  77.         }
  78.         if errorMsg == "" {
  79.             client.respond("ok", nil)
  80.         } else {
  81.             client.logger.Error("failed", "reason", errorMsg)
  82.             client.respond("failed", errorMsg)
  83.         }
  84.     case "getSize":
  85.         if client.image == nil {
  86.             client.logger.Error("getSize Error", "reason", "image not found")
  87.             client.respond("failed", "No image load")
  88.         } else {
  89.             client.respond("getSizeResult", &proto.ImageSize{
  90.                 client.image.Bounds().Max.X,
  91.                 client.image.Bounds().Max.Y,
  92.             })
  93.         }
  94.     case "getColor":
  95.         if client.image == nil {
  96.             client.logger.Error("getSize Error", "reason", "image not found")
  97.             client.respond("failed", "No image load")
  98.         } else {
  99.             errorMsg := ""
  100.             if req.Data == nil {
  101.                 errorMsg = "data field is absent"
  102.             } else {
  103.                 var coordinatesSchema proto.Coordinates
  104.                 if err := json.Unmarshal(*req.Data, &coordinatesSchema); err != nil {
  105.                     errorMsg = "malformed data field"
  106.                 } else {
  107.                     r, g, b, a := client.image.At(coordinatesSchema.X, coordinatesSchema.Y).RGBA()
  108.                     client.respond("getColorResult", &proto.ImageColor{
  109.                         int(r), int(g), int(b), int(a),
  110.                     })
  111.                 }
  112.             }
  113.  
  114.             if errorMsg != "" {
  115.                 client.logger.Error("failed", "reason", errorMsg)
  116.                 client.respond("failed", errorMsg)
  117.             }
  118.         }
  119.     default:
  120.         client.logger.Error("unknown command")
  121.         client.respond("failed", "unknown command")
  122.     }
  123.     return false
  124. }
  125.  
  126. // respond - вспомогательный метод для передачи ответа с указанным статусом
  127. // и данными. Данные могут быть пустыми (data == nil).
  128. func (client *Client) respond(status string, data interface{}) {
  129.     var raw json.RawMessage
  130.     raw, _ = json.Marshal(data)
  131.     client.enc.Encode(&proto.Response{status, &raw})
  132. }
  133.  
  134. func main() {
  135.     // Работа с командной строкой, в которой может указываться необязательный ключ -addr.
  136.     var addrStr string
  137.     flag.StringVar(&addrStr, "addr", "127.0.0.1:6000", "specify ip address and port")
  138.     flag.Parse()
  139.  
  140.     // Разбор адреса, строковое представление которого находится в переменной addrStr.
  141.     if addr, err := net.ResolveTCPAddr("tcp", addrStr); err != nil {
  142.         log.Error("address resolution failed", "address", addrStr)
  143.     } else {
  144.         log.Info("resolved TCP address", "address", addr.String())
  145.  
  146.         // Инициация слушания сети на заданном адресе.
  147.         if listener, err := net.ListenTCP("tcp", addr); err != nil {
  148.             log.Error("listening failed", "reason", err)
  149.         } else {
  150.             // Цикл приёма входящих соединений.
  151.             for {
  152.                 if conn, err := listener.AcceptTCP(); err != nil {
  153.                     log.Error("cannot accept connection", "reason", err)
  154.                 } else {
  155.                     log.Info("accepted connection", "address", conn.RemoteAddr().String())
  156.  
  157.                     // Запуск go-программы для обслуживания клиентов.
  158.                     go NewClient(conn).serve()
  159.                 }
  160.             }
  161.         }
  162.     }
  163. }
  164.  
Add Comment
Please, Sign In to add comment