Missing symbols when importing `github.com/influxdb/influxdb/client/v2` package - go

Setting up a web socket on google cloud in Golang, and import code that works fine on my local machine does not work on the cloud.
I have:
import "github.com/influxdb/influxdb/client/v2"
and have run
go get "github.com/influxdb/influxdb/client/v2"
Upon running go run server.go I get:
# command-line-arguments
./pi_server.go:47: undefined: client.NewClient
./pi_server.go:47: undefined: client.Config
Full code below, excluding const declarations and html:
package main
import (
"flag"
"html/template"
"log"
"net/http"
"github.com/gorilla/websocket"
"fmt"
"net/url"
"github.com/influxdb/influxdb/client/v2"
"time"
)
var addr = flag.String("addr", "localhost:8080", "http service address")
var upgrader = websocket.Upgrader{} // use default options
func echo(w http.ResponseWriter, r *http.Request) {
//Influx init
u,err := url.Parse("http://localhost:8086")
checkError(err)
influx_c := client.NewClient(client.Config{
URL: u,
Username: username,
Password: password,
})
bp,err := client.NewBatchPoints(client.BatchPointsConfig{
Database: MyDB,
Precision: "s",
})
tags := map[string]string{"my_sensor_id": my_sensor_id}
//end influx init
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Print("upgrade:", err)
return
}
defer c.Close()
for {
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
log.Printf("recv: %s", message)
/*
write to influx here
*/
fields := map[string]interface{}{
"random_int": message,
"other_stuff": 69696,
}
pt,err := client.NewPoint("test_collection", tags, fields, time.Now())
checkError(err)
bp.AddPoint(pt)
influx_c.Write(bp)
err = c.WriteMessage(mt, message)
if err != nil {
log.Println("write:", err)
break
}
}
}
func home(w http.ResponseWriter, r *http.Request) {
homeTemplate.Execute(w, "ws://"+r.Host+"/echo", )
}
func main() {
flag.Parse()
log.SetFlags(0)
http.HandleFunc("/echo", echo)
http.HandleFunc("/", home)
log.Fatal(http.ListenAndServe(*addr, nil))
}

You local machine has a version of github.com/influxdb/influxdb/client/v2 before this commit. Your cloud server is fetching a more recent version of the package.
To fix the issue, run
go get -u github.com/influxdb/influxdb/client/v2
on your local machine to get the latest version of the package. Update the application code to use the new function and type names:
influx_c := client.NewHTTPClient(client.HTTPConfig{
URL: u,
Username: username,
Password: password,
})

Nailed it, thanks! Also note from following code:
influx_c,err := client.NewHTTPClient(client.HTTPConfig{
Addr: "http://localhost:8086",
Username: username,
Password: password,
})
They changed URL field to Addr, with is a string literal instead of a net/url object

Related

go build doesn't recognise methods

