Hi all,
I am working on a small side project to learn go and I have hit an issue that hours of Googling and trying have made no impact on for me.
I am storing records in mongodb via mgo
, which works fine.
I can pull records from mongo and send JSON perfectly.
However when I try to convert the data from mongo back into concrete types I am "missing" data that implements the "Alert" interface.
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sns"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
type Alert interface {
Send(message string) error
}
type EndPoint struct {
Name string `json:"name" bson:"name"`
URI string `json:"uri" bson:"uri"`
Method string `json:"method" bson:"method"`
IgnoreSSL bool `json:"ignoreSsl" bson:"ignoreSsl"`
CheckInterval string `json:"checkInterval" bson:"checkInterval"`
LastStatus bool `json:"lastStatus" bson:"lastStatus"`
Headers http.Header `json:"headers" bson:"headers"`
Alerts []Alert `json:"alerts" bson:"alerts"`
}
type ConsoleAlert struct {
Type string `json:"type" bson:"type"`
}
func (ca ConsoleAlert) Send(message string) error {
log.Println(message)
return nil
}
type SNSAlert struct {
Type string `json:"type" bson:"type"`
Region string `json:"region" bson:"region"`
Key string `json:"key" bson:"key"`
Secret string `json:"secret" bson:"secret"`
TopicARN string `json:"topic_arn" bson:"topic_arn"`
}
func getSession(sa SNSAlert) (*session.Session, error) {
sess, err := session.NewSession(&aws.Config{
Region: aws.String(sa.Region),
Credentials: credentials.NewStaticCredentials(sa.Key, sa.Secret, ""),
})
if err != nil {
return &session.Session{}, err
}
return sess, nil
}
func (sa SNSAlert) Send(message string) error {
sess, err := getSession(sa)
if err != nil {
return err
}
svc := sns.New(sess)
params := &sns.PublishInput{
Message: aws.String(message),
TopicArn: aws.String(sa.TopicARN),
}
_, err = svc.Publish(params)
if err != nil {
return err
}
return nil
}
func main() {
session, err := mgo.Dial("localhost")
if err != nil {
panic(err)
}
defer session.Close()
DB := session.DB("mogon")
COL := DB.C("serverstest")
var bsonEPs []bson.M
err = COL.Find(bson.M{}).All(&bsonEPs)
if err != nil {
fmt.Println(err)
}
jsonResp, merr := json.Marshal(bsonEPs)
if merr != nil {
fmt.Println(err)
}
// We can get the data just fine as JSON
fmt.Printf("\nJSON DATA\n")
fmt.Println(string(jsonResp))
var endpoints []interface{}
json.Unmarshal(jsonResp, &endpoints)
fmt.Printf("\nSTRUCT DATA\n")
fmt.Println(endpoints)
// mgo can't Find into a slice of EndPoints
var bsonEPsAttempt = make([]EndPoint, 10)
err = COL.Find(bson.M{}).All(&bsonEPsAttempt)
if err != nil {
fmt.Println(err)
}
fmt.Println(bsonEPsAttempt)
}
Below is the console output when trying to get EndPoints
JSON DATA
[{"_id":"5a0e42ab26d6291543f2128b","alerts":[{"type":"console"},{"key":"AWS KEY","region":"us-east-1","secret":"AWS SECRET","topic_arn":"arn:aws:sns:us-east-1:424242:alert","type":"sns"}],"checkInterval":"14s","headers":{"authKey":["password"]},"ignoreSsl":false,"lastStatus":false,"method":"GET","name":"myserver","uri":"https://myapp.com/check"}]
STRUCT DATA
[map[alerts:[map[type:console] map[key:AWS KEY region:us-east-1 secret:AWS SECRET topic_arn:arn:aws:sns:us-east-1:424242:alert type:sns]] headers:map[authKey:[password]] lastStatus:false method:GET uri:https://myapp.com/check _id:5a0e42ab26d6291543f2128b checkInterval:14s ignoreSsl:false name:myserver]]
[]EndPoint FAIL
reflect.Set: value of type bson.M is not assignable to type alerts.Alert
[]
How can I reliably create an EndPoint?
评论:
Kraigius:
xandout:Umm..you didn't post the struct for alerts.Alert and can you post a minimal repro case?
Kraigius:I have edited the code above,
alerts.Alert
is nowAlert
xandout:Thanks. I admit that I didn't try your code but I have a better understanding of it now. I found one thread on stackoverflow that seems to suggest that it's not possible without a workaround but I'll keep looking.
https://stackoverflow.com/questions/26039580/how-to-use-interface-type-as-a-model-in-mgo-go
edit: related?
Ended up with a less than elegant solution involving a switch and json marshalling.
Thanks for the tips
