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.
 
 
 
 

235 lines
5.9 KiB

package main
import (
"context"
"crypto/tls"
"fmt"
"io"
"log"
"net/http"
"os"
"os/exec"
"sync"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"src.whiteboxsystems.nl/DECOZO/okapidemo/sharedmodel"
"src.whiteboxsystems.nl/DECOZO/okapidemo/whiteboxservice/model"
)
type UIService struct {
srv *http.Server
inited bool
clientCert tls.Certificate
data *gorm.DB
}
func (srv *UIService) LoadData(location string) error {
var err error
srv.data, err = model.GetDB(location)
return err
}
func (srv *UIService) Addr() string {
if srv.srv == nil {
return ""
}
return srv.srv.Addr
}
func (srv *UIService) ListenAndServe() {
if !srv.inited {
srv.init()
}
log.Println("Listening on %v", srv.srv.Addr)
srv.srv.ListenAndServe()
}
func (srv *UIService) Shutdown(ctx context.Context) error {
return srv.srv.Shutdown(ctx)
}
func (srv *UIService) init() {
r := srv.srv.Handler.(*gin.Engine)
r.LoadHTMLGlob("templates/*")
r.Static("/assets", "./assets")
r.Use(srv.Authenticate)
r.GET("/", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "/ui")
})
r.GET("/ui", srv.GetIndex)
r.GET("/ui/*page", srv.GetIndex)
r.GET("/api/connections", srv.GetConnections)
r.GET("/api/connections/:connID", srv.GetConnection)
r.GET("/api/connections/:connID/:serviceID", srv.GetSubscriptions)
r.GET("/api/connections/:connID/:serviceID/:patientID", srv.GetPatient)
r.GET("/api/registrations", srv.GetRegistrations)
srv.inited = true
}
func (srv *UIService) GetIndex(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", gin.H{})
}
func (srv *UIService) GetConnection(c *gin.Context) {
connID := c.Param("connID")
connection := &sharedmodel.Connection{}
srv.data.Where("id = ?", connID).Find(&connection)
c.JSON(http.StatusOK, connection)
}
func (srv *UIService) GetSubscriptions(c *gin.Context) {
connID := c.Param("connID")
serviceID := c.Param("serviceID")
serviceConfig := &sharedmodel.ServiceConfig{}
srv.data.Preload("Service").Preload("Subscriptions").Where("connection_id = ? and id = ?", connID, serviceID).Find(&serviceConfig)
c.JSON(http.StatusOK, serviceConfig)
}
func (srv *UIService) GetPatient(c *gin.Context) {
connID := c.Param("connID")
serviceID := c.Param("serviceID")
patientID := c.Param("patientID")
patient := &sharedmodel.Subscription{}
serviceConfig := &sharedmodel.ServiceConfig{}
if err := srv.data.Preload("FetchProtocol").Preload("FetchProtocol.AuthConfig").Preload("Service").Where("connection_id = ? and id = ?", connID, serviceID).Find(&serviceConfig).Error; err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
srv.data.Where("service_config_id = ? and id = ?", serviceID, patientID).Find(&patient)
protoconfig := map[string]string{}
protometa := map[string]string{}
err := serviceConfig.FetchProtocol.UnmarshalConfig(&protoconfig)
if err != nil {
c.AbortWithStatus(http.StatusBadRequest)
return
}
err = patient.GetProtocolMeta(&protometa)
if err != nil {
c.AbortWithStatus(http.StatusBadRequest)
return
}
url := fmt.Sprintf("%v/%v/%v", protoconfig["url"], "patients", protometa["patientID"])
req, _ := http.NewRequest("GET", url, nil)
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
Certificates: []tls.Certificate{srv.clientCert},
},
},
}
resp, err := client.Do(req)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
if resp.StatusCode >= 400 {
c.AbortWithError(resp.StatusCode, fmt.Errorf("%v", resp.Status))
return
}
cmd := exec.Command(binFolder+"/ediviewer", binFolder+"/medeur.json", binFolder+"/template.html", "/dev/stdin")
sin, err := cmd.StdinPipe()
if err != nil {
log.Println("[ediviewer] Failed to open stdin pipe:", err)
c.AbortWithError(http.StatusInternalServerError, err)
return
}
defer sin.Close()
serr, err := cmd.StderrPipe()
if err != nil {
log.Println("[ediviewer] Failed to open stderr pipe:", err)
c.AbortWithError(http.StatusInternalServerError, err)
return
}
defer serr.Close()
sout, err := cmd.StdoutPipe()
if err != nil {
log.Println("[ediviewer] Failed to open stdout pipe:", err)
c.AbortWithError(http.StatusInternalServerError, err)
return
}
defer sout.Close()
if err := cmd.Start(); err != nil {
log.Println("[ediviewer] Failed to start:", err)
c.AbortWithError(http.StatusInternalServerError, err)
return
}
wg := sync.WaitGroup{}
wg.Add(3)
go func() {
defer wg.Done()
if _, err := io.Copy(sin, resp.Body); err != nil {
log.Println("[ediviewer] Error reading EDIFACT:", err)
c.AbortWithError(http.StatusInternalServerError, err)
}
}()
go func() {
defer wg.Done()
if _, err := io.Copy(c.Writer, sout); err != nil {
log.Println("[ediviewer] Error output EDIFACT:", err)
c.AbortWithError(http.StatusInternalServerError, err)
}
}()
go func() {
defer wg.Done()
if _, err := io.Copy(os.Stderr, serr); err != nil {
log.Println("[ediviewer] Error stderr EDIFACT:", err)
c.AbortWithError(http.StatusInternalServerError, err)
}
}()
wg.Wait()
if err := cmd.Wait(); err != nil {
log.Println("[ediviewer] Failed:", err)
c.AbortWithError(http.StatusInternalServerError, err)
}
}
func (srv *UIService) Authenticate(c *gin.Context) {
// Maybe authenticate user
}
func (srv *UIService) GetConnections(c *gin.Context) {
connections := []*sharedmodel.Connection{}
srv.data.Preload("Services").Preload("Services.Service").Preload("Services.Subscriptions").Find(&connections)
c.JSON(http.StatusOK, connections)
}
func (srv *UIService) GetRegistrations(c *gin.Context) {
registrations := []*sharedmodel.Registration{}
srv.data.Where("status = ?", sharedmodel.RegistrationStatusPending).Find(&registrations)
c.JSON(http.StatusOK, registrations)
}
func NewUIServer(addr string) *UIService {
cert := loadCert()
srv := &UIService{srv: &http.Server{
Addr: addr,
Handler: gin.Default(),
}, clientCert: *cert}
return srv
}