Skip to content

Commit f0ca659

Browse files
authored
Merge pull request #108 from blinklabs-io/feat-show-qr-code
feat: add QRcode generate to scan it with snek mobile
2 parents 75b71dd + cac1f86 commit f0ca659

File tree

5 files changed

+86
-13
lines changed

5 files changed

+86
-13
lines changed

api/api.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ type API interface {
1919

2020
type APIv1 struct {
2121
engine *gin.Engine
22-
apiGroup *gin.RouterGroup
23-
host string
24-
port string
22+
ApiGroup *gin.RouterGroup
23+
Host string
24+
Port string
2525
}
2626

2727
type APIRouteRegistrar interface {
@@ -33,19 +33,19 @@ type APIOption func(*APIv1)
3333
func WithGroup(group string) APIOption {
3434
// Expects '/v1' as the group
3535
return func(a *APIv1) {
36-
a.apiGroup = a.engine.Group(group)
36+
a.ApiGroup = a.engine.Group(group)
3737
}
3838
}
3939

4040
func WithHost(host string) APIOption {
4141
return func(a *APIv1) {
42-
a.host = host
42+
a.Host = host
4343
}
4444
}
4545

4646
func WithPort(port string) APIOption {
4747
return func(a *APIv1) {
48-
a.port = port
48+
a.Port = port
4949
}
5050
}
5151

@@ -56,8 +56,8 @@ func New(debug bool, options ...APIOption) *APIv1 {
5656
once.Do(func() {
5757
apiInstance = &APIv1{
5858
engine: ConfigureRouter(debug),
59-
host: "localhost",
60-
port: "8080",
59+
Host: "localhost",
60+
Port: "8080",
6161
}
6262
for _, opt := range options {
6363
opt(apiInstance)
@@ -87,7 +87,7 @@ func (a *APIv1) Engine() *gin.Engine {
8787
// @license.name Apache 2.0
8888
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
8989
func (a *APIv1) Start() error {
90-
address := a.host + ":" + a.port
90+
address := a.Host + ":" + a.Port
9191
// Use buffered channel to not block goroutine
9292
errChan := make(chan error, 1)
9393

@@ -132,8 +132,8 @@ func (a *APIv1) AddRoute(method, path string, handler gin.HandlerFunc) {
132132

133133
// Check if a specific apiGroup is set
134134
// If so, add the route to it. Otherwise, add to the main engine.
135-
if a.apiGroup != nil {
136-
addRouteToTarget(a.apiGroup)
135+
if a.ApiGroup != nil {
136+
addRouteToTarget(a.ApiGroup)
137137
} else {
138138
addRouteToTarget(a.engine)
139139
}

api/api_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ import (
1111
)
1212

1313
func TestRouteRegistration(t *testing.T) {
14+
1415
// Initialize the API and set it to debug mode for testing
1516
apiInstance := api.New(true)
1617

1718
// Check if Fcm implements APIRouteRegistrar and register its routes
18-
// TODO: update this with actual plugin
1919
pushPlugin := &push.PushOutput{}
2020
if registrar, ok := interface{}(pushPlugin).(api.APIRouteRegistrar); ok {
2121
registrar.RegisterRoutes()

cmd/snek/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func main() {
105105
}
106106

107107
// Create API instance with debug disabled
108-
apiInstance := api.New(true,
108+
apiInstance := api.New(false,
109109
api.WithGroup("/v1"),
110110
api.WithPort("8080"))
111111

output/push/api_routes.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ func (p *PushOutput) RegisterRoutes() {
2727
}
2828

2929
apiInstance := api.GetInstance()
30+
var apiEndpoint string
31+
if apiInstance.ApiGroup != nil {
32+
apiEndpoint = apiInstance.Host + apiInstance.ApiGroup.BasePath() + "/fcm"
33+
} else {
34+
apiEndpoint = apiInstance.Host + "/fcm"
35+
}
3036

3137
apiInstance.AddRoute("POST", "/fcm", storeFCMToken)
3238
apiInstance.AddRoute("POST", "/fcm/", storeFCMToken)
@@ -37,5 +43,7 @@ func (p *PushOutput) RegisterRoutes() {
3743
apiInstance.AddRoute("DELETE", "/fcm/:token", deleteFCMToken)
3844
apiInstance.AddRoute("DELETE", "/fcm/:token/", deleteFCMToken)
3945

46+
apiInstance.AddRoute("GET", "/qrcode", generateQRPage(apiEndpoint))
47+
4048
routesRegistered = true
4149
}

output/push/qr_generator.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package push
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"net/http"
7+
"text/template"
8+
9+
"github.com/gin-gonic/gin"
10+
)
11+
12+
type QRValue struct {
13+
ApiEndpoint string `json:"apiEndpoint"`
14+
}
15+
16+
func generateQRPage(apiEndpoint string) gin.HandlerFunc {
17+
return func(c *gin.Context) {
18+
qrValue, err := json.Marshal(QRValue{
19+
ApiEndpoint: apiEndpoint,
20+
})
21+
if err != nil {
22+
c.JSON(http.StatusInternalServerError, gin.H{
23+
"error": err.Error(),
24+
})
25+
return
26+
}
27+
28+
qrValueEscaped := template.JSEscapeString(string(qrValue))
29+
30+
htmlContent := fmt.Sprintf(`
31+
<!DOCTYPE html>
32+
<html lang="en">
33+
<head>
34+
<meta charset="UTF-8">
35+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
36+
<title>QR Code</title>
37+
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
38+
<script src="https://cdn.jsdelivr.net/npm/qrious@latest/dist/qrious.min.js"></script>
39+
</head>
40+
<body class="bg-gray-100 h-screen flex items-center justify-center">
41+
<!-- QR Code Container -->
42+
<div class="bg-white p-8 rounded-lg shadow-md text-center">
43+
<p class="text-xl mb-4">Scan QR code with Snek Mobile to connect to the Snek Server on <span class="font-semibold">%s</span></p>
44+
<canvas id="qrCanvas" class="mx-auto"></canvas>
45+
</div>
46+
47+
<!-- Generate QR Code using JavaScript -->
48+
<script>
49+
window.onload = function() {
50+
const canvas = document.getElementById('qrCanvas');
51+
const qrValue = "%s";
52+
const qr = new QRious({
53+
element: canvas,
54+
value: qrValue,
55+
size: 250
56+
});
57+
}
58+
</script>
59+
</body>
60+
</html>
61+
`, apiEndpoint, qrValueEscaped)
62+
63+
c.Data(http.StatusOK, "text/html; charset=utf-8", []byte(htmlContent))
64+
}
65+
}

0 commit comments

Comments
 (0)