Exporting two dbus objects not possible - go

Using godbus library and according to their server example, I'm trying to export (serve) two different objects with different interfaces. One object path is /a/b/c and another is /a/b/c/d. If I export one of them everything works fine. Even if have no overlap everything works fine(/a/b/c & /w/x/y/z). But exporting /a/b/c & /a/b/c/d results in just having one of them on the dbus. Here is my code:
package main
import (
"fmt"
"os"
"github.com/godbus/dbus/v5"
"github.com/godbus/dbus/v5/introspect"
)
const introP = `
<node>
<interface name="a.b.c.Ping">
<method name="Ping">
<arg direction="out" type="s"/>
</method>
</interface>` + introspect.IntrospectDataString + `</node> `
type ping string
func (p ping) Ping() (string, *dbus.Error) {
fmt.Println(p)
return string(p), nil
}
const introZ = `
<node>
<interface name="a.b.c.d.Zing">
<method name="Zing">
<arg direction="out" type="s"/>
</method>
</interface>` + introspect.IntrospectDataString + `</node> `
type zing string
func (z zing) Zing() (string, *dbus.Error) {
fmt.Println(z)
return string(z), nil
}
func main() {
conn, err := dbus.ConnectSessionBus()
if err != nil {
panic(err)
}
defer conn.Close()
reply, err := conn.RequestName("a.b.c",
dbus.NameFlagDoNotQueue)
if err != nil {
panic(err)
}
if reply != dbus.RequestNameReplyPrimaryOwner {
fmt.Fprintln(os.Stderr, "name already taken")
os.Exit(1)
}
p := ping("Pong")
conn.Export(p, "/a/b/c", "a.b.c.Ping")
conn.Export(introspect.Introspectable(introP), "/a/b/c",
"org.freedesktop.DBus.Introspectable")
z := zing("Zong")
conn.Export(z, "/a/b/c/d", "a.b.c.d.Zing")
conn.Export(introspect.Introspectable(introZ), "/a/b/c/d",
"org.freedesktop.DBus.Introspectable")
fmt.Println("Listening on dbus...")
select {}
}

package main
import (
"fmt"
"os"
"github.com/godbus/dbus/v5"
"github.com/godbus/dbus/v5/introspect"
)
type ping string
func (p ping) Ping() (string, *dbus.Error) {
fmt.Println(p)
return string(p), nil
}
type zing string
func (z zing) Zing() (string, *dbus.Error) {
fmt.Println(z)
return string(z), nil
}
func main() {
conn, err := dbus.SessionBus()
if err != nil {
panic(err)
}
replyP, errP := conn.RequestName("a.b.c.d.Ping",
dbus.NameFlagDoNotQueue)
if errP != nil {
panic(errP)
}
if replyP != dbus.RequestNameReplyPrimaryOwner {
fmt.Fprintln(os.Stderr, "name already taken")
os.Exit(1)
}
p := ping("Pong")
var introP = &introspect.Node{
Name: "/a/b/c/d/Ping",
Interfaces: []introspect.Interface{
introspect.IntrospectData,
{
Name: "a.b.c.d.Ping",
Methods: introspect.Methods(p),
},
},
}
conn.Export(p, "/a/b/c/d/Ping", "a.b.c.d.Ping")
z := zing("Zong")
var introZ = &introspect.Node{
Name: "/a/b/c/Zing",
Interfaces: []introspect.Interface{
introspect.IntrospectData,
{
Name: "a.b.c.Zing",
Methods: introspect.Methods(z),
},
},
}
conn.Export(z, "/a/b/c/Zing", "a.b.c.Zing")
conn.Export(introspect.NewIntrospectable(&introspect.Node{
Name: "/",
Children: []introspect.Node{
{
Name: "a",
},
},
}), "/", "org.freedesktop.DBus.Introspectable")
conn.Export(introspect.NewIntrospectable(&introspect.Node{
Name: "/a",
Children: []introspect.Node{
{
Name: "b",
},
},
}), "/com", "org.freedesktop.DBus.Introspectable")
conn.Export(introspect.NewIntrospectable(&introspect.Node{
Name: "/a/b",
Children: []introspect.Node{
{
Name: "c",
},
},
}), "/a/b", "org.freedesktop.DBus.Introspectable")
conn.Export(introspect.NewIntrospectable(&introspect.Node{
Name: "/a/b/c",
Children: []introspect.Node{
{
Name: "d",
},
{
Name: "Zing",
},
},
}), "/a/b/c", "org.freedesktop.DBus.Introspectable")
conn.Export(introspect.NewIntrospectable(&introspect.Node{
Name: "/a/b/c/d",
Children: []introspect.Node{
{
Name: "Ping",
},
},
}), "/a/b/c/d", "org.freedesktop.DBus.Introspectable")
conn.Export(introspect.NewIntrospectable(introP), "/a/b/c/d/Ping",
"org.freedesktop.DBus.Introspectable")
conn.Export(introspect.NewIntrospectable(introZ), "/a/b/c/Zing",
"org.freedesktop.DBus.Introspectable")
fmt.Printf("Listening on %s / %s ...\n", "a.b.c...", "/a/b/c...")
select {}
}

