Ver código fonte

feature: syncing status

bigeagle 9 anos atrás
pai
commit
3d38e413ce
3 arquivos alterados com 184 adições e 0 exclusões
  1. 1 0
      .testpackages.txt
  2. 144 0
      internal/status/status.go
  3. 39 0
      internal/status/status_test.go

+ 1 - 0
.testpackages.txt

@@ -1,2 +1,3 @@
 github.com/tuna/tunasync/internal
+github.com/tuna/tunasync/internal/status
 github.com/tuna/tunasync/manager

+ 144 - 0
internal/status/status.go

@@ -0,0 +1,144 @@
+package status
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type syncStatus uint8
+
+const (
+	None syncStatus = iota
+	Failed
+	Success
+	Syncing
+	PreSyncing
+	Paused
+	Disabled
+)
+
+type MirrorStatus struct {
+	Name       string
+	Status     syncStatus
+	LastUpdate time.Time
+	Upstream   string
+	Size       string // approximate size
+}
+
+func (s MirrorStatus) MarshalJSON() ([]byte, error) {
+	m := map[string]interface{}{
+		"name":           s.Name,
+		"status":         s.Status,
+		"last_update":    s.LastUpdate.Format("2006-01-02 15:04:05"),
+		"last_update_ts": fmt.Sprintf("%d", s.LastUpdate.Unix()),
+		"size":           s.Size,
+		"upstream":       s.Upstream,
+	}
+	return json.Marshal(m)
+}
+
+func (s *MirrorStatus) UnmarshalJSON(v []byte) error {
+	var m map[string]interface{}
+
+	err := json.Unmarshal(v, &m)
+	if err != nil {
+		return err
+	}
+
+	if name, ok := m["name"]; ok {
+		if s.Name, ok = name.(string); !ok {
+			return errors.New("name should be a string")
+		}
+	} else {
+		return errors.New("key `name` does not exist in the json")
+	}
+	if upstream, ok := m["upstream"]; ok {
+		if s.Upstream, ok = upstream.(string); !ok {
+			return errors.New("upstream should be a string")
+		}
+	} else {
+		return errors.New("key `upstream` does not exist in the json")
+	}
+	if size, ok := m["size"]; ok {
+		if s.Size, ok = size.(string); !ok {
+			return errors.New("size should be a string")
+		}
+	} else {
+		return errors.New("key `size` does not exist in the json")
+	}
+	// tricky: status
+	if status, ok := m["status"]; ok {
+		if ss, ok := status.(string); ok {
+			err := json.Unmarshal([]byte(`"`+ss+`"`), &(s.Status))
+			if err != nil {
+				return err
+			}
+		} else {
+			return errors.New("status should be a string")
+		}
+	} else {
+		return errors.New("key `status` does not exist in the json")
+	}
+	// tricky: last update
+	if lastUpdate, ok := m["last_update_ts"]; ok {
+		if sts, ok := lastUpdate.(string); ok {
+			ts, err := strconv.Atoi(sts)
+			if err != nil {
+				return fmt.Errorf("last_update_ts should be a interger, got: %s", sts)
+			}
+			s.LastUpdate = time.Unix(int64(ts), 0)
+		} else {
+			return fmt.Errorf("last_update_ts should be a string of integer, got: %s", lastUpdate)
+		}
+	} else {
+		return errors.New("key `last_update_ts` does not exist in the json")
+	}
+	return nil
+}
+
+func (s syncStatus) MarshalJSON() ([]byte, error) {
+	var strStatus string
+	switch s {
+	case None:
+		strStatus = "none"
+	case Success:
+		strStatus = "success"
+	case Syncing:
+		strStatus = "syncing"
+	case PreSyncing:
+		strStatus = "pre-syncing"
+	case Paused:
+		strStatus = "paused"
+	case Disabled:
+		strStatus = "disabled"
+	default:
+		return []byte{}, errors.New("Invalid status value")
+	}
+
+	return json.Marshal(strStatus)
+}
+
+func (s *syncStatus) UnmarshalJSON(v []byte) error {
+	sv := strings.Trim(string(v), `"`)
+	switch sv {
+	case "none":
+		*s = None
+	case "success":
+		*s = Success
+	case "syncing":
+		*s = Syncing
+	case "pre-syncing":
+		*s = PreSyncing
+	case "paused":
+		*s = Paused
+	case "disabled":
+		*s = Disabled
+	default:
+		return fmt.Errorf("Invalid status value: %s", string(v))
+	}
+	return nil
+}

+ 39 - 0
internal/status/status_test.go

@@ -0,0 +1,39 @@
+package status
+
+import (
+	"encoding/json"
+	"testing"
+	"time"
+
+	. "github.com/smartystreets/goconvey/convey"
+)
+
+func TestStatus(t *testing.T) {
+	Convey("status json ser-de should work", t, func() {
+		tz := "Asia/Shanghai"
+		loc, err := time.LoadLocation(tz)
+		So(err, ShouldBeNil)
+
+		m := MirrorStatus{
+			Name:       "tunalinux",
+			Status:     Success,
+			LastUpdate: time.Date(2016, time.April, 16, 23, 8, 10, 0, loc),
+			Size:       "5GB",
+			Upstream:   "rsync://mirrors.tuna.tsinghua.edu.cn/tunalinux/",
+		}
+
+		b, err := json.Marshal(m)
+		So(err, ShouldBeNil)
+		// fmt.Println(string(b))
+		var m2 MirrorStatus
+		err = json.Unmarshal(b, &m2)
+		So(err, ShouldBeNil)
+		// fmt.Printf("%#v", m2)
+		So(m2.Name, ShouldEqual, m.Name)
+		So(m2.Status, ShouldEqual, m.Status)
+		So(m2.LastUpdate.Unix(), ShouldEqual, m.LastUpdate.Unix())
+		So(m2.LastUpdate.UnixNano(), ShouldEqual, m.LastUpdate.UnixNano())
+		So(m2.Size, ShouldEqual, m.Size)
+		So(m2.Upstream, ShouldEqual, m.Upstream)
+	})
+}