Skip to content

Commit

Permalink
Cleaning updates
Browse files Browse the repository at this point in the history
  • Loading branch information
Dokotela committed Nov 21, 2024
1 parent 8eca5be commit 5822cfb
Show file tree
Hide file tree
Showing 10 changed files with 219 additions and 413 deletions.
31 changes: 15 additions & 16 deletions build/build_ios.sh
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
#!/bin/bash

# Navigate to the root directory of the project
cd "$(dirname "$0")/.."

# Clean up previous builds
rm -f pocketfhir_ios

# Initialize Go modules in the root directory if go.mod does not exist
# Ensure Go modules are initialized
if [ ! -f go.mod ]; then
go mod init pocketfhir
fi

# Tidy up Go modules in the root directory
go mod tidy
# Install necessary tools
go get -u golang.org/x/mobile/bind
go install golang.org/x/mobile/cmd/gomobile@latest
gomobile init

# Build the PocketFHIR server for iOS (arm64 architecture)
echo "Building PocketFHIR for iOS..."
GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -o pocketfhir_ios ./src
echo "iOS PocketFHIR build completed."
# Build PocketFHIR .framework for iOS
echo "Building PocketFHIR .framework for iOS..."
gomobile bind -target=ios -o pocketfhir.framework ./pocketfhir
if [ $? -ne 0 ]; then
echo "iOS build failed!"
exit 1
fi

# Start the PocketFHIR server in the background (for the regular platform)
./pocketfhir serve &
# Move the framework to the appropriate iOS directory
mv pocketfhir.framework ../fhir_ant/ios/libs/pocketfhir.framework

