WIP dynamic start

This commit is contained in:
Michael Bumann 2024-01-21 13:08:16 +01:00
parent 904893c5ab
commit 02e39d7ac0
15 changed files with 219 additions and 180 deletions

15
api.go
View file

@ -208,10 +208,23 @@ func (svc *Service) ListApps() ([]api.App, error) {
func (svc *Service) GetInfo() *api.InfoResponse {
info := api.InfoResponse{}
info.BackendType = svc.cfg.LNBackendType
info.SetupCompleted = svc.lnClient != nil
info.SetupCompleted = svc.cfg.LNBackendType != ""
info.Running = svc.lnClient != nil
return &info
}
func (svc *Service) Start(startRequest *api.StartRequest) (*api.InfoResponse, error) {
err := svc.StartApp()
if err != nil {
panic(err)
}
info := api.InfoResponse{}
info.BackendType = svc.cfg.LNBackendType
info.SetupCompleted = svc.lnClient != nil
info.Running = svc.lnClient != nil
return &info, nil
}
func (svc *Service) Setup(setupRequest *api.SetupRequest) error {
dbConfig := db.Config{}

View file

@ -48,6 +48,7 @@ func (svc *Service) RegisterSharedRoutes(e *echo.Echo) {
e.GET("/api/info", svc.InfoHandler)
e.POST("/api/logout", svc.LogoutHandler)
e.POST("/api/setup", svc.SetupHandler)
e.POST("/api/start", svc.StartHandler)
frontend.RegisterHandlers(e)
}
@ -67,6 +68,18 @@ func (svc *Service) InfoHandler(c echo.Context) error {
return c.JSON(http.StatusOK, responseBody)
}
func (svc *Service) StartHandler(c echo.Context) error {
var startRequest api.StartRequest
if err := c.Bind(&startRequest); err != nil {
return c.JSON(http.StatusBadRequest, ErrorResponse{
Message: fmt.Sprintf("Bad request: %s", err.Error()),
})
}
responseBody, _ := svc.Start(&startRequest)
return c.JSON(http.StatusOK, responseBody)
}
func (svc *Service) LogoutHandler(c echo.Context) error {
sess, err := session.Get(CookieName, c)
if err != nil {

View file

@ -4,9 +4,9 @@
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"dev:http": "yarn prepare:http && vite",
"dev:wails": "yarn prepare:wails && VITE_NWC_APP_TYPE=WAILS vite",
"build": "tsc && vite build",
"build:http": "yarn prepare:http && tsc && vite build",
"prepare:wails": "cp ./platform_specific/wails/src/utils/request.ts src/utils/request.ts",
"prepare:http": "cp ./platform_specific/http/src/utils/request.ts src/utils/request.ts",
"build:wails": "yarn prepare:wails && tsc && VITE_NWC_APP_TYPE=WAILS vite build",

View file

@ -13,6 +13,7 @@ import NotFound from "src/screens/NotFound";
import { useInfo } from "./hooks/useInfo";
import Loading from "./components/Loading";
import { Setup } from "./screens/Setup";
import Start from "./screens/Start";
function App() {
const { data: info } = useInfo();
@ -21,21 +22,23 @@ function App() {
return <Loading />;
}
let home;
if (info?.setupCompleted && info.running) {
home = "/apps";
} else if (info.setupCompleted && !info.running) {
home = "/start";
} else {
home = "/setup";
}
return (
<div className="bg:white dark:bg-black min-h-full">
<div className="bg:white min-h-full dark:bg-black">
<Toaster />
<HashRouter>
<Routes>
<Route path="/" element={<Navbar />}>
<Route
index
element={
<Navigate
to={info.setupCompleted ? "/apps" : "/setup"}
replace
/>
}
/>
<Route index element={<Navigate to={home} replace />} />
<Route path="start" element={<Start />} />
<Route path="setup" element={<Setup />} />
<Route path="apps" element={<AppsList />} />
<Route path="apps/:pubkey" element={<ShowApp />} />

View file

@ -1,6 +1,6 @@
import React from "react";
import { useNavigate } from "react-router-dom";
import Loading from "src/components/Loading";
import ConnectButton from "src/components/ConnectButton";
import { useCSRF } from "src/hooks/useCSRF";
import { useInfo } from "src/hooks/useInfo";
import { BackendType } from "src/types";
@ -62,7 +62,7 @@ export function Setup() {
value={backendType}
onChange={(e) => setBackendType(e.target.value as BackendType)}
id="backend-type"
className="mb-4 bg-gray-50 border border-gray-300 text-gray-900 focus:ring-purple-700 dark:focus:ring-purple-600 dark:ring-offset-gray-800 focus:ring-2 text-sm rounded-lg block w-full p-2.5 dark:bg-surface-00dp dark:border-gray-700 dark:placeholder-gray-400 dark:text-white"
className="dark:bg-surface-00dp mb-4 block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:ring-2 focus:ring-purple-700 dark:border-gray-700 dark:text-white dark:placeholder-gray-400 dark:ring-offset-gray-800 dark:focus:ring-purple-600"
>
<option value={"BREEZ"}>Breez</option>
<option value={"LND"}>LND</option>
@ -78,30 +78,6 @@ export function Setup() {
);
}
type ConnectButtonProps = {
isConnecting: boolean;
};
function ConnectButton({ isConnecting }: ConnectButtonProps) {
return (
<button
type="submit"
className={`mt-4 gap-2 inline-flex w-full ${
isConnecting ? "bg-gray-300 dark:bg-gray-700" : "bg-purple-700"
} cursor-pointer dark:text-neutral-200 duration-150 focus-visible:ring-2 focus-visible:ring-offset-2 focus:outline-none font-medium hover:bg-purple-900 items-center justify-center px-5 py-3 rounded-md shadow text-white transition`}
disabled={isConnecting}
>
{isConnecting ? (
<>
<Loading /> Connecting...
</>
) : (
<>Connect</>
)}
</button>
);
}
type SetupFormProps = {
isConnecting: boolean;
handleSubmit(data: unknown): void;
@ -141,7 +117,7 @@ function BreezForm({ isConnecting, handleSubmit }: SetupFormProps) {
value={greenlightInviteCode}
type="password"
id="greenlight-invite-code"
className="bg-gray-50 border border-gray-300 text-gray-900 focus:ring-purple-700 dark:focus:ring-purple-600 dark:ring-offset-gray-800 focus:ring-2 text-sm rounded-lg block w-full p-2.5 dark:bg-surface-00dp dark:border-gray-700 dark:placeholder-gray-400 dark:text-white"
className="dark:bg-surface-00dp block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:ring-2 focus:ring-purple-700 dark:border-gray-700 dark:text-white dark:placeholder-gray-400 dark:ring-offset-gray-800 dark:focus:ring-purple-600"
/>
<label
htmlFor="breez-api-key"
@ -155,7 +131,7 @@ function BreezForm({ isConnecting, handleSubmit }: SetupFormProps) {
value={breezApiKey}
type="password"
id="breez-api-key"
className="bg-gray-50 border border-gray-300 text-gray-900 focus:ring-purple-700 dark:focus:ring-purple-600 dark:ring-offset-gray-800 focus:ring-2 text-sm rounded-lg block w-full p-2.5 dark:bg-surface-00dp dark:border-gray-700 dark:placeholder-gray-400 dark:text-white"
className="dark:bg-surface-00dp block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:ring-2 focus:ring-purple-700 dark:border-gray-700 dark:text-white dark:placeholder-gray-400 dark:ring-offset-gray-800 dark:focus:ring-purple-600"
/>
<label
htmlFor="mnemonic"
@ -169,7 +145,7 @@ function BreezForm({ isConnecting, handleSubmit }: SetupFormProps) {
value={breezMnemonic}
type="password"
id="mnemonic"
className="bg-gray-50 border border-gray-300 text-gray-900 focus:ring-purple-700 dark:focus:ring-purple-600 dark:ring-offset-gray-800 focus:ring-2 text-sm rounded-lg block w-full p-2.5 dark:bg-surface-00dp dark:border-gray-700 dark:placeholder-gray-400 dark:text-white"
className="dark:bg-surface-00dp block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:ring-2 focus:ring-purple-700 dark:border-gray-700 dark:text-white dark:placeholder-gray-400 dark:ring-offset-gray-800 dark:focus:ring-purple-600"
/>
</>
<ConnectButton isConnecting={isConnecting} />
@ -209,7 +185,7 @@ function LNDForm({ isConnecting, handleSubmit }: SetupFormProps) {
onChange={(e) => setLndAddress(e.target.value)}
value={lndAddress}
id="lnd-address"
className="bg-gray-50 border border-gray-300 text-gray-900 focus:ring-purple-700 dark:focus:ring-purple-600 dark:ring-offset-gray-800 focus:ring-2 text-sm rounded-lg block w-full p-2.5 dark:bg-surface-00dp dark:border-gray-700 dark:placeholder-gray-400 dark:text-white"
className="dark:bg-surface-00dp block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:ring-2 focus:ring-purple-700 dark:border-gray-700 dark:text-white dark:placeholder-gray-400 dark:ring-offset-gray-800 dark:focus:ring-purple-600"
/>
<label
@ -224,7 +200,7 @@ function LNDForm({ isConnecting, handleSubmit }: SetupFormProps) {
value={lndCertHex}
type="password"
id="lnd-cert-hex"
className="bg-gray-50 border border-gray-300 text-gray-900 focus:ring-purple-700 dark:focus:ring-purple-600 dark:ring-offset-gray-800 focus:ring-2 text-sm rounded-lg block w-full p-2.5 dark:bg-surface-00dp dark:border-gray-700 dark:placeholder-gray-400 dark:text-white"
className="dark:bg-surface-00dp block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:ring-2 focus:ring-purple-700 dark:border-gray-700 dark:text-white dark:placeholder-gray-400 dark:ring-offset-gray-800 dark:focus:ring-purple-600"
/>
<label
htmlFor="lnd-macaroon-hex"
@ -238,7 +214,7 @@ function LNDForm({ isConnecting, handleSubmit }: SetupFormProps) {
value={lndMacaroonHex}
type="password"
id="lnd-macaroon-hex"
className="bg-gray-50 border border-gray-300 text-gray-900 focus:ring-purple-700 dark:focus:ring-purple-600 dark:ring-offset-gray-800 focus:ring-2 text-sm rounded-lg block w-full p-2.5 dark:bg-surface-00dp dark:border-gray-700 dark:placeholder-gray-400 dark:text-white"
className="dark:bg-surface-00dp block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:ring-2 focus:ring-purple-700 dark:border-gray-700 dark:text-white dark:placeholder-gray-400 dark:ring-offset-gray-800 dark:focus:ring-purple-600"
/>
</>
<ConnectButton isConnecting={isConnecting} />

View file

@ -0,0 +1,62 @@
import React from "react";
import { useNavigate } from "react-router-dom";
import { useCSRF } from "src/hooks/useCSRF";
import { request, handleRequestError } from "src/utils/request";
import ConnectButton from "src/components/ConnectButton";
export default function Start() {
const [unlockPassword, setUnlockPassword] = React.useState("");
const [loading, setLoading] = React.useState(false);
const navigate = useNavigate();
const { data: csrf } = useCSRF();
async function onSubmit(e: React.FormEvent) {
e.preventDefault();
try {
setLoading(true);
if (!csrf) {
throw new Error("info not loaded");
}
const res = await request("/api/start", {
method: "POST",
headers: {
"X-CSRF-Token": csrf,
"Content-Type": "application/json",
},
body: JSON.stringify({
unlockPassword,
}),
});
console.log({ res });
navigate("/apps");
} catch (error) {
handleRequestError("Failed to connect", error);
} finally {
setLoading(false);
}
}
return (
<>
<form onSubmit={onSubmit}>
<>
<label
htmlFor="greenlight-invite-code"
className="block font-medium text-gray-900 dark:text-white"
>
Unlock password
</label>
<input
name="unlock"
onChange={(e) => setUnlockPassword(e.target.value)}
value={unlockPassword}
type="password"
className="dark:bg-surface-00dp block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:ring-2 focus:ring-purple-700 dark:border-gray-700 dark:text-white dark:placeholder-gray-400 dark:ring-offset-gray-800 dark:focus:ring-purple-600"
/>
<ConnectButton isConnecting={loading} />
</>
</form>
</>
);
}

View file

@ -19,7 +19,7 @@ export type BudgetRenewalType = "daily" | "weekly" | "monthly" | "yearly" | "";
export type IconMap = {
[key in RequestMethodType]: (
props: React.SVGAttributes<SVGElement>
props: React.SVGAttributes<SVGElement>,
) => JSX.Element;
};
@ -89,6 +89,7 @@ export interface NostrEvent {
export interface InfoResponse {
backendType: BackendType;
setupCompleted: boolean;
running: boolean;
}
export interface CreateAppResponse {

1
go.mod
View file

@ -13,6 +13,7 @@ require (
github.com/labstack/echo/v4 v4.10.2
github.com/nbd-wtf/go-nostr v0.25.5
github.com/nbd-wtf/ln-decodepay v1.11.1
github.com/orandin/lumberjackrus v1.0.1
github.com/stretchr/testify v1.8.2
github.com/wailsapp/wails/v2 v2.7.1
google.golang.org/grpc v1.53.0

2
go.sum
View file

@ -656,6 +656,8 @@ github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAl
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/orandin/lumberjackrus v1.0.1 h1:7ysDQ0MHD79zIFN9/EiDHjUcgopNi5ehtxFDy8rUkWo=
github.com/orandin/lumberjackrus v1.0.1/go.mod h1:xYLt6H8W93pKnQgUQaxsApS0Eb4BwHLOkxk5DVzf5H0=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pierrec/lz4/v4 v4.0.3/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=

199
main.go
View file

@ -15,158 +15,97 @@ import (
"github.com/joho/godotenv"
"github.com/kelseyhightower/envconfig"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip19"
"github.com/orandin/lumberjackrus"
log "github.com/sirupsen/logrus"
"gorm.io/gorm"
)
// TODO: move to service.go
func NewService(ctx context.Context) *Service {
func NewService(ctx context.Context) (*Service, error) {
// Load config from environment variables / .env file
godotenv.Load(".env")
cfg := &Config{}
err := envconfig.Process("", cfg)
if err != nil {
log.Fatalf("Error loading environment variables: %v", err)
}
var db *gorm.DB
var sqlDb *sql.DB
db, err = gorm.Open(sqlite.Open(cfg.DatabaseUri), &gorm.Config{})
if err != nil {
log.Fatalf("Failed to open DB %v", err)
}
// Override SQLite config to max one connection
cfg.DatabaseMaxConns = 1
// Enable foreign keys for sqlite
db.Exec("PRAGMA foreign_keys=ON;")
sqlDb, err = db.DB()
if err != nil {
log.Fatalf("Failed to set DB config: %v", err)
}
sqlDb.SetMaxOpenConns(cfg.DatabaseMaxConns)
sqlDb.SetMaxIdleConns(cfg.DatabaseMaxIdleConns)
sqlDb.SetConnMaxLifetime(time.Duration(cfg.DatabaseConnMaxLifetime) * time.Second)
err = migrations.Migrate(db)
if err != nil {
log.Fatalf("Migration failed: %v", err)
}
log.Println("Any pending migrations ran successfully")
ctx, _ = signal.NotifyContext(ctx, os.Interrupt)
var wg sync.WaitGroup
wg.Add(1)
svc := &Service{
cfg: cfg,
db: db,
ctx: ctx,
wg: &wg,
}
dbConfig, err := svc.setupDbConfig()
if err != nil {
log.Fatalf("Failed to setup DB config: %v", err)
}
// TODO: should not re-set config like this
cfg.NostrSecretKey = dbConfig.NostrSecretKey
if cfg.NostrSecretKey == "" {
log.Fatalf("No nostr secret key set")
}
// calculate pubkey
identityPubkey, err := nostr.GetPublicKey(cfg.NostrSecretKey)
if err != nil {
log.Fatalf("Error converting nostr privkey to pubkey: %v", err)
}
// TODO: should not re-set config like this
cfg.IdentityPubkey = identityPubkey
npub, err := nip19.EncodePublicKey(identityPubkey)
if err != nil {
log.Fatalf("Error converting nostr privkey to pubkey: %v", err)
return nil, err
}
logger := log.New()
logger.SetFormatter(&log.JSONFormatter{})
logger.SetOutput(os.Stdout)
logger.SetLevel(log.InfoLevel)
svc.Logger = logger
logger.Infof("Starting nostr-wallet-connect. npub: %s hex: %s", npub, identityPubkey)
err = svc.launchLNBackend()
hook, err := lumberjackrus.NewHook(
&lumberjackrus.LogFile{
Filename: "nwc.general.log",
},
log.InfoLevel,
&log.JSONFormatter{},
&lumberjackrus.LogFileOpts{
log.InfoLevel: &lumberjackrus.LogFile{
Filename: "./log/nwc-info.log",
MaxAge: 1,
MaxBackups: 2,
},
log.ErrorLevel: &lumberjackrus.LogFile{
Filename: "./log/nwc-error.log",
MaxAge: 1,
MaxBackups: 2,
},
},
)
if err != nil {
// LN backend not needed immediately, just log errors
svc.Logger.Warnf("Failed to launch LN backend: %v", err)
return nil, err
}
logger.AddHook(hook)
var db *gorm.DB
var sqlDb *sql.DB
db, err = gorm.Open(sqlite.Open(cfg.DatabaseUri), &gorm.Config{})
if err != nil {
return nil, err
}
// Enable foreign keys for sqlite
db.Exec("PRAGMA foreign_keys=ON;")
sqlDb, err = db.DB()
if err != nil {
return nil, err
}
sqlDb.SetMaxOpenConns(1)
sqlDb.SetMaxIdleConns(5)
sqlDb.SetConnMaxLifetime(time.Duration(1800) * time.Second)
err = migrations.Migrate(db)
if err != nil {
return nil, err
}
go func() {
//connect to the relay
svc.Logger.Infof("Connecting to the relay: %s", cfg.Relay)
ctx, _ = signal.NotifyContext(ctx, os.Interrupt)
relay, err := nostr.RelayConnect(ctx, cfg.Relay, nostr.WithNoticeHandler(svc.noticeHandler))
if err != nil {
svc.Logger.Errorf("Failed to connect to relay: %v", err)
wg.Done()
return
}
var wg sync.WaitGroup
svc := &Service{
cfg: cfg,
db: db,
ctx: ctx,
wg: &wg,
Logger: logger,
}
//publish event with NIP-47 info
err = svc.PublishNip47Info(ctx, relay)
if err != nil {
svc.Logger.WithError(err).Error("Could not publish NIP47 info")
}
//Start infinite loop which will be only broken by canceling ctx (SIGINT)
//TODO: we can start this loop for multiple relays
for {
svc.Logger.Info("Subscribing to events")
sub, err := relay.Subscribe(ctx, svc.createFilters())
if err != nil {
svc.Logger.Fatal(err)
}
err = svc.StartSubscription(ctx, sub)
if err != nil {
//err being non-nil means that we have an error on the websocket error channel. In this case we just try to reconnect.
svc.Logger.WithError(err).Error("Got an error from the relay while listening to subscription. Reconnecting...")
relay, err = nostr.RelayConnect(ctx, cfg.Relay)
if err != nil {
svc.Logger.Fatal(err)
}
continue
}
//err being nil means that the context was canceled and we should exit the program.
break
}
svc.Logger.Info("Disconnecting from relay...")
err = relay.Close()
if err != nil {
svc.Logger.Error(err)
}
if svc.lnClient != nil {
svc.Logger.Info("Shutting down LN backend...")
err = svc.lnClient.Shutdown()
if err != nil {
svc.Logger.Error(err)
}
}
svc.Logger.Info("Relay subroutine ended")
wg.Done()
}()
return svc
return svc, nil
}
func (svc *Service) setupDbConfig() (*db.Config, error) {
func (svc *Service) loadConfig() (*db.Config, error) {
// setup database config from the env on first run
// after first run, changes to ENV will have no effect for these fields
// because the database values always take precedence!
godotenv.Load(".env")
cfg := &Config{}
err := envconfig.Process("", cfg)
if err != nil {
return nil, err
}
var existingDbConfig db.Config
res := svc.db.Limit(1).Find(&existingDbConfig)
@ -185,7 +124,6 @@ func (svc *Service) setupDbConfig() (*db.Config, error) {
}
newDbConfig := db.Config{
ID: 1,
LNBackendType: svc.cfg.LNBackendType,
LNDAddress: svc.cfg.LNDAddress,
LNDCertHex: svc.cfg.LNDCertHex,
@ -207,7 +145,7 @@ func (svc *Service) launchLNBackend() error {
if svc.lnClient != nil {
err := svc.lnClient.Shutdown()
if err != nil {
svc.Logger.Fatalf("Failed to disconnect from current node: %v", err)
return err
}
svc.lnClient = nil
}
@ -219,8 +157,15 @@ func (svc *Service) launchLNBackend() error {
return errors.New("No LNBackendType specified")
}
svc.cfg.NostrSecretKey = dbConfig.NostrSecretKey
identityPubkey, err := nostr.GetPublicKey(svc.cfg.NostrSecretKey)
if err != nil {
log.Fatalf("Error converting nostr privkey to pubkey: %v", err)
}
// TODO: should not re-set config like this
svc.cfg.IdentityPubkey = identityPubkey
svc.Logger.Infof("Launching LN Backend: %s", dbConfig.LNBackendType)
var err error
var lnClient LNClient
switch dbConfig.LNBackendType {
case LNDBackendType:

View file

@ -21,11 +21,7 @@ import (
func main() {
log.Info("NWC Starting in HTTP mode")
ctx := context.Background()
svc := NewService(ctx)
if svc.cfg.CookieSecret == "" {
svc.Logger.Fatalf("required key COOKIE_SECRET missing value")
}
svc, _ := NewService(ctx)
echologrus.Logger = svc.Logger
e := echo.New()
@ -35,7 +31,7 @@ func main() {
//start Echo server
go func() {
if err := e.Start(fmt.Sprintf(":%v", svc.cfg.Port)); err != nil && err != http.ErrServerClosed {
e.Logger.Fatalf("shutting down the server: %v", err)
svc.Logger.Fatalf("shutting down the server: %v", err)
}
}()
//handle graceful shutdown

View file

@ -14,7 +14,7 @@ import (
func main() {
log.Info("NWC Starting in WAILS mode")
ctx, cancel := context.WithCancel(context.Background())
svc := NewService(ctx)
svc, _ := NewService(ctx)
app := NewApp(svc)
LaunchWailsApp(app)

View file

@ -32,6 +32,10 @@ type CreateAppRequest struct {
ReturnTo string `json:"returnTo"`
}
type StartRequest struct {
unlockPassword string `json:"unlockPassword"`
}
type SetupRequest struct {
LNBackendType string `json:"backendType"`
// Breez fields
@ -61,4 +65,5 @@ type User struct {
type InfoResponse struct {
BackendType string `json:"backendType"`
SetupCompleted bool `json:"setupCompleted"`
Running bool `json:"running"`
}

View file

@ -36,6 +36,7 @@ func LaunchWailsApp(app *WailsApp) {
AssetServer: &assetserver.Options{
Assets: assets,
},
HideWindowOnClose: true,
//BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1},
OnStartup: app.startup,
Bind: []interface{}{

View file

@ -77,6 +77,27 @@ func (a *WailsApp) WailsRequestRouter(route string, method string, body string)
infoResponse := a.svc.GetInfo()
res := WailsRequestRouterResponse{Body: *infoResponse, Error: ""}
return res
case "/api/start":
startRequest := &api.StartRequest{}
err := json.Unmarshal([]byte(body), startRequest)
if err != nil {
a.svc.Logger.WithFields(logrus.Fields{
"route": route,
"method": method,
"body": body,
}).Errorf("Failed to decode request to wails router: %v", err)
return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
}
res, err := a.svc.Start(startRequest)
if err != nil {
a.svc.Logger.WithFields(logrus.Fields{
"route": route,
"method": method,
"body": body,
}).Errorf("Failed to setup node: %v", err)
return WailsRequestRouterResponse{Body: res, Error: err.Error()}
}
return WailsRequestRouterResponse{Body: res, Error: ""}
case "/api/csrf":
return WailsRequestRouterResponse{Body: "dummy", Error: ""}
case "/api/setup":