package main import ( "backend/config" "backend/parser" "backend/typesdefs" "backend/utils" "fmt" "log" "reflect" "regexp" "slices" "strconv" "strings" "time" ) type MiogestHandler struct { Caratterisiche typesdefs.ListaCaratteristiche Categorie []typesdefs.Categoria AnnunciXML typesdefs.AnnunciXML AnnunciParsed typesdefs.AnnunciParsed annunci_cache_expires time.Time vars_cache_expires time.Time } func NewMiogestHandler() *MiogestHandler { return &MiogestHandler{ Caratterisiche: typesdefs.ListaCaratteristiche{}, Categorie: nil, AnnunciXML: typesdefs.AnnunciXML{}, AnnunciParsed: typesdefs.AnnunciParsed{}, annunci_cache_expires: time.Now(), vars_cache_expires: time.Now(), } } // ANNUNCI FROM MIOGEST func (m *MiogestHandler) GetAnnunci() (typesdefs.AnnunciXML, error) { if len(m.AnnunciXML.Annuncio) == 0 || time.Now().After(m.annunci_cache_expires) { err := m.GetAnnunciFromMiogest() if err != nil { return typesdefs.AnnunciXML{}, err } } return m.AnnunciXML, nil } func (m *MiogestHandler) GetAnnunciFromMiogest() error { maxRetries := 3 baseDelay := 10 * time.Second for attempt := range maxRetries { var err error m.AnnunciXML, err = utils.GetDataXML[typesdefs.AnnunciXML]("http://partner.miogest.com/agenzie/infoalloggi.xml") if err == nil { // Success - validate we got data if len(m.AnnunciXML.Annuncio) > 0 { m.annunci_cache_expires = time.Now().Add(1 * time.Hour) return nil } log.Printf("Warning: Successfully fetched XML but got 0 annunci") } // Log the specific error type if err != nil { log.Printf("Failed to get annunci (attempt %d/%d): %v", attempt+1, maxRetries, err) } // Failed - check if we should retry if attempt < maxRetries-1 { delay := baseDelay * time.Duration(1< bestPriority { bestPriority = p best = i } } return best, true } func processLocatore(tmp *typesdefs.AnnuncioParsed, annuncio *typesdefs.AnnuncioXML) { idx, ok := selectTargetCliente(annuncio) if !ok { log.Printf("Annuncio %s has no client information", utils.GetStringValue(annuncio.Codice)) return } trg := annuncio.Clienti[idx] tmp.Email = parser.ParseEmail(trg.Email1) var number string for _, tel := range []*string{trg.Tel1, trg.Tel2, trg.Tel3} { if tel != nil { cleanedTel := re.ReplaceAllString(*tel, "") if cleanedTel != "" { number = cleanedTel break } } } tmp.Numero = &number if trg.Cognome != nil && trg.Nome != nil { rawLoc := fmt.Sprintf("%s %s", utils.MakeUppercase(*trg.Cognome), utils.MakeUppercase(*trg.Nome)) rawLoc = strings.TrimSpace(rawLoc) rawLoc = regexp.MustCompile(`\s+`).ReplaceAllString(rawLoc, " ") // Replace multiple spaces with a single space tmp.Locatore = strUpd(rawLoc) } tmp.Idlocatore = trg.Id tmp.Tipo_locatore = strUpd(flatClienteTipologia(trg.Tipologie)) } func processIndirizzo(tmp *typesdefs.AnnuncioParsed, annuncio *typesdefs.AnnuncioXML) { tmp.Indirizzo = strUpd(utils.MakeUppercase(utils.GetStringValue(annuncio.Indirizzo))) tmp.Civico = annuncio.Civico tmp.Comune = strUpd(utils.MakeUppercase(utils.GetStringValue(annuncio.Comune))) tmp.Cap = annuncio.Cap tmp.Provincia = annuncio.Provincia tmp.Regione = annuncio.Regione tmp.Lat = annuncio.Latitudine tmp.Lon = annuncio.Longitudine tmp.Indirizzo_secondario = strUpd(utils.MakeUppercase(utils.GetStringValue(annuncio.IndirizzoSecondario))) tmp.Civico_secondario = annuncio.CivicoSecondario tmp.Lat_secondario = annuncio.LatitudineSecondario tmp.Lon_secondario = annuncio.LongitudineSecondario } func processCategorie(tmp *typesdefs.AnnuncioParsed, annuncio *typesdefs.AnnuncioXML, m *MiogestHandler) { if annuncio.Categoria == nil { return } resultArray := make([]string, 0) cats := *annuncio.Categoria defaultCategorie := m.GetCategorie() for _, cat := range cats { for _, catdef := range defaultCategorie { if cat == catdef.Id { resultArray = append(resultArray, catdef.Nome) } } } if tmp.Categorie == nil { tmp.Categorie = &[]string{} } *tmp.Categorie = resultArray } func processDatiImmobile(tmp *typesdefs.AnnuncioParsed, annuncio *typesdefs.AnnuncioXML) { tmpanno := utils.GetStringValue(annuncio.Anno) if tmpanno != "0" && tmpanno != "" { tmp.Anno = &tmpanno } tmp.Prezzo = parser.ParsePrezzo(annuncio.Prezzo) tmp.Classe = annuncio.Classe if annuncio.Mq != nil { replaced := strings.ReplaceAll(*annuncio.Mq, ",", ".") if s, err := strconv.ParseFloat(replaced, 64); err == nil { tmp.Mq = &s } } tmp.Piano = annuncio.Piano tmp.Piano_palazzo = annuncio.PianiCondominio tmp.Unita_condominio = annuncio.UnitaCondominio tmp.Numero_vani = annuncio.Vani tmp.Numero_camere = annuncio.Camere tmp.Numero_bagni = annuncio.Bagni tmp.Numero_balconi = annuncio.Balconi tmp.Numero_terrazzi = annuncio.Terrazzi tmp.Numero_box = annuncio.Box tmp.Numero_postiauto = annuncio.PostiAuto } func parseCaratteristiche(wrkrecord *typesdefs.AnnuncioXML, m *MiogestHandler) map[string]interface{} { if reflect.TypeOf(wrkrecord).Kind() != reflect.Ptr || reflect.ValueOf(wrkrecord).Elem().Kind() != reflect.Struct { return nil } tmpCaratteristiche := make(map[string]interface{}) val := reflect.ValueOf(wrkrecord).Elem() numField := val.NumField() for i := 0; i < numField; i++ { if strings.HasPrefix(val.Type().Field(i).Name, "Scheda_") { nameField := val.Type().Field(i).Name valueField := val.Field(i) if valueField.IsValid() && !valueField.IsNil() { tmpCaratteristiche[nameField] = valueField.Interface() } else { tmpCaratteristiche[nameField] = nil } } } for _, scheda := range m.GetCaratteristiche().Caratteristiche { if _, ok := tmpCaratteristiche[scheda.Tagxml]; !ok { tmpCaratteristiche[scheda.Tagxml] = nil } } return tmpCaratteristiche }