alby_http_service.go raw
1 package http
2
3 import (
4 "errors"
5 "fmt"
6 "net/http"
7
8 "github.com/getAlby/hub/alby"
9 "github.com/getAlby/hub/config"
10 "github.com/getAlby/hub/logger"
11 "github.com/getAlby/hub/service"
12 "github.com/labstack/echo/v4"
13 )
14
15 type AlbyHttpService struct {
16 albySvc alby.AlbyService
17 albyOAuthSvc alby.AlbyOAuthService
18 appConfig *config.AppConfig
19 svc service.Service
20 }
21
22 func NewAlbyHttpService(svc service.Service, albySvc alby.AlbyService, albyOAuthSvc alby.AlbyOAuthService, appConfig *config.AppConfig) *AlbyHttpService {
23 return &AlbyHttpService{
24 albySvc: albySvc,
25 albyOAuthSvc: albyOAuthSvc,
26 appConfig: appConfig,
27 svc: svc,
28 }
29 }
30
31 func (albyHttpSvc *AlbyHttpService) RegisterSharedRoutes(readOnlyApiGroup *echo.Group, fullAccessApiGroup *echo.Group, e *echo.Echo) {
32 e.GET("/api/alby/callback", albyHttpSvc.albyCallbackHandler)
33 e.GET("/api/alby/info", albyHttpSvc.albyInfoHandler)
34 e.GET("/api/alby/rates/:currency", albyHttpSvc.albyBitcoinRateHandler)
35 e.GET("/api/alby/currencies", albyHttpSvc.albyCurrenciesHandler)
36 e.GET("/api/alby/stories", albyHttpSvc.albyStoriesHandler)
37 readOnlyApiGroup.GET("/alby/me", albyHttpSvc.albyMeHandler)
38 fullAccessApiGroup.POST("/alby/link-account", albyHttpSvc.albyLinkAccountHandler)
39 fullAccessApiGroup.POST("/alby/auto-channel", albyHttpSvc.autoChannelHandler)
40 fullAccessApiGroup.POST("/alby/unlink-account", albyHttpSvc.unlinkHandler)
41 }
42
43 func (albyHttpSvc *AlbyHttpService) autoChannelHandler(c echo.Context) error {
44 ctx := c.Request().Context()
45
46 var autoChannelRequest alby.AutoChannelRequest
47 if err := c.Bind(&autoChannelRequest); err != nil {
48 return c.JSON(http.StatusBadRequest, ErrorResponse{
49 Message: fmt.Sprintf("Bad request: %s", err.Error()),
50 })
51 }
52
53 autoChannelResponseResponse, err := albyHttpSvc.albyOAuthSvc.RequestAutoChannel(ctx, albyHttpSvc.svc.GetLNClient(), autoChannelRequest.IsPublic)
54
55 if err != nil {
56 return c.JSON(http.StatusInternalServerError, ErrorResponse{
57 Message: fmt.Sprintf("Failed to request auto channel: %s", err.Error()),
58 })
59 }
60
61 return c.JSON(http.StatusOK, autoChannelResponseResponse)
62 }
63
64 func (albyHttpSvc *AlbyHttpService) unlinkHandler(c echo.Context) error {
65 ctx := c.Request().Context()
66
67 err := albyHttpSvc.albyOAuthSvc.UnlinkAccount(ctx)
68
69 if err != nil {
70 return c.JSON(http.StatusInternalServerError, ErrorResponse{
71 Message: fmt.Sprintf("Failed to unlink: %s", err.Error()),
72 })
73 }
74
75 return c.NoContent(http.StatusNoContent)
76 }
77
78 func (albyHttpSvc *AlbyHttpService) albyInfoHandler(c echo.Context) error {
79 info, err := albyHttpSvc.albySvc.GetInfo(c.Request().Context())
80 if err != nil {
81 logger.Logger.WithError(err).Error("Failed to request alby info endpoint")
82 return c.JSON(http.StatusInternalServerError, ErrorResponse{
83 Message: fmt.Sprintf("Failed to request alby info endpoint: %s", err.Error()),
84 })
85 }
86
87 return c.JSON(http.StatusOK, info)
88 }
89
90 func (albyHttpSvc *AlbyHttpService) albyBitcoinRateHandler(c echo.Context) error {
91 rate, err := albyHttpSvc.albySvc.GetBitcoinRate(c.Request().Context(), c.Param("currency"))
92 if err != nil {
93 logger.Logger.WithError(err).Error("Failed to get Bitcoin rate")
94 return c.JSON(http.StatusInternalServerError, ErrorResponse{
95 Message: fmt.Sprintf("Failed to get Bitcoin rate: %s", err.Error()),
96 })
97 }
98 return c.JSON(http.StatusOK, rate)
99 }
100
101 func (albyHttpSvc *AlbyHttpService) albyCurrenciesHandler(c echo.Context) error {
102 currencies, err := albyHttpSvc.albySvc.GetCurrencies(c.Request().Context())
103 if err != nil {
104 logger.Logger.WithError(err).Error("Failed to get currencies")
105 return c.JSON(http.StatusInternalServerError, ErrorResponse{
106 Message: fmt.Sprintf("Failed to get currencies: %s", err.Error()),
107 })
108 }
109
110 return c.JSON(http.StatusOK, currencies)
111 }
112
113 func (albyHttpSvc *AlbyHttpService) albyStoriesHandler(c echo.Context) error {
114 stories, err := albyHttpSvc.albyOAuthSvc.GetStories(c.Request().Context())
115 if err != nil {
116 logger.Logger.WithError(err).Error("Failed to get stories")
117 return c.JSON(http.StatusInternalServerError, ErrorResponse{
118 Message: fmt.Sprintf("Failed to get stories: %s", err.Error()),
119 })
120 }
121 return c.JSON(http.StatusOK, stories)
122 }
123
124 func (albyHttpSvc *AlbyHttpService) albyCallbackHandler(c echo.Context) error {
125 code := c.QueryParam("code")
126
127 err := albyHttpSvc.albyOAuthSvc.CallbackHandler(c.Request().Context(), code)
128 if err != nil {
129 logger.Logger.WithError(err).Error("Failed to handle Alby OAuth callback")
130 return c.JSON(http.StatusInternalServerError, ErrorResponse{
131 Message: fmt.Sprintf("Failed to handle Alby OAuth callback: %s", err.Error()),
132 })
133 }
134
135 if albyHttpSvc.appConfig.IsDefaultClientId() {
136 // do not redirect if using default OAuth client
137 // redirect will be handled by the frontend instead
138 return c.NoContent(http.StatusNoContent)
139 }
140
141 redirectUrl := albyHttpSvc.appConfig.GetBaseFrontendUrl()
142
143 if redirectUrl == "" {
144 // OAuth using a custom client requires a base URL set for the callback
145 return errors.New("no BASE_URL set")
146 }
147
148 return c.Redirect(http.StatusFound, redirectUrl)
149 }
150
151 func (albyHttpSvc *AlbyHttpService) albyMeHandler(c echo.Context) error {
152 me, err := albyHttpSvc.albyOAuthSvc.GetMe(c.Request().Context())
153 if err != nil {
154 logger.Logger.WithError(err).Error("Failed to request alby me endpoint")
155 return c.JSON(http.StatusInternalServerError, ErrorResponse{
156 Message: fmt.Sprintf("Failed to request alby me endpoint: %s", err.Error()),
157 })
158 }
159
160 return c.JSON(http.StatusOK, me)
161 }
162
163 func (albyHttpSvc *AlbyHttpService) albyLinkAccountHandler(c echo.Context) error {
164 var linkAccountRequest alby.AlbyLinkAccountRequest
165 if err := c.Bind(&linkAccountRequest); err != nil {
166 return c.JSON(http.StatusBadRequest, ErrorResponse{
167 Message: fmt.Sprintf("Bad request: %s", err.Error()),
168 })
169 }
170
171 err := albyHttpSvc.albyOAuthSvc.LinkAccount(c.Request().Context(), albyHttpSvc.svc.GetLNClient(), linkAccountRequest.Budget, linkAccountRequest.Renewal)
172 if err != nil {
173 logger.Logger.WithError(err).Error("Failed to connect alby account")
174 return err
175 }
176
177 return c.NoContent(http.StatusNoContent)
178 }
179