GRPC: quick create static file download Web service

Posted by chen2424 on Mon, 06 Dec 2021 23:56:02 +0100

introduce

This article describes how to rk-boot Quickly build a static file download Web service.

What is the static file download Web UI?

Quickly build Web services that can download files through configuration files.

Please visit the following address for a complete tutorial:

install

go get github.com/rookie-ninja/rk-boot

Quick start

Rk boot provides a convenient method for users to quickly realize the function of web page [browsing and downloading] static files.

Currently, rk boot supports the following file sources. If users want to support more file sources, they can implement the http.FileSystem interface.

  • Local file system
  • pkger

1. Create boot.yaml

---
grpc:
  - name: greeter                     # Required
    port: 8080                        # Required
    enabled: true                     # Required
    static:
      enabled: true                   # Optional, default: false
      path: "/rk/v1/static"           # Optional, default: /rk/v1/static
      sourceType: local               # Required, options: pkger, local
      sourcePath: "."                 # Required, full path of source directory

2. Create main.go

// Copyright (c) 2021 rookie-ninja
//
// Use of this source code is governed by an Apache-style
// license that can be found in the LICENSE file.
package main

import (
	"context"
	"github.com/rookie-ninja/rk-boot"
)

// Application entrance.
func main() {
	// Create a new boot instance.
	boot := rkboot.NewBoot()

	// Bootstrap
	boot.Bootstrap(context.Background())

	// Wait for shutdown sig
	boot.WaitForShutdownSig(context.Background())
}

3. Folder structure

.
├── boot.yaml
├── go.mod
├── go.sum
└── main.go

0 directories, 4 files

4. Verification

visit http://localhost:8080/rk/v1/static

Read file from pkger (embedded static file)

pkger Is a tool that can embed static files into. go files.

In this example, we embed all the files in the current folder into the pkger.go file.

The advantage of this is that you don't have to consider copying a pile of folder structures during deployment.

1. Download pkger command line

go get github.com/markbates/pkger/cmd/pkger

2. Create boot.yaml

pkger will use modules to distinguish different package s. Therefore, in sourcePath, we added the prefix of corresponding modules.

---
grpc:
  - name: greeter                                             # Required
    port: 8080                                                # Required
    enabled: true                                             # Required
    static:
      enabled: true                                           # Optional, default: false
      path: "/rk/v1/static"                                   # Optional, default: /rk/v1/static
      sourceType: pkger                                       # Required, options: pkger, local
      sourcePath: "github.com/rookie-ninja/rk-demo:/"         # Required, full path of source directory

3. Create main.go

There are two things to note in the code.

  • pkger.Include("./")

This code does nothing but tell the pkger command line which files to package.

  • _ "github.com/rookie-ninja/rk-demo/internal"

We must import it in this way, because we will put the pkger.go file into internal/pkger.go, and set variables in the pkger.go file. Only in this way can we import variables smoothly when compiling main.go.

// Copyright (c) 2021 rookie-ninja
//
// Use of this source code is governed by an Apache-style
// license that can be found in the LICENSE file.
package main

import (
	"context"
	"github.com/markbates/pkger"
	"github.com/rookie-ninja/rk-boot"
	// Must be present in order to make pkger load embedded files into memory.
	_ "github.com/rookie-ninja/rk-demo/internal"
)

func init() {
	// This is used while running pkger CLI
	pkger.Include("./")
}

// Application entrance.
func main() {
	// Create a new boot instance.
	boot := rkboot.NewBoot()

	// Bootstrap
	boot.Bootstrap(context.Background())

	// Wait for shutdown sig
	boot.WaitForShutdownSig(context.Background())
}

4. Generate pkger.go

pkger -o internal

5. Folder structure

.
├── boot.yaml
├── go.mod
├── go.sum
├── internal
│   └── pkged.go
└── main.go

1 directory, 5 files

6. Verification

visit http://localhost:8080/rk/v1/static

Custom file source

We will use memFs in afero package as an example.

If you want to read from AWS S3, you can implement your own http.FileSystem.

Rk boot will gradually implement these functions in subsequent updates.

1. Create boot.yaml

---
grpc:
  - name: greeter                     # Required
    port: 8080                        # Required
    enabled: true                     # Required

2. Create main.go

We created a / folder folder and a / file.txt file in memFs.

// Copyright (c) 2021 rookie-ninja
//
// Use of this source code is governed by an Apache-style
// license that can be found in the LICENSE file.
package main

import (
	"context"
	"github.com/rookie-ninja/rk-boot"
	"github.com/rookie-ninja/rk-grpc/boot"
	"github.com/spf13/afero"
	"os"
)

// Application entrance.
func main() {
	// Create a new boot instance.
	boot := rkboot.NewBoot()

	// Create a memory fs
	fs := afero.NewHttpFs(afero.NewMemMapFs())

	// Add folder and file.txt into memory fs
	fs.MkdirAll("/folder", os.ModePerm)
	f, _ := fs.Create("/file.txt")
	f.Write([]byte("this is my content!"))
	f.Close()

	// Set StaticFileEntry
	grpcEntry := boot.GetGrpcEntry("greeter")
	grpcEntry.StaticFileEntry = rkgrpc.NewStaticFileHandlerEntry(
		rkgrpc.WithPathStatic("/rk/v1/static"),
		rkgrpc.WithFileSystemStatic(fs))

	// Bootstrap
	boot.Bootstrap(context.Background())

	// Wait for shutdown sig
	boot.WaitForShutdownSig(context.Background())
}

3. Verification

visit http://localhost:8080/rk/v1/static

Topics: Go Microservices grpc