Related

Optional array in struct

I want to make an array optional in struct and use it with an if else in a func.
type TestValues struct {
Test1 string `json:"test1"`
DefaultTests []string `json:"__tests"`
//DefaultTests *array `json:"__tests,omitempty" validate:"option"`
Test2 string `json:"__Test2"`
}
func (x *Controller) createTest(context *gin.Context, uniqueId string, testBody *TestValues) (*http.Response, error) {
if testBody.DefaultTags {
postBody, err := json.Marshal(map[string]string{
"Test2": testBody.Test2,
"Test1": testBody.Test1,
"defaultTests": testBody.DefaultTests,
"uniqueId": uniqueId,
})
} else {
postBody, err := json.Marshal(map[string]string{
"Test2": testBody.Test2,
"Test1": testBody.Test1,
"uniqueId": uniqueId,
})
}
...
}
When I run the code it tells me that DefaultTests is undefined array but I don't want this error to pop because DefaultTests can existe and sometimes it won't be present in the json that's why I want to make it optional. The if else part is not working too.
It's better to use len() when checking if an array is empty here.
if len(testBody.DefaultTests) > 0 {
...
}
Check the Zero value of the DefaultTests in struct below for more clarity on this behaviour
package main
import "fmt"
type TestValues struct {
Test1 string `json:"test1"`
DefaultTests []string `json:"__tests"`
//DefaultTests *array `json:"__tests,omitempty" validate:"option"`
Test2 string `json:"__Test2"`
}
func main() {
var tv = TestValues{Test1: "test"}
if len(tv.DefaultTests) > 0 {
fmt.Printf("Default Tests: %v\n", tv.DefaultTests)
} else {
fmt.Printf("Default Tests empty value: %v\n", tv.DefaultTests)
}
}
Here's my final code with Marc's answer
func (x *Controller) createTest(context *gin.Context, uniqueId string, testBody *TestValues) (*http.Response, error) {
if len(testBody.DefaultTags) > 0 {
postBody, err := json.Marshal(testBody.DefaultTags)
} else {
postBody, err := json.Marshal(map[string]string{
"Test2": testBody.Test2,
"Test1": testBody.Test1,
"uniqueId": uniqueId,
})
}
...
}

Go gin nested JSON request body POST, error unexpected end of JSON input

