// Inizializzare il server in ascolto per le Sincronizzazione delle conversazioni // // "laddress string" indica su quali indirizza ascoltare e su quale porta func StartServer(laddress string) { ln, err := net.Listen("tcp", laddress) logs.Log("Server in ascolto su: \"", laddress, "\"") if err != nil { logs.Error("Errore nell'aprire la connessione: ", err.Error()) return //TODO handle error } //database.MainConv = database.NewConversation(database.ServerFakeUser) //duplicato! //canale := make(chan byte, 256) codaReadiness := make(chan *Client, 64) codaAccettazioni := make(chan *Client, 64) logs.AggiungiAzioneDiChiusura(func() { close(codaReadiness) close(codaAccettazioni) }) go spedisci(codaAccettazioni, codaReadiness) var spegniti bool = false logs.AggiungiAzioneDiChiusura(func() { spegniti = true ln.Close() }) for !spegniti { conn, err := ln.Accept() if spegniti { return } if err != nil { //TODO fare un pacchetto per la raccolta degli errori logs.Error("Tentativo di connessione non andato a buon fine: ", err.Error()) } go func() { client, gestore := GestisciClient(conn) if client != nil { go gestore(codaReadiness) codaAccettazioni <- client } else { //L'handshaking non è andato a buon fine conn.Close() } }() } }
// Inizializza tutte le operazioni necessarie per sul database func init() { logs.Log("init del database") ServerFakeUser = new(User) ServerFakeUser.ID = 0 ServerFakeUser.Username = "******" serverPassword := sha256.New() serverPassword.Write([]byte("toor")) ServerFakeUser.password = serverPassword.Sum([]byte{}) err := CreateDataBaseSQL() if err != nil { logs.Error(err.Error()) } // MainConv = NewConversation(ServerFakeUser) err = Data.caricaConversazioni() if err != nil { logs.Error("Impossibile caricare le conversazioni vecchie\nmotivo: ", err.Error()) } // err = salvaUtente(ServerFakeUser) // if err != nil { // logs.Error("Impossibile salvare l'utente server nel database\nmotivo: ", err.Error()) // }() Data.CaricaUtentiSQL() if err != nil { logs.Error("Impossibile caricare gli utenti dal database\nmotivo: ", err.Error()) } go func() { var spegniti bool = false logs.AggiungiAzioneDiChiusura(func() { spegniti = true }) tk := time.NewTicker(10 * time.Minute) for !spegniti { <-tk.C err := MainConv.salvaTutteLeConversazioniSQL() if err != nil { logs.Error("Impossibile salvare tutti i post\nmotivo: ", err.Error()) } logs.Log("salvate tutte le conversazioni sul database") //err := MainConv.salvaTuttiIPostSQL(&Data) //if err != nil { // logs.Error("Impossibile salvare tutti i post\nmotivo: ", err.Error()) //} } tk.Stop() }() }
// Inizializza la struttura dati del client e crea la funzione per gestire il client // (da partire come goroutine) func GestisciClient(conn net.Conn) (*Client, func(chan *Client)) { fmt.Print("Nuova connessione: ") fmt.Println(conn.RemoteAddr()) client := NewClient(&conn) if client == nil { conn.Close() return nil, nil } return client, func(readiness chan *Client) { var spegniti bool = false logs.AggiungiAzioneDiChiusura(func() { spegniti = true }) for !spegniti { _, size, err := client.stream.ReadRune() if err != nil { logs.Error("connessione interrotta: ", conn.RemoteAddr().String(), "\n\tmotivazione: ", err.Error()) client.gestisciDisconnessione(database.MainConv) return } // for i := 0; i < size; i++ { fmt.Printf("letto carattere di %v byte\n", size) err = client.stream.UnreadRune() if err != nil { logs.Error("impossibile fare UnreadByte: ", conn.RemoteAddr().String(), "\n\tmotivazione: ", err.Error()) client.gestisciDisconnessione(database.MainConv) return } // } readiness <- client <-client.blocco } (*client.conn).Close() } }
// Funzione che innesta tutta la procedura per il parsing di quello ricevuto // dai client. //TODO migliora la documentazione func flasher(codaCiclica *list.List, readiness chan *Client) { tempoDaAspettare := 30 * time.Millisecond var lastActiveUser int = -1 input := make(chan rune, 256) output := make(chan string, 256) logs.AggiungiAzioneDiChiusura(func() { close(input) close(output) }) go gestisciTestoConversazione(input, output) // semplice funzione che rispedisce tutto quello che passa // dal canale di output sui socket delle connessioni go func() { for buffer := range output { for e := codaCiclica.Front(); e != nil; e = e.Next() { client := e.Value.(*Client) client.stream.WriteString(buffer) client.stream.Flush() } } }() var spegniti bool = false logs.AggiungiAzioneDiChiusura(func() { spegniti = true }) for !spegniti { start := time.Now() quanti := len(readiness) for i := 0; i < quanti; i++ { clientAttivo := <-readiness var chiSonoString string if lastActiveUser != clientAttivo.user.ID { chiSonoString = strings.Join([]string{"\\U", strconv.Itoa(clientAttivo.user.ID), "\\"}, "") lastActiveUser = clientAttivo.user.ID database.MainConv.UtenteAttivo = lastActiveUser } else { chiSonoString = "" } chiSonoSSize := len(chiSonoString) //leggi cosa spedire var daLeggere int = clientAttivo.stream.Reader.Buffered() buffer := make([]rune, chiSonoSSize, daLeggere+chiSonoSSize) var err error var letto rune var size, i, j int for i, j = chiSonoSSize, 0; i < chiSonoSSize+daLeggere && j < daLeggere; i++ { letto, size, err = clientAttivo.stream.ReadRune() buffer = append(buffer, letto) j += size //fmt.Printf("#####size:_%v_ carattere:_%v_%v_\n",strconv.Itoa(size),string(buffer[i]),buffer[i]) if err != nil { //TODO gestisci errore logs.Error("Errore nel leggere dalla rete") clientAttivo.blocco <- 1 //TODO dovresti chiudere il canale e tutto quanto clientAttivo.gestisciDisconnessione(database.MainConv) break } } clientAttivo.blocco <- 0 //prepara il buffer da spedire for i := 0; i < chiSonoSSize; i++ { buffer[i] = []rune(chiSonoString)[i] } // buffer = buffer[:i] //spedisci for i := 0; i < len(buffer); i++ { input <- buffer[i] } } duration := time.Since(start) if duration <= tempoDaAspettare { time.Sleep(tempoDaAspettare - duration) } } }
// Funzione che inizializza tutte le cose necessarie per collegare il // database SQL, e lo collega func CreateDataBaseSQL() error { var err error db, err = sql.Open("postgres", "dbname=thinkzoneDB user=thinkzone") if err != nil { logs.Error("Impossibile aprire il database") return err } /* for i := range createDbSqlScript { _, err = db.Exec(createDbSqlScript[i]) if err != nil { if "result error: ERROR: relation \"t_user\" already exists\n" != err.Error() { logs.Error("Impossibile creare le tabelle del database\nmotivo: _", err.Error(), "_") return err } break } } */ insertUserOp, err = db.Prepare(insertUser) if err != nil { // logs.Error("Impossibile salvare gli utenti nel database\nmotivo: ", err.Error()) return err } insertPostOp, err = db.Prepare(insertPost) if err != nil { // logs.Error("Impossibile creare i post nel database\nmotivo: ", err.Error()) return err } updatePostOp, err = db.Prepare(updatePost) if err != nil { // logs.Error("Impossibile salvare i post nel database\nmotivo: ", err.Error()) return err } insertConvOp, err = db.Prepare(insertConv) if err != nil { // logs.Error("Impossibile salvare le conversazioni nel database\nmotivo: ", err.Error()) return err } updateConvOp, err = db.Prepare(updateConv) if err != nil { return err } logs.AggiungiAzioneDiChiusura(func() { if insertUserOp != nil { insertUserOp.Close() } if insertConvOp != nil { err := MainConv.salvaTutteLeConversazioniSQL() if err != nil { logs.Error("Impossibile salvare tutti i post\nmotivo: ", err.Error()) } insertConvOp.Close() } if insertPostOp != nil { insertPostOp.Close() } if updatePostOp != nil { updatePostOp.Close() } if updateConvOp != nil { updateConvOp.Close() } return }) return nil }