From 5b934b82c44e1f636043a7abf3e06c1dd9393f20 Mon Sep 17 00:00:00 2001 From: Dokotela Date: Wed, 13 Nov 2024 19:47:02 -0800 Subject: [PATCH] updates --- build/build_android.sh | 37 +++-------- go.mod | 18 +++--- go.sum | 38 +++++------ main.go | 4 +- pocketfhir/hooks.go | 80 +++++++++++++++++++++++- pocketfhir/register_management_routes.go | 30 +++++++++ pocketfhir/server.go | 31 +++++++-- 7 files changed, 176 insertions(+), 62 deletions(-) create mode 100644 pocketfhir/register_management_routes.go diff --git a/build/build_android.sh b/build/build_android.sh index 0e76b76..6f21773 100755 --- a/build/build_android.sh +++ b/build/build_android.sh @@ -1,38 +1,19 @@ #!/bin/bash -# Navigate to the root directory of the project -cd "$(dirname "$0")/.." - -# Clean up previous Android builds -rm -f pocketfhir_server_android - -# 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 - -# Set the Android target platform -ANDROID_ARCH=arm64 -ANDROID_SDK_ROOT=$HOME/Android/Sdk - -# Set the Android NDK toolchain path (ensure you have the correct NDK version installed) -NDK_TOOLCHAIN=$ANDROID_SDK_ROOT/ndk/28.0.12433566/toolchains/llvm/prebuilt/linux-x86_64 - -# Set up cross-compilation environment variables for Android -export GOARCH=$ANDROID_ARCH -export GOOS=android -export CGO_ENABLED=1 - -# Set the Android-specific compiler and linker -export CC=$NDK_TOOLCHAIN/bin/aarch64-linux-android21-clang -export CXX=$NDK_TOOLCHAIN/bin/aarch64-linux-android21-clang++ +# 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 Android -echo "Building PocketFHIR for Android platform..." -if ! go build -o pocketfhir_server_android ./main.go; then +# Build PocketFHIR .aar for Android +echo "Building PocketFHIR .aar file for Android..." +gomobile bind -target=android -androidapi=21 -o pocketfhir.aar ./pocketfhir +if [ $? -ne 0 ]; then echo "Android build failed!" exit 1 fi diff --git a/go.mod b/go.mod index 4e214df..0a8396f 100644 --- a/go.mod +++ b/go.mod @@ -76,16 +76,18 @@ require ( github.com/valyala/fasttemplate v1.2.2 // indirect go.opencensus.io v0.24.0 // indirect gocloud.dev v0.37.0 // indirect - golang.org/x/crypto v0.27.0 // indirect - golang.org/x/image v0.20.0 // indirect - golang.org/x/net v0.29.0 // indirect + golang.org/x/crypto v0.29.0 // 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/net v0.31.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/term v0.24.0 // indirect - golang.org/x/text v0.18.0 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.27.0 // indirect + golang.org/x/term v0.26.0 // indirect + golang.org/x/text v0.20.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.25.0 // indirect + golang.org/x/tools v0.27.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/api v0.187.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect diff --git a/go.sum b/go.sum index c71f2af..f6b5fbb 100644 --- a/go.sum +++ b/go.sum @@ -669,27 +669,29 @@ golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.20.0 h1:7cVCUjQwfL18gyBJOmYvptfSHS8Fb3YUDtfLIZ7Nbpw= -golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM= +golang.org/x/image v0.22.0 h1:UtK5yLUzilVrkjMAZAZ34DXGpASN8i8pj8g+O+yd10g= +golang.org/x/image v0.22.0/go.mod h1:9hPFhljd4zZ1GNSIZJ49sqbp45GKK9t6w+iXvGqZUz4= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/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= -golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -719,8 +721,8 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -733,8 +735,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -774,12 +776,12 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= -golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -787,8 +789,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -820,8 +822,8 @@ golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191219041853-979b82bfef62/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= -golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= +golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o= +golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/main.go b/main.go index 1e120e8..1698bee 100644 --- a/main.go +++ b/main.go @@ -3,5 +3,7 @@ package main import "github.com/fhir-fli/pocketfhir/pocketfhir" func main() { - pocketfhir.RunServer() + // Use the string wrapper for local development + dataDir := "." + pocketfhir.RunServer(dataDir) } diff --git a/pocketfhir/hooks.go b/pocketfhir/hooks.go index 9ac9e90..19d7f4b 100644 --- a/pocketfhir/hooks.go +++ b/pocketfhir/hooks.go @@ -2,10 +2,19 @@ package pocketfhir import ( "log" + "sync" "github.com/labstack/echo/v5" "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/core" + "github.com/pocketbase/pocketbase/models" + "golang.org/x/net/websocket" +) + +var ( + // Clients holds the connected WebSocket clients + clients = make(map[*websocket.Conn]bool) + clientsMu sync.Mutex ) // Register custom hooks @@ -15,6 +24,9 @@ func registerHooks(app *pocketbase.PocketBase) { // Setup versioning and history hooks setupHooks(app) + + // Register WebSocket endpoint for live updates + registerWebSocketEndpoint(app) } // Log each request @@ -30,14 +42,78 @@ func registerRequestLoggingHook(app *pocketbase.PocketBase) { }) } +// Setup hooks for resource versioning and history func setupHooks(app *pocketbase.PocketBase) { // Hook for handling resource creation app.OnRecordAfterCreateRequest().Add(func(e *core.RecordCreateEvent) error { - return handleResourceCreation(app, e) + err := handleResourceCreation(app, e) + if err == nil { + broadcastWebSocketMessage("created", e.Record) + } + return err }) // Hook for handling resource updates app.OnRecordBeforeUpdateRequest().Add(func(e *core.RecordUpdateEvent) error { - return handleResourceUpdate(app, e) + err := handleResourceUpdate(app, e) + if err == nil { + broadcastWebSocketMessage("updated", e.Record) + } + return err + }) + + // Hook for handling resource deletion + app.OnRecordAfterDeleteRequest().Add(func(e *core.RecordDeleteEvent) error { + broadcastWebSocketMessage("deleted", e.Record) + return nil + }) +} + +// Register WebSocket endpoint for live updates +func registerWebSocketEndpoint(app *pocketbase.PocketBase) { + app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + e.Router.GET("/ws/live-updates", func(c echo.Context) error { + websocket.Handler(func(ws *websocket.Conn) { + clientsMu.Lock() + clients[ws] = true + clientsMu.Unlock() + + defer func() { + clientsMu.Lock() + delete(clients, ws) + clientsMu.Unlock() + ws.Close() + }() + + // Keep the connection alive + for { + if _, err := ws.Read(nil); err != nil { + break + } + } + }).ServeHTTP(c.Response(), c.Request()) + return nil + }) + return nil }) } + +// Broadcast a message to all connected WebSocket clients +func broadcastWebSocketMessage(eventType string, record *models.Record) { + clientsMu.Lock() + defer 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) + } + } +} diff --git a/pocketfhir/register_management_routes.go b/pocketfhir/register_management_routes.go new file mode 100644 index 0000000..9e7061c --- /dev/null +++ b/pocketfhir/register_management_routes.go @@ -0,0 +1,30 @@ +package pocketfhir + +import ( + "net/http" + + "github.com/labstack/echo/v5" + "github.com/pocketbase/pocketbase" + "github.com/pocketbase/pocketbase/core" +) + +// Register additional server management routes +func registerManagementRoutes(app *pocketbase.PocketBase) { + app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + // Health check endpoint + e.Router.GET("/api/status", func(c echo.Context) error { + return c.JSON(http.StatusOK, map[string]string{ + "status": "running", + }) + }) + + // Version endpoint + e.Router.GET("/api/version", func(c echo.Context) error { + return c.JSON(http.StatusOK, map[string]string{ + "version": "0.1.0", + }) + }) + + return nil + }) +} diff --git a/pocketfhir/server.go b/pocketfhir/server.go index af1130d..6d0b4a6 100644 --- a/pocketfhir/server.go +++ b/pocketfhir/server.go @@ -2,12 +2,19 @@ package pocketfhir import ( "log" + "os" + "os/signal" + "syscall" "github.com/pocketbase/pocketbase" ) -// RunServer initializes and runs the PocketFHIR server -func RunServer() { +func RunServer(dataDir string) { + // Set the environment variable for Pocketbase data directory + if err := os.Setenv("POCKETBASE_DATA_DIR", dataDir); err != nil { + log.Fatalf("Failed to set data directory: %v", err) + } + app := pocketbase.New() // Standard setup for app @@ -19,12 +26,26 @@ func RunServer() { // Register FHIR routes registerFHIRRoutes(app) + // Register server management routes + registerManagementRoutes(app) + // Initialize collections only if necessary if err := initializeCollections(app); err != nil { log.Fatalf("Failed to initialize collections: %v", err) } - if err := app.Start(); err != nil { - log.Fatalf("Failed to start the app: %v", err) - } + // Handle graceful shutdown + stop := make(chan os.Signal, 1) + signal.Notify(stop, os.Interrupt, syscall.SIGTERM) + + go func() { + if err := app.Start(); err != nil { + log.Fatalf("Failed to start the app: %v", err) + } + }() + + // Wait for interrupt signal to gracefully shut down the server + <-stop + log.Println("Shutting down PocketFHIR server...") + app.ResetBootstrapState() // Optional: Clean up any resources before shutting down }