From d33cf1f6738a3c3771247dd29e764c296b806f4c Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Tue, 15 Dec 2015 19:47:22 +0100 Subject: improved error handling and overall resilience to different situations diff --git a/src/helsinki.at/rhimport/fetcher.go b/src/helsinki.at/rhimport/fetcher.go index ae7c910..38e1d7f 100644 --- a/src/helsinki.at/rhimport/fetcher.go +++ b/src/helsinki.at/rhimport/fetcher.go @@ -134,6 +134,8 @@ func FetchFileCurl(ctx *ImportContext, uri *url.URL) (err error) { // still: let's make a special configurable directory the local:/// dir // and only allow absolute paths here which will be based on the // 'local' directory +// TODO: also check if file exists and is accessable!!! otherwise curl will blow up +// with a not-easy-to-understand error func FetchFileLocal(ctx *ImportContext, uri *url.URL) (err error) { rhl.Printf("Local fetcher called for '%s'", ctx.SourceUri) if ctx.ProgressCallBack != nil { diff --git a/src/helsinki.at/rhimport/importer.go b/src/helsinki.at/rhimport/importer.go index aa5343d..94065f6 100644 --- a/src/helsinki.at/rhimport/importer.go +++ b/src/helsinki.at/rhimport/importer.go @@ -49,6 +49,7 @@ type ImportContext struct { ClearShowCarts bool GroupName string Cart uint + ClearCart bool Cut uint Channels uint NormalizationLevel int @@ -73,6 +74,7 @@ func NewImportContext(conf *Config, rddb *RdDb, user string) *ImportContext { ctx.ClearShowCarts = false ctx.GroupName = "" ctx.Cart = 0 + ctx.ClearCart = false ctx.Cut = 0 ctx.Channels = conf.ImportParamDefaults.Channels ctx.NormalizationLevel = conf.ImportParamDefaults.NormalizationLevel @@ -210,6 +212,14 @@ func (self *ImportResult) fromRDWebResult(rdres *RDWebResult) { } func add_cart(ctx *ImportContext, res *ImportResult) (err error) { + rhdl.Printf("importer: add_cart() called for cart: %d", ctx.Cart) + + if ctx.GroupName == "" { + if err = ctx.getGroupOfCart(); err != nil { + return + } + } + var b bytes.Buffer w := multipart.NewWriter(&b) @@ -247,6 +257,7 @@ func add_cart(ctx *ImportContext, res *ImportResult) (err error) { return } res.fromRDWebResult(rdres) + res.Cart = ctx.Cart return } var cartadd *RDCartAdd @@ -261,6 +272,7 @@ func add_cart(ctx *ImportContext, res *ImportResult) (err error) { } func add_cut(ctx *ImportContext, res *ImportResult) (err error) { + rhdl.Printf("importer: add_cut() called for cart/cut: %d/%d", ctx.Cart, ctx.Cut) var b bytes.Buffer w := multipart.NewWriter(&b) @@ -290,6 +302,8 @@ func add_cut(ctx *ImportContext, res *ImportResult) (err error) { return } res.fromRDWebResult(rdres) + res.Cart = ctx.Cart + res.Cut = ctx.Cut return } var cutadd *RDCutAdd @@ -298,12 +312,14 @@ func add_cut(ctx *ImportContext, res *ImportResult) (err error) { } res.ResponseCode = resp.StatusCode res.ErrorString = "OK" + res.Cart = ctx.Cart res.Cut = cutadd.Cuts[0].Number ctx.Cut = cutadd.Cuts[0].Number return } func remove_cart(ctx *ImportContext, res *ImportResult) (err error) { + rhdl.Printf("importer: remove_cart() called for cart: %d", ctx.Cart) var b bytes.Buffer w := multipart.NewWriter(&b) @@ -332,10 +348,49 @@ func remove_cart(ctx *ImportContext, res *ImportResult) (err error) { return } res.fromRDWebResult(rdres) + res.Cart = ctx.Cart + return +} + +func remove_cut(ctx *ImportContext, res *ImportResult) (err error) { + rhdl.Printf("importer: remove_cut() called for cart/cut: %d/%d", ctx.Cart, ctx.Cut) + var b bytes.Buffer + w := multipart.NewWriter(&b) + + if err = w.WriteField("COMMAND", "11"); err != nil { + return + } + if err = w.WriteField("LOGIN_NAME", ctx.UserName); err != nil { + return + } + if err = w.WriteField("PASSWORD", ctx.Password); err != nil { + return + } + if err = w.WriteField("CART_NUMBER", fmt.Sprintf("%d", ctx.Cart)); err != nil { + return + } + if err = w.WriteField("CUT_NUMBER", fmt.Sprintf("%d", ctx.Cut)); err != nil { + return + } + w.Close() + + var resp *http.Response + if resp, err = send_post_request(ctx.Config.RDXportEndpoint, &b, w.FormDataContentType()); err != nil { + return + } + defer resp.Body.Close() + + var rdres *RDWebResult + if rdres, err = NewRDWebResultFromXML(resp.Body); err != nil { + return + } + res.fromRDWebResult(rdres) + res.Cart = ctx.Cart + res.Cut = ctx.Cut return } -func send_post_request(url string, b *bytes.Buffer, contenttype string) (res *http.Response, err error) { +func send_post_request(url string, b *bytes.Buffer, contenttype string) (resp *http.Response, err error) { var req *http.Request if req, err = http.NewRequest("POST", url, b); err != nil { return @@ -345,7 +400,7 @@ func send_post_request(url string, b *bytes.Buffer, contenttype string) (res *ht } client := &http.Client{} - if res, err = client.Do(req); err != nil { + if resp, err = client.Do(req); err != nil { return } return @@ -388,7 +443,8 @@ func import_audio_create_request(ctx *ImportContext, easy *curl.CURL) (form *cur return } -func import_audio(ctx *ImportContext, result *ImportResult) (err error) { +func import_audio(ctx *ImportContext, res *ImportResult) (err error) { + rhdl.Printf("importer: import_audio() called for cart/cut: %d/%d", ctx.Cart, ctx.Cut) easy := curl.EasyInit() if easy != nil { @@ -431,8 +487,9 @@ func import_audio(ctx *ImportContext, result *ImportResult) (err error) { if rdres, err = NewRDWebResultFromXML(bufio.NewReader(&resbody)); err != nil { return } - result.fromRDWebResult(rdres) - return + res.fromRDWebResult(rdres) + res.Cart = ctx.Cart + res.Cut = ctx.Cut } else { err = fmt.Errorf("Error initializing libcurl") } @@ -440,14 +497,21 @@ func import_audio(ctx *ImportContext, result *ImportResult) (err error) { return } -func remove_add_cart_cut(ctx *ImportContext, res *ImportResult) (err error) { - if err = remove_cart(ctx, res); err != nil || (res.ResponseCode != http.StatusOK && res.ResponseCode != http.StatusNotFound) { +func add_cart_cut(ctx *ImportContext, res *ImportResult) (err error) { + if err = add_cart(ctx, res); err != nil || res.ResponseCode != http.StatusOK { return } - if err = add_cart(ctx, res); err != nil || res.ResponseCode != http.StatusOK { + if err = add_cut(ctx, res); err != nil || res.ResponseCode != http.StatusOK { + return remove_cart(ctx, &ImportResult{ResponseCode: http.StatusOK}) + } + return +} + +func remove_add_cart_cut(ctx *ImportContext, res *ImportResult) (err error) { + if err = remove_cart(ctx, res); err != nil || (res.ResponseCode != http.StatusOK && res.ResponseCode != http.StatusNotFound) { return } - return add_cut(ctx, res) + return add_cart_cut(ctx, res) } func is_cart_member_of_show(ctx *ImportContext, res *ImportResult, carts []uint) (found bool) { @@ -484,7 +548,10 @@ func add_show_cart_cut(ctx *ImportContext, res *ImportResult, carts []uint) (err } for _, cart := range carts { if cart == ctx.Cart { - return add_cut(ctx, res) + if err = add_cut(ctx, res); err != nil || res.ResponseCode != http.StatusOK { + return remove_cart(ctx, &ImportResult{ResponseCode: http.StatusOK}) + } + return } } if err = remove_cart(ctx, res); err != nil || res.ResponseCode != http.StatusOK { @@ -516,6 +583,8 @@ func cleanup_files(ctx *ImportContext) { func ImportFile(ctx *ImportContext) (res *ImportResult, err error) { defer cleanup_files(ctx) + rhdl.Printf("importer: ImportFile called with: show-id: %d, pool-name: '%s', cart/cut: %d/%d", ctx.ShowId, ctx.GroupName, ctx.Cart, ctx.Cut) + if ctx.ProgressCallBack != nil { ctx.ProgressCallBack(2, "importing", 0.0, ctx.ProgressCallBackData) } @@ -526,6 +595,8 @@ func ImportFile(ctx *ImportContext) (res *ImportResult, err error) { } } + rmCartOnErr := false + rmCutOnErr := false res = &ImportResult{ResponseCode: http.StatusOK} if ctx.ShowId != 0 { var show_carts []uint @@ -541,6 +612,7 @@ func ImportFile(ctx *ImportContext) (res *ImportResult, err error) { if err = add_show_cart_cut(ctx, res, show_carts); err != nil || res.ResponseCode != http.StatusOK { return } + rmCartOnErr = true } else if ctx.GroupName != "" { if err = ctx.getMusicInfo(); err != nil { return @@ -548,12 +620,25 @@ func ImportFile(ctx *ImportContext) (res *ImportResult, err error) { if err = remove_add_cart_cut(ctx, res); err != nil || res.ResponseCode != http.StatusOK { return } - } else if ctx.Cart != 0 && ctx.Cut == 0 { // TODO: we should add a DeleteCart option... - if err = ctx.getGroupOfCart(); err != nil { - return - } - if err = remove_add_cart_cut(ctx, res); err != nil || res.ResponseCode != http.StatusOK { - return + rmCartOnErr = true + } else if ctx.Cart != 0 && ctx.Cut == 0 { + if ctx.ClearCart { + if err = remove_add_cart_cut(ctx, res); err != nil || res.ResponseCode != http.StatusOK { + return + } + rmCartOnErr = true + } else { + if err = add_cut(ctx, res); err != nil { + return + } + if res.ResponseCode != http.StatusOK { + if err = add_cart_cut(ctx, res); err != nil || res.ResponseCode != http.StatusOK { + return + } + rmCartOnErr = true + } else { + rmCutOnErr = true + } } } @@ -561,13 +646,22 @@ func ImportFile(ctx *ImportContext) (res *ImportResult, err error) { if err = import_audio(ctx, res); err != nil { return } - res.Cart = ctx.Cart - res.Cut = ctx.Cut + if res.ResponseCode != http.StatusOK { + rmres := ImportResult{ResponseCode: http.StatusOK} + if rmCartOnErr { + if err = remove_cart(ctx, &rmres); err != nil { + return + } + } else if rmCutOnErr { + if err = remove_cut(ctx, &rmres); err != nil { + return + } + } + } } else { res.ResponseCode = http.StatusBadRequest res.ErrorString = "The request doesn't contain enough information to be processed" } - rhdl.Printf("ImportResult: %+v\n", res) return } diff --git a/src/helsinki.at/rhimport/rddb.go b/src/helsinki.at/rhimport/rddb.go index 34019e8..28fa6bd 100644 --- a/src/helsinki.at/rhimport/rddb.go +++ b/src/helsinki.at/rhimport/rddb.go @@ -33,7 +33,7 @@ import ( ) var ( - showMacroRe = regexp.MustCompile(`^LL 1 ([^ ]+) 0\!$`) + showMacroRe = regexp.MustCompile(`^LL 1 ([^ ]+) 0\!$`) mysqlTableNameRe = regexp.MustCompile(`^[_0-9a-zA-Z-]+$`) ) diff --git a/src/helsinki.at/rhimportd/ctrlWeb.go b/src/helsinki.at/rhimportd/ctrlWeb.go index 6475a96..0341a95 100644 --- a/src/helsinki.at/rhimportd/ctrlWeb.go +++ b/src/helsinki.at/rhimportd/ctrlWeb.go @@ -46,5 +46,5 @@ func StartControlWeb(addr_s string, conf *rhimport.Config, rddb *rhimport.RdDb) http.Handle("/trusted/simple", webHandler{conf, rddb, true, webSimpleHandler}) rhl.Println("listening on", addr_s) - http.ListenAndServe(addr_s, nil) + http.ListenAndServe(addr_s, nil) // TODO: reader.Timeout, writer.Timeout??? } diff --git a/src/helsinki.at/rhimportd/ctrlWebSimple.go b/src/helsinki.at/rhimportd/ctrlWebSimple.go index 41e4f81..2de324f 100644 --- a/src/helsinki.at/rhimportd/ctrlWebSimple.go +++ b/src/helsinki.at/rhimportd/ctrlWebSimple.go @@ -40,6 +40,7 @@ type webSimpleRequestData struct { ClearShowCarts bool `json:"CLEAR_SHOW_CARTS"` MusicPoolGroup string `json:"MUSIC_POOL_GROUP"` Cart uint `json:"CART_NUMBER"` + ClearCart bool `json:"CLEAR_CART"` Cut uint `json:"CUT_NUMBER"` Channels uint `json:"CHANNELS"` NormalizationLevel int `json:"NORMALIZATION_LEVEL"` @@ -56,6 +57,7 @@ func newWebSimpleRequestData(conf *rhimport.Config) *webSimpleRequestData { rd.ClearShowCarts = false rd.MusicPoolGroup = "" rd.Cart = 0 + rd.ClearCart = false rd.Cut = 0 rd.Channels = conf.ImportParamDefaults.Channels rd.NormalizationLevel = conf.ImportParamDefaults.NormalizationLevel @@ -113,6 +115,7 @@ func webSimpleParseRequest(conf *rhimport.Config, rddb *rhimport.RdDb, trusted b ctx.ClearShowCarts = reqdata.ClearShowCarts ctx.GroupName = reqdata.MusicPoolGroup ctx.Cart = reqdata.Cart + ctx.ClearCart = reqdata.ClearCart ctx.Cut = reqdata.Cut ctx.Channels = reqdata.Channels ctx.NormalizationLevel = reqdata.NormalizationLevel diff --git a/src/helsinki.at/rhimportd/main.go b/src/helsinki.at/rhimportd/main.go index 5184870..1b9e5e0 100644 --- a/src/helsinki.at/rhimportd/main.go +++ b/src/helsinki.at/rhimportd/main.go @@ -26,12 +26,13 @@ package main import ( "flag" - "helsinki.at/rhimport" "log" "os" "os/signal" "sync" - // "io/ioutil" + + "helsinki.at/rhimport" + // "io/ioutil" ) var ( diff --git a/test/simple-show2.json b/test/simple-show2.json new file mode 100644 index 0000000..33f1d72 --- /dev/null +++ b/test/simple-show2.json @@ -0,0 +1,7 @@ +{ + "LOGIN_NAME": "heslinki", + "PASSWORD": "123456", + "SHOW_ID": 10002, + "CLEAR_SHOW_CARTS": true, + "SOURCE_URI": "local:///home/equinox/helsinki/rivenhell/contrib/rhimportd/test/silence1s.wav" +} diff --git a/test/simple-show2a.json b/test/simple-show2a.json new file mode 100644 index 0000000..280745e --- /dev/null +++ b/test/simple-show2a.json @@ -0,0 +1,6 @@ +{ + "LOGIN_NAME": "heslinki", + "PASSWORD": "123456", + "SHOW_ID": 10002, + "SOURCE_URI": "http://www.tonycuffe.com/mp3/tail%20toddle.mp3" +} diff --git a/test/simple1.json b/test/simple1.json index 84748ec..582e2f5 100644 --- a/test/simple1.json +++ b/test/simple1.json @@ -2,6 +2,7 @@ "LOGIN_NAME": "heslinki", "PASSWORD": "123456", "CART_NUMBER": 100000, + "CLEAR_CART": true, "CHANNELS": 2, "NORMALIZATION_LEVEL": -12, "AUTOTRIM_LEVEL": 0, diff --git a/test/simple1a.json b/test/simple1a.json new file mode 100644 index 0000000..84748ec --- /dev/null +++ b/test/simple1a.json @@ -0,0 +1,10 @@ +{ + "LOGIN_NAME": "heslinki", + "PASSWORD": "123456", + "CART_NUMBER": 100000, + "CHANNELS": 2, + "NORMALIZATION_LEVEL": -12, + "AUTOTRIM_LEVEL": 0, + "USE_METADATA": true, + "SOURCE_URI": "http://www.tonycuffe.com/mp3/tail%20toddle.mp3" +} diff --git a/test/simple3.json b/test/simple3.json index a43c43e..2f27641 100644 --- a/test/simple3.json +++ b/test/simple3.json @@ -2,6 +2,7 @@ "LOGIN_NAME": "heslinki", "PASSWORD": "123456", "CART_NUMBER": 100000, + "CLEAR_CART": true, "CHANNELS": 2, "NORMALIZATION_LEVEL": -12, "AUTOTRIM_LEVEL": 0, diff --git a/test/simple3a.json b/test/simple3a.json new file mode 100644 index 0000000..a43c43e --- /dev/null +++ b/test/simple3a.json @@ -0,0 +1,10 @@ +{ + "LOGIN_NAME": "heslinki", + "PASSWORD": "123456", + "CART_NUMBER": 100000, + "CHANNELS": 2, + "NORMALIZATION_LEVEL": -12, + "AUTOTRIM_LEVEL": 0, + "USE_METADATA": true, + "SOURCE_URI": "http://www.jtricks.com/download-unknown" +} -- cgit v0.10.2