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
-}