echo "PocketFHIR server started."
echo "PocketFHIR iOS build completed successfully."
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,6 @@ require (
golang.org/x/crypto/x509roots/fallback v0.0.0-20240507223354-67b13616a595 // indirect
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
golang.org/x/image v0.22.0 // indirect
golang.org/x/mobile v0.0.0-20241108191957-fa514ef75a0f // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/sync v0.9.0 // indirect
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1022,8 +1022,6 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20241108191957-fa514ef75a0f h1:23H/YlmTHfmmvpZ+ajKZL0qLz0+IwFOIqQA0mQbmLeM=
golang.org/x/mobile v0.0.0-20241108191957-fa514ef75a0f/go.mod h1:UbSUP4uu/C9hw9R2CkojhXlAxvayHjBdU9aRvE+c1To=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
Expand Down
17 changes: 11 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@ package main
import "github.com/fhir-fli/pocketfhir/pocketfhir"

func main() {
// Use the string wrapper for local development
dataDir := "./assets"
ipAddress := "127.0.0.1"
port := "8080" // Changed from 443 to 8080 to avoid permission issues
enableApiLogs := false
// Configuration for local development
dataDir := "./assets" // The directory to use for PocketBase data
pbIpAddress := "127.0.0.1" // PocketBase IP address for local development
caddyIpAddress := "127.0.0.1" // Caddy server loopback IP address to prevent conflict
pbPort := "8090" // PocketBase port set to 8080
httpPort := "8081" // Caddy HTTP traffic port
httpsPort := "8443" // Caddy HTTPS traffic port
enableApiLogs := true // Enable API logs for detailed local debugging
storagePath := "./storage" // Local storage path for Caddy

pocketfhir.RunServer(dataDir, ipAddress, port, enableApiLogs)
// Start PocketFHIR server with local development configuration
pocketfhir.StartPocketFHIR(pbPort, httpPort, httpsPort, pbIpAddress, caddyIpAddress, dataDir, enableApiLogs, storagePath)
}
86 changes: 41 additions & 45 deletions pocketfhir/caddy.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,77 +10,73 @@ import (
_ "github.com/caddyserver/caddy/v2/modules/standard"
)

// CaddyConfig is a struct that contains the configuration parameters for starting the Caddy server.
type CaddyConfig struct {
PbPort string
HttpPort string
HttpsPort string
PbUrl string
StoragePath string
IpAddress string
}

// StartCaddy starts the Caddy server with the provided configuration.
func StartCaddy(pbPort, httpPort, httpsPort, pbUrl, storagePath, ipAddress string) {
func StartCaddy(config CaddyConfig) {
// Change working directory
if err := os.Chdir(storagePath); err != nil {
log.Fatalf("Failed to change working directory to %s: %v", storagePath, err)
if err := os.Chdir(config.StoragePath); err != nil {
log.Fatalf("Failed to change working directory to %s: %v", config.StoragePath, err)
}

// Log configuration for transparency
log.Printf("Starting Caddy server with the following configuration:")
log.Printf("PocketBase Port: %s", pbPort)
log.Printf("HTTP Port: %s", httpPort)
log.Printf("HTTPS Port: %s", httpsPort)
log.Printf("Upstream URL: %s", pbUrl)
log.Printf("Storage Path: %s", storagePath)
// Log consolidated configuration details
log.Printf("Starting Caddy server with configuration: %+v", config)

// Generate Caddy config
cfg := createConfig(pbPort, httpPort, httpsPort, pbUrl, storagePath, ipAddress)
caddyCfg := createConfig(config)

// Serialize for debugging
configJSON, err := json.MarshalIndent(cfg, "", " ")
configJSON, err := json.MarshalIndent(caddyCfg, "", " ")
if err != nil {
log.Fatalf("Failed to serialize Caddy config: %v", err)
}
log.Printf("Generated Caddy config: %s", string(configJSON))

// Initialize Caddy
// Initialize and run Caddy
log.Println("Initializing Caddy...")
if err := caddy.Run(cfg); err != nil {
if err := caddy.Run(caddyCfg); err != nil {
log.Fatalf("Error running Caddy: %v", err)
}

log.Println("Caddy server started successfully.")
}

// CreateConfig generates a basic Caddy configuration to run a reverse proxy with HTTP and a static file server.
func createConfig(pbPort, httpPort, httpsPort, pbUrl, storagePath, ipAddress string) *caddy.Config {
// createConfig generates a basic Caddy configuration to run a reverse proxy with HTTP and a static file server.
func createConfig(config CaddyConfig) *caddy.Config {
// Define paths for certs and proxy logs
pbProxyPath := fmt.Sprintf("%s/proxy_access.log", storagePath)

// Generate the JSON configuration
jsonConfig := jsonConfig(pbPort, httpPort, httpsPort, pbUrl, storagePath, ipAddress, pbProxyPath)
log.Printf("Generated JSON Configuration: %s", jsonConfig)

// Parse the JSON into a caddy.Config struct
var caddyConfig caddy.Config
err := json.Unmarshal([]byte(jsonConfig), &caddyConfig)
if err != nil {
log.Fatalf("Failed to parse JSON configuration: %v", err)
}
pbProxyPath := fmt.Sprintf("%s/proxy_access.log", config.StoragePath)

log.Printf("Generated Caddy Configuration: %s", jsonConfig)

return &caddyConfig
}

func jsonConfig(pbPort, httpPort, httpsPort, pbUrl, storagePath, ipAddress, pbProxyPath string) string {
// Construct each part individually and combine them
// Generate the full configuration using helpers
loggingConfig := generateLoggingConfig(pbProxyPath)
storageConfig := generateStorageConfig(storagePath)
httpAppConfig := generateHttpAppConfig(pbPort, httpPort, httpsPort, pbUrl, ipAddress)
tlsConfig := generateTlsConfig(ipAddress)
storageConfig := generateStorageConfig(config.StoragePath)
httpAppConfig := generateHttpAppConfig(config)
tlsConfig := generateTlsConfig(config.IpAddress)

// Combine the parts into the final JSON configuration
return fmt.Sprintf(`{
// Combine all configurations into the final JSON
combinedConfig := fmt.Sprintf(`{
%s,
%s,
"apps": {
%s,
%s
}
}`, loggingConfig, storageConfig, httpAppConfig, tlsConfig)

var caddyConfig caddy.Config
err := json.Unmarshal([]byte(combinedConfig), &caddyConfig)
if err != nil {
log.Fatalf("Failed to parse JSON configuration: %v", err)
}

return &caddyConfig
}

// Generates the logging configuration section
Expand Down Expand Up @@ -112,18 +108,18 @@ func generateStorageConfig(storagePath string) string {
}

// Generates the HTTP application configuration section
func generateHttpAppConfig(pbPort, httpPort, httpsPort, pbUrl, ipAddress string) string {
httpsServerConfig := generateHttpsServerConfig(httpsPort, ipAddress, pbUrl, pbPort)
func generateHttpAppConfig(config CaddyConfig) string {
httpsServerConfig := generateHttpsServerConfig(config)
return fmt.Sprintf(`"http": {
"http_port": %s,
"servers": {
%s
}
}`, httpPort, httpsServerConfig)
}`, config.HttpPort, httpsServerConfig)
}

// Generates the HTTP server configuration for reverse proxy with health checks
func generateHttpsServerConfig(httpsPort, ipAddress, pbUrl, pbPort string) string {
func generateHttpsServerConfig(config CaddyConfig) string {
return fmt.Sprintf(`"srv_https": {
"listen": [":%s"],
"routes": [
Expand Down Expand Up @@ -152,7 +148,7 @@ func generateHttpsServerConfig(httpsPort, ipAddress, pbUrl, pbPort string) strin
]
}
]
}`, httpsPort, ipAddress, pbUrl, pbPort)
}`, config.HttpsPort, config.IpAddress, config.PbUrl, config.PbPort)
}

// Generates the TLS automation configuration
Expand Down
51 changes: 39 additions & 12 deletions pocketfhir/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package pocketfhir
import (
"log"
"sync"
"time"

"github.com/labstack/echo/v5"
"github.com/pocketbase/pocketbase"
Expand Down Expand Up @@ -34,7 +35,7 @@ func registerRequestLoggingHook(app *pocketbase.PocketBase) {
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
e.Router.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
log.Printf("Request: %s %s", c.Request().Method, c.Request().URL.Path)
log.Printf("[INFO] Request: %s %s", c.Request().Method, c.Request().URL.Path)
return next(c)
}
})
Expand Down Expand Up @@ -82,13 +83,31 @@ func registerWebSocketEndpoint(app *pocketbase.PocketBase) {
clientsMu.Lock()
delete(clients, ws)
clientsMu.Unlock()
ws.Close()
_ = ws.Close()
log.Println("[INFO] WebSocket connection closed")
}()

// Keep the connection alive
log.Println("[INFO] New WebSocket connection established")

// Heartbeat mechanism to keep the connection alive
heartbeatTicker := time.NewTicker(30 * time.Second)
defer heartbeatTicker.Stop()

for {
if _, err := ws.Read(nil); err != nil {
break
select {
case <-heartbeatTicker.C:
if err := ws.SetDeadline(time.Now().Add(35 * time.Second)); err != nil {
log.Printf("[ERROR] Failed to set deadline for WebSocket: %v", err)
return
}
if _, err := ws.Write([]byte("ping")); err != nil {
log.Printf("[ERROR] Failed to send heartbeat: %v", err)
return
}
case <-c.Request().Context().Done():
// Handle client disconnection gracefully
log.Println("[INFO] WebSocket client disconnected")
return
}
}
}).ServeHTTP(c.Response(), c.Request())
Expand All @@ -101,19 +120,27 @@ func registerWebSocketEndpoint(app *pocketbase.PocketBase) {
// Broadcast a message to all connected WebSocket clients
func broadcastWebSocketMessage(eventType string, record *models.Record) {
clientsMu.Lock()
defer clientsMu.Unlock()
clientsSnapshot := make([]*websocket.Conn, 0, len(clients))
for client := range clients {
clientsSnapshot = append(clientsSnapshot, client)
}
clientsMu.Unlock()

message := map[string]interface{}{
"type": eventType,
"record": record,
"resource": record.Get("resource"),
}

for client := range clients {
if err := websocket.JSON.Send(client, message); err != nil {
log.Printf("Failed to send WebSocket message: %v", err)
client.Close()
delete(clients, client)
}
for _, client := range clientsSnapshot {
go func(client *websocket.Conn) {
if err := websocket.JSON.Send(client, message); err != nil {
log.Printf("[ERROR] Failed to send WebSocket message: %v", err)
clientsMu.Lock()
delete(clients, client)
clientsMu.Unlock()
_ = client.Close()
}
}(client)
}
}
20 changes: 0 additions & 20 deletions pocketfhir/initial_collections.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,6 @@ func initializeCollections(app *pocketbase.PocketBase) error {
return err
}

// Step 2: Check if FHIR spec has been initialized
if !isFhirSpecInitialized(app) {
// Load the FHIR spec into the database
// if err := loadFhirSpecOnce(app); err != nil {
// log.Printf("Failed to load FHIR spec: %v", err)
// return err
// }

// Set the FHIR spec as initialized
// setFhirSpecInitialized(app)
} else {
log.Println("FHIR spec already initialized.")
}

// Step 3: Load MIMIC-IV dataset (optional step)
// if err := loadMimicIVData(app); err != nil {
// log.Printf("Failed to load MIMIC-IV dataset: %v", err)
// return err
// }

return nil
})
return nil
Expand Down
Loading

0 comments on commit 5822cfb

Please sign in to comment.