123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- 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()
- }
- }
|