I try to setup a small Golang Microservice for users with Gin and Mongodb.
package main
import (
"context"
"fmt"
"github.com/wzslr321/artiver/entity"
"github.com/wzslr321/artiver/settings"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"log"
"os"
"os/signal"
"syscall"
"time"
)
type application struct {
users *entity.UserCollection
}
var app *application
func init() {
initMongo()
}
func initMongo() {
oc := options.Client().ApplyURI(settings.MongodbSettings.Uri)
client, err := mongo.NewClient(oc)
if err != nil {
log.Fatalf("Error occured while initializing a new mongo client: %v", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
err = client.Connect(ctx)
if err != nil {
log.Fatalf("Errorr occurred while connecting to a client: %v", err)
}
defer func() {
if err = client.Disconnect(ctx); err != nil {
panic(err)
}
}()
log.Println("Successfully connected to the database!")
app = &application{
users: &entity.UserCollection{
C: client.Database("artiver").Collection("users"),
},
}
}
func main() {
router := app.InitRouter()
It doesn't show any errors in my IDE ( GoLand ), but when I try to build it I get an error:
# command-line-arguments
users/cmd/app/main.go:67:15: app.InitRouter undefined (type *application has no field or method InitRouter)
It it easily visible on the image above, that I do have access to such a method. It is defined in the same package.
package main
import (
"github.com/gin-gonic/gin"
cors "github.com/rs/cors/wrapper/gin"
"net/http"
)
func (app *application) InitRouter() *gin.Engine {
r := gin.New()
r.Use(gin.Recovery())
r.Use(cors.Default())
r.GET("/", func(ctx *gin.Context) {
ctx.String(http.StatusOK, "Hello World")
})
user := r.Group("/api/user")
{
user.POST("/add", app.CreateUser)
}
return r
}
I have no idea how am I supposed to fix it and what is done wrong. I'd appreciate any hint about what isn't done correctly.
Answer based on #mkopriva help in comments.
The issue was related to not running all needed .go files.
In my case, the solution was to build it this way in my Makefile:
go build -o $(path)users cmd/app/*
In similar cases, go run . most likely will do the job.

chi.URLParam not working when handler is defined outside main package

So I am new to go and I currently try to build a little REST-API using chi (and I love it). Yesterday I run into a problem, that I cannot quite understand.
In my little test-project I have a main.go file which contains the main function with router instantiation, adding middlewares and starting the server:
func main() {
router := chi.NewRouter()
// Middleware
router.Use(middleware.RequestID)
router.Use(middleware.RealIP)
router.Use(middleware.Logger)
router.Use(middleware.Recoverer)
// Routes
router.Post("/login", users.Login)
router.Post("/register", users.Register)
router.With(users.LoginRequired).Route("/users", func(r chi.Router) {
r.Get("/{user_id}", users.GetUser)
})
// Start Server
port := ":8080"
log.Printf("Server starting at port %v\n", port)
log.Fatal(http.ListenAndServe(port, router))
}
First the problem didn't exist because I defined all the handler functions within my main.go file and the GetUser-function worked as expected and returned a user from my "Database" (array with 3 users):
func GetUser(w http.ResponseWriter, r *http.Request) {
uID := chi.URLParam(r, "user_id") // Problem when not in main -> uID = ""
id, err := strconv.Atoi(uID)
if err != nil {
log.Printf("Error while parsing int: %v\n", err)
// TODO: return error 400
}
user := DataBase[id-1]
response, err := json.Marshal(user)
if err != nil {
log.Printf("Error while marshalling user: %v\n", err)
}
w.Write(response)
}
As soon as I moved this function out of the main.go file into another package called users the chi.URLParam function returns an empty string and cannot find the URLParam anymore. I read it has something to do with the context, but I cannot wrap my head around that I have to place functions inside the main-file if I want to use the chi functions.
Am I missing something?
UPDATE
As requested I removed everything except the GetUser function. My main.go file currently looks like this:
package main
import (
"encoding/json"
"log"
"net/http"
"strconv"
"github.com/MyUserName/MyProjectName/internals/users"
"github.com/go-chi/chi/v5"
)
func GetUser(w http.ResponseWriter, r *http.Request) {
id, err := strconv.Atoi(chi.URLParam(r, "user_id"))
if err != nil {
log.Printf("Error while parsing int: %v\n", err)
// TODO: return error 400
}
log.Printf("ID=%v, Current Database=%v\n", id, users.DataBase)
user := users.DataBase[id-1]
response, err := json.Marshal(user)
if err != nil {
log.Printf("Error while marshalling user: %v\n", err)
}
w.Write(response)
}
func main() {
router := chi.NewRouter()
// Routes
router.Get("/users/{user_id}", GetUser)
// Start Server
port := ":8080"
log.Printf("Server starting at port %v\n", port)
log.Fatal(http.ListenAndServe(port, router))
}
and my users package looks like this:
package users
import (
"encoding/json"
"log"
"net/http"
"strconv"
"github.com/MyUserName/MyProjectName/internals/models"
"github.com/go-chi/chi"
)
var (
DataBase = make([]models.User, 0)
)
func GetUser(w http.ResponseWriter, r *http.Request) {
id, err := strconv.Atoi(chi.URLParam(r, "user_id"))
if err != nil {
log.Printf("Error while parsing int: %v\n", err)
// TODO: return error 400
}
log.Printf("ID=%v, Current Database=%v\n", id, DataBase)
user := DataBase[id-1]
response, err := json.Marshal(user)
if err != nil {
log.Printf("Error while marshalling user: %v\n", err)
}
w.Write(response)
}
func init() {
initUser := []models.User{
{
ID: 1,
UserName: "john",
Password: "doe",
},
{
ID: 2,
UserName: "max",
Password: "mustermann",
},
{
ID: 3,
UserName: "jane",
Password: "doe",
},
}
for _, user := range initUser {
DataBase = append(DataBase, user)
}
log.Println("Initializing Database")
}
When I use the function from the users package it does not work and is still an empty string, if I use the function from the main.go file it works.
UPDATE
So apparently I am to stupid to import the same packages twice. In my main file I used "github.com/go-chi/chi/v5" and in my users package I used "github.com/go-chi/chi". Using the same resolved the issue, thanks a lot
Adding answer because the comments just saved me!
Check that all files in your go solution have the same version of chi in use. If you're using VSCode it may import a different version than you expect. In my code I had one file with
import(
"github.com/go-chi/chi"
)
and in the other
import(
"github.com/go-chi/chi/v5"
)
This meant that when I was calling into middleware function to extract URLParams the context was not finding a value.
TL;DR
Check that all files use same version of Chi!

How to use Context when getting a direction with GO?

I'm having the following code to get the direction from Google Cloud:
import (
"google.golang.org/appengine"
"google.golang.org/appengine/urlfetch"
"fmt"
"io/ioutil"
"net/http"
)
const directionAPIKey = "APIKey"
const directionURL = "https://maps.googleapis.com/maps/api/directions/json?origin=%s&destination=%s&mode=%s&key=%s"
func main() {
http.HandleFunc("/", handler)
}
func handler(w http.ResponseWriter, r *http.Request) {
ctx := appengine.NewContext(r)
direction, err := fetchDirection(ctx, r.FormValue("origin"), r.FormValue("destination"), r.FormValue("mode"))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json; charset=utf-8")
w.Write(direction)
}
func fetchDirection(ctx appengine.Context, origin string, destination string, mode string) ([]byte, error) {
client := urlfetch.Client(ctx)
resp, err := client.Get(fmt.Sprintf(directionURL, origin, destination, mode, directionAPIKey))
if err != nil {
return nil, err
}
defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
}
But I get an error:
undefined: appengine.Context
When trying to deploy the app. What I have tried is to change:
ctx := appengine.NewContext(r)
into
ctx := r.Context()
And
func fetchDirection(ctx appengine.Context, origin string...)
into
func fetchDirection(ctx Context, origin string...)
But I get:
undefined: Context
I'm completely lost. I'm new to Go and GCP, so please be patient with me. Thanks
If you check the godoc for urlfetch you'll see it links to where the Context type is defined. That in turn tells you that "As of Go 1.7 this package is available in the standard library under the name context. https://golang.org/pkg/context."
So add an import:
import "context"
and refer to it as:
func fetchDirection(ctx context.Context, origin string...)

Infinite loop when db.Ping() is called

I am attempting to create a basic connection to a database. The problem happens when I try to test the connection with db.Ping(); everything works until I get to this line. The Ping sends the program into an infinite loop (the function call never returns), and I'm not sure how to go about fixing this.
package main
import (
"database/sql"
"fmt"
"html/template"
"net/http"
_ "github.com/lib/pq"
}
type Page struct {
Name string
DBStatus bool
}
const (
host = "localhost"
port = 8080
user = "username"
password = "password"
dbname = "GoTest"
)
func main() {
templates := template.Must(template.ParseFiles("templates/index.html"))
psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname)
db, err := sql.Open("postgres", psqlInfo)
if err != nil {
panic(err)
}
defer db.Close()
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
p := Page{Name: "Gopher"}
if name := r.FormValue("name"); name != "" {
p.Name = name
}
p.DBStatus = db.Ping() == nil //this point is reached but never returned
if err := templates.ExecuteTemplate(w, "index.html", p); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
fmt.Println(http.ListenAndServe(":8080", nil))
}
It seems I can connect to the database fine, as the sql.Open call doesn't return an error, and if I called the Ping outside of the http server handle function, it also returns just fine.
Any help would be greatly appreciated!
Your database configurations are wrong. It's pointing to the Golang server port 8080. It should point to the pgsql port(default 5432)

TCP client not working correcty golang

I have rest-ful interface written in golang. I need to do the authentication on each endpoint. once authentication is done I have to forward it back to a tcp server.
I created a tcp client and any value that is coming from the channel is to be send to tcp server. the channel is populated from the http request body.
The issue is that once I issue curl command the client is stuck with no response; so obviously I am doing something wrong not sure what is wrong. does anyone have any insights on what my problem might be?
package main
import (
"bufio"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
"net/http/httputil"
"net/url"
"os"
"strconv"
auth "github.com/abbot/go-http-auth"
)
type Configuration struct {
Server string
Port int64
UserName string
Pwd string
Realm string
ProxyPort int64
Edeserver string
}
var (
Config *Configuration
logp = flag.Bool("log", false, "enable logging")
)
func ReadConfiguration() {
file, _ := os.Open("Config.json")
decoder := json.NewDecoder(file)
Config = &Configuration{}
err := decoder.Decode(&Config)
if err != nil {
fmt.Println("error:", err)
}
}
func Secret(user, realm string) string {
if user == Config.UserName {
// password is "hello"
return Config.Pwd
}
return ""
}
func reverseProxyTows(w http.ResponseWriter, authenticatedRequest *auth.AuthenticatedRequest) {
req := &authenticatedRequest.Request
if *logp {
log.Println(" Authenticated Username ", authenticatedRequest.Username)
log.Println(" Authenticated URL ", req.URL.RequestURI())
}
destinationURL := fmt.Sprintf("http://%s:%d", Config.Server, Config.Port)
u, err := url.Parse(destinationURL)
if err != nil {
log.Fatal(err)
}
if *logp {
log.Println("reverse_proxy", u)
}
reverseProxy := httputil.NewSingleHostReverseProxy(u)
reverseProxy.ServeHTTP(w, req)
}
func openConnectionTotcp(edechannel chan string) {
conn, _ := net.Dial("tcp", Config.Edeserver)
text := <-edechannel
fmt.Fprintf(conn, text+"\n")
message, _ := bufio.NewReader(conn).ReadString('\n')
fmt.Print("Message from server: " + message)
}
func main() {
ReadConfiguration()
flag.Parse()
c := make(chan string)
go openConnectionTotcp(c)
fmt.Printf("Started proxy to destination server %v:%d and is listening on %d ", Config.Server, Config.Port, Config.ProxyPort)
authenticator := auth.NewBasicAuthenticator(Config.Realm, Secret)
http.HandleFunc("/", authenticator.Wrap(reverseProxyTows))
http.HandleFunc("/tyrion/1", authenticator.Wrap(func(w http.ResponseWriter, authenticatedRequest *auth.AuthenticatedRequest) {
req := &authenticatedRequest.Request
bodyBytes, err2 := ioutil.ReadAll(req.Body)
if err2 != nil {
log.Fatal(err2)
}
bodyString := string(bodyBytes)
c <- bodyString
fmt.Fprintf(w, "success")
}))
http.ListenAndServe(":"+strconv.FormatInt(Config.ProxyPort, 10), nil)
}
Your code execution blocks at c <- bodyString because nothing appears to be reading from that unbuffered channel. That line will pause execution until another routine reads from the channel.

Resources