Wrap io.PipeReader to store progress - go

I would like to keep track of the progress in an io.Pipe. I came up with the following struct ProgressPipeReader which wraps io.PipeReader, storing the progress in bytes inside ProgressPipeReader.progress:
type ProgressPipeReader struct {
io.PipeReader
progress int64
}
func (pr *ProgressPipeReader) Read(data []byte) (int, error) {
n, err := pr.PipeReader.Read(data)
if err == nil {
pr.progress += int64(n)
}
return n, err
}
Unfortunately, I can't seem to use it to wrap an io.PipeReader. The following snippet
pr, pw := io.Pipe()
pr = &ProgressPipeReader{PipeReader: pr}
yields the error
cannot use pr (type *io.PipeReader) as type io.PipeReader in field value
Any hints?

As the error describes, you are trying to store a *io.PipeReader value in a io.PipeReader field. You can fix this by updating your struct definition to the correct type:
type ProgressPipeReader struct {
*io.PipeReader
progress int64
}

Related

Error while trying to fetch queryresult.KV object in JSON.Unmarshal

I am a little bit confused here and although I have searched a lot on this, something is clearly missing from my knowledge and I am asking your help.
I have created a Hyperledger Fabric Network and installed a chaincode in it. And I want to make a function that retrieves all the World State inputs about the Keys. I have done it already with the bytes.Buffer and it worked. But what I want to do is to do it with a struct.
So, I created the following struct that has only the key:
type WSKeys struct {
Key string `json: "key"`
Namespace string `json: "Namespace"`
}
And this is my code function:
func (s *SmartContract) getAllWsDataStruct(APIstub shim.ChaincodeStubInterface , args []string) sc.Response {
var keyArrayStr []WSKeys
resultsIterator, err := APIstub.GetQueryResult("{\"selector\":{\"_id\":{\"$ne\": null }} }")
if err != nil {
return shim.Error("Error occured when trying to fetch data: "+err.Error())
}
for resultsIterator.HasNext() {
// Get the next record
queryResponse, err := resultsIterator.Next()
if err != nil {
return shim.Error(err.Error())
}
fmt.Println(queryResponse)
var qry_key_json WSKeys
json.Unmarshal([]byte(queryResponse), &qry_key_json)
keyArray = append(keyArray, qry_key_json)
}
defer resultsIterator.Close()
all_bytes, _ := json.Marshal(keyArray)
fmt.Println(keyArray)
return shim.Success(all_bytes)
}
When executing the above I get the following error:
cannot convert queryResponse (type *queryresult.KV) to type []byte
I can get the results correctly if I, for example do this:
func (s *SmartContract) getAllWsDataStruct(APIstub shim.ChaincodeStubInterface , args []string) sc.Response {
var keyArray []string
resultsIterator, err := APIstub.GetQueryResult("{\"selector\":{\"_id\":{\"$ne\": null }} }")
if err != nil {
return shim.Error("Error occured when trying to fetch data: "+err.Error())
}
for resultsIterator.HasNext() {
// Get the next record
queryResponse, err := resultsIterator.Next()
if err != nil {
return shim.Error(err.Error())
}
fmt.Println(queryResponse)
keyArray = append(keyArray, queryResponse.Key)
}
defer resultsIterator.Close()
all_bytes, _ := json.Marshal(keyArray)
fmt.Println(keyArray)
return shim.Success(all_bytes)
}
But, why I get the above error when trying to add the queryResponse into a custom struct?
Do I need to add it to a struct that is only its type?
Please someone can explain what I am missing here?
The error statement is verbose enough to indicate, that your []byte conversion failed for the type queryResponse which, with a bit of lookup seems to be a struct type. In Go you cannot natively convert a struct instance to its constituent bytes without encoding using gob or other means.
Perhaps your intention was to use the Key record in the struct for un-marshalling
json.Unmarshal([]byte(queryResponse.Key), &qry_key_json)

Extra data in buffer error when decoding with gob - golang

