How should I handle the errors when I try to write in DB - http

Not sure how should I deal with errors when I try to write in DB in this particular case:
So I use this func to insert in DB
func SaveToDB(dateid string, content string) {
db, err := sql.Open("mysql", dbLink)
if err != nil {
log.Fatal(err)
}
queryString := fmt.Sprintf("INSERT INTO balances (dateid, content) VALUES('%v','%v');", dateid, content)
rows, err := db.Query(queryString)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
}
But I would like to don't stop the server when error is duplicate so I tried this version:
func SaveToDB(dateid string, content string) {
db, err := sql.Open("mysql", dbLink)
if err != nil {
log.Fatal(err)
}
queryString := fmt.Sprintf("INSERT INTO balances (dateid, content) VALUES('%v','%v');", dateid, content)
rows, err1 := db.Query(queryString)
if err1 != nil {
thisErr, err2 := regexp.MatchString("Error 1062: Duplicate entry", err.Error())
if err2 != nil {
log.Fatal("ERROR: error occured while trying to perform regex on SaveToDB", err2)
}
if thisErr == true {
log.Println("ERROR: Not able to save in DB due to ducplicate: ", err1)
}else{log.Fatal("ERROR: error occured when trying to save to DB: ", err1)}
}
defer rows.Close()
}
But in this situation I receive panic. So how I can stop this function from executing before it reaches "defer rows.Close()"? I guess that is the reason for panic...

Don't use log.Fatal and install deferred code once you have the correct data:
rows, err := db.Query(queryString)
if err != nil {
log.Error(err)
return
}
defer rows.Close()

Related

Getting A Database Locked Error When Using Golang and SQLite

I'm experiencing a database locked error in this piece of code.
The thing is I already wrote pretty similar code to this and I wasn't getting any errors.
But now when I run it, I get a Database Locked Error with the error code 5.
The error occurs on the tx.Commit() statement.
Here's the code itself:
type UserRepository struct {
db *driver.QuestionlyDb
}
/*
Creates a new user sql driver that executes user sql statements on the sql driver.
*/
func CreateUserRepository(db *driver.QuestionlyDb) *UserRepository {
return &UserRepository{db: db}
}
/*
Create a new user row in the database.
*/
func (ur *UserRepository) CreateUser(u *User) error {
tx, err := ur.db.Begin()
if err != nil {
return err
}
stmt, err := tx.Prepare(`INSERT INTO users (id, email, password, username) VALUES (?, ?, ?, ?);`)
if err != nil {
_ = tx.Rollback()
return err
}
defer stmt.Close()
_, err = stmt.Exec(u.GetID(), u.GetEmail(), u.GetPassword(), u.GetUsername())
if err != nil {
tx.Rollback()
return err
}
if err := tx.Commit(); err != nil {
return err
}
return nil
}
The database connection is created in the following way:
type QuestionlyDb struct {
*sql.DB
}
/*
Creates a new database connection.
*/
func CreateDatabase() (*QuestionlyDb, error) {
db, err := connectToDb()
if err != nil {
return nil, err
}
sqlDb := &QuestionlyDb{db}
return sqlDb, nil
}
// TODO: Set db name as env variable
func connectToDb() (*sql.DB, error) {
db, err := sql.Open("sqlite3", "./questionly.db")
if err != nil {
return nil, err
}
return db, err
}

multipart writer CreateFormFile stuck

trying to post multipart/form-data image using go
image file receive from request client and already saved as multipart.File
here my code
func postImage(file multipart.File, url string, filename string) (*http.Response, error) {
r, w := io.Pipe()
defer w.Close()
m := multipart.NewWriter(w)
defer m.Close()
errchan := make(chan error)
defer close(errchan)
go func() {
part, err := m.CreateFormFile("file", filename)
log.Println(err)
if err != nil {
errchan <- err
return
}
if _, err := io.Copy(part, file); err != nil {
errchan <- err
return
}
}()
merr := <-errchan
if merr != nil {
return nil, merr
}
resp, err := http.Post(url, m.FormDataContentType(), r)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return resp, err
}
when i try using it, it stuck at part, err := m.CreateFormFile("file", filename) never return anything
any solution?
Thanks
Use the pipe error to propagate the error back to the main goroutine. Close the write side of the pipe to prevent the client from blocking forever on read. Close the read side of the pipe to ensure that the goroutine exits.
func postImage(file multipart.File, url string, filename string) (*http.Response, error) {
r, w := io.Pipe()
// Close the read side of the pipe to ensure that
// the goroutine exits in the case where http.Post
// does not read all of the request body.
defer r.Close()
m := multipart.NewWriter(w)
go func() {
part, err := m.CreateFormFile("file", filename)
if err != nil {
// The error is returned from read on the pipe.
w.CloseWithError(err)
return
}
if _, err := io.Copy(part, file); err != nil {
// The error is returned from read on the pipe.
w.CloseWithError(err)
return
}
// The http.Post function reads the pipe until
// an error or EOF. Close to return an EOF to
// http.Post.
w.Close()
}()
resp, err := http.Post(url, m.FormDataContentType(), r)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return resp, err
}

request.FormValue is empty in the 'net/http' in Go