I am new to GO and was trying to create a simple POST API with gin and gorm.
The request data is nested JSON like below:
{
"fall_orders_request": [
{
"fruit": "Watermelon",
"vegetable": "Carrot"
}
],
"spring_orders_request": [
{
"fruit": "Watermelon",
"vegetable": "Carrot",
"cupcake": "minions"
}
],
"custome_rates": [
{
"fruit": "Watermelon",
"greentea": "Japanese",
"cupcake": "pokemon"
}
]
}
After receiving the request i.e orders the backend will save it to corresponding Databases for each session.
This is my code for the orders.go:
package order
import (
"net/http"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
type FallOrders struct {
ID uint `gorm:"primarykey"`
Fruit string `json:"fruit"`
Vegetable string `json:"vegetable"`
}
type SpringOrders struct {
ID uint `gorm:"primarykey"`
Fruit string `json:"fruit"`
Vegetable string `json:"vegetable"`
Cupcake string `json:"cupcake"`
}
type WinterOrders struct {
ID uint `gorm:"primarykey"`
Fruit string `json:"fruit"`
Greentea string `json:"greentea"`
Cupcake string `json:"cupcake"`
}
type allOrders struct {
FallOrders []FallOrders `json:"fall_orders"`
SpringOrders []SpringOrders `json:"spring_orders"`
WinterOrders []WinterOrders `json:"winter_orders"`
}
type FallOrdersRequest struct {
Fruit string `json:"fruit"`
Vegetable string `json:"vegetable"`
}
type SpringOrdersRequest struct {
Fruit string `json:"fruit"`
Vegetable string `json:"vegetable"`
Cupcake string `json:"cupcake"`
}
type WinterOrdersRequest struct {
Fruit string `json:"fruit"`
Greentea string `json:"greentea"`
Cupcake string `json:"cupcake"`
}
type AllOrdersRequest struct {
FallOrdersRequest []FallOrdersRequest `json:"fall_orders_request"`
SpringOrdersRequest []SpringOrdersRequest `json:"spring_orders_request"`
WinterOrdersRequest []WinterOrdersRequest `json:"winter_orders_request"`
}
type AllOrdersManager struct {
DB *gorm.DB
}
type FallOrdersManager struct {
DB *gorm.DB
}
type SpringOrdersManager struct {
DB *gorm.DB
}
type WinterOrdersManager struct {
DB *gorm.DB
}
func CreateModularRates() gin.HandlerFunc {
return func(c *gin.Context) {
var aor AllOrdersRequest
var form FallOrdersManager
var sorm SpringOrdersManager
var worm WinterOrdersManager
if err := c.BindJSON(&aor); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
for _, fall := range aor.FallOrdersRequest {
fallOrders := FallOrders{
Fruit: fall.Fruit,
Vegetable: fall.Vegetable,
}
c.JSON(http.StatusCreated, fallOrders)
res := form.DB.Create(&fallOrders)
if res.Error != nil {
return
}
}
for _, spring := range aor.SpringOrdersRequest {
springOrders := SpringOrders{
Fruit: spring.Fruit,
Vegetable: spring.Vegetable,
Cupcake: spring.Cupcake,
}
c.JSON(http.StatusCreated, springOrders)
res := sorm.DB.Create(&springOrders)
if res.Error != nil {
return
}
}
for _, winter := range aor.WinterOrdersRequest {
winterOrders := WinterOrders{
Fruit: winter.Fruit,
Greentea: winter.Greentea,
Cupcake: winter.Cupcake,
}
c.JSON(http.StatusCreated, winterOrders)
res := worm.DB.Create(&winterOrders)
if res.Error != nil {
return
}
}
}
}
And this is the automated test orders_test.go
package order
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
)
func TestOrderData() order.AllOrdersRequest {
fall_orders_request := []order.FallOrdersRequest{}
spring_orders_request := []order.SpringOrdersRequest{}
winter_orders_request := []order.WinterOrdersRequest{}
fall_orders_request = append(fall_orders_request, order.FallOrdersRequest{
Fruit: "Watermelon",
Vegetable: "Carrot",
})
spring_orders_request = append(spring_orders_request, order.spring_orders_request{
Fruit: "Watermelon",
Vegetable: "Carrot",
Cupcake: "minions",
})
winter_orders_request = append(winter_orders_request, order.winter_orders_request{
Fruit: "Watermelon",
Greentea: "Japanese",
Cupcake: "pokemon",
})
return order.AllOrdersRequest{
fall_orders_request: fall_orders_request,
spring_orders_request: spring_orders_request,
winter_orders_request: winter_orders_request,
}
}
func TestOrderCreation(t *testing.T) {
params := TestOrderData()
jsonPayload, _ := json.Marshal(params)
w := httptest.NewRecorder()
req, _ := http.NewRequest(
"POST",
"/orders",
bytes.NewReader(jsonPayload),
)
var c *gin.Context
assert.Equal(t, 201, w.Code)
err2 := c.ShouldBindJSON(&req)
if err2 == nil {
return
}
}
After running the test I get the following error:
Error: unexpected end of JSON input
{"message":"Error #01: EOF\n"}
Logging the request shows the request body is JSON as expected but not sure why I am getting this error.
If you are already in the order package you don't need it to reference it in each place you can directly access the method defined in the order package
Here struct name are incorrect order.spring_orders_request, order.winter_orders_request it should be order.SpringOrdersRequest, order.WinterOrdersRequest
spring_orders_request = append(spring_orders_request, order.spring_orders_request{
Fruit: "Watermelon",
Vegetable: "Carrot",
Cupcake: "minions",
})
winter_orders_request = append(winter_orders_request, order.winter_orders_request{
Fruit: "Watermelon",
Greentea: "Japanese",
Cupcake: "pokemon",
})
The key here are wrong is fall_orders_request, spring_orders_request, winter_orders_request it should be FallOrdersRequest, SpringOrdersRequest, WinterOrdersRequest
return order.AllOrdersRequest{
fall_orders_request: fall_orders_request,
spring_orders_request: spring_orders_request,
winter_orders_request: winter_orders_request,
}
Final:
package order
import (
"fmt"
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
// "github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
)
func OrderData() AllOrdersRequest {
fall_orders_request := []FallOrdersRequest{}
spring_orders_request := []SpringOrdersRequest{}
winter_orders_request := []WinterOrdersRequest{}
fall_orders_request = append(fall_orders_request, FallOrdersRequest{
Fruit: "Watermelon",
Vegetable: "Carrot",
})
spring_orders_request = append(spring_orders_request, SpringOrdersRequest{
Fruit: "Watermelon",
Vegetable: "Carrot",
Cupcake: "minions",
})
winter_orders_request = append(winter_orders_request, WinterOrdersRequest{
Fruit: "Watermelon",
Greentea: "Japanese",
Cupcake: "pokemon",
})
return AllOrdersRequest{
FallOrdersRequest: fall_orders_request,
SpringOrdersRequest: spring_orders_request,
WinterOrdersRequest: winter_orders_request,
}
}
func TestOrderCreation(t *testing.T) {
params := OrderData()
jsonPayload, _ := json.Marshal(params)
// fmt.Println(jsonPayload)
_bytes := bytes.NewReader(jsonPayload)
// default `ResponseRecorder` `http.Response` status is 200
// we need to update it to 201 before we access it in `assert`
w := httptest.NewRecorder()
w.WriteHeader(201)
contentLength, err := w.Write(jsonPayload)
fmt.Println(contentLength, err)
req, _ := http.NewRequest(
"POST",
"http://localhost:8080/orders",
_bytes,
)
assert.Equal(t, 201, w.Code)
res := w.Result()
fmt.Println(req)
fmt.Println(res)
// Not sure what you are trying to do here but since there is nothing
// in the context and req variable is already defined of `http.Request` type
// below statements doesn't make sense.
// var c *gin.Context
// if err := c.ShouldBindJSON(&req); err != nil {
// return
// }
}

