chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:25:07 +08:00
commit a26e856398
1681 changed files with 296950 additions and 0 deletions
+38
View File
@@ -0,0 +1,38 @@
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
# ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
# ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
# ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
# ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
# ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
# ┃ Copyright (c) 2017, the Perspective Authors. ┃
# ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
# ┃ This file is part of the Perspective library, distributed under the terms ┃
# ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
[package]
name = "rust-axum"
version = "4.5.2"
edition = "2024"
publish = false
[features]
default = []
# TODO(texodus): Due to feature unification and `wasm_bindgen_futures`
# requirements for `Send` bounds interacting poorly with `rust-analyzer`,
# this cannot require the "axum-ws" feature by defualt without impacting
# developer sanity. In a stand-alone project outside the perspective repo, this
# hack is not necessary.
#
# This feature flag is passed on the CLI by `package.json` instead.
_hack = ["perspective/axum-ws"]
[dependencies]
perspective = { version = "4.5.2", default-features = false }
axum = { version = ">=0.8,<0.9", features = ["ws"] }
futures = "0.3"
tokio = { version = "1.0", features = ["full"] }
tower-http = { version = "0.5.0", features = ["fs", "trace"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
+15
View File
@@ -0,0 +1,15 @@
{
"name": "rust-axum",
"private": true,
"version": "4.5.2",
"description": "An example of a Rust/Axum virtual Perspective server",
"scripts": {
"start": "cargo run --target=$(rustc -vV | sed -n 's|host: ||p') --features=_hack"
},
"keywords": [],
"license": "Apache-2.0",
"dependencies": {
"superstore-arrow": "catalog:"
},
"devDependencies": {}
}
+38
View File
@@ -0,0 +1,38 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" />
<script type="module" src="/node_modules/@perspective-dev/viewer/dist/cdn/perspective-viewer.js"></script>
<script type="module" src="/node_modules/@perspective-dev/viewer-datagrid/dist/cdn/perspective-viewer-datagrid.js"></script>
<script type="module" src="/node_modules/@perspective-dev/viewer-charts/dist/cdn/perspective-viewer-charts.js"></script>
<link rel="preload" href="/node_modules/@perspective-dev/viewer/dist/wasm/perspective-viewer.wasm" as="fetch" type="application/wasm" crossorigin="anonymous" />
<link rel="stylesheet" crossorigin="anonymous" href="/node_modules/@perspective-dev/viewer/dist/css/themes.css" />
<script type="module">
import "/node_modules/@perspective-dev/viewer/dist/cdn/perspective-viewer.js";
import perspective from "/node_modules/@perspective-dev/client/dist/cdn/perspective.js";
const socket = await perspective.websocket("/ws");
const table = socket.open_table("my_data_source");
const viewer = document.getElementsByTagName("perspective-viewer")[0];
viewer.load(table);
viewer.restore({ settings: true, plugin_config: { edit_mode: "EDIT" } });
</script>
<style>
perspective-viewer {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
</style>
</head>
<body>
<perspective-viewer></perspective-viewer>
</body>
</html>
+91
View File
@@ -0,0 +1,91 @@
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
// ┃ This file is part of the Perspective library, distributed under the terms ┃
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
use std::fs::File;
use std::io::Read;
#[cfg(feature = "_hack")]
use std::net::SocketAddr;
#[cfg(feature = "_hack")]
use axum::Router;
#[cfg(feature = "_hack")]
use axum::routing::get_service;
use perspective::client::{TableInitOptions, UpdateData};
use perspective::server::Server;
#[cfg(feature = "_hack")]
use tower_http::{
services::{ServeDir, ServeFile},
trace::TraceLayer,
};
use tracing_subscriber::filter::LevelFilter;
use tracing_subscriber::fmt::layer;
use tracing_subscriber::prelude::*;
use tracing_subscriber::registry;
const ROOT_PATH: &str = ".";
const ARROW_FILE_PATH: &str = "node_modules/superstore-arrow/superstore.arrow";
#[cfg(feature = "_hack")]
const SERVER_ADDRESS: &str = "0.0.0.0:3000";
/// A local error synonym for this module only.
type AppError = Box<dyn std::error::Error + Send + Sync>;
/// Load the example Apache Arrow file from disk and create a
/// [`perspective::Table`] named "my_data_source".
async fn load_server_arrow(server: &Server) -> Result<(), AppError> {
let client = server.new_local_client();
let mut file = File::open(std::path::Path::new(ROOT_PATH).join(ARROW_FILE_PATH))?;
let mut feather = Vec::with_capacity(file.metadata()?.len() as usize);
file.read_to_end(&mut feather)?;
let data = UpdateData::Arrow(feather.into());
let mut options = TableInitOptions::default();
options.set_name("my_data_source");
client.table(data.into(), options).await?;
client.close().await;
Ok(())
}
/// Host a combination HTTP file server + WebSocket server, which serves a
/// simple Perspective application. The app's HTML, etc., assets are served
/// from the root, while the app's embedded WebAssembly [`perspective::Client`]
/// will connect to this server over a WebSocket via the path `/ws`.
async fn start_web_server_and_block(_server: Server) -> Result<(), AppError> {
#[cfg(feature = "_hack")]
{
let app = Router::new()
.route("/", get_service(ServeFile::new("src/index.html")))
.route("/ws", perspective::axum::websocket_handler())
.fallback_service(ServeDir::new(ROOT_PATH))
.with_state(_server)
.layer(TraceLayer::new_for_http());
let service = app.into_make_service_with_connect_info::<SocketAddr>();
let listener = tokio::net::TcpListener::bind(SERVER_ADDRESS).await?;
tracing::info!("listening on {}", listener.local_addr()?);
axum::serve(listener, service).await?;
}
Ok(())
}
#[tokio::main(flavor = "multi_thread")]
async fn main() -> Result<(), AppError> {
registry()
.with(layer().compact().with_filter(LevelFilter::INFO))
.init();
let server = Server::new(None);
load_server_arrow(&server).await?;
start_web_server_and_block(server).await?;
Ok(())
}