I had stuck with Google Cloud Storage and os.create()
This is my example code
func upload(w http.ResponseWriter, r *http.Request) {
// some process request msg, decode base64 to image byte
// create image file in current directory with os.create()
//
path := os.create("shop_logo.jpeg")
bucket := client.Bucket("myBucket")
write := bucket.Object(path).NewWriter(ctx)
}
Create file with directory
func upload(w http.ResponseWriter, r *http.Request) {
// some process request msg, decode base64 to image byte
// create image file in current directory with os.create()
//
path := os.create("home/../project/repo/shop_logo.jpeg") //absolute path
bucket := client.Bucket("myBucket")
write := bucket.Object(path).NewWriter(ctx)
}
Acutally everything it work, like mybucket/shop_logo.jpeg
But I want to organize the bucket path such as mybucket/shop_v1/shop_logo.jpeg
But the I used the os.create() like os.create("shop_v1/shop_logo.jpeg)
It's can't work, look like this function can't create the folder.
but when I used the Absolute Path It's work. like os.create("/home/project/shop_v1/shop_logo.jpeg)
The problem is bucket.Object("path/to/image_file") is require the path of file.
So If I used the Absolute Path to upload it.
My bucket will be myBucket/home/project/shop_v1/shop_logo.jpeg .
But the thing that I expect it is mybucket/shop_v1/shop_logo.jpeg
Anyone have idea?
Oh, I just found the os.create() can create directory also.
It my fault like this
inputPath := "/shop_v1/shop_logo.jpeg"
os.create(inputPath)
The application will error, can't find blah blah.
I just have to remove the first slash of inputPath variable
inputPath := "shop_v1/shop_logo.jpeg"
os.create(inputPath)
Now it work!.
Related
I would love to be able to set my executable to handle custom Url Scheme (aaa:) so that I can handle deep linking with my program.
You need to modify Windows registry, in order to tell os which protocol to open with which executable.
There are multiple ways you can go about it, depending if you want to add your url scheme handler for all users or for current user.
Easiest way to handle it is to make Windows pass custom url as argument to default executable.
That way both chrome and edge will ask user to open your installed app.
Here is a minimal Golang implementation to set your executable as default url scheme handler:
var k registry.Key
var err error
prefix := "SOFTWARE\\Classes\\"
urlScheme := "aaa"
basePath := prefix + urlScheme
permission := uint32(registry.QUERY_VALUE | registry.SET_VALUE)
baseKey := registry.CURRENT_USER
programLocation := "\"C:\\Windows\\notepad.exe\""
// create key
registry.CreateKey(baseKey, basePath, permission)
// set description
k.SetStringValue("", "Notepad app")
k.SetStringValue("URL Protocol", "")
// set icon
registry.CreateKey(registry.CURRENT_USER, "lumiere\\DefaultIcon", registry.ALL_ACCESS)
k.SetStringValue("", softwareToOpen+",1")
// create tree
registry.CreateKey(baseKey, basePath+"\\shell", permission)
registry.CreateKey(baseKey, basePath+"\\shell\\open", permission)
registry.CreateKey(baseKey, basePath+"\\shell\\open\\command", permission)
// set open command
k.SetStringValue("", softwareToOpen+" \"%1\"")
Getting custom URL after having your app set as default is quite straightforward
You can do this:
func main() {
url := os.Args[1:]
log.Printf("my custom aaa url is: %s", url)
}
As mentioned in GoDocs, os.Create() creates a file in specific path.
os.Create("fonts/foo/font.eot")
But when fonts or foo doesn't exists, it returns panic: open fonts/foo/font.eot: The system cannot find the path specified.
So i used os.MkdirAll() to create nested directory. But there are many other problems with this function.
path := "fonts/foo/font.eot"
// this line create a directory named (font.eot) !
os.MkdirAll(path, os.ModePerm)
Is there any better way to create a file in nested directories?
The standard way is something like this:
func create(p string) (*os.File, error) {
if err := os.MkdirAll(filepath.Dir(p), 0770); err != nil {
return nil, err
}
return os.Create(p)
}
A few notes:
os.Create does not panic as stated in the question.
Create a directory from the directory part of the file path, not the full path.
I'd like to have a single binary for a go-app, rather than having to bundle static files alongside the deployment.
I'm using a function like this to access PNGs I'm loading:
func getFileList(dir string) (fileList []os.FileInfo, err error) {
// USAGE:
// fileList,_ := getFileList(PNG_DIR)
f, err := os.Open(PNG_DIR)
defer f.Close()
checkErr(err)
fileList, err = f.Readdir(0)
checkErr(err)
return fileList, err
}
I take this list of files and serve it on a static endpoint, with some logic.
I have read the following documentation for using go-assets
https://github.com/jessevdk/go-assets-builder/blob/master/builder.go
https://github.com/jessevdk/go-assets-builder
https://github.com/jessevdk/go-assets/blob/master/generate.go
As well as this gin specific example:
https://github.com/gin-gonic/gin/blob/master/examples/assets-in-binary/assets.go
https://github.com/jessevdk/go-assets/blob/master/example_test.go
https://github.com/gin-gonic/gin/tree/master/examples/assets-in-binary
Which contains the following example:
Prepare Packages
go get github.com/gin-gonic/gin go get
github.com/jessevdk/go-assets-builder
Generate assets.go
go-assets-builder html -o assets.go
Build the server
go build -o assets-in-binary
Run
./assets-in-binary
However, it's not clear to me how to call this file I have built. For example, What do I change in my getFileList() function to now point to whatever I built in the binary, what is it even called and how would I know that?
Usually on gin you would use router.Statuc(path, dir) however you said you first load a list of files and I guess you will later use http.ServeFile.
With go-bindata you have all the files already inside the executable, you can access them using the Asset(file) function...
Basically this is a very simple static handler for gin:
func StaticHandler(c *gin.Context) {
p := c.Param("filepath")
data, err := Assets(p)
if err != nil { return }
c.Writer.Write(data)
}
You can register the static handler into your router:
router.GET("/static/*filepath", StaticHandler)
This allows to access static resources the following way: /static/css/style.css and will load the file css/style.css
You could get the list of files inside your folder, create a map and use that map for the static handler (to limit what files are accesed)
I am building a web application.
On one of the pages there is an upload form, where user can upload a file. After the upload is done, I want to check on the server if the uploaded file is an image.
Is it possible to check this beyond simple file extension checking (i.e. not assuming that a *.png filename is actually a PNG image)?
For example, if I edit a JPEG image adding/editing a byte in a random place to make an invalid JPEG file, I want to detect that it is not a JPEG image anymore. I used to do such type of thing via PHP some time ago, using a GD library.
I would like to know if it is possible to do with Go?
DetectContentType is way better than a manual magic number checking. The use is simple:
clientFile, _, _ := r.FormFile("img") // or get your file from a file system
defer clientFile.Close()
buff := make([]byte, 512) // docs tell that it take only first 512 bytes into consideration
if _, err = clientFile.Read(buff); err != nil {
fmt.Println(err) // do something with that error
return
}
fmt.Println(http.DetectContentType(buff)) // do something based on your detection.
Using this method you need to know that you still are not guaranteed to have a correct file. So I would recommend to do some image manipulation with that file (like resize it to make sure this is really an image).
The http package can do this for you:
func DetectContentType(data []byte) string
DetectContentType implements the algorithm described at
http://mimesniff.spec.whatwg.org/ to determine the Content-Type of the
given data. It considers at most the first 512 bytes of data.
DetectContentType always returns a valid MIME type: if it cannot
determine a more specific one, it returns "application/octet-stream".
Code: https://golang.org/src/net/http/sniff.go
What is usually done is checking if the file has the right magic number for the image file format you want. While this test is not super accurate, it is usually good enough. You can use code like this:
package foo
import "strings"
// image formats and magic numbers
var magicTable = map[string]string{
"\xff\xd8\xff": "image/jpeg",
"\x89PNG\r\n\x1a\n": "image/png",
"GIF87a": "image/gif",
"GIF89a": "image/gif",
}
// mimeFromIncipit returns the mime type of an image file from its first few
// bytes or the empty string if the file does not look like a known file type
func mimeFromIncipit(incipit []byte) string {
incipitStr := []byte(incipit)
for magic, mime := range magicTable {
if strings.HasPrefix(incipitStr, magic) {
return mime
}
}
return ""
}
I'm working on a small web application in Go that's meant to be used as a tool on a developer's machine to help debug their applications/web services. The interface to the program is a web page that includes not only the HTML but some JavaScript (for functionality), images, and CSS (for styling). I'm planning on open-sourcing this application, so users should be able to run a Makefile, and all the resources will go where they need to go. However, I'd also like to be able to simply distribute an executable with as few files/dependencies as possible. Is there a good way to bundle the HTML/CSS/JS with the executable, so users only have to download and worry about one file?
Right now, in my app, serving a static file looks a little like this:
// called via http.ListenAndServe
func switchboard(w http.ResponseWriter, r *http.Request) {
// snipped dynamic routing...
// look for static resource
uri := r.URL.RequestURI()
if fp, err := os.Open("static" + uri); err == nil {
defer fp.Close()
staticHandler(w, r, fp)
return
}
// snipped blackhole route
}
So it's pretty simple: if the requested file exists in my static directory, invoke the handler, which simply opens the file and tries to set a good Content-Type before serving. My thought was that there's no reason this needs to be based on the real filesystem: if there were compiled resources, I could simply index them by request URI and serve them as such.
Let me know if there's not a good way to do this or I'm barking up the wrong tree by trying to do this. I just figured the end-user would appreciate as few files as possible to manage.
If there are more appropriate tags than go, please feel free to add them or let me know.
Starting with Go 1.16 the go tool has support for embedding static files directly in the executable binary.
You have to import the embed package, and use the //go:embed directive to mark what files you want to embed and into which variable you want to store them.
3 ways to embed a hello.txt file into the executable:
import "embed"
//go:embed hello.txt
var s string
print(s)
//go:embed hello.txt
var b []byte
print(string(b))
//go:embed hello.txt
var f embed.FS
data, _ := f.ReadFile("hello.txt")
print(string(data))
Using the embed.FS type for the variable you can even include multiple files into a variable that will provide a simple file-system interface:
// content holds our static web server content.
//go:embed image/* template/*
//go:embed html/index.html
var content embed.FS
The net/http has support to serve files from a value of embed.FS using http.FS() like this:
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(content))))
The template packages can also parse templates using text/template.ParseFS(), html/template.ParseFS() functions and text/template.Template.ParseFS(), html/template.Template.ParseFS() methods:
template.ParseFS(content, "*.tmpl")
The following of the answer lists your old options (prior to Go 1.16).
Embedding Text Files
If we're talking about text files, they can easily be embedded in the source code itself. Just use the back quotes to declare the string literal like this:
const html = `
<html>
<body>Example embedded HTML content.</body>
</html>
`
// Sending it:
w.Write([]byte(html)) // w is an io.Writer
Optimization tip:
Since most of the times you will only need to write the resource to an io.Writer, you can also store the result of a []byte conversion:
var html = []byte(`
<html><body>Example...</body></html>
`)
// Sending it:
w.Write(html) // w is an io.Writer
Only thing you have to be careful about is that raw string literals cannot contain the back quote character (`). Raw string literals cannot contain sequences (unlike the interpreted string literals), so if the text you want to embed does contain back quotes, you have to break the raw string literal and concatenate back quotes as interpreted string literals, like in this example:
var html = `<p>This is a back quote followed by a dot: ` + "`" + `.</p>`
Performance is not affected, as these concatenations will be executed by the compiler.
Embedding Binary Files
Storing as a byte slice
For binary files (e.g. images) most compact (regarding the resulting native binary) and most efficient would be to have the content of the file as a []byte in your source code. This can be generated by 3rd party toos/libraries like go-bindata.
If you don't want to use a 3rd party library for this, here's a simple code snippet that reads a binary file, and outputs Go source code that declares a variable of type []byte that will be initialized with the exact content of the file:
imgdata, err := ioutil.ReadFile("someimage.png")
if err != nil {
panic(err)
}
fmt.Print("var imgdata = []byte{")
for i, v := range imgdata {
if i > 0 {
fmt.Print(", ")
}
fmt.Print(v)
}
fmt.Println("}")
Example output if the file would contain bytes from 0 to 16 (try it on the Go Playground):
var imgdata = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
Storing as base64 string
If the file is not "too large" (most images/icons qualify), there are other viable options too. You can convert the content of the file to a Base64 string and store that in your source code. On application startup (func init()) or when needed, you can decode it to the original []byte content. Go has nice support for Base64 encoding in the encoding/base64 package.
Converting a (binary) file to base64 string is as simple as:
data, err := ioutil.ReadFile("someimage.png")
if err != nil {
panic(err)
}
fmt.Println(base64.StdEncoding.EncodeToString(data))
Store the result base64 string in your source code, e.g. as a const.
Decoding it is just one function call:
const imgBase64 = "<insert base64 string here>"
data, err := base64.StdEncoding.DecodeString(imgBase64) // data is of type []byte
Storing as quoted string
More efficient than storing as base64, but may be longer in source code is storing the quoted string literal of the binary data. We can obtain the quoted form of any string using the strconv.Quote() function:
data, err := ioutil.ReadFile("someimage.png")
if err != nil {
panic(err)
}
fmt.Println(strconv.Quote(string(data))
For binary data containing values from 0 up to 64 this is how the output would look like (try it on the Go Playground):
"\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?"
(Note that strconv.Quote() appends and prepends a quotation mark to it.)
You can directly use this quoted string in your source code, for example:
const imgdata = "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?"
It is ready to use, no need to decode it; the unquoting is done by the Go compiler, at compile time.
You may also store it as a byte slice should you need it like that:
var imgdata = []byte("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?")
The go-bindata package looks like it might be what you're interested in.
https://github.com/go-bindata/go-bindata
It will allow you to convert any static file into a function call that can be embedded in your code and will return a byte slice of the file content when called.
Bundle React application
For example, you have a build output from react like the following:
build/favicon.ico
build/index.html
build/asset-manifest.json
build/static/css/**
build/static/js/**
build/manifest.json
When you use go:embed like this, it will serve the contents as http://localhost:port/build/index.html which is not what we want (unexpected /build).
//go:embed build/*
var static embed.FS
// ...
http.Handle("/", http.FileServer(http.FS(static)))
In fact, we will need to take one more step to make it works as expected by using fs.Sub:
package main
import (
"embed"
"io/fs"
"log"
"net/http"
)
//go:embed build/*
var static embed.FS
func main() {
contentStatic, _ := fs.Sub(static, "build")
http.Handle("/", http.FileServer(http.FS(contentStatic)))
log.Fatal(http.ListenAndServe("localhost:8080", nil))
}
Now, http://localhost:8080 should serve your web application as expected.
Credit to Amit Mittal.
Note: go:embed requires go 1.16 or higher.
also there is some exotic way - I use maven plugin to build GoLang projects and it allows to use JCP preprocessor to embed binary blocks and text files into sources. In the case code just look like line below (and some example can be found here)
var imageArray = []uint8{/*$binfile("./image.png","uint8[]")$*/}
As a popular alternative to go-bindata mentioned in another answer, mjibson/esc also embeds arbitrary files, but handles directory trees particularly conveniently.