summaryrefslogtreecommitdiff
path: root/src/pool-import/rddb.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pool-import/rddb.go')
-rw-r--r--src/pool-import/rddb.go228
1 files changed, 228 insertions, 0 deletions
diff --git a/src/pool-import/rddb.go b/src/pool-import/rddb.go
new file mode 100644
index 0000000..7d2e4c2
--- /dev/null
+++ b/src/pool-import/rddb.go
@@ -0,0 +1,228 @@
+//
+// pool-import
+//
+// Copyright (C) 2016 Christian Pointner <equinox@helsinki.at>
+//
+// This file is part of pool-import.
+//
+// pool-import 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.
+//
+// pool-import 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 pool-import. If not, see <http://www.gnu.org/licenses/>.
+//
+
+package main
+
+import (
+ "database/sql"
+ "fmt"
+ "regexp"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/ziutek/mymysql/godrv"
+)
+
+var (
+ mysqlTableNameRe = regexp.MustCompile(`^[_0-9a-zA-Z-]+$`)
+)
+
+const (
+ DB_VERSION = 182
+ defaultCartTitle = "[new cart]"
+)
+
+type CutListEntry struct {
+ Number uint
+ Evergreen bool
+ Description string
+ Duration time.Duration
+ Imported NullTime
+ NumPlayed uint
+ LastPlayed NullTime
+}
+
+type CartListEntry struct {
+ Number uint
+ Exists bool
+ Artist string
+ Title string
+ Album string
+ Cuts []CutListEntry
+}
+
+type PoolListEntry struct {
+ Group string
+ Description string
+}
+
+type getPoolCartListResult struct {
+ carts map[uint]CartListEntry
+ err error
+}
+
+type getPoolCartListRequest struct {
+ pool PoolListEntry
+ response chan<- getPoolCartListResult
+}
+
+type db struct {
+ conf *config
+ dbh *sql.DB
+ getPoolCartListChan chan getPoolCartListRequest
+ getPoolCartsStmt *sql.Stmt
+ quit chan bool
+ done chan bool
+}
+
+func (d *db) init() (err error) {
+ godrv.Register("SET CHARACTER SET utf8;")
+
+ dsn := fmt.Sprintf("tcp:%s:3306*%s/%s/%s", d.conf.dbHost, d.conf.dbDb, d.conf.dbUser, d.conf.dbPasswd)
+ if d.dbh, err = sql.Open("mymysql", dsn); err != nil {
+ return
+ }
+
+ var dbver int
+ err = d.dbh.QueryRow("select DB from VERSION;").Scan(&dbver)
+ if err != nil {
+ err = fmt.Errorf("fetching version: %s", err)
+ return
+ }
+ if dbver != DB_VERSION {
+ err = fmt.Errorf("version mismatch is %d, should be %d", dbver, DB_VERSION)
+ return
+ }
+
+ if d.getPoolCartsStmt, err = d.dbh.Prepare("select CART.NUMBER,CART.ARTIST,CART.TITLE,CART.ALBUM,CUTS.CUT_NAME,CUTS.EVERGREEN,CUTS.DESCRIPTION,CUTS.LENGTH,CUTS.ORIGIN_DATETIME,CUTS.PLAY_COUNTER,CUTS.LAST_PLAY_DATETIME from CUTS,CART where CUTS.CART_NUMBER = CART.NUMBER and CART.GROUP_NAME = ?;"); err != nil {
+ return
+ }
+
+ return
+}
+
+func (d *db) getPoolCartList(pool PoolListEntry) (result getPoolCartListResult) {
+ var rows *sql.Rows
+ if rows, result.err = d.getPoolCartsStmt.Query(pool.Group); result.err != nil {
+ return
+ }
+ defer rows.Close()
+
+ result.carts = make(map[uint]CartListEntry)
+ for rows.Next() {
+ var cut CutListEntry
+ var cart, length uint
+ var cutName, evergreen string
+ var artist, title, album sql.NullString
+
+ if result.err = rows.Scan(&cart, &artist, &title, &album, &cutName, &evergreen, &cut.Description, &length, &cut.Imported, &cut.NumPlayed, &cut.LastPlayed); result.err != nil {
+ return
+ }
+
+ parts := strings.Split(cutName, "_")
+ if len(parts) == 2 {
+ if cn, converr := strconv.ParseUint(parts[1], 10, 32); converr != nil {
+ continue
+ } else {
+ cut.Number = uint(cn)
+ }
+ } else {
+ continue
+ }
+ switch evergreen {
+ case "Y":
+ cut.Evergreen = true
+ default:
+ cut.Evergreen = false
+ }
+ cut.Duration = time.Duration(length) * time.Millisecond
+
+ if c, exists := result.carts[cart]; !exists {
+ c = CartListEntry{cart, true, artist.String, title.String, album.String, nil}
+ c.Cuts = append(c.Cuts, cut)
+ result.carts[cart] = c
+ } else {
+ c.Cuts = append(c.Cuts, cut)
+ }
+ }
+ result.err = rows.Err()
+ return
+}
+
+func (d *db) dispatchRequests() {
+ defer func() { d.done <- true }()
+ for {
+ select {
+ case <-d.quit:
+ return
+ case req := <-d.getPoolCartListChan:
+ req.response <- d.getPoolCartList(req.pool)
+ }
+ }
+}
+
+// *********************************************************
+// Public Interface
+
+type DB struct {
+ getPoolCartListChan chan<- getPoolCartListRequest
+}
+
+func (d *DB) GetPoolCartList(pool PoolListEntry) (map[uint]CartListEntry, error) {
+ resCh := make(chan getPoolCartListResult)
+ req := getPoolCartListRequest{}
+ req.pool = pool
+ req.response = resCh
+ d.getPoolCartListChan <- req
+
+ res := <-resCh
+ if res.err != nil {
+ return nil, res.err
+ }
+ return res.carts, nil
+}
+
+func (d *db) GetInterface() *DB {
+ ch := &DB{}
+ ch.getPoolCartListChan = d.getPoolCartListChan
+ return ch
+}
+
+func (d *db) Cleanup() {
+ d.quit <- true
+ <-d.done
+ close(d.quit)
+ close(d.done)
+ if d.dbh != nil {
+ d.dbh.Close()
+ }
+ if d.getPoolCartsStmt != nil {
+ d.getPoolCartsStmt.Close()
+ }
+}
+
+func NewDB(configfile string) (d *db, err error) {
+ d = new(db)
+ if d.conf, err = newConfig(configfile); err != nil {
+ return
+ }
+ d.quit = make(chan bool)
+ d.done = make(chan bool)
+ d.getPoolCartListChan = make(chan getPoolCartListRequest, 10)
+
+ if err = d.init(); err != nil {
+ return
+ }
+
+ go d.dispatchRequests()
+ return
+}