From 6c5d73d41af3cdc4d616258dc85c26f68ac2ab02 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Thu, 1 Aug 2013 18:19:18 +0300 Subject: [PATCH] more refactoring and added first test --- cmd/cgr-engine/cgr-engine.go | 19 ++++++++ engine/calldesc.go | 57 ++++++++++++---------- engine/destinations_test.go | 1 - engine/history_test.go | 38 +++++++++++++++ engine/storage_map.go | 1 + history/controller.go | 34 -------------- history/file_scribe.go | 91 ++++++++++++++++++++++++++++++++++++ history/file_store.go | 72 ---------------------------- history/mock_scribe.go | 52 +++++++++++++++++++++ history/mock_stor.go | 1 - history/proxy_scribe.go | 42 +++++++++++++++++ history/proxy_store.go | 24 ---------- history/scribe.go | 65 ++++++++++++++++++++++++++ history/store.go | 47 ------------------- 14 files changed, 340 insertions(+), 204 deletions(-) create mode 100644 engine/history_test.go delete mode 100644 history/controller.go create mode 100644 history/file_scribe.go delete mode 100644 history/file_store.go create mode 100644 history/mock_scribe.go delete mode 100644 history/mock_stor.go create mode 100644 history/proxy_scribe.go delete mode 100644 history/proxy_store.go create mode 100644 history/scribe.go delete mode 100644 history/store.go diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index 3f75dabe0..7083ecf95 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -27,6 +27,7 @@ import ( "github.com/cgrates/cgrates/cdrs" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/history" "github.com/cgrates/cgrates/mediator" "github.com/cgrates/cgrates/scheduler" "github.com/cgrates/cgrates/sessionmanager" @@ -213,6 +214,24 @@ func checkConfigSanity() error { return nil } +func startHistoryScribe() (err error) { + var scribe history.Scribe + flag.Parse() + if "*masterAddr" != "" { + scribe, err = history.NewProxyScribe("*masterAddr") + } else { + scribe, err = history.NewFileScribe("*dataFile") + } + rpc.RegisterName("Scribe", scribe) + rpc.HandleHTTP() + _, e := net.Listen("tcp", ":1234") + if e != nil { + return err + } + //http.Serve(l, nil) + return nil +} + func main() { flag.Parse() if *version { diff --git a/engine/calldesc.go b/engine/calldesc.go index 532b658bb..db12794c1 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -22,6 +22,7 @@ import ( "errors" "fmt" "github.com/cgrates/cgrates/cache2go" + "github.com/cgrates/cgrates/history" "github.com/cgrates/cgrates/utils" "log/syslog" "strings" @@ -54,8 +55,39 @@ var ( debitPeriod = 10 * time.Second roundingMethod = "*middle" roundingDecimals = 4 + historyScribe, _ = history.NewMockScribe() ) +// Exported method to set the storage getter. +func SetDataStorage(sg DataStorage) { + storageGetter = sg +} + +// Sets the global rounding method and decimal precision for GetCost method +func SetRoundingMethodAndDecimals(rm string, rd int) { + roundingMethod = rm + roundingDecimals = rd +} + +/* +Sets the database for logging (can be de same as storage getter or different db) +*/ +func SetStorageLogger(sg DataStorage) { + storageLogger = sg +} + +/* +Exported method to set the debit period for caching purposes. +*/ +func SetDebitPeriod(d time.Duration) { + debitPeriod = d +} + +// Exported method to set the history scribe. +func SetHistoryScribe(scribe history.Scribe) { + historyScribe = scribe +} + /* The input stucture that contains call information. */ @@ -94,31 +126,6 @@ func (cd *CallDescriptor) getUserBalance() (ub *UserBalance, err error) { return cd.userBalance, err } -// Exported method to set the storage getter. -func SetDataStorage(sg DataStorage) { - storageGetter = sg -} - -// Sets the global rounding method and decimal precision for GetCost method -func SetRoundingMethodAndDecimals(rm string, rd int) { - roundingMethod = rm - roundingDecimals = rd -} - -/* -Sets the database for logging (can be de same as storage getter or different db) -*/ -func SetStorageLogger(sg DataStorage) { - storageLogger = sg -} - -/* -Exported method to set the debit period for caching purposes. -*/ -func SetDebitPeriod(d time.Duration) { - debitPeriod = d -} - /* Restores the activation periods for the specified prefix from storage. */ diff --git a/engine/destinations_test.go b/engine/destinations_test.go index 352f6fda4..61b97e9f1 100644 --- a/engine/destinations_test.go +++ b/engine/destinations_test.go @@ -21,7 +21,6 @@ package engine import ( "encoding/json" "github.com/cgrates/cgrates/cache2go" - //"log" "reflect" "testing" ) diff --git a/engine/history_test.go b/engine/history_test.go new file mode 100644 index 000000000..12eb5ac74 --- /dev/null +++ b/engine/history_test.go @@ -0,0 +1,38 @@ +/* +Rating system designed to be used in VoIP Carriers World +Copyright (C) 2013 ITsysCOM + +This program 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 +(at your option) any later version. + +This program 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 this program. If not, see +*/ + +package engine + +import ( + "github.com/cgrates/cgrates/history" + "testing" +) + +func TestHistory(t *testing.T) { + scribe := historyScribe.(*history.MockScribe) + expected := `[{"Key":"GERMANY","Object":{"Id":"GERMANY","Prefixes":["49"]}}] + [{"Key":"GERMANY","Object":{"Id":"GERMANY","Prefixes":["49"]}},{"Key":"GERMANY_O2","Object":{"Id":"GERMANY_O2","Prefixes":["41"]}}] + [{"Key":"GERMANY","Object":{"Id":"GERMANY","Prefixes":["49"]}},{"Key":"GERMANY_O2","Object":{"Id":"GERMANY_O2","Prefixes":["41"]}},{"Key":"GERMANY_PREMIUM","Object":{"Id":"GERMANY_PREMIUM","Prefixes":["43"]}}] + [{"Key":"ALL","Object":{"Id":"ALL","Prefixes":["49","41","43"]}},{"Key":"GERMANY","Object":{"Id":"GERMANY","Prefixes":["49"]}},{"Key":"GERMANY_O2","Object":{"Id":"GERMANY_O2","Prefixes":["41"]}},{"Key":"GERMANY_PREMIUM","Object":{"Id":"GERMANY_PREMIUM","Prefixes":["43"]}}] + [{"Key":"ALL","Object":{"Id":"ALL","Prefixes":["49","41","43"]}},{"Key":"GERMANY","Object":{"Id":"GERMANY","Prefixes":["49"]}},{"Key":"GERMANY_O2","Object":{"Id":"GERMANY_O2","Prefixes":["41"]}},{"Key":"GERMANY_PREMIUM","Object":{"Id":"GERMANY_PREMIUM","Prefixes":["43"]}},{"Key":"NAT","Object":{"Id":"NAT","Prefixes":["0256","0257","0723"]}}] + [{"Key":"ALL","Object":{"Id":"ALL","Prefixes":["49","41","43"]}},{"Key":"GERMANY","Object":{"Id":"GERMANY","Prefixes":["49"]}},{"Key":"GERMANY_O2","Object":{"Id":"GERMANY_O2","Prefixes":["41"]}},{"Key":"GERMANY_PREMIUM","Object":{"Id":"GERMANY_PREMIUM","Prefixes":["43"]}},{"Key":"NAT","Object":{"Id":"NAT","Prefixes":["0256","0257","0723"]}},{"Key":"RET","Object":{"Id":"RET","Prefixes":["0723","0724"]}}] + [{"Key":"ALL","Object":{"Id":"ALL","Prefixes":["49","41","43"]}},{"Key":"GERMANY","Object":{"Id":"GERMANY","Prefixes":["49"]}},{"Key":"GERMANY_O2","Object":{"Id":"GERMANY_O2","Prefixes":["41"]}},{"Key":"GERMANY_PREMIUM","Object":{"Id":"GERMANY_PREMIUM","Prefixes":["43"]}},{"Key":"NAT","Object":{"Id":"NAT","Prefixes":["0256","0257","0723"]}},{"Key":"RET","Object":{"Id":"RET","Prefixes":["0723","0724"]}},{"Key":"nat","Object":{"Id":"nat","Prefixes":["0257","0256","0723"]}}]` + if scribe.Buf.String() != expected { + t.Error("Error in history content: ", scribe.Buf.String()) + } +} diff --git a/engine/storage_map.go b/engine/storage_map.go index 7b1922ac3..28ab76546 100644 --- a/engine/storage_map.go +++ b/engine/storage_map.go @@ -70,6 +70,7 @@ func (ms *MapStorage) GetDestination(key string) (dest *Destination, err error) func (ms *MapStorage) SetDestination(dest *Destination) (err error) { result, err := ms.ms.Marshal(dest) ms.dict[DESTINATION_PREFIX+dest.Id] = result + historyScribe.Record(dest.Id, dest) return } diff --git a/history/controller.go b/history/controller.go deleted file mode 100644 index 0971196fb..000000000 --- a/history/controller.go +++ /dev/null @@ -1,34 +0,0 @@ -package history - -import ( - "flag" - "log" - "net" - "net/http" - "net/rpc" -) - -var ( - dataFile = flag.String("file", "store.json", "data store file name") - hostname = flag.String("host", "localhost:8080", "http host name") - masterAddr = flag.String("master", "", "RPC master address") -) - -var store Store - -func start() { - - flag.Parse() - if *masterAddr != "" { - store, err := NewProxyStore(*masterAddr) - } else { - store, err := NewFileStore(*dataFile) - } - rpc.RegisterName("Store", store) - rpc.HandleHTTP() - l, e := net.Listen("tcp", ":1234") - if e != nil { - log.Fatal("listen error:", e) - } - http.Serve(l, nil) -} diff --git a/history/file_scribe.go b/history/file_scribe.go new file mode 100644 index 000000000..15f6d7361 --- /dev/null +++ b/history/file_scribe.go @@ -0,0 +1,91 @@ +/* +Rating system designed to be used in VoIP Carriers World +Copyright (C) 2013 ITsysCOM + +This program 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 +(at your option) any later version. + +This program 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 this program. If not, see +*/ + +package history + +import ( + "bufio" + "encoding/json" + "errors" + "os" + "os/exec" + "sync" +) + +type FileScribe struct { + sync.RWMutex + filename string + records records +} + +func NewFileScribe(filename string) (Scribe, error) { + // looking for git + _, err := exec.LookPath("git") + if err != nil { + return nil, errors.New("Please install git: " + err.Error()) + } + s := &FileScribe{filename: filename} + return s, s.load() +} + +func (s *FileScribe) Record(key string, obj interface{}) error { + s.Lock() + defer s.Unlock() + s.records = s.records.SetOrAdd(key, obj) + s.save() + return nil +} + +func (s *FileScribe) commit() error { + out, err := exec.Command("git", "commit", "-a", "-m", "'historic commit'").Output() + if err != nil { + return errors.New(string(out) + " " + err.Error()) + } + return nil +} + +func (s *FileScribe) load() error { + f, err := os.Open(s.filename) + if err != nil { + return err + } + defer f.Close() + d := json.NewDecoder(f) + + if err := d.Decode(&s.records); err != nil { + return err + } + s.records.Sort() + return nil +} + +func (s *FileScribe) save() error { + f, err := os.Create(s.filename) + if err != nil { + return err + } + b := bufio.NewWriter(f) + e := json.NewEncoder(b) + defer f.Close() + defer b.Flush() + s.records.Sort() + if err := e.Encode(s.records); err != nil { + return err + } + return s.commit() +} diff --git a/history/file_store.go b/history/file_store.go deleted file mode 100644 index 0d1550ad3..000000000 --- a/history/file_store.go +++ /dev/null @@ -1,72 +0,0 @@ -package history - -import ( - "bufio" - "encoding/json" - "errors" - "os" - "os/exec" - "sync" -) - -type FileStore struct { - sync.RWMutex - filename string - records records -} - -func NewFileStore(filename string) (*FileStore, error) { - // looking for git - _, err := exec.LookPath("git") - if err != nil { - return nil, errors.New("Please install git: " + err.Error()) - } - s := &FileStore{filename: filename} - return s, s.load() -} - -func (s *FileStore) Record(key string, obj interface{}) error { - s.Lock() - defer s.Unlock() - s.records = s.records.SetOrAdd(key, obj) - return nil -} - -func (s *FileStore) commit() error { - out, err := exec.Command("git", "commit", "-a", "-m", "'historic commit'").Output() - if err != nil { - return errors.New(string(out) + " " + err.Error()) - } - return nil -} - -func (s *FileStore) load() error { - f, err := os.Open(s.filename) - if err != nil { - return err - } - defer f.Close() - d := json.NewDecoder(f) - - if err := d.Decode(&s.records); err != nil { - return err - } - s.records.Sort() - return nil -} - -func (s *FileStore) save(filename string) error { - f, err := os.Create(filename) - if err != nil { - return err - } - b := bufio.NewWriter(f) - e := json.NewEncoder(b) - defer f.Close() - defer b.Flush() - s.records.Sort() - if err := e.Encode(s.records); err != nil { - return err - } - return s.commit() -} diff --git a/history/mock_scribe.go b/history/mock_scribe.go new file mode 100644 index 000000000..3b2665b9c --- /dev/null +++ b/history/mock_scribe.go @@ -0,0 +1,52 @@ +/* +Rating system designed to be used in VoIP Carriers World +Copyright (C) 2013 ITsysCOM + +This program 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 +(at your option) any later version. + +This program 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 this program. If not, see +*/ + +package history + +import ( + "bufio" + "bytes" + "encoding/json" + "sync" +) + +type MockScribe struct { + sync.RWMutex + records records + Buf bytes.Buffer +} + +func NewMockScribe() (Scribe, error) { + return &MockScribe{}, nil +} + +func (s *MockScribe) Record(key string, obj interface{}) error { + s.Lock() + defer s.Unlock() + s.records = s.records.SetOrAdd(key, obj) + s.save() + return nil +} + +func (s *MockScribe) save() error { + b := bufio.NewWriter(&s.Buf) + e := json.NewEncoder(b) + defer b.Flush() + s.records.Sort() + return e.Encode(s.records) +} diff --git a/history/mock_stor.go b/history/mock_stor.go deleted file mode 100644 index 3dfb0b865..000000000 --- a/history/mock_stor.go +++ /dev/null @@ -1 +0,0 @@ -package history \ No newline at end of file diff --git a/history/proxy_scribe.go b/history/proxy_scribe.go new file mode 100644 index 000000000..c0c2564e5 --- /dev/null +++ b/history/proxy_scribe.go @@ -0,0 +1,42 @@ +/* +Rating system designed to be used in VoIP Carriers World +Copyright (C) 2013 ITsysCOM + +This program 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 +(at your option) any later version. + +This program 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 this program. If not, see +*/ + +package history + +import ( + "net/rpc" +) + +type ProxyScribe struct { + client *rpc.Client +} + +func NewProxyScribe(addr string) (Scribe, error) { + client, err := rpc.DialHTTP("tcp", addr) + if err != nil { + return nil, err + } + return &ProxyScribe{client: client}, nil +} + +func (ps *ProxyScribe) Record(key string, obj interface{}) error { + if err := ps.client.Call("Scribe.Record", key, obj); err != nil { + return err + } + return nil +} diff --git a/history/proxy_store.go b/history/proxy_store.go deleted file mode 100644 index 61bedd497..000000000 --- a/history/proxy_store.go +++ /dev/null @@ -1,24 +0,0 @@ -package history - -import ( - "net/rpc" -) - -type ProxyStore struct { - client *rpc.Client -} - -func NewProxyStore(addr string) (*ProxyStore, error) { - client, err := rpc.DialHTTP("tcp", addr) - if err != nil { - return nil, err - } - return &ProxyStore{client: client}, nil -} - -func (ps *ProxyStore) Record(key string, obj interface{}) error { - if err := ps.client.Call("Store.Record", key, obj); err != nil { - return err - } - return nil -} diff --git a/history/scribe.go b/history/scribe.go new file mode 100644 index 000000000..fe1349548 --- /dev/null +++ b/history/scribe.go @@ -0,0 +1,65 @@ +/* +Rating system designed to be used in VoIP Carriers World +Copyright (C) 2013 ITsysCOM + +This program 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 +(at your option) any later version. + +This program 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 this program. If not, see +*/ + +package history + +import ( + "sort" +) + +type Scribe interface { + Record(key string, obj interface{}) error +} + +type record struct { + Key string + Object interface{} +} + +type records []*record + +func (rs records) Len() int { + return len(rs) +} + +func (rs records) Swap(i, j int) { + rs[i], rs[j] = rs[j], rs[i] +} + +func (rs records) Less(i, j int) bool { + return rs[i].Key < rs[j].Key +} + +func (rs records) Sort() { + sort.Sort(rs) +} + +func (rs records) SetOrAdd(key string, obj interface{}) records { + found := false + for _, r := range rs { + if r.Key == key { + found = true + r.Object = obj + return rs + } + } + if !found { + rs = append(rs, &record{key, obj}) + } + return rs +} diff --git a/history/store.go b/history/store.go deleted file mode 100644 index 0c1288666..000000000 --- a/history/store.go +++ /dev/null @@ -1,47 +0,0 @@ -package history - -import ( - "sort" -) - -type Store interface { - Record(key string, obj interface{}) error -} - -type record struct { - Key string - Object interface{} -} - -type records []*record - -func (rs records) Len() int { - return len(rs) -} - -func (rs records) Swap(i, j int) { - rs[i], rs[j] = rs[j], rs[i] -} - -func (rs records) Less(i, j int) bool { - return rs[i].Key < rs[j].Key -} - -func (rs records) Sort() { - sort.Sort(rs) -} - -func (rs records) SetOrAdd(key string, obj interface{}) records { - found := false - for _, r := range rs { - if r.Key == key { - found = true - r.Object = obj - return rs - } - } - if !found { - rs = append(rs, &record{key, obj}) - } - return rs -}