diff --git a/dfssd/gui/application.qrc b/dfssd/gui/application.qrc
index 65c5cfcd87581ab614c456eab60d777c2a797f3e..d51b0b6b2e107929e33a5c00953e4d60e0223745 100644
--- a/dfssd/gui/application.qrc
+++ b/dfssd/gui/application.qrc
@@ -1,5 +1,13 @@
widget.ui
+ images/server_key.png
+ images/server_connect.png
+ images/node_magnifier.png
+ images/control_play.png
+ images/control_play_blue.png
+ images/control_pause.png
+ images/control_pause_blue.png
+ images/control_rewind_blue.png
diff --git a/dfssd/gui/colors.go b/dfssd/gui/colors.go
new file mode 100644
index 0000000000000000000000000000000000000000..384c1e9ee4cc3fb6bd91a048d3ecc5a87caac5da
--- /dev/null
+++ b/dfssd/gui/colors.go
@@ -0,0 +1,18 @@
+package gui
+
+// This file stores useful colors
+
+import "github.com/visualfc/goqt/ui"
+
+var colors = map[string]uint32{
+ "red": 0x00ff0000,
+ "green": 0x0000aa00,
+ "blue": 0x000000ff,
+ "black": 0x00000000,
+}
+
+var pen_black = ui.NewPenWithColor(ui.NewColorWithGlobalcolor(ui.Qt_black))
+var pen_gray = ui.NewPenWithColor(ui.NewColorWithGlobalcolor(ui.Qt_gray))
+
+var brush_none = ui.NewBrushWithGlobalcolorBrushstyle(ui.Qt_transparent, ui.Qt_SolidPattern)
+var brush_black = ui.NewBrushWithGlobalcolorBrushstyle(ui.Qt_black, ui.Qt_SolidPattern)
diff --git a/dfssd/gui/events.go b/dfssd/gui/events.go
new file mode 100644
index 0000000000000000000000000000000000000000..e03d81d7888c705b7b09afac98acb8dddef922c2
--- /dev/null
+++ b/dfssd/gui/events.go
@@ -0,0 +1,153 @@
+package gui
+
+// This file handles event timers and imports.
+
+import (
+ "fmt"
+ "math"
+ "time"
+
+ "dfss/dfssd/api"
+ "github.com/visualfc/goqt/ui"
+)
+
+// TEMPORARY
+const quantum = 100 // discretization argument for events (ns)
+const speed = 1000 // duration of a quantum (ms)
+
+// AddEvent interprets an incoming event into a graphic one.
+// Expected format:
+//
+// Timestamp: unix nano timestamp
+// Identifier: either "platform", "ttp" or ""
+// Log: one of the following
+// "sent promise to "
+// "sent signature to "
+//
+// Other messages are currently ignored.
+func (w *Window) AddEvent(e *api.Log) {
+ event := Event{
+ Sender: w.scene.identifierToIndex(e.Identifier),
+ Date: time.Unix(0, e.Timestamp),
+ }
+
+ w.Log(fmt.Sprint(e.Identifier, " ", e.Log))
+
+ var receiver string
+ if n, _ := fmt.Sscanf(e.Log, "sent promise to %s", &receiver); n > 0 {
+ event.Type = PROMISE
+ event.Receiver = w.scene.identifierToIndex(receiver)
+ } else if n, _ := fmt.Sscanf(e.Log, "sent signature to %s", &receiver); n > 0 {
+ event.Type = SIGNATURE
+ event.Receiver = w.scene.identifierToIndex(receiver)
+ }
+
+ if receiver != "" {
+ w.scene.Events = append(w.scene.Events, event)
+ }
+}
+
+// DrawEvent triggers the appropriate draw action for a spectific event.
+func (w *Window) DrawEvent(e *Event) {
+ xa, ya := w.GetClientPosition(e.Sender)
+ xb, yb := w.GetClientPosition(e.Receiver)
+
+ var color string
+ switch e.Type {
+ case PROMISE:
+ color = "blue"
+ case SIGNATURE:
+ color = "green"
+ default:
+ color = "black"
+ }
+
+ w.DrawArrow(xa, ya, xb, yb, colors[color])
+}
+
+// PrintQuantumInformation triggers the update of the "x / y" quantum information.
+func (w *Window) PrintQuantumInformation() {
+ if len(w.scene.Events) == 0 {
+ w.progress.SetText("No event")
+ return
+ }
+
+ beginning := w.scene.Events[0].Date.UnixNano()
+ totalDuration := w.scene.Events[len(w.scene.Events)-1].Date.UnixNano() - beginning
+ nbQuantum := math.Max(1, math.Ceil(float64(totalDuration)/quantum))
+ durationFromBeginning := w.scene.currentTime.UnixNano() - beginning
+ currentQuantum := math.Ceil(float64(durationFromBeginning)/quantum) + 1
+
+ if w.scene.currentEvent == 0 {
+ currentQuantum = 0
+ }
+ w.progress.SetText(fmt.Sprint(currentQuantum, " / ", nbQuantum))
+}
+
+// initTimer is called during window initialization. It initializes the timeout signal called for each refresh.
+func (w *Window) initTimer() {
+ w.timer = ui.NewTimerWithParent(w)
+
+ lastNbOfClients := len(w.scene.Clients)
+
+ w.timer.OnTimeout(func() {
+ nbEvents := len(w.scene.Events)
+ if w.scene.currentEvent >= nbEvents {
+ w.replayButton.Click()
+ return
+ }
+
+ // Remove arrows from last tick
+ w.RemoveArrows()
+
+ // Check that we have a least one event to read
+ if nbEvents == 0 {
+ return
+ }
+
+ // Check if need to redraw everything
+ if lastNbOfClients != len(w.scene.Clients) {
+ w.initScene()
+ }
+
+ // Init first time
+ if w.scene.currentEvent == 0 {
+ w.scene.currentTime = w.scene.Events[0].Date
+ }
+
+ endOfQuantum := w.scene.currentTime.Add(quantum * time.Nanosecond)
+
+ for i := w.scene.currentEvent; i < nbEvents; i++ {
+ e := w.scene.Events[i]
+
+ if e.Date.After(endOfQuantum) || e.Date.Equal(endOfQuantum) {
+ break
+ }
+
+ w.DrawEvent(&e)
+ w.scene.currentEvent++
+ }
+
+ w.PrintQuantumInformation()
+ w.scene.currentTime = endOfQuantum
+ })
+}
+
+// identifierToIndex is used to retrieve a client index from its name, inserting a new client if needed.
+func (s *Scene) identifierToIndex(identifier string) int {
+ if identifier == "platform" {
+ return -1
+ }
+ if identifier == "ttp" {
+ return -2
+ }
+
+ for i, c := range s.Clients {
+ if c.Name == identifier {
+ return i
+ }
+ }
+
+ s.Clients = append(s.Clients, Client{Name: identifier})
+ return len(s.Clients) - 1
+}
diff --git a/dfssd/gui/graphics.go b/dfssd/gui/graphics.go
new file mode 100644
index 0000000000000000000000000000000000000000..d83d8bd91bf9ce77a0ccbc1179ce118ec95ff3d2
--- /dev/null
+++ b/dfssd/gui/graphics.go
@@ -0,0 +1,115 @@
+package gui
+
+// This file handles complex graphic primitives for the demonstrator.
+
+import (
+ "math"
+
+ "github.com/visualfc/goqt/ui"
+)
+
+// These two constants are used to configure arrows
+const ARROW_T = math.Pi / 6 // angle
+const ARROW_L = 15 // side length
+
+// DrawClients draws the different clients in a circle.
+func (w *Window) DrawClients() {
+ scene := w.graphics.Scene()
+ for i, c := range w.scene.Clients {
+ x, y := w.GetClientPosition(i)
+
+ // Add ellipse
+ scene.AddEllipseFWithXYWidthHeightPenBrush(x-10, y-10, 20, 20, pen_black, brush_black)
+
+ // Add text
+ t := scene.AddSimpleText(c.Name)
+ r := t.BoundingRect()
+ t.SetX(x - r.Width()/2)
+ t.SetY(y + 10)
+ }
+}
+
+// GetClientPosition translates a client index into its cartesian coordinates.
+func (w *Window) GetClientPosition(i int) (x, y float64) {
+ if i < 0 {
+ return w.GetServerPosition(i == -1)
+ }
+
+ nbClients := float64(len(w.scene.Clients))
+ angle := 2 * math.Pi * float64(i) / nbClients
+ return math.Cos(angle) * (w.circleSize / 2), math.Sin(angle) * (w.circleSize / 2)
+}
+
+// GetServerPosition translates a server into its cartesian coordinates.
+func (w *Window) GetServerPosition(platform bool) (x, y float64) {
+ x = w.circleSize/2 + 150
+ y = 0
+ if !platform {
+ x *= -1
+ }
+ return
+}
+
+// DrawServers draws the DFSS main servers (ttp and platform)
+func (w *Window) DrawServers() {
+ scene := w.graphics.Scene()
+
+ ttp := scene.AddPixmap(w.pixmaps["ttp"])
+ x, y := w.GetServerPosition(false)
+ ttp.SetPosFWithXY(x-32, y-16) // we are shifting here a bit for better arrow display
+ ttp.SetToolTip("TTP")
+
+ platform := scene.AddPixmap(w.pixmaps["platform"])
+ x, y = w.GetServerPosition(true)
+ platform.SetPosFWithXY(x, y-16)
+ platform.SetToolTip("Platform")
+}
+
+// DrawArrow is the graphic primitive for drawing an arrow between A and B points
+func (w *Window) DrawArrow(xa, ya, xb, yb float64, rgb uint32) {
+ scene := w.graphics.Scene()
+
+ path := ui.NewPainterPath()
+ path.MoveToFWithXY(xa, ya)
+ path.LineToFWithXY(xb, yb)
+
+ v := ui.NewVector2DWithXposYpos(xa-xb, ya-yb)
+ l := v.Length()
+
+ // from http://math.stackexchange.com/a/1314050
+ xc := xb + ARROW_L/l*(v.X()*math.Cos(ARROW_T)+v.Y()*math.Sin(ARROW_T))
+ yc := yb + ARROW_L/l*(v.Y()*math.Cos(ARROW_T)-v.X()*math.Sin(ARROW_T))
+ xd := xb + ARROW_L/l*(v.X()*math.Cos(ARROW_T)-v.Y()*math.Sin(ARROW_T))
+ yd := yb + ARROW_L/l*(v.Y()*math.Cos(ARROW_T)+v.X()*math.Sin(ARROW_T))
+
+ path.LineToFWithXY(xc, yc)
+ path.LineToFWithXY(xd, yd)
+ path.LineToFWithXY(xb, yb)
+ path.SetFillRule(ui.Qt_WindingFill)
+
+ color := ui.NewColorWithRgb(rgb)
+ color.SetAlpha(200)
+
+ pen := ui.NewPenWithColor(color)
+ pen.SetWidth(3)
+ pen.SetJoinStyle(ui.Qt_RoundJoin)
+
+ brush := ui.NewBrush()
+ brush.SetColor(color)
+ brush.SetStyle(ui.Qt_SolidPattern)
+
+ arrow := scene.AddPathWithPathPenBrush(path, pen, brush)
+ w.currentArrows = append(w.currentArrows, arrow)
+}
+
+// RemoveArrows remove every arrow present in the graphic area, and delete them for better memory management.
+func (w *Window) RemoveArrows() {
+ scene := w.graphics.Scene()
+
+ for _, arrow := range w.currentArrows {
+ scene.RemoveItem(&arrow.QGraphicsItem)
+ defer arrow.Delete()
+ }
+
+ w.currentArrows = nil
+}
diff --git a/dfssd/gui/images/control_pause.png b/dfssd/gui/images/control_pause.png
new file mode 100644
index 0000000000000000000000000000000000000000..186f361f08b9d67858da54d9decd084f25072f2e
Binary files /dev/null and b/dfssd/gui/images/control_pause.png differ
diff --git a/dfssd/gui/images/control_pause_blue.png b/dfssd/gui/images/control_pause_blue.png
new file mode 100644
index 0000000000000000000000000000000000000000..3ab8b69db2782806559e5ba9cb057bdf899ea869
Binary files /dev/null and b/dfssd/gui/images/control_pause_blue.png differ
diff --git a/dfssd/gui/images/control_play.png b/dfssd/gui/images/control_play.png
new file mode 100644
index 0000000000000000000000000000000000000000..3b64790b971704537cdf56306d98c15f0f7d1c16
Binary files /dev/null and b/dfssd/gui/images/control_play.png differ
diff --git a/dfssd/gui/images/control_play_blue.png b/dfssd/gui/images/control_play_blue.png
new file mode 100644
index 0000000000000000000000000000000000000000..a1f7345f3713a730b613faf82026caaa0adb375c
Binary files /dev/null and b/dfssd/gui/images/control_play_blue.png differ
diff --git a/dfssd/gui/images/control_rewind_blue.png b/dfssd/gui/images/control_rewind_blue.png
new file mode 100644
index 0000000000000000000000000000000000000000..de9fc07b247950c8cb283a10fae0316d2954f35b
Binary files /dev/null and b/dfssd/gui/images/control_rewind_blue.png differ
diff --git a/dfssd/gui/images/node_magnifier.png b/dfssd/gui/images/node_magnifier.png
new file mode 100644
index 0000000000000000000000000000000000000000..b19d01b580acfa7344e6e94c937f0c0b96f20186
Binary files /dev/null and b/dfssd/gui/images/node_magnifier.png differ
diff --git a/dfssd/gui/images/server_connect.png b/dfssd/gui/images/server_connect.png
new file mode 100644
index 0000000000000000000000000000000000000000..faca1bc1c184be44a70bf00431066fb0400375f7
Binary files /dev/null and b/dfssd/gui/images/server_connect.png differ
diff --git a/dfssd/gui/images/server_key.png b/dfssd/gui/images/server_key.png
new file mode 100644
index 0000000000000000000000000000000000000000..a4ae3f38830844ac864a31b2eb6eb53cd5752a12
Binary files /dev/null and b/dfssd/gui/images/server_key.png differ
diff --git a/dfssd/gui/save.go b/dfssd/gui/save.go
new file mode 100644
index 0000000000000000000000000000000000000000..d230c4971f797388eb5f4805a982eccfef7198a2
--- /dev/null
+++ b/dfssd/gui/save.go
@@ -0,0 +1,43 @@
+package gui
+
+// This file handles open/save feature.
+
+import (
+ "encoding/json"
+ "io/ioutil"
+ "strconv"
+)
+
+func (w *Window) Save(filename string) {
+ data, err := json.Marshal(w.scene)
+ if err != nil {
+ w.StatusBar().ShowMessage(err.Error())
+ return
+ }
+
+ err = ioutil.WriteFile(filename, data, 0600)
+ if err != nil {
+ w.StatusBar().ShowMessage(err.Error())
+ return
+ }
+ w.StatusBar().ShowMessage("Saved file as " + filename)
+}
+
+func (w *Window) Open(filename string) {
+ data, err := ioutil.ReadFile(filename)
+ if err != nil {
+ w.StatusBar().ShowMessage(err.Error())
+ return
+ }
+
+ newScene := &Scene{}
+ err = json.Unmarshal(data, newScene)
+ if err != nil {
+ w.StatusBar().ShowMessage(err.Error())
+ return
+ }
+
+ w.scene = newScene
+ w.StatusBar().ShowMessage("Imported file from " + filename + " (" + strconv.Itoa(len(w.scene.Events)) + " events)")
+ w.initScene()
+}
diff --git a/dfssd/gui/structures.go b/dfssd/gui/structures.go
new file mode 100644
index 0000000000000000000000000000000000000000..209fd856356eda31cc8c219b3e772fbce1e2acdd
--- /dev/null
+++ b/dfssd/gui/structures.go
@@ -0,0 +1,60 @@
+package gui
+
+// This file stores strucutures used in GUI for fast documentation.
+
+import (
+ "time"
+
+ "github.com/visualfc/goqt/ui"
+)
+
+// Window contains all information used to make the demonstrator works.
+// It extends QMainWindow and cache several graphic informations.
+// Do not attempt to instantiante it directly, use `NewWindow` function instead.
+type Window struct {
+ *ui.QMainWindow
+
+ logField *ui.QTextEdit
+ graphics *ui.QGraphicsView
+ progress *ui.QLabel
+ playButton *ui.QPushButton
+ stopButton *ui.QPushButton
+ replayButton *ui.QPushButton
+ scene *Scene
+ circleSize float64
+ pixmaps map[string]*ui.QPixmap
+
+ currentArrows []*ui.QGraphicsPathItem
+ timer *ui.QTimer
+}
+
+// Client represents a DFSSC instance
+type Client struct {
+ Name string
+}
+
+// EventType is used as an enum for event types, to differenciate promises, signatures...
+type EventType int
+
+const (
+ PROMISE EventType = iota
+ SIGNATURE
+ OTHER
+)
+
+// Event represents a single signature event
+type Event struct {
+ Type EventType
+ Sender int
+ Receiver int
+ Date time.Time
+}
+
+// Scene holds the global scene for registered clients and signature events
+type Scene struct {
+ Clients []Client
+ Events []Event
+
+ currentTime time.Time
+ currentEvent int
+}
diff --git a/dfssd/gui/widget.ui b/dfssd/gui/widget.ui
index 207beb568fed08a8a802062dd6ca8d661e5b5d13..7e1c26393ee66374ccfed1b814926ecc38f85ba6 100644
--- a/dfssd/gui/widget.ui
+++ b/dfssd/gui/widget.ui
@@ -1,7 +1,7 @@
- CalculatorForm
-
+ Demonstrator
+
true
@@ -39,6 +39,15 @@
300
+
+
+
+ 255
+ 255
+ 255
+
+
+
-
@@ -57,10 +66,32 @@
0
-
- Play
+
+
+ 40
+ 40
+
+
+
+ Qt::NoFocus
+
+
+ true
+
+
+
+ -
+
+
+
+ 40
+ 40
+
-
+
+ Qt::NoFocus
+
+
true
@@ -73,8 +104,17 @@
0
-
- Replay
+
+
+ 40
+ 40
+
+
+
+ Qt::NoFocus
+
+
+ true
@@ -99,6 +139,9 @@
0
+
+ Qt::TabFocus
+
us
@@ -132,11 +175,14 @@
-
-
+
0
0
+
+ Qt::TabFocus
+
Qt::Horizontal
@@ -148,6 +194,22 @@
+ -
+
+
+
+ 80
+ 0
+
+
+
+
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
-
diff --git a/dfssd/gui/window.go b/dfssd/gui/window.go
index a4aa9aef09f945dad9f18e5102442c1b07e91574..8ea71a917f63484e277b2d6739c14d4b7a33037b 100644
--- a/dfssd/gui/window.go
+++ b/dfssd/gui/window.go
@@ -1,16 +1,18 @@
+// Package gui is the graphic part of the dfssd program.
package gui
+// This file is the entry point of the gui package.
+// It handles window instantiation and basic operations on it.
+
import (
+ "math"
+ "time"
+
"dfss"
"github.com/visualfc/goqt/ui"
)
-type Window struct {
- *ui.QMainWindow
-
- logField *ui.QTextEdit
-}
-
+// NewWindow creates and initialiaze a new dfssd main window.
func NewWindow() *Window {
file := ui.NewFileWithName(":/widget.ui")
loader := ui.NewUiLoader()
@@ -23,32 +25,138 @@ func NewWindow() *Window {
w := &Window{
QMainWindow: window,
+ scene: &Scene{},
}
+ w.InstallEventFilter(w)
// Load dynamic elements from driver
w.logField = ui.NewTextEditFromDriver(widget.FindChild("logField"))
+ w.graphics = ui.NewGraphicsViewFromDriver(widget.FindChild("graphicsView"))
+ w.progress = ui.NewLabelFromDriver(widget.FindChild("progressLabel"))
+
+ w.playButton = ui.NewPushButtonFromDriver(widget.FindChild("playButton"))
+ w.stopButton = ui.NewPushButtonFromDriver(widget.FindChild("stopButton"))
+ w.replayButton = ui.NewPushButtonFromDriver(widget.FindChild("replayButton"))
+
+ // Load pixmaps
+ w.pixmaps = map[string]*ui.QPixmap{
+ "ttp": ui.NewPixmapWithFilenameFormatFlags(":/images/server_key.png", "", ui.Qt_AutoColor),
+ "platform": ui.NewPixmapWithFilenameFormatFlags(":/images/server_connect.png", "", ui.Qt_AutoColor),
+ }
+
+ // Load icons
+ w.addIcons()
// Add actions
w.addActions()
+ w.initScene()
+ w.initTimer()
w.StatusBar().ShowMessage("Ready")
+ w.PrintQuantumInformation()
return w
}
+// OnResizeEvent is called by Qt each time an user tries to resize the window.
+// We have to redraw the whole scene to adapt.
+func (w *Window) OnResizeEvent(ev *ui.QResizeEvent) bool {
+ w.initScene()
+ return true
+}
+
+// Log is used to print a new line in the log area of the window.
+// It should be thread-safe.
func (w *Window) Log(str string) {
+ str = time.Now().Format("[15:04:05.000] ") + str
w.logField.Append(str)
w.logField.EnsureCursorVisible()
}
+// addIcons adds icons to control buttons, since we cannot add them directly in QtCreator.
+func (w *Window) addIcons() {
+ w.SetWindowIcon(ui.NewIconWithFilename(":/images/node_magnifier.png"))
+
+ var i *ui.QIcon
+ i = ui.NewIconWithFilename(":/images/control_play_blue.png")
+ i.AddFileWithFilenameSizeModeState(":/images/control_play.png", ui.NewSizeWithWidthHeight(32, 32), ui.QIcon_Disabled, ui.QIcon_Off)
+ w.playButton.SetIcon(i)
+
+ i = ui.NewIconWithFilename(":/images/control_pause_blue.png")
+ i.AddFileWithFilenameSizeModeState(":/images/control_pause.png", ui.NewSizeWithWidthHeight(32, 32), ui.QIcon_Disabled, ui.QIcon_Off)
+ w.stopButton.SetIcon(i)
+
+ i = ui.NewIconWithFilename(":/images/control_rewind_blue.png")
+ w.replayButton.SetIcon(i)
+}
+
+// addActions adds action listenners to interactive parts of the window.
func (w *Window) addActions() {
+ // MENU BAR
openAct := ui.NewActionWithTextParent("&Open", w)
openAct.SetShortcuts(ui.QKeySequence_Open)
openAct.SetStatusTip("Open a demonstration file")
+ openAct.OnTriggered(func() {
+ filename := ui.QFileDialogGetOpenFileName()
+ if filename != "" {
+ w.Open(filename)
+ }
+ })
saveAct := ui.NewActionWithTextParent("&Save", w)
saveAct.SetShortcuts(ui.QKeySequence_Save)
saveAct.SetStatusTip("Save a demonstration file")
+ saveAct.OnTriggered(func() {
+ filename := ui.QFileDialogGetSaveFileName()
+ if filename != "" {
+ w.Save(filename)
+ }
+ })
w.MenuBar().AddAction(openAct)
w.MenuBar().AddAction(saveAct)
+
+ // SIMULATION CONTROL
+ w.playButton.OnClicked(func() {
+ w.playButton.SetDisabled(true)
+ w.stopButton.SetDisabled(false)
+ w.timer.StartWithMsec(speed)
+ })
+
+ w.stopButton.OnClicked(func() {
+ w.playButton.SetDisabled(false)
+ w.stopButton.SetDisabled(true)
+ w.timer.Stop()
+ })
+ w.stopButton.SetDisabled(true)
+
+ w.replayButton.OnClicked(func() {
+ w.RemoveArrows()
+ w.scene.currentEvent = 0
+ w.PrintQuantumInformation()
+ })
+}
+
+// initScene creates the Qt graphic scene associated to our custom scene.
+// It draws the base circle, clients and servers, and do some memory management for us.
+func (w *Window) initScene() {
+ // Save old scene
+ oldScene := w.graphics.Scene()
+
+ scene := ui.NewGraphicsScene()
+ w.graphics.SetScene(scene)
+
+ // Draw base circle
+ w.circleSize = math.Min(float64(w.graphics.Width()), float64(w.graphics.Height())) - 50
+ r := w.circleSize / 2
+ scene.AddEllipseFWithXYWidthHeightPenBrush(-r, -r, w.circleSize, w.circleSize, pen_gray, brush_none)
+
+ // Draw clients
+ w.DrawClients()
+ w.DrawServers()
+
+ // Purge
+ if oldScene != nil {
+ w.RemoveArrows()
+ defer oldScene.Delete()
+ }
}
diff --git a/dfssd/main.go b/dfssd/main.go
index 6be4fd8864356e8922d66042b64f76a018a189d6..fc2ede4eddb35074f830002ac2ab6ea9d78a39c9 100644
--- a/dfssd/main.go
+++ b/dfssd/main.go
@@ -8,8 +8,9 @@ import (
"strconv"
"dfss"
- "dfss/dfssd/server"
+ "dfss/dfssd/api"
"dfss/dfssd/gui"
+ "dfss/dfssd/server"
"github.com/visualfc/goqt/ui"
)
@@ -51,10 +52,10 @@ func main() {
case "version":
fmt.Println("v"+dfss.Version, runtime.GOOS, runtime.GOARCH)
case "nogui":
- lfn := func(str string) {
- fmt.Println(str)
+ fn := func(v *api.Log) {
+ fmt.Printf("[%d] %s: %s\n", v.Timestamp, v.Identifier, v.Log)
}
- err := server.Listen("0.0.0.0:" + strconv.Itoa(port), lfn)
+ err := server.Listen("0.0.0.0:"+strconv.Itoa(port), fn)
if err != nil {
os.Exit(1)
}
@@ -62,7 +63,7 @@ func main() {
ui.Run(func() {
window := gui.NewWindow()
go func() {
- err := server.Listen("0.0.0.0:" + strconv.Itoa(port), window.Log)
+ err := server.Listen("0.0.0.0:"+strconv.Itoa(port), window.AddEvent)
if err != nil {
window.Log("!! " + err.Error())
}
diff --git a/dfssd/server/server.go b/dfssd/server/server.go
index cf0a4841de5c62bb2ae692fc1ea2996986eaf6c1..02f2bdcef0970b566d00bfa61e65ce37378eece7 100644
--- a/dfssd/server/server.go
+++ b/dfssd/server/server.go
@@ -20,17 +20,16 @@ func (s *Server) SendLog(ctx context.Context, in *api.Log) (*api.Ack, error) {
}
// Listen with gRPG service
-func Listen(addrPort string, lfn func(string)) error {
+func Listen(addrPort string, fn func(*api.Log)) error {
// open tcp socket
lis, err := net.Listen("tcp", addrPort)
if err != nil {
grpclog.Fatalf("Failed to open tcp socket: %v", err)
return err
}
- lfn("Server listening on " + addrPort)
// log display manager
- go displayHandler(lfn)
+ go displayHandler(fn)
// bootstrap gRPC service !
grpcServer := grpc.NewServer()
diff --git a/dfssd/server/storage.go b/dfssd/server/storage.go
index b2e4e0c5da45ee901a89eb44ebfd35124ce93f69..d11211fbb3b3499f5211b777e82c009f2595230b 100644
--- a/dfssd/server/storage.go
+++ b/dfssd/server/storage.go
@@ -1,7 +1,6 @@
package server
import (
- "fmt"
"sort"
"sync"
"time"
@@ -23,7 +22,7 @@ func addMessage(msg *api.Log) {
}
// display logs that are more than since (ms) old
-func display(since int64, lfn func(string)) {
+func display(since int64, fn func(*api.Log)) {
var out []*api.Log // sorted messages to display
var recycled []*api.Log // messages too recent to be displayed
@@ -45,15 +44,16 @@ func display(since int64, lfn func(string)) {
sort.Sort(ByTimestamp(out))
for _, v := range out {
- lfn(fmt.Sprintf("[%d] %s:: %s", v.Timestamp, v.Identifier, v.Log))
+ //lfn()
+ fn(v)
}
}
// refresh every second
-func displayHandler(lfn func(string)) {
+func displayHandler(fn func(*api.Log)) {
ticker := time.NewTicker(time.Second)
for range ticker.C {
- display(1000, lfn)
+ display(1000, fn)
}
}