You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
okapidemo/his/openapiclient.go

373 lines
9.3 KiB

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": externalAddr + "/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": externalAddr + "/external/api",
},
Auth: &openkv.AuthConfig{
Method: openkv.AuthMethod_APIToken,
},
},
})
} else if m, _ := regexp.MatchString("voorbeeld:*", service); m { // Kis
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": externalAddr + "/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": externalAddr + "/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": externalAddr + "/external/fhir/Patient",
},
Auth: &openkv.AuthConfig{
Method: openkv.AuthMethod_APIToken,
},
},
Push: &openkv.ServiceConfig{
Protocol: "https://hl7.org/fhir",
Config: map[string]string{
"url": externalAddr + "/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
}
}