Golang Channel Streams - rest

I am relatively new to Golang and don't fully understand streams. I have a function (circuit breaker function) that is making Rest calls. I have it working but it is only streaming the "responseBody" back. I would actually like to stream back the entire request of stream back both the Body and the Header together.
When I try to use a similar approach on the "header" then I get an error that the header is not streamable.
Is there a good/best way to accomplish this? Thank you. Below is my function.
func CallWithRetries(req *http.Request, output chan []byte) error {
r := retrier.New(retrier.ConstantBackoff(RETRIES, 100 * time.Millisecond), nil)
attempt := 0
err := r.Run(func() error {
attempt++
resp, err := Client.Do(req)
if err == nil && resp.StatusCode < 299 {
responseBody, err := ioutil.ReadAll(resp.Body)
if err == nil {
output <- responseBody
return err
}
return err
} else if err == nil {
customLogger.LogDebug("Status code was: " , transactionId)
err = fmt.Errorf("Status was %v", resp.StatusCode)
}
return err
})
return err
}

You are looking for the httputil.DumpResponse function.
The code might be changed to something similar to
func CallWithRetries(req *http.Request, output chan []byte) error {
r := retrier.New(retrier.ConstantBackoff(RETRIES, 100*time.Millisecond), nil)
attempt := 0
err := r.Run(func() error {
attempt++
resp, err := Client.Do(req)
if err == nil && resp.StatusCode < 299 {
dump, err := httputil.DumpResponse(resp, true)
if err == nil {
output <- dump
return err
}
return err
} else if err == nil {
customLogger.LogDebug("Status code was: ", transactionId)
err = fmt.Errorf("Status was %v", resp.StatusCode)
}
return err
})
return err
}
Side notes,
you might want to consider to close the response body as mentioned in the documentation https://golang.org/pkg/net/http/#Client.Get
Looks likes the err variable is shadowed, this should be modified to avoid any surprises.
This version of the code attempts to return errors early, and to close the response body. It was not tested, only written on the fly, to use with care.
func CallWithRetries(req *http.Request, output chan []byte) error {
r := retrier.New(retrier.ConstantBackoff(RETRIES, 100*time.Millisecond), nil)
attempt := 0
return r.Run(func() error {
attempt++
var resp *http.Response
{
r, err := Client.Do(req)
if err != nil {
return err
}
defer r.Body.Close()
if resp.StatusCode > 299 {
customLogger.LogDebug("Status code was: ", transactionId)
return fmt.Errorf("Status was %v", resp.StatusCode)
}
resp = r
}
var out []byte
{
x, err := httputil.DumpResponse(resp, true)
if err != nil {
return err
}
out = x
}
output <- out
return nil
})
}

Related

Receiving error(*errors.errorString) *{s: "pq: unexpected DataRow in simple query execution"}

The error
(*errors.errorString) *{s: "pq: unexpected DataRow in simple query execution"}
appears after the line with the commentary. Didn't find any solution online. Since stackoverflow asks for more details, this is an update query that is supposed to update a todo and a list of subtasks in the database. The exact error is in the question topic. I post the complete code for the function that returns the error.
func (t *TodoTable) UpdateTodo(ctx context.Context, todo *Todo, t_id int) error {
tx, err := t.sqlxdb.BeginTxx(ctx, &sql.TxOptions{})
if err != nil {
return err
}
rollback_err := func(err error) error {
if err2 := tx.Rollback(); err2 != nil {
return fmt.Errorf("%v; %v", err, err2)
}
return err
}
row := tx.QueryRowxContext(ctx, "UPDATE todos SET todo_name=$1, deadline=$2, updated_at=$3 WHERE todo_id=$4 returning todo_id", todo.TodoName, todo.Deadline, todo.UpdatedAt, t_id)
if row.Err() != nil {
return rollback_err(err)
}
var subs_ids []int
// Getting subs ids from database
query := fmt.Sprintf("SELECT sub_id FROM subs WHERE todo_id=%d", t_id)
// THE ERROR COMES AFTER EXECUTING THE LINE BELOW
rows, err := tx.Query(query)
if err != nil {
rollback_err(err)
}
if rows != nil {
for rows.Next() {
var sub_id int
err = rows.Scan(&sub_id)
if err != nil {
rollback_err(err)
}
subs_ids = append(subs_ids, sub_id)
}
if err := tx.Commit(); err != nil {
return rollback_err(err)
}
}
// Updating subs
for i, sub := range todo.Subs {
_, err = tx.ExecContext(ctx, fmt.Sprintf("UPDATE subs SET sub_name='%s' WHERE sub_id=%d", sub.Sub_name, subs_ids[i]))
if err != nil {
return rollback_err(err)
}
}
return nil
}

session was not created by this client - MongoDB, Golang

