Skip to content

Commit

Permalink
Added window
Browse files Browse the repository at this point in the history
  • Loading branch information
asticode committed Apr 22, 2017
1 parent 4abdf04 commit 3a5ab0d
Show file tree
Hide file tree
Showing 9 changed files with 292 additions and 54 deletions.
43 changes: 20 additions & 23 deletions astilectron.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const (
// Vars
var (
astilectronDirectoryPath = flag.String("astilectron-directory-path", "", "the astilectron directory path")
boundary = []byte("--++__astilectron_boundary__++--")
validOSes = []string{"darwin", "linux", "windows"}
)

Expand All @@ -36,9 +37,11 @@ type Astilectron struct {
canceller *asticontext.Canceller
channelQuit chan bool
dispatcher *Dispatcher
identifier *identifier
paths *Paths
provisioner Provisioner
reader *reader
writer *writer
}

// Options represents Astilectron options
Expand All @@ -58,6 +61,7 @@ func New(o Options) (a *Astilectron, err error) {
canceller: asticontext.NewCanceller(),
channelQuit: make(chan bool),
dispatcher: newDispatcher(),
identifier: newIdentifier(),
provisioner: DefaultProvisioner,
}

Expand All @@ -72,19 +76,6 @@ func New(o Options) (a *Astilectron, err error) {
err = errors.Wrap(err, "creating new paths failed")
return
}

// Set default listeners
a.On(EventNameElectronLog, func(p interface{}) {
// Parse payload
var m, ok = "", false
if m, ok = p.(string); !ok {
astilog.Errorf("%+v is not a string", p)
return
}

// Log
astilog.Debugf("Electron says: %s", m)
})
return
}

Expand All @@ -102,7 +93,7 @@ func (a *Astilectron) SetProvisioner(p Provisioner) *Astilectron {
return a
}

