diff --git a/plattform/synapse/.air.toml b/plattform/synapse/.air.toml new file mode 100644 index 0000000..afe5918 --- /dev/null +++ b/plattform/synapse/.air.toml @@ -0,0 +1,52 @@ +root = "." +testdata_dir = "testdata" +tmp_dir = "tmp" + +[build] + args_bin = [] + bin = "./tmp/main" + cmd = "go build -o ./tmp/main ./cmd/synapse" + delay = 1000 + exclude_dir = ["assets", "tmp", "vendor", "testdata"] + exclude_file = [] + exclude_regex = ["_test.go"] + exclude_unchanged = false + follow_symlink = false + full_bin = "" + include_dir = [] + include_ext = ["go", "tpl", "tmpl", "html"] + include_file = [] + kill_delay = "0s" + log = "build-errors.log" + poll = false + poll_interval = 0 + post_cmd = [] + pre_cmd = [] + rerun = false + rerun_delay = 500 + send_interrupt = false + stop_on_error = false + +[color] + app = "" + build = "yellow" + main = "magenta" + runner = "green" + watcher = "cyan" + +[log] + main_only = false + silent = false + time = false + +[misc] + clean_on_exit = false + +[proxy] + app_port = 0 + enabled = false + proxy_port = 0 + +[screen] + clear_on_rebuild = false + keep_scroll = true diff --git a/plattform/synapse/cmd/synapse/main.go b/plattform/synapse/cmd/synapse/main.go new file mode 100644 index 0000000..d53fc11 --- /dev/null +++ b/plattform/synapse/cmd/synapse/main.go @@ -0,0 +1,31 @@ +package main + +import ( + "flag" + "os" + "synapse/internal/connector" +) + +type config struct { + dispoliveApiKey string +} + +func main() { + var cfg config + // ctx := context.Background() + + flag.StringVar(&cfg.dispoliveApiKey, "dispolive-key", os.Getenv("DISPOLIVE_API_KEY"), "DispoLive Api Key") + flag.Parse() + + dlds := new(connector.DispoliveLegacyDataSource) + dlds.Login() + // rawData, err := dlds.Read(ctx) + // if err != nil { + // panic(err.Error()) + // } + // tData, err := transformer.TransformTourData(rawData) + // if err != nil { + // panic(err.Error()) + // } + // println(len(rawData), len(tData)) +} diff --git a/plattform/synapse/go.mod b/plattform/synapse/go.mod new file mode 100644 index 0000000..856cb10 --- /dev/null +++ b/plattform/synapse/go.mod @@ -0,0 +1,3 @@ +module synapse + +go 1.23.2 diff --git a/plattform/synapse/internal/connector/connector.go b/plattform/synapse/internal/connector/connector.go new file mode 100644 index 0000000..34f1132 --- /dev/null +++ b/plattform/synapse/internal/connector/connector.go @@ -0,0 +1,13 @@ +package connector + +import "time" + +type DataSource interface { + Read() ([]byte, error) +} + +var backoffSchedule = []time.Duration{ + 1 * time.Second, + 3 * time.Second, + 10 * time.Second, +} diff --git a/plattform/synapse/internal/connector/dispolive-connector.go b/plattform/synapse/internal/connector/dispolive-connector.go new file mode 100644 index 0000000..57b3dd8 --- /dev/null +++ b/plattform/synapse/internal/connector/dispolive-connector.go @@ -0,0 +1,43 @@ +package connector + +import ( + "context" + "fmt" + "io" + "net/http" + "os" + "time" +) + +type DispoliveDataSource struct { +} + +func (dc *DispoliveDataSource) Read(ctx context.Context) ([]byte, error) { + ctxWithTimeout, cancel := context.WithTimeout(ctx, 1000*time.Millisecond) + defer cancel() + + key := os.Getenv("DISPOLIVE_API_KEY") + if key == "" { + return []byte{}, fmt.Errorf("couldn't perform request: Dispolive API key not found") + } + + req, err := http.NewRequestWithContext(ctxWithTimeout, "GET", "https://avicenna.dispolive.de/custom/open-api/fahrberichte/findByRange/2025-06-20_2025-06-21", nil) + if err != nil { + return []byte{}, fmt.Errorf("couldn't construct the request: %w", err) + } + req.Header.Set("Authorization", "Bearer "+key) + req.Header.Set("dispolive-api-version", "v1.0.1") + + client := &http.Client{} + res, err := client.Do(req) + if err != nil { + return []byte{}, fmt.Errorf("request returned an error: %w", err) + } + body, err := io.ReadAll(res.Body) + res.Body.Close() + if err != nil { + return []byte{}, fmt.Errorf("couldn't read body: %w", err) + } + + return body, nil +} diff --git a/plattform/synapse/internal/connector/dispolive-legacy-connector.go b/plattform/synapse/internal/connector/dispolive-legacy-connector.go new file mode 100644 index 0000000..d880124 --- /dev/null +++ b/plattform/synapse/internal/connector/dispolive-legacy-connector.go @@ -0,0 +1,88 @@ +package connector + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "strings" + "time" +) + +const dispoliveBaseUrl = "https://avicenna.dispolive.de" + +type DispoliveLegacyDataSource struct{} + +func (dc *DispoliveLegacyDataSource) Read(ctx context.Context) ([]byte, error) { + ctxWithTimeout, cancel := context.WithTimeout(ctx, 1000*time.Millisecond) + defer cancel() + + key := os.Getenv("DISPOLIVE_API_KEY") + if key == "" { + return []byte{}, fmt.Errorf("couldn't perform request: Dispolive API key not found") + } + + req, err := http.NewRequestWithContext(ctxWithTimeout, "GET", "https://avicenna.dispolive.de/custom/open-api/fahrberichte/findByRange/2025-06-20_2025-06-21", nil) + if err != nil { + return []byte{}, fmt.Errorf("couldn't construct the request: %w", err) + } + req.Header.Set("Authorization", "Bearer "+key) + req.Header.Set("dispolive-api-version", "v1.0.1") + + client := &http.Client{} + res, err := client.Do(req) + if err != nil { + return []byte{}, fmt.Errorf("request returned an error: %w", err) + } + body, err := io.ReadAll(res.Body) + res.Body.Close() + if err != nil { + return []byte{}, fmt.Errorf("couldn't read body: %w", err) + } + + return body, nil +} + +func (dc *DispoliveLegacyDataSource) Login() (string, error) { + username := os.Getenv("DISPOLIVE_USERNAME") + password := os.Getenv("DISPOLIVE_PASSWORD") + if username == "" || password == "" { + return "", fmt.Errorf("authentication not possible, no username or password") + } + return dc.login(username, password) +} + +func (dc *DispoliveLegacyDataSource) login(username, password string) (string, error) { + ctxWithTimeout, cancel := context.WithTimeout(context.TODO(), 1000*time.Millisecond) + defer cancel() + + payload := map[string]string{"username": username, "password": password} + jsonPayload, _ := json.Marshal(payload) + req, err := http.NewRequestWithContext(ctxWithTimeout, "POST", dispoliveBaseUrl+"/login", bytes.NewBuffer(jsonPayload)) + if err != nil { + return "", fmt.Errorf("couldn't construct the request: %w", err) + } + req.Header.Set("Content-Type", "application/json") + res, err := http.DefaultClient.Do(req) + if err != nil { + return "", fmt.Errorf("request returned an error: %w", err) + } + + cookies := res.Header.Values("set-cookie") + + cookieString := strings.Split(strings.Join(cookies, ";"), ";") + var authCookies = "" + for _, v := range cookieString { + if strings.Contains(v, "koa.sid") { + if authCookies == "" { + authCookies = v + } else { + authCookies = strings.Join([]string{authCookies, v}, "; ") + } + } + } + return authCookies, nil +} diff --git a/plattform/synapse/internal/transformer/transformer.go b/plattform/synapse/internal/transformer/transformer.go new file mode 100644 index 0000000..7e3401f --- /dev/null +++ b/plattform/synapse/internal/transformer/transformer.go @@ -0,0 +1,7 @@ +package transformer + +import "synapse/pkg/model" + +func TransformTourData(rawData []byte) ([]model.TransformedTourModel, error) { + return []model.TransformedTourModel{}, nil +} diff --git a/plattform/synapse/pkg/model/api-tour-model.go b/plattform/synapse/pkg/model/api-tour-model.go new file mode 100644 index 0000000..82eecd4 --- /dev/null +++ b/plattform/synapse/pkg/model/api-tour-model.go @@ -0,0 +1,186 @@ +package model + +import "time" + +type ApiTourModel struct { + _ID string `json:"_id"` + Abrechnung struct { + Tarife []struct { + ID string `json:"_id"` + AbKm string `json:"abKm"` + Fahrtart []string `json:"fahrtart"` + KmBesetzt string `json:"kmBesetzt"` + PosNr string `json:"posNr"` + PosText string `json:"posText"` + Preis string `json:"preis"` + Tarif string `json:"tarif"` + TarifBerechnung string `json:"tarifBerechnung"` + TarifFrom string `json:"tarifFrom"` + TarifTo string `json:"tarifTo"` + VertragsID string `json:"vertragsId"` + VertragName string `json:"vertragName"` + TarifCheck int `json:"tarifCheck"` + Faktor int `json:"faktor"` + GesamtPosPreis string `json:"gesamtPosPreis"` + Linie int `json:"linie,omitempty"` + PlzArt string `json:"plzArt,omitempty"` + Transportart []string `json:"transportart,omitempty"` + BisUhrzeit string `json:"bisUhrzeit,omitempty"` + Di int `json:"di,omitempty"` + Do int `json:"do,omitempty"` + Fr int `json:"fr,omitempty"` + Mi int `json:"mi,omitempty"` + Mo int `json:"mo,omitempty"` + NoFeiertagVertrag int `json:"noFeiertagVertrag,omitempty"` + UhrzeitVertrag int `json:"uhrzeitVertrag,omitempty"` + VonUhrzeit string `json:"vonUhrzeit,omitempty"` + WochentagVertrag int `json:"wochentagVertrag,omitempty"` + Sa int `json:"sa,omitempty"` + So int `json:"so,omitempty"` + } `json:"tarife"` + } `json:"abrechnung"` + AuftraggeberCity string `json:"auftraggeberCity"` + AuftraggeberID string `json:"auftraggeberId"` + AuftraggeberInfo string `json:"auftraggeberInfo"` + AuftraggeberLand string `json:"auftraggeberLand"` + AuftraggeberName string `json:"auftraggeberName"` + AuftraggeberStreet string `json:"auftraggeberStreet"` + AuftraggeberSurname string `json:"auftraggeberSurname"` + AuftraggeberTelefon string `json:"auftraggeberTelefon"` + AuftraggeberZip string `json:"auftraggeberZip"` + AusrueckZeit string `json:"ausrueckZeit"` + BesetztKm float64 `json:"besetztKm"` + Birthday string `json:"birthday"` + Check string `json:"check"` + Color string `json:"color"` + CostStatus string `json:"costStatus"` + CreateTime string `json:"createTime"` + Date string `json:"date"` + DateIso time.Time `json:"date_iso"` + Direction string `json:"direction"` + DistanceDurationText string `json:"distanceDurationText"` + DistanceDurationValue int `json:"distanceDurationValue"` + DistanceStartWacheDurationValue int `json:"distanceStartWacheDurationValue"` + DistanceTargetWacheDurationValue int `json:"distanceTargetWacheDurationValue"` + DistanceText string `json:"distanceText"` + DistanceValue int `json:"distanceValue"` + EaSum string `json:"eaSum"` + Eigenanteil string `json:"eigenanteil"` + EinsatzNummer string `json:"einsatzNummer"` + EndTime string `json:"endTime"` + EndDate string `json:"end_date"` + EventLength string `json:"event_length"` + EventPid string `json:"event_pid"` + FirmName string `json:"firmName"` + Frei string `json:"frei"` + FreiTrigger int `json:"freiTrigger"` + Gefahren int `json:"gefahren"` + GefahreneFirma string `json:"gefahreneFirma"` + GefahreneKm string `json:"gefahreneKm"` + GesamtPreis float64 `json:"gesamtPreis"` + KkID string `json:"kkId"` + Krankenkasse string `json:"krankenkasse"` + LeerKm string `json:"leerKm"` + Materialfahrt bool `json:"materialfahrt"` + Month string `json:"month"` + Mwst int `json:"mwst"` + NettoPreis interface{} `json:"nettoPreis"` + PatCity string `json:"patCity"` + PatKasse string `json:"patKasse"` + PatName string `json:"patName"` + PatStreet string `json:"patStreet"` + PatSurname string `json:"patSurname"` + PatZip string `json:"patZip"` + PatientenLand string `json:"patientenLand"` + PreisBoEA float64 `json:"preisBoEA"` + PreisBrutto float64 `json:"preisBrutto"` + PreisEA int `json:"preisEA"` + PreisNetto float64 `json:"preisNetto"` + PreisSteuer int `json:"preisSteuer"` + RecPattern string `json:"rec_pattern"` + RecType string `json:"rec_type"` + SerienKategorName string `json:"serienKategorName"` + SerienKategorie string `json:"serienKategorie"` + Sonderleistungen []string `json:"sonderleistungen"` + StartBegin string `json:"startBegin"` + StartCity string `json:"startCity"` + StartEnd string `json:"startEnd"` + StartInfo string `json:"startInfo"` + StartInst interface{} `json:"startInst"` + StartInstitution string `json:"startInstitution"` + StartLat float64 `json:"startLat"` + StartLng float64 `json:"startLng"` + StartStreet string `json:"startStreet"` + StartTime string `json:"startTime"` + StartTimeArr []struct { + StartTime string `json:"startTime"` + SetDate string `json:"setDate"` + } `json:"startTimeArr"` + StartTimeBis string `json:"startTimeBis"` + StartZip string `json:"startZip"` + StartDate string `json:"start_date"` + TargetCity string `json:"targetCity"` + TargetInfo string `json:"targetInfo"` + TargetInstitution string `json:"targetInstitution"` + TargetLat float64 `json:"targetLat"` + TargetLng float64 `json:"targetLng"` + TargetStreet string `json:"targetStreet"` + TargetZip string `json:"targetZip"` + Termin bool `json:"termin"` + TransVorhanden string `json:"transVorhanden"` + TransportKrz string `json:"transportKrz"` + TransportName string `json:"transportName"` + Transportart string `json:"transportart"` + Type string `json:"type"` + VerordnungsID string `json:"verordnungsId"` + VerordnungsName string `json:"verordnungsName"` + VersNr string `json:"versNr"` + VersTName string `json:"versTName"` + VersType string `json:"versType"` + Ziel string `json:"ziel"` + ZielBegin string `json:"zielBegin"` + CarPlan string `json:"carPlan"` + PatientenHandy string `json:"patientenHandy"` + PatientenTelefon string `json:"patientenTelefon"` + CarName string `json:"carName"` + CarNo string `json:"carNo"` + Kennzeichen string `json:"kennzeichen"` + KeyFahrzeug string `json:"keyFahrzeug"` + SendStatusArrived bool `json:"sendStatusArrived"` + SendStatusRead bool `json:"sendStatusRead"` + Eday int `json:"_eday"` + FirstChunk bool `json:"_first_chunk"` + LastChunk bool `json:"_last_chunk"` + Length int `json:"_length"` + Sday int `json:"_sday"` + Sorder int `json:"_sorder"` + Sweek int `json:"_sweek"` + Timed bool `json:"_timed"` + ID string `json:"id"` + LadezeitMin int `json:"ladezeitMin"` + WatchDogAlert bool `json:"watchDogAlert"` + Endgen string `json:"endgen"` + GenAusstellungsDatum string `json:"genAusstellungsDatum"` + Startgen string `json:"startgen"` + VerordnungAusstellungsDatum string `json:"verordnungAusstellungsDatum"` + ZuzahlungBis string `json:"zuzahlungBis"` + ZuzahlungVon string `json:"zuzahlungVon"` + AppStatusKrz string `json:"appStatusKrz"` + Beifahrer string `json:"beifahrer"` + BeifahrerKrz string `json:"beifahrerKrz"` + BeifahrerName string `json:"beifahrerName"` + Fahrer string `json:"fahrer"` + FahrerKrz string `json:"fahrerKrz"` + FahrerName string `json:"fahrerName"` + DT string `json:"DT"` + AbrDate string `json:"abrDate"` + AbrNum string `json:"abrNum"` + AbrTime string `json:"abrTime"` + SendStatus struct { + Type string `json:"type"` + Date string `json:"date"` + } `json:"sendStatus"` + ZadStatus string `json:"zadStatus"` + Auftraggebercoop bool `json:"auftraggebercoop"` + Nomeet bool `json:"nomeet"` +} diff --git a/plattform/synapse/pkg/model/transformed-tour-model.go b/plattform/synapse/pkg/model/transformed-tour-model.go new file mode 100644 index 0000000..f69a99c --- /dev/null +++ b/plattform/synapse/pkg/model/transformed-tour-model.go @@ -0,0 +1,56 @@ +package model + +import "time" + +type TransformedTourModel struct { + ID string `json:"id"` + Done bool `json:"done"` + Direction string `json:"direction"` + CarName string `json:"carName"` + OperationID string `json:"operationId"` + DriverID string `json:"driverId"` + DriverName string `json:"driverName"` + CodriverID string `json:"codriverId"` + CodriverName string `json:"codriverName"` + PatientID string `json:"patientId"` + PatientName string `json:"patientName"` + PatientSurname string `json:"patientSurname"` + PatientStreet string `json:"patientStreet"` + PatientZip string `json:"patientZip"` + PatientCity string `json:"patientCity"` + HealthInsurance string `json:"healthInsurance"` + HealthInsuranceNumber string `json:"healthInsuranceNumber"` + Type string `json:"type"` + Category string `json:"category"` + TransportType string `json:"transportType"` + OrdinanceType string `json:"ordinanceType"` + RangeEndDate time.Time `json:"rangeEndDate"` + StartInstitution string `json:"startInstitution"` + StartStreet string `json:"startStreet"` + StartZip string `json:"startZip"` + StartCity string `json:"startCity"` + TargetInstitution string `json:"targetInstitution"` + TargetStreet string `json:"targetStreet"` + TargetZip string `json:"targetZip"` + TargetCity string `json:"targetCity"` + StartDate time.Time `json:"startDate"` + Check int `json:"check"` + OccupiedKm float64 `json:"occupiedKm"` + TotalKm float64 `json:"totalKm"` + StartBegin string `json:"startBegin"` + StartEnd string `json:"startEnd"` + Target string `json:"target"` + TargetBegin string `json:"targetBegin"` + Empty string `json:"empty"` + HasInfection bool `json:"hasInfection"` + InfectionName string `json:"infectionName"` + RevenueDispoLive float64 `json:"revenueDispoLive"` + BillDate time.Time `json:"billDate"` + BillNumber string `json:"billNumber"` + Revenue float64 `json:"revenue"` + ConsumptionCosts float64 `json:"consumptionCosts"` + RevenueDeviation float64 `json:"revenueDeviation"` + CreatedAt time.Time `json:"createdAt"` + DeletedAt time.Time `json:"deletedAt"` + TicketID string `json:"ticketId"` +} diff --git a/plattform/synapse/synapse b/plattform/synapse/synapse new file mode 100755 index 0000000..d680d65 Binary files /dev/null and b/plattform/synapse/synapse differ diff --git a/plattform/synapse/tmp/build-errors.log b/plattform/synapse/tmp/build-errors.log new file mode 100644 index 0000000..0913c77 --- /dev/null +++ b/plattform/synapse/tmp/build-errors.log @@ -0,0 +1 @@ +exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file diff --git a/plattform/synapse/tmp/main b/plattform/synapse/tmp/main new file mode 100755 index 0000000..952340f Binary files /dev/null and b/plattform/synapse/tmp/main differ