Compare commits

...

8 Commits

  1. 8
      cmd/coconut_desktop/main.go
  2. 338
      data/ui/UI.glade
  3. 1
      go.mod
  4. 4
      go.sum
  5. 28
      internal/client/client.go
  6. 5
      internal/client/client_test.go
  7. 297
      internal/client/ui.go
  8. 2
      pkg/go.mod
  9. 4
      pkg/go.sum
  10. 33
      pkg/log/log.go
  11. 16
      pkg/log/log_test.go
  12. 33
      pkg/util/util.go

8
cmd/coconut_desktop/main.go

@ -1,7 +1,13 @@
package main
import "github.com/jaeha-choi/Proj_Coconut_Desktop/internal/client"
import (
//_ "embed"
"github.com/jaeha-choi/Proj_Coconut_Desktop/internal/client"
)
//var uiString []byte
func main() {
client.Start("./data/ui/UI.glade")
//client.Start(string(uiString))
}

338
data/ui/UI.glade

@ -2,207 +2,243 @@
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<object class="GtkListStore" id="contactList"/>
<object class="GtkListStore" id="fileList">
<columns>
<!-- column-name Selected -->
<column type="gboolean"/>
<!-- column-name Filename -->
<column type="gchararray"/>
<!-- column-name Size -->
<column type="guint64"/>
<!-- column-name Date -->
<column type="gchararray"/>
<!-- column-name Path -->
<!-- column-name Status -->
<column type="gchararray"/>
<!-- column-name Full path -->
<column type="gchararray"/>
<!-- column-name Size in Bytes -->
<column type="gint64"/>
</columns>
<data>
<row>
<col id="0">True</col>
<col id="1" translatable="yes">cat.jpg</col>
<col id="2">5953</col>
<col id="3" translatable="yes">2021/06/23</col>
<col id="4" translatable="yes">/home/jaeha/cat_photos</col>
</row>
<row>
<col id="0">False</col>
<col id="1" translatable="yes">resume.pdf</col>
<col id="2">1360</col>
<col id="3" translatable="yes">2021/07/01</col>
<col id="4" translatable="yes">/home/jaeha/docs</col>
</row>
</data>
</object>
<object class="GtkWindow" id="main_window">
<property name="can-focus">False</property>
<property name="resizable">False</property>
<property name="default-width">500</property>
<property name="default-height">700</property>
<signal name="key-press-event" handler="keyPress" swapped="no"/>
<child>
<object class="GtkBox">
<object class="GtkNotebook" id="pager">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="can-focus">True</property>
<signal name="switch-page" handler="switchPage" swapped="no"/>
<child>
<object class="GtkTreeView" id="file_list">
<object class="GtkBox" id="fileBox">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="model">fileList</property>
<property name="enable-grid-lines">horizontal</property>
<child internal-child="selection">
<object class="GtkTreeSelection">
<property name="mode">multiple</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkTreeView" id="fileListView">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="model">fileList</property>
<property name="enable-grid-lines">horizontal</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="fileSelected">
<property name="mode">multiple</property>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="fileName">
<property name="max-width">150</property>
<property name="title" translatable="yes">Filename</property>
<property name="expand">True</property>
<property name="clickable">True</property>
<property name="sort-column-id">0</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="fileSize">
<property name="max-width">50</property>
<property name="title" translatable="yes">Size</property>
<property name="clickable">True</property>
<property name="sort-column-id">4</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="fileStatus">
<property name="max-width">200</property>
<property name="title" translatable="yes">Status</property>
<property name="expand">True</property>
<property name="clickable">True</property>
<property name="sort-column-id">2</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkTreeViewColumn" id="fileDeselect">
<object class="GtkBox" id="infoBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">5</property>
<property name="margin-end">2</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="label" translatable="yes">Selected File(s):</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCellRendererToggle" id="selectToggle"/>
<attributes>
<attribute name="active">0</attribute>
</attributes>
<object class="GtkLabel" id="infoFileCount">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">5</property>
<property name="margin-end">2</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="infoFileSize">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">2</property>
<property name="margin-end">5</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">2</property>
<property name="margin-end">5</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="label" translatable="yes">Total Size:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<child type="tab">
<object class="GtkLabel" id="fileTabLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="tooltip-text" translatable="yes">Select files to send</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">Files</property>
</object>
<packing>
<property name="tab-fill">False</property>
</packing>
</child>
<child>
<object class="GtkTreeView" id="contactListView">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="model">contactList</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
<child>
<object class="GtkTreeViewColumn" id="fileName">
<property name="resizable">True</property>
<property name="title" translatable="yes">Filename</property>
<property name="expand">True</property>
<object class="GtkTreeViewColumn" id="contactSelect">
<property name="clickable">True</property>
<property name="sort-indicator">True</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
<object class="GtkCellRendererToggle" id="contactSelectToggle"/>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="fileSize">
<property name="resizable">True</property>
<property name="title" translatable="yes">Size</property>
<object class="GtkTreeViewColumn" id="contactName">
<property name="min-width">100</property>
<property name="title" translatable="yes">Name</property>
<property name="clickable">True</property>
<property name="sort-indicator">True</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="fileDate">
<property name="resizable">True</property>
<object class="GtkTreeViewColumn" id="contactDate">
<property name="min-width">80</property>
<property name="title" translatable="yes">Date</property>
<property name="clickable">True</property>
<property name="sort-indicator">True</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">3</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="filePath">
<property name="resizable">True</property>
<property name="title" translatable="yes">Path</property>
<property name="expand">True</property>
<object class="GtkTreeViewColumn" id="contactPubkey">
<property name="title" translatable="yes">PubKey</property>
<property name="clickable">True</property>
<property name="sort-indicator">True</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">4</attribute>
</attributes>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<child type="tab">
<object class="GtkLabel" id="contactTabLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">5</property>
<property name="margin-end">2</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="label" translatable="yes">Selected File(s):</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="file_count_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">5</property>
<property name="margin-end">2</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="label" translatable="yes">3</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">2</property>
<property name="margin-end">5</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="label" translatable="yes">7 MB</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">2</property>
<property name="margin-end">5</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="label" translatable="yes">Total Size:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">3</property>
</packing>
</child>
<property name="tooltip-text" translatable="yes">Manage contacts</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">Contacts</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
<property name="position">1</property>
<property name="tab-fill">False</property>
</packing>
</child>
</object>
@ -226,7 +262,7 @@
<property name="activatable">False</property>
<property name="selectable">False</property>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="programName">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Project Coconut</property>
@ -260,7 +296,7 @@
</object>
</child>
<child>
<object class="GtkButton" id="send_button">
<object class="GtkButton" id="sendButton">
<property name="label" translatable="yes">Send</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
@ -269,11 +305,12 @@
</object>
</child>
<child>
<object class="GtkButton" id="add_files_button">
<object class="GtkButton" id="addButton">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="receives-default">True</property>
<property name="relief">none</property>
<signal name="clicked" handler="addButtonClick" object="main_window" swapped="no"/>
<child>
<object class="GtkImage" id="add_icon">
<property name="visible">True</property>
@ -287,7 +324,7 @@
</packing>
</child>
<child>
<object class="GtkMenuButton" id="menu_button">
<object class="GtkMenuButton" id="menuButton">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="focus-on-click">False</property>
@ -307,11 +344,12 @@
</packing>
</child>
<child>
<object class="GtkToggleButton" id="view_toggle_button">
<object class="GtkToggleButton" id="viewToggle">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="receives-default">True</property>
<property name="relief">none</property>
<property name="active">True</property>
<child>
<object class="GtkImage" id="image1">
<property name="visible">True</property>

