package main import ( "encoding/json" "hash/fnv" "os" "time" ) type FileEvent struct { Op string `json:"op"` Path string `json:"path"` New string `json:"new_path,omitempty"` } type FileMeta struct { Size int64 Mode os.FileMode ModTime time.Time Symlink string Hash uint64 } type FileMetaJSON struct { Size int64 `json:"size"` Mode uint32 `json:"mode"` ModTime string `json:"modtime"` Symlink string `json:"symlink,omitempty"` Hash uint64 `json:"hash,omitempty"` } type Manifest struct { Files map[string]FileMeta } type ProtocolMessage struct { Type string `json:"type"` Files map[string]FileMetaJSON `json:"files,omitempty"` Path string `json:"path,omitempty"` Content []byte `json:"content,omitempty"` } func (m *Manifest) ToJSON() map[string]FileMetaJSON { files := make(map[string]FileMetaJSON, len(m.Files)) for k, v := range m.Files { files[k] = FileMetaJSON{ Size: v.Size, Mode: uint32(v.Mode), ModTime: v.ModTime.UTC().Format(time.RFC3339Nano), Symlink: v.Symlink, Hash: v.Hash, } } return files } func ManifestFromJSON(files map[string]FileMetaJSON) *Manifest { m := &Manifest{Files: make(map[string]FileMeta, len(files))} for k, v := range files { t, _ := time.Parse(time.RFC3339Nano, v.ModTime) m.Files[k] = FileMeta{ Size: v.Size, Mode: os.FileMode(v.Mode), ModTime: t, Symlink: v.Symlink, Hash: v.Hash, } } return m } func DecodeMessage(data []byte) (*ProtocolMessage, error) { var msg ProtocolMessage if err := json.Unmarshal(data, &msg); err != nil { return nil, err } return &msg, nil } func EncodeMessage(msg *ProtocolMessage) ([]byte, error) { return json.Marshal(msg) } func hashFile(path string) uint64 { f, err := os.Open(path) if err != nil { return 0 } defer f.Close() h := fnv.New64a() buf := make([]byte, 32*1024) for { n, err := f.Read(buf) if n > 0 { h.Write(buf[:n]) } if err != nil { break } } return h.Sum64() }