How to create multi instance in google cloud functions with golang

I am trying to create multi instance in GCP with cloud function, use golang programing.
I refer tutorial in https://medium.com/google-cloud/using-cloud-scheduler-and-cloud-functions-to-deploy-a-periodic-compute-engine-vm-worker-2b897ef68dc5 then write some customize in my context. Here is my code
package cloudfunctions
import (
"context"
"fmt"
"log"
"net/http"
"os"
"google.golang.org/api/compute/v1"
)
var ProjectID = ""
var Zone = ""
var Region = ""
var InstanceName = ""
var InstanceType = ""
func DeployInstance(w http.ResponseWriter, r *http.Request) {
ProjectID = os.Getenv("PROJECT_ID")
Zone = os.Getenv("ZONE")
Region = os.Getenv("REGION")
cs, err := InitComputeService()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
log.Fatal(err)
}
var listInstance = []string{"e2-standard-2", "e2-standard-8", "n2-standard-2", "n2-standard-8", "n1-custom-2-8192", "n1-custom-8-32768", "c2-standard-8" }
for i:=0; i < 7; i++ {
InstanceType = listInstance[i]
InstanceName = "benchmark-"+InstanceType
instance, err := GetInstance(cs)
if err != nil {
w.WriteHeader(http.StatusTemporaryRedirect)
w.Write([]byte(err.Error() + " instance may not exist yet"))
log.Print(err)
_, err = CreateInstance(cs)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("creating instance " + InstanceName + "in zone: " + Zone))
startInstance(cs, w)
}
} else {
msg := "instance is in intermediate state: " + instance.Status
w.WriteHeader(http.StatusAccepted)
w.Write([]byte(msg))
log.Println(msg)
}
}
}
func InitComputeService() (*compute.Service, error) {
ctx := context.Background()
return compute.NewService(ctx)
}
func GetInstance(computeService *compute.Service) (*compute.Instance, error) {
return computeService.Instances.Get(ProjectID, Zone, InstanceName).Do()
}
func StartInstance(computeService *compute.Service) (*compute.Operation, error) {
return computeService.Instances.Start(ProjectID, Zone, InstanceName).Do()
}
// CreateInstance creates a given instance with metadata that logs its information.
func CreateInstance(computeService *compute.Service) (*compute.Operation, error) {
instance := &compute.Instance{
Name: InstanceName,
MachineType: fmt.Sprintf("zones/%s/machineTypes/%s", Zone, InstanceType),
NetworkInterfaces: []*compute.NetworkInterface{
{
Name: "default",
Subnetwork: fmt.Sprintf("projects/%s/regions/%s/subnetworks/default", ProjectID, Region),
AccessConfigs: []*compute.AccessConfig{
{
Name: "External NAT",
Type: "ONE_TO_ONE_NAT",
NetworkTier: "PREMIUM",
},
},
},
},
Scheduling: &compute.Scheduling{
Preemptible: true,
},
Disks: []*compute.AttachedDisk{
{
Boot: true, // The first disk must be a boot disk.
AutoDelete: true, //Optional
Mode: "READ_WRITE", //Mode should be READ_WRITE or READ_ONLY
Interface: "SCSI", //SCSI or NVME - NVME only for SSDs
InitializeParams: &compute.AttachedDiskInitializeParams{
DiskName: "worker-instance-boot-disk",
SourceImage: "projects/centos-cloud/global/images/family/centos-7",
DiskType: fmt.Sprintf("projects/%s/zones/%s/diskTypes/pd-ssd", ProjectID, Zone),
DiskSizeGb: 200,
},
},
},
}
return computeService.Instances.Insert(ProjectID, Zone, instance).Do()
}
// startInstance is a wrapper function for the switch statement
func startInstance(cs *compute.Service, w http.ResponseWriter) {
operation, err := StartInstance(cs)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
log.Fatal(err)
}
w.WriteHeader(http.StatusOK)
data, _ := operation.MarshalJSON()
w.Write(data)
}
In above code, I want to create 7 instance with 7 difference setting, specific is instance type and instance name. I test this code in cloud function with DeployInstance is start function. But there is only one instance was created, with name is benchmark-e2-standard-2 and type is e2-standard-2. It output an error with message Error: Infrastructure cannot communicate with function. There was likely a crash or deadlock in the user-provided code. Additional troubleshooting documentation can be found at https://cloud.google.com/functions/docs/troubleshooting#logging
I visited website but I not find a solution to fix my code. Who can help me why my code not true, how can I fix it. Step by step if possible.
Thanks in advance.
I was found my answer. Root cause is each instance must have a disk partition, with different name.
So, I change my code with some change, you can see it bellow.
package cloudfunctions
import (
"context"
"fmt"
"log"
"net/http"
"os"
"google.golang.org/api/compute/v1"
"time"
)
var ProjectID = ""
var Zone = ""
var Region = ""
var InstanceName = ""
var InstanceType = ""
var IDiskName = ""
func DeployInstance(w http.ResponseWriter, r *http.Request) {
ProjectID = os.Getenv("PROJECT_ID")
Zone = os.Getenv("ZONE")
Region = os.Getenv("REGION")
var listInstance = []string{"e2-standard-8","e2-standard-2", "n2-standard-2", "n2-standard-8", "n1-custom-2-8192", "n1-custom-8-32768", "c2-standard-8"}
for i:=0; i < len(listInstance); i++ {
cs, err := compute.NewService(context.Background())
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
log.Fatal(err)
}
InstanceType = listInstance[i]
InstanceName = "benchmark-"+InstanceType
IDiskName = InstanceName+"-boot-disk"
instance, err := GetInstance(cs)
if err != nil {
w.WriteHeader(http.StatusTemporaryRedirect)
w.Write([]byte(err.Error() + " instance may not exist yet"))
_, err = CreateInstance(cs)
if err != nil {
for {
disk, derr := cs.Disks.Get(ProjectID, Zone, IDiskName).Context(context.Background()).Do()
log.Print(IDiskName + " is " + disk.Status)
time.Sleep(1 * time.Second)
if derr != nil {
startInstance(cs, w)
break
}
}
}
} else {
msg := "instance "+ InstanceName +" is in intermediate state: " + instance.Status
w.WriteHeader(http.StatusAccepted)
w.Write([]byte(msg))
log.Println(msg)
}
}
}
func GetInstance(computeService *compute.Service) (*compute.Instance, error) {
return computeService.Instances.Get(ProjectID, Zone, InstanceName).Do()
}
func StartInstance(computeService *compute.Service) (*compute.Operation, error) {
return computeService.Instances.Start(ProjectID, Zone, InstanceName).Do()
}
// CreateInstance creates a given instance with metadata that logs its information.
func CreateInstance(computeService *compute.Service) (*compute.Operation, error) {
instance := &compute.Instance{
Name: InstanceName,
MachineType: fmt.Sprintf("zones/%s/machineTypes/%s", Zone, InstanceType),
NetworkInterfaces: []*compute.NetworkInterface{
{
Name: "default",
Subnetwork: fmt.Sprintf("projects/%s/regions/%s/subnetworks/default", ProjectID, Region),
AccessConfigs: []*compute.AccessConfig{
{
Name: "External NAT",
Type: "ONE_TO_ONE_NAT",
NetworkTier: "PREMIUM",
},
},
},
},
Scheduling: &compute.Scheduling{
Preemptible: true,
},
Disks: []*compute.AttachedDisk{
{
Boot: true, // The first disk must be a boot disk.
AutoDelete: true, //Optional
Mode: "READ_WRITE", //Mode should be READ_WRITE or READ_ONLY
Interface: "SCSI", //SCSI or NVME - NVME only for SSDs
InitializeParams: &compute.AttachedDiskInitializeParams{
DiskName: IDiskName,
SourceImage: "projects/centos-cloud/global/images/family/centos-7",
DiskType: fmt.Sprintf("projects/%s/zones/%s/diskTypes/pd-ssd", ProjectID, Zone),
DiskSizeGb: 100,
},
},
},
}
return computeService.Instances.Insert(ProjectID, Zone, instance).Do()
}
// startInstance is a wrapper function for the switch statement
func startInstance(cs *compute.Service, w http.ResponseWriter) {
operation, err := StartInstance(cs)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
log.Fatal(err)
}
w.WriteHeader(http.StatusOK)
data, _ := operation.MarshalJSON()
w.Write(data)
}
If you have any question about this problem, drop your comment. I hope I can support for you.
Thanks all.

