Compare commits

...

9 Commits

16 changed files with 785 additions and 415 deletions

4
.gitignore vendored
View File

@@ -23,4 +23,6 @@ tilt/base/_manifest.yaml
NuGet.Config
sync.list
packages.lock.json
package-lock.json
package-lock.json
src/Atlantis/.direnv
src/Sorcerer/.direnv

View File

@@ -60,6 +60,7 @@
"@spectrum-web-components/underlay": "^1.0.3",
"@turf/bezier-spline": "^7.1.0",
"@vaadin/login": "^24.4.9",
"html2canvas": "^1.4.1",
"lit": "^3.1.0",
"lit-html": "^3.1.0",
"ol": "^10.1.0",
@@ -70,4 +71,4 @@
"react-plotly.js": "^2.6.0",
"vis-timeline": "^7.7.2"
}
}
}

View File

@@ -59,6 +59,7 @@ importSideEffects "@spectrum-web-components/dialog/sp-dialog.js"
importSideEffects "@spectrum-web-components/infield-button/sp-infield-button.js"
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-add.js"
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-add-circle.js"
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-airplane.js"
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-alert.js"
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-prototyping.js"
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-close.js"
@@ -103,3 +104,4 @@ importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-social-
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-checkmark.js"
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-rotate-cc-w.js"
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-align-bottom.js"
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-camera.js"

View File

@@ -62,6 +62,7 @@ type FvcomApi(url) =
member val Archive = createApi Remoting.buildProxy<Api.Fvcom.Archive>
member val Layer = createBinApi Remoting.buildProxy<Api.Fvcom.Layer>
member val CompressedLayer = createBinApi Remoting.buildProxy<Api.Fvcom.CompressedLayer>
member val Node = createBinApi Remoting.buildProxy<Api.Fvcom.Node>
member val Element = createBinApi Remoting.buildProxy<Api.Fvcom.Element>
member val Batch = createBinApi Remoting.buildProxy<Api.Fvcom.Batch>

View File

@@ -18,6 +18,12 @@ open Maps
let sideEffectCmd fn arg = Elmish.Cmd.OfPromise.perform fn arg Noop
let sideEffectCmd' (fn: unit -> unit) = Elmish.Cmd.OfPromise.perform (fn >> Promise.lift) () Noop
[<Emit("performance.now()")>]
let perfNow () = jsNative
/// Used to gather timings of variable fetch -> drawn layer
let mutable t0: float = 0.0
let private logPos x = if x < 1.e-10f then -10.f else x |> float |> Math.Log10 |> single
let private logNeg x = if x < -1.e10f then -10.f else -x |> float |> Math.Log10 |> single
@@ -40,6 +46,7 @@ let updateWebglLayer model prop (layer: MapLayer) =
webglLayer.updateOpacity prop.Alpha
webglLayer.updateProps data
source.refresh ()
console.debug $"time: {(perfNow ()) - t0}"
)
}
|> Async.StartImmediate
@@ -819,6 +826,7 @@ let oceanControls dispatch model =
let toggleWindBarbs _ = dispatch (ShowWindBarbs(not model.showWindBarbs))
let toggleWhiteWindBarbs _ = dispatch (SetWhiteWindBarbs(not model.whiteWindBarbs))
let toggleStreams _ = (ShowStreams >> dispatch) (not model.showStreams)
let toggleCompressed _ = (UseCompressedProps >> dispatch) (not model.compressedProps)
let windSlider =
html $"""
@@ -835,6 +843,40 @@ let oceanControls dispatch model =
> </sp-slider>
"""
let flyToLatLon (lat, lon) (zoom) =
let c = Utils.toEpsg3857' (lon, lat)
flyTo model.map zoom [| fst c; snd c|]
let NappSamples = [|
(68.12, 13.593, 13.5)
(68.05, 13.55, 13.5)
(68.2, 13.3, 11.6)
(68.145, 13.458, 11.0)
(68.145, 13.458, 13.0)
(67.98, 13.56, 12.)
|]
let PO5Samples = [|
(62.68, 7.15, 11.0)
(63.09, 6.33, 10.0)
(62.51, 5.94, 12.0)
(62.37, 6.15, 12.6)
(62.40, 5.33, 11.0)
(61.95, 5.09, 12.0)
|]
let destButton (dest: float * float) (zoom: float) (num: int) =
html $"""
<sp-action-button
@click="{Ev(fun _ -> flyToLatLon dest zoom)}"
id="flyto-button"
value="flyto"
size="m"
>
{num}
</sp-action-button>
"""
html $"""
<div
slot="content"
@@ -859,6 +901,13 @@ let oceanControls dispatch model =
<sp-radio ?disabled={disabled} value="{Prop.Speed}" @change={Ev(setProp Prop.Speed)}>Speed</sp-radio>
<sp-radio ?disabled={disabled} value="{Prop.Bathy}" @change={Ev(setProp Prop.Bathy)}>Depth</sp-radio>
</sp-radio-group>
<sp-switch label="ZFP"
?disabled={disabled}
?checked={model.compressedProps}
@click={Ev(toggleCompressed)}
>
ZFP
</sp-switch>
</div>
<div>
@@ -904,6 +953,44 @@ let oceanControls dispatch model =
{if model.showWindBarbs then windSlider else Lit.nothing}
</div>
</div>
<div style="margin: 10px;">
<sp-field-label size="s" for="napp-samples">
Napp Samples
</sp-field-label>
<div style="
display: flex;
flex-direction: row;
flex-wrap: wrap;
max-width: 320;
gap: 5px;
">
{
NappSamples
|> Array.mapi (fun i (lon, lat, zoom) ->
destButton (lon, lat) zoom i
)}
</div>
</div>
<div style="margin: 10px;">
<sp-field-label size="s" for="PO5-samples">
PO5 Samples
</sp-field-label>
<div style="
display: flex;
flex-direction: row;
flex-wrap: wrap;
max-width: 320;
gap: 5px;
">
{
PO5Samples
|> Array.mapi (fun i (lon, lat, zoom) ->
destButton (lon, lat) zoom i
)}
</div>
</div>
</div>
"""

