|
@@ -1,242 +0,0 @@
|
|
-package rest_websocket
|
|
|
|
-
|
|
|
|
-import (
|
|
|
|
- "bytes"
|
|
|
|
- "io"
|
|
|
|
- "time"
|
|
|
|
-
|
|
|
|
- "git.ali33.ru/fcg-xvii/go-tools/json"
|
|
|
|
- "git.ali33.ru/fcg-xvii/rest"
|
|
|
|
-)
|
|
|
|
-
|
|
|
|
-// Int64ToBytes упаковывает int64 в срез байтов заданной длины
|
|
|
|
-func Int64ToBytes(num int64, byteCount int) []byte {
|
|
|
|
- bytes := make([]byte, byteCount)
|
|
|
|
- for i := 0; i < byteCount; i++ {
|
|
|
|
- shift := uint((byteCount - 1 - i) * 8)
|
|
|
|
- bytes[i] = byte(num >> shift)
|
|
|
|
- }
|
|
|
|
- return bytes
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// BytesToInt64 конвертирует срез байтов в int64
|
|
|
|
-func BytesToInt64(bytes []byte) int64 {
|
|
|
|
- var num int64
|
|
|
|
- for _, b := range bytes {
|
|
|
|
- num = (num << 8) | int64(b)
|
|
|
|
- }
|
|
|
|
- return num
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func ioError(field string, err error) rest.IErrorArgs {
|
|
|
|
- return rest.NewError(
|
|
|
|
- "ErrIO",
|
|
|
|
- json.Map{
|
|
|
|
- "field": field,
|
|
|
|
- "error": err.Error(),
|
|
|
|
- },
|
|
|
|
- )
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func ReadMessage(r io.Reader) (*Message, rest.IErrorArgs) {
|
|
|
|
- // todo
|
|
|
|
- // id
|
|
|
|
- sType := make([]byte, 1)
|
|
|
|
- if _, err := r.Read(sType); err != nil {
|
|
|
|
- return nil, ioError("type", err)
|
|
|
|
- }
|
|
|
|
- mes := Message{
|
|
|
|
- mType: rest.RequestType(sType[0]),
|
|
|
|
- }
|
|
|
|
- if mes.mType == rest.RequestTypeMessage || mes.mType == rest.RequestTypeAnswer {
|
|
|
|
- sID := make([]byte, 2)
|
|
|
|
- if _, err := r.Read(sID); err != nil {
|
|
|
|
- return nil, ioError("id", err)
|
|
|
|
- }
|
|
|
|
- mes.id = BytesToInt64(sID)
|
|
|
|
- }
|
|
|
|
- if mes.mType == rest.RequestTypeMessage {
|
|
|
|
- sTimeout := make([]byte, 8)
|
|
|
|
- if _, err := r.Read(sTimeout); err != nil {
|
|
|
|
- return nil, ioError("timeout", err)
|
|
|
|
- }
|
|
|
|
- mes.timeout = time.Unix(BytesToInt64(sTimeout), 0)
|
|
|
|
- }
|
|
|
|
- sCommandSize := make([]byte, 2)
|
|
|
|
- if _, err := r.Read(sCommandSize); err != nil {
|
|
|
|
- return nil, ioError("data_size", err)
|
|
|
|
- }
|
|
|
|
- if BytesToInt64(sCommandSize) > 0 {
|
|
|
|
- sCommand := make([]byte, BytesToInt64(sCommandSize))
|
|
|
|
- if _, err := r.Read(sCommand); err != nil {
|
|
|
|
- return nil, ioError("data", err)
|
|
|
|
- }
|
|
|
|
- mes.command = string(sCommand)
|
|
|
|
- }
|
|
|
|
- sDataSize := make([]byte, 8)
|
|
|
|
- if _, err := r.Read(sDataSize); err != nil {
|
|
|
|
- return nil, ioError("data_size", err)
|
|
|
|
- }
|
|
|
|
- sData := make([]byte, BytesToInt64(sDataSize))
|
|
|
|
- if _, err := r.Read(sData); err != nil {
|
|
|
|
- return nil, ioError("data", err)
|
|
|
|
- }
|
|
|
|
- if len(sData) > 0 {
|
|
|
|
- if err := json.Unmarshal(sData, &mes.data); err != nil {
|
|
|
|
- return nil, ioError("data", err)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- sFilesCount := make([]byte, 2)
|
|
|
|
- if _, err := r.Read(sFilesCount); err != nil {
|
|
|
|
- return nil, ioError("files_count", err)
|
|
|
|
- }
|
|
|
|
- filesCount := BytesToInt64(sFilesCount)
|
|
|
|
- files := make(map[string]rest.IReadCloserLen)
|
|
|
|
- for i := 0; i < int(filesCount); i++ {
|
|
|
|
- sFileNameLen := make([]byte, 2)
|
|
|
|
- if _, err := r.Read(sFileNameLen); err != nil {
|
|
|
|
- return nil, ioError("file_name_length", err)
|
|
|
|
- }
|
|
|
|
- sFileName := make([]byte, BytesToInt64(sFileNameLen))
|
|
|
|
- if _, err := r.Read(sFileName); err != nil {
|
|
|
|
- return nil, ioError("file_name", err)
|
|
|
|
- }
|
|
|
|
- sFileSize := make([]byte, 8)
|
|
|
|
- if _, err := r.Read(sFileSize); err != nil {
|
|
|
|
- return nil, ioError("file_size", err)
|
|
|
|
- }
|
|
|
|
- fileSize := BytesToInt64(sFileSize)
|
|
|
|
- if fileSize < 1024*1024 {
|
|
|
|
- // RAM buffer
|
|
|
|
- sFileData := make([]byte, fileSize)
|
|
|
|
- if _, err := r.Read(sFileData); err != nil {
|
|
|
|
- return nil, ioError("file_data", err)
|
|
|
|
- }
|
|
|
|
- buf := rest.NewReadCloserLen(
|
|
|
|
- io.NopCloser(bytes.NewBuffer(sFileData)),
|
|
|
|
- int64(len(sFileData)),
|
|
|
|
- )
|
|
|
|
- files[string(sFileName)] = buf
|
|
|
|
- } else {
|
|
|
|
- // temporary file
|
|
|
|
- tmpF, err := rest.NewTemporaryFile(fileSize, r)
|
|
|
|
- if err != nil {
|
|
|
|
- return nil, err
|
|
|
|
- }
|
|
|
|
- files[string(sFileName)] = tmpF
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return &mes, nil
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func NewMessage(command string, data json.Map, files map[string]rest.IReadCloserLen, timeout time.Duration, mType rest.RequestType) *Message {
|
|
|
|
- return &Message{
|
|
|
|
- command: command,
|
|
|
|
- data: data,
|
|
|
|
- files: files,
|
|
|
|
- mType: mType,
|
|
|
|
- timeout: time.Now().Add(timeout),
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-type Message struct {
|
|
|
|
- id int64
|
|
|
|
- command string
|
|
|
|
- mType rest.RequestType
|
|
|
|
- timeout time.Time
|
|
|
|
- data json.Map
|
|
|
|
- files map[string]rest.IReadCloserLen
|
|
|
|
- owner *WebSocket
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func (s *Message) Data() json.Map {
|
|
|
|
- return s.data
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func (s *Message) File(name string) (rest.IReadCloserLen, bool) {
|
|
|
|
- file, check := s.files[name]
|
|
|
|
- return file, check
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func (s *Message) FileKeys() []string {
|
|
|
|
- keys := make([]string, 0, len(s.files))
|
|
|
|
- for k := range s.files {
|
|
|
|
- keys = append(keys, k)
|
|
|
|
- }
|
|
|
|
- return keys
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func (s *Message) Command() string {
|
|
|
|
- return s.command
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func (s *Message) IsBinagy() bool {
|
|
|
|
- return len(s.files) > 0
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func (s *Message) Write(w io.Writer) rest.IErrorArgs {
|
|
|
|
- // id
|
|
|
|
- if _, err := w.Write(Int64ToBytes(s.id, 2)); err != nil {
|
|
|
|
- return ioError("id", err)
|
|
|
|
- }
|
|
|
|
- // type
|
|
|
|
- if _, err := w.Write(Int64ToBytes(int64(s.mType), 1)); err != nil {
|
|
|
|
- return ioError("type", err)
|
|
|
|
- }
|
|
|
|
- // timeout
|
|
|
|
- if _, err := w.Write(Int64ToBytes(s.timeout.Unix(), 8)); err != nil {
|
|
|
|
- return ioError("timeout", err)
|
|
|
|
- }
|
|
|
|
- // command length
|
|
|
|
- if _, err := w.Write(Int64ToBytes(int64(len(s.command)), 2)); err != nil {
|
|
|
|
- return ioError("command_length", err)
|
|
|
|
- }
|
|
|
|
- // command
|
|
|
|
- if len(s.command) > 0 {
|
|
|
|
- if _, err := w.Write([]byte(s.command)); err != nil {
|
|
|
|
- return ioError("command", err)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- // data
|
|
|
|
- data := s.data.JSON()
|
|
|
|
- // data size
|
|
|
|
- if _, err := w.Write(Int64ToBytes(int64(len(data)), 8)); err != nil {
|
|
|
|
- return ioError("data_size", err)
|
|
|
|
- }
|
|
|
|
- // data body
|
|
|
|
- if _, err := w.Write(data); err != nil {
|
|
|
|
- return ioError("data_body", err)
|
|
|
|
- }
|
|
|
|
- // files count
|
|
|
|
- filesCount := int64(len(s.files))
|
|
|
|
- if _, err := w.Write(Int64ToBytes(filesCount, 2)); err != nil {
|
|
|
|
- return ioError("files_count", err)
|
|
|
|
- }
|
|
|
|
- // files
|
|
|
|
- for name, file := range s.files {
|
|
|
|
- // file name size
|
|
|
|
- fileNameSize := int64(len(name))
|
|
|
|
- if _, err := w.Write(Int64ToBytes(fileNameSize, 2)); err != nil {
|
|
|
|
- return ioError("file_name_size", err)
|
|
|
|
- }
|
|
|
|
- // file name
|
|
|
|
- if _, err := w.Write([]byte(name)); err != nil {
|
|
|
|
- return ioError("file_name", err)
|
|
|
|
- }
|
|
|
|
- // file body size
|
|
|
|
- if _, err := w.Write(Int64ToBytes(file.Len(), 8)); err != nil {
|
|
|
|
- return ioError("file_body_size", err)
|
|
|
|
- }
|
|
|
|
- // file body
|
|
|
|
- if _, err := io.Copy(w, file); err != nil {
|
|
|
|
- return ioError("file_body", err)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return nil
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func (s *Message) Close() {
|
|
|
|
- for _, file := range s.files {
|
|
|
|
- file.Close()
|
|
|
|
- }
|
|
|
|
-}
|
|
|