package main import ( "context" "fmt" "log" "regexp" "google.golang.org/grpc" "gorm.io/gorm" "whiteboxsystems.nl/openkvpoc/his/model" "whiteboxsystems.nl/openkvpoc/openkv" "whiteboxsystems.nl/openkvpoc/sharedmodel" ) const CONN_PSK = "0000" func getUnauthenticatedClient(addr string) (openkv.OpenKVClient, error) { opts := []grpc.DialOption{ grpc.WithInsecure(), // dont do this in any production env... } conn, err := grpc.Dial(addr, opts...) if err != nil { return nil, err } // defer conn.Close() return openkv.NewOpenKVClient(conn), nil } func getAuthenticatedClient(addr, psk string) (openkv.OpenKVClient, error) { opts := []grpc.DialOption{ grpc.WithPerRPCCredentials(makePSKAuth(psk, true)), grpc.WithInsecure(), // dont do this in any production env... } conn, err := grpc.Dial(addr, opts...) if err != nil { return nil, err } // defer conn.Close() return openkv.NewOpenKVClient(conn), nil } type PSKAuth struct { psk string insecure bool } func (ma PSKAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) { return map[string]string{ "authorization": ma.psk, }, nil } func (ma PSKAuth) RequireTransportSecurity() bool { return !ma.insecure } func makePSKAuth(psk string, insecure bool) *PSKAuth { return &PSKAuth{psk, insecure} } func (srv *HISServer) register(addr string) (*model.Connection, error) { client, err := getUnauthenticatedClient(addr) if err != nil { return nil, err } auth := &openkv.AuthConfig{ Method: openkv.AuthMethod_APIToken, Config: &openkv.AuthConfig_ApiTokenConfig{&openkv.APITokenConfig{Token: CONN_PSK}}, } resp, err := client.Register(context.Background(), &openkv.RegisterRequest{ OrganisationId: "00009999", OrganisationIdSystem: "https://vektis.nl/agbz", OrganisationDisplayName: "Praktijk de oude berg", Auth: auth, }) if err != nil { log.Printf("Err in request: %v", err) return nil, err } if !resp.Success { return nil, fmt.Errorf("%v", resp.Error.Message) } connection := &model.Connection{ Addr: addr, AuthConfig: &sharedmodel.AuthConfig{ Method: openkv.AuthMethod_APIToken, Raw: CONN_PSK, }, State: model.ConnectionStatePending, Reference: resp.Reference, } meta, _ := srv.listMeta(connection) connection.Supplier = meta.Supplier connection.System = meta.System if err := srv.data.Create(connection).Error; err != nil { return nil, err } return connection, nil } func (srv *HISServer) activate(conn *model.Connection, psk string) (*model.Connection, error) { client, err := getAuthenticatedClient(conn.Addr, conn.AuthConfig.Raw) if err != nil { panic(err) } resp, err := client.CompleteRegistration(context.Background(), &openkv.CompleteRegistrationRequest{ Reference: conn.Reference, RegistrationToken: psk, }) if err != nil { log.Printf("Err in request: %v", err) return nil, err } else if !resp.Success { log.Printf("success: %v; Err: %v", resp.Success, resp.Error) return nil, fmt.Errorf("%v", resp.Error.Message) } meta, err := srv.listMeta(conn) if err != nil { return conn, fmt.Errorf("Failed to retreive metadata: %v ", err) } conn.State = model.ConnectionStateCompleted conn.Supplier = meta.Supplier conn.System = meta.System if err := srv.data.Save(conn).Error; err != nil { return nil, err } return conn, err } func (srv *HISServer) listMeta(conn *model.Connection) (*openkv.GetMetadataResponse, error) { client, err := getUnauthenticatedClient(conn.Addr) if err != nil { return nil, err } resp, err := client.GetMetadata(context.Background(), &openkv.GetMetadataRequest{}) if err != nil { log.Printf("Err in request: %v", err) return nil, err } else if !resp.Success { log.Printf("success: %v; Err: %v", resp.Success, resp.Error) return nil, fmt.Errorf("%v", resp.Error.Message) } return resp, nil } func (srv *HISServer) enableService(conn *model.Connection, service string, active bool) error { client, err := getAuthenticatedClient(conn.Addr, conn.AuthConfig.Raw) if err != nil { return err } moddedService := &model.Service{} moddedServiceErr := srv.data.Where("connection_id = ? and service_id = ?", conn.ID, service).First(moddedService).Error if moddedServiceErr != nil && moddedServiceErr != gorm.ErrRecordNotFound { return moddedServiceErr } if moddedServiceErr != nil && !active { return nil } if moddedServiceErr == nil && active { return nil } meta, _ := srv.listMeta(conn) var serviceDefinition *openkv.ServiceDefinition for _, sd := range meta.Services { if sd.Id == service { serviceDefinition = sd } } if serviceDefinition == nil { return fmt.Errorf("Invalid service: %v", service) } var resp *openkv.ConfigServiceResponse if m, _ := regexp.MatchString("wbx:*", service); m { // Whitebox resp, err = client.ConfigService(context.Background(), &openkv.ConfigServiceRequest{ Service: service, Enabled: active, Fetch: &openkv.ServiceConfig{ Protocol: "https://whiteboxsystems.nl/protospecs/whitebox-fetch/http", Config: map[string]string{ "url": "http://localhost:8084/external/api", }, Auth: &openkv.AuthConfig{ Method: openkv.AuthMethod_APIToken, }, }, Push: &openkv.ServiceConfig{ Protocol: "https://whiteboxsystems.nl/protospecs/whitebox-push/http", Config: map[string]string{ "url": "http://localhost:8084/external/api", }, Auth: &openkv.AuthConfig{ Method: openkv.AuthMethod_APIToken, }, }, }) } else { // DVZA / FHIR resp, err = client.ConfigService(context.Background(), &openkv.ConfigServiceRequest{ Service: service, Enabled: active, Fetch: &openkv.ServiceConfig{ Protocol: "https://hl7.org/fhir", Config: map[string]string{ "url": "http://localhost:8084/external/fhir/Patient", }, Auth: &openkv.AuthConfig{ Method: openkv.AuthMethod_APIToken, }, }, Push: &openkv.ServiceConfig{ Protocol: "https://hl7.org/fhir", Config: map[string]string{ "url": "http://localhost:8084/external/fhir/Patient", }, Auth: &openkv.AuthConfig{ Method: openkv.AuthMethod_APIToken, }, }, }) } if err != nil { log.Printf("Err in request: %v", err) return err } else if !resp.Success { log.Printf("success: %v; Err: %v", resp.Success, resp.Error) return fmt.Errorf("%v", resp.Error) } if !active { subs := []model.Patient{} srv.data.Model(moddedService).Association("Subscriptions").Find(&subs) srv.data.Model(moddedService).Association("Subscriptions").Delete(subs) srv.subscribePatients(conn, moddedService, false, subs) return srv.data.Unscoped().Delete(moddedService).Error } return srv.data.Create(&model.Service{ ConnectionID: conn.ID, ServiceID: serviceDefinition.Id, Name: serviceDefinition.Name, Description: serviceDefinition.Name, SubscriptionPolicy: serviceDefinition.SubscriptionPolicy, ConsentPolicy: serviceDefinition.ConsentPolicy, AuthConfig: &sharedmodel.AuthConfig{ Method: resp.Fetch.Auth.Method, Raw: resp.Fetch.Auth.GetApiTokenConfig().Token, }, }).Error } func (srv *HISServer) subscribePatients(conn *model.Connection, service *model.Service, active bool, patients []model.Patient) (*openkv.UpdateSubscriptionsResponse, error) { client, err := getAuthenticatedClient(conn.Addr, conn.AuthConfig.Raw) if err != nil { return nil, err } subs := []*openkv.SubscriptionData{} for _, pat := range patients { subs = append(subs, &openkv.SubscriptionData{ Subscribe: active, Subject: &openkv.PatientMeta{ ExternalId: pat.ExternalId, ExternalIdSystem: "http://fhir.nl/fhir/NamingSystem/bsn", Name: pat.Name, Birthdate: pat.Birthdate, }, ProtocolMeta: map[string]string{ "patientID": pat.PatientID, }, }) } req := &openkv.UpdateSubscriptionsRequest{ ServiceId: service.ServiceID, SubscriptionData: subs, } resp, err := client.UpdateSubscriptions(context.Background(), req) if err != nil { log.Printf("Err in request: %v", err) return nil, err } else if !resp.Success { log.Printf("success: %v; Err: %v", resp.Success, resp.Errors) return nil, err } return resp, nil } func listSubscriptions(addr, service string) { client, err := getAuthenticatedClient(addr, CONN_PSK) if err != nil { panic(err) } req := &openkv.ListSubscriptionsRequest{ ServiceId: service, } if resp, err := client.ListSubscriptions(context.Background(), req); err != nil { log.Printf("Err in request: %v", err) return } else { if !resp.Success { log.Printf("success: %v; Err: %v", resp.Success, resp.Error) } else { log.Printf("success: %v", resp) } return } }