File diff suppressed because it is too large Load Diff

View File

@@ -236,6 +236,7 @@ type Model = {
showWindBarbs: bool
whiteWindBarbs: bool
surface: bool
compressedProps: bool // Whether to fetch zfp-compressed slices
customGrid: CircleGrid option
auxGrid: PlainGrid option
@@ -313,6 +314,7 @@ with
contourCutoff = Map [0, (false, 330.0); 1, (false, 10.0); 2, (false, 100.0); 3, (false, 10_000.0)]
contourKind = FullContour
surface = true
compressedProps = false
showWindBarbs = false
whiteWindBarbs = false
isLoading = None
@@ -365,6 +367,7 @@ type Msg =
| InitOcean of ViewProp
| InitLayer of (MapLayer * ViewProp)
| ShowSurface of bool
| UseCompressedProps of bool
| ShowGrid of bool
| ShowWindBarbs of bool
| SetWhiteWindBarbs of bool

View File

@@ -1,6 +1,7 @@
module Probing
open Browser
open Fable.Core
open Fable.Core.JsInterop
open Fable.OpenLayers
open Lit
@@ -305,6 +306,56 @@ let backButton model dispatch =
</div>
"""
[<ImportDefault("html2canvas")>]
[<Emit("html2canvas($1)")>]
let html2canvas (element: Types.HTMLElement) : JS.Promise<Types.HTMLCanvasElement> = jsNative
let openScreenshot (c: Types.Element) =
emitJsExpr (c) "window.open('', $0.toDataURL())"
[<ImportDefault("html2canvas")>]
[<Emit("html2canvas($1).then($2)")>]
let html2canvasThen e f = jsNative
// TODO: Implement this properly
let screenshotButton (model: Model) =
let takeScreenshot () =
// let f arg =
// arg |> openScreenshot
// let mapDiv = document.getElementById("map-container")
// html2canvasThen mapDiv f
// let l = document.getElementsByTagName("canvas")
// console.log(l)
// let canvas = l[0]
// canvas |> openScreenshot
let canvas = model.map.getViewport().querySelectorAll(".ol-layer canvas, canvas.ol-layer")
console.log canvas
let canvas' = canvas[0]
canvas' |> openScreenshot
// promise {
// console.log("starting promise...")
// let mapDiv = document.getElementById("map-container")
// console.log(mapDiv)
// let! canvas = html2canvas mapDiv
// canvas |> openScreenshot
// console.log(canvas)
// } |> Promise.start
html $"""
<sp-action-button
@click="{Ev(fun _ -> takeScreenshot ())}"
id="screenshot-button"
value="screenshot"
size="m"
>
<sp-icon-camera slot="icon"></sp-icon-camera>
</sp-actio n-button>
"""
// TODO: Rename to something more general like topbar or something
/// <summary>
/// A selection of button toggles that enables tooling and interactions against the map. Currently there
@@ -381,6 +432,7 @@ let measures (model: Model) dispatch =
<sp-action-group class="measures-button-group">
{Drifters.driftersInputModal model.selectedDrifters (CloneDriftersInput >> dispatch)}
{screenshotButton model}
</sp-action-group>
</div>
"""

View File

@@ -240,6 +240,8 @@
fragColor = color;
}
</script>
<script src="js/decomp_wasm.js"></script>
<script src="js/zfp_decomp.js"></script>
</head>
<body>

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -0,0 +1,29 @@
/**
* Decompress the compressed data given by `compressedData`. Assumes target is 1d double array.
* @param {compressedData} Uint8Array containing the compressed data
* @param {originalLength} the original size of the uncompressed double array
* @param {tolerance} Inaccuracy tolerance used in compression
* @returns {Float32Array} Decompressed data
*/
async function decompress(compressedData, originalLength, tolerance) {
// Wait for wasm module to load
const Zfp = await Module();
const t0 = performance.now();
// malloc and memcpy compressed array into wasm heap
let compressed_p = Zfp._malloc(compressedData.length);
Zfp.HEAP8.set(compressedData, compressed_p);
// Run decompression
let new_data_p = Zfp._decompress(
compressed_p,
compressedData.length,
originalLength,
tolerance,
);
const t = performance.now();
console.log(`decompress: ${t - t0}`);
// Retrieve uncompressed data from wasm heap
return Zfp.HEAPF32.subarray(new_data_p / 4, new_data_p / 4 + originalLength);
}