I'm decoding with gob several objects fetched from a key/value database called "bitcask".
When I try to decode all of them one by one I get the "extra data in buffer" error from the gob decoder but exclusively for the first element that was added in the database and only after I've already fetched them at least once.
What am I doing wrong?
// Just the nest of all the bugs.
type Nest struct {
buf bytes.Buffer
dec *gob.Decoder
enc *gob.Encoder
db *bitcask.Bitcask
sync.Mutex
}
// Saves the bug into the nest.
func (n *Nest) Put(id int64, b Bug) error {
n.Lock()
defer n.Unlock()
if err := n.enc.Encode(b); err != nil {
return err
}
defer n.buf.Reset()
return n.db.Put(itosl(id), n.buf.Bytes())
}
// Retrieves a bug from the nest.
func (n *Nest) Get(id int64) (Bug, error) {
var bg Bug
b, err := n.db.Get(itosl(id))
if err != nil {
return bg, err
}
n.Lock()
defer n.Unlock()
if _, err = n.buf.Write(b); err != nil {
return bg, err
}
defer n.buf.Reset()
return bg, n.dec.Decode(&bg) // error extra data in buffer
}
Note: the "Get" function get's called for every ID in the database everytime the API endpoint is called.
The structs I'm encoding/decoding are the following:
type Comment struct {
Date int64 `json:"date"`
Text string `json:"text"`
Author string `json:"author"`
}
type Bug struct {
Id int64 `json:"id"`
Body string `json:"body"`
Open bool `json:"open"`
Tags []string `json:"tags"`
Date int64 `json:"date"`
Comments []Comment `json:"comments"`
Author string `json:"author"`
}
Also when I try to use a new decoder and buffer each time the "Get" function gets called (as I've seen in an answer to a similar question) the decode operation results in the following error: gob: unknown type id or corrupted data.
Refer to this link for the complete source code:
https://github.com/NicoNex/ladybug

How to write struct onto ledger state

I am trying to write chaincode for Hyperledger that has a mapping, that stores struct values mapped to strings. This is my first time writing contracts for Hyperledger and also my first time using go and it appears I am not approaching this the right way.
This is my mapping, Data struct, Init function and addVData function that shows the problem.
type Data struct{
Timestamp string
Velocity string
Location string
}
var all_data map[string]Data
func (t *DataContract) Init(stub shim.ChaincodeStubInterface) peer.Response {
all_data = make(map[string]Data)
return shim.Success(nil)
}
func (t *DataContract) addVData(stub shim.ChaincodeStubInterface, args []string) peer.Response {
params := stub.GetStringArgs()
fmt.Println("The params passed in are:", params)
if len(params) != 4 {
fmt.Println("Please resubmit in this particular order: addVData, Timestamp, Velocity, Location")
return shim.Error("Please resubmit in this particular order: addVData, Timestamp, Velocity, Location")
}
var d = Data{Timestamp:params[1], Velocity:params[2], Location:params[3]}
all_data[params[1]] = d
var err = stub.PutState(params[1],d)
return shim.Success(nil)
}
The error I am getting is actually very clear:
./data.go:79:35: cannot use d (type Data) as type []byte in argument to stub.PutState
I am wondering, since my data is not in form of a byte array, how do I go about storing it?
Also, I am not certain I have implemented the Init method and the mappings in the correct way but have had a hard time finding examples. If you could please explain and point me in the right direction it would be very appreciated, thank you.
Use json.Marshal function to convert the struct into bytes
type UserData struct {
a string
}
userdata := &UserData{a: "hello"}
// Mashelling struct to jsonByte object to put it into the ledger
userDataJSONBytes, err := json.Marshal(&userdata)
if err != nil {
return shim.Error(err.Error())
}
var err = stub.PutState(params[1],userDataJSONBytes)

How do I Override UnmarshalJSON Correctly?

I am trying to write a simple custom marshaler and failing. Notice I have an interface that has three functions. Both Happy and Sad structs implement this interface by embedding the emotion struct which implements all the three required functions.
The problem is UnmarshalJSON does not get invoked when I call json.Unmarshal() on the pointer to either Happy or Sad and I can't understand why. You can reproduce the exact codebase in Go Playground or just look below. You will notice that while MarshalJSON is correctly called, UnmarshalJSON isn't.
type Emotion interface {
String() string
MarshalJSON() ([]byte, error)
UnmarshalJSON(data []byte) error
}
type emotion struct {
status string
}
func (s emotion) String() string {
return s.status
}
func (s emotion) MarshalJSON() ([]byte, error) {
fmt.Println("MarshalJSON is overriden: I am called fine")
x := struct {
Status string
}{
Status: s.String(),
}
return json.Marshal(x)
}
func (s *emotion) UnmarshalJSON(data []byte) error {
fmt.Println("MarshalJSON is overriden: I am never called")
y := struct {
Status string
}{
Status: "",
}
err := json.Unmarshal(data, &y)
if err != nil {
return err
}
s.status = y.Status
return nil
}
type Happy struct {
*emotion
}
// Job is not in any detention
type Sad struct {
*emotion
}
func main() {
x := Happy{&emotion{status: "happy"}}
jsonX, _ := json.Marshal(x)
var y Emotion
err := json.Unmarshal(jsonX, &y)
fmt.Printf("%v", err)
}
You cannot unmarshal into an abstract interface type.
An interface value is just a pointer to a type (associating that types methods) - it has no storage behind it - because an abstract type cannot know the exact size of any concrete value it may have in the future.
Using a concrete value type (that also implements that interface) will work:
y2 := emotion{}
err = json.Unmarshal(jsonX, &y2)
Playground: https://play.golang.org/p/8aCEjLgfKVQ
MarshalJSON is overriden: I am called fine
EXPECTED ERROR, Can't unmarshal into a non-concrete value: json: cannot unmarshal object into Go value of type main.Emotion
MarshalJSON is overriden: I am (fixed) and now called
SHOULD NOT ERROR: <nil>
VALUE: happy

How to change integer to string with go in this case?

Using gorm to connect db. Here get all the records:
func GetPeople(c *gin.Context) {
var people []Person
var count int
find_people := db.Find(&people)
find_people.Count(&count)
if err := find_people.Error; err != nil {
c.AbortWithStatus(404)
fmt.Println(err)
} else {
c.Header("X-Total-Count", &count)
c.JSON(200, people)
}
}
About count, the c.Header("X-Total-Count", &count) can't passed since this error:
cannot use &count (type *int) as type string in argument to c.Header
Have tried strconv.Itoa(&count), got another error:
cannot use &count (type *int) as type int in argument to strconv.Itoa
So how to convert integer to string in this case?
In the c.Header() call pass the value of the variable instead of a pointer.
c.Header("X-Total-Count", strconv.Itoa(count))
For reference, the method signature is:
func (c *Context) Header(key, value string) {

Resources