wails_handlers.go raw
1 package wails
2
3 import (
4 "encoding/json"
5 "fmt"
6 "net/url"
7 "os"
8 "regexp"
9 "strconv"
10 "strings"
11
12 "github.com/sirupsen/logrus"
13
14 "github.com/wailsapp/wails/v2/pkg/runtime"
15
16 "github.com/getAlby/hub/alby"
17 "github.com/getAlby/hub/api"
18 "github.com/getAlby/hub/logger"
19 )
20
21 type WailsRequestRouterResponse struct {
22 Body interface{} `json:"body"`
23 Error string `json:"error"`
24 }
25
26 // TODO: make this match echo
27 func (app *WailsApp) WailsRequestRouter(route string, method string, body string) WailsRequestRouterResponse {
28 ctx := app.ctx
29
30 // the grouping is done to avoid other parameters like &unused=true
31 albyCallbackRegex := regexp.MustCompile(
32 `/api/alby/callback\?code=([^&]+)(&.*)?`,
33 )
34
35 authCodeMatch := albyCallbackRegex.FindStringSubmatch(route)
36
37 switch {
38 case len(authCodeMatch) > 1:
39 code := authCodeMatch[1]
40
41 err := app.svc.GetAlbyOAuthSvc().CallbackHandler(ctx, code)
42 if err != nil {
43 logger.Logger.WithFields(logrus.Fields{
44 "route": route,
45 "method": method,
46 }).WithError(err).Error("Failed to decode request to wails router")
47 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
48 }
49 return WailsRequestRouterResponse{Body: nil, Error: ""}
50 }
51
52 appv2Regex := regexp.MustCompile(
53 `/api/v2/apps/([0-9a-f]+)`,
54 )
55
56 appv2Match := appv2Regex.FindStringSubmatch(route)
57
58 switch {
59 case len(appv2Match) > 1:
60 appIdStr := appv2Match[1]
61
62 appId, err := strconv.ParseUint(appIdStr, 10, 64)
63 if err != nil {
64 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
65 }
66
67 dbApp := app.appsSvc.GetAppById(uint(appId))
68 if dbApp == nil {
69 return WailsRequestRouterResponse{Body: nil, Error: "App does not exist"}
70 }
71
72 switch method {
73 case "GET":
74 app, err := app.api.GetApp(dbApp)
75 if err != nil {
76 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
77 }
78 return WailsRequestRouterResponse{Body: app, Error: ""}
79 }
80 }
81
82 appRegex := regexp.MustCompile(
83 `/api/apps/([0-9a-f]+)`,
84 )
85
86 appMatch := appRegex.FindStringSubmatch(route)
87
88 switch {
89 case len(appMatch) > 1:
90 pubkey := appMatch[1]
91 dbApp := app.appsSvc.GetAppByPubkey(pubkey)
92 if dbApp == nil {
93 return WailsRequestRouterResponse{Body: nil, Error: "App does not exist"}
94 }
95
96 switch method {
97 case "GET":
98 app, err := app.api.GetApp(dbApp)
99 if err != nil {
100 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
101 }
102 return WailsRequestRouterResponse{Body: app, Error: ""}
103 case "PATCH":
104 updateAppRequest := &api.UpdateAppRequest{}
105 err := json.Unmarshal([]byte(body), updateAppRequest)
106 if err != nil {
107 logger.Logger.WithFields(logrus.Fields{
108 "route": route,
109 "method": method,
110 }).WithError(err).Error("Failed to decode request to wails router")
111 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
112 }
113 err = app.api.UpdateApp(dbApp, updateAppRequest)
114 if err != nil {
115 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
116 }
117 return WailsRequestRouterResponse{Body: nil, Error: ""}
118 case "DELETE":
119 err := app.api.DeleteApp(dbApp)
120 if err != nil {
121 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
122 }
123 return WailsRequestRouterResponse{Body: nil, Error: ""}
124 }
125 }
126
127 // list apps
128 if strings.HasPrefix(route, "/api/apps") && method == "GET" {
129 limit := uint64(0)
130 offset := uint64(0)
131 var filtersJSON string
132 var orderBy string
133
134 // Extract limit and offset parameters
135 paramRegex := regexp.MustCompile(`[?&](limit|offset|filters|order_by)=([^&]+)`)
136 paramMatches := paramRegex.FindAllStringSubmatch(route, -1)
137 for _, match := range paramMatches {
138 switch match[1] {
139 case "limit":
140 if parsedLimit, err := strconv.ParseUint(match[2], 10, 64); err == nil {
141 limit = parsedLimit
142 }
143 case "offset":
144 if parsedOffset, err := strconv.ParseUint(match[2], 10, 64); err == nil {
145 offset = parsedOffset
146 }
147 case "filters":
148 filtersJSON = match[2]
149 case "order_by":
150 orderBy = match[2]
151 }
152 }
153
154 var filters api.ListAppsFilters
155 if filtersJSON != "" {
156 err := json.Unmarshal([]byte(filtersJSON), &filters)
157 if err != nil {
158 logger.Logger.WithError(err).WithFields(logrus.Fields{
159 "filters": filtersJSON,
160 }).Error("Failed to deserialize app filters")
161 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
162 }
163 }
164
165 apps, err := app.api.ListApps(limit, offset, filters, orderBy)
166 if err != nil {
167 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
168 }
169 return WailsRequestRouterResponse{Body: apps, Error: ""}
170 }
171
172 peerChannelRegex := regexp.MustCompile(
173 `/api/peers/([^/]+)/channels/([^/]+)`,
174 )
175
176 peerChannelMatch := peerChannelRegex.FindStringSubmatch(route)
177
178 switch {
179 case len(peerChannelMatch) == 3:
180 peerId := peerChannelMatch[1]
181 channelId := peerChannelMatch[2]
182 switch method {
183 case "PATCH":
184 updateChannelRequest := &api.UpdateChannelRequest{}
185 err := json.Unmarshal([]byte(body), updateChannelRequest)
186 if err != nil {
187 logger.Logger.WithFields(logrus.Fields{
188 "route": route,
189 "method": method,
190 }).WithError(err).Error("Failed to decode request to wails router")
191 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
192 }
193 updateChannelRequest.ChannelId = channelId
194 updateChannelRequest.NodeId = peerId
195
196 err = app.api.UpdateChannel(ctx, updateChannelRequest)
197 if err != nil {
198 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
199 }
200 return WailsRequestRouterResponse{Body: nil, Error: ""}
201 case "DELETE":
202 channelIdParts := strings.SplitN(channelId, "?", 2)
203
204 var force bool
205 if len(channelIdParts) == 2 {
206 channelId = channelIdParts[0]
207 queryParams := channelIdParts[1]
208 force = strings.Contains(queryParams, "force=true")
209 }
210
211 closeChannelResponse, err := app.api.CloseChannel(ctx, peerId, channelId, force)
212 if err != nil {
213 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
214 }
215 return WailsRequestRouterResponse{Body: closeChannelResponse, Error: ""}
216 }
217 }
218
219 peerRegex := regexp.MustCompile(
220 `/api/peers/([^/]+)`,
221 )
222
223 peerMatch := peerRegex.FindStringSubmatch(route)
224
225 switch {
226 case len(peerMatch) == 2:
227 peerId := peerMatch[1]
228 switch method {
229 case "DELETE":
230 err := app.api.DisconnectPeer(ctx, peerId)
231 if err != nil {
232 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
233 }
234 return WailsRequestRouterResponse{Body: nil, Error: ""}
235 }
236 }
237
238 networkGraphRegex := regexp.MustCompile(
239 `/api/node/network-graph\?nodeIds=(.+)`,
240 )
241
242 networkGraphMatch := networkGraphRegex.FindStringSubmatch(route)
243
244 switch {
245 case len(networkGraphMatch) == 2:
246 nodeIds := networkGraphMatch[1]
247 networkGraphResponse, err := app.api.GetNetworkGraph(ctx, strings.Split(nodeIds, ","))
248 if err != nil {
249 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
250 }
251 return WailsRequestRouterResponse{Body: networkGraphResponse, Error: ""}
252 }
253
254 mempoolApiRegex := regexp.MustCompile(
255 `/api/mempool\?endpoint=(.+)`,
256 )
257 mempoolApiEndpointMatch := mempoolApiRegex.FindStringSubmatch(route)
258
259 switch {
260 case len(mempoolApiEndpointMatch) > 1:
261 endpoint := mempoolApiEndpointMatch[1]
262 node, err := app.api.RequestMempoolApi(ctx, endpoint)
263 if err != nil {
264 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
265 }
266
267 return WailsRequestRouterResponse{Body: node, Error: ""}
268 }
269
270 transactionLabelRegex := regexp.MustCompile(
271 `/api/transactions/([0-9]+)/labels`,
272 )
273 transactionLabelMatch := transactionLabelRegex.FindStringSubmatch(route)
274
275 switch {
276 case len(transactionLabelMatch) > 1:
277 transactionID, err := strconv.ParseUint(transactionLabelMatch[1], 10, 64)
278 if err != nil {
279 return WailsRequestRouterResponse{Body: nil, Error: "Invalid transaction ID"}
280 }
281 switch method {
282 case "PATCH":
283 labelsRequest := &api.SetTransactionUserLabelsRequest{}
284 err = json.Unmarshal([]byte(body), labelsRequest)
285 if err != nil {
286 logger.Logger.WithFields(logrus.Fields{
287 "route": route,
288 "method": method,
289 }).WithError(err).Error("Failed to decode request to wails router")
290 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
291 }
292 err = app.api.SetTransactionUserLabels(ctx, uint(transactionID), labelsRequest.Labels)
293 if err != nil {
294 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
295 }
296 return WailsRequestRouterResponse{Body: nil, Error: ""}
297 }
298 }
299
300 transactionRegex := regexp.MustCompile(
301 `/api/transactions/([0-9a-fA-F]+)`,
302 )
303 paymentHashMatch := transactionRegex.FindStringSubmatch(route)
304
305 switch {
306 case len(paymentHashMatch) > 1:
307 paymentHash := paymentHashMatch[1]
308 paymentInfo, err := app.api.LookupInvoice(ctx, paymentHash)
309 if err != nil {
310 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
311 }
312
313 return WailsRequestRouterResponse{Body: paymentInfo, Error: ""}
314 }
315
316 listTransactionsRegex := regexp.MustCompile(
317 `/api/transactions`,
318 )
319
320 switch {
321 case listTransactionsRegex.MatchString(route):
322 limit := uint64(20)
323 offset := uint64(0)
324 var appId *uint
325
326 parsedUrl, err := url.Parse(route)
327 if err != nil {
328 return WailsRequestRouterResponse{Body: nil, Error: "invalid route"}
329 }
330 query := parsedUrl.Query()
331
332 if limitParam := query.Get("limit"); limitParam != "" {
333 if parsedLimit, err := strconv.ParseUint(limitParam, 10, 64); err == nil {
334 limit = parsedLimit
335 }
336 }
337
338 if offsetParam := query.Get("offset"); offsetParam != "" {
339 if parsedOffset, err := strconv.ParseUint(offsetParam, 10, 64); err == nil {
340 offset = parsedOffset
341 }
342 }
343
344 if appIdParam := query.Get("appId"); appIdParam != "" {
345 if parsedAppId, err := strconv.ParseUint(appIdParam, 10, 64); err == nil {
346 var unsignedAppId = uint(parsedAppId)
347 appId = &unsignedAppId
348 }
349 }
350
351 filters, err := api.ParseListTransactionsFilters(query)
352 if err != nil {
353 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
354 }
355
356 transactions, err := app.api.ListTransactions(ctx, appId, limit, offset, filters)
357 if err != nil {
358 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
359 }
360 return WailsRequestRouterResponse{Body: transactions, Error: ""}
361 }
362
363 paymentRegex := regexp.MustCompile(
364 `/api/payments/([0-9a-zA-Z]+)`,
365 )
366 invoiceMatch := paymentRegex.FindStringSubmatch(route)
367
368 switch {
369 case len(invoiceMatch) > 1:
370 invoice := invoiceMatch[1]
371 payRequest := &api.PayInvoiceRequest{}
372 if body != "" {
373 err := json.Unmarshal([]byte(body), payRequest)
374 if err != nil {
375 logger.Logger.WithFields(logrus.Fields{
376 "route": route,
377 "method": method,
378 }).WithError(err).Error("Failed to decode request to wails router")
379 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
380 }
381 }
382 amountMsat := api.ResolveToMsat(payRequest.AmountSat, payRequest.AmountMsat, nil, payRequest.Amount)
383 paymentResponse, err := app.api.SendPayment(ctx, invoice, amountMsat, payRequest.Metadata, payRequest.FromAppID)
384 if err != nil {
385 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
386 }
387
388 return WailsRequestRouterResponse{Body: paymentResponse, Error: ""}
389 }
390
391 albyRateRegex := regexp.MustCompile(`/api/alby/rates/([^/?]+)`)
392 albyRateMatch := albyRateRegex.FindStringSubmatch(route)
393
394 switch {
395 case len(albyRateMatch) > 1:
396 currency := albyRateMatch[1]
397 rate, err := app.svc.GetAlbySvc().GetBitcoinRate(ctx, currency)
398 if err != nil {
399 logger.Logger.WithFields(logrus.Fields{
400 "route": route,
401 "method": method,
402 "currency": currency,
403 }).WithError(err).Error("Failed to get Bitcoin rate")
404 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
405 }
406 return WailsRequestRouterResponse{Body: rate, Error: ""}
407 }
408
409 switch route {
410 case "/api/transfers":
411 transferRequest := &api.TransferRequest{}
412 err := json.Unmarshal([]byte(body), transferRequest)
413 if err != nil {
414 logger.Logger.WithFields(logrus.Fields{
415 "route": route,
416 "method": method,
417 }).WithError(err).Error("Failed to decode request to wails router")
418 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
419 }
420 amountMsat := uint64(0)
421 resolvedAmountMsat := api.ResolveToMsat(transferRequest.AmountSat, transferRequest.AmountMsat, nil, nil)
422 if resolvedAmountMsat != nil {
423 amountMsat = *resolvedAmountMsat
424 }
425
426 err = app.api.Transfer(ctx, transferRequest.FromAppId, transferRequest.ToAppId, amountMsat, transferRequest.Description)
427 if err != nil {
428 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
429 }
430 return WailsRequestRouterResponse{Body: nil, Error: ""}
431 case "/api/alby/info":
432 info, err := app.svc.GetAlbySvc().GetInfo(ctx)
433 if err != nil {
434 logger.Logger.WithFields(logrus.Fields{
435 "route": route,
436 "method": method,
437 }).WithError(err).Error("Failed to decode request to wails router")
438 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
439 }
440 return WailsRequestRouterResponse{Body: info, Error: ""}
441 case "/api/alby/me":
442 me, err := app.svc.GetAlbyOAuthSvc().GetMe(ctx)
443 if err != nil {
444 logger.Logger.WithFields(logrus.Fields{
445 "route": route,
446 "method": method,
447 }).WithError(err).Error("Failed to decode request to wails router")
448 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
449 }
450 return WailsRequestRouterResponse{Body: me, Error: ""}
451 case "/api/alby/unlink-account":
452 err := app.svc.GetAlbyOAuthSvc().UnlinkAccount(ctx)
453 if err != nil {
454 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
455 }
456 return WailsRequestRouterResponse{Body: nil, Error: ""}
457 case "/api/alby/currencies":
458 currencies, err := app.svc.GetAlbySvc().GetCurrencies(ctx)
459 if err != nil {
460 logger.Logger.WithFields(logrus.Fields{
461 "route": route,
462 "method": method,
463 }).WithError(err).Error("Failed to get currencies")
464 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
465 }
466 return WailsRequestRouterResponse{Body: currencies, Error: ""}
467 case "/api/alby/stories":
468 stories, err := app.api.GetStories(ctx)
469 if err != nil {
470 logger.Logger.WithFields(logrus.Fields{
471 "route": route,
472 "method": method,
473 }).WithError(err).Error("Failed to get stories")
474 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
475 }
476 return WailsRequestRouterResponse{Body: stories, Error: ""}
477 case "/api/apps":
478 switch method {
479 case "POST":
480 createAppRequest := &api.CreateAppRequest{}
481 err := json.Unmarshal([]byte(body), createAppRequest)
482 if err != nil {
483 logger.Logger.WithFields(logrus.Fields{
484 "route": route,
485 "method": method,
486 }).WithError(err).Error("Failed to decode request to wails router")
487 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
488 }
489
490 createAppResponse, err := app.api.CreateApp(createAppRequest)
491 if err != nil {
492 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
493 }
494 return WailsRequestRouterResponse{Body: createAppResponse, Error: ""}
495 }
496 case "/api/reset-router":
497 resetRouterRequest := &api.ResetRouterRequest{}
498 err := json.Unmarshal([]byte(body), resetRouterRequest)
499 if err != nil {
500 logger.Logger.WithFields(logrus.Fields{
501 "route": route,
502 "method": method,
503 }).WithError(err).Error("Failed to decode request to wails router")
504 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
505 }
506
507 err = app.api.ResetRouter(resetRouterRequest.Key)
508 if err != nil {
509 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
510 }
511 res := WailsRequestRouterResponse{Body: nil, Error: ""}
512 return res
513 case "/api/stop":
514 err := app.api.Stop()
515 if err != nil {
516 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
517 }
518 res := WailsRequestRouterResponse{Body: nil, Error: ""}
519 return res
520 case "/api/channels":
521 switch method {
522 case "GET":
523 channels, err := app.api.ListChannels(ctx)
524 if err != nil {
525 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
526 }
527 res := WailsRequestRouterResponse{Body: channels, Error: ""}
528 return res
529 case "POST":
530 openChannelRequest := &api.OpenChannelRequest{}
531 err := json.Unmarshal([]byte(body), openChannelRequest)
532 if err != nil {
533 logger.Logger.WithFields(logrus.Fields{
534 "route": route,
535 "method": method,
536 }).WithError(err).Error("Failed to decode request to wails router")
537 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
538 }
539 openChannelResponse, err := app.api.OpenChannel(ctx, openChannelRequest)
540 if err != nil {
541 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
542 }
543 return WailsRequestRouterResponse{Body: openChannelResponse, Error: ""}
544 }
545 case "/api/channel-offer":
546 offer, err := app.api.GetLSPChannelOffer(ctx)
547 if err != nil {
548 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
549 }
550 res := WailsRequestRouterResponse{Body: offer, Error: ""}
551 return res
552 case "/api/channels/suggestions":
553 suggestions, err := app.api.GetChannelPeerSuggestions(ctx)
554 if err != nil {
555 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
556 }
557 res := WailsRequestRouterResponse{Body: suggestions, Error: ""}
558 return res
559 case "/api/channels/rebalance":
560 rebalanceChannelRequest := &api.RebalanceChannelRequest{}
561 err := json.Unmarshal([]byte(body), rebalanceChannelRequest)
562 if err != nil {
563 logger.Logger.WithFields(logrus.Fields{
564 "route": route,
565 "method": method,
566 }).WithError(err).Error("Failed to decode request to wails router")
567 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
568 }
569 rebalanceChannelResponse, err := app.api.RebalanceChannel(ctx, rebalanceChannelRequest)
570 if err != nil {
571 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
572 }
573 return WailsRequestRouterResponse{Body: rebalanceChannelResponse, Error: ""}
574 case "/api/balances":
575 balancesResponse, err := app.api.GetBalances(ctx)
576 if err != nil {
577 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
578 }
579 res := WailsRequestRouterResponse{Body: *balancesResponse, Error: ""}
580 return res
581 case "/api/invoices":
582 makeInvoiceRequest := &api.MakeInvoiceRequest{}
583 err := json.Unmarshal([]byte(body), makeInvoiceRequest)
584 if err != nil {
585 logger.Logger.WithFields(logrus.Fields{
586 "route": route,
587 "method": method,
588 }).WithError(err).Error("Failed to decode request to wails router")
589 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
590 }
591 amountMsat := uint64(0)
592 resolvedAmountMsat := api.ResolveToMsat(makeInvoiceRequest.AmountSat, makeInvoiceRequest.AmountMsat, nil, makeInvoiceRequest.Amount)
593 if resolvedAmountMsat != nil {
594 amountMsat = *resolvedAmountMsat
595 }
596 invoice, err := app.api.CreateInvoice(ctx, amountMsat, makeInvoiceRequest.Description, makeInvoiceRequest.ToAppID)
597 if err != nil {
598 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
599 }
600 res := WailsRequestRouterResponse{Body: invoice, Error: ""}
601 return res
602 case "/api/wallet/sync":
603 app.api.SyncWallet()
604 return WailsRequestRouterResponse{Body: nil, Error: ""}
605 case "/api/wallet/address":
606 address, err := app.api.GetUnusedOnchainAddress(ctx)
607 if err != nil {
608 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
609 }
610 return WailsRequestRouterResponse{Body: address, Error: ""}
611 case "/api/wallet/new-address":
612 newAddress, err := app.api.GetNewOnchainAddress(ctx)
613 if err != nil {
614 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
615 }
616 return WailsRequestRouterResponse{Body: newAddress, Error: ""}
617 case "/api/wallet/redeem-onchain-funds":
618 redeemOnchainFundsRequest := &api.RedeemOnchainFundsRequest{}
619 err := json.Unmarshal([]byte(body), redeemOnchainFundsRequest)
620 if err != nil {
621 logger.Logger.WithFields(logrus.Fields{
622 "route": route,
623 "method": method,
624 }).WithError(err).Error("Failed to decode request to wails router")
625 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
626 }
627
628 amountSat := uint64(0)
629 resolvedAmountSat := api.ResolveToSat(redeemOnchainFundsRequest.AmountSat, nil, redeemOnchainFundsRequest.Amount, nil)
630 if resolvedAmountSat != nil {
631 amountSat = *resolvedAmountSat
632 }
633
634 redeemOnchainFundsResponse, err := app.api.RedeemOnchainFunds(ctx, redeemOnchainFundsRequest.ToAddress, amountSat, redeemOnchainFundsRequest.FeeRate, redeemOnchainFundsRequest.SendAll)
635 if err != nil {
636 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
637 }
638 return WailsRequestRouterResponse{Body: *redeemOnchainFundsResponse, Error: ""}
639 case "/api/wallet/sign-message":
640 signMessageRequest := &api.SignMessageRequest{}
641 err := json.Unmarshal([]byte(body), signMessageRequest)
642 if err != nil {
643 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
644 }
645 signMessageResponse, err := app.api.SignMessage(ctx, signMessageRequest.Message)
646 if err != nil {
647 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
648 }
649 return WailsRequestRouterResponse{Body: *signMessageResponse, Error: ""}
650 case "/api/wallet/capabilities":
651 capabilitiesResponse, err := app.api.GetWalletCapabilities(ctx)
652 if err != nil {
653 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
654 }
655 return WailsRequestRouterResponse{Body: *capabilitiesResponse, Error: ""}
656 case "/api/lsp-orders":
657 newInstantChannelRequest := &api.LSPOrderRequest{}
658 err := json.Unmarshal([]byte(body), newInstantChannelRequest)
659 if err != nil {
660 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
661 }
662 newInstantChannelResponse, err := app.api.RequestLSPOrder(ctx, newInstantChannelRequest)
663 if err != nil {
664 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
665 }
666 return WailsRequestRouterResponse{Body: *newInstantChannelResponse, Error: ""}
667 case "/api/peers":
668 switch method {
669 case "GET":
670 peers, err := app.api.ListPeers(ctx)
671 if err != nil {
672 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
673 }
674 return WailsRequestRouterResponse{Body: peers, Error: ""}
675 case "POST":
676 connectPeerRequest := &api.ConnectPeerRequest{}
677 err := json.Unmarshal([]byte(body), connectPeerRequest)
678 if err != nil {
679 logger.Logger.WithFields(logrus.Fields{
680 "route": route,
681 "method": method,
682 }).WithError(err).Error("Failed to decode request to wails router")
683 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
684 }
685 err = app.api.ConnectPeer(ctx, connectPeerRequest)
686 if err != nil {
687 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
688 }
689 return WailsRequestRouterResponse{Body: nil, Error: ""}
690 }
691 case "/api/node/connection-info":
692 nodeConnectionInfo, err := app.api.GetNodeConnectionInfo(ctx)
693 if err != nil {
694 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
695 }
696 return WailsRequestRouterResponse{Body: *nodeConnectionInfo, Error: ""}
697 case "/api/node/status":
698 nodeStatus, err := app.api.GetNodeStatus(ctx)
699 if err != nil {
700 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
701 }
702 if nodeStatus == nil {
703 return WailsRequestRouterResponse{Body: nil, Error: ""}
704 }
705 return WailsRequestRouterResponse{Body: *nodeStatus, Error: ""}
706 case "/api/node/transactions":
707 transactions, err := app.api.ListOnchainTransactions(ctx)
708 if err != nil {
709 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
710 }
711 return WailsRequestRouterResponse{Body: transactions, Error: ""}
712 case "/api/info":
713 infoResponse, err := app.api.GetInfo(ctx)
714 if err != nil {
715 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
716 }
717 infoResponse.Unlocked = infoResponse.Running
718 res := WailsRequestRouterResponse{Body: *infoResponse, Error: ""}
719 return res
720 case "/api/node/migrate-storage":
721 migrateNodeStorageRequest := &api.MigrateNodeStorageRequest{}
722 err := json.Unmarshal([]byte(body), migrateNodeStorageRequest)
723 if err != nil {
724 logger.Logger.WithFields(logrus.Fields{
725 "route": route,
726 "method": method,
727 }).WithError(err).Error("Failed to decode request to wails router")
728 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
729 }
730 err = app.api.MigrateNodeStorage(ctx, migrateNodeStorageRequest.To)
731 if err != nil {
732 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
733 }
734 return WailsRequestRouterResponse{Body: nil, Error: ""}
735 case "/api/alby/auto-channel":
736 newAutoChannelRequest := &alby.AutoChannelRequest{}
737 err := json.Unmarshal([]byte(body), newAutoChannelRequest)
738 if err != nil {
739 logger.Logger.WithFields(logrus.Fields{
740 "route": route,
741 "method": method,
742 }).WithError(err).Error("Failed to decode request to wails router")
743 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
744 }
745 autoChannelResponse, err := app.svc.GetAlbyOAuthSvc().RequestAutoChannel(ctx, app.svc.GetLNClient(), newAutoChannelRequest.IsPublic)
746 if err != nil {
747 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
748 }
749 return WailsRequestRouterResponse{Body: *autoChannelResponse, Error: ""}
750
751 case "/api/alby/link-account":
752 linkAccountRequest := &alby.AlbyLinkAccountRequest{}
753 err := json.Unmarshal([]byte(body), linkAccountRequest)
754 if err != nil {
755 logger.Logger.WithFields(logrus.Fields{
756 "route": route,
757 "method": method,
758 }).WithError(err).Error("Failed to decode request to wails router")
759 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
760 }
761 err = app.svc.GetAlbyOAuthSvc().LinkAccount(ctx, app.svc.GetLNClient(), linkAccountRequest.Budget, linkAccountRequest.Renewal)
762 if err != nil {
763 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
764 }
765 res := WailsRequestRouterResponse{Error: ""}
766 return res
767 case "/api/mnemonic":
768 mnemonicRequest := &api.MnemonicRequest{}
769 err := json.Unmarshal([]byte(body), mnemonicRequest)
770 if err != nil {
771 logger.Logger.WithFields(logrus.Fields{
772 "route": route,
773 "method": method,
774 }).WithError(err).Error("Failed to parse mnemonic request")
775 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
776 }
777 mnemonicResponse, err := app.api.GetMnemonic(mnemonicRequest.UnlockPassword)
778 if err != nil {
779 logger.Logger.WithFields(logrus.Fields{
780 "route": route,
781 "method": method,
782 }).WithError(err).Error("Failed to get mnemonic")
783 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
784 }
785 res := WailsRequestRouterResponse{Body: *mnemonicResponse, Error: ""}
786 return res
787 case "/api/backup-reminder":
788 backupReminderRequest := &api.BackupReminderRequest{}
789 err := json.Unmarshal([]byte(body), backupReminderRequest)
790 if err != nil {
791 logger.Logger.WithFields(logrus.Fields{
792 "route": route,
793 "method": method,
794 }).WithError(err).Error("Failed to decode request to wails router")
795 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
796 }
797
798 err = app.api.SetNextBackupReminder(backupReminderRequest)
799 if err != nil {
800 logger.Logger.WithFields(logrus.Fields{
801 "route": route,
802 "method": method,
803 }).WithError(err).Error("Failed to store backup reminder")
804 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
805 }
806 return WailsRequestRouterResponse{Body: nil, Error: ""}
807 case "/api/unlock-password":
808 changeUnlockPasswordRequest := &api.ChangeUnlockPasswordRequest{}
809 err := json.Unmarshal([]byte(body), changeUnlockPasswordRequest)
810 if err != nil {
811 logger.Logger.WithFields(logrus.Fields{
812 "route": route,
813 "method": method,
814 }).WithError(err).Error("Failed to decode request to wails router")
815 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
816 }
817
818 err = app.api.ChangeUnlockPassword(changeUnlockPasswordRequest)
819 if err != nil {
820 logger.Logger.WithFields(logrus.Fields{
821 "route": route,
822 "method": method,
823 }).WithError(err).Error("Failed to change unlock password")
824 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
825 }
826 return WailsRequestRouterResponse{Body: nil, Error: ""}
827 case "/api/settings":
828 updateSettingsRequest := &api.UpdateSettingsRequest{}
829 err := json.Unmarshal([]byte(body), updateSettingsRequest)
830 if err != nil {
831 logger.Logger.WithFields(logrus.Fields{
832 "route": route,
833 "method": method,
834 }).WithError(err).Error("Failed to decode request to wails router")
835 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
836 }
837
838 err = app.api.UpdateSettings(updateSettingsRequest)
839 if err != nil {
840 logger.Logger.WithFields(logrus.Fields{
841 "route": route,
842 "method": method,
843 }).WithError(err).Error("Failed to update settings")
844 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
845 }
846 return WailsRequestRouterResponse{Body: nil, Error: ""}
847 case "/api/auto-unlock":
848 autoUnlockRequest := &api.AutoUnlockRequest{}
849 err := json.Unmarshal([]byte(body), autoUnlockRequest)
850 if err != nil {
851 logger.Logger.WithFields(logrus.Fields{
852 "route": route,
853 "method": method,
854 }).WithError(err).Error("Failed to decode request to wails router")
855 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
856 }
857
858 err = app.api.SetAutoUnlockPassword(autoUnlockRequest.UnlockPassword)
859 if err != nil {
860 logger.Logger.WithFields(logrus.Fields{
861 "route": route,
862 "method": method,
863 }).WithError(err).Error("Failed to set auto unlock password")
864 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
865 }
866 return WailsRequestRouterResponse{Body: nil, Error: ""}
867 case "/api/start":
868 startRequest := &api.StartRequest{}
869 err := json.Unmarshal([]byte(body), startRequest)
870 if err != nil {
871 logger.Logger.WithFields(logrus.Fields{
872 "route": route,
873 "method": method,
874 }).WithError(err).Error("Failed to decode request to wails router")
875 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
876 }
877
878 go app.api.Start(startRequest)
879
880 return WailsRequestRouterResponse{Body: nil, Error: ""}
881 case "/api/setup":
882 setupRequest := &api.SetupRequest{}
883 err := json.Unmarshal([]byte(body), setupRequest)
884 if err != nil {
885 logger.Logger.WithFields(logrus.Fields{
886 "route": route,
887 "method": method,
888 }).WithError(err).Error("Failed to decode request to wails router")
889 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
890 }
891 err = app.api.Setup(ctx, setupRequest)
892 if err != nil {
893 logger.Logger.WithFields(logrus.Fields{
894 "route": route,
895 "method": method,
896 }).WithError(err).Error("Failed to setup node")
897 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
898 }
899 return WailsRequestRouterResponse{Body: nil, Error: ""}
900 case "/api/backup":
901 backupRequest := &api.BasicBackupRequest{}
902 err := json.Unmarshal([]byte(body), backupRequest)
903 if err != nil {
904 logger.Logger.WithFields(logrus.Fields{
905 "route": route,
906 "method": method,
907 }).WithError(err).Error("Failed to decode request to wails router")
908 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
909 }
910
911 saveFilePath, err := runtime.SaveFileDialog(ctx, runtime.SaveDialogOptions{
912 Title: "Save Backup File",
913 DefaultFilename: "albyhub.bkp",
914 })
915 if err != nil {
916 logger.Logger.WithFields(logrus.Fields{
917 "route": route,
918 "method": method,
919 }).WithError(err).Error("Failed to open save file dialog")
920 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
921 }
922
923 backupFile, err := os.Create(saveFilePath)
924 if err != nil {
925 logger.Logger.WithFields(logrus.Fields{
926 "route": route,
927 "method": method,
928 }).WithError(err).Error("Failed to create backup file")
929 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
930 }
931
932 defer backupFile.Close()
933
934 err = app.api.CreateBackup(backupRequest.UnlockPassword, backupFile)
935
936 if err != nil {
937 logger.Logger.WithFields(logrus.Fields{
938 "route": route,
939 "method": method,
940 }).WithError(err).Error("Failed to create backup")
941 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
942 }
943 return WailsRequestRouterResponse{Body: nil, Error: ""}
944 case "/api/restore":
945 restoreRequest := &api.BasicRestoreWailsRequest{}
946 err := json.Unmarshal([]byte(body), restoreRequest)
947 if err != nil {
948 logger.Logger.WithFields(logrus.Fields{
949 "route": route,
950 "method": method,
951 }).WithError(err).Error("Failed to decode request to wails router")
952 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
953 }
954
955 backupFilePath, err := runtime.OpenFileDialog(ctx, runtime.OpenDialogOptions{
956 Title: "Select Backup File",
957 DefaultFilename: "albyhub.bkp",
958 })
959 if err != nil {
960 logger.Logger.WithFields(logrus.Fields{
961 "route": route,
962 "method": method,
963 }).WithError(err).Error("Failed to open save file dialog")
964 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
965 }
966
967 backupFile, err := os.Open(backupFilePath)
968 if err != nil {
969 logger.Logger.WithFields(logrus.Fields{
970 "route": route,
971 "method": method,
972 }).WithError(err).Error("Failed to open backup file")
973 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
974 }
975
976 defer backupFile.Close()
977
978 err = app.api.RestoreBackup(restoreRequest.UnlockPassword, backupFile)
979 if err != nil {
980 logger.Logger.WithFields(logrus.Fields{
981 "route": route,
982 "method": method,
983 }).WithError(err).Error("Failed to restore backup")
984 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
985 }
986 return WailsRequestRouterResponse{Body: nil, Error: ""}
987 case "/api/health":
988 nodeHealth, err := app.api.Health(ctx)
989 if err != nil {
990 logger.Logger.WithFields(logrus.Fields{
991 "route": route,
992 "method": method,
993 }).WithError(err).Error("Failed to check node health")
994 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
995 }
996 return WailsRequestRouterResponse{Body: *nodeHealth, Error: ""}
997 case "/api/offers":
998 makeOfferRequest := &api.MakeOfferRequest{}
999 err := json.Unmarshal([]byte(body), makeOfferRequest)
1000 if err != nil {
1001 logger.Logger.WithFields(logrus.Fields{
1002 "route": route,
1003 "method": method,
1004 }).WithError(err).Error("Failed to decode request to wails router")
1005 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1006 }
1007 offer, err := app.api.MakeOffer(ctx, makeOfferRequest.Description)
1008 if err != nil {
1009 logger.Logger.WithFields(logrus.Fields{
1010 "route": route,
1011 "method": method,
1012 }).WithError(err).Error("Failed to generate BOLT-12 offer")
1013 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1014 }
1015 return WailsRequestRouterResponse{Body: offer, Error: ""}
1016 case "/api/commands":
1017 nodeCommandsResponse, err := app.api.GetCustomNodeCommands()
1018 if err != nil {
1019 logger.Logger.WithFields(logrus.Fields{
1020 "route": route,
1021 "method": method,
1022 }).WithError(err).Error("Failed to get node commands")
1023 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1024 }
1025 return WailsRequestRouterResponse{Body: nodeCommandsResponse, Error: ""}
1026 case "/api/command":
1027 commandRequest := &api.ExecuteCustomNodeCommandRequest{}
1028 err := json.Unmarshal([]byte(body), commandRequest)
1029 if err != nil {
1030 logger.Logger.WithFields(logrus.Fields{
1031 "route": route,
1032 "method": method,
1033 }).WithError(err).Error("Failed to decode request to wails router")
1034 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1035 }
1036 commandResponse, err := app.api.ExecuteCustomNodeCommand(ctx, commandRequest.Command)
1037 if err != nil {
1038 logger.Logger.WithFields(logrus.Fields{
1039 "route": route,
1040 "method": method,
1041 }).WithError(err).Error("Failed to execute command")
1042 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1043 }
1044 return WailsRequestRouterResponse{Body: commandResponse, Error: ""}
1045 case "/api/autoswap":
1046 switch method {
1047 case "GET":
1048 autoSwapsConfig, err := app.api.GetAutoSwapConfig()
1049 if err != nil {
1050 logger.Logger.WithFields(logrus.Fields{
1051 "route": route,
1052 "method": method,
1053 }).WithError(err).Error("Failed to get auto swap configuration")
1054 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1055 }
1056 return WailsRequestRouterResponse{Body: autoSwapsConfig, Error: ""}
1057 case "POST":
1058 enableAutoSwapRequest := &api.EnableAutoSwapRequest{}
1059 err := json.Unmarshal([]byte(body), enableAutoSwapRequest)
1060 if err != nil {
1061 logger.Logger.WithFields(logrus.Fields{
1062 "route": route,
1063 "method": method,
1064 }).WithError(err).Error("Failed to decode request to wails router")
1065 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1066 }
1067 err = app.api.EnableAutoSwapOut(ctx, enableAutoSwapRequest)
1068 if err != nil {
1069 logger.Logger.WithFields(logrus.Fields{
1070 "route": route,
1071 "method": method,
1072 }).WithError(err).Error("Failed to enable auto swap")
1073 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1074 }
1075 return WailsRequestRouterResponse{Body: nil, Error: ""}
1076 case "DELETE":
1077 err := app.api.DisableAutoSwap()
1078 if err != nil {
1079 logger.Logger.WithFields(logrus.Fields{
1080 "route": route,
1081 "method": method,
1082 }).WithError(err).Error("Failed to disable auto swap")
1083 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1084 }
1085 return WailsRequestRouterResponse{Body: nil, Error: ""}
1086 }
1087 case "/api/swaps/out/info":
1088 swapOutInfo, err := app.api.GetSwapOutInfo()
1089 if err != nil {
1090 logger.Logger.WithFields(logrus.Fields{
1091 "route": route,
1092 "method": method,
1093 }).WithError(err).Error("Failed to get swap out info")
1094 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1095 }
1096 return WailsRequestRouterResponse{Body: swapOutInfo, Error: ""}
1097 case "/api/swaps/in/info":
1098 swapInInfo, err := app.api.GetSwapInInfo()
1099 if err != nil {
1100 logger.Logger.WithFields(logrus.Fields{
1101 "route": route,
1102 "method": method,
1103 }).WithError(err).Error("Failed to get swap in info")
1104 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1105 }
1106 return WailsRequestRouterResponse{Body: swapInInfo, Error: ""}
1107 case "/api/swaps/out":
1108 initiateSwapOutRequest := &api.InitiateSwapRequest{}
1109 err := json.Unmarshal([]byte(body), initiateSwapOutRequest)
1110 if err != nil {
1111 logger.Logger.WithFields(logrus.Fields{
1112 "route": route,
1113 "method": method,
1114 }).WithError(err).Error("Failed to decode request to wails router")
1115 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1116 }
1117 swapOutResponse, err := app.api.InitiateSwapOut(ctx, initiateSwapOutRequest)
1118 if err != nil {
1119 logger.Logger.WithFields(logrus.Fields{
1120 "route": route,
1121 "method": method,
1122 }).WithError(err).Error("Failed to initiate swap out")
1123 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1124 }
1125 return WailsRequestRouterResponse{Body: swapOutResponse, Error: ""}
1126 case "/api/swaps/in":
1127 initiateSwapInRequest := &api.InitiateSwapRequest{}
1128 err := json.Unmarshal([]byte(body), initiateSwapInRequest)
1129 if err != nil {
1130 logger.Logger.WithFields(logrus.Fields{
1131 "route": route,
1132 "method": method,
1133 }).WithError(err).Error("Failed to decode request to wails router")
1134 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1135 }
1136 swapInResponse, err := app.api.InitiateSwapIn(ctx, initiateSwapInRequest)
1137 if err != nil {
1138 logger.Logger.WithFields(logrus.Fields{
1139 "route": route,
1140 "method": method,
1141 }).WithError(err).Error("Failed to initiate swap in")
1142 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1143 }
1144 return WailsRequestRouterResponse{Body: swapInResponse, Error: ""}
1145 case "/api/swaps/refund":
1146 refundSwapRequest := &api.RefundSwapRequest{}
1147 err := json.Unmarshal([]byte(body), refundSwapRequest)
1148 if err != nil {
1149 logger.Logger.WithFields(logrus.Fields{
1150 "route": route,
1151 "method": method,
1152 }).WithError(err).Error("Failed to decode request to wails router")
1153 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1154 }
1155 err = app.api.RefundSwap(refundSwapRequest)
1156 if err != nil {
1157 logger.Logger.WithFields(logrus.Fields{
1158 "route": route,
1159 "method": method,
1160 }).WithError(err).Error("Failed to process swap refund")
1161 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1162 }
1163 return WailsRequestRouterResponse{Body: nil, Error: ""}
1164 case "/api/swaps/mnemonic":
1165 mnemonic := app.api.GetSwapMnemonic()
1166 return WailsRequestRouterResponse{Body: mnemonic, Error: ""}
1167 case "/api/node/alias":
1168 setNodeAliasRequest := &api.SetNodeAliasRequest{}
1169 err := json.Unmarshal([]byte(body), setNodeAliasRequest)
1170 if err != nil {
1171 logger.Logger.WithFields(logrus.Fields{
1172 "route": route,
1173 "method": method,
1174 }).WithError(err).Error("Failed to decode request to wails router")
1175 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1176 }
1177
1178 err = app.api.SetNodeAlias(setNodeAliasRequest.NodeAlias)
1179 if err != nil {
1180 logger.Logger.WithFields(logrus.Fields{
1181 "route": route,
1182 "method": method,
1183 }).WithError(err).Error("Failed to set node alias")
1184 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1185 }
1186 return WailsRequestRouterResponse{Body: nil, Error: ""}
1187 case "/api/event":
1188 switch method {
1189 case "POST":
1190 sendEventRequest := &api.SendEventRequest{}
1191 err := json.Unmarshal([]byte(body), sendEventRequest)
1192 if err != nil {
1193 logger.Logger.WithFields(logrus.Fields{
1194 "route": route,
1195 "method": method,
1196 }).WithError(err).Error("Failed to send event")
1197 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1198 }
1199
1200 app.api.SendEvent(sendEventRequest.Event, sendEventRequest.Properties)
1201
1202 return WailsRequestRouterResponse{Body: nil, Error: ""}
1203 }
1204 case "/api/lightning-addresses":
1205 switch method {
1206 case "POST":
1207 createLightningAddressRequest := &api.CreateLightningAddressRequest{}
1208 err := json.Unmarshal([]byte(body), createLightningAddressRequest)
1209 if err != nil {
1210 logger.Logger.WithFields(logrus.Fields{
1211 "route": route,
1212 "method": method,
1213 }).WithError(err).Error("Failed to decode request to wails router")
1214 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1215 }
1216
1217 err = app.api.CreateLightningAddress(ctx, createLightningAddressRequest)
1218 if err != nil {
1219 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1220 }
1221 return WailsRequestRouterResponse{Body: nil, Error: ""}
1222 }
1223 case "/api/forwards":
1224 forwards, err := app.api.GetForwards()
1225 if err != nil {
1226 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1227 }
1228 return WailsRequestRouterResponse{Body: forwards, Error: ""}
1229 }
1230
1231 lightningAddressRegex := regexp.MustCompile(
1232 `/api/lightning-addresses/([^/]+)`,
1233 )
1234 lightningAddressMatch := lightningAddressRegex.FindStringSubmatch(route)
1235
1236 switch {
1237 case len(lightningAddressMatch) == 2:
1238 appIdStr := lightningAddressMatch[1]
1239 appId, err := strconv.ParseUint(appIdStr, 10, 64)
1240 if err != nil {
1241 return WailsRequestRouterResponse{Body: nil, Error: "Invalid app ID"}
1242 }
1243
1244 switch method {
1245 case "DELETE":
1246 err := app.api.DeleteLightningAddress(ctx, uint(appId))
1247 if err != nil {
1248 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1249 }
1250 return WailsRequestRouterResponse{Body: nil, Error: ""}
1251 }
1252 }
1253
1254 // Swap lookup and listing is shifted to the bottom so it
1255 // doesn't interfere with other swap endpoints
1256 swapRegex := regexp.MustCompile(
1257 `/api/swaps/([0-9a-zA-Z]+)`,
1258 )
1259 swapIdMatch := swapRegex.FindStringSubmatch(route)
1260
1261 switch {
1262 case len(swapIdMatch) > 1:
1263 swapId := swapIdMatch[1]
1264 swapInfo, err := app.api.LookupSwap(swapId)
1265 if err != nil {
1266 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1267 }
1268
1269 return WailsRequestRouterResponse{Body: swapInfo, Error: ""}
1270 }
1271
1272 listSwapsRegex := regexp.MustCompile(
1273 `/api/swaps`,
1274 )
1275
1276 switch {
1277 case listSwapsRegex.MatchString(route):
1278 swaps, err := app.api.ListSwaps()
1279 if err != nil {
1280 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1281 }
1282 return WailsRequestRouterResponse{Body: swaps, Error: ""}
1283 }
1284
1285 if strings.HasPrefix(route, "/api/log/") {
1286 logType := strings.TrimPrefix(route, "/api/log/")
1287 logType = strings.Split(logType, "?")[0]
1288 if logType != api.LogTypeNode && logType != api.LogTypeApp {
1289 return WailsRequestRouterResponse{Body: nil, Error: fmt.Sprintf("Invalid log type: '%s'", logType)}
1290 }
1291 parsedUrl, err := url.Parse(route)
1292 if err != nil {
1293 return WailsRequestRouterResponse{Body: nil, Error: "Failed to parse route URL"}
1294 }
1295 queryParams := parsedUrl.Query()
1296 getLogOutputRequest := &api.GetLogOutputRequest{}
1297 if maxLen := queryParams.Get("maxLen"); maxLen != "" {
1298 getLogOutputRequest.MaxLen, err = strconv.Atoi(maxLen)
1299 if err != nil {
1300 return WailsRequestRouterResponse{Body: nil, Error: "Invalid max length parameter"}
1301 }
1302 }
1303 logOutputResponse, err := app.api.GetLogOutput(ctx, logType, getLogOutputRequest)
1304 if err != nil {
1305 logger.Logger.WithFields(logrus.Fields{
1306 "route": route,
1307 "method": method,
1308 }).WithError(err).Error("Failed to get log output")
1309 return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
1310 }
1311 return WailsRequestRouterResponse{Body: logOutputResponse, Error: ""}
1312 }
1313
1314 logger.Logger.WithFields(logrus.Fields{
1315 "route": route,
1316 "method": method,
1317 }).Error("Unhandled route")
1318 return WailsRequestRouterResponse{Body: nil, Error: fmt.Sprintf("Unhandled route: %s %s", method, route)}
1319 }
1320