Skip to content

Commit

Permalink
[v0.0.2] Working for Windows, Linux and Mac
Browse files Browse the repository at this point in the history
Mac requires some attention to the .app package
  • Loading branch information
Donovan Solms committed Apr 24, 2018
1 parent 53e5b07 commit 259ecee
Show file tree
Hide file tree
Showing 15 changed files with 253 additions and 55 deletions.
5 changes: 5 additions & 0 deletions Makefile
Expand Up @@ -18,6 +18,9 @@ run: build
run_debug: build
./bin/linux-amd64/'${APP_NAME}' -d

run_only_debug:
./bin/linux-amd64/'${APP_NAME}' -d

webdev:
./scripts/run_browsersync.sh

Expand All @@ -27,3 +30,5 @@ fmt:

clean:
rm -Rf bin/
rm src/windows.syso
rm src/bind*
2 changes: 1 addition & 1 deletion src/bundler.json
@@ -1,5 +1,5 @@
{
"app_name": "Stellite GUI Miner v0.0.1",
"app_name": "Stellite GUI Miner v0.0.2",
"environments": [
{"arch": "amd64", "os": "darwin"},
{"arch": "amd64", "os": "linux"},
Expand Down
122 changes: 73 additions & 49 deletions src/gui/gui.go
Expand Up @@ -9,6 +9,7 @@ import (
"os"
"os/user"
"path/filepath"
"runtime"
"time"

astilectron "github.com/asticode/go-astilectron"
Expand All @@ -22,8 +23,6 @@ import (
type GUI struct {
// window is the main Astilectron window
window *astilectron.Window
// // minerCmd is a reference to the xmr-stak miner process
// minerCmd *exec.Cmd
// astilectronOptions holds the Astilectron options
astilectronOptions bootstrap.Options
// config for the miner
Expand Down Expand Up @@ -51,21 +50,13 @@ func New(
asset bootstrap.Asset,
restoreAssets bootstrap.RestoreAssets,
apiEndpoint string,
workingDir string,
isDebug bool) (*GUI, error) {

if apiEndpoint == "" {
return nil, errors.New("The API Endpoint must be specified")
}

workingDir, err := os.Getwd()
if err != nil {
return nil, fmt.Errorf("Can't read current directory: %s", err)
}
workingDir, err = filepath.Abs(workingDir)
if err != nil {
return nil, fmt.Errorf("Can't read current directory: %s", err)
}

gui := GUI{
config: config,
workingDir: workingDir,
Expand All @@ -89,6 +80,65 @@ func New(
Mid: uuid.New().String(),
}
}
var menu []*astilectron.MenuItemOptions

// Setup the logging, by default we log to stdout
logrus.SetFormatter(&logrus.TextFormatter{
FullTimestamp: true,
TimestampFormat: "Jan 02 15:04:05",
})
logrus.SetLevel(logrus.InfoLevel)

logrus.SetOutput(os.Stdout)
if isDebug {
logrus.SetLevel(logrus.DebugLevel)
debugLog, err := os.OpenFile(
filepath.Join(gui.workingDir, "debug.log"),
os.O_CREATE|os.O_TRUNC|os.O_WRONLY,
0644)
if err != nil {
panic(err)
}
logrus.SetOutput(debugLog)

// We only show the menu bar in debug mode
menu = append(menu, &astilectron.MenuItemOptions{
Label: astilectron.PtrStr("File"),
SubMenu: []*astilectron.MenuItemOptions{
{
Role: astilectron.MenuItemRoleClose,
},
},
})
}
// To make copy and paste work on Mac, the copy and paste entries need to
// be defined, the alternative is to implement the clipboard API
// https://github.com/electron/electron/blob/master/docs/api/clipboard.md
if runtime.GOOS == "darwin" {
menu = append(menu, &astilectron.MenuItemOptions{
Label: astilectron.PtrStr("Edit"),
SubMenu: []*astilectron.MenuItemOptions{
{
Role: astilectron.MenuItemRoleCut,
},
{
Role: astilectron.MenuItemRoleCopy,
},
{
Role: astilectron.MenuItemRolePaste,
},
{
Role: astilectron.MenuItemRoleSelectAll,
},
},
})
}

// Setting the WithFields now will ensure all log entries from this point
// includes the fields
gui.logger = logrus.WithFields(logrus.Fields{
"service": "stellite-gui-miner",
})

gui.astilectronOptions = bootstrap.Options{
Debug: isDebug,
Expand All @@ -101,20 +151,20 @@ func New(
AppIconDefaultPath: "resources/icon.png",
},
WindowOptions: &astilectron.WindowOptions{
Title: astilectron.PtrStr("Stellite GUI Miner"),
// TODO: Frameless looks amazing, first I'd need to implement draggable
// sections and control buttons
//Frame: astilectron.PtrBool(false),
BackgroundColor: astilectron.PtrStr("#0B0C22"),
Center: astilectron.PtrBool(true),
Height: astilectron.PtrInt(700),
Width: astilectron.PtrInt(1175),
},
MenuOptions: []*astilectron.MenuItemOptions{{
Label: astilectron.PtrStr("File"),
SubMenu: []*astilectron.MenuItemOptions{
{
Role: astilectron.MenuItemRoleClose,
},
},
}},
// TODO: Fix this tray to display nicely
/*TrayOptions: &astilectron.TrayOptions{
Image: astilectron.PtrStr("/static/i/miner-logo.png"),
Tooltip: astilectron.PtrStr(appName),
},*/
MenuOptions: menu,
// OnWait is triggered as soon as the electron window is ready and running
OnWait: func(
_ *astilectron.Astilectron,
Expand All @@ -139,32 +189,6 @@ func New(
MessageHandler: gui.handleElectronCommands,
}

// Setup the logging, by default we log to stdout
logrus.SetFormatter(&logrus.TextFormatter{
FullTimestamp: true,
TimestampFormat: "Jan 02 15:04:05",
})
logrus.SetLevel(logrus.InfoLevel)

logrus.SetOutput(os.Stdout)
if isDebug {
logrus.SetLevel(logrus.DebugLevel)
// TODO: Handle this debug log better
debugLog, err := os.OpenFile(
fmt.Sprintf(".%c%s", os.PathSeparator, "debug.log"),
os.O_CREATE|os.O_TRUNC|os.O_WRONLY,
0644)
if err != nil {
panic(err)
}
logrus.SetOutput(debugLog)
}
// Setting the WithFields now will ensure all log entries from this point
// includes the fields
gui.logger = logrus.WithFields(logrus.Fields{
"service": "stellite-gui-miner",
})

gui.logger.Info("Setup complete")
return &gui, nil
}
Expand Down Expand Up @@ -315,10 +339,10 @@ func (gui *GUI) configureMiner(command bootstrap.MessageIn) {
gui.logger.Fatalf("Unable to configure miner: '%s'", err)
}
scanPath := filepath.Join(gui.workingDir, "miner")
if gui.config.Miner.Path != "" {
// TODO: Fix own miner paths option
// TODO: Fix own miner paths option
/*if gui.config.Miner.Path != "" {
//scanPath = path.Base(gui.config.Miner.Path)
}
}*/
gui.logger.WithField(
"scan_path", scanPath,
).Debug("Determining miner type")
Expand Down
7 changes: 5 additions & 2 deletions src/gui/helper.go
Expand Up @@ -8,6 +8,7 @@ import (
"io/ioutil"
"log"
"net/http"
"path/filepath"
)

// GetPoolList returns the list of pools available to the GUI miner
Expand Down Expand Up @@ -40,13 +41,15 @@ func (gui *GUI) GetPool(id int) (PoolData, error) {
}

// SaveConfig saves the configuration to disk
// TODO: Specify path here
func (gui *GUI) SaveConfig(config Config) error {
configBytes, err := json.Marshal(&config)
if err != nil {
return err
}
err = ioutil.WriteFile("config.json", configBytes, 0644)
err = ioutil.WriteFile(
filepath.Join(gui.workingDir, "config.json"),
configBytes,
0644)
if err != nil {
return err
}
Expand Down
File renamed without changes.
58 changes: 58 additions & 0 deletions src/gui/miner/base_linux.go
@@ -0,0 +1,58 @@
package miner

import (
"fmt"
"os"
"os/exec"
"strings"

ps "github.com/mitchellh/go-ps"
)

// Base implements core functionality common to all miners
type Base struct {
executableName string
executablePath string
command *exec.Cmd
}

// Start the miner
func (b *Base) Start() error {
params := []string{}
commandName := fmt.Sprintf(".%c%s", os.PathSeparator, b.executableName)
commandDir := b.executablePath
b.command = exec.Command(commandName, params...)
b.command.Dir = commandDir
return b.command.Start()
}

// Stop the miner
func (b *Base) Stop() error {
if b.command != nil {
// Some of the miners fork in a way that we loose track of the actual
// miner's pid. To make sure the miner is stopped, we find all processes
// that match the original executable name
processes, err := ps.Processes()
if err != nil {
// If for some reason we can't get the process list, we use the
// standard kill available
return b.command.Process.Kill()
}
for _, process := range processes {
if strings.Contains(strings.ToLower(process.Executable()), b.executableName) {
p, err := os.FindProcess(process.Pid())
if err != nil {
// If the process is in the list, but we can't find it by Pid, then
// it probably died or something weird is going on
return err
}
// Kill the process we found, then continue searching - just in case
// there is still others lingering around. Not worried about any errors
// here since there is nothing we can do about it at this point
_ = p.Kill()
}
}

}
return nil
}
64 changes: 64 additions & 0 deletions src/gui/miner/base_windows.go
@@ -0,0 +1,64 @@
package miner

import (
"fmt"
"os"
"os/exec"
"strings"
"syscall"

ps "github.com/mitchellh/go-ps"
)

// Base implements core functionality common to all miners
type Base struct {
executableName string
executablePath string
command *exec.Cmd
}

// Start the miner
func (b *Base) Start() error {
params := []string{}
commandName := fmt.Sprintf(".%c%s", os.PathSeparator, b.executableName)
commandDir := b.executablePath
b.command = exec.Command(commandName, params...)
b.command.Dir = commandDir
// This hides the syscall section on Linux where SysProcAttr defines different
// attributes
b.command.SysProcAttr = &syscall.SysProcAttr{
HideWindow: true,
}
return b.command.Start()
}

// Stop the miner
func (b *Base) Stop() error {
if b.command != nil {
// Some of the miners fork in a way that we loose track of the actual
// miner's pid. To make sure the miner is stopped, we find all processes
// that match the original executable name
processes, err := ps.Processes()
if err != nil {
// If for some reason we can't get the process list, we use the
// standard kill available
return b.command.Process.Kill()
}
for _, process := range processes {
if strings.Contains(strings.ToLower(process.Executable()), b.executableName) {
p, err := os.FindProcess(process.Pid())
if err != nil {
// If the process is in the list, but we can't find it by Pid, then
// it probably died or something weird is going on
return err
}
// Kill the process we found, then continue searching - just in case
// there is still others lingering around. Not worried about any errors
// here since there is nothing we can do about it at this point
_ = p.Kill()
}
}

}
return nil
}
10 changes: 9 additions & 1 deletion src/gui/miner/xmrig.go
Expand Up @@ -5,6 +5,7 @@ import (
"io/ioutil"
"net/http"
"path/filepath"
"runtime"
)

// Xmrig implements the miner interface for the xmrig miner, including
Expand Down Expand Up @@ -210,10 +211,17 @@ func (miner *Xmrig) defaultConfig(
poolEndpoint string,
walletAddress string) XmrigConfig {

runInBackground := true
// On Mac OSX xmrig doesn't run is we fork the process to the background and
// xmrig forks to the background again
if runtime.GOOS == "darwin" {
runInBackground = false
}

return XmrigConfig{
Algo: "cryptonight",
Av: 0,
Background: true,
Background: runInBackground,
Colors: true,
CPUAffinity: nil,
CPUPriority: nil,
Expand Down

0 comments on commit 259ecee

Please sign in to comment.