1
go.mod

@ -5,6 +5,7 @@ go 1.16
require (
github.com/gotk3/gotk3 v0.6.1
github.com/jaeha-choi/Proj_Coconut_Utility v0.0.0-20210705231131-ec06b1d1b8e2
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
)
replace github.com/jaeha-choi/Proj_Coconut_Utility => ./pkg

4
go.sum

@ -1,2 +1,6 @@
github.com/gotk3/gotk3 v0.6.1 h1:GJ400a0ecEEWrzjBvzBzH+pB/esEMIGdB9zPSmBdoeo=
github.com/gotk3/gotk3 v0.6.1/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

28
internal/client/client.go

@ -1 +1,29 @@
package client
import (
"crypto/tls"
"github.com/jaeha-choi/Proj_Coconut_Utility/log"
"strconv"
)
type Client struct {
ServerIp string `yaml:"server_ip"`
ServerPort uint16 `yaml:"server_port"`
tlsConfig *tls.Config
}
func Connect() {
client1 := &Client{
ServerIp: "127.0.0.1",
ServerPort: 9129,
tlsConfig: &tls.Config{InsecureSkipVerify: true},
}
dial, err := tls.Dial("tcp", client1.ServerIp+":"+strconv.Itoa(int(client1.ServerPort)), client1.tlsConfig)
if err != nil {
log.Debug(err)
log.Error("Error while connecting to the server")
return
}
_, _ = dial.Write([]byte("hello"))
_ = dial.Close()
}