// On adds a listener for the main *Astilectron (ID = 0) for a specific event
// On implements the Listenable interface
func (a *Astilectron) On(eventName string, l Listener) {
a.dispatcher.addListener(mainTargetID, eventName, l)
}
Expand Down Expand Up @@ -131,8 +122,8 @@ func (a *Astilectron) Start() (err error) {
// provision provisions Astilectron
func (a *Astilectron) provision() error {
astilog.Debug("Provisioning...")
a.dispatcher.Dispatch(Event{Name: EventNameProvisionStart, TargetID: mainTargetID})
defer a.dispatcher.Dispatch(Event{Name: EventNameProvisionStop, TargetID: mainTargetID})
a.dispatcher.Dispatch(Event{Name: EventNameProvision, TargetID: mainTargetID})
defer a.dispatcher.Dispatch(Event{Name: EventNameProvisionDone, TargetID: mainTargetID})
return a.provisioner.Provision(a.paths)
}

Expand All @@ -151,7 +142,7 @@ func (a *Astilectron) execute() (err error) {
err = errors.Wrap(err, "piping stdin failed")
return
}
_ = stdin
a.writer = newWriter(stdin)

// Pipe StdOut
var stdout io.ReadCloser
Expand All @@ -165,11 +156,13 @@ func (a *Astilectron) execute() (err error) {
go a.reader.read()

// Start command
astilog.Debugf("Starting cmd %s", strings.Join(cmd.Args, " "))
if err = cmd.Start(); err != nil {
err = errors.Wrapf(err, "starting cmd %s failed", strings.Join(cmd.Args, " "))
return
}
synchronousFunc(a, EventNameElectronReady, func() {
astilog.Debugf("Starting cmd %s", strings.Join(cmd.Args, " "))
if err = cmd.Start(); err != nil {
err = errors.Wrapf(err, "starting cmd %s failed", strings.Join(cmd.Args, " "))
return
}
})
return
}

Expand All @@ -179,6 +172,7 @@ func (a *Astilectron) Close() {
a.canceller.Cancel()
a.dispatcher.close()
a.reader.close()
a.writer.close()
}

// HandleSignals handles signals
Expand All @@ -196,7 +190,10 @@ func (a *Astilectron) HandleSignals() {
// Stop orders Astilectron to stop
func (a *Astilectron) Stop() {
astilog.Debug("Stopping...")
close(a.channelQuit)
if a.channelQuit != nil {
close(a.channelQuit)
a.channelQuit = nil
}
}

// Wait is a blocking pattern
Expand Down
39 changes: 31 additions & 8 deletions dispatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@ package astilectron
import "sync"

// Listener represents a listener executed when an event is dispatched
type Listener func(payload interface{})
type Listener func(e Event) (deleteListener bool)

// Listenable represents an object that can listen
type Listenable interface {
On(eventName string, l Listener)
}

// Dispatcher represents a dispatcher
type Dispatcher struct {
c chan Event
cq chan bool
l map[int]map[string][]Listener // Indexed by target ID then by event name
l map[string]map[string][]Listener // Indexed by target ID then by event name
m *sync.Mutex
}

Expand All @@ -18,13 +23,13 @@ func newDispatcher() *Dispatcher {
return &Dispatcher{
c: make(chan Event),
cq: make(chan bool),
l: make(map[int]map[string][]Listener),
l: make(map[string]map[string][]Listener),
m: &sync.Mutex{},
}
}

// addListener adds a listener
func (d *Dispatcher) addListener(targetID int, eventName string, l Listener) {
func (d *Dispatcher) addListener(targetID, eventName string, l Listener) {
d.m.Lock()
if _, ok := d.l[targetID]; !ok {
d.l[targetID] = make(map[string][]Listener)
Expand All @@ -35,7 +40,23 @@ func (d *Dispatcher) addListener(targetID int, eventName string, l Listener) {

// close closes the dispatcher properly
func (d *Dispatcher) close() {
close(d.cq)
if d.cq != nil {
close(d.cq)
d.cq = nil
}
}

// delListener delete a specific listener
func (d *Dispatcher) delListener(targetID, eventName string, index int) {
d.m.Lock()
defer d.m.Unlock()
if _, ok := d.l[targetID]; !ok {
return
}
if _, ok := d.l[targetID][eventName]; !ok {
return
}
d.l[targetID][eventName] = append(d.l[targetID][eventName][:index], d.l[targetID][eventName][index+1:]...)
}

// Dispatch dispatches an event
Expand All @@ -48,8 +69,10 @@ func (d *Dispatcher) start() {
for {
select {
case e := <-d.c:
for _, l := range d.listeners(e.TargetID, e.Name) {
l(e.Payload)
for i, l := range d.listeners(e.TargetID, e.Name) {
if deleteListener := l(e); deleteListener {
d.delListener(e.TargetID, e.Name, i)
}
}
case <-d.cq:
return
Expand All @@ -58,7 +81,7 @@ func (d *Dispatcher) start() {
}

// listeners returns the listeners for a target ID and an event name
func (d *Dispatcher) listeners(targetID int, eventName string) []Listener {
func (d *Dispatcher) listeners(targetID, eventName string) []Listener {
d.m.Lock()
defer d.m.Unlock()
if _, ok := d.l[targetID]; !ok {
Expand Down
29 changes: 20 additions & 9 deletions event.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,31 @@ package astilectron

// Event names
const (
EventNameElectronLog = "electron.log"
EventNameElectronStop = "electron.stop"
EventNameProvisionStart = "provision.start"
EventNameProvisionStop = "provision.stop"
EventNameElectronReady = "electron.ready"
EventNameElectronStopped = "electron.stopped"
EventNameProvision = "provision"
EventNameProvisionDone = "provision.done"
EventNameWindowCreate = "window.create"
EventNameWindowCreateDone = "window.create.done"
EventNameWindowReadyToShow = "window.ready.to.show"
EventNameWindowShow = "window.show"
EventNameWindowShowDone = "window.show.done"
)

// Other constants
const (
mainTargetID = 0
mainTargetID = "main"
)

// Event represents a go-astilectron event
// Event represents an event
type Event struct {
Name string
Payload interface{}
TargetID int
// This is the base of the event
Name string `json:"name"`
TargetID string `json:"targetID"`

// This is a list of all possible payloads.
// A choice was made not to use interfaces since it's a pain in the ass asserting each an every payload afterwards
// We use pointers so that omitempty works
Message string `json:"message,omitempty"`
WindowOptions *WindowOptions `json:"windowOptions,omitempty"`
}
17 changes: 16 additions & 1 deletion examples/basic_window/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,28 @@ func main() {
}
defer a.Close()
a.HandleSignals()
a.On(astilectron.EventNameElectronStop, func(p interface{}) { a.Stop() })
a.On(astilectron.EventNameElectronStopped, func(e astilectron.Event) (deleteListener bool) {
a.Stop()
return
})

// Start
if err = a.Start(); err != nil {
astilog.Fatal(errors.Wrap(err, "starting failed"))
}

// Create window
var w *astilectron.Window
if w, err = a.NewWindow(&astilectron.WindowOptions{
Center: astilectron.PtrBool(true),
Show: astilectron.PtrBool(false),
Height: astilectron.PtrInt(600),
Width: astilectron.PtrInt(600),
}); err != nil {
astilog.Fatal(errors.Wrap(err, "creating new window failed"))
}
w.Show()

// Blocking pattern
a.Wait()
}
46 changes: 45 additions & 1 deletion helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"os"
"path/filepath"

astilog "github.com/asticode/go-astilog"
"github.com/asticode/go-astilog"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -131,3 +131,47 @@ func Unzip(dst, src string) (err error) {
}
return
}

// PtrBool transforms a bool into a *bool
func PtrBool(i bool) *bool {
return &i
}

// PtrInt transforms an int into an *int
func PtrInt(i int) *int {
return &i
}

// PtrStr transforms a string into a *string
func PtrStr(i string) *string {
return &i
}

// synchronousFunc executes a function and blocks until it has received a specific event
func synchronousFunc(l Listenable, eventNameDone string, fn func()) {
var c = make(chan bool)
defer func() {
if c != nil {
close(c)
}
}()
l.On(eventNameDone, func(e Event) (deleteListener bool) {
close(c)
c = nil
return true
})
fn()
<-c
}

// synchronousEvent sends an event and blocks until it has received a specific event
func synchronousEvent(l Listenable, w *writer, e Event, eventNameDone string) (err error) {
synchronousFunc(l, eventNameDone, func() {
if err = w.write(e); err != nil {
err = errors.Wrapf(err, "writing %+v event failed", e)
return
}
return
})
return
}
25 changes: 25 additions & 0 deletions identifier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package astilectron

import (
"strconv"
"sync"
)

// identifier is in charge of delivering a unique identifier
type identifier struct {
i int
m *sync.Mutex
}

// newIdentifier creates a new identifier
func newIdentifier() *identifier {
return &identifier{m: &sync.Mutex{}}
}

// new returns a new unique identifier
func (i *identifier) new() string {
i.m.Lock()
defer i.m.Unlock()
i.i++
return strconv.Itoa(i.i)
}
Loading

0 comments on commit 3a5ab0d

Please sign in to comment.