This repository has been archived by the owner on Feb 3, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
369 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
.idea/ | ||
*.exe | ||
gohost* | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package gohost | ||
|
||
import ( | ||
"errors" | ||
"github.com/timshannon/bolthold" | ||
) | ||
|
||
var ( | ||
ErrGroupExist = errors.New("group is already existed") | ||
) | ||
|
||
type Group struct { | ||
ID uint `boltholdKey:"ID"` | ||
ParentID uint | ||
Name string | ||
Desc string | ||
} | ||
|
||
func (g Group) Title() string { | ||
return g.Name | ||
} | ||
func (g Group) Description() string { | ||
return g.Desc | ||
} | ||
func (g Group) FilterValue() string { | ||
return g.Name | ||
} | ||
|
||
func (g Group) GetID() uint { | ||
return g.ID | ||
} | ||
|
||
func (g Group) GetParentID() uint { | ||
return g.ParentID | ||
} | ||
|
||
func (s *Service) loadGroups() []Group { | ||
var groups []Group | ||
if err := s.store.FindNullable(&groups, &bolthold.Query{}); err != nil { | ||
panic(err) | ||
} | ||
return groups | ||
} | ||
|
||
func (s *Service) loadGroupNodes() []*Node[TreeNode] { | ||
groups := s.loadGroups() | ||
|
||
groupNodes := make([]*Node[TreeNode], 0, len(groups)) | ||
for _, group := range groups { | ||
groupNodes = append(groupNodes, NewNode[TreeNode](group, 0)) | ||
} | ||
return groupNodes | ||
} | ||
|
||
func (s *Service) SaveGroup(group Group) error { | ||
if _, exist := s.nodes[group.ID]; exist { | ||
return ErrGroupExist | ||
} | ||
err := s.store.Insert(group.ID, group) | ||
if err != nil { | ||
return err | ||
} | ||
// FIXME set correct depth | ||
s.nodes[group.ID] = NewNode[TreeNode](&group, 0) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package gohost | ||
|
||
import ( | ||
"github.com/stretchr/testify/assert" | ||
"gohost/db" | ||
"testing" | ||
) | ||
|
||
func TestGroupService_Save(t *testing.T) { | ||
store := db.Instance() | ||
defer store.Close() | ||
a := assert.New(t) | ||
service := GetService() | ||
groups := []Group{ | ||
{ID: 1, ParentID: 0, Name: "g-1", Desc: "desc1"}, | ||
{ID: 11, ParentID: 1, Name: "g-1-1", Desc: "desc11"}, | ||
{ID: 111, ParentID: 11, Name: "g-1-1-1", Desc: "desc111"}, | ||
{ID: 112, ParentID: 11, Name: "g-1-1-2", Desc: "desc112"}, | ||
{ID: 12, ParentID: 1, Name: "g-1-2", Desc: "desc12"}, | ||
{ID: 13, ParentID: 1, Name: "g-1-3", Desc: "desc13"}, | ||
{ID: 131, ParentID: 13, Name: "g-1-3-1", Desc: "desc131"}, | ||
{ID: 132, ParentID: 13, Name: "g-1-3-2", Desc: "desc132"}, | ||
{ID: 2, ParentID: 0, Name: "g-2", Desc: "desc2"}, | ||
{ID: 3, ParentID: 0, Name: "g-3", Desc: "desc3"}, | ||
{ID: 31, ParentID: 3, Name: "g-3-1", Desc: "desc31"}, | ||
{ID: 32, ParentID: 3, Name: "g-3-2", Desc: "desc32"}, | ||
{ID: 4, ParentID: 0, Name: "g-4", Desc: "desc4"}, | ||
} | ||
for _, g := range groups { | ||
if err := service.SaveGroup(g); err != nil { | ||
a.NoError(err) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package gohost | ||
|
||
import ( | ||
"github.com/timshannon/bolthold" | ||
"gohost/util" | ||
) | ||
|
||
type Host interface { | ||
TreeNode | ||
GetID() uint | ||
GetName() string | ||
GetContent() []byte | ||
GetDesc() string | ||
GetGroupID() uint | ||
} | ||
|
||
func (s *Service) SaveHost(host Host) error { | ||
if err := s.store.Insert(host.GetDesc(), host); err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func (s *Service) LoadHosts(groupID uint) []Host { | ||
return s.loadLocalHosts(groupID) | ||
} | ||
|
||
func (s *Service) LoadHostNodes(groupID uint) []*Node[TreeNode] { | ||
groupNode := s.nodes[groupID] | ||
if groupNode == nil { | ||
return nil | ||
} | ||
hostNodeDepth := groupNode.Depth + 1 | ||
hosts := s.LoadHosts(groupID) | ||
hostNodes := make([]*Node[TreeNode], 0, len(hosts)) | ||
for _, host := range hosts { | ||
node := NewNode[TreeNode](host, hostNodeDepth) | ||
hostNodes = append(hostNodes, node) | ||
} | ||
return hostNodes | ||
} | ||
|
||
func (s *Service) loadLocalHosts(groupID uint) []Host { | ||
var hosts []*LocalHost | ||
if err := s.store.FindNullable(&hosts, bolthold.Where("GroupID").Eq(groupID)); err != nil { | ||
panic(err) | ||
} | ||
return util.WrapSlice[Host](hosts) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package gohost | ||
|
||
import ( | ||
"fmt" | ||
"github.com/stretchr/testify/assert" | ||
"testing" | ||
) | ||
|
||
func TestService_SaveHost(t *testing.T) { | ||
a := assert.New(t) | ||
hosts := []Host{ | ||
&LocalHost{ | ||
ID: 1000, | ||
Name: "host-1000", | ||
Content: []byte("127.0.0.1 localhost"), | ||
Desc: "host1000", | ||
GroupID: 3, | ||
}, | ||
} | ||
|
||
for _, host := range hosts { | ||
if err := GetService().SaveHost(host); err != nil { | ||
a.NoError(err) | ||
} | ||
} | ||
} | ||
|
||
func TestService_LoadHost(t *testing.T) { | ||
hosts := GetService().loadLocalHosts(3) | ||
for _, host := range hosts { | ||
fmt.Println(host) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package gohost | ||
|
||
type LocalHost struct { | ||
ID uint | ||
Name string | ||
Content []byte | ||
Desc string | ||
GroupID uint | ||
} | ||
|
||
// Implement of Host | ||
|
||
func (h *LocalHost) GetID() uint { | ||
return h.ID | ||
} | ||
|
||
func (h *LocalHost) GetName() string { | ||
return h.Name | ||
} | ||
|
||
func (h *LocalHost) GetContent() []byte { | ||
return h.Content | ||
} | ||
|
||
func (h *LocalHost) GetDesc() string { | ||
return h.Desc | ||
} | ||
|
||
func (h *LocalHost) GetGroupID() uint { | ||
return h.GroupID | ||
} | ||
|
||
// Implement of TreeNode | ||
|
||
func (h *LocalHost) FilterValue() string { | ||
return h.Name | ||
} | ||
|
||
func (h *LocalHost) GetParentID() uint { | ||
return h.GroupID | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package gohost | ||
|
||
import "github.com/charmbracelet/bubbles/list" | ||
|
||
type TreeNode interface { | ||
list.Item | ||
GetID() uint | ||
GetParentID() uint | ||
} | ||
|
||
type Node[T TreeNode] struct { | ||
Data T | ||
Children []*Node[T] | ||
Depth int | ||
IsFolded bool | ||
} | ||
|
||
func NewNode[T TreeNode](data T, depth int) *Node[T] { | ||
return &Node[T]{ | ||
Data: data, | ||
Children: make([]*Node[T], 0), | ||
Depth: depth, | ||
IsFolded: true, | ||
} | ||
} | ||
|
||
func (n *Node[T]) FilterValue() string { | ||
return n.Data.FilterValue() | ||
} | ||
|
||
func (n *Node[T]) GetID() uint { | ||
return n.Data.GetID() | ||
} | ||
|
||
func (n *Node[T]) GetParentID() uint { | ||
return n.Data.GetParentID() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package gohost | ||
|
||
type RemoteHost struct { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package gohost | ||
|
||
import ( | ||
"gohost/db" | ||
"sort" | ||
"sync" | ||
) | ||
|
||
var ( | ||
service *Service | ||
serviceOnce sync.Once | ||
) | ||
|
||
func GetService() *Service { | ||
serviceOnce.Do(func() { | ||
service = NewService() | ||
}) | ||
return service | ||
} | ||
|
||
func NewService() *Service { | ||
return &Service{ | ||
store: db.Instance(), | ||
nodes: make(map[uint]*Node[TreeNode], 0), | ||
tree: make([]*Node[TreeNode], 0), | ||
} | ||
} | ||
|
||
type Service struct { | ||
store *db.Store | ||
nodes map[uint]*Node[TreeNode] | ||
tree []*Node[TreeNode] | ||
} | ||
|
||
func (s *Service) Tree() []*Node[TreeNode] { | ||
return s.tree | ||
} | ||
|
||
func (s *Service) cacheNodes(nodes []*Node[TreeNode]) { | ||
for _, node := range nodes { | ||
s.nodes[node.GetID()] = node | ||
} | ||
} | ||
|
||
func (s *Service) buildTree() { | ||
// Build tree | ||
for _, node := range s.nodes { | ||
p, exist := s.nodes[node.Data.GetParentID()] | ||
if !exist { | ||
s.tree = append(s.tree, node) | ||
continue | ||
} | ||
node.Depth = p.Depth + 1 | ||
p.Children = append(p.Children, node) | ||
} | ||
// Bfs to set depth | ||
sort.Slice(s.tree, func(i, j int) bool { | ||
return s.tree[i].Data.GetID() < s.tree[j].GetID() | ||
}) | ||
nodes := s.tree | ||
depth := 0 | ||
for len(nodes) > 0 { | ||
for _, node := range nodes { | ||
node.Depth = depth | ||
sort.Slice(node.Children, func(i, j int) bool { | ||
return node.Children[i].GetID() < node.Children[j].GetID() | ||
}) | ||
nodes = append(nodes, node.Children...) | ||
nodes = nodes[1:] | ||
} | ||
depth++ | ||
} | ||
} | ||
|
||
func (s *Service) Load() { | ||
nodes := make([]*Node[TreeNode], 0) | ||
nodes = append(nodes, s.loadGroupNodes()...) | ||
s.cacheNodes(nodes) | ||
s.buildTree() | ||
} | ||
|
||
func (s *Service) ChildNodes(nodeID uint) []*Node[TreeNode] { | ||
return s.nodes[nodeID].Children | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package gohost | ||
|
||
type SysHost struct { | ||
HostsEnable map[int]struct{} | ||
} |
Oops, something went wrong.