5
internal/client/client_test.go

@ -3,8 +3,13 @@ package client
import (
"github.com/jaeha-choi/Proj_Coconut_Utility/log"
"os"
"testing"
)
func init() {
log.Init(os.Stdout, log.DEBUG)
}
func TestConnect(t *testing.T) {
Connect()
}

297
internal/client/ui.go

@ -2,18 +2,47 @@ package client
import (
"errors"
"github.com/gotk3/gotk3/gdk"
"github.com/gotk3/gotk3/glib"
"github.com/gotk3/gotk3/gtk"
"github.com/jaeha-choi/Proj_Coconut_Utility/log"
"os"
"path/filepath"
"strconv"
)
const (
appId = "dev.jaeha.coconut"
)
const (
fileNameIdx = iota
fileSizeWithUnitIdx
fileStatusIdx
fileFullPath
fileSizeInBytes
)
var AssertFailed = errors.New("type assertion failed")
type UIStatus struct {
builder *gtk.Builder
isFileTab bool
fileListOrder []int
fileMap map[string]struct{}
}
type preprocessing func(string) ([]interface{}, error)
func initUIStatus() (stat *UIStatus) {
return &UIStatus{
builder: nil,
isFileTab: true,
fileListOrder: []int{fileNameIdx, fileSizeWithUnitIdx, fileStatusIdx, fileFullPath, fileSizeInBytes},
fileMap: map[string]struct{}{},
}
}
func Start(uiGladePath string) {
log.Init(os.Stdout, log.DEBUG)
@ -32,8 +61,12 @@ func Start(uiGladePath string) {
// Connect function to application activate event
application.Connect("activate", func() {
var err error
stat := initUIStatus()
// Get the GtkBuilder ui definition in the glade file.
builder, err := gtk.BuilderNewFromFile(uiGladePath)
stat.builder, err = gtk.BuilderNewFromFile(uiGladePath)
//stat.builder, err = gtk.BuilderNewFromString(uiString)
if err != nil {
log.Debug(err)
log.Error("Error in BuilderNewFromFile")
@ -42,27 +75,18 @@ func Start(uiGladePath string) {
// Map the handlers to callback functions, and connect the signals
// to the Builder.
//signals := map[string]interface{}{
// "resize": windResize,
//}
//builder.ConnectSignals(signals)
// Get the object with the id of "main_window".
obj, err := builder.GetObject("main_window")
if err != nil {
log.Debug(err)
log.Error("Error in GetObject")
return
signals := map[string]interface{}{
"switchPage": stat.switchPage,
"addButtonClick": stat.addButtonClick,
"keyPress": stat.keyPress,
}
stat.builder.ConnectSignals(signals)
// Verify that the object is a pointer to a gtk.ApplicationWindow.
win, err := isWindow(obj)
win, err := stat.getWindowWithId("main_window")
if err != nil {
log.Debug(err)
log.Error("Error in isWindow")
log.Fatal("Could not find main_window")
return
}
//win.SetDecorated(false)
// Show the Window and all of its components.
win.Show()
@ -79,10 +103,241 @@ func Start(uiGladePath string) {
os.Exit(application.Run(os.Args))
}
func isWindow(obj glib.IObject) (*gtk.Window, error) {
// Make type assertion (as per gtk.go).
if win, ok := obj.(*gtk.Window); ok {
return win, nil
func (ui *UIStatus) addButtonClick() {
log.Debug("Add button is clicked")
win, err := ui.getWindowWithId("main_window")
if err != nil {
return
}
if ui.isFileTab {
chooser, err := gtk.FileChooserNativeDialogNew("Select Files to Send", win, gtk.FILE_CHOOSER_ACTION_OPEN, "Select", "Cancel")
if err != nil {
log.Debug(err)
log.Error("Error while showing file chooser dialog")
return
}
chooser.SetSelectMultiple(true)
// Run and wait until user selects file
ret := chooser.Run()
log.Debug("Chooser returned: ", ret)
// If user clicks "Select"
if gtk.ResponseType(ret) == gtk.RESPONSE_ACCEPT {
filenames, err := chooser.GetFilenames()
if err != nil {
log.Debug(err)
log.Error("Error while getting filenames")
return
}
fileList, err := ui.getListStoreWithId("fileList")
if err != nil {
return
}
treeView, err := ui.getTreeViewWithId("fileListView")
if err != nil {
return
}
addToListStore(fileList, treeView, filenames, ui.fileListOrder, ui.getFileInfo)
}
} else {
// Add contacts
}
}
func (ui *UIStatus) keyPress(_ *gtk.Window, event *gdk.Event) {
log.Debug("KeyPress function called")
eventKey := gdk.EventKeyNewFromEvent(event)
// If pressed key is "Delete" key, remove selected files from the list
if eventKey.KeyVal() == gdk.KEY_Delete {
if err := ui.removeSelected(); err != nil {
log.Debug(err)
log.Error("Error while removing selected")
return
}
}
}
func (ui *UIStatus) removeSelected() (err error) {
listStore, err := ui.getListStoreWithId("fileList")
if err != nil {
return err
}
treeView, err := ui.getTreeViewWithId("fileListView")
if err != nil {
return err
}
selected, err := treeView.GetSelection()
if err != nil {
log.Debug(err)
log.Error("Error while getting selected files")
return err
}
rows := selected.GetSelectedRows(listStore)
// Reverse is called to preserve the head of the linked list for iter.
// Without it, not all nodes will be deleted properly.
reversed := rows.Reverse()
reversed.Foreach(func(item interface{}) {
path, err := isTreePath(item)
if err != nil {
return
}
iter, err := listStore.GetIter(path)
if err != nil {
log.Debug(err)
log.Error("Error while getting iterator")
return
}
value, err := listStore.GetValue(iter, fileFullPath)
if err != nil {
log.Debug(err)
log.Error("Error while getting value")
return
}
fullPath, err := value.GetString()
if err != nil {
log.Debug(err)
log.Error("Error while getting string from *glib.Value")
return
}
log.Debug("Full path: ", fullPath)
// Delete from the map as well
delete(ui.fileMap, fullPath)
_ = listStore.Remove(iter)
})
return nil
}
func addToListStore(listStore *gtk.ListStore, treeView *gtk.TreeView, dataToAdd []string, order []int, f preprocessing) {
for i, data := range dataToAdd {
row, err := f(data)
if err != nil {
log.Debug(err)
log.Error("Error while adding element. continuing")
continue
}
// Row is empty if the elem is already added
if row != nil {
iter := listStore.Append()
// Show file full path as a tooltip
treeView.SetTooltipColumn(fileFullPath)
if err = listStore.Set(iter, order, row); err != nil {
log.Debug("Error while adding ", dataToAdd[i])
continue
}
} else {
log.Debug("Element already added; Skipping...")
}
}
}
func (ui *UIStatus) getFileInfo(fileName string) ([]interface{}, error) {
if _, exist := ui.fileMap[fileName]; exist {
return nil, nil
}
_, fName := filepath.Split(fileName)
s, err := os.Stat(fileName)
ui.fileMap[fileName] = struct{}{}
if err != nil {
log.Debug(err)
log.Error("Error while getting stats")
return nil, err
}
size := s.Size()
return []interface{}{fName, sizeAddUnit(size), "Pending", fileName, size}, nil
}
func sizeAddUnit(size int64) (sizeStr string) {
// Decimal points arent too important, so omit it for UI space
if size < 1e+3 {
sizeStr = strconv.Itoa(int(size)) + " B"
} else if size < 1e+6 {
sizeStr = strconv.Itoa(int(size/1e+3)) + " KB"
} else if size < 1e+9 {
sizeStr = strconv.Itoa(int(size/1e+6)) + " MB"
} else {
sizeStr = strconv.Itoa(int(size/1e+9)) + " MB"
}
return sizeStr
}
func (ui *UIStatus) switchPage() {
log.Debug("Switch page clicked")
ui.isFileTab = !ui.isFileTab
log.Debug(ui.isFileTab)
}
func (ui *UIStatus) getButtonWithId(buttonId string) (button *gtk.Button, err error) {
object, err := ui.builder.GetObject(buttonId)
if err != nil {
log.Debug(err)
log.Errorf("Error while getting button with button id: %s", buttonId)
return nil, err
}
button, ok := object.(*gtk.Button)
if ok {
return button, nil
}
log.Debug(AssertFailed)
log.Error("object is not a button")
return nil, AssertFailed
}
func (ui *UIStatus) getTreeViewWithId(treeViewId string) (treeView *gtk.TreeView, err error) {
object, err := ui.builder.GetObject(treeViewId)
if err != nil {
log.Debug(err)
log.Errorf("Error while getting treeView with treeView id: %s", treeViewId)
return nil, err
}
treeView, ok := object.(*gtk.TreeView)
if ok {
return treeView, nil
}
log.Debug(AssertFailed)
log.Error("object is not a treeView")
return nil, AssertFailed
}
func (ui *UIStatus) getListStoreWithId(listStoreId string) (listStore *gtk.ListStore, err error) {
object, err := ui.builder.GetObject(listStoreId)
if err != nil {
log.Debug(err)
log.Errorf("Error while getting listStore with listStore id: %s", listStoreId)
return nil, err
}
listStore, ok := object.(*gtk.ListStore)
if ok {
return listStore, nil
}
log.Debug(AssertFailed)
log.Error("object is not a listStore")
return nil, AssertFailed
}
func (ui *UIStatus) getWindowWithId(windowId string) (window *gtk.Window, err error) {
object, err := ui.builder.GetObject(windowId)
if err != nil {
log.Debug(err)
log.Errorf("Error while getting window with window id: %s", windowId)
return nil, err
}
window, ok := object.(*gtk.Window)
if ok {
return window, nil
}
log.Debug(AssertFailed)
log.Error("object is not a window")
return nil, AssertFailed
}
func isTreePath(item interface{}) (*gtk.TreePath, error) {
path, ok := item.(*gtk.TreePath)
if ok {
return path, nil
}
log.Debug(AssertFailed)
log.Error("Item is not a TreePath")
return nil, AssertFailed
}

2
pkg/go.mod

@ -1,3 +1,5 @@
module github.com/jaeha-choi/Proj_Coconut_Utility
go 1.16
require gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b

4
pkg/go.sum

@ -0,0 +1,4 @@
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

33
pkg/log/log.go

@ -37,6 +37,13 @@ func Debug(msg ...interface{}) {
}
}
// Debugf logs if LoggingMode is set to DEBUG or lower
func Debugf(format string, msg ...interface{}) {
if mode <= DEBUG {
_ = logger.Output(2, "DEBUG:\t"+fmt.Sprintf(format, msg...))
}
}
// Info logs if LoggingMode is set to INFO or lower
func Info(msg ...interface{}) {
if mode <= INFO {
@ -44,6 +51,13 @@ func Info(msg ...interface{}) {
}
}
// Infof logs if LoggingMode is set to INFO or lower
func Infof(format string, msg ...interface{}) {
if mode <= INFO {
_ = logger.Output(2, "INFO:\t"+fmt.Sprintf(format, msg...))
}
}
// Warning logs if LoggingMode is set to WARNING or lower
func Warning(msg ...interface{}) {
if mode <= WARNING {
@ -51,6 +65,13 @@ func Warning(msg ...interface{}) {
}
}
// Warningf logs if LoggingMode is set to WARNING or lower
func Warningf(format string, msg ...interface{}) {
if mode <= WARNING {
_ = logger.Output(2, "WARNING:\t"+fmt.Sprintf(format, msg...))
}
}
// Error logs if LoggingMode is set to ERROR or lower
func Error(msg ...interface{}) {
if mode <= ERROR {
@ -58,7 +79,19 @@ func Error(msg ...interface{}) {
}
}
// Errorf logs if LoggingMode is set to ERROR or lower
func Errorf(format string, msg ...interface{}) {
if mode <= ERROR {
_ = logger.Output(2, "Error:\t"+fmt.Sprintf(format, msg...))
}
}
// Fatal always logs when used
func Fatal(msg ...interface{}) {
_ = logger.Output(2, "FATAL:\t"+fmt.Sprint(msg...))
}
// Fatalf always logs when used
func Fatalf(format string, msg ...interface{}) {
_ = logger.Output(2, "FATAL:\t"+fmt.Sprintf(format, msg...))
}

16
pkg/log/log_test.go

@ -6,7 +6,7 @@ import (
"testing"
)
func TestInit(t *testing.T) {
func init() {
initTesting(os.Stdout, DEBUG)
}
@ -29,6 +29,20 @@ func TestDebug(t *testing.T) {
}
}
func TestDebugf(t *testing.T) {
var buffer bytes.Buffer
initTesting(&buffer, DEBUG)
Debugf(" %s", "test debug")
if "Test: DEBUG:\t test debug\n" != buffer.String() {
t.Error("Output mismatch")
}
buffer.Reset()
Infof("%s1", "test info")
if "Test: INFO:\ttest info1\n" != buffer.String() {
t.Error("Output mismatch")
}
}
func TestInfo(t *testing.T) {
var buffer bytes.Buffer
initTesting(&buffer, INFO)

33
pkg/util/util.go

@ -4,6 +4,7 @@ import (
"encoding/binary"
"errors"
"github.com/jaeha-choi/Proj_Coconut_Utility/log"
"gopkg.in/yaml.v3"
"io"
"io/ioutil"
"net"
@ -391,3 +392,35 @@ func IntToUint32(n int64) (uint32, error) {
func CheckIPAddress(ip string) bool {
return net.ParseIP(ip) != nil
}
// WriteConfig writes config to fileName in yaml format
func WriteConfig(fileName string, config interface{}) (err error) {
dstFile, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
log.Debug(err)
log.Error("Error while creating file for config")
return err
}
defer func() {
if err := dstFile.Close(); err != nil {
log.Debug(err)
log.Error("Error while closing config file")
return
}
}()
marshal, err := yaml.Marshal(&config)
if err != nil {
log.Debug(err)
log.Error("Error while converting serv struct to []byte")
return err
}
if _, err := dstFile.Write(marshal); err != nil {
log.Debug(err)
log.Error("Error while writing config file")
return err
}
return nil
}

Loading…
Cancel
Save