View File

@@ -32,6 +32,16 @@ module Api =
GetVNode: Guid -> FrameIdx -> LayerIdx -> Async<single array>
}
type CompressedLayer = {
GetBathymetry: Guid -> Async<byte array>
GetSalinity: Guid -> FrameIdx -> LayerIdx -> Async<byte array>
GetTemperature: Guid -> FrameIdx -> LayerIdx -> Async<byte array>
GetZeta: Guid -> FrameIdx -> Async<byte array>
GetSpeed: Guid -> FrameIdx -> LayerIdx -> Async<byte array>
GetUNode: Guid -> FrameIdx -> LayerIdx -> Async<byte array>
GetVNode: Guid -> FrameIdx -> LayerIdx -> Async<byte array>
}
type Node = {
GetSiglev: Guid -> NodeIdx -> Async<single array>
GetSiglay: Guid -> NodeIdx -> Async<single array>
@@ -69,38 +79,84 @@ module Api =
let routeBuilder = routeBuilder "drifters"
type Archive = {
GetNumFrames: Guid -> Async<int>
GetSimType: Guid -> Async<DriftersVariant>
}
type Archive = { GetNumFrames: Guid -> Async<int>; GetSimType: Guid -> Async<DriftersVariant> }
type Particles = {
GetFrame: Guid -> FrameIdx -> Async<ApiParticle[]>
GetReleaseSites: Guid -> Async<Site[]>
}
type Particles = { GetFrame: Guid -> FrameIdx -> Async<ApiParticle[]>; GetReleaseSites: Guid -> Async<Site[]> }
type Network = {
GetReleaseSites: Guid -> Async<{| coord: float * float; radius: float |}[]>
GetConnectionMatrix: Guid -> FrameIdx -> FieldKind -> GroupKind list -> ParticleKind list -> ParticleState -> Async<float[][]>
GetConnectionMatrix:
Guid
-> FrameIdx
-> FieldKind
-> GroupKind list
-> ParticleKind list
-> ParticleState
-> Async<float[][]>
}
type Sedimentation = {
GetField: Guid -> FrameIdx -> FieldKind -> SedimentKind -> Async<single[]>
GetContour: Guid -> FrameIdx -> FieldKind -> SedimentKind -> ContourKind -> double -> Async<(float*float) [][]>
GetContour:
Guid -> FrameIdx -> FieldKind -> SedimentKind -> ContourKind -> double -> Async<(float * float)[][]>
GetSeries: Guid -> FrameIdx * FrameIdx -> FieldKind -> SedimentKind -> NodeIdx -> Async<single[]>
}
type Field2D = {
GetWaterContactField: Guid -> FrameIdx -> FieldKind -> GroupKind list -> ParticleKind list -> ParticleState -> Async<single[]>
GetWaterContactSeries: Guid -> FrameIdx * FrameIdx -> FieldKind -> GroupKind list -> ParticleKind list -> ParticleState -> NodeIdx -> Async<single[]>
GetField: Guid -> FrameIdx -> FieldKind -> GroupKind list -> ParticleKind list -> ParticleState -> Async<single[]>
GetSeries: Guid -> FrameIdx * FrameIdx -> FieldKind -> GroupKind list -> ParticleKind list -> ParticleState -> NodeIdx -> Async<single[]>
GetWaterContactField:
Guid -> FrameIdx -> FieldKind -> GroupKind list -> ParticleKind list -> ParticleState -> Async<single[]>
GetWaterContactSeries:
Guid
-> FrameIdx * FrameIdx
-> FieldKind
-> GroupKind list
-> ParticleKind list
-> ParticleState
-> NodeIdx
-> Async<single[]>
GetField:
Guid -> FrameIdx -> FieldKind -> GroupKind list -> ParticleKind list -> ParticleState -> Async<single[]>
GetSeries:
Guid
-> FrameIdx * FrameIdx
-> FieldKind
-> GroupKind list
-> ParticleKind list
-> ParticleState
-> NodeIdx
-> Async<single[]>
}
type Field3D = {
GetField: Guid -> FrameIdx -> FieldKind -> GroupKind list -> ParticleKind list -> ParticleState -> LayerIdx list -> Async<single[]>
GetContour: Guid -> FrameIdx -> FieldKind -> GroupKind list -> ParticleKind list -> LayerIdx list -> ContourKind -> double -> Async<(float*float) [][]>
GetSeries: Guid -> FrameIdx * FrameIdx -> FieldKind -> GroupKind list -> ParticleKind list -> ParticleState -> LayerIdx list -> NodeIdx -> Async<single[]>
GetField:
Guid
-> FrameIdx
-> FieldKind
-> GroupKind list
-> ParticleKind list
-> ParticleState
-> LayerIdx list
-> Async<single[]>
GetContour:
Guid
-> FrameIdx
-> FieldKind
-> GroupKind list
-> ParticleKind list
-> LayerIdx list
-> ContourKind
-> double
-> Async<(float * float)[][]>
GetSeries:
Guid
-> FrameIdx * FrameIdx
-> FieldKind
-> GroupKind list
-> ParticleKind list
-> ParticleState
-> LayerIdx list
-> NodeIdx
-> Async<single[]>
}
type FieldMetaData = {
@@ -118,7 +174,8 @@ module Api =
/// <summary>
/// Fetches wind velocities from the given archive at a given time 't', with a number of arrows 'n', from tile map coordinates 'x', 'y', and 'z'
/// </summary>
WindTile: Guid -> int (*t*) -> int (*n*)-> int (*z*) -> int (*x*) -> int (*y*) -> Async<V2<single> option array>
WindTile:
Guid -> int (*t*) -> int (*n*) -> int (*z*) -> int (*x*) -> int (*y*) -> Async<V2<single> option array>
/// <summary>
/// Fetches json that describes barb shapes and their corresponding speeds to which they should be drawn.
/// </summary>
@@ -160,41 +217,48 @@ module Api =
type FvStatsSeries = {
GetSalinity: Guid -> StatMetric -> Layer -> NodeIdx -> Async<single[]>
GetTemperature: Guid -> StatMetric -> Layer -> NodeIdx -> Async<single[]>
GetSpeed: Guid -> StatMetric -> Layer -> ElemIdx -> Async<single[]>
GetSpeed: Guid -> StatMetric -> Layer -> ElemIdx -> Async<single[]>
}
module Crop =
let routeBuilder = routeBuilder "crop"
type Fvcom = {
CropTemp: Guid -> int -> float * float -> float * float -> int * int -> float -> Async<single[]>
CropSalinity: Guid -> int -> float * float -> float * float -> int * int -> float -> Async<single[]>
CropSpeed: Guid -> int -> float * float -> float * float -> int * int -> float -> Async<single[]>
CropUV: Guid -> int -> float * float -> float * float -> int * int -> float -> Async<(single * single)[]>
CropTemp: Guid -> int -> float * float -> float * float -> int * int -> float -> Async<single[]>
CropSalinity: Guid -> int -> float * float -> float * float -> int * int -> float -> Async<single[]>
CropSpeed: Guid -> int -> float * float -> float * float -> int * int -> float -> Async<single[]>
CropUV: Guid -> int -> float * float -> float * float -> int * int -> float -> Async<(single * single)[]>
}
type Stats = {
CropTemp: Guid -> Period -> StatMetric -> float * float -> float * float -> int * int -> float -> Async<single[]>
CropSalinity: Guid -> Period -> StatMetric -> float * float -> float * float -> int * int -> float -> Async<single[]>
CropSpeed: Guid -> Period -> StatMetric -> float * float -> float * float -> int * int -> float -> Async<single[]>
CropUV: Guid -> Period -> StatMetric -> float * float -> float * float -> int * int -> float -> Async<(single * single)[]>
CropTemp:
Guid -> Period -> StatMetric -> float * float -> float * float -> int * int -> float -> Async<single[]>
CropSalinity:
Guid -> Period -> StatMetric -> float * float -> float * float -> int * int -> float -> Async<single[]>
CropSpeed:
Guid -> Period -> StatMetric -> float * float -> float * float -> int * int -> float -> Async<single[]>
CropUV:
Guid
-> Period
-> StatMetric
-> float * float
-> float * float
-> int * int
-> float
-> Async<(single * single)[]>
}
module Ocean =
let routeBuilder = routeBuilder "ocean"
type PointRequest = {
aid: Guid
coord: float * float
time: DateTime
}
type PointRequest = { aid: Guid; coord: float * float; time: DateTime }
type TimeseriesRequest = {
aid: Guid
coord: float * float
depth: float
time: DateTime
days: int
aid: Guid
coord: float * float
depth: float
time: DateTime
days: int
}
type Property =

View File

@@ -295,6 +295,7 @@ module Fvcom =
Log.Information("sorcerer: grid: user {username} -> {RequestPath}", ctx.User.Identity.Name, ctx.Request.Path)
let uid = ctx.User.Identity.Name
let observer = ctx.GetService<ObserverFactory>().Create(uid, tag="Fvcom.layer")
let s = Diagnostics.Stopwatch ()
{
GetBathymetry =
fun aid ->
@@ -308,38 +309,52 @@ module Fvcom =
GetSalinity =
fun aid t l ->
async {
let logData = {| aid = aid; t = t; l = l |}
use _ = observer.trace ("GetSalinity", "{@log_data}", logData)
return
s.Start ()
let salt =
Fvcom.salinity aid t l
|> Result.defaultValue Array.empty
s.Stop ()
Log.Debug $"Salt time: {s.Elapsed.TotalMilliseconds}"
return salt
}
GetTemperature =
fun aid t l ->
async {
let logData = {| aid = aid; t = t; l = l |}
use _ = observer.trace ("GetTemperature", "{@log_data}", logData)
return
s.Start ()
// let logData = {| aid = aid; t = t; l = l |}
// use _ = observer.trace ("GetTemperature", "{@log_data}", logData)
let temp =
Fvcom.temp aid t l
|> Result.defaultValue Array.empty
s.Stop ()
Log.Debug $"Temp time: {s.Elapsed.TotalMilliseconds}"
return temp
}
GetZeta =
fun aid t ->
async {
let logData = {| aid = aid; t = t |}
use _ = observer.trace ("GetZeta", "{@log_data}", logData)
return
s.Start ()
// let logData = {| aid = aid; t = t |}
// use _ = observer.trace ("GetZeta", "{@log_data}", logData)
let zeta =
Fvcom.zeta aid t
|> Result.defaultValue Array.empty
s.Stop ()
Log.Debug $"Zeta time: {s.Elapsed.TotalMilliseconds}"
return zeta
}
GetSpeed =
fun aid t l ->
async {
let logData = {| aid = aid; t = t; l = l |}
use _ = observer.trace ("GetSpeed", "{@log_data}", logData)
return
s.Start ()
// let logData = {| aid = aid; t = t; l = l |}
// use _ = observer.trace ("GetSpeed", "{@log_data}", logData)
let speed =
Fvcom.speedAtNodes aid t l
|> Result.defaultValue Array.empty
s.Stop ()
Log.Debug $"Speed time: {s.Elapsed.TotalMilliseconds}"
return speed
}
GetUv =
fun aid t l ->
@@ -353,16 +368,117 @@ module Fvcom =
GetUNode =
fun aid t l ->
async {
return
s.Start ()
let u =
Fvcom.uAtNodes aid t l
|> Result.defaultValue Array.empty
s.Stop ()
Log.Debug $"U time: {s.Elapsed.TotalMilliseconds}"
return u
}
GetVNode =
fun aid t l ->
async {
return
s.Start ()
let v =
Fvcom.vAtNodes aid t l
|> Result.defaultValue Array.empty
s.Stop ()
Log.Debug $"V time: {s.Elapsed.TotalMilliseconds}"
return v
}
}
let compressedLayerApi (ctx: HttpContext) : Fvcom.CompressedLayer =
Log.Information("sorcerer: grid: user {username} -> {RequestPath}", ctx.User.Identity.Name, ctx.Request.Path)
let s = Diagnostics.Stopwatch ()
{
GetBathymetry =
fun aid ->
async {
return
Settings.shaverArchives
|> Map.tryFind aid
|> Option.map (fun p -> IO.File.ReadAllBytes $"{p}/bathymetry.zfp")
|> Option.defaultValue Array.empty
}
GetSalinity =
fun aid t l ->
async {
s.Start ()
let salt =
Settings.shaverArchives
|> Map.tryFind aid
|> Option.map (fun p -> IO.File.ReadAllBytes $"{p}/salinity-{t}-{l}.zfp")
|> Option.defaultValue Array.empty
s.Stop ()
Log.Debug $"Comp salt time: {s.Elapsed.TotalMilliseconds}"
return salt
}
GetTemperature =
fun aid t l ->
async {
s.Start ()
let temp =
Settings.shaverArchives
|> Map.tryFind aid
|> Option.map (fun p -> IO.File.ReadAllBytes $"{p}/temp-{t}-{l}.zfp")
|> Option.defaultValue Array.empty
s.Stop ()
Log.Debug $"Comp temp time: {s.Elapsed.TotalMilliseconds}"
return temp
}
GetZeta =
fun aid t ->
async {
s.Start ()
let zeta =
Settings.shaverArchives
|> Map.tryFind aid
|> Option.map (fun p -> IO.File.ReadAllBytes $"{p}/zeta-{t}.zfp")
|> Option.defaultValue Array.empty
s.Stop ()
Log.Debug $"Comp zeta time: {s.Elapsed.TotalMilliseconds}"
return zeta
}
GetSpeed =
fun aid t l ->
async {
s.Start ()
let speed =
Settings.shaverArchives
|> Map.tryFind aid
|> Option.map (fun p -> IO.File.ReadAllBytes $"{p}/speed-{t}-{l}.zfp")
|> Option.defaultValue Array.empty
s.Stop ()
Log.Debug $"Comp speed time: {s.Elapsed.TotalMilliseconds}"
return speed
}
GetUNode =
fun aid t l ->
async {
s.Start ()
let u =
Settings.shaverArchives
|> Map.tryFind aid
|> Option.map (fun p -> IO.File.ReadAllBytes $"{p}/UNode-{t}-{l}.zfp")
|> Option.defaultValue Array.empty
s.Stop ()
Log.Debug $"Comp U time: {s.Elapsed.TotalMilliseconds}"
return u
}
GetVNode =
fun aid t l ->
async {
s.Start ()
let v =
Settings.shaverArchives
|> Map.tryFind aid
|> Option.map (fun p -> IO.File.ReadAllBytes $"{p}/VNode-{t}-{l}.zfp")
|> Option.defaultValue Array.empty
s.Stop ()
Log.Debug $"Comp V time: {s.Elapsed.TotalMilliseconds}"
return v
}
}
@@ -845,6 +961,13 @@ module Endpoints =
|> Remoting.withBinarySerialization
|> Remoting.buildHttpHandler
let compressedLayerEndpoints: HttpHandler =
Remoting.createApi ()
|> Remoting.fromContext Fvcom.compressedLayerApi
|> Remoting.withRouteBuilder Fvcom.routeBuilder
|> Remoting.withBinarySerialization
|> Remoting.buildHttpHandler
let nodeEndpoints: HttpHandler =
Remoting.createApi ()
|> Remoting.fromContext Fvcom.nodeApi

View File

@@ -227,6 +227,7 @@ let webApp: HttpHandler =
routeStartsWith "/api/v2" >=> requireViewPermission >=> choose [
Fvcom.archiveEndpoints
Fvcom.layerEndpoints
Fvcom.compressedLayerEndpoints
Fvcom.nodeEndpoints
Fvcom.elementEndpoints
Fvcom.batchEndpoints

View File

@@ -272,6 +272,25 @@ let private archiveService: Archmaester.Dto.ArchiveService = {
let archiveAgent = ArchiveAgent.ArchiveAgent(archiveService)
let dataAgent = new DatasetAgent.DatasetAgent(archiveAgent)
// NOTE: Hacky hard-coded solution for now
let shaverArchives : Map<Guid, string> =
Map
[
Guid "0581b47d-89ac-46ae-ad41-c3cfbf02a371", "/data/archives/Oty/Napp-1"
Guid "1954c96b-79d3-4f5b-8802-1b6020eca473", "/data/archives/Oty/Napp-2"
Guid "799a83cb-8250-4dc1-a4da-6d6e507528d1", "/data/archives/Oty/Napp-3"
Guid "80b3a73c-d0d7-4893-87b0-e41c513b95d8", "/data/archives/Oty/Napp-4"
Guid "7c817a9e-2b02-467e-b8b0-16ea78675dfc", "/data/archives/Oty/Napp-5"
Guid "4f6a655c-f79c-4911-9474-139ea1bc0596", "/data/archives/Oty/Napp-6"
Guid "f7605499-12e2-46e0-a413-492f75218169", "/data/archives/Oty/Napp-7"
Guid "11d9a61c-bd2c-4c4c-8943-1f2d1af91584", "/data/archives/Oty/Napp-8"
Guid "4f5385b2-5164-475c-93cb-8c45ed27ddf4", "/data/archives/Oty/Napp-9"
Guid "c518fe07-bf3c-49f4-9704-52d516d1f3bf", "/data/archives/Oty/Napp-10"
Guid "c9849c87-eb7f-4c50-8add-b347e13b0bb5", "/data/archives/Oty/Napp-11"
Guid "db88a44e-2d08-441c-826c-9a298b1dbb1e", "/data/archives/Oty/Napp-12"
Guid "006e1823-1f1b-4b09-8769-4b63a3273515", "/data/archives/Oty/PO5"
]
let barbsJson =
let txt = File.ReadAllText "public/arrows.json"
match Decode.Auto.fromString<Sorcerer.Types.Arrow<float> array> txt with