I'm trying to create a simple http service with the endpoint to download file to the local system in Go. The link comes in ?uri tag, but when I want to get it I receive an empty string. I tried to parse the form of my request but it didn't help. Here is my code:
func main() {
http.HandleFunc("/download", DownloadHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func DownloadHandler(writer http.ResponseWriter, request *http.Request) {
prsErr := request.ParseForm()
if prsErr != nil{
panic(prsErr)
}
uri := request.FormValue("?uri")
_, _ = writer.Write([]byte(uri))
err := DownloadFile("img.png", uri)
if err != nil {
panic(err)
}
}
func DownloadFile(filepath string, url string) error {
// Create the file
out, err := os.Create(filepath)
if err != nil {
return err
}
defer out.Close()
// Get the data
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
// Write the body to file
_, err = io.Copy(out, resp.Body)
if err != nil {
return err
}
return nil
}
I will appreciate any help! Thank you!
invalid at request.FormValue("?uri")
uri := request.FormValue("uri")

Stream HAR events

I have a long running app that I'd like to monitor in real time. HAR files allow me to do this after the fact, but as they are an "archive", they don't allow me to do this in real time.
Is their anyway to stream the "events" array of the HAR file so I can process them as they are generated?
This can be firefox or chrome.
So with some help from https://github.com/mafredri/cdp/tree/master/example/screencast I figured out how to do this in go with chrome's debugger api
What this code doesn't do is tie the request body to the response (where it isn't available), but as I show the RequestID will be consistent so if one serializes event processing (say via locking) one can save the body and use it when the response event is seen.
package main
import (
"context"
"log"
"github.com/mafredri/cdp"
"github.com/mafredri/cdp/cdpcmd"
"github.com/mafredri/cdp/devtool"
"github.com/mafredri/cdp/rpcc"
)
func main() {
if err := run(); err != nil {
panic(err)
}
}
func run() error {
ctx, cancel := context.WithCancel(context.TODO())
defer cancel()
devt := devtool.New("http://localhost:9222")
page, err := devt.Get(ctx, devtool.Page)
if err != nil {
return err
}
conn, err := rpcc.DialContext(ctx, page.WebSocketDebuggerURL)
if err != nil {
return err
}
defer conn.Close()
c := cdp.NewClient(conn)
err = c.Page.Enable(ctx)
if err != nil {
return err
}
loadEventFired, err := c.Page.LoadEventFired(ctx)
if err != nil {
return err
}
_, err = c.Page.Navigate(ctx, cdpcmd.NewPageNavigateArgs("https://github.com/"))
if err != nil {
return err
}
_, err = loadEventFired.Recv()
if err != nil {
return err
}
loadEventFired.Close()
a := &cdpcmd.NetworkEnableArgs{}
a.SetMaxResourceBufferSize(32000)
a.SetMaxTotalBufferSize(96000)
err = c.Network.Enable(ctx, a)
responseEvents, err := c.Network.ResponseReceived(ctx)
requestEvents, err := c.Network.RequestWillBeSent(ctx)
go func() {
defer responseEvents.Close()
for {
ev, err := responseEvents.Recv()
if err != nil {
log.Printf("Failed to receive network event: %v", err)
return
}
log.Printf("requestid = %v, url = %v", ev.RequestID, ev.Response.URL)
}
}()
go func() {
defer requestEvents.Close()
for {
ev, err := requestEvents.Recv()
if err != nil {
log.Printf("Failed to receive network event: %v", err)
return
}
log.Printf("requestid = %v, url = %v", ev.RequestID, ev.Request.URL)
}
}()
select {}
return nil
}

Reading content from http.Get in Golang

I'm having a tough time reading XML from a GET request in Go. I just started to learn Go and haven't found any resources on this topic. What I tried:
response, err := http.Get(url)
if err != nil {
log.Fatal(err)
} else {
defer response.Body.Close()
xml, _ := ioutil.ReadAll(response.Body)
if err != nil {
log.Fatal(err)
}
}
_, err := io.Copy(os.Stdout, response.Body) works but I'd like to store the XML for further processing.
Any help is greatly appreciated.
What you've tried is mostly good. Few things to improve it:
http.Get() returns an http.Response and an optional error. If there is no error, that only means that the HTTP GET operation succeeded, but the server might have responded with an error document. So you still have to check the response HTTP status code.
Also io.ReadAll() also returns an error (besides the read data), don't forget to check that too.
Let's wrap it in a function:
func getXML(url string) (string, error) {
resp, err := http.Get(url)
if err != nil {
return "", fmt.Errorf("GET error: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("Status error: %v", resp.StatusCode)
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("Read body: %v", err)
}
return string(data), nil
}
Testing / using the above function:
if xmlStr, err := getXML("http://somehost.com/some.xml"); err != nil {
log.Printf("Failed to get XML: %v", err)
} else {
log.Println("Received XML:")
log.Println(xmlStr)
}
Also note that it would be the same to get the content of any other responses, so it's worth not "encoding" the string conversion and return type. This one is more general:
func getContent(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return nil, fmt.Errorf("GET error: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("Status error: %v", resp.StatusCode)
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("Read body: %v", err)
}
return data, nil
}
Using this to get an XML doc:
if data, err := getContent("http://somehost.com/some.xml"); err != nil {
log.Printf("Failed to get XML: %v", err)
} else {
log.Println("Received XML:")
log.Println(string(data))
}

Resources