I'd like to connect from Go to the running instance of the Memgraph database. I'm using Docker and I've installed the Memgraph Platform. What exactly do I need to do?
The procedure for connecting fro Go to Memgraph is rather simple. For this you need to use Bolt protocol. Here are the needed steps:
First, create a new directory for your app, /MyApp, and position yourself in it. Next, create a program.go file with the following code:
package main
import (
"fmt"
"github.com/neo4j/neo4j-go-driver/v4/neo4j"
)
func main() {
dbUri := "bolt://localhost:7687"
driver, err := neo4j.NewDriver(dbUri, neo4j.BasicAuth("username", "password", ""))
if err != nil {
panic(err)
}
// Handle driver lifetime based on your application lifetime requirements driver's lifetime is usually
// bound by the application lifetime, which usually implies one driver instance per application
defer driver.Close()
item, err := insertItem(driver)
if err != nil {
panic(err)
}
fmt.Printf("%v\n", item.Message)
}
func insertItem(driver neo4j.Driver) (*Item, error) {
// Sessions are short-lived, cheap to create and NOT thread safe. Typically create one or more sessions
// per request in your web application. Make sure to call Close on the session when done.
// For multi-database support, set sessionConfig.DatabaseName to requested database
// Session config will default to write mode, if only reads are to be used configure session for
// read mode.
session := driver.NewSession(neo4j.SessionConfig{})
defer session.Close()
result, err := session.WriteTransaction(createItemFn)
if err != nil {
return nil, err
}
return result.(*Item), nil
}
func createItemFn(tx neo4j.Transaction) (interface{}, error) {
records, err := tx.Run(
"CREATE (a:Greeting) SET a.message = $message RETURN 'Node ' + id(a) + ': ' + a.message",
map[string]interface{}{"message": "Hello, World!"})
// In face of driver native errors, make sure to return them directly.
// Depending on the error, the driver may try to execute the function again.
if err != nil {
return nil, err
}
record, err := records.Single()
if err != nil {
return nil, err
}
// You can also retrieve values by name, with e.g. `id, found := record.Get("n.id")`
return &Item{
Message: record.Values[0].(string),
}, nil
}
type Item struct {
Message string
}
Now, create a go.mod file using the go mod init example.com/hello command.
I've mentioned the Bolt driver earlier. You need to add it with go get github.com/neo4j/neo4j-go-driver/v4#v4.3.1. You can run your program with go run .\program.go.
The complete documentation is located at Memgraph site.
Related
I have this module that use Google Cloud API to retrieve a list of all running Virtual Machine instances for a particular project. I'm new to Go, and followed the intro tutorial to help me out. I'm still trying to debug my code but no luck.
The problem is I'm able to communicate to Google Cloud API and pass authentication but that is all I can get through
compute.go module:
compute.go is able to communicate to Google Cloud servers and pass authentication (I'm not getting an auth error)
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package compute
// [START compute_instances_list_all]
import (
"context"
"fmt"
"io"
compute "cloud.google.com/go/compute/apiv1"
"google.golang.org/api/iterator"
computepb "google.golang.org/genproto/googleapis/cloud/compute/v1"
"google.golang.org/protobuf/proto"
)
// listAllInstances prints all instances present in a project, grouped by their zone.
func ListAllInstances(w io.Writer, projectID string) error {
// projectID := "your_project_id"
ctx := context.Background()
instancesClient, err := compute.NewInstancesRESTClient(ctx)
// instancesClient, err := compute.NewInstancesRESTClient(ctx, option.WithCredentialsFile(`C:\path\to\jsonkey.json`))
if err != nil {
return fmt.Errorf("NewInstancesRESTClient: %v", err)
}
defer instancesClient.Close()
// Use the `MaxResults` parameter to limit the number of results that the API returns per response page.
req := &computepb.AggregatedListInstancesRequest{
Project: projectID,
MaxResults: proto.Uint32(6),
}
it := instancesClient.AggregatedList(ctx, req)
fmt.Fprintf(w, "Instances found:\n")
// Despite using the `MaxResults` parameter, you don't need to handle the pagination
// yourself. The returned iterator object handles pagination
// automatically, returning separated pages as you iterate over the results.
for {
pair, err := it.Next()
if err == iterator.Done {
break
}
if err != nil {
return err
}
instances := pair.Value.Instances
if len(instances) > 0 {
fmt.Fprintf(w, "%s\n", pair.Key)
for _, instance := range instances {
fmt.Fprintf(w, "- %s %s\n", instance.GetName(), instance.GetMachineType())
}
}
}
return nil
}
// [END compute_instances_list_all]
However the problem is when I run my main function that calls ListAllInstances, it returns a <nil>. Not allowing me to know what is wrong.
caller api.go module where I run go run .:
package main
import (
"fmt"
"example.com/compute"
"bytes"
)
func main() {
buf := new(bytes.Buffer)
// Get a message and print it.
respone := compute.ListAllInstances(buf, "project-unique-id")
fmt.Println(respone)
}
How else can I further debug this to figure out what is wrong with my code?
You're not printing buf. Your function returns an object of type error, which is nil (no error!), the actual output is written to buf.
Either print it out:
func main() {
buf := new(bytes.Buffer)
// Get a message and print it.
err := compute.ListAllInstances(buf, "project-unique-id")
if err != nil {
panic(err)
}
fmt.Println(buf.String()) // <======= Print buf contents!
}
Or just use os.Stdout:
func main() {
err := compute.ListAllInstances(os.Stdout, "project-unique-id")
if err != nil {
panic(err)
}
}
To answer your question about debugging, try using VSCode with the Go extension, in there you can run a debugger, set breakpoints and step through the code line-by-line, watching how variables change.
See also Debug Go programs in VS Code.
I'm new to smart contract developing, and trying to make it work for handling assets. My assets are called GOcerts.
I have used the token UTXO smart contract as a basis to start learning, and added changes and functions depending on my needs.
I have added an aditional function called ClaimGO(), which is supposed to delete the asset and create and store two new assets in the ledger. But function DeleteState and putState do not seem to be storing anything on the ledger, because when I query the ledger after calling the function, is like if nothing had changed the ledger state.
The implementation of the ClaimGO function is as follows:
//ClaimGO claims an amount X of GOcert Y. This function is implemented following the UTXO model
func (s *SmartContract) ClaimGO(ctx contractapi.TransactionContextInterface, goCertInputKey string, amount int) ([]GOCERT, error) {
//1. Get ID of submitting client identity
clientID, err := ctx.GetClientIdentity().GetID()
if err != nil {
return nil, fmt.Errorf("failed to get client id: %v", err)
}
//2. Validate GOcert input
goCertInputCompositeKey, err := ctx.GetStub().CreateCompositeKey("goCert", []string{clientID, goCertInputKey})
if err != nil {
return nil, fmt.Errorf("failed to create composite key: %v", err)
}
goCertInput := GOCERT{}
//2.1 Validate that client has a GOcert matching the input key
goCertAsBytes, err := ctx.GetStub().GetState(goCertInputCompositeKey)
if err != nil {
return nil, fmt.Errorf("failed to read goCertInputCompositeKey %s from world state: %v", goCertInputCompositeKey, err)
}
errr := json.Unmarshal(goCertAsBytes, &goCertInput)
if errr != nil {
return nil, fmt.Errorf("goCertInput %s not found for client %s: %v\n, gocertInput: %#v\n gocerAsbytes: %v", goCertInputKey, clientID, errr, goCertInput, goCertAsBytes)
}
txID := ctx.GetStub().GetTxID()
pbKey := goCertInput.ProdBatchKey
expDate := goCertInput.ExpirationDate
//erase previous GOcert
err = ctx.GetStub().DelState(goCertInputCompositeKey)
if err != nil {
return nil, err
}
log.Printf("goCertInput deleted: %+v", goCertInput)
var goCertOutputs []GOCERT
//goCertOutput1 is the GO with the cancelled amount
goCertOutput1 := GOCERT{}
goCertOutput1.Amount = amount
goCertOutput1.ExpirationDate = expDate
goCertOutput1.Owner = clientID
goCertOutput1.ProdBatchKey = pbKey
goCertOutput1.State = "Cancelled"
goCertOutput1.Key = fmt.Sprintf("%s.%d", txID, 0)
goCertOutputs = append(goCertOutputs, goCertOutput1)
goCertAsBytes, _ := json.Marshal(goCertOutput1)
goCertOutputCompositeKey, err := ctx.GetStub().CreateCompositeKey("goCert", []string{goCertOutput1.Owner, goCertOutput1.Key})
err = ctx.GetStub().PutState(goCertOutputCompositeKey, goCertAsBytes)
if err != nil {
return nil, err
}
log.Printf("goCertOutput created: %+v", goCertOutput1)
//goCertOutput 2 is the GO with the remaining amount that has not been claimed yet
goCertOutput2 := GOCERT{}
goCertOutput2.Amount = goCertInput.Amount - amount
goCertOutput2.ExpirationDate = expDate
goCertOutput2.Owner = clientID
goCertOutput2.ProdBatchKey = pbKey
goCertOutput2.State = "Issued"
goCertOutput2.Key = fmt.Sprintf("%s.%d", txID, 1)
goCertOutputs = append(goCertOutputs, goCertOutput2)
goCertAsBytes2, _ := json.Marshal(goCertOutput2)
goCertOutputCompositeKey2, err := ctx.GetStub().CreateCompositeKey("goCert", []string{goCertOutput2.Owner, goCertOutput2.Key})
err = ctx.GetStub().PutState(goCertOutputCompositeKey2, goCertAsBytes2)
if err != nil {
return nil, err
}
log.Printf("goCertOutput created: %+v", goCertOutput2)
return goCertOutputs, nil
}
I'm trying the smart contract with the Hyperledger Fabric test-network. Using the logspout tool, I can see that the two log messages are displayed, so I know that the code is being executed correctly. The issue is that, eve though it executes with no errors, the functions DeleteState and PutState are not actually changing anything on the ledger.
Any help on what could be the issue will be highly appreciated.
Thank you very much.
The ledger doesn't actually get updated until after a transaction is endorsed, submitted to the orderer, committed in a block, and distributed to peers so they can update their local ledger state. It is still possible for the transaction to fail to commit successfully after sending to the orderer if some endorsement requirements have not been met.
If you are using the peer chaincode query command to do your invocation, the transaction is not sent to the orderer so no ledger update occurs. If you are using the peer chaincode invoke command then the endorsed transaction will be sent to the orderer and update the ledger.
However, query commands following an invoke command will not see the ledger update caused by the invoke until the peer they execute on has received the committed block from the orderer and updated its local ledger state. To have the peer chaincode invoke command wait for transactions to be committed in peer ledgers before exiting, use the --waitForEvent command-line flag.
Run peer chaincode invoke --help for details of the available command-line flags.
Lets say I have the following function I'd like to write a test for:
func GetBootTime() (time.Time, error) {
currentTime := time.Now()
var info unix.Sysinfo_t
if err := unix.Sysinfo(&info); err != nil {
return time.Time{}, fmt.Errorf("error getting system uptime: %s", err)
}
return currentTime.Add(-time.Duration(info.Uptime) * time.Second).Truncate(time.Second), nil
}
How can I get unix.Sysinfo to return an error?
You cannot.
But you can "abstract it away" in one way or another.
For instance, you can have
var sysInfo := unix.SysInfo
func GetBootTime() (time.Time, error) {
currentTime := time.Now()
var info unix.Sysinfo_t
if err := sysInfo(&info); err != nil {
return time.Time{}, fmt.Errorf("error getting system uptime: %s", err)
}
return currentTime.Add(-time.Duration(info.Uptime) * time.Second).Truncate(time.Second), nil
}
…and then in your testing code have something like
sysInfo = func (_ *unix.Sysinfo_t) error {
return syscall.Errno(42)
}
before the actual test runs.
Note that this patching must be synchronized with other goroutines which may run testing code which ultimately calls into this function.
Note that there exist more hard-core appoaches which abstract away whole subsystems — such as github.com/spf13/afero which abstracts away all the filesystem operations available via the os and path/filepath packages and github.com/LopatkinEvgeniy/clock which abstracts away most functions from the time package.
With such an approach, you write all your code in a way so that it uses a single object implementing a particular interface, to carry out certain class of tasks, and at runtime, this object is either a "real" one or a "fake" one — when you do testing.
I'm setting up a tcp server in a pet project I'm writing in go. I want to be able to maintain a slice of all connected clients, and then modify it whenever a new client connects or disconnects from my server.
My main mental obstacle right now is whether I should be declaring a package level slice, or just passing a slice into my handler.
My first thought was to declare my ClientList slice (I'm aware that a slice might not be my best option here, but I've decided to leave it as is for now) as a package level variable. While I think this would work, I've seen a number of posts discouraging the use of them.
My other thought was to declare ClientList as a slice in my main function, and then I pass ClientList to my HandleClient function, so whenever a client connects/disconnects I can call AddClient or RemoveClient and pass this slice in and add/remove the appropriate client.
This implementation is seen below. There are definitely other issues with the code, but I'm stuck trying to wrap my head around something that seems like it should be very simple.
type Client struct {
Name string
Conn net.Conn
}
type ClientList []*Client
// Identify is used to set the name of the client
func (cl *Client) Identify() error {
// code here to set the client's name in the based on input from client
}
// This is not a threadsafe way to do this - need to use mutex/channels
func (cList *ClientList) AddClient(cl *Client) {
*cList = append(*cList, cl)
}
func (cl *Client) HandleClient(cList *ClientList) {
defer cl.Conn.Close()
cList.AddClient(cl)
err := cl.Identify()
if err != nil {
log.Println(err)
return
}
for {
err := cl.Conn.SetDeadline(time.Now().Add(20 * time.Second))
if err != nil {
log.Println(err)
return
}
cl.Conn.Write([]byte("What command would you like to perform?\n"))
netData, err := bufio.NewReader(cl.Conn).ReadString('\n')
if err != nil {
log.Println(err)
return
}
cmd := strings.TrimSpace(string(netData))
if cmd == "Ping" {
cl.Ping() //sends a pong msg back to client
} else {
cl.Conn.Write([]byte("Unsupported command at this time\n"))
}
}
}
func main() {
arguments := os.Args
PORT := ":" + arguments[1]
l, err := net.Listen("tcp4", PORT)
if err != nil {
fmt.Println(err)
return
}
defer l.Close()
fmt.Println("Listening...")
// Create a new slice to store pointers to clients
var cList ClientList
for {
c, err := l.Accept()
if err != nil {
log.Println(err)
return
}
// Create client cl1
cl1 := Client{Conn: c}
// Go and handle the client
go cl1.HandleClient(&cList)
}
}
From my initial testing, this appears to work. I am able to print out my client list and I can see that new clients are being added, and their name is being added after Identify() is called as well.
When I run it with the -race flag, I do get data race warnings, so I know I will need a threadsafe way to handle adding clients. The same goes for removing clients when I add that in.
Are there any other issues I might be missing by passing my ClientList into HandleClient, or any benefits I would gain from declaring ClientList as a package level variable instead?
Several problems with this approach.
First, your code contains a data race: each TCP connection is served by a separate goroutine, and they all attempt to modify the slice concurrently.
You might try building your code with go build -race (or go install -race — whatever you're using), and see it crash by the enabled runtime checks.
This one is easy to fix. The most straightforward approach is to add a mutex variable into the ClientList type:
type ClientList struct {
mu sync.Mutex
clients []*Client
}
…and make the type's methods hold the mutex while they're mutating the clients field, like this:
func (cList *ClientList) AddClient(cl *Client) {
cList.mu.Lock()
defer cList.mu.Unlock()
cList.clients = append(cList.clients, o)
}
(If you will ever encounter the typical usage pattern of your ClientList type is to frequently call methods which only read the contained list, you may start using the sync.RWLock type instead, which allows multiple concurrent readers.)
Second, I'd split the part which "identifies" a client out of the handler function.
As of now, in the handler, if the identification fails, the handler exits but the client is not delisted.
I'd say it would be better to identify it up front and only run the handler once the client is beleived to be okay.
Also it supposedly worth adding a deferred call to something like RemoveClient at the top of the handler's body so that the client is properly delisted when the handler is done with it.
IOW, I'd expect to see something like this:
func (cl *Client) HandleClient(cList *ClientList) {
defer cl.Conn.Close()
err := cl.Identify()
if err != nil {
log.Println(err)
return
}
cList.AddClient(cl)
defer cList.RemoveClient(cl)
// ... the rest of the code
}
I am using a mysql database and have many different Functions/Methods that interact with the database. For every Function I offcourse have to supply the Database Credentials such as
ReadAll.go
func ReadAll() {
db, err := sql.Open("mysql",
"user:password#tcp(127.0.0.1:3306)/hello")
if err != nil {
log.Fatal(err)
}
defer db.Close()
}
The part of "mysql",
"user:password#tcp(127.0.0.1:3306)/hello" never changes and I am supplying that to every Function that interacts with DB. I was wondering how can I for instance create a new File say DataBase.go put those credentials into some global variable and then reference when I need those strings ? That way if I have to change the credentials I only have to change them in 1 place.
I want to do something like
Database.go
const GlobalDB := "mysql","user:password#tcp(127.0.0.1:3306)/hello"
then
ReadAll.go
func ReadAll() {
db, err := sql.Open(GlobalDB)
if err != nil {
log.Fatal(err)
}
defer db.Close()
}
I am brand new to Golang but trying to figure this out.
I would probably do this by opening a session to the database once, then pass this session around to any function or method that may need it. This has a few potential problems:
You may need to lock access to it, so you don't co-mingle multiple queries on the same session (but it may be that your DB library ensures this, FWIW "database/sql" is concurrency-safe and recommends NOT opening short-lived database connections)
You can't safely close the session as it may still be in use elsewhere.
Another way would be to have a function that returns a DB sesssion, so instead of doing:
db, err := sql.Open("mysql", "user:password#tcp(127.0.0.1:3306)/hello")
You do the following:
func dbSession() (sql.DB, error) {
return sql.Open("mysql", "credentials")
}
func ReadAll() {
db, err := dbSession()
if err != nil {
log.Fatal(err)
}
defer db.Close()
}
And if you want even more flexibility, you can have a struct that contains the data you need, then build your DB connection parameters from that.
type dbData struct {
DBType, DBName, User, Host, Password string
}
var DBData dbData
func dbSession() (*sql.DB, error) {
return sql.Open(DBData.DBType, fmt.Sprintf("%s:%s#tcp(%s)/%s", DBData.User, DBData.Password, DBData.Host, DBData.DBName)
}
Also note the following in the documentation from sql.Open:
The returned DB is safe for concurrent use by multiple goroutines and
maintains its own pool of idle connections. Thus, the Open function
should be called just once. It is rarely necessary to close a DB.
you can easily create a new File with your credentials. Just have the file be in the main package main.
package main
var myDBConnectionString := "mysql://...."
This will be included when you compile your source.
The problem is, that you have to recompile your code everytime you have to connect to another database. Think about a development System vs. production System. The database credentials should differ in those systems, right? :)
To fix this, it is quit common to have a config file. So you can change the credentials with out re compiling your code.
I've got an other idea - just connect to the db once, and access this resource globally.
package main
import (
"fmt"
)
var myDb = "example"
func main() {
fmt.Println("Hello, playground")
doSomthingWithDatabase()
}
func doSomthingWithDatabase() {
fmt.Println("We can access a global variable here, see", myDb)
}
https://play.golang.org/p/npZ6Z49ink
For the configuration handling you can look here
https://blog.gopheracademy.com/advent-2014/reading-config-files-the-go-way/
hiboot-data provides out of the box starter that meet your requirement, the starter is github.com/hidevopsio/hiboot-data/starter/gorm, or you can implement your own starter by using hiboot framework, then you can inject then anywhere to decouple from the creation of the database configuration.
package service
import (
"errors"
"hidevops.io/hiboot-data/examples/gorm/entity"
"hidevops.io/hiboot-data/starter/gorm"
"hidevops.io/hiboot/pkg/app"
"hidevops.io/hiboot/pkg/utils/idgen"
)
type UserService interface {
AddUser(user *entity.User) (err error)
GetUser(id uint64) (user *entity.User, err error)
GetAll() (user *[]entity.User, err error)
DeleteUser(id uint64) (err error)
}
type UserServiceImpl struct {
// add UserService, it means that the instance of UserServiceImpl can be found by UserService
UserService
repository gorm.Repository
}
func init() {
// register UserServiceImpl
app.Component(newUserService)
}
// will inject BoltRepository that configured in github.com/hidevopsio/hiboot/pkg/starter/data/bolt
func newUserService(repository gorm.Repository) UserService {
repository.AutoMigrate(&entity.User{})
return &UserServiceImpl{
repository: repository,
}
}
func (s *UserServiceImpl) AddUser(user *entity.User) (err error) {
if user == nil {
return errors.New("user is not allowed nil")
}
if user.Id == 0 {
user.Id, _ = idgen.Next()
}
err = s.repository.Create(user).Error()
return
}
func (s *UserServiceImpl) GetUser(id uint64) (user *entity.User, err error) {
user = &entity.User{}
err = s.repository.Where("id = ?", id).First(user).Error()
return
}
func (s *UserServiceImpl) GetAll() (users *[]entity.User, err error) {
users = &[]entity.User{}
err = s.repository.Find(users).Error()
return
}
func (s *UserServiceImpl) DeleteUser(id uint64) (err error) {
err = s.repository.Where("id = ?", id).Delete(entity.User{}).Error()
return
}