astilectron

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 25, 2017 License: MIT Imports: 29 Imported by: 0

README

Thanks to go-astilectron build cross platform GUI apps with GO and Electron (HTML/JS/CSS). It is the official GO bindings of astilectron and is powered by Electron.

Quick start

WARNING: the code below doesn't handle errors for readibility purposes. However you SHOULD!

Import go-astilectron

To import go-astilectron run:

$ go get -u github.com/asticode/go-astilectron
Start go-astilectron
// Initialize astilectron
var a, _ = astilectron.New(astilectron.Options{BaseDirectoryPath: "<where you want the provisioner to install the dependencies>"})
defer a.Close()

// Start astilectron
a.Start()

For everything to work properly we need to fetch 2 dependencies : astilectron and Electron. .Start() takes care of it by downloading the sources and setting them up properly.

In case you want to embed the sources in the binary to keep a unique binary you can implement your own Provisioner and attach it to go-astilectron with .SetProvisioner(p Provisioner). Your custom Provisioner would look something like :

// myProvisioner represents your custom provisioner
type myProvisioner struct {}

// Provision implements the Provisioner interface
func (p myProvisioner) Provision(ctx context.Context, p Paths) error {
	// TODO Extract the .zip files embeded in GO. It will depend on the solution you choose to embed data in GO.
	
	// Call the default provisioner to finish the work
	return astilectron.DefaultProvisioner.Provision(ctx, p)
}

If no BaseDirectoryPath is provided, it defaults to the user's home directory path.

The majority of methods are synchrone which means that when executing them go-astilectron will block until it receives a specific Electron event or until the overall context is cancelled. This is the case of .Start() which will block until it receives the app.event.ready astilectron event or until the overall context is cancelled.

Create a window
// Create a new window
var w, _ = a.NewWindow("http://127.0.0.1:4000", &astilectron.WindowOptions{
    Center: astilectron.PtrBool(true),
    Height: astilectron.PtrInt(600),
    Width:  astilectron.PtrInt(600),
})
w.Create()

When creating a window you need to indicate a URL as well as options that fit Electron's window options.

This is pretty straightforward except the astilectron.Ptr* methods so let me explain: GO doesn't do optional fields when json encoding unless you use pointers whereas Electron does handle optional fields. Therefore I added helper methods to convert int, bool and string into pointers and used pointers in structs sent to Electron.

Add listeners
// Add a listener on Astilectron
a.On(astilectron.EventNameAppStop, func(e astilectron.Event) (deleteListener bool) {
    a.Stop()
    return
})

// Add a listener on the window
w.On(astilectron.EventNameWindowEventResize, func(e astilectron.Event) (deleteListener bool) {
    astilog.Info("Window resized")
    return
})

Nothing much to say here either except that you can add listeners to Astilectron as well.

Play with the window
// Play with the window
w.Resize(200, 200)
time.Sleep(time.Second)
w.Maximize()

Check out the Window doc for a list of all exported methods

Send messages between GO and your webserver

In your webserver add the following javascript to any of the pages you want to interact with:

<script>
    // This will wait for the astilectron namespace to be ready
    document.addEventListener('astilectron-ready', function() {
    
        // This will listen to messages sent by GO
        astilectron.listen(function(message) {
                            
            // This will send a message back to GO
            astilectron.send("I'm good bro")
        });
    })
</script>

In your GO app add the following:

// Listen to messages sent by webserver
w.On(astilectron.EventNameWindowEventMessage, func(e astilectron.Event) (deleteListener bool) {
    var m string
    e.Message.Unmarshal(&m)
    astilog.Infof("Received message %s", m)
    return
})

// Send message to webserver
w.Send("What's up?")

And that's it!

NOTE: needless to say that the message can be something other than a string. A custom struct for instance!

Final code
// Set up the logger
var l <your logger type>
astilog.SetLogger(l)

// Start an http server
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte(`<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Hello world</title>
    </head>
    <body>
        <span id="message">Hello world</span>
        <script>
            // This will wait for the astilectron namespace to be ready
            document.addEventListener('astilectron-ready', function() {
                // This will listen to messages sent by GO
                astilectron.listen(function(message) {
                    document.getElementById('message').innerHTML = message
                    // This will send a message back to GO
                    astilectron.send("I'm good bro")
                });
            })
        </script>
    </body>
    </html>`))
})
go http.ListenAndServe("127.0.0.1:4000", nil)

// Initialize astilectron
var a, _ = astilectron.New(astilectron.Options{BaseDirectoryPath: "<where you want the provisioner to install the dependencies>"})
defer a.Close()

// Handle quit
a.HandleSignals()
a.On(astilectron.EventNameAppStop, func(e astilectron.Event) (deleteListener bool) {
    a.Stop()
    return
})

