mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 00:05:15 +00:00
add basic desktop app
This commit is contained in:
parent
0cb2a3c452
commit
621321f5db
10
Makefile
10
Makefile
|
@ -37,16 +37,22 @@ docker:
|
|||
docker build --build-arg GO_MOD_CACHE=_mod --tag yoanlin/bbgo .
|
||||
bash -c "[[ -n $(DOCKER_TAG) ]] && docker tag yoanlin/bbgo yoanlin/bbgo:$(DOCKER_TAG)"
|
||||
|
||||
|
||||
docker-push:
|
||||
docker push yoanlin/bbgo
|
||||
bash -c "[[ -n $(DOCKER_TAG) ]] && docker push yoanlin/bbgo:$(DOCKER_TAG)"
|
||||
|
||||
static:
|
||||
static: pkged.go
|
||||
(cd frontend && yarn export)
|
||||
pkger
|
||||
git commit pkged.go -m "update pkged static files"
|
||||
|
||||
desktop: build/BBGO.app/Contents/MacOS/bbgo-desktop static
|
||||
mkdir -p $(dir $<)
|
||||
go build -o $< ./cmd/bbgo-desktop
|
||||
# bash desktop/build-darwin.sh
|
||||
|
||||
tools:
|
||||
GO111MODULES=off go get github.com/markbates/pkger/cmd/pkger
|
||||
|
||||
.PHONY: dist migrations
|
||||
.PHONY: dist migrations desktop
|
||||
|
|
141
cmd/bbgo-desktop/main.go
Normal file
141
cmd/bbgo-desktop/main.go
Normal file
|
@ -0,0 +1,141 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
|
||||
"github.com/zserge/lorca"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/bbgo"
|
||||
"github.com/c9s/bbgo/pkg/cmd"
|
||||
"github.com/c9s/bbgo/pkg/server"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var args []string
|
||||
if runtime.GOOS == "linux" {
|
||||
args = append(args, "--class=bbgo")
|
||||
}
|
||||
args = append(args, "--class=bbgo")
|
||||
|
||||
// here allocate a chrome window with a blank page.
|
||||
ui, err := lorca.New("", "", 800, 640, args...)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("failed to initialize the window")
|
||||
return
|
||||
}
|
||||
|
||||
defer ui.Close()
|
||||
|
||||
// A simple way to know when UI is ready (uses body.onload event in JS)
|
||||
ui.Bind("start", func() {
|
||||
log.Println("lorca is ready")
|
||||
})
|
||||
|
||||
// Create and bind Go object to the UI
|
||||
// ui.Bind("counterAdd", c.Add)
|
||||
|
||||
// Load HTML.
|
||||
// You may also use `data:text/html,<base64>` approach to load initial HTML,
|
||||
// e.g: ui.Load("data:text/html," + url.PathEscape(html))
|
||||
// TODO: load the loading page html
|
||||
|
||||
// find a free port for binding the server
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:9999")
|
||||
if err != nil {
|
||||
log.WithError(err).Error("can not bind listener")
|
||||
return
|
||||
}
|
||||
|
||||
defer ln.Close()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
configFile := "bbgo.yaml"
|
||||
var setup *server.Setup
|
||||
var userConfig *bbgo.Config
|
||||
|
||||
_, err = os.Stat(configFile)
|
||||
if os.IsNotExist(err) {
|
||||
setup = &server.Setup{
|
||||
Context: ctx,
|
||||
Cancel: cancel,
|
||||
Token: "",
|
||||
}
|
||||
userConfig = &bbgo.Config{
|
||||
Notifications: nil,
|
||||
Persistence: nil,
|
||||
Sessions: nil,
|
||||
ExchangeStrategies: nil,
|
||||
}
|
||||
} else {
|
||||
userConfig, err = bbgo.Load(configFile, true)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("can not load config file")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
environ := bbgo.NewEnvironment()
|
||||
trader := bbgo.NewTrader(environ)
|
||||
|
||||
// we could initialize the environment from the settings
|
||||
if setup == nil {
|
||||
if err := cmd.BootstrapEnvironment(ctx, environ, userConfig) ; err != nil {
|
||||
log.WithError(err).Error("failed to bootstrap environment")
|
||||
return
|
||||
}
|
||||
|
||||
if err := cmd.ConfigureTrader(trader, userConfig) ; err != nil {
|
||||
log.WithError(err).Error("failed to configure trader")
|
||||
return
|
||||
}
|
||||
|
||||
// for setup mode, we don't start the trader
|
||||
trader.Subscribe()
|
||||
if err := trader.Run(ctx); err != nil {
|
||||
log.WithError(err).Error("failed to start trader")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
srv := &server.Server{
|
||||
Config: userConfig,
|
||||
Environ: environ,
|
||||
Trader: trader,
|
||||
OpenInBrowser: false,
|
||||
Setup: setup,
|
||||
}
|
||||
|
||||
if err := srv.RunWithListener(ctx, ln); err != nil {
|
||||
log.WithError(err).Errorf("server error")
|
||||
}
|
||||
}()
|
||||
|
||||
baseURL := "http://" + ln.Addr().String()
|
||||
|
||||
go server.PingUntil(ctx, baseURL, func() {
|
||||
if err := ui.Load(baseURL) ; err != nil {
|
||||
log.WithError(err).Error("failed to load page")
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// Wait until the interrupt signal arrives or browser window is closed
|
||||
sigc := make(chan os.Signal)
|
||||
signal.Notify(sigc, os.Interrupt)
|
||||
|
||||
select {
|
||||
case <-sigc:
|
||||
case <-ui.Done():
|
||||
}
|
||||
|
||||
log.Println("exiting...")
|
||||
}
|
|
@ -1,17 +1,17 @@
|
|||
#!/bin/sh
|
||||
|
||||
APP="BBGO.app"
|
||||
APP_DIR=build/$APP
|
||||
|
||||
mkdir -p $APP/Contents/{MacOS,Resources}
|
||||
go build -o $APP/Contents/MacOS/bbgo
|
||||
mkdir -p $APP_DIR/Contents/{MacOS,Resources}
|
||||
go build -o $APP_DIR/Contents/MacOS/bbgo-desktop ./cmd/bbgo-desktop
|
||||
|
||||
cat > $APP/Contents/Info.plist << EOF
|
||||
cat > $APP_DIR/Contents/Info.plist << EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>bbgo</string>
|
||||
<string>bbgo-desktop</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>icon.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
|
@ -20,5 +20,5 @@ cat > $APP/Contents/Info.plist << EOF
|
|||
</plist>
|
||||
EOF
|
||||
|
||||
cp icons/icon.icns $APP/Contents/Resources/icon.icns
|
||||
find $APP
|
||||
cp -v desktop/icons/icon.icns $APP_DIR/Contents/Resources/icon.icns
|
||||
find $APP_DIR
|
||||
|
|
|
@ -48,7 +48,7 @@ export function queryStrategies(cb) {
|
|||
export function querySessions(cb) {
|
||||
return axios.get(baseURL + '/api/sessions', {})
|
||||
.then(response => {
|
||||
cb(response.data.sessions)
|
||||
cb(response.data.sessions || [])
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -44,10 +44,10 @@ export default function Home() {
|
|||
|
||||
React.useEffect(() => {
|
||||
querySessions((sessions) => {
|
||||
if (sessions.length == 0) {
|
||||
push("/setup");
|
||||
} else {
|
||||
if (sessions && sessions.length > 0) {
|
||||
setSessions(sessions)
|
||||
} else {
|
||||
push("/setup");
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
|
|
1
go.mod
1
go.mod
|
@ -51,6 +51,7 @@ require (
|
|||
github.com/ugorji/go v1.2.3 // indirect
|
||||
github.com/valyala/fastjson v1.5.1
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2
|
||||
github.com/zserge/lorca v0.1.9
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 // indirect
|
||||
golang.org/x/text v0.3.5 // indirect
|
||||
|
|
3
go.sum
3
go.sum
|
@ -370,6 +370,8 @@ github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7V
|
|||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
github.com/zserge/lorca v0.1.9 h1:vbDdkqdp2/rmeg8GlyCewY2X8Z+b0s7BqWyIQL/gakc=
|
||||
github.com/zserge/lorca v0.1.9/go.mod h1:bVmnIbIRlOcoV285KIRSe4bUABKi7R7384Ycuum6e4A=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
|
@ -426,6 +428,7 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M=
|
||||
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
|
|
|
@ -95,14 +95,9 @@ func runSetup(baseCtx context.Context, userConfig *bbgo.Config, enableApiServer
|
|||
return nil
|
||||
}
|
||||
|
||||
func runConfig(basectx context.Context, userConfig *bbgo.Config, enableApiServer bool) error {
|
||||
ctx, cancelTrading := context.WithCancel(basectx)
|
||||
defer cancelTrading()
|
||||
|
||||
environ := bbgo.NewEnvironment()
|
||||
|
||||
if viper.IsSet("mysql-url") {
|
||||
dsn := viper.GetString("mysql-url")
|
||||
func BootstrapEnvironment(ctx context.Context, environ *bbgo.Environment, userConfig *bbgo.Config) error {
|
||||
if dsn, ok := os.LookupEnv("MYSQL_URL") ; ok {
|
||||
if err := environ.ConfigureDatabase(ctx, dsn); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -230,8 +225,10 @@ func runConfig(basectx context.Context, userConfig *bbgo.Config, enableApiServer
|
|||
}
|
||||
}
|
||||
|
||||
trader := bbgo.NewTrader(environ)
|
||||
return nil
|
||||
}
|
||||
|
||||
func ConfigureTrader(trader *bbgo.Trader, userConfig *bbgo.Config) error {
|
||||
if userConfig.RiskControls != nil {
|
||||
trader.SetRiskControls(userConfig.RiskControls)
|
||||
}
|
||||
|
@ -262,6 +259,23 @@ func runConfig(basectx context.Context, userConfig *bbgo.Config, enableApiServer
|
|||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runConfig(basectx context.Context, userConfig *bbgo.Config, enableApiServer bool) error {
|
||||
ctx, cancelTrading := context.WithCancel(basectx)
|
||||
defer cancelTrading()
|
||||
|
||||
environ := bbgo.NewEnvironment()
|
||||
if err := BootstrapEnvironment(ctx, environ, userConfig) ; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trader := bbgo.NewTrader(environ)
|
||||
if err := ConfigureTrader(trader, userConfig) ; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trader.Subscribe()
|
||||
|
||||
if err := trader.Run(ctx); err != nil {
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func pingUntil(ctx context.Context, baseURL string, callback func()) {
|
||||
func PingUntil(ctx context.Context, baseURL string, callback func()) {
|
||||
pingURL := baseURL + "/api/ping"
|
||||
timeout := time.NewTimer(time.Minute)
|
||||
|
||||
|
@ -37,7 +37,7 @@ func pingUntil(ctx context.Context, baseURL string, callback func()) {
|
|||
|
||||
func pingAndOpenURL(ctx context.Context, baseURL string) {
|
||||
setupURL := baseURL + "/setup"
|
||||
go pingUntil(ctx, baseURL, func() {
|
||||
go PingUntil(ctx, baseURL, func() {
|
||||
if err := openURL(setupURL); err != nil {
|
||||
logrus.WithError(err).Errorf("can not call open command to open the web page")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user