Flutter web with Golang Server - go

Is it possible to run flutter web build using golang server? Golang has facility to serve html file and flutter web gives output as index.html and js files.
if it is possible then how golang code should look like?

as the friendly doc mentions it, i believe you got to build your app.
https://flutter.dev/docs/get-started/web#build
Run the following command to generate a release build:
flutter build web
This populates a build/web directory with built files, including an assets directory, which need to be served together.
how golang code should look like?
like any other regular HTTP golang server.
http.Handle("/build/web/", http.StripPrefix("/build/web/", http.FileServer(http.Dir("build/web"))))
http.ListenAndServe(":8080", nil)

package main
import (
"flag"
"log"
"net/http"
)
func main() {
port := flag.String("p", "8181", "port to serve on")
directory := flag.String("d", "web", "the directory of static file to host")
flag.Parse()
http.Handle("/", http.FileServer(http.Dir(*directory)))
log.Printf("Serving %s on HTTP port: %s\n", *directory, *port)
log.Fatal(http.ListenAndServe(":"+*port, nil))
}
Just copy web folder to your's go app.

Related

gcp cloud function returns 404 when deployed from command line

If I deploy the example hello world within the console, the url/trigger works. If I deploy from command line it looks to be exact same code / attributes in cloud functions console, but the url is 404. I can't spot the difference/issue.
The deployed trigger/url shows - "404 page not found" for the below hello world example if deployed this way from command line.
gcloud functions deploy hellogo --entry-point=HelloWorld --trigger-http --region=us-central1 --memory=128MB --runtime=go116 --allow-unauthenticated
// Package p contains an HTTP Cloud Function.
package p
import (
"encoding/json"
"fmt"
"html"
"io"
"log"
"net/http"
)
// HelloWorld prints the JSON encoded "message" field in the body
// of the request or "Hello, World!" if there isn't one.
func HelloWorld(w http.ResponseWriter, r *http.Request) {
var d struct {
Message string `json:"message"`
}
if err := json.NewDecoder(r.Body).Decode(&d); err != nil {
switch err {
case io.EOF:
fmt.Fprint(w, "Hello World!")
return
default:
log.Printf("json.NewDecoder: %v", err)
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
}
if d.Message == "" {
fmt.Fprint(w, "Hello World!")
return
}
fmt.Fprint(w, html.EscapeString(d.Message))
}
Tried to reproduce your error but couldn't replicate on my end. I've use the same command as yours and I can successfully access the url or call via HTTP trigger the deployed hello world cloud function.
gcloud functions deploy hellogo --entry-point=HelloWorld --trigger-http --region=us-central1 --memory=128MB --runtime=go116 --allow-unauthenticated
Output of successful curl:
I suggest you check the url you're trying to access since according to this GCP doc:
If you attempt to invoke a function that does not exist, Cloud Functions responds with an HTTP/2 302 redirect which takes you to the Google account login page. This is incorrect. It should respond with an HTTP/2 404 error response code. The problem is being addressed.
The solution
Make sure you specify the name of your function correctly. You can
always check using gcloud functions call which returns the correct 404
error for a missing function.
You can also refer to this complete guide to quickstart your CF creation and deployment using the Go runtime.
Thanks all, my project where I got stuck has more code in it than just this function. I went down this path after trying to deploy a single function/file within larger project. If I simplify down to a folder with just a hello.go and go.mod indeed it works :-/ to deploy it from command line:
gcloud functions deploy hellogo --entry-point=HelloWorld --trigger-http --region=us-central1 --memory=128MB --runtime=go116 --allow-unauthenticated
// go.mod
module github.com/nickfoden/hello
go 1.16
Thank you for the fast replies and assistance. Rather than try to create a single function within existing project with larger go.sum, multiple folders, existing server/api etc. I am going to start from here having a single file with a cloud function and build on top of it and see at what point/if I get stuck again.

Is embedding a directory supported for cross-compilation?

Summary of the problem: access to embedded files in directories work for a native compilation but not for cross-compiled code
I have the following code that embeds a file (static/index.html) in a directory and exposes it via HTTP:
package main
import (
"embed"
"net/http"
"os"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/rs/cors"
"github.com/rs/zerolog/log"
)
//go:embed static
var content embed.FS
func main() {
// API and static site
r := mux.NewRouter()
r.Use(mux.CORSMethodMiddleware(r))
r.Use(func(next http.Handler) http.Handler {
return handlers.LoggingHandler(os.Stdout, next)
})
c := cors.New(cors.Options{
AllowCredentials: true,
//Debug: true,
})
handler := c.Handler(r)
r.PathPrefix("/").Handler(http.FileServer(http.Dir("./static/")))
log.Info().Msg("starting dash webserver at port 1495")
_ = http.ListenAndServe("0.0.0.0:1495", handler)
}
I compiled this code (go1.16.7) in Windows 10 WSL2 (EDIT: and in native Windows 10) via go build -o goembed.wsl2. When started, running curl localhost:1495 gives the right result (the text in index.html).
I then compiled it (still in WSL2/Win10) via env GOOS=linux GOARCH=amd64 go build -o goembed.linux (or the relevant incantation in Windows 10 to set the environment variables) and started goembed.linux on an Ubuntu 18.04 server.
The program started but the output of curl localhost:1495 was 404 File Not Found.
Why is it so?
Interestingly, embedding a single file (the variable containing it is then of type []byte) exposes it correctly via the HTTP server in both binaries (the native WSL one, and the amd64).
EDIT: I have the same behaviour when compiling in native Windows 10, I updated the references above
It is a mistake from my side: I embed static but serve ./static/ which is the local (OS) directory, instead of the embedded one. It should be:
r.PathPrefix("/").Handler(http.FileServer(http.FS(content)))

Go web server 404 page not found

I am new to web assembly
I write a web.go to server index.html wasm_exec.js main.wasm under directory Hello_WebAssembly
Then I go run web.go in terminal
Then i go to localhost:8080 it reports 404 page not found
I am following the instructions https://github.com/golang/go/wiki/WebAssembly
Here is my web.go code
package main
import (
"log"
"net/http"
)
func main() {
fs := http.FileServer(http.Dir("Hello_WebAssembly"))
http.Handle("/", fs)
log.Println("Listening...")
http.ListenAndServe(":8080", nil)
}
I don't know why
Hope someone can help me out
Thanks in advance
By the way my OS is win10
I presume your project is called Hello_WebAssembly and you are running the go run command from within the folder.
If this is the case, then your http.Dirinvocation should be http.Dir(".") as you want to serve resources from your current directory (the Project).

How to load local assets within a GCP cloud function?

I'm building a tiny GCP cloud function in Golang that returns a generated PNG file when calling it via HTTP. I deployed my code via ZIP-Upload in the Google Cloud Console.
Currently it gets called properly and the code gets compiled etc. But in my code I have to load several local files - a font and a .png image.
I bundled those in the ZIP I uploaded and the files are visible in the Source-View in GCP. All files (images, fonts and go-files) are within the same directory.
When calling the cloud function the log states the following:
2019/01/21 14:59:31 open /english.png: no such file or directory
I tried to change the way i build the path to the file in go. I already used /german.png statically, used several attempts to build the path dynamically.
I'm not 100 percent sure if this is the way to go, but it is my first experiment with "serverless" and i am willing to get it done the "right" way.
import "github.com/fogleman/gg"
func main() {
ex, err := os.Executable()
if err != nil {
panic(err)
}
executableDir := filepath.Dir(ex)
img, err :=gg.LoadPNG(path.Join(executableDir, "./english.png"))
if err != nil {
log.Fatal(err)
}
}
Currently the file can not be found in any attempt i made. Maybe the path the images get "deployed" into are different from the ones i tried - i have not found any note on that in the documentation.
I'd obviously expect it to be loaded properly.
For the Go 1.13 according to the documentation, as of today (Jul 2020), source code is located in the ./serverless_function_source_code directory.
A good reference to follow is the buildpack.
I created http functions with the following structure:
api
|--test.txt
|--api.go
And wrote simple function to reply with file content:
package api
import (
"io/ioutil"
"net/http"
)
// FileTest func
func FileTest(w http.ResponseWriter, r *http.Request) {
content, err := ioutil.ReadFile("./test.txt")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
w.Write(content)
}
It returns the file content without any problems. https://us-central1-clickshield24m.cloudfunctions.net/api
So in your case I would try change the path to gg.LoadPNG("./english.png")
./serverless_function_source_code didn't work for me using go113 runtime with vendoring. I wanted to locate a file in the vendor directory.
My file structure is:
myfn
|- main.go
|- go.mod
|- .gcloudignore
My deployment steps are:
cd myfn
go mod vendor
gcloud functions deploy MyFunction --runtime go113 --set-env-vars "PATH_FILES=./src/myfn/vendor/static"
I found this out by deploying a function that listed all files to a certain depth starting with "." and didn't see a serverless_function_source_code directory. But there was src/myfn.

How to get project ID using Go SDK for Google cloud platform?

I would like to fetch project-id in Go through the service account I am using in my system so that whenever that code runs on a compute instance in GCP, it should retrieve the project-id where the compute instance lies. Also if I run the code from my local machine, it should get the project-id same as "gcloud info" command gets from command line.
Does anyone have any idea which API to use in Go?
Figured out the correct API.
package main
import (
"fmt"
"golang.org/x/net/context"
"google.golang.org/api/compute/v1"
"golang.org/x/oauth2/google"
)
func main() {
ctx := context.Background()
credentials, err := google.FindDefaultCredentials(ctx,compute.ComputeScope)
if err != nil {
fmt.Println(err)
}
fmt.Printf(credentials.ProjectID)
}
You can find out the project ID of the Compute Engine instance by using the Google Cloud API [1] with a GET request to “http://metadata.google.internal/computeMetadata/v1/project/project-id” with the header “Metadata-Flavor: Google” in order to be allowed.
It can be tested in the Cloud Shell or a secure shell (SSH) terminal by using:
curl
"http://metadata.google.internal/computeMetadata/v1/project/project-id"
-H "Metadata-Flavor: Google"
[1] : https://cloud.google.com/compute/docs/storing-retrieving-metadata#default

Resources