I try to use REST over gRPC using google api annotations.
Unfortunately, I'm facing a protoc issue telling me annotations.proto is not exists or had errors.
I tried several fixes in vain.
I even tried to reinstall a complete stack in case I did something wrong.
I will detail you as much as possible the full lines and files I have set from my fresh install.
From a fresh go install VM I type these shell lines :
$ mkdir sources/golang
$ echo 'export GOPATH=$HOME/sources/golang' >> $HOME/.zshrc
$ source ~/.zshrc
$ cd sources/golang
$ mkdir src
$ cd src
$ export PATH=$PATH:$GOPATH/bin
$ go get -u google.golang.org/grpc
$ go get -u github.com/golang/protobuf/protoc-gen-go
$ go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
$ go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
$ mkdir -p test/proto/test
$ cd test/proto/test
$ vim test.proto
In My test.proto file, I wrote very basic lines :
syntax = "proto3";
package main;
import "google/api/annotations.proto";
service Tester {
rpc Test (Request) returns (Reply) {
option (google.api.http) = { get: "/v1/test" };
}
}
message Request {
string Message = 1;
}
message Reply {
string Message = 1;
}
Then
$ cd $GOPATH/src
$ vim main.go
In my main.go, very basic too :
package main
import (
tc "test/proto/test"
"context"
"fmt"
"log"
"net"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
)
func main() {
err := StartServer("tcp", "127.0.0.1:50051")
if err != nil {
fmt.Printf("Error!! %s", err)
}
}
type Server struct {
tc.UnimplementedTesterServer
}
func (s *Server) Test(ctx context.Context, in *tc.Request) (*tc.Reply, error) {
return &tc.Reply{Message: ""}, nil
}
func StartServer(protocol string, port string) error {
lis, err := net.Listen(protocol, port)
if err != nil {
fmt.Printf("failed to listen: %v", err)
}
s := grpc.NewServer()
tc.RegisterTesterServer(s, &Server{})
error := s.Serve(lis)
if error != nil {
fmt.Printf("failed to serve: %v", error)
return error
}
return nil
}
Finally, I try to compile my proto files :
$ protoc --proto_path=.:$GOPATH/src --go_out=plugins=grpc:. proto/*/*.proto
And I systematically have the following error :
proto/test/test.proto:5:1: Import "github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis/google/api/annotations.proto" was not found or had errors.
When I see files get by go get ..., they are placed under $GOPATH/pkg/mod/
For example the googleapis' annotations.proto file is under : $GOPATH/pkg/mod/github.com/grpc-ecosystem/grpc-gateway#v1.12.1/third_party/googleapis/google/api/annotations.proto
Maybe is it the cause?
Mixing up your protobuf commands and your go commands is making this more complicated than it needs to be. Just focus on the protobuf to handle the error.
You are importing "google/api/annotations.proto"
Your proto_path is --proto_path=.:$GOPATH/src
So that means that when you execute protoc you should have the file located at ./google/api/annotations.proto or $GOPATH/src/google/api/annotations.proto
I faced the same problem and I was trying to automate a solution that would work on any Linux with as little dependencies as possible.
The official docs for grpc_gateway states:
You will need to provide the required third party protobuf files to the protoc compiler. They are included in this repo under the third_party/googleapis folder, and we recommend copying them into your protoc generation file structure. If you've structured your proto files according to something like the Buf style guide, you could copy the files into a top-level ./google folder.
In other words: download it somehow and make it work.
Also, since this quote is also a quote in the original source, it is not very visible which made me skip it the first 2 times I read it looking for a solution, which is bad.
So, as I argued on the comments of #SeanF answer, using go get is not a maintainable option since it saves the project in a folder whose name contains the latest version, which would cause headaches to maintain when the version changes.
So the best option is actually to clone the grpc-gateway project:
git clone https://github.com/grpc-ecosystem/grpc-gateway
protoc -I grpc-gateway/ \
-I grpc-gateway/third_party/googleapis \
--go_out=plugins=grpc:. proto/*/*.proto
I also wrote a gist with my solution which depends only on docker and bash and, thus, should be stable:
https://gist.github.com/VinGarcia/43dfa71b412c16b9365c224d3760af5e
There is a problem with it, where I am using go.mod but discarding it after every execution, which is not good. But it works well enough for now and it might be helpful to some people.
Regards
Related
I am attempting to create named loggers automatically for HTTP handlers that I'm writing, where I am passed a function (pointer).
I'm using the code mentioned in this question to get the name of a function:
package utils
import (
"reflect"
"runtime"
)
func GetFunctionName(fn interface{}) string {
value := reflect.ValueOf(fn)
ptr := value.Pointer()
ffp := runtime.FuncForPC(ptr)
return ffp.Name()
}
I'm using this in my main function to try it out like so:
package main
import (
"github.com/naftulikay/golang-webapp/experiments/functionname/long"
"github.com/naftulikay/golang-webapp/experiments/functionname/long/nested/path"
"github.com/naftulikay/golang-webapp/experiments/functionname/utils"
"log"
)
type Empty struct{}
func main() {
a := long.HandlerA
b := path.HandlerB
c := path.HandlerC
log.Printf("long.HandlerA: %s", utils.GetFunctionName(a))
log.Printf("long.nested.path.HandlerB: %s", utils.GetFunctionName(b))
log.Printf("long.nested.path.HandlerC: %s", utils.GetFunctionName(c))
}
I see output like this:
github.com/naftulikay/golang-webapp/experiments/functionname/long.HandlerA
This is okay but I'd like an output such as long.HandlerA, long.nested.path.HandlerB, etc.
If I could get the Go module name (github.com/naftulikay/golang-webapp/experiments/functionname), I can then use strings.Replace to remove the module name to arrive at long/nested/path.HandlerB, then strings.Replace to replace / with . to finally get to my desired value, which is long.nested.path.HandlerB.
The first question is: can I do better than runtime.FuncForPC(reflect.ValueOf(fn).Pointer()) for getting the qualified path to a function?
If the answer is no, is there a way to get the current Go module name using runtime or reflect so that I can transform the output of runtime.FuncForPC into what I need?
Once again, I'm getting values like:
github.com/naftulikay/golang-webapp/experiments/functionname/long.HandlerA
github.com/naftulikay/golang-webapp/experiments/functionname/long/nested/path.HandlerB
github.com/naftulikay/golang-webapp/experiments/functionname/long/nested/path.HandlerC
And I'd like to get values like:
long.HandlerA
long.nested.path.HandlerB
long.nested.path.HandlerC
EDIT: It appears that Go does not have a runtime representation of modules, and that's okay, if I can do it at compile time that would be fine too. I've seen the codegen documentation and I'm having a hard time figuring out how to write my own custom codegen that can be used from go generate.
The module info is included in the executable binary, and can be acquired using the debug.ReadBuildInfo() function (the only requirement is that the executable must be built using module support, but this is the default in the current version, and likely the only in future versions).
BuildInfo.Path is the current module's path.
Let's say you have the following go.mod file:
module example.com/foo
Example reading the build info:
bi, ok := debug.ReadBuildInfo()
if !ok {
log.Printf("Failed to read build info")
return
}
fmt.Println(bi.Main.Path)
// or
fmt.Println(bi.Path)
This will output (try it on the Go Playground):
example.com/foo
example.com/foo
See related: Golang - How to display modules version from inside of code
If your goal is to just have the name of the module available in your program, and if you are okay with setting this value at link time, then you may use the -ldflags build option.
You can get the name of the module with go list -m from within the module directory.
You can place everything in a Makefile or in a shell script:
MOD_NAME=$(go list -m)
go build -ldflags="-X 'main.MODNAME=$MOD_NAME'" -o main ./...
With main.go looking like:
package main
import "fmt"
var MODNAME string
func main() {
fmt.Println(MODNAME) // example.com
}
With the mentioned "golang.org/x/mod/modfile" package, an example might look like:
package main
import (
"fmt"
"golang.org/x/mod/modfile"
_ "embed"
)
//go:embed go.mod
var gomod []byte
func main() {
f, err := modfile.Parse("go.mod", gomod, nil)
if err != nil {
panic(err)
}
fmt.Println(f.Module.Mod.Path) // example.com
}
However embedding the entire go.mod file in your use case seems overkill. Of course you could also open the file at runtime, but that means you have to deploy go.mod along with your executable. Setting the module name with -ldflags is more straightforward IMO.
I am not able to call a gRPC function due to type mismatch
my proto file :
message Analytics {
fields ...
}
message AnalyticsSet {
repeated Analytics analytics = 1;
}
service StatService {
rpc MyMethod(AnalyticsSet) returns (<something>) {}
}
Now, I need to call "MyMethod"
My current code :
type Analytics struct {
same fields as in proto : Analytics
}
analytics := make([]Analytics, 4)
// .. some modifications in analytics ...
_, err := c.MyMethod(context.Background(), analytics)
if err != nil {
log.Fatalf("error: %s", err)
}
in Proto file "AnalyticsSet" is the array of "Analytics"
and in Go code "analytics" is an array of type "Analytics"
but this is not enough to call "MyMethod", and I am facing type mismatch..
How should I modify the go code ?
You must use the Analytics struct generated from the proto file -- you cannot use your own type.
You can generate the required Go code using protoc with your .proto file. Here is an example with gRPC generation options set as well:
.
$ protoc --go_out=. --go-grpc_out=. --go_opt=paths=source_relative --go-grpc_opt=paths=source_relative analytics.proto
Your proto file should have the go_package option set to describe the Go import path for that your generated proto code belongs to. You will also need to install the go / go-grpc generator utilities required by protoc:
$ go install google.golang.org/protobuf/cmd/protoc-gen-go#latest
$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc#latest
More details can be found in:
https://developers.google.com/protocol-buffers/docs/gotutorial
https://developers.google.com/protocol-buffers/docs/reference/go-generated
https://grpc.io/docs/languages/go/quickstart/
Actually I want to use c4 to generate the c4 id for the video files, So I found the below repo which is developed to do this thing, So I clone this repo
https://github.com/Avalanche-io/c4/tree/v0.7.0
Now as suggested in this answer from stack overflow: Not able to install cmd version of c4 from github
I execute the following command in my ubuntu terminal
go get github.com/Avalanche-io
go get github.com/Avalanche-io/c4/id
go get github.com/Avalanche-io/c4/cmd/c4
then as they have shown in the example of how to use this repo
package main
import (
"fmt"
"io"
"os"
c4 "github.com/avalanche-io/c4/id"
)
func main() {
file := "main.go"
f, err := os.Open(file)
if err != nil {
panic(err)
}
defer f.Close()
// create a ID encoder.
e := c4.NewEncoder()
// the encoder is an io.Writer
_, err = io.Copy(e, f)
if err != nil {
panic(err)
}
// ID will return a *c4.ID.
// Be sure to be done writing bytes before calling ID()
id := e.ID()
// use the *c4.ID String method to get the c4id string
fmt.Printf("C4id of \"%s\": %s\n", file, id)
return
}
I just copy this same example and created a main.go file and when I run this command which they have defined here in their README.md https://github.com/Avalanche-io/c4/blob/v0.7.0/id/README.md
The command is go run main.go ```` Instead of getting the c4 id``` of the file as they have shown in their example. I am getting the following error
main.go:8:3: cannot find package "github.com/avalanche-io/c4/id" in any of:
/usr/lib/go-1.13/src/github.com/avalanche-io/c4/id (from $GOROOT)
/home/vinay/go/src/github.com/avalanche-io/c4/id (from $GOPATH)
I don't know about go language so it is becoming very difficult for me to solve the problem here, Is there any go developer which will help me out.
main.go file is not able to find the package github.com/avalanche-io/c4/id inside /home/vinay/go/src/github.com/avalanche-io/c4/id , As I can see you have run the following go get commands
go get github.com/Avalanche-io
go get github.com/Avalanche-io/c4/id
go get github.com/Avalanche-io/c4/cmd/c4
but none of them has name github.com/avalanche-io/c4/id
so according to me, You need to execute the following command
go get github.com/avalanche-io/c4/id
Now just run your main.go
go run main.go
I have a main.go file that uses the proto files in pkg/models to Marshal and Unmarshal a proto struct like this:
// Convert to string
protoStr := proto.MarshalTextString(proto)
// Unmarshal string back to proto struct
var proto2 models.Stuff
err := proto.UnmarshalText(protoStr, &proto2)
The setup is here: https://github.com/chuyval/qqs/tree/master/q2
The project contains a vendor directory that only has the github.com/golang/protobuf repo checked out. (run glide install to create vendor if it doesnt exist)
The main.go program works fine when running go run main.go from inside the project.
When I move the main.go file one level up to the parent directory, and run the same command go run main.go at the parent level, it reports the following error:
line 2: unknown field name "value_list" in models.Stuff
When I delete the vendor directory in the project directory, and run go run main.go at the parent level, I get no error.
Why would having a vendor directory in the project repository make it error out?
Another thing to note, if I run the same main.go application inside of the dependent repo, it works every time (with or without the vendor repository).
Sample code:
package main
import (
"github.com/chuyval/qqs/q2/pkg/models"
"github.com/golang/protobuf/proto"
"log"
)
func main () {
stuff := createProtoStuff()
log.Printf("Stuff: %+v", stuff)
// Convert to string
stuffStr := proto.MarshalTextString(stuff)
// Unmarshal string back to proto struct
var stuff2 models.Stuff
err := proto.UnmarshalText(stuffStr, &stuff2)
if err != nil {
log.Printf("It didnt work. Error: %s", err.Error())
} else {
log.Printf("It worked. Proto: %+v", stuff2)
}
}
func createProtoStuff() *models.Stuff {
someValueList := []*models.SomeValue{&models.SomeValue{Id: "Some Value ID"}}
valueList := &models.SomeValueList{SomeValue: someValueList}
stuffValueList := &models.Stuff_ValueList{
ValueList: valueList,
}
stuff := &models.Stuff{
Id: "Stuff List Id",
Stuff: stuffValueList,
}
return stuff
}
Software Versions
glide version 0.13.1
go version go1.10.3 darwin/amd64
protoc version libprotoc 3.6.0
I am working on testing an application of mine, for which I need to create temporary files with specific extensions. My goal is to create files in a temp directory that look similar to this example123.ac.json.
In order to do this I am using ioutil.TempDir and ioutil.TempFile.
Here is a small contrived example of what I am doing.
main.go:
package main
func main() {
}
main_test.go:
package main
import (
"fmt"
"io/ioutil"
"os"
"testing"
)
func TestMain(t *testing.T) {
dir, err := ioutil.TempDir("", "testing")
if err != nil {
t.Fatalf("unable to create temp directory for testing")
}
defer os.RemoveAll(dir)
file, err := ioutil.TempFile(dir, "*.ac.json") // Create a temporary file with '.ac.json' extension
if err != nil {
t.Fatalf("unable to create temporary file for testing")
}
fmt.Printf("created the following file: %v\n", file.Name())
}
When I run the tests locally on my Mac with go test the following is outputted from the fmt.Printf is
$ go test
created the following file: /var/folders/tj/1_mxwn350_d2c5r9b_2zgy7m0000gn/T/testing566832606/900756901.ac.json
PASS
ok github.com/JonathonGore/travisci-bug 0.004s
So it works as expected but when I run it in TravisCI the following is outputted from the Printf statement:
created the following file: /tmp/testing768620677/*.ac.json193187872
For some reason it is using the literal asterisk inside TravisCI but not when running on my own computer.
Here is a link to the TravisCI logs if interested.
For completeness here is my .travis.yml:
language: go
go:
- "1.10"
Anyone have any idea what is going on here? Or am I missing something obvious?
The feature of replacing the first asterisk with the random value was added in Go 1.11. It looks like you are using go 1.10 for your Travis CI runs so the asterisk won't be replaced.