Why I cannot get my donationId's value from stub's GetState function

Currently, I am learning hyperledger/fabric and trying to write the chaincode. Below is the invoke function and customized function I created.
type Donation struct {
Id string `json:"id"`
Who string `json:"who"`
Rid string `json:"rid"`
Money int `json:"money"`
}
type Request struct {
Id string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
ExpectedMoney int `json:"expectedMoney"`
CurrentMoney int `json:"currentMoney"`
DonationList []string `json:"donationList"`
}
type Person struct {
Id string `json:"id"`
Name string `json:"name"`
MyRequests []string `json:"myRequests"`
MyDonations []string `json:"myDonations"`
}
func (t *SimpleChaincode) Invoke(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
if function == "createDonation" {
return t.createDonation(stub, args)
}
return nil, errors.New("Received unknown function invocation")
}
func (t *SimpleChaincode) createDonation(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
var from, toRid string
var money int
var err error
if len(args) != 3 {
return nil, errors.New("My createDonation. Incorrect number of arguments. Expecting 3")
}
from = args[0]
toRid = args[1]
money, err = strconv.Atoi(args[2])
if err != nil {
return nil, errors.New("money cannot convert to number")
}
var donation Donation
donation = Donation{Id: "donationid", Rid: toRid, Who: from, Money: money}
djson, err := json.Marshal(&donation)
if err != nil {
return nil, err
}
var a = donation.Id
stub.PutState(a, djson)
personByte, err := stub.GetState(from + "")
fmt.Println(personByte)
return nil, nil
}
func (t *SimpleChaincode) read(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
log.Println("Get into read function")
var key, jsonResp string
var err error
key = args[0]
valAsbytes, err := stub.GetState(key)
if err != nil {
jsonResp = "{\"Error\":\"Failed to get state for " + key + "\"}"
return nil, errors.New(jsonResp)
}
if valAsbytes == nil {
return []byte("cannot find the key's value of the chaincode"), nil
}
return valAsbytes, nil
}
However, When I tried to use swagger UI to invoke and retrieve the "donationid"'s value, it is empty. Is there anything wrong about my code? Thanks in advance.
Invoke
{
"jsonrpc": "2.0",
"method": "invoke",
"params": {
"type": 1,
"chaincodeID": {
"name": "92d975f9301f9b72c7b148e65dcc835a971be55b2555a45c41d6d2eed04ecfd6b1974245cfb77d002e244e9e581e4042747e9f4d6a46b59e9d7e8a7419476296"
},
"ctorMsg": {
"function": "createDonation",
"args": [
"Simon",
"requestid",
"300"
]
},
"secureContext": "user_type1_XXXXXXX"
},
"id": 3
}
query
{
"jsonrpc": "2.0",
"method": "query",
"params": {
"type": 1,
"chaincodeID": {
"name": "92d975f9301f9b72c7b148e65dcc835a971be55b2555a45c41d6d2eed04ecfd6b1974245cfb77d002e244e9e581e4042747e9f4d6a46b59e9d7e8a7419476296"
},
"ctorMsg": {
"function": "read",
"args": [
"donationid"
]
},
"secureContext": "user_type1_xxxxxx"
},
"id": 2
}

