From e8ae139371e7488dbcc0f2af62f09ea9ec49427b Mon Sep 17 00:00:00 2001 From: Scantlight Date: Wed, 30 Jan 2013 14:15:39 +0100 Subject: [PATCH 01/11] flag parse + log module + configuration file flag parse, application can be started using some basic command line arguments: log - specify amount of output log (text messages) conf - path to a configuration file configuration file, function to load and parse configuration file log module, when log level is to hight application will panic --- admin/admin.go | 23 +++++++++++++++++++++++ log/.log.go.swo | Bin 12288 -> 0 bytes log/log.go | 8 +++++++- mapo.go | 25 +++++++++++++++++++++---- 4 files changed, 51 insertions(+), 5 deletions(-) delete mode 100644 log/.log.go.swo diff --git a/admin/admin.go b/admin/admin.go index feda89c..561f98d 100644 --- a/admin/admin.go +++ b/admin/admin.go @@ -21,3 +21,26 @@ along with Mapo. If not, see . Package admin implements the API for Mapo's administration components. */ package admin + +import ( + "gconf/conf" +) + +/* +GlobalConfiguration, il oggetto globale per l'accesso ai dati contenuti nel +file di configurazione. +*/ +var GlobalConfiguration *conf.ConfigFile + +/* +ReadConfiguration, attiva il GlobalConfiguration. +*/ +func ReadConfiguration(filepath string) error { + + c, err := conf.ReadConfigFile(filepath) + if err == nil { + GlobalConfiguration = c + } + + return err +} diff --git a/log/.log.go.swo b/log/.log.go.swo deleted file mode 100644 index 31bbc0735276017e5aef0f3d0fa4d67ce4a3b674..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2&ubiI7{{M_u&i1uN{ikeS1Oyboo$jsC2f>#nzW1CWV_k5#H#S_>^r-Iv-2+V zzOx~%(X&dyqo4@>0cvTH)`Lec7EuuN;?YAv@us(c-*;xWk-FC6t?~vwnVol@_xbUC zo|zsO?F5%rZeUiPW01|p27 z?09qRu+o*I%0LWN_AQpCq7y$~h*YlvyxzY@of5z;IR%^o(-lZfaOAmtG(R_c)EYcf ze43wlygl94tvUsq0!{&^fK$LJ;1qBQI0c*n|4RkTa1XtO${rY3cW!*#bH{Of>JCl; zr+`zyDc}@v3OEIv0!{&^fK$LJ;1qBQ+=mK?F46CMiP{AukN^Kq{{G+DPjmxZ2OokD zz-!kI?z zlSv?ad1-rwFHxnE+cI8@)GT-)wH7_e!f-KjU*t%RWQ1RdCQ)mvD{E7O*5W|jV@zv0 zEu{7R_lV2Q=2~-V$mJwa$vwu*Y^Mdy-2XM|Hc_Dv42;*XG6$vNAXVLWD^dgx2iTvGu}$plv1|RTv?i(otw92*k%o_^YyHW!8rR# z`(Oj5Gehg27bktdqA#@MtSbw5m}I(5EbPgh26>GWi|ovr=*`gh{k+AP2CR%kGO2Am zI8+FOvBil+j=XFhV4MwFK8X1ew3;;Ot}|yxY2pSBv+>HDtxHq4XQkWz#v?kpz*-v3 zrY~8gW|*3BTA1@}u@|Y1h-`~{G9j|1?4H@6);S|hGFIB$&Ze6B##WC8W$IGFN=SuF zCUhWFMv$*!ZMbCbnCeJ`k?2I3i#!LN?JnAO7pYK0e~T0jhAOdJXej*G?Olb4bhtu| z-BX5JgZG*3y{EAOJ_l)J!XtUEd5RuY4wKy|A{F--J?ryXyx{CH*8+|eWY<#iiM}zz zg-T^}bJOd^sizXW?Hu|t)>2oV_h>_qoQ?Gf(}y$?LA*>omp$QxVpN*=c~;ooNXM>>PP<> z-Hfx0t!^Re*c3@3Vq+^Is}F~oyP=)iOwex9?3*w$s;>~D+v-^SAjuPoT)VK3cI1q68+h==DCTmV-?E~ zf)E)SU}asw_drjq?jo_!JhTnbeH7E#x?N*nQ_kGlrCalYF}|f^rBFd Uxt_nv&y5g2TqNoW{m>5WpVYT|z5oCK diff --git a/log/log.go b/log/log.go index b39a22f..52a0985 100644 --- a/log/log.go +++ b/log/log.go @@ -42,7 +42,13 @@ var l logger // SetLevel sets the output level for the global logger func SetLevel(level int) { - l.level = level + + if level <= DEBUG { + l.level = level + return + } + + panic(fmt.Sprintf("Unknown log level %v", level)) } func print(level int, format string, v ...interface{}) { diff --git a/mapo.go b/mapo.go index 5c2790b..2cc952c 100644 --- a/mapo.go +++ b/mapo.go @@ -21,16 +21,33 @@ package main import ( "mapo/log" + "mapo/admin" + + "flag" ) func main() { + + log.Info("Starting application") + // parse flags + var logLevel = flag.Int("log", 1, "set message level eg: 0 = DEBUG, 1 = INFO, 2 = ERROR") + var confFilePath = flag.String("conf", "./conf.ini", "set path to configuration file") + flag.Parse() - // load config and setup application - log.SetLevel(log.DEBUG) - log.Info("Setting log level to DEBUG") + // set log level + log.SetLevel(*logLevel) + log.Info("Setting log level to %d", *logLevel) - log.Info("Starting application") + // load config and setup application + log.Info("Loading configuration from file") + err := admin.ReadConfiguration(*confFilePath) + if err != nil { + log.Info("%s, no such file or directory", *confFilePath) + return + } + + // setup application // register with supervisor log.Info("Joining supervisor") From c25380a4e7dc02878705995cbba86ef94b862fba Mon Sep 17 00:00:00 2001 From: Scantlight Date: Wed, 30 Jan 2013 15:05:03 +0100 Subject: [PATCH 02/11] Personalized http muxer. --- mapo.go | 35 ++++++++-- mux.go | 209 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 240 insertions(+), 4 deletions(-) diff --git a/mapo.go b/mapo.go index 2cc952c..f4efce1 100644 --- a/mapo.go +++ b/mapo.go @@ -23,6 +23,10 @@ import ( "mapo/log" "mapo/admin" + "net/http" + "os" + "os/signal" + "syscall" "flag" ) @@ -49,20 +53,43 @@ func main() { // setup application - // register with supervisor - log.Info("Joining supervisor") - // init db log.Info("Initializing db") // load addons log.Info("Loading addons") + // al momento del spegnimento dell'applicazione potremo trovarci con delle + // connessione attive dal parte del cliente. Il handler personalizzato usato + // qui, ci permette di dire al server di spegnersi ma prima deve aspettare + // che tutte le richieste siano processate e la connessione chiusa. + // + // Oltre al spegnimento sicuro il ServeMux permette di registra dei nuovi + // handler usando come descrizione anche il metodo http tipo GET o POST. + muxer := NewServeMux() + + // prepare server + server := &http.Server { + Addr: ":8081", + Handler: muxer, + } + + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGINT) + + // aviamo in una nuova gorutine la funzione che ascolterà per il segnale di + // spegnimento del server + go muxer.getSignalAndClose(c) + // register handlers log.Info("Registering handlers") + // register with supervisor + log.Info("Joining supervisor") + // start server - log.Info("Accepting requests") + log.Info("Listening for requests") + log.Info("close server with message: %v", server.ListenAndServe()) // inform supervisor that we are up diff --git a/mux.go b/mux.go index ff97c40..05547fb 100644 --- a/mux.go +++ b/mux.go @@ -18,3 +18,212 @@ along with Mapo. If not, see . */ package main + +import ( + "mapo/log" + + "os" + "sync" + "time" + "regexp" + "strings" + "net/http" +) + +/* +ServeMux, nasce dalla necessita di registrare dei handler differenziati anche +dal metodo http usato durante la richiesta dal parte del utente. Cosi lo stesso +url usato con il metodo POST ha un funzionamento diverso da una richiesta dove +si usa il metodo GET. + +Un altra possibilità che ci offre questo handler personalizzato è di poter +interrompere il server usando la combinazione dei tasti CTRL+C +*/ +type ServeMux struct { + + // lista dei handler registrati, con o senza autenticazione + m map[string]Handler + mVars map[string]map[int]string + + // il numero delle connessione attive in questo momento + current_connections int + lock sync.Mutex + + // il server è o no in fase di chiusura + closing bool +} + +func (mux *ServeMux) HandleFunc(method, path string, handle func(http.ResponseWriter, *http.Request)) { + handlerFunc := new(http.HandlerFunc) + *handlerFunc = handle + + pattern := createPattern(method, path) + + mux.m[pattern] = handlerFunc + mux.mVars[pattern] = createUrlVars(path) +} + +func (mux *ServeMux) Handle(method, path string, handler Handler) { + pattern := createPattern(method, path) + mux.m[pattern] = handler + mux.mVars[pattern] = createUrlVars(path) +} + +/* +createPattern, crea l'espressione regulare che si usa più tardi per trovare +il handler corretto per il path/risorsa richiesta. +*/ +func createPattern(method, path string) string { + pattern := "(?i)^" + + if method != "" { + pattern = pattern + method + ":/" + } else { + pattern = pattern + "(GET|POST)" + ":/" + } + + if len(path) > 1 { + pathSlice := strings.Split(path[1:], "/") + for _, v := range(pathSlice) { + if v[0] == '{' { + pattern = pattern + "[0-9a-z_\\ \\.\\+\\-]*/" + } else { + pattern = pattern + v + "/" + } + } + } + pattern = pattern + "$" + return pattern +} + +/* +createUrlVars, mappa le variabili inserite del url inserite al momento della +registrazione del handler. Le variabili sono segnati con le parentesi graffe +al interno delle quali si trova il nome della variabile. Questa mappa sarà usata +più tardi per passare i dati a forma di copie (chiave:valore) ai handler. +*/ +func createUrlVars(path string) map[int]string { + vlist := strings.Split(path, "/") + + data := make(map[int]string,0) + + for i, v := range(vlist) { + if len(v) < 3 { + continue + } + if v[0] == '{' && v[len(v)-1] == '}' { + data[i] = v[1:len(v)-1] + } + } + + return data +} + +/* +match, è usata per identificare quale dei handler corrisponde per un certo url. +Questa funzione fa utilizzo dei pattern (espressioni regolari). +*/ +func (mux *ServeMux) match(r *http.Request) (Handler, string) { + method := r.Method + url := r.URL.Path + + if url[len(url)-1] != '/' { + url = url + "/" + } + + var handler Handler + var pattern string + + for k, v := range(mux.m) { + matching, _ := regexp.MatchString(k, method + ":" + url) + if matching { + handler = v + pattern = k + break + } + } + + if handler != nil { + return handler, pattern + } + return http.NotFoundHandler(), "" +} + +/* +NewServeMux, restituisce un nuovo miltiplixier personalizzato. +*/ +func NewServeMux() *ServeMux { + mux := new(ServeMux) + mux.m = make(map[string]Handler, 0) + mux.mVars = make(map[string]map[int]string, 0) + + return mux +} + +/* +Handler, è un interfaccia che come funzionalità e struttura non è diversa dal +handler originale del modulo http di go. +TODO: Probabilmente è più corretto usare il http.Handler, resta da verificare. +*/ +type Handler interface { + ServeHTTP(http.ResponseWriter, *http.Request) +} + +// ServeHTTP e la funzione che vine eseguita come gorutine ogni volta che +// si deve processare qualche richiesta. Questa funzione soltanto si assicura +// che venga incrementato o decrementato il numero delle connessione attive e +// avvierà la funzione RequestHandler che processerà la richiesta del cliente. +// Comunque, il server http viene interrotto in maniera brutta ma senza alcun +// rischio. TODO: approfondire questa feature se servirà. +func (mux *ServeMux) ServeHTTP(out http.ResponseWriter, in *http.Request) { + if !mux.closing { + start := time.Now() + defer func() { + log.Info("time: %v for %s", time.Since(start), in.URL.Path) + }() + + mux.lock.Lock() + mux.current_connections++ + mux.lock.Unlock() + + defer func() { + mux.lock.Lock() + mux.current_connections-- + mux.lock.Unlock() + }() + + handle, pattern := mux.match(in) + if len(pattern) > 0 { + in.ParseMultipartForm(0) + urlValues := strings.Split(in.URL.Path, "/") + for k, v := range(mux.mVars[pattern]) { + in.Form[v] = []string{urlValues[k]} + } + } + handle.ServeHTTP(out, in) + } +} + +// se viene richiesto che l'applicazione si deve chiudere, in questo momento si +// parla del commando CTRL+C dal terminale, potremmo corrompere i dati a colpa +// del'interruzione in maniera incorretta delle richieste in corso. La presente +// Funzione sta in ascolto per il segnale SIGINT dopo di che si assicura che il +// server venga chiuso non appena le connessione attive saranno zero. +func (mux *ServeMux) getSignalAndClose(c chan os.Signal) { + + _ = <-c + log.Info("closing ...") + mux.closing = true + + // TODO: send notification to load balancing that this node is unavailable + + for { + if mux.current_connections == 0 { + log.Info("bye ... :)") + os.Exit(1) + } else { + log.Info("waiting for %d opened connections", mux.current_connections) + time.Sleep(500 * time.Millisecond) + } + } +} From 9997d09fd0acff4b6c734e33a0554c4fb36788e1 Mon Sep 17 00:00:00 2001 From: Scantlight Date: Thu, 31 Jan 2013 14:06:29 +0100 Subject: [PATCH 03/11] Formated code with gofmt tool. --- admin/admin.go | 12 ++++++------ log/log.go | 10 +++++----- mapo.go | 23 +++++++++++------------ 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/admin/admin.go b/admin/admin.go index 561f98d..de01598 100644 --- a/admin/admin.go +++ b/admin/admin.go @@ -23,7 +23,7 @@ Package admin implements the API for Mapo's administration components. package admin import ( - "gconf/conf" + "gconf/conf" ) /* @@ -37,10 +37,10 @@ ReadConfiguration, attiva il GlobalConfiguration. */ func ReadConfiguration(filepath string) error { - c, err := conf.ReadConfigFile(filepath) - if err == nil { - GlobalConfiguration = c - } + c, err := conf.ReadConfigFile(filepath) + if err == nil { + GlobalConfiguration = c + } - return err + return err } diff --git a/log/log.go b/log/log.go index 52a0985..c196ed0 100644 --- a/log/log.go +++ b/log/log.go @@ -43,12 +43,12 @@ var l logger // SetLevel sets the output level for the global logger func SetLevel(level int) { - if level <= DEBUG { - l.level = level - return - } + if level <= DEBUG { + l.level = level + return + } - panic(fmt.Sprintf("Unknown log level %v", level)) + panic(fmt.Sprintf("Unknown log level %v", level)) } func print(level int, format string, v ...interface{}) { diff --git a/mapo.go b/mapo.go index 2cc952c..4fe9ca8 100644 --- a/mapo.go +++ b/mapo.go @@ -20,10 +20,10 @@ along with Mapo. If not, see . package main import ( + "mapo/admin" "mapo/log" - "mapo/admin" - "flag" + "flag" ) func main() { @@ -31,21 +31,21 @@ func main() { log.Info("Starting application") // parse flags - var logLevel = flag.Int("log", 1, "set message level eg: 0 = DEBUG, 1 = INFO, 2 = ERROR") - var confFilePath = flag.String("conf", "./conf.ini", "set path to configuration file") - flag.Parse() + var logLevel = flag.Int("log", 1, "set message level eg: 0 = DEBUG, 1 = INFO, 2 = ERROR") + var confFilePath = flag.String("conf", "./conf.ini", "set path to configuration file") + flag.Parse() - // set log level + // set log level log.SetLevel(*logLevel) log.Info("Setting log level to %d", *logLevel) // load config and setup application log.Info("Loading configuration from file") - err := admin.ReadConfiguration(*confFilePath) - if err != nil { - log.Info("%s, no such file or directory", *confFilePath) - return - } + err := admin.ReadConfiguration(*confFilePath) + if err != nil { + log.Info("%s, no such file or directory", *confFilePath) + return + } // setup application @@ -81,7 +81,6 @@ func main() { // return result to user - // close on signal log.Info("Closing application") } From 2ff35b2de3fd7754636481afe4905abc61afb773 Mon Sep 17 00:00:00 2001 From: Scantlight Date: Thu, 31 Jan 2013 14:14:53 +0100 Subject: [PATCH 04/11] Formated with gofmt tool. --- admin/admin.go | 12 ++++----- log/log.go | 10 ++++---- mapo.go | 70 +++++++++++++++++++++++++------------------------- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/admin/admin.go b/admin/admin.go index 561f98d..de01598 100644 --- a/admin/admin.go +++ b/admin/admin.go @@ -23,7 +23,7 @@ Package admin implements the API for Mapo's administration components. package admin import ( - "gconf/conf" + "gconf/conf" ) /* @@ -37,10 +37,10 @@ ReadConfiguration, attiva il GlobalConfiguration. */ func ReadConfiguration(filepath string) error { - c, err := conf.ReadConfigFile(filepath) - if err == nil { - GlobalConfiguration = c - } + c, err := conf.ReadConfigFile(filepath) + if err == nil { + GlobalConfiguration = c + } - return err + return err } diff --git a/log/log.go b/log/log.go index 52a0985..c196ed0 100644 --- a/log/log.go +++ b/log/log.go @@ -43,12 +43,12 @@ var l logger // SetLevel sets the output level for the global logger func SetLevel(level int) { - if level <= DEBUG { - l.level = level - return - } + if level <= DEBUG { + l.level = level + return + } - panic(fmt.Sprintf("Unknown log level %v", level)) + panic(fmt.Sprintf("Unknown log level %v", level)) } func print(level int, format string, v ...interface{}) { diff --git a/mapo.go b/mapo.go index f4efce1..ce2f52e 100644 --- a/mapo.go +++ b/mapo.go @@ -20,14 +20,14 @@ along with Mapo. If not, see . package main import ( + "mapo/admin" "mapo/log" - "mapo/admin" - "net/http" - "os" - "os/signal" - "syscall" - "flag" + "flag" + "net/http" + "os" + "os/signal" + "syscall" ) func main() { @@ -35,21 +35,21 @@ func main() { log.Info("Starting application") // parse flags - var logLevel = flag.Int("log", 1, "set message level eg: 0 = DEBUG, 1 = INFO, 2 = ERROR") - var confFilePath = flag.String("conf", "./conf.ini", "set path to configuration file") - flag.Parse() + var logLevel = flag.Int("log", 1, "set message level eg: 0 = DEBUG, 1 = INFO, 2 = ERROR") + var confFilePath = flag.String("conf", "./conf.ini", "set path to configuration file") + flag.Parse() - // set log level + // set log level log.SetLevel(*logLevel) log.Info("Setting log level to %d", *logLevel) // load config and setup application log.Info("Loading configuration from file") - err := admin.ReadConfiguration(*confFilePath) - if err != nil { - log.Info("%s, no such file or directory", *confFilePath) - return - } + err := admin.ReadConfiguration(*confFilePath) + if err != nil { + log.Info("%s, no such file or directory", *confFilePath) + return + } // setup application @@ -59,37 +59,37 @@ func main() { // load addons log.Info("Loading addons") - // al momento del spegnimento dell'applicazione potremo trovarci con delle - // connessione attive dal parte del cliente. Il handler personalizzato usato - // qui, ci permette di dire al server di spegnersi ma prima deve aspettare - // che tutte le richieste siano processate e la connessione chiusa. - // - // Oltre al spegnimento sicuro il ServeMux permette di registra dei nuovi - // handler usando come descrizione anche il metodo http tipo GET o POST. - muxer := NewServeMux() + // al momento del spegnimento dell'applicazione potremo trovarci con delle + // connessione attive dal parte del cliente. Il handler personalizzato usato + // qui, ci permette di dire al server di spegnersi ma prima deve aspettare + // che tutte le richieste siano processate e la connessione chiusa. + // + // Oltre al spegnimento sicuro il ServeMux permette di registra dei nuovi + // handler usando come descrizione anche il metodo http tipo GET o POST. + muxer := NewServeMux() - // prepare server - server := &http.Server { - Addr: ":8081", - Handler: muxer, - } + // prepare server + server := &http.Server{ + Addr: ":8081", + Handler: muxer, + } - c := make(chan os.Signal, 1) - signal.Notify(c, syscall.SIGINT) + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGINT) - // aviamo in una nuova gorutine la funzione che ascolterà per il segnale di - // spegnimento del server - go muxer.getSignalAndClose(c) + // aviamo in una nuova gorutine la funzione che ascolterà per il segnale di + // spegnimento del server + go muxer.getSignalAndClose(c) // register handlers log.Info("Registering handlers") - // register with supervisor + // register with supervisor log.Info("Joining supervisor") // start server log.Info("Listening for requests") - log.Info("close server with message: %v", server.ListenAndServe()) + log.Info("close server with message: %v", server.ListenAndServe()) // inform supervisor that we are up From e85bb643f1ed61a01d1b3336e547bc19cfeba273 Mon Sep 17 00:00:00 2001 From: Scantlight Date: Thu, 31 Jan 2013 16:34:01 +0100 Subject: [PATCH 05/11] =?UTF-8?q?Al=20avvio=20dell'applicazione=20tutti=20?= =?UTF-8?q?i=20messaggi=20esistenti=20fino=20a=20quando=20il=20livello=20d?= =?UTF-8?q?el=20log=20viene=20cambiato=20da=20nul=20al=20valore=20passato?= =?UTF-8?q?=20nella=20riga=20di=20caomando,=20non=20vengono=20visualizzati?= =?UTF-8?q?.=20Perch=C3=A9=20il=20logger,=20appunto,=20ha=20un=20valore=20?= =?UTF-8?q?indefinito.=20Per=20risolvere=20questa=20situazione,=20impostia?= =?UTF-8?q?mo=20un=20valore=20di=20default=201=20(INFO)=20nel=20momento=20?= =?UTF-8?q?della=20dichiarazione=20del=20logger=20globale.=20var=20l=20log?= =?UTF-8?q?ger=20=3D=20logger{1}?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La funzione SetLevel non risponde più con un panico nel momento in quale il valore del log richiesto è fuori dalle limiti predefinite. Ma restituisce un errore che permette all'applicazione di chiudere in una maniera meno stressante per l'utente. --- log/log.go | 11 ++++++----- mapo.go | 6 +++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/log/log.go b/log/log.go index c196ed0..e15d353 100644 --- a/log/log.go +++ b/log/log.go @@ -23,6 +23,7 @@ Package log contains a simple multi-level logger. package log import ( + "errors" "fmt" "time" ) @@ -38,17 +39,17 @@ type logger struct { level int } -var l logger +var l logger = logger{1} // SetLevel sets the output level for the global logger -func SetLevel(level int) { +func SetLevel(level int) error { - if level <= DEBUG { + if level <= DEBUG && level >= ERROR { l.level = level - return + return nil } - panic(fmt.Sprintf("Unknown log level %v", level)) + return errors.New(fmt.Sprintf("Unknown log level %v", level)) } func print(level int, format string, v ...interface{}) { diff --git a/mapo.go b/mapo.go index 4fe9ca8..3f31667 100644 --- a/mapo.go +++ b/mapo.go @@ -36,8 +36,12 @@ func main() { flag.Parse() // set log level - log.SetLevel(*logLevel) log.Info("Setting log level to %d", *logLevel) + if err := log.SetLevel(*logLevel); err != nil { + log.SetLevel(0) + log.Error("%v", err) + return + } // load config and setup application log.Info("Loading configuration from file") From e193546d5d55a1c31c998206c7c6b25efa07092b Mon Sep 17 00:00:00 2001 From: Scantlight Date: Thu, 31 Jan 2013 19:59:17 +0100 Subject: [PATCH 06/11] Renamed gconf back to it's original name goconf code.google.com/p/goconf --- admin/admin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/admin.go b/admin/admin.go index de01598..18d1716 100644 --- a/admin/admin.go +++ b/admin/admin.go @@ -23,7 +23,7 @@ Package admin implements the API for Mapo's administration components. package admin import ( - "gconf/conf" + "goconf/conf" ) /* From 0494eac37659b795785ba48b495cadbdb658c63e Mon Sep 17 00:00:00 2001 From: Scantlight Date: Wed, 30 Jan 2013 15:21:41 +0100 Subject: [PATCH 07/11] database module --- db/db.go | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/db/db.go b/db/db.go index 0c097cc..4a9060e 100644 --- a/db/db.go +++ b/db/db.go @@ -22,3 +22,69 @@ Package db contains a data abstraction layer and underlying facilities to store entities in a database. */ package db + +import ( + "mapo/log" + + "labix.org/v2/mgo" + "labix.org/v2/mgo/bson" +) + +// un oggetto globale che contiene una connessione attiva con la database. +var database *mgo.Database + +// TODO: definire una funzione che si occupa con la creazione e gestione della +// connessione verso un database. +func NewConnection(databaseName string) error { + log.Debug("executing NewConnection function") + + session, err := mgo.Dial("localhost") + if err != nil { + log.Debug("error when connecting to database (%v)", err.Error()) + return err + } + + database = session.DB(databaseName) + return nil + // connessione alla data base avvenne usando diversi livelli di autenticazione +} + +// Store salva nella database un singolo oggetto +func Store(data interface{}, table string) error { + + c := database.C(table) + + err := c.Insert(data) + + return err +} + +// RestoreOne riprende dalla database un singolo oggetto identificato da un id +func RestoreOne(data interface{}, filter bson.M, table string) error { + + c := database.C(table) + + err := c.Find(filter).One(data) + + return err +} + +// RestoreList riprende dalla database una lista (tutti) di oggetti, senza alcun filtro +func RestoreList(data interface{}, filter bson.M, table string) error { + + c := database.C(table) + + err := c.Find(filter).All(data) + + return err +} + +// Update aggiorna i valori di un oggetto nella database, identificato da un id +func Update(data interface{}, id string, table string) error { + + c := database.C(table) + + err := c.Update(bson.M{"_id": id}, data) + + return err +} From e41b67326d1098c9b6ff3bbb3908747a1886024e Mon Sep 17 00:00:00 2001 From: Scantlight Date: Wed, 30 Jan 2013 15:33:40 +0100 Subject: [PATCH 08/11] Richiamato il modulo db nel modulo main durante la configurazione dell'applicazione. --- db/db.go | 3 +-- mapo.go | 31 ++++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/db/db.go b/db/db.go index 4a9060e..c16b32b 100644 --- a/db/db.go +++ b/db/db.go @@ -36,11 +36,10 @@ var database *mgo.Database // TODO: definire una funzione che si occupa con la creazione e gestione della // connessione verso un database. func NewConnection(databaseName string) error { - log.Debug("executing NewConnection function") + log.Info("executing NewConnection function") session, err := mgo.Dial("localhost") if err != nil { - log.Debug("error when connecting to database (%v)", err.Error()) return err } diff --git a/mapo.go b/mapo.go index 5f2ffbf..0953931 100644 --- a/mapo.go +++ b/mapo.go @@ -20,8 +20,9 @@ along with Mapo. If not, see . package main import ( - "mapo/admin" "mapo/log" + "mapo/admin" + "mapo/db" "flag" "net/http" @@ -59,6 +60,34 @@ func main() { // init db log.Info("Initializing db") + /* + in questa configurazione, connessione alla database viene attivata in un + oggetto definito globalmente al interno del modulo db. + L'idea originale per Mapo è di creare un oggetto che contenga la + connessione attiva e passare questo aggetto a tutte le funzione che ne + hanno bisogno di fare una richiesta alla database. + + Passare l'oggetto database da una funzione ad altra, potrebbe + significare, creare una catena dalla prima funzione all'ultima. Che + avvolte non fa niente altro che aumentare il numero dei parametri passati + da una funzione ad altra. Per esempio, la connessione al database si usa + nel modulo objectspace che viene chiamato dal modulo admin che al suo tempo + viene chiamato da main. Inutile passare questo oggetto al modulo admin, + visto che li lui non serve. + + NOTA: accesso ai oggetti globali deve essere in qualche modo sincronizzato + per evitare i problemi di inconsistenza. + + NOTA: le osservazioni dimostrano che avendo una connessione attiva alla + database che poi viene riutilizzata, diminuisce considerevolmente i tempi di + interrogazione. + */ + err = db.NewConnection("mapo") + if err != nil { + log.Error("%v", err) + return + } + // load addons log.Info("Loading addons") From d3b5e77a6192481dd99d817fe9b5cf880b30e1e9 Mon Sep 17 00:00:00 2001 From: Scantlight Date: Thu, 7 Feb 2013 19:48:23 +0100 Subject: [PATCH 09/11] Switched to log and conf module from utils repository. --- admin/admin.go | 23 ------------- log/log.go | 88 -------------------------------------------------- mapo.go | 40 ++++++++++++++--------- 3 files changed, 25 insertions(+), 126 deletions(-) delete mode 100644 log/log.go diff --git a/admin/admin.go b/admin/admin.go index 18d1716..feda89c 100644 --- a/admin/admin.go +++ b/admin/admin.go @@ -21,26 +21,3 @@ along with Mapo. If not, see . Package admin implements the API for Mapo's administration components. */ package admin - -import ( - "goconf/conf" -) - -/* -GlobalConfiguration, il oggetto globale per l'accesso ai dati contenuti nel -file di configurazione. -*/ -var GlobalConfiguration *conf.ConfigFile - -/* -ReadConfiguration, attiva il GlobalConfiguration. -*/ -func ReadConfiguration(filepath string) error { - - c, err := conf.ReadConfigFile(filepath) - if err == nil { - GlobalConfiguration = c - } - - return err -} diff --git a/log/log.go b/log/log.go deleted file mode 100644 index e15d353..0000000 --- a/log/log.go +++ /dev/null @@ -1,88 +0,0 @@ -/* -Copyright 2013 Petru Ciobanu, Francesco Paglia, Lorenzo Pierfederici - -This file is part of Mapo. - -Mapo 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 2 of the License, or -(at your option) any later version. - -Mapo 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 Mapo. If not, see . -*/ - -/* -Package log contains a simple multi-level logger. -*/ -package log - -import ( - "errors" - "fmt" - "time" -) - -// Available log levels -const ( - ERROR = iota - INFO - DEBUG -) - -type logger struct { - level int -} - -var l logger = logger{1} - -// SetLevel sets the output level for the global logger -func SetLevel(level int) error { - - if level <= DEBUG && level >= ERROR { - l.level = level - return nil - } - - return errors.New(fmt.Sprintf("Unknown log level %v", level)) -} - -func print(level int, format string, v ...interface{}) { - if level <= l.level { - var msgType string - - switch level { - case ERROR: - msgType = "ERROR" - case INFO: - msgType = "INFO" - case DEBUG: - msgType = "DEBUG" - } - - msg := fmt.Sprintf(format, v...) - t := time.Now().Format(time.RFC1123) - fmt.Printf("%s [%s]: %s\n", t, msgType, msg) - - } -} - -// Error logs a message at "ERROR" level -func Error(format string, v ...interface{}) { - print(ERROR, format, v...) -} - -// Info logs a message at "INFO" level -func Info(format string, v ...interface{}) { - print(INFO, format, v...) -} - -// Debug logs a message at "DEBUG" level -func Debug(format string, v ...interface{}) { - print(DEBUG, format, v...) -} diff --git a/mapo.go b/mapo.go index 3f31667..abee75c 100644 --- a/mapo.go +++ b/mapo.go @@ -20,39 +20,49 @@ along with Mapo. If not, see . package main import ( - "mapo/admin" - "mapo/log" + "github.com/maponet/utils/log" + "github.com/maponet/utils/conf" "flag" ) func main() { - log.Info("Starting application") + /* + parse flags - // parse flags - var logLevel = flag.Int("log", 1, "set message level eg: 0 = DEBUG, 1 = INFO, 2 = ERROR") + In some situation we will pass path to configuration file as a command line + value. This meaning that for first off all we need to define and parse all flags. + The only flag that we required on this step is only conf flag ... But we + can't distribute code with same functionality along file or files. + */ + var logLevel = log.FlagLevel("log") var confFilePath = flag.String("conf", "./conf.ini", "set path to configuration file") flag.Parse() - // set log level - log.Info("Setting log level to %d", *logLevel) - if err := log.SetLevel(*logLevel); err != nil { - log.SetLevel(0) + // load config and setup application + err := conf.ParseConfigFile(*confFilePath) + if err != nil { log.Error("%v", err) return } - // load config and setup application - log.Info("Loading configuration from file") - err := admin.ReadConfiguration(*confFilePath) - if err != nil { - log.Info("%s, no such file or directory", *confFilePath) - return + // setup configuration value passed as command line arguments + if len(*logLevel) > 0 { + conf.GlobalConfiguration.AddOption("default", "loglevel", *logLevel) } // setup application + // set log level + value, _ := conf.GlobalConfiguration.GetString("default", "loglevel") + if err := log.SetLevelString(value); err != nil { + log.Error("%v", err) + return + } + + log.Info("Starting application") + // register with supervisor log.Info("Joining supervisor") From 2cce02e6f31a2bfc6402167eb8eb1b3b23ee30b4 Mon Sep 17 00:00:00 2001 From: Scantlight Date: Thu, 7 Feb 2013 19:58:31 +0100 Subject: [PATCH 10/11] Sample of configuration file. --- conf.ini | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 conf.ini diff --git a/conf.ini b/conf.ini new file mode 100644 index 0000000..1cfd8c7 --- /dev/null +++ b/conf.ini @@ -0,0 +1,7 @@ +[default] +cookiesecret = some secrete phrase +mapohome = /mapo/root/folder + +[googleoauth] +clientid = client_id +clientsecret = client_secret From 63529cc77721bd30eeb3ecc482bb4ad19b3f673a Mon Sep 17 00:00:00 2001 From: Scantlight Date: Fri, 8 Feb 2013 01:27:33 +0100 Subject: [PATCH 11/11] Switch to log module from maponet/utils repository. --- mux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mux.go b/mux.go index 05547fb..ac85da4 100644 --- a/mux.go +++ b/mux.go @@ -20,7 +20,7 @@ along with Mapo. If not, see . package main import ( - "mapo/log" + "github.com/maponet/utils/log" "os" "sync"