I am trying to creat transaction in MongoDB with Golang and Iris. Problem is that transaction did not accept iris context and Con, I don't know why this thing happened. Can you tell me what I am doing wrong here?
Main.go Using Iris
func main() {
app := iris.New()
app.Logger().SetLevel("debug")
app.Use(recover.New())
app.Use(logger.New())
// Resource: http://localhost:8080
app.Get("/", func(ctx iris.Context) {
ctx.JSON(iris.Map{"message": "Welcome to Woft Bank"})
})
// API endpoints
router.SetRoute(app)
app.Listen(PORT)}
Router
func SetRoute(app *iris.Application) {
userRoute := app.Party("/user")
{
userRoute.Post("/register", middleware.UserValidator, controller.CreateUser)
userRoute.Get("/detail", middleware.UserValidator, controller.GetUserBalanceWithUserID)
userRoute.Patch("/transfer", middleware.TransferValidator, controller.Transfer)
}}
Transacion function (session was not created by this client)
func Transfer(ctx iris.Context) {
senderID := ctx.URLParam("from")
receiverID := ctx.URLParam("to")
amount, _ := strconv.ParseInt(ctx.URLParam("amount"), 10, 64)
session, err := Config.DB().StartSession()
if err != nil {
handleErr(ctx, err)
return
}
defer session.EndSession(ctx)
callback := func(sessCtx mongo.SessionContext) (interface{}, error) {
upsert := false
after := options.After
opt := options.FindOneAndUpdateOptions{
ReturnDocument: &after,
Upsert: &upsert,
}
sender := Models.User{}
filter := bson.M{"username": senderID}
update := bson.M{"$inc": bson.M{"balance": -amount}}
//FindOneAndUpdate did not accept sessCtx
err := UserCollection.FindOneAndUpdate(sessCtx, filter, update, &opt).Decode(&sender)
if err != nil {
return nil, err
}
if sender.Balance < 0 {
return nil, errors.New("sender's balance is not enough")
}
filter = bson.M{"username": receiverID}
update = bson.M{"$inc": bson.M{"balance": +amount}}
_, err = UserCollection.UpdateOne(sessCtx, filter, update)
if err != nil {
return nil, err
}
return sender, nil
}
result, err := session.WithTransaction(ctx, callback)
if err != nil {
handleErr(ctx, err)
return
}
response(result, "success", ctx)}

Is there a way with GRPC to notify the stream of CRUD operations to give realtime updates to the client?

I am new to GRPC and I am trying to implement a basic CRUD + listing. I use unary rpc's for the CRUD and a server stream for the listing. What I would like to do however is update the client whenever someone changes a record in the database that you are listing.
So for example user A is listing 10 companies. And user B is updating one of those companies. I want user A's client to be updated once the update rpc is called.
This is what I have for now
func RegisterCompanyServer(l hclog.Logger, gs *grpc.Server) {
r := postgres.NewPostgresCompanyRepository()
cs := NewCompanyServer(l, r)
pb.RegisterCompanyServiceServer(gs, cs)
}
type CompanyServer struct {
logger hclog.Logger
repo repo.CompanyRepository
pb.UnimplementedCompanyServiceServer
}
func NewCompanyServer(l hclog.Logger, r repo.CompanyRepository) *CompanyServer {
return &CompanyServer{
logger: l,
repo: r,
}
}
func (c *CompanyServer) ListCompany(req *pb.CompanyListRequest, stream pb.CompanyService_ListCompanyServer) error {
//Somehow listen to CreateCompany() and update the client
companies, err := c.repo.List(req.Query)
if err != nil {
return err
}
for _, c := range companies {
bytes, err := json.Marshal(c)
if err != nil {
return err
}
out := &pb.Company{}
if err = jsonEnc.Unmarshal(bytes, out); err != nil {
return err
}
res := &pb.CompanyListResponse{
Company: out,
}
err = stream.Send(res)
if err != nil {
return err
}
}
return nil
}
func (c *CompanyServer) CreateCompany(context context.Context, req *pb.CompanyCreateRequest) (*pb.CompanyCreateResponse, error) {
input := req.GetCompany()
if input == nil {
return nil, errors.New("Parsing Error")
}
bytes, err := jsonEnc.Marshal(input)
if err != nil {
return nil, err
}
company := &myCompany.Company{}
if err = json.Unmarshal(bytes, company); err != nil {
return nil, err
}
result, err := c.repo.Create(company)
if err != nil {
return nil, err
}
res := &pb.CompanyCreateResponse{
Id: result,
}
//Somehow notify the stream that a company was created
return res, nil
}
Is this even feasable with GRPC? What techniques are out there to do this? I am currently working with a postgresql database.

golang net/smtp getting smtp server response DSN

