-
Notifications
You must be signed in to change notification settings - Fork 340
Fix for issue #190 #191
base: master
Are you sure you want to change the base?
Fix for issue #190 #191
Changes from 5 commits
54ab773
c74f8d0
f169105
0224def
e189c63
ac66b4f
0302461
13f1a91
54792fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ import ( | |
| "os" | ||
| "os/exec" | ||
| "os/signal" | ||
| "path/filepath" | ||
| "runtime" | ||
| "sync" | ||
| "syscall" | ||
|
|
@@ -19,9 +20,9 @@ import ( | |
|
|
||
| // Versions | ||
| const ( | ||
| DefaultAcceptTCPTimeout = 30 * time.Second | ||
| VersionAstilectron = "0.32.0" | ||
| VersionElectron = "4.0.1" | ||
| DefaultAcceptTimeout = 30 * time.Second | ||
| VersionAstilectron = "0.32.0" | ||
| VersionElectron = "4.0.1" | ||
| ) | ||
|
|
||
| // Misc vars | ||
|
|
@@ -45,6 +46,11 @@ const ( | |
| EventNameAppTooManyAccept = "app.too.many.accept" | ||
| ) | ||
|
|
||
| // // Unix socket path | ||
|
||
| // var ( | ||
| // UNIX_SOCKET_PATH = filepath.Join(a.paths.DataDirectory(), "astilectron.sock") | ||
| // ) | ||
|
|
||
| // Astilectron represents an object capable of interacting with Astilectron | ||
| type Astilectron struct { | ||
| canceller *asticontext.Canceller | ||
|
|
@@ -68,16 +74,16 @@ type Astilectron struct { | |
|
|
||
| // Options represents Astilectron options | ||
| type Options struct { | ||
| AcceptTCPTimeout time.Duration | ||
| AppName string | ||
| AppIconDarwinPath string // Darwin systems requires a specific .icns file | ||
| AppIconDefaultPath string | ||
| BaseDirectoryPath string | ||
| DataDirectoryPath string | ||
| ElectronSwitches []string | ||
| SingleInstance bool | ||
| SkipSetup bool // If true, the user must handle provisioning and executing astilectron. | ||
| TCPPort *int // The port to listen on. | ||
| AcceptTimeout time.Duration | ||
| AppName string | ||
| AppIconDarwinPath string // Darwin systems requires a specific .icns file | ||
| AppIconDefaultPath string | ||
| BaseDirectoryPath string | ||
| DataDirectoryPath string | ||
| ElectronSwitches []string | ||
| SingleInstance bool | ||
| SkipSetup bool // If true, the user must handle provisioning and executing astilectron. | ||
| TCPPort *int // The port to listen on. | ||
|
||
| } | ||
|
|
||
| // Supported represents Astilectron supported features | ||
|
|
@@ -170,15 +176,14 @@ func (a *Astilectron) Start() (err error) { | |
| } | ||
| } | ||
|
|
||
| // Unfortunately communicating with Electron through stdin/stdout doesn't work on Windows so all communications | ||
| // will be done through TCP | ||
| if err = a.listenTCP(); err != nil { | ||
| return errors.Wrap(err, "listening failed") | ||
| listenType, listenErr := a.listen() | ||
|
||
| if listenErr != nil { | ||
| return listenErr | ||
| } | ||
|
|
||
| // Execute | ||
| if !a.options.SkipSetup { | ||
| if err = a.execute(); err != nil { | ||
| if err = a.execute(listenType); err != nil { | ||
|
||
| return errors.Wrap(err, "executing failed") | ||
| } | ||
| } else { | ||
|
|
@@ -194,35 +199,90 @@ func (a *Astilectron) provision() error { | |
| return a.provisioner.Provision(ctx, a.options.AppName, runtime.GOOS, runtime.GOARCH, *a.paths) | ||
| } | ||
|
|
||
| // listenTCP creates a TCP server for astilectron to connect to | ||
| // and listens to the first TCP connection coming its way (this should be Astilectron). | ||
| func (a *Astilectron) listenTCP() (err error) { | ||
| // function to create TCP/Unix socket connection | ||
| func (a *Astilectron) listen() (string, error) { | ||
|
||
| /* | ||
| * Switching between Unix-Socket and TCP-Socket | ||
| * Windows will use TCP Socket | ||
| * MAC and Linux will use Unix-Socket | ||
| */ | ||
| if runtime.GOOS == "windows" { | ||
| // Unfortunately communicating with Electron through stdin/stdout doesn't | ||
| // work on Windows so all communications will be done through TCP | ||
| if err := a.listenTCP(); err != nil { | ||
| return " ", errors.Wrap(err, "TCP Socket listening failed") | ||
| } | ||
| return "tcp", nil | ||
| } else { | ||
| if err := a.listenUnix(); err != nil { | ||
| return "", errors.Wrap(err, "Unix Socket listening failed") | ||
| } | ||
| return "unix", nil | ||
| } | ||
| return "", nil | ||
| } | ||
|
|
||
| func (a *Astilectron) listenFunc(fn func() error) (err error) { | ||
|
||
| // Log | ||
| astilog.Debug("Listening...") | ||
|
|
||
| addr := "127.0.0.1:" | ||
| if a.options.TCPPort != nil { | ||
| addr += fmt.Sprint(*a.options.TCPPort) | ||
| } | ||
| // Listen | ||
| if a.listener, err = net.Listen("tcp", addr); err != nil { | ||
| return errors.Wrap(err, "tcp net.Listen failed") | ||
| // Custom | ||
| if err = fn(); err != nil { | ||
| err = errors.Wrap(err, "main: custom listen failed") | ||
| return | ||
| } | ||
|
|
||
| // Check a connection has been accepted quickly enough | ||
| var chanAccepted = make(chan bool) | ||
| go a.watchNoAccept(a.options.AcceptTCPTimeout, chanAccepted) | ||
| go a.watchNoAccept(a.options.AcceptTimeout, chanAccepted) | ||
|
|
||
| // Accept connections | ||
| go a.acceptTCP(chanAccepted) | ||
| go a.accept(chanAccepted) | ||
| return | ||
| } | ||
|
|
||
| // Creates a unix socket | ||
| func (a *Astilectron) listenUnix() (err error) { | ||
|
|
||
| UNIX_SOCKET_PATH := filepath.Join(a.paths.DataDirectory(), "astilectron.sock") | ||
|
||
|
|
||
| _ = os.Remove(UNIX_SOCKET_PATH) | ||
|
||
|
|
||
| if err := a.listenFunc(func() error { | ||
|
||
| // Listen | ||
| if a.listener, err = net.Listen("unix", UNIX_SOCKET_PATH); err != nil { | ||
| return errors.Wrap(err, "Unix net.Listen failed") | ||
| } | ||
| return nil | ||
| }); err != nil { | ||
| return errors.Wrap(err, "main: listen func failed") | ||
| } | ||
| return | ||
| } | ||
|
|
||
| // listenTCP listens to the first TCP connection coming its way (this should be Astilectron) | ||
| func (a *Astilectron) listenTCP() (err error) { | ||
|
|
||
| if err = a.listenFunc(func() error { | ||
| addr := "127.0.0.1:" | ||
| if a.options.TCPPort != nil { | ||
| addr += fmt.Sprint(*a.options.TCPPort) | ||
| } | ||
| // Listen | ||
| if a.listener, err = net.Listen("tcp", addr); err != nil { | ||
| return errors.Wrap(err, "tcp net.Listen failed") | ||
| } | ||
| return nil | ||
| }); err != nil { | ||
| return errors.Wrap(err, "main: listen func failed") | ||
| } | ||
| return | ||
| } | ||
|
|
||
| // watchNoAccept checks whether a TCP connection is accepted quickly enough | ||
| // watchNoAccept checks whether a connection is accepted quickly enough | ||
| func (a *Astilectron) watchNoAccept(timeout time.Duration, chanAccepted chan bool) { | ||
| //check timeout | ||
| if timeout == 0 { | ||
| timeout = DefaultAcceptTCPTimeout | ||
| timeout = DefaultAcceptTimeout | ||
| } | ||
| var t = time.NewTimer(timeout) | ||
| defer t.Stop() | ||
|
|
@@ -231,22 +291,22 @@ func (a *Astilectron) watchNoAccept(timeout time.Duration, chanAccepted chan boo | |
| case <-chanAccepted: | ||
| return | ||
| case <-t.C: | ||
| astilog.Errorf("No TCP connection has been accepted in the past %s", timeout) | ||
| astilog.Errorf("No connection has been accepted in the past %s", timeout) | ||
| a.dispatcher.dispatch(Event{Name: EventNameAppNoAccept, TargetID: targetIDApp}) | ||
| a.dispatcher.dispatch(Event{Name: EventNameAppCmdStop, TargetID: targetIDApp}) | ||
| return | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // watchAcceptTCP accepts TCP connections | ||
| func (a *Astilectron) acceptTCP(chanAccepted chan bool) { | ||
| // watchAccept accepts connections | ||
| func (a *Astilectron) accept(chanAccepted chan bool) { | ||
| for i := 0; i <= 1; i++ { | ||
| // Accept | ||
| var conn net.Conn | ||
| var err error | ||
| if conn, err = a.listener.Accept(); err != nil { | ||
| astilog.Errorf("%s while TCP accepting", err) | ||
| astilog.Errorf("%s while accepting connection", err) | ||
| a.dispatcher.dispatch(Event{Name: EventNameAppErrorAccept, TargetID: targetIDApp}) | ||
| a.dispatcher.dispatch(Event{Name: EventNameAppCmdStop, TargetID: targetIDApp}) | ||
| return | ||
|
|
@@ -255,7 +315,7 @@ func (a *Astilectron) acceptTCP(chanAccepted chan bool) { | |
| // We only accept the first connection which should be Astilectron, close the next one and stop | ||
| // the app | ||
| if i > 0 { | ||
| astilog.Errorf("Too many TCP connections") | ||
| astilog.Errorf("Too many connections") | ||
| a.dispatcher.dispatch(Event{Name: EventNameAppTooManyAccept, TargetID: targetIDApp}) | ||
| a.dispatcher.dispatch(Event{Name: EventNameAppCmdStop, TargetID: targetIDApp}) | ||
| conn.Close() | ||
|
|
@@ -274,7 +334,7 @@ func (a *Astilectron) acceptTCP(chanAccepted chan bool) { | |
| } | ||
|
|
||
| // execute executes Astilectron in Electron | ||
| func (a *Astilectron) execute() (err error) { | ||
| func (a *Astilectron) execute(listenType string) (err error) { | ||
|
||
| // Log | ||
| astilog.Debug("Executing...") | ||
|
|
||
|
|
@@ -286,7 +346,7 @@ func (a *Astilectron) execute() (err error) { | |
| } else { | ||
| singleInstance = "false" | ||
| } | ||
| var cmd = exec.CommandContext(ctx, a.paths.AppExecutable(), append([]string{a.paths.AstilectronApplication(), a.listener.Addr().String(), singleInstance}, a.options.ElectronSwitches...)...) | ||
| var cmd = exec.CommandContext(ctx, a.paths.AppExecutable(), append([]string{a.paths.AstilectronApplication(), listenType, a.listener.Addr().String(), singleInstance}, a.options.ElectronSwitches...)...) | ||
|
||
| a.stderrWriter = astiexec.NewStdWriter(func(i []byte) { astilog.Debugf("Stderr says: %s", i) }) | ||
| a.stdoutWriter = astiexec.NewStdWriter(func(i []byte) { astilog.Debugf("Stdout says: %s", i) }) | ||
| cmd.Stderr = a.stderrWriter | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.