Skip to content
This repository has been archived by the owner on Feb 1, 2024. It is now read-only.

Commit

Permalink
Kelp GUI: kaas mode, quit() disabled in KaaS mode, update AppName (cl…
Browse files Browse the repository at this point in the history
…oses #687) (#689)

* 1 - add enable-kaas mode to server command; trade.go accepts --trigger as 'ui' or 'kaas' instead of bool --ui flag

- update AppName to include difference between trigger mode 'ui' and 'kaas'
- disable /quit endpoint, logic, frontend button if kaas is enabled (and by default until we get server metadata)
- new constants.go file (and support/constants package)

* 2 - validate trigger input

* 3 - log cli input flags

* 4 - move log file in server to be after logging setup

* 5 - log client.AppName being used in trade.go

* 6 - add correct AppName in server.go for kaas trigger and log
  • Loading branch information
nikhilsaraf authored Apr 8, 2021
1 parent 6ad2cde commit 0bc17c7
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 37 deletions.
63 changes: 42 additions & 21 deletions cmd/server_amd64.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const readyPlaceholder = "READY_STRING"
const readyStringIndicator = "Serving frontend and API server on HTTP port"
const downloadCcxtUpdateIntervalLogMillis = 1000

type serverInputs struct {
type serverInputOptions struct {
port *uint16
dev *bool
devAPIPort *uint16
Expand All @@ -68,19 +68,27 @@ type serverInputs struct {
verbose *bool
noElectron *bool
disablePubnet *bool
enableKaas *bool
}

// String is the stringer method impl.
func (o serverInputOptions) String() string {
return fmt.Sprintf("serverInputOptions[port=%d, dev=%v, devAPIPort=%d, horizonTestnetURI='%s', horizonPubnetURI='%s', noHeaders=%v, verbose=%v, noElectron=%v, disablePubnet=%v, enableKaas=%v]",
*o.port, *o.dev, *o.devAPIPort, *o.horizonTestnetURI, *o.horizonPubnetURI, *o.noHeaders, *o.verbose, *o.noElectron, *o.disablePubnet, *o.enableKaas)
}

func init() {
options := serverInputs{}
options := serverInputOptions{}
options.port = serverCmd.Flags().Uint16P("port", "p", 8000, "port on which to serve")
options.dev = serverCmd.Flags().Bool("dev", false, "run in dev mode for hot-reloading of JS code")
options.devAPIPort = serverCmd.Flags().Uint16("dev-api-port", 8001, "port on which to run API server when in dev mode")
options.horizonTestnetURI = serverCmd.Flags().String("horizon-testnet-uri", "https://horizon-testnet.stellar.org", "URI to use for the horizon instance connected to the Stellar Test Network (must contain the word 'test')")
options.horizonPubnetURI = serverCmd.Flags().String("horizon-pubnet-uri", "https://horizon.stellar.org", "URI to use for the horizon instance connected to the Stellar Public Network (must not contain the word 'test')")
options.noHeaders = serverCmd.Flags().Bool("no-headers", false, "do not use Amplitude or set X-App-Name and X-App-Version headers on requests to horizon")
options.verbose = serverCmd.Flags().BoolP("verbose", "v", false, "enable verbose log lines typically used for debugging")
options.noElectron = serverCmd.Flags().Bool("no-electron", false, "open in browser instead of using electron")
options.noElectron = serverCmd.Flags().Bool("no-electron", false, "open in browser instead of using electron, only applies when not in KaaS mode")
options.disablePubnet = serverCmd.Flags().Bool("disable-pubnet", false, "disable pubnet option")
options.enableKaas = serverCmd.Flags().Bool("enable-kaas", false, "enable kelp-as-a-service (KaaS) mode, which does not bring up browser or electron")

serverCmd.Run = func(ccmd *cobra.Command, args []string) {
isLocalMode := env == envDev
Expand Down Expand Up @@ -126,6 +134,8 @@ func init() {
}
}

log.Printf("initialized server with cli flag inputs: %s", options)

if runtime.GOOS == "windows" {
if !*options.noElectron {
log.Printf("input options had specified noElectron=false for windows, but electron is not supported on windows yet. force setting noElectron=true for windows.\n")
Expand Down Expand Up @@ -180,15 +190,18 @@ func init() {
electronURL = tailFilepath.Native()
}

// kick off the desktop window for UI feedback to the user
// local mode (non --dev) and release binary should open browser (since --dev already opens browser via yarn and returns)
go func() {
if *options.noElectron {
openBrowser(appURL, openBrowserWg)
} else {
openElectron(trayIconPath, electronURL)
}
}()
// only open browser or electron when not running in kaas mode
if !*options.enableKaas {
// kick off the desktop window for UI feedback to the user
// local mode (non --dev) and release binary should open browser (since --dev already opens browser via yarn and returns)
go func() {
if *options.noElectron {
openBrowser(appURL, openBrowserWg)
} else {
openElectron(trayIconPath, electronURL)
}
}()
}
}

log.Printf("Starting Kelp GUI Server, gui=%s, cli=%s [%s]\n", guiVersion, version, gitHash)
Expand Down Expand Up @@ -223,12 +236,17 @@ func init() {
HTTP: http.DefaultClient,
}
if !*options.noHeaders {
if *options.noElectron {
apiTestNet.AppName = "kelp--gui-desktop--admin-browser"
apiPubNet.AppName = "kelp--gui-desktop--admin-browser"
if *options.enableKaas {
apiTestNet.AppName = "kelp--gui-kaas--admin"
apiPubNet.AppName = "kelp--gui-kaas--admin"
} else {
apiTestNet.AppName = "kelp--gui-desktop--admin-electron"
apiPubNet.AppName = "kelp--gui-desktop--admin-electron"
if *options.noElectron {
apiTestNet.AppName = "kelp--gui-desktop--admin-browser"
apiPubNet.AppName = "kelp--gui-desktop--admin-browser"
} else {
apiTestNet.AppName = "kelp--gui-desktop--admin-electron"
apiPubNet.AppName = "kelp--gui-desktop--admin-electron"
}
}

apiTestNet.AppVersion = version
Expand All @@ -245,6 +263,7 @@ func init() {
}
}
}
log.Printf("using apiTestNet.AppName = '%s' and apiPubNet.AppName = '%s'", apiTestNet.AppName, apiPubNet.AppName)

if isLocalDevMode {
log.Printf("not checking ccxt in local dev mode")
Expand Down Expand Up @@ -346,6 +365,7 @@ func init() {
apiPubNet,
*rootCcxtRestURL,
*options.disablePubnet,
*options.enableKaas,
*options.noHeaders,
quit,
metricsTracker,
Expand All @@ -364,7 +384,7 @@ func init() {
// the frontend app checks the REACT_APP_API_PORT variable to be set when serving
os.Setenv("REACT_APP_API_PORT", fmt.Sprintf("%d", *options.devAPIPort))
go runAPIServerDevBlocking(s, *options.port, *options.devAPIPort)
runWithYarn(kos, options, guiWebPath)
runWithYarn(kos, *options.port, guiWebPath)

log.Printf("should not have reached here after running yarn")
return
Expand Down Expand Up @@ -574,11 +594,11 @@ func runAPIServerDevBlocking(s *backend.APIServer, frontendPort uint16, devAPIPo
log.Fatal(e)
}

func runWithYarn(kos *kelpos.KelpOS, options serverInputs, guiWebPath *kelpos.OSPath) {
func runWithYarn(kos *kelpos.KelpOS, port uint16, guiWebPath *kelpos.OSPath) {
// yarn requires the PORT variable to be set when serving
os.Setenv("PORT", fmt.Sprintf("%d", *options.port))
os.Setenv("PORT", fmt.Sprintf("%d", port))

log.Printf("Serving frontend via yarn on HTTP port: %d\n", *options.port)
log.Printf("Serving frontend via yarn on HTTP port: %d\n", port)
e := kos.StreamOutput(exec.Command("yarn", "--cwd", guiWebPath.Unix(), "start"))
if e != nil {
panic(e)
Expand Down Expand Up @@ -710,6 +730,7 @@ func openElectron(trayIconPath *kelpos.OSPath, url string) {
}

func quit() {
// this is still valid when running in KaaS mode since it doesn't matter. we can disable it (or make it error) if we wanted
log.Printf("quitting...")
os.Exit(0)
}
Expand Down
18 changes: 13 additions & 5 deletions cmd/trade.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/stellar/kelp/kelpdb"
"github.com/stellar/kelp/model"
"github.com/stellar/kelp/plugins"
"github.com/stellar/kelp/support/constants"
"github.com/stellar/kelp/support/database"
"github.com/stellar/kelp/support/logger"
"github.com/stellar/kelp/support/monitoring"
Expand Down Expand Up @@ -105,7 +106,7 @@ type inputs struct {
logPrefix *string
fixedIterations *uint64
noHeaders *bool
ui *bool
trigger *string
cpuProfile *string
memProfile *string
}
Expand All @@ -127,6 +128,10 @@ func validateCliParams(l logger.Logger, options inputs) {
} else {
l.Infof("will run only %d update iterations\n", *options.fixedIterations)
}

if *options.trigger != constants.TriggerDefault && *options.trigger != constants.TriggerUI && *options.trigger != constants.TriggerKaas {
panic(fmt.Sprintf("invalid trigger argument: '%s'", *options.trigger))
}
}

func validateBotConfig(l logger.Logger, botConfig trader.BotConfig) {
Expand Down Expand Up @@ -167,15 +172,15 @@ func init() {
options.logPrefix = tradeCmd.Flags().StringP("log", "l", "", "log to a file (and stdout) with this prefix for the filename")
options.fixedIterations = tradeCmd.Flags().Uint64("iter", 0, "only run the bot for the first N iterations (defaults value 0 runs unboundedly)")
options.noHeaders = tradeCmd.Flags().Bool("no-headers", false, "do not use Amplitude or set X-App-Name and X-App-Version headers on requests to horizon")
options.ui = tradeCmd.Flags().Bool("ui", false, "indicates a bot that is started from the Kelp UI server")
options.trigger = tradeCmd.Flags().String("trigger", constants.TriggerDefault, fmt.Sprintf("indicates a bot that is triggered from a parent process ('%s' or '%s')", constants.TriggerUI, constants.TriggerKaas))
options.cpuProfile = tradeCmd.Flags().String("cpuprofile", "", "write cpu profile to `file`")
options.memProfile = tradeCmd.Flags().String("memprofile", "", "write memory profile to `file`")

requiredFlag("botConf")
requiredFlag("strategy")
hiddenFlag("operationalBuffer")
hiddenFlag("operationalBufferNonNativePct")
hiddenFlag("ui")
hiddenFlag("trigger")
tradeCmd.Flags().SortFlags = false

tradeCmd.Run = func(ccmd *cobra.Command, args []string) {
Expand Down Expand Up @@ -564,7 +569,7 @@ func runTradeCmd(options inputs) {
l.Infof("Trading %s:%s for %s:%s\n", botConfig.AssetCodeA, botConfig.IssuerA, botConfig.AssetCodeB, botConfig.IssuerB)

var guiVersionFlag string
if *options.ui {
if *options.trigger == constants.TriggerUI || *options.trigger == constants.TriggerKaas {
guiVersionFlag = guiVersion
}

Expand Down Expand Up @@ -644,8 +649,10 @@ func runTradeCmd(options inputs) {
}
if !*options.noHeaders {
client.AppName = "kelp--cli--bot"
if *options.ui {
if *options.trigger == constants.TriggerUI {
client.AppName = "kelp--gui-desktop--bot"
} else if *options.trigger == constants.TriggerKaas {
client.AppName = "kelp--gui-kaas--bot"
}
client.AppVersion = version

Expand All @@ -660,6 +667,7 @@ func runTradeCmd(options inputs) {
}
}
}
log.Printf("using client.AppName = %s", client.AppName)

if *rootCcxtRestURL == "" && botConfig.CcxtRestURL != nil {
e := sdk.SetBaseURL(*botConfig.CcxtRestURL)
Expand Down
3 changes: 3 additions & 0 deletions gui/backend/api_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type APIServer struct {
apiTestNet *horizonclient.Client
apiPubNet *horizonclient.Client
disablePubnet bool
enableKaas bool
noHeaders bool
quitFn func()
metricsTracker *plugins.MetricsTracker
Expand All @@ -71,6 +72,7 @@ func MakeAPIServer(
apiPubNet *horizonclient.Client,
ccxtRestUrl string,
disablePubnet bool,
enableKaas bool,
noHeaders bool,
quitFn func(),
metricsTracker *plugins.MetricsTracker,
Expand All @@ -93,6 +95,7 @@ func MakeAPIServer(
apiTestNet: apiTestNet,
apiPubNet: apiPubNet,
disablePubnet: disablePubnet,
enableKaas: enableKaas,
noHeaders: noHeaders,
cachedOptionsMetadata: optionsMetadata,
quitFn: quitFn,
Expand Down
6 changes: 6 additions & 0 deletions gui/backend/quit.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package backend

import (
"fmt"
"net/http"
"time"
)

func (s *APIServer) quit(w http.ResponseWriter, r *http.Request) {
if s.enableKaas {
w.WriteHeader(http.StatusInternalServerError)
panic(fmt.Errorf("quit functionality should have been disabled in routes when running in KaaS mode"))
}

go func() {
// sleep so we can respond to the request
time.Sleep(1 * time.Second)
Expand Down
8 changes: 6 additions & 2 deletions gui/backend/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@ import (
"github.com/go-chi/chi"
)

// SetRoutes
// SetRoutes adds the handlers for the endpoints
func SetRoutes(r *chi.Mux, s *APIServer) {
r.Route("/api/v1", func(r chi.Router) {
if !s.enableKaas {
// /quit is only enabled when we are not in KaaS mode
r.Get("/quit", http.HandlerFunc(s.quit))
}

r.Get("/version", http.HandlerFunc(s.version))
r.Get("/quit", http.HandlerFunc(s.quit))
r.Get("/serverMetadata", http.HandlerFunc(s.serverMetadata))
r.Get("/newSecretKey", http.HandlerFunc(s.newSecretKey))
r.Get("/optionsMetadata", http.HandlerFunc(s.optionsMetadata))
Expand Down
2 changes: 2 additions & 0 deletions gui/backend/serverMetadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import (
// ServerMetadataResponse is the response from the /serverMetadata endpoint
type ServerMetadataResponse struct {
DisablePubnet bool `json:"disable_pubnet"`
EnableKaas bool `json:"enable_kaas"`
}

func (s *APIServer) serverMetadata(w http.ResponseWriter, r *http.Request) {
metadata := ServerMetadataResponse{
DisablePubnet: s.disablePubnet,
EnableKaas: s.enableKaas,
}

b, e := json.Marshal(metadata)
Expand Down
10 changes: 9 additions & 1 deletion gui/backend/start_bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/stellar/go/support/config"
"github.com/stellar/kelp/gui/model2"
"github.com/stellar/kelp/support/constants"
"github.com/stellar/kelp/support/kelpos"
"github.com/stellar/kelp/trader"
)
Expand Down Expand Up @@ -120,11 +121,18 @@ func (s *APIServer) doStartBot(userData UserData, botName string, strategy strin
return fmt.Errorf("cannnot start pubnet bots when pubnet is disabled")
}

command := fmt.Sprintf("trade -c %s -s %s -f %s -l %s --ui",
// triggerMode informs the underlying bot process how it was started so it can set anything specific on that bot that it needs to
// it is only one of these two because it is not started up manually, which would not have a trigger mode (i.e. default)
triggerMode := constants.TriggerUI
if s.enableKaas {
triggerMode = constants.TriggerKaas
}
command := fmt.Sprintf("trade -c %s -s %s -f %s -l %s --trigger %s",
traderRelativeConfigPath.Unix(),
strategy,
stratRelativeConfigPath.Unix(),
logRelativePrefixPath.Unix(),
triggerMode,
)
if iterations != nil {
command = fmt.Sprintf("%s --iter %d", command, *iterations)
Expand Down
34 changes: 26 additions & 8 deletions gui/web/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class App extends Component {

this.setVersion = this.setVersion.bind(this);
this.fetchServerMetadata = this.fetchServerMetadata.bind(this);
this.showQuitButton = this.showQuitButton.bind(this);
this.quit = this.quit.bind(this);
this.addError = this.addError.bind(this);
this.addErrorToObject = this.addErrorToObject.bind(this);
Expand Down Expand Up @@ -92,6 +93,11 @@ class App extends Component {
}

quit() {
if (!this.showQuitButton()) {
console.error("calling quit function when showQuitButton() returned false!");
return
}

var _this = this
this._asyncRequests["quit"] = quit(baseUrl).then(resp => {
if (!_this._asyncRequests["quit"]) {
Expand Down Expand Up @@ -313,20 +319,32 @@ class App extends Component {
this.setState({ "active_error": null });
}

showQuitButton() {
// showQuit defaults to false, use this instead of enableKaas so it's more explicit
return this.state.server_metadata ? !this.state.server_metadata.enable_kaas : false;
}

render() {
// construction of metricsTracker in server_amd64.go (isTestnet) needs to logically match this variable
// we use the state because that is updated from the /serverMetadata endpoint
const enablePubnetBots = this.state.server_metadata ? !this.state.server_metadata.disable_pubnet : false;

let quitButton = "";
if (this.showQuitButton()) {
quitButton = (
<Button
eventName="main-quit"
className={styles.quit}
size="small"
onClick={this.quit}
>
Quit
</Button>
);
}

let banner = (<div className={styles.banner}>
<Button
eventName="main-quit"
className={styles.quit}
size="small"
onClick={this.quit}
>
Quit
</Button>
{quitButton}
Kelp GUI (beta) v1.0.0-rc2
</div>);

Expand Down
8 changes: 8 additions & 0 deletions support/constants/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package constants

// Trigger values representing the various trigger modes of starting up a bot
const (
TriggerDefault string = ""
TriggerUI string = "ui"
TriggerKaas string = "kaas"
)

0 comments on commit 0bc17c7

Please sign in to comment.