diff options
Diffstat (limited to 'src/rhimportd/ctrlWatchDir.go')
-rw-r--r-- | src/rhimportd/ctrlWatchDir.go | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/src/rhimportd/ctrlWatchDir.go b/src/rhimportd/ctrlWatchDir.go new file mode 100644 index 0000000..6f84c15 --- /dev/null +++ b/src/rhimportd/ctrlWatchDir.go @@ -0,0 +1,219 @@ +// +// rhimportd +// +// The Radio Helsinki Rivendell Import Daemon +// +// +// Copyright (C) 2015-2016 Christian Pointner <equinox@helsinki.at> +// +// This file is part of rhimportd. +// +// rhimportd is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// rhimportd is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with rhimportd. If not, see <http://www.gnu.org/licenses/>. +// + +package main + +import ( + "encoding/json" + "fmt" + "helsinki.at/rhimport" + "net/http" + "os" + "path/filepath" + "strings" + "time" +) + +type watchDirRequestData struct { + UserName string `json:"LOGIN_NAME"` + ShowId uint `json:"SHOW_ID"` + 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"` + AutotrimLevel int `json:"AUTOTRIM_LEVEL"` + UseMetaData bool `json:"USE_METADATA"` + SourceUri string `json:"SOURCE_URI"` +} + +func newWatchDirRequestData(conf *rhimport.Config) *watchDirRequestData { + rd := new(watchDirRequestData) + rd.UserName = "" + rd.ShowId = 0 + rd.ClearShowCarts = false + rd.MusicPoolGroup = "" + rd.Cart = 0 + rd.ClearCart = false + rd.Cut = 0 + rd.Channels = conf.ImportParamDefaults.Channels + rd.NormalizationLevel = conf.ImportParamDefaults.NormalizationLevel + rd.AutotrimLevel = conf.ImportParamDefaults.AutotrimLevel + rd.UseMetaData = conf.ImportParamDefaults.UseMetaData + rd.SourceUri = "" + + return rd +} + +type watchDirResponseData struct { + ResponseCode int `json:"REPONSE_CODE"` + ErrorString string `json:"ERROR_STRING"` + Cart uint `json:"CART_NUMBER"` + Cut uint `json:"CUT_NUMBER"` +} + +func watchDirWriteResponse(filename string, resp *watchDirResponseData) { + file, err := os.OpenFile(filename, os.O_WRONLY|os.O_TRUNC, 0) + if err != nil { + rhl.Printf("watch-dir-ctrl: writing response failed: %s", err) + return + } + encoder := json.NewEncoder(file) + encoder.Encode(resp) + file.Close() + + dstname := strings.TrimSuffix(filename, ".running") + ".done" + os.Rename(filename, dstname) +} + +func watchDirErrorResponse(filename string, code int, errStr string) { + watchDirWriteResponse(filename, &watchDirResponseData{code, errStr, 0, 0}) +} + +func watchDirResponse(filename string, result *rhimport.Result) { + watchDirWriteResponse(filename, &watchDirResponseData{result.ResponseCode, result.ErrorString, result.Cart, result.Cut}) +} + +func watchDirParseRequest(conf *rhimport.Config, rddb *rhimport.RdDbChan, req *os.File) (ctx *rhimport.Context, err error) { + + decoder := json.NewDecoder(req) + reqdata := newWatchDirRequestData(conf) + if jsonerr := decoder.Decode(reqdata); jsonerr != nil { + err = fmt.Errorf("Error parsing JSON response: %s", jsonerr) + return + } + + ctx = rhimport.NewContext(conf, rddb) + ctx.UserName = reqdata.UserName + ctx.Trusted = true + ctx.ShowId = reqdata.ShowId + 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 + ctx.AutotrimLevel = reqdata.AutotrimLevel + ctx.UseMetaData = reqdata.UseMetaData + ctx.SourceUri = reqdata.SourceUri + return +} + +func watchDirHandler(conf *rhimport.Config, rddb *rhimport.RdDbChan, ctx *rhimport.Context, filename string) { + rhdl.Printf("WatchDirHandler: request for '%s'", filename) + + var err error + if err = ctx.SanityCheck(); err != nil { + watchDirErrorResponse(filename, http.StatusBadRequest, err.Error()) + return + } + + var res *rhimport.Result + if res, err = rhimport.FetchFile(ctx); err != nil { + watchDirErrorResponse(filename, http.StatusInternalServerError, err.Error()) + return + } + if res.ResponseCode != http.StatusOK { + watchDirErrorResponse(filename, res.ResponseCode, res.ErrorString) + return + } + + if res, err = rhimport.ImportFile(ctx); err != nil { + watchDirErrorResponse(filename, http.StatusInternalServerError, err.Error()) + return + } + if res.ResponseCode == http.StatusOK { + rhl.Println("ImportFile succesfully imported", ctx.SourceFile) + } else { + rhl.Println("ImportFile import of", ctx.SourceFile, "was unsuccesful") + } + + watchDirResponse(filename, res) + return +} + +func watchDirRun(dir *os.File, conf *rhimport.Config, rddb *rhimport.RdDbChan) { + rhl.Printf("watch-dir-ctrl: watching for files in %s", dir.Name()) + for { + var err error + if _, err = dir.Seek(0, 0); err != nil { + rhl.Printf("watch-dir-ctrl: reading directory contents failed: %s", err) + return + } + + var names []string + if names, err = dir.Readdirnames(0); err != nil { + rhl.Printf("watch-dir-ctrl: reading directory contents failed: %s", err) + return + } + + for _, name := range names { + if strings.HasSuffix(name, ".new") { + srcname := filepath.Join(dir.Name(), name) + + rhdl.Printf("watch-dir-ctrl: found new file %s", srcname) + var file *os.File + if file, err = os.Open(srcname); err != nil { + rhl.Printf("watch-dir-ctrl: error reading new file: %s", err) + continue + } + if ctx, err := watchDirParseRequest(conf, rddb, file); err == nil { + file.Close() + dstname := strings.TrimSuffix(srcname, ".new") + ".running" + os.Rename(srcname, dstname) + go watchDirHandler(conf, rddb, ctx, dstname) + } else { // ignoring files with json errors -> maybe the file has not been written completely + file.Close() + rhdl.Printf("watch-dir-ctrl: new file %s parser error: %s, ignoring for now", srcname, err) + } + } + } + + time.Sleep(1 * time.Second) + } +} + +func StartWatchDir(dirname string, conf *rhimport.Config, rddb *rhimport.RdDbChan) { + for { + time.Sleep(5 * time.Second) + dir, err := os.Open(dirname) + if err != nil { + rhl.Printf("watch-dir-ctrl: %s", err) + continue + } + if i, err := dir.Stat(); err != nil { + rhl.Printf("watch-dir-ctrl: %s", err) + continue + } else { + if !i.IsDir() { + rhl.Printf("watch-dir-ctrl: %s is not a directory", dirname) + continue + } + } + watchDirRun(dir, conf, rddb) + } +} |