I am using golang net/smtp to send mails
Whenever I send to my smtp server I need to capture the response from the server
Especially the DSN
For example my local smtp server gives a "ok queued as " at the end of the mail
I need to capture this and print in the logs
How can I do this
package main
import (
"log"
"net/smtp"
)
func sendEmail(msg []byte) {
c, err := smtp.Dial("localhost:25")
if err != nil {
log.Fatal(err)
}
if err := c.Mail("sender#example.org"); err != nil {
log.Fatal(err)
}
if err := c.Rcpt("recipient#example.net"); err != nil {
log.Fatal(err)
}
wc, err := c.Data()
if err != nil {
log.Fatal(err)
}
_, err = wc.Write(msg)
if err != nil {
log.Fatal(err)
}
//How do I get the response here ??
err = wc.Close()
if err != nil {
log.Fatal(err)
}
err = c.Quit()
if err != nil {
log.Fatal(err)
}
}
As mentioned in the comments you can use c.Text.ReadResponse():
package main
import (
"net/smtp"
)
func sendEmail(msg []byte) (code int, message string, err error) {
c, err := smtp.Dial("localhost:25")
if err != nil {
return
}
defer c.Quit() // make sure to quit the Client
if err = c.Mail("sender#example.org"); err != nil {
return
}
if err = c.Rcpt("recipient#example.net"); err != nil {
return
}
wc, err := c.Data()
if err != nil {
return
}
defer wc.Close() // make sure WriterCloser gets closed
_, err = wc.Write(msg)
if err != nil {
return
}
code, message, err = c.Text.ReadResponse(0)
return
}
The code, message and any err are now passed to the caller, don't use log.Fatal throughout your code, handle the error on the calling side.
package main
import (
"net/smtp"
)
func sendEmail(msg []byte) (code int, message string, err error) {
c, err := smtp.Dial("localhost:25")
if err != nil {
return
}
defer c.Quit() // make sure to quit the Client
if err = c.Mail("sender#example.org"); err != nil {
return
}
if err = c.Rcpt("recipient#example.net"); err != nil {
return
}
wc, err := c.Data()
if err != nil {
return
}
_, err = wc.Write(msg)
if err != nil {
return
}
code, message, err = closeData(c)
if err != nil {
return 0, "", err
}
return code, message, err
}
func closeData(client *smtp.Client) error {
d := &dataCloser{
c: client,
WriteCloser: client.Text.DotWriter(),
}
return d.Close()
}
type dataCloser struct {
c *smtp.Client
io.WriteCloser
}
func (d *dataCloser) Close() (int, string, error) {
d.WriteCloser.Close() // make sure WriterCloser gets closed
code, message, err := d.c.Text.ReadResponse(250)
fmt.Printf("Message %v, Error %v\n", message, err)
return code, message, err
}

How does golang's net.Conn.Read when to stop reading?

I'm trying to write a simple sockets based go server. I'm just wondering how does the connection.Read below knows when to stop reading.
(Note: this is not my code, I copied it from Unix Sockets in Go as example)
package main
import (
"log"
"net"
)
func echoServer(c net.Conn) {
for {
buf := make([]byte, 512)
nr, err := c.Read(buf)
if err != nil {
return
}
data := buf[0:nr]
println("Server got:", string(data))
_, err = c.Write(data)
if err != nil {
log.Fatal("Write: ", err)
}
}
}
func main() {
l, err := net.Listen("unix", "/tmp/echo.sock")
if err != nil {
log.Fatal("listen error:", err)
}
for {
fd, err := l.Accept()
if err != nil {
log.Fatal("accept error:", err)
}
go echoServer(fd)
}
}
Is it the EOF character or there's something else?
It would be really helpful if someone can point me to a link official go docs. Thanks.
This is the implementation of the default Read method on net.Conn.Read:
// Read implements the Conn Read method.
func (c *conn) Read(b []byte) (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
}
n, err := c.fd.Read(b)
if err != nil && err != io.EOF {
err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
}
return n, err
}
This is the implementation of the c.fd.Read(b) that is called within the function above:
func (fd *netFD) Read(p []byte) (n int, err error) {
if err := fd.readLock(); err != nil {
return 0, err
}
defer fd.readUnlock()
if len(p) == 0 {
// If the caller wanted a zero byte read, return immediately
// without trying. (But after acquiring the readLock.) Otherwise
// syscall.Read returns 0, nil and eofError turns that into
// io.EOF.
// TODO(bradfitz): make it wait for readability? (Issue 15735)
return 0, nil
}
if err := fd.pd.prepareRead(); err != nil {
return 0, err
}
if fd.isStream && len(p) > 1<<30 {
p = p[:1<<30]
}
for {
n, err = syscall.Read(fd.sysfd, p)
if err != nil {
n = 0
if err == syscall.EAGAIN {
if err = fd.pd.waitRead(); err == nil {
continue
}
}
}
err = fd.eofError(n, err)
break
}
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("read", err)
}
return
}
So, yes, an EOF will make it stop reading. But so will plenty of other non-nil errors.
It will stop reading when its underlying implementation hits any error.
Error may be an actual I/O error, or it could be the operating system signaling connection closed with io.EOF, or it could be a timeout, so on.