go-swagger not generating model info

Here is my simple rest service:
// Package classification User API.
//
// the purpose of this application is to provide an application
// that is using plain go code to define an API
//
// This should demonstrate all the possible comment annotations
// that are available to turn go code into a fully compliant swagger 2.0 spec
//
// Terms Of Service:
//
// there are no TOS at this moment, use at your own risk we take no responsibility
//
// Schemes: http, https
// Host: localhost
// BasePath: /v2
// Version: 0.0.1
// License: MIT http://opensource.org/licenses/MIT
// Contact: John Doe<john.doe#example.com> http://john.doe.com
//
// Consumes:
// - application/json
// - application/xml
//
// Produces:
// - application/json
// - application/xml
//
//
// swagger:meta
package main
import (
"github.com/gin-gonic/gin"
"strconv"
"database/sql"
_ "github.com/go-sql-driver/mysql"
"gopkg.in/gorp.v1"
"log"
)
// swagger:model
// User represents the user for this application
//
// A user is the security principal for this application.
// It's also used as one of main axis for reporting.
//
// A user can have friends with whom they can share what they like.
//
type User struct {
// the id for this user
//
// required: true
// min: 1
Id int64 `db:"id" json:"id"`
// the first name for this user
// required: true
// min length: 3
Firstname string `db:"firstname" json:"firstname"`
// the last name for this user
// required: true
// min length: 3
Lastname string `db:"lastname" json:"lastname"`
}
func main() {
r := gin.Default()
r.Use(Cors())
v1 := r.Group("api/v1")
{
v1.GET("/users", GetUsers)
v1.GET("/users/:id", GetUser)
v1.POST("/users", PostUser)
v1.PUT("/users/:id", UpdateUser)
v1.DELETE("/users/:id", DeleteUser)
v1.OPTIONS("/users", OptionsUser) // POST
v1.OPTIONS("/users/:id", OptionsUser) // PUT, DELETE
}
r.Run(":8696")
}
func GetUsers(c *gin.Context) {
// swagger:route GET /user listPets pets users
//
// Lists pets filtered by some parameters.
//
// This will show all available pets by default.
// You can get the pets that are out of stock
//
// Consumes:
// - application/json
// - application/x-protobuf
//
// Produces:
// - application/json
// - application/x-protobuf
//
// Schemes: http, https, ws, wss
//
// Security:
// api_key:
// oauth: read, write
//
// Responses:
// default: genericError
// 200: someResponse
// 422: validationError
var users []User
_, err := dbmap.Select(&users, "SELECT * FROM user")
if err == nil {
c.JSON(200, users)
} else {
c.JSON(404, gin.H{"error": "no user(s) into the table"})
}
// curl -i http://localhost:8080/api/v1/users
}
func GetUser(c *gin.Context) {
id := c.Params.ByName("id")
var user User
err := dbmap.SelectOne(&user, "SELECT * FROM user WHERE id=?", id)
if err == nil {
user_id, _ := strconv.ParseInt(id, 0, 64)
content := &User{
Id: user_id,
Firstname: user.Firstname,
Lastname: user.Lastname,
}
c.JSON(200, content)
} else {
c.JSON(404, gin.H{"error": "user not found"})
}
// curl -i http://localhost:8080/api/v1/users/1
}
func PostUser(c *gin.Context) {
var user User
c.Bind(&user)
if user.Firstname != "" && user.Lastname != "" {
if insert, _ := dbmap.Exec(`INSERT INTO user (firstname, lastname) VALUES (?, ?)`, user.Firstname, user.Lastname); insert != nil {
user_id, err := insert.LastInsertId()
if err == nil {
content := &User{
Id: user_id,
Firstname: user.Firstname,
Lastname: user.Lastname,
}
c.JSON(201, content)
} else {
checkErr(err, "Insert failed")
}
}
} else {
c.JSON(422, gin.H{"error": "fields are empty"})
}
// curl -i -X POST -H "Content-Type: application/json" -d "{ \"firstname\": \"Thea\", \"lastname\": \"Queen\" }" http://localhost:8080/api/v1/users
}
func UpdateUser(c *gin.Context) {
id := c.Params.ByName("id")
var user User
err := dbmap.SelectOne(&user, "SELECT * FROM user WHERE id=?", id)
if err == nil {
var json User
c.Bind(&json)
user_id, _ := strconv.ParseInt(id, 0, 64)
user := User{
Id: user_id,
Firstname: json.Firstname,
Lastname: json.Lastname,
}
if user.Firstname != "" && user.Lastname != ""{
_, err = dbmap.Update(&user)
if err == nil {
c.JSON(200, user)
} else {
checkErr(err, "Updated failed")
}
} else {
c.JSON(422, gin.H{"error": "fields are empty"})
}
} else {
c.JSON(404, gin.H{"error": "user not found"})
}
// curl -i -X PUT -H "Content-Type: application/json" -d "{ \"firstname\": \"Thea\", \"lastname\": \"Merlyn\" }" http://localhost:8080/api/v1/users/1
}
func DeleteUser(c *gin.Context) {
id := c.Params.ByName("id")
var user User
err := dbmap.SelectOne(&user, "SELECT id FROM user WHERE id=?", id)
if err == nil {
_, err = dbmap.Delete(&user)
if err == nil {
c.JSON(200, gin.H{"id #" + id: " deleted"})
} else {
checkErr(err, "Delete failed")
}
} else {
c.JSON(404, gin.H{"error": "user not found"})
}
// curl -i -X DELETE http://localhost:8080/api/v1/users/1
}
var dbmap = initDb()
func initDb() *gorp.DbMap {
db, err := sql.Open("mysql",
"root:max_123#tcp(127.0.0.1:3306)/gotest")
checkErr(err, "sql.Open failed")
dbmap := &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{"InnoDB", "UTF8"}}
dbmap.AddTableWithName(User{}, "User").SetKeys(true, "Id")
err = dbmap.CreateTablesIfNotExists()
checkErr(err, "Create table failed")
return dbmap
}
func checkErr(err error, msg string) {
if err != nil {
log.Fatalln(msg, err)
}
}
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
c.Writer.Header().Add("Access-Control-Allow-Origin", "*")
c.Next()
}
}
func OptionsUser(c *gin.Context) {
c.Writer.Header().Add("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Methods", "DELETE,POST, PUT")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type")
c.Next()
}
Now when I'm executing :
swagger generate spec -o ./swagger.json
to generate the json spec I'm getting:
{
"consumes": ["application/json", "application/xml"],
"produces": ["application/json", "application/xml"],
"schemes": ["http", "https"],
"swagger": "2.0",
"info": {
"description": "the purpose of this application is to provide an application\nthat is using plain go code to define an API\n\nThis should demonstrate all the possible comment annotations\nthat are available to turn go code into a fully compliant swagger 2.0 spec",
"title": "User API.",
"termsOfService": "there are no TOS at this moment, use at your own risk we take no responsibility",
"contact": {
"name": "John Doe",
"url": "http://john.doe.com",
"email": "john.doe#example.com"
},
"license": {
"name": "MIT",
"url": "http://opensource.org/licenses/MIT"
},
"version": "0.0.1"
},
"host": "localhost",
"basePath": "/v2",
"paths": {
"/user": {
"get": {
"description": "This will show all available pets by default.\nYou can get the pets that are out of stock",
"consumes": ["application/json", "application/x-protobuf"],
"produces": ["application/json", "application/x-protobuf"],
"schemes": ["http", "https", "ws", "wss"],
"tags": ["listPets", "pets"],
"summary": "Lists pets filtered by some parameters.",
"operationId": "users",
"security": [{
"api_key": null
}, {
"oauth": ["read", "write"]
}],
"responses": {
"200": {
"$ref": "#/responses/someResponse"
},
"422": {
"$ref": "#/responses/validationError"
},
"default": {
"$ref": "#/responses/genericError"
}
}
}
}
},
"definitions": {}
}
Note that my definitions are empty, not sure why.
If I paste the same json spec in http://editor.swagger.io/#/
It says
Error
Object
message: "options.definition is required"
code: "UNCAUGHT_SWAY_WORKER_ERROR"
Any directions on what is the right way to generate swagger documentation would help
It's because go-swagger can't detect the usage of your definitions. I made the assumption that you'd always have a struct describing the parameters and that those would always use the definitions that are in use.
It would be great if you could submit this question as an issue on the repo with your sample program. I'll add it to my tests.

Resources