// Start astilectron: this will download and set up the dependencies, and start the Electron app
a.Start()

// Create a new window with a listener on resize
var w, _ = a.NewWindow("http://127.0.0.1:4000", &astilectron.WindowOptions{
    Center: astilectron.PtrBool(true),
    Height: astilectron.PtrInt(600),
    Width:  astilectron.PtrInt(600),
})
w.On(astilectron.EventNameWindowEventResize, func(e astilectron.Event) (deleteListener bool) {
    astilog.Info("Window resized")
    return
})
w.On(astilectron.EventNameWindowEventMessage, func(e astilectron.Event) (deleteListener bool) {
	var m string
	e.Message.Unmarshal(&m)
	astilog.Infof("Received message %s", m)
	return
})
w.Create()

// Play with the window
w.Resize(200, 200)
time.Sleep(time.Second)
w.Maximize()

// Send a message to the server
time.Sleep(time.Second)
w.Send("What's up?")

// Blocking pattern
a.Wait()

I want to see it in actions!

To make things clearer I've tried to split features in different examples.

To run any of the examples, run the following commands:

$ go run examples/<name of the example>/main.go -v

Here's a list of the examples:

Features and roadmap

  • window basic methods (create, show, close, resize, minimize, maximize, ...)
  • window basic events (close, blur, focus, unresponsive, crashed, ...)
  • remote messaging (messages between GO and the JS in the webserver)
  • menu methods
  • menu events
  • session methods
  • session events
  • window advanced options (add missing ones)
  • window advanced methods (add missing ones)
  • window advanced events (add missing ones)
  • child windows

Cheers to

go-thrust which is awesome but unfortunately not maintained anymore. It inspired this project.

Documentation

Index

Constants

View Source
const (
	EventNameAppEventReady                     = "app.event.ready"
	EventNameAppClose                          = "app.close"
	EventNameAppCrash                          = "app.crash"
	EventNameAppStop                           = "app.stop" // This event is equal to EventNameAppClose || EventNameAppCrash
	EventNameProvisionStart                    = "provision.start"
	EventNameProvisionDone                     = "provision.done"
	EventNameWindowCmdBlur                     = "window.cmd.blur"
	EventNameWindowCmdCenter                   = "window.cmd.center"
	EventNameWindowCmdClose                    = "window.cmd.close"
	EventNameWindowCmdCreate                   = "window.cmd.create"
	EventNameWindowCmdDestroy                  = "window.cmd.destroy"
	EventNameWindowCmdFocus                    = "window.cmd.focus"
	EventNameWindowCmdHide                     = "window.cmd.hide"
	EventNameWindowCmdMaximize                 = "window.cmd.maximize"
	EventNameWindowCmdMessage                  = "window.cmd.message"
	EventNameWindowCmdMinimize                 = "window.cmd.minimize"
	EventNameWindowCmdMove                     = "window.cmd.move"
	EventNameWindowCmdResize                   = "window.cmd.resize"
	EventNameWindowCmdRestore                  = "window.cmd.restore"
	EventNameWindowCmdShow                     = "window.cmd.show"
	EventNameWindowCmdUnmaximize               = "window.cmd.unmaximize"
	EventNameWindowCmdWebContentsCloseDevTools = "window.cmd.web.contents.close.dev.tools"
	EventNameWindowCmdWebContentsOpenDevTools  = "window.cmd.web.contents.open.dev.tools"
	EventNameWindowEventBlur                   = "window.event.blur"
	EventNameWindowEventClosed                 = "window.event.closed"
	EventNameWindowEventDidFinishLoad          = "window.event.did.finish.load"
	EventNameWindowEventFocus                  = "window.event.focus"
	EventNameWindowEventHide                   = "window.event.hide"
	EventNameWindowEventMaximize               = "window.event.maximize"
	EventNameWindowEventMessage                = "window.event.message"
	EventNameWindowEventMinimize               = "window.event.minimize"
	EventNameWindowEventMove                   = "window.event.move"
	EventNameWindowEventReadyToShow            = "window.event.ready.to.show"
	EventNameWindowEventResize                 = "window.event.resize"
	EventNameWindowEventRestore                = "window.event.restore"
	EventNameWindowEventShow                   = "window.event.show"
	EventNameWindowEventUnmaximize             = "window.event.unmaximize"
	EventNameWindowEventUnresponsive           = "window.event.unresponsive"
)

Event names

Variables

View Source
var DefaultProvisioner = &defaultProvisioner{
	httpClient: &http.Client{},
}

Default provisioner

View Source
var (
	ErrWindowDestroyed = errors.New("window.destroyed")
)

Window errors

Functions

func Download

func Download(ctx context.Context, c *http.Client, dst, src string) (err error)

Download is a cancellable function that downloads a src into a dst using a specific *http.Client and deals with failed downloads

func PtrBool

func PtrBool(i bool) *bool

PtrBool transforms a bool into a *bool

func PtrInt

func PtrInt(i int) *int

PtrInt transforms an int into an *int

func PtrStr

func PtrStr(i string) *string

PtrStr transforms a string into a *string

func Unzip

func Unzip(ctx context.Context, dst, src string) error

Unzip unzips a src into a dst. Possible src formats are /path/to/zip.zip or /path/to/zip.zip/internal/path.

Types

type Astilectron

type Astilectron struct {
	// contains filtered or unexported fields
}

Astilectron represents an object capable of interacting with Astilectron

func New

func New(o Options) (a *Astilectron, err error)

New creates a new Astilectron instance

func (*Astilectron) Close

func (a *Astilectron) Close()

Close closes Astilectron properly

func (*Astilectron) HandleSignals

func (a *Astilectron) HandleSignals()

HandleSignals handles signals

func (*Astilectron) NewWindow

func (a *Astilectron) NewWindow(url string, o *WindowOptions) (w *Window, err error)

NewWindow creates a new window

func (*Astilectron) On

func (a *Astilectron) On(eventName string, l Listener)

On implements the Listenable interface

func (*Astilectron) SetProvisioner

func (a *Astilectron) SetProvisioner(p Provisioner) *Astilectron

SetProvisioner sets the provisioner

func (*Astilectron) Start

func (a *Astilectron) Start() (err error)

Start starts Astilectron

func (*Astilectron) Stop

func (a *Astilectron) Stop()

Stop orders Astilectron to stop

func (*Astilectron) Wait

func (a *Astilectron) Wait()

Wait is a blocking pattern

type Event

type Event struct {
	// 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       *EventMessage  `json:"message,omitempty"`
	URL           string         `json:"url,omitempty"`
	WindowOptions *WindowOptions `json:"windowOptions,omitempty"`
}

Event represents an event

type EventMessage

type EventMessage struct {
	// contains filtered or unexported fields
}

EventMessage represents an event message

func (*EventMessage) MarshalJSON

func (p *EventMessage) MarshalJSON() ([]byte, error)

MarshalJSON implements the JSONMarshaler interface

func (*EventMessage) Unmarshal

func (p *EventMessage) Unmarshal(i interface{}) error

Unmarshal unmarshals the payload into the given interface

func (*EventMessage) UnmarshalJSON

func (p *EventMessage) UnmarshalJSON(i []byte) error

UnmarshalJSON implements the JSONUnmarshaler interface

type Listener

type Listener func(e Event) (deleteListener bool)

Listener represents a listener executed when an event is dispatched

type Options

type Options struct {
	BaseDirectoryPath string
}

Options represents Astilectron options

type Paths

type Paths struct {
	// contains filtered or unexported fields
}

Paths represents the set of paths needed by Astilectron

func (*Paths) AstilectronApplication

func (p *Paths) AstilectronApplication() string

AstilectronApplication returns the astilectron application path

func (*Paths) AstilectronDirectory

func (p *Paths) AstilectronDirectory() string

AstilectronDirectory returns the astilectron directory path

func (*Paths) AstilectronDownloadDst

func (p *Paths) AstilectronDownloadDst() string

AstilectronDownloadDst returns the astilectron download destination path

func (*Paths) AstilectronDownloadSrc

func (p *Paths) AstilectronDownloadSrc() string

AstilectronDownloadSrc returns the astilectron download source path

func (*Paths) AstilectronUnzipSrc

func (p *Paths) AstilectronUnzipSrc() string

AstilectronUnzipSrc returns the astilectron unzip source path

func (*Paths) BaseDirectory

func (p *Paths) BaseDirectory() string

BaseDirectory returns the base directory path

func (*Paths) ElectronDirectory

func (p *Paths) ElectronDirectory() string

ElectronDirectory returns the electron directory path

func (*Paths) ElectronDownloadDst

func (p *Paths) ElectronDownloadDst() string

ElectronDownloadDst returns the electron download destination path

func (*Paths) ElectronDownloadSrc

func (p *Paths) ElectronDownloadSrc() string

ElectronDownloadSrc returns the electron download source path

func (*Paths) ElectronExecutable

func (p *Paths) ElectronExecutable() string

ElectronExecutable returns the electron eecutable path

func (*Paths) ElectronUnzipSrc

func (p *Paths) ElectronUnzipSrc() string

ElectronUnzipSrc returns the electron unzip source path

func (*Paths) VendorDirectory

func (p *Paths) VendorDirectory() string

BaseDirectory returns the vendor directory path

type Provisioner

type Provisioner interface {
	Provision(ctx context.Context, p Paths) error
}

Provisioner represents an object capable of provisioning Astilectron

type Window

type Window struct {
	// contains filtered or unexported fields
}

Window represents a window https://github.com/electron/electron/blob/master/docs/api/browser-window.md TODO Add missing window options TODO Add missing window methods TODO Add missing window events

func (*Window) Blur

func (w *Window) Blur() (err error)

Blur blurs the window

func (*Window) Center

func (w *Window) Center() (err error)

Center centers the window

func (*Window) Close

func (w *Window) Close() (err error)

Close closes the window

func (*Window) CloseDevTools

func (w *Window) CloseDevTools() (err error)

CloseDevTools closes the dev tools

func (*Window) Create

func (w *Window) Create() (err error)

Create creates the window We wait for EventNameWindowEventDidFinishLoad since we need the web content to be fully loaded before being able to send messages to it

func (*Window) Destroy

func (w *Window) Destroy() (err error)

Destroy destroys the window

func (*Window) Focus

func (w *Window) Focus() (err error)

Focus focuses on the window

func (*Window) Hide

func (w *Window) Hide() (err error)

Hide hides the window

func (*Window) Maximize

func (w *Window) Maximize() (err error)

Maximize maximizes the window

func (*Window) Minimize

func (w *Window) Minimize() (err error)

Minimize minimizes the window

func (*Window) Move

func (w *Window) Move(x, y int) (err error)

Move moves the window

func (*Window) On

func (w *Window) On(eventName string, l Listener)

On implements the Listenable interface

func (*Window) OpenDevTools

func (w *Window) OpenDevTools() (err error)

OpenDevTools opens the dev tools

func (*Window) Resize

func (w *Window) Resize(width, height int) (err error)

Resize resizes the window

func (*Window) Restore

func (w *Window) Restore() (err error)

Restore restores the window

func (*Window) Send

func (w *Window) Send(message interface{}) (err error)

Send sends a message to the inner JS of the Web content of the window

func (*Window) Show

func (w *Window) Show() (err error)

Show shows the window

func (*Window) Unmaximize

func (w *Window) Unmaximize() (err error)

Unmaximize unmaximize the window

type WindowOptions

type WindowOptions struct {
	AcceptFirstMouse       *bool   `json:"acceptFirstMouse,omitempty"`
	AlwaysOnTop            *bool   `json:"alwaysOnTop,omitempty"`
	AutoHideMenuBar        *bool   `json:"autoHideMenuBar,omitempty"`
	BackgroundColor        *string `json:"backgroundColor,omitempty"`
	Center                 *bool   `json:"center,omitempty"`
	Closable               *bool   `json:"closable,omitempty"`
	DisableAutoHideCursor  *bool   `json:"disableAutoHideCursor,omitempty"`
	EnableLargerThanScreen *bool   `json:"enableLargerThanScreen,omitempty"`
	Focusable              *bool   `json:"focusable,omitempty"`
	Frame                  *bool   `json:"frame,omitempty"`
	Fullscreen             *bool   `json:"fullscreen,omitempty"`
	Fullscreenable         *bool   `json:"fullscreenable,omitempty"`
	HasShadow              *bool   `json:"hasShadow,omitempty"`
	Height                 *int    `json:"height,omitempty"`
	Icon                   *string `json:"icon,omitempty"`
	Kiosk                  *bool   `json:"kiosk,omitempty"`
	MaxHeight              *int    `json:"maxHeight,omitempty"`
	Maximizable            *bool   `json:"maximizable,omitempty"`
	MaxWidth               *int    `json:"maxWidth,omitempty"`
	MinHeight              *int    `json:"minHeight,omitempty"`
	Minimizable            *bool   `json:"minimizable,omitempty"`
	MinWidth               *int    `json:"minWidth,omitempty"`
	Modal                  *bool   `json:"modal,omitempty"`
	Movable                *bool   `json:"movable,omitempty"`
	Resizable              *bool   `json:"resizable,omitempty"`
	Show                   *bool   `json:"show,omitempty"`
	SkipTaskbar            *bool   `json:"skipTaskbar,omitempty"`
	Title                  *string `json:"title,omitempty"`
	Transparent            *bool   `json:"transparent,omitempty"`
	UseContentSize         *bool   `json:"useContentSize,omitempty"`
	Width                  *int    `json:"width,omitempty"`
	X                      *int    `json:"x,omitempty"`
	Y                      *int    `json:"y,omitempty"`
}

WindowOptions represents window options We must use pointers since GO doesn't handle optional fields whereas NodeJS does. Use PtrBool, PtrInt or PtrStr to fill the struct

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL