mirror of
https://github.com/alexgo-io/bitcoin-indexer.git
synced 2026-01-12 22:43:06 +08:00
feat: draft ordhook-sdk-js
This commit is contained in:
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -440,8 +440,6 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
[[package]]
|
||||
name = "chainhook-sdk"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbaf86f829fe63fd8aab5fb43483cc8ada8d02537cec76df6a23b77d1a75cb5c"
|
||||
dependencies = [
|
||||
"base58 0.2.0",
|
||||
"base64 0.13.1",
|
||||
@@ -461,7 +459,7 @@ dependencies = [
|
||||
"regex",
|
||||
"reqwest",
|
||||
"rocket",
|
||||
"schemars 0.8.11",
|
||||
"schemars 0.8.12",
|
||||
"serde",
|
||||
"serde-hex",
|
||||
"serde_derive",
|
||||
@@ -475,11 +473,9 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "chainhook-types"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03af00efeffbc0259632c2ffc410663f326f6cdeee604e91971f889648a92c2f"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"schemars 0.8.11",
|
||||
"schemars 0.8.12",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
members = [
|
||||
"components/ordhook-cli",
|
||||
"components/ordhook-core",
|
||||
"components/ordhook-sdk-js"
|
||||
]
|
||||
|
||||
default-members = ["components/ordhook-cli"]
|
||||
|
||||
@@ -21,7 +21,9 @@ use crate::{
|
||||
core::{
|
||||
pipeline::processors::block_archiving::store_compacted_blocks,
|
||||
protocol::{
|
||||
inscription_parsing::{get_inscriptions_revealed_in_block, get_inscriptions_transferred_in_block},
|
||||
inscription_parsing::{
|
||||
get_inscriptions_revealed_in_block, get_inscriptions_transferred_in_block,
|
||||
},
|
||||
inscription_sequencing::{
|
||||
augment_block_with_ordinals_inscriptions_data_and_write_to_db_tx,
|
||||
parallelize_inscription_data_computations, SequenceCursor,
|
||||
|
||||
@@ -6,7 +6,7 @@ use chainhook_sdk::bitcoincore_rpc_json::bitcoin::Txid;
|
||||
use chainhook_sdk::indexer::bitcoin::{standardize_bitcoin_block, BitcoinBlockFullBreakdown};
|
||||
use chainhook_sdk::types::{
|
||||
BitcoinBlockData, BitcoinNetwork, BitcoinTransactionData, OrdinalInscriptionCurseType,
|
||||
OrdinalInscriptionRevealData, OrdinalOperation, OrdinalInscriptionTransferData,
|
||||
OrdinalInscriptionRevealData, OrdinalInscriptionTransferData, OrdinalOperation,
|
||||
};
|
||||
use chainhook_sdk::utils::Context;
|
||||
use chainhook_sdk::{
|
||||
|
||||
@@ -19,7 +19,7 @@ use chainhook_sdk::chainhooks::types::BitcoinChainhookSpecification;
|
||||
use chainhook_sdk::indexer::bitcoin::{
|
||||
build_http_client, download_and_parse_block_with_retry, retrieve_block_hash_with_retry,
|
||||
};
|
||||
use chainhook_sdk::observer::{gather_proofs, EventObserverConfig};
|
||||
use chainhook_sdk::observer::{gather_proofs, DataHandlerEvent, EventObserverConfig};
|
||||
use chainhook_sdk::types::{
|
||||
BitcoinBlockData, BitcoinChainEvent, BitcoinChainUpdatedWithBlocksData,
|
||||
};
|
||||
@@ -273,7 +273,7 @@ pub async fn execute_predicates_action<'a>(
|
||||
}
|
||||
BitcoinChainhookOccurrence::Data(payload) => {
|
||||
if let Some(ref tx) = config.data_handler_tx {
|
||||
let _ = tx.send(payload);
|
||||
let _ = tx.send(DataHandlerEvent::Process(payload));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -31,8 +31,8 @@ use chainhook_sdk::chainhooks::types::{
|
||||
BitcoinChainhookSpecification, ChainhookFullSpecification, ChainhookSpecification,
|
||||
};
|
||||
use chainhook_sdk::observer::{
|
||||
start_event_observer, BitcoinBlockDataCached, EventObserverConfig, HandleBlock,
|
||||
ObserverCommand, ObserverEvent, ObserverSidecar,
|
||||
start_event_observer, BitcoinBlockDataCached, DataHandlerEvent, EventObserverConfig,
|
||||
HandleBlock, ObserverCommand, ObserverEvent, ObserverSidecar,
|
||||
};
|
||||
use chainhook_sdk::types::{BitcoinBlockData, BlockIdentifier};
|
||||
use chainhook_sdk::utils::{BlockHeights, Context};
|
||||
@@ -374,7 +374,7 @@ impl Service {
|
||||
) -> Result<
|
||||
(
|
||||
EventObserverConfig,
|
||||
Option<crossbeam_channel::Receiver<BitcoinChainhookOccurrencePayload>>,
|
||||
Option<crossbeam_channel::Receiver<DataHandlerEvent>>,
|
||||
),
|
||||
String,
|
||||
> {
|
||||
@@ -456,9 +456,7 @@ impl Service {
|
||||
&self.ctx,
|
||||
)?;
|
||||
}
|
||||
|
||||
let tx_replayer = start_observer_forwarding(event_observer_config, &self.ctx);
|
||||
|
||||
self.update_state(Some(tx_replayer)).await?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -469,7 +467,6 @@ impl Service {
|
||||
) -> Result<(), String> {
|
||||
// Start predicate processor
|
||||
let mut last_block_processed = 0;
|
||||
|
||||
while let Some((start_block, end_block, speed)) =
|
||||
should_sync_ordhook_db(&self.config, &self.ctx)?
|
||||
{
|
||||
@@ -482,10 +479,12 @@ impl Service {
|
||||
block_post_processor.clone(),
|
||||
);
|
||||
|
||||
info!(
|
||||
self.ctx.expect_logger(),
|
||||
"Indexing inscriptions from block #{start_block} to block #{end_block}"
|
||||
);
|
||||
self.ctx.try_log(|logger| {
|
||||
info!(
|
||||
logger,
|
||||
"Indexing inscriptions from block #{start_block} to block #{end_block}"
|
||||
)
|
||||
});
|
||||
|
||||
let ordhook_config = self.config.get_ordhook_config();
|
||||
let first_inscription_height = ordhook_config.first_inscription_height;
|
||||
@@ -515,7 +514,7 @@ impl Service {
|
||||
let blocks_post_processor =
|
||||
start_transfers_recomputing_processor(&self.config, &self.ctx, block_post_processor);
|
||||
|
||||
let ordhook_config = self.config.get_ordhook_config();
|
||||
let ordhook_config = self.config.get_ordhook_config();
|
||||
let first_inscription_height = ordhook_config.first_inscription_height;
|
||||
download_and_pipeline_blocks(
|
||||
&self.config,
|
||||
|
||||
4755
components/ordhook-sdk-js/Cargo.lock
generated
Normal file
4755
components/ordhook-sdk-js/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
25
components/ordhook-sdk-js/Cargo.toml
Normal file
25
components/ordhook-sdk-js/Cargo.toml
Normal file
@@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "ordhook-sdk-js"
|
||||
version = "0.2.0"
|
||||
license = "ISC"
|
||||
edition = "2018"
|
||||
exclude = ["index.node"]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
serde = "1"
|
||||
error-chain = "0.12"
|
||||
ordhook = { path = "../ordhook-core" }
|
||||
hiro-system-kit = "0.1.0"
|
||||
crossbeam-channel = "0.5.6"
|
||||
|
||||
[dependencies.neon]
|
||||
version = "0.9.1"
|
||||
default-features = false
|
||||
features = ["napi-4", "channel-api", "event-queue-api", "try-catch-api"]
|
||||
|
||||
[dependencies.num]
|
||||
version = "0.2"
|
||||
default-features = false
|
||||
58
components/ordhook-sdk-js/README.md
Normal file
58
components/ordhook-sdk-js/README.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# ordhook-sdk-js
|
||||
|
||||
`ordhook-sdk-js` is a node library, designed to let developers write protocols sitting on top of the Ordinals theory.
|
||||
It is implemented as a dynamic library that can be loaded by Node.
|
||||
|
||||
### Installation
|
||||
|
||||
```console
|
||||
# Yarn
|
||||
yarn add dev @hirosystems/ordhook-sdk-js
|
||||
|
||||
# NPM
|
||||
npm install --save-dev @hirosystems/ordhook-sdk-js
|
||||
```
|
||||
|
||||
If any error occurs during the installation of this package, feel free to open an issue on this repository.
|
||||
|
||||
|
||||
### Usage
|
||||
|
||||
```typescript
|
||||
import { OrdinalsIndexer } from "@hirosystems/ordhook-sdk-js";
|
||||
|
||||
let indexer = new OrdinalsIndexer({
|
||||
bitcoinRpcUrl: 'http://localhost:8332',
|
||||
bitcoinRpcUsername: 'devnet',
|
||||
bitcoinRpcPassword: 'devnet',
|
||||
workingDirectory: '/etc/ordinals/db'
|
||||
logs: true
|
||||
});
|
||||
|
||||
indexer.applyBlock((block) => {
|
||||
|
||||
})
|
||||
|
||||
indexer.undoBlock((block) => {
|
||||
|
||||
})
|
||||
|
||||
indexer.onTermination(() => {
|
||||
|
||||
})
|
||||
|
||||
indexer.start();
|
||||
|
||||
|
||||
// indexer.dropBlock();
|
||||
// indexer.recomputeBlock();
|
||||
// indexer.replayBlocks();
|
||||
|
||||
```
|
||||
|
||||
### Case Study
|
||||
|
||||
BRC20
|
||||
|
||||
### Screencasts
|
||||
|
||||
71
components/ordhook-sdk-js/lib/index.ts
Normal file
71
components/ordhook-sdk-js/lib/index.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
ordinalsIndexerNew,
|
||||
ordinalsIndexerStart,
|
||||
ordinalsIndexerOnBlockApply,
|
||||
ordinalsIndexerOnBlockUndo,
|
||||
} = require("../native/index.node");
|
||||
|
||||
// import {
|
||||
// BitcoinChainUpdate,
|
||||
// Block,
|
||||
// StacksBlockMetadata,
|
||||
// StacksBlockUpdate,
|
||||
// StacksChainUpdate,
|
||||
// StacksTransaction,
|
||||
// StacksTransactionMetadata,
|
||||
// Transaction,
|
||||
// } from "@hirosystems/chainhook-types";
|
||||
// export * from "@hirosystems/chainhook-types";
|
||||
|
||||
export class OrdinalsIndexer {
|
||||
handle: any;
|
||||
|
||||
/**
|
||||
* @summary Construct a new OrdinalsIndexer
|
||||
* @param
|
||||
* @memberof OrdinalsIndexer
|
||||
*/
|
||||
constructor(settings: {
|
||||
bitcoinRpcUrl: string,
|
||||
bitcoinRpcUsername: string,
|
||||
bitcoinRpcPassword: string,
|
||||
workingDirectory: string,
|
||||
logs: boolean,
|
||||
}) {
|
||||
this.handle = ordinalsIndexerNew(settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Start indexing ordinals
|
||||
* @memberof OrdinalsIndexer
|
||||
*/
|
||||
start() {
|
||||
return ordinalsIndexerStart.call(this.handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Apply Block
|
||||
* @memberof OrdinalsIndexer
|
||||
*/
|
||||
applyBlock(callback: (block: any) => void) {
|
||||
return ordinalsIndexerOnBlockApply.call(this.handle, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Undo Block
|
||||
* @memberof OrdinalsIndexer
|
||||
*/
|
||||
undoBlock(callback: (block: any) => void) {
|
||||
return ordinalsIndexerOnBlockUndo.call(this.handle, callback);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @summary Terminates the containers
|
||||
// * @memberof DevnetNetworkOrchestrator
|
||||
// */
|
||||
// terminate(): boolean {
|
||||
// return stacksDevnetTerminate.call(this.handle);
|
||||
// }
|
||||
}
|
||||
19
components/ordhook-sdk-js/lib/test.ts
Normal file
19
components/ordhook-sdk-js/lib/test.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { OrdinalsIndexer } from "./index";
|
||||
|
||||
const indexer = new OrdinalsIndexer({
|
||||
bitcoinRpcUrl: 'http://0.0.0.0:8332',
|
||||
bitcoinRpcUsername: 'devnet',
|
||||
bitcoinRpcPassword: 'devnet',
|
||||
workingDirectory: '/Users/ludovic/ordhook-sdk-js',
|
||||
logs: false
|
||||
});
|
||||
|
||||
indexer.applyBlock(block => {
|
||||
console.log(`Hello from JS ${JSON.stringify(block)}`);
|
||||
});
|
||||
|
||||
indexer.undoBlock(block => {
|
||||
console.log(`Hello from JS ${JSON.stringify(block)}`);
|
||||
});
|
||||
|
||||
indexer.start();
|
||||
2552
components/ordhook-sdk-js/package-lock.json
generated
Normal file
2552
components/ordhook-sdk-js/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
48
components/ordhook-sdk-js/package.json
Normal file
48
components/ordhook-sdk-js/package.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "@hirosystems/ordhook-sdk-js",
|
||||
"version": "1.7.1",
|
||||
"description": "ordhook-sdk-js is a library for writing protocols .",
|
||||
"author": "Ludo Galabru",
|
||||
"repository": "https://github.com/hirosystems/ordhook/tree/main/components/ordhook-sdk-js",
|
||||
"license": "GPL-3.0",
|
||||
"main": "dist/index.js",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc --build && cargo-cp-artifact -nc native/index.node -- cargo build --message-format=json-render-diagnostics",
|
||||
"build-debug": "npm run build --",
|
||||
"build-release": "npm run build -- --release",
|
||||
"build-linux-x64-glibc": "npm run build-release -- --target x86_64-unknown-linux-gnu",
|
||||
"build-linux-x64-musl": "npm run build-release -- --target x86_64-unknown-linux-musl",
|
||||
"build-windows-x64": "npm run build-release -- --target x86_64-pc-windows-msvc",
|
||||
"build-darwin-x64": "npm run build-release -- --target x86_64-apple-darwin",
|
||||
"build-darwin-arm64": "npm run build-release -- --target aarch64-apple-darwin",
|
||||
"install": "node-pre-gyp install --fallback-to-build=false || npm run build-release",
|
||||
"lint": "eslint .",
|
||||
"package": "node-pre-gyp package",
|
||||
"spec": "jest",
|
||||
"test": "npm run build && npm run spec",
|
||||
"upload-binary": "npm run build-release && node-pre-gyp package && node-pre-gyp-github publish",
|
||||
"version": "npm run build-release"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hirosystems/chainhook-types": "^1.1.2",
|
||||
"@mapbox/node-pre-gyp": "^1.0.8",
|
||||
"neon-cli": "^0.9.1",
|
||||
"node-pre-gyp-github": "^1.4.3",
|
||||
"typescript": "^4.5.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.11",
|
||||
"cargo-cp-artifact": "^0.1"
|
||||
},
|
||||
"binary": {
|
||||
"module_name": "index",
|
||||
"host": "https://github.com/hirosystems/clarinet/releases/download/",
|
||||
"remote_path": "v{version}",
|
||||
"package_name": "stacks-devnet-js-{platform}-{arch}-{libc}.tar.gz",
|
||||
"module_path": "./native",
|
||||
"pkg_path": "."
|
||||
}
|
||||
}
|
||||
308
components/ordhook-sdk-js/src/lib.rs
Normal file
308
components/ordhook-sdk-js/src/lib.rs
Normal file
@@ -0,0 +1,308 @@
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
|
||||
mod serde;
|
||||
|
||||
use core::panic;
|
||||
use crossbeam_channel::{select, Sender};
|
||||
use neon::prelude::*;
|
||||
use ordhook::chainhook_sdk::chainhooks::bitcoin::{
|
||||
BitcoinApplyTransactionPayload, BitcoinRollbackTransactionPayload,
|
||||
};
|
||||
use ordhook::chainhook_sdk::observer::DataHandlerEvent;
|
||||
use ordhook::chainhook_sdk::utils::Context as OrdhookContext;
|
||||
use ordhook::config::Config;
|
||||
use ordhook::db::{initialize_ordhook_db, open_readwrite_ordhook_db_conn_rocks_db};
|
||||
use ordhook::service::Service;
|
||||
use std::thread;
|
||||
|
||||
type ApplyCallback = Box<dyn FnOnce(&Channel, BitcoinApplyTransactionPayload) + Send>;
|
||||
type UndoCallback = Box<dyn Fn(&Channel, BitcoinRollbackTransactionPayload) + Send>;
|
||||
|
||||
struct OrdinalsIndexerConfig {
|
||||
pub bitcoin_rpc_url: String,
|
||||
pub bitcoin_rpc_username: String,
|
||||
pub bitcoin_rpc_password: String,
|
||||
pub working_directory: String,
|
||||
pub logs_enabled: bool,
|
||||
}
|
||||
|
||||
impl OrdinalsIndexerConfig {
|
||||
pub fn default() -> OrdinalsIndexerConfig {
|
||||
OrdinalsIndexerConfig {
|
||||
bitcoin_rpc_url: "http://0.0.0.0:8332".to_string(),
|
||||
bitcoin_rpc_username: "devnet".to_string(),
|
||||
bitcoin_rpc_password: "devnet".to_string(),
|
||||
working_directory: "/tmp/ordinals".to_string(),
|
||||
logs_enabled: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct OrdinalsIndexer {
|
||||
command_tx: Sender<IndexerCommand>,
|
||||
custom_indexer_command_tx: Sender<CustomIndexerCommand>,
|
||||
}
|
||||
|
||||
enum IndexerCommand {
|
||||
Start,
|
||||
Stop,
|
||||
}
|
||||
|
||||
enum CustomIndexerCommand {
|
||||
UpdateApplyCallback(Root<JsFunction>),
|
||||
UpdateUndoCallback(Root<JsFunction>),
|
||||
}
|
||||
|
||||
impl Finalize for OrdinalsIndexer {}
|
||||
|
||||
impl OrdinalsIndexer {
|
||||
fn new<'a, C>(cx: &mut C, ordhook_config: Config) -> Self
|
||||
where
|
||||
C: Context<'a>,
|
||||
{
|
||||
let (command_tx, command_rx) = crossbeam_channel::unbounded();
|
||||
let (custom_indexer_command_tx, custom_indexer_command_rx) = crossbeam_channel::unbounded();
|
||||
|
||||
let logger = hiro_system_kit::log::setup_logger();
|
||||
let _guard = hiro_system_kit::log::setup_global_logger(logger.clone());
|
||||
let ctx = OrdhookContext {
|
||||
logger: Some(logger),
|
||||
tracer: false,
|
||||
};
|
||||
|
||||
// Initialize service
|
||||
// {
|
||||
// let _ = initialize_ordhook_db(&ordhook_config.expected_cache_path(), &ctx);
|
||||
// let _ = open_readwrite_ordhook_db_conn_rocks_db(&ordhook_config.expected_cache_path(), &ctx);
|
||||
// }
|
||||
let mut service: Service = Service::new(ordhook_config, ctx);
|
||||
|
||||
// Set-up the observer sidecar - used for augmenting the bitcoin blocks with
|
||||
// ordinals informations
|
||||
let observer_sidecar = service
|
||||
.set_up_observer_sidecar_runloop()
|
||||
.expect("unable to setup indexer");
|
||||
// Prepare internal predicate
|
||||
let (observer_config, payload_rx) = service
|
||||
.set_up_observer_config(vec![], true)
|
||||
.expect("unable to setup indexer");
|
||||
|
||||
// Indexing thread
|
||||
let channel = cx.channel();
|
||||
thread::spawn(move || {
|
||||
let payload_rx = payload_rx.unwrap();
|
||||
|
||||
channel.send(move |mut cx| {
|
||||
let mut apply_callback: Option<Root<JsFunction>> = None;
|
||||
let mut undo_callback: Option<Root<JsFunction>> = None;
|
||||
|
||||
loop {
|
||||
select! {
|
||||
recv(payload_rx) -> msg => {
|
||||
match msg {
|
||||
Ok(DataHandlerEvent::Process(payload)) => {
|
||||
if let Some(ref callback) = undo_callback {
|
||||
for to_rollback in payload.rollback.into_iter() {
|
||||
let callback = callback.clone(&mut cx).into_inner(&mut cx);
|
||||
let this = cx.undefined();
|
||||
let payload = serde::to_value(&mut cx, &to_rollback).expect("Unable to serialize block");
|
||||
let args: Vec<Handle<JsValue>> = vec![payload];
|
||||
callback.call(&mut cx, this, args)?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref callback) = apply_callback {
|
||||
for to_apply in payload.apply.into_iter() {
|
||||
let callback = callback.clone(&mut cx).into_inner(&mut cx);
|
||||
let this = cx.undefined();
|
||||
let payload = serde::to_value(&mut cx, &to_apply).expect("Unable to serialize block");
|
||||
let args: Vec<Handle<JsValue>> = vec![payload];
|
||||
callback.call(&mut cx, this, args)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(DataHandlerEvent::Terminate) => {
|
||||
return Ok(());
|
||||
}
|
||||
_ => {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
recv(custom_indexer_command_rx) -> msg => {
|
||||
match msg {
|
||||
Ok(CustomIndexerCommand::UpdateApplyCallback(callback)) => {
|
||||
apply_callback = Some(callback);
|
||||
}
|
||||
Ok(CustomIndexerCommand::UpdateUndoCallback(callback)) => {
|
||||
undo_callback = Some(callback);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Processing thread
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
let cmd = match command_rx.recv() {
|
||||
Ok(cmd) => cmd,
|
||||
Err(e) => {
|
||||
panic!("Runloop error: {}", e.to_string());
|
||||
}
|
||||
};
|
||||
|
||||
match cmd {
|
||||
IndexerCommand::Start => {
|
||||
// We start the service as soon as the start() method is being called.
|
||||
let future = service.catch_up_with_chain_tip(false, &observer_config);
|
||||
let _ = hiro_system_kit::nestable_block_on(future)
|
||||
.expect("unable to start indexer");
|
||||
let future = service.start_event_observer(observer_sidecar);
|
||||
let (command_tx, event_rx) = hiro_system_kit::nestable_block_on(future)
|
||||
.expect("unable to start indexer");
|
||||
// Blocking call
|
||||
let _ = service.start_main_runloop(&command_tx, event_rx, None);
|
||||
break;
|
||||
}
|
||||
IndexerCommand::Stop => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Self {
|
||||
command_tx,
|
||||
custom_indexer_command_tx,
|
||||
// termination_rx,
|
||||
}
|
||||
}
|
||||
|
||||
fn start(&self) -> Result<bool, String> {
|
||||
let _ = self.command_tx.send(IndexerCommand::Start);
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn update_apply_callback(&self, callback: Root<JsFunction>) -> Result<bool, String> {
|
||||
let _ = self
|
||||
.custom_indexer_command_tx
|
||||
.send(CustomIndexerCommand::UpdateApplyCallback(callback));
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn update_undo_callback(&self, callback: Root<JsFunction>) -> Result<bool, String> {
|
||||
let _ = self
|
||||
.custom_indexer_command_tx
|
||||
.send(CustomIndexerCommand::UpdateUndoCallback(callback));
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
impl OrdinalsIndexer {
|
||||
fn js_new(mut cx: FunctionContext) -> JsResult<JsBox<OrdinalsIndexer>> {
|
||||
let settings = cx.argument::<JsObject>(0)?;
|
||||
|
||||
let mut config = OrdinalsIndexerConfig::default();
|
||||
|
||||
if let Ok(res) = settings
|
||||
.get(&mut cx, "bitcoinRpcUrl")?
|
||||
.downcast::<JsString, _>(&mut cx)
|
||||
{
|
||||
config.bitcoin_rpc_url = res.value(&mut cx);
|
||||
}
|
||||
if let Ok(res) = settings
|
||||
.get(&mut cx, "bitcoinRpcUsername")?
|
||||
.downcast::<JsString, _>(&mut cx)
|
||||
{
|
||||
config.bitcoin_rpc_username = res.value(&mut cx);
|
||||
}
|
||||
|
||||
if let Ok(res) = settings
|
||||
.get(&mut cx, "bitcoinRpcPassword")?
|
||||
.downcast::<JsString, _>(&mut cx)
|
||||
{
|
||||
config.bitcoin_rpc_password = res.value(&mut cx);
|
||||
}
|
||||
|
||||
if let Ok(res) = settings
|
||||
.get(&mut cx, "workingDirectory")?
|
||||
.downcast::<JsString, _>(&mut cx)
|
||||
{
|
||||
config.working_directory = res.value(&mut cx);
|
||||
}
|
||||
|
||||
if let Ok(res) = settings
|
||||
.get(&mut cx, "logs")?
|
||||
.downcast::<JsBoolean, _>(&mut cx)
|
||||
{
|
||||
config.logs_enabled = res.value(&mut cx);
|
||||
}
|
||||
|
||||
let mut ordhook_config = Config::mainnet_default();
|
||||
ordhook_config.network.bitcoind_rpc_username = config.bitcoin_rpc_username.clone();
|
||||
ordhook_config.network.bitcoind_rpc_password = config.bitcoin_rpc_password.clone();
|
||||
ordhook_config.network.bitcoind_rpc_url = config.bitcoin_rpc_url.clone();
|
||||
ordhook_config.storage.working_dir = config.working_directory.clone();
|
||||
ordhook_config.logs.chainhook_internals = config.logs_enabled;
|
||||
ordhook_config.logs.ordinals_internals = config.logs_enabled;
|
||||
|
||||
let devnet: OrdinalsIndexer = OrdinalsIndexer::new(&mut cx, ordhook_config);
|
||||
Ok(cx.boxed(devnet))
|
||||
}
|
||||
|
||||
fn js_start(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
cx.this()
|
||||
.downcast_or_throw::<JsBox<OrdinalsIndexer>, _>(&mut cx)?
|
||||
.start()
|
||||
.or_else(|err| cx.throw_error(err.to_string()))?;
|
||||
|
||||
Ok(cx.undefined())
|
||||
}
|
||||
|
||||
fn js_terminate(mut cx: FunctionContext) -> JsResult<JsBoolean> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn js_on_block_apply(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
let callback = cx.argument::<JsFunction>(0)?.root(&mut cx);
|
||||
|
||||
cx.this()
|
||||
.downcast_or_throw::<JsBox<OrdinalsIndexer>, _>(&mut cx)?
|
||||
.update_apply_callback(callback)
|
||||
.or_else(|err| cx.throw_error(err.to_string()))?;
|
||||
|
||||
Ok(cx.undefined())
|
||||
}
|
||||
|
||||
fn js_on_block_undo(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
let callback = cx.argument::<JsFunction>(0)?.root(&mut cx);
|
||||
|
||||
cx.this()
|
||||
.downcast_or_throw::<JsBox<OrdinalsIndexer>, _>(&mut cx)?
|
||||
.update_undo_callback(callback)
|
||||
.or_else(|err| cx.throw_error(err.to_string()))?;
|
||||
|
||||
Ok(cx.undefined())
|
||||
}
|
||||
}
|
||||
|
||||
#[neon::main]
|
||||
fn main(mut cx: ModuleContext) -> NeonResult<()> {
|
||||
cx.export_function("ordinalsIndexerNew", OrdinalsIndexer::js_new)?;
|
||||
cx.export_function("ordinalsIndexerStart", OrdinalsIndexer::js_start)?;
|
||||
cx.export_function("ordinalsIndexerTerminate", OrdinalsIndexer::js_terminate)?;
|
||||
cx.export_function(
|
||||
"ordinalsIndexerOnBlockApply",
|
||||
OrdinalsIndexer::js_on_block_apply,
|
||||
)?;
|
||||
cx.export_function(
|
||||
"ordinalsIndexerOnBlockUndo",
|
||||
OrdinalsIndexer::js_on_block_undo,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
84
components/ordhook-sdk-js/src/serde/errors.rs
Normal file
84
components/ordhook-sdk-js/src/serde/errors.rs
Normal file
@@ -0,0 +1,84 @@
|
||||
//! Defines error handling types used by the create
|
||||
//! uses the `error-chain` create for generation
|
||||
|
||||
use neon;
|
||||
use serde::ser;
|
||||
use std::convert::From;
|
||||
use std::fmt::Display;
|
||||
|
||||
error_chain! {
|
||||
errors {
|
||||
/// nodejs has a hard coded limit on string length
|
||||
/// trying to serialize a string that is too long will result in an error
|
||||
StringTooLong(len: usize) {
|
||||
description("String too long for nodejs")
|
||||
display("String too long for nodejs len: {}", len)
|
||||
}
|
||||
/// when deserializing to a boolean `false` `undefined` `null` `number`
|
||||
/// are valid inputs
|
||||
/// any other types will result in error
|
||||
UnableToCoerce(to_type: &'static str) {
|
||||
description("Unable to coerce")
|
||||
display("Unable to coerce value to type: {}", to_type)
|
||||
}
|
||||
/// occurs when deserializing a char from an empty string
|
||||
EmptyString {
|
||||
description("EmptyString")
|
||||
display("EmptyString")
|
||||
}
|
||||
/// occurs when deserializing a char from a sting with
|
||||
/// more than one character
|
||||
StringTooLongForChar(len: usize) {
|
||||
description("String too long to be a char")
|
||||
display("String too long to be a char expected len: 1 got len: {}", len)
|
||||
}
|
||||
/// occurs when a deserializer expects a `null` or `undefined`
|
||||
/// property and found another type
|
||||
ExpectingNull {
|
||||
description("ExpectingNull")
|
||||
display("ExpectingNull")
|
||||
}
|
||||
/// occurs when deserializing to an enum and the source object has
|
||||
/// a none-1 number of properties
|
||||
InvalidKeyType(key: String) {
|
||||
description("InvalidKeyType")
|
||||
display("key: '{}'", key)
|
||||
}
|
||||
/// an internal deserialization error from an invalid array
|
||||
ArrayIndexOutOfBounds(index: u32, length: u32) {
|
||||
description("ArrayIndexOutOfBounds")
|
||||
display(
|
||||
"ArrayIndexOutOfBounds: attempt to access ({}) size: ({})",
|
||||
index,
|
||||
length
|
||||
)
|
||||
} #[doc(hidden)]
|
||||
/// This type of object is not supported
|
||||
NotImplemented(name: &'static str) {
|
||||
description("Not Implemented")
|
||||
display("Not Implemented: '{}'", name)
|
||||
}
|
||||
/// A JS exception was thrown
|
||||
Js(throw: neon::result::Throw) {
|
||||
description("JS exception")
|
||||
display("JS exception")
|
||||
}
|
||||
/// failed to convert something to f64
|
||||
CastError {
|
||||
description("CastError")
|
||||
display("CastError")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ser::Error for Error {
|
||||
fn custom<T: Display>(msg: T) -> Self {
|
||||
ErrorKind::Msg(msg.to_string()).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<neon::result::Throw> for Error {
|
||||
fn from(throw: neon::result::Throw) -> Self {
|
||||
ErrorKind::Js(throw).into()
|
||||
}
|
||||
}
|
||||
4
components/ordhook-sdk-js/src/serde/mod.rs
Normal file
4
components/ordhook-sdk-js/src/serde/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
mod errors;
|
||||
mod ser;
|
||||
|
||||
pub use ser::to_value;
|
||||
575
components/ordhook-sdk-js/src/serde/ser.rs
Normal file
575
components/ordhook-sdk-js/src/serde/ser.rs
Normal file
@@ -0,0 +1,575 @@
|
||||
//!
|
||||
//! Serialize a Rust data structure into a `JsValue`
|
||||
//!
|
||||
|
||||
use super::errors::Error;
|
||||
use super::errors::ErrorKind;
|
||||
use super::errors::Result as LibResult;
|
||||
use neon::prelude::*;
|
||||
use num;
|
||||
use serde::ser::{self, Serialize};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
fn as_num<T: num::cast::NumCast, OutT: num::cast::NumCast>(n: T) -> LibResult<OutT> {
|
||||
match num::cast::<T, OutT>(n) {
|
||||
Some(n2) => Ok(n2),
|
||||
None => bail!(ErrorKind::CastError),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a value of type `V` to a `JsValue`
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// * `NumberCastError` trying to serialize a `u64` can fail if it overflows in a cast to `f64`
|
||||
/// * `StringTooLong` if the string exceeds v8's max string size
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_value<'j, C, V>(cx: &mut C, value: &V) -> LibResult<Handle<'j, JsValue>>
|
||||
where
|
||||
C: Context<'j>,
|
||||
V: Serialize + ?Sized,
|
||||
{
|
||||
let serializer = Serializer {
|
||||
cx,
|
||||
ph: PhantomData,
|
||||
};
|
||||
let serialized_value = value.serialize(serializer)?;
|
||||
Ok(serialized_value)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct Serializer<'a, 'j, C: 'a>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
cx: &'a mut C,
|
||||
ph: PhantomData<&'j ()>,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct ArraySerializer<'a, 'j, C: 'a>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
cx: &'a mut C,
|
||||
array: Handle<'j, JsArray>,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct TupleVariantSerializer<'a, 'j, C: 'a>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
outer_object: Handle<'j, JsObject>,
|
||||
inner: ArraySerializer<'a, 'j, C>,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct MapSerializer<'a, 'j, C: 'a>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
cx: &'a mut C,
|
||||
object: Handle<'j, JsObject>,
|
||||
key_holder: Handle<'j, JsObject>,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct StructSerializer<'a, 'j, C: 'a>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
cx: &'a mut C,
|
||||
object: Handle<'j, JsObject>,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct StructVariantSerializer<'a, 'j, C: 'a>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
outer_object: Handle<'j, JsObject>,
|
||||
inner: StructSerializer<'a, 'j, C>,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<'a, 'j, C> ser::Serializer for Serializer<'a, 'j, C>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
type Ok = Handle<'j, JsValue>;
|
||||
type Error = Error;
|
||||
|
||||
type SerializeSeq = ArraySerializer<'a, 'j, C>;
|
||||
type SerializeTuple = ArraySerializer<'a, 'j, C>;
|
||||
type SerializeTupleStruct = ArraySerializer<'a, 'j, C>;
|
||||
type SerializeTupleVariant = TupleVariantSerializer<'a, 'j, C>;
|
||||
type SerializeMap = MapSerializer<'a, 'j, C>;
|
||||
type SerializeStruct = StructSerializer<'a, 'j, C>;
|
||||
type SerializeStructVariant = StructVariantSerializer<'a, 'j, C>;
|
||||
|
||||
#[inline]
|
||||
fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(JsBoolean::new(self.cx, v).upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(JsNumber::new(self.cx, as_num::<_, f64>(v)?).upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(JsNumber::new(self.cx, as_num::<_, f64>(v)?).upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(JsNumber::new(self.cx, as_num::<_, f64>(v)?).upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(JsNumber::new(self.cx, as_num::<_, f64>(v)?).upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(JsNumber::new(self.cx, as_num::<_, f64>(v)?).upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(JsNumber::new(self.cx, as_num::<_, f64>(v)?).upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(JsNumber::new(self.cx, as_num::<_, f64>(v)?).upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(JsNumber::new(self.cx, as_num::<_, f64>(v)?).upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(JsNumber::new(self.cx, as_num::<_, f64>(v)?).upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(JsNumber::new(self.cx, as_num::<_, f64>(v)?).upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(JsNumber::new(self.cx, as_num::<_, f64>(v)?).upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(JsNumber::new(self.cx, v).upcast())
|
||||
}
|
||||
|
||||
fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error> {
|
||||
let mut b = [0; 4];
|
||||
let result = v.encode_utf8(&mut b);
|
||||
let js_str =
|
||||
JsString::try_new(self.cx, result).map_err(|_| ErrorKind::StringTooLongForChar(4))?;
|
||||
Ok(js_str.upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
|
||||
let len = v.len();
|
||||
let js_str = JsString::try_new(self.cx, v).map_err(|_| ErrorKind::StringTooLong(len))?;
|
||||
Ok(js_str.upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
let mut buff = JsBuffer::new(self.cx, as_num::<_, u32>(v.len())?)?;
|
||||
self.cx
|
||||
.borrow_mut(&mut buff, |buff| buff.as_mut_slice().clone_from_slice(v));
|
||||
Ok(buff.upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(JsNull::new(self.cx).upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(JsNull::new(self.cx).upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(JsNull::new(self.cx).upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_unit_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
) -> Result<Self::Ok, Self::Error> {
|
||||
self.serialize_str(variant)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_newtype_struct<T: ?Sized>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_newtype_variant<T: ?Sized>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let obj = JsObject::new(&mut *self.cx);
|
||||
let value_js = to_value(self.cx, value)?;
|
||||
obj.set(self.cx, variant, value_js)?;
|
||||
|
||||
Ok(obj.upcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
Ok(ArraySerializer::new(self.cx))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
||||
Ok(ArraySerializer::new(self.cx))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_tuple_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||
Ok(ArraySerializer::new(self.cx))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_tuple_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||
TupleVariantSerializer::new(self.cx, variant)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||
Ok(MapSerializer::new(self.cx))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStruct, Self::Error> {
|
||||
Ok(StructSerializer::new(self.cx))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_struct_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
||||
StructVariantSerializer::new(self.cx, variant)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<'a, 'j, C> ArraySerializer<'a, 'j, C>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
#[inline]
|
||||
fn new(cx: &'a mut C) -> Self {
|
||||
let array = JsArray::new(cx, 0);
|
||||
ArraySerializer { cx, array }
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<'a, 'j, C> ser::SerializeSeq for ArraySerializer<'a, 'j, C>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
type Ok = Handle<'j, JsValue>;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let value = to_value(self.cx, value)?;
|
||||
|
||||
let arr: Handle<'j, JsArray> = self.array;
|
||||
let len = arr.len(self.cx);
|
||||
arr.set(self.cx, len, value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.array.upcast())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'j, C> ser::SerializeTuple for ArraySerializer<'a, 'j, C>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
type Ok = Handle<'j, JsValue>;
|
||||
type Error = Error;
|
||||
|
||||
#[inline]
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
ser::SerializeSeq::serialize_element(self, value)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
ser::SerializeSeq::end(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<'a, 'j, C> ser::SerializeTupleStruct for ArraySerializer<'a, 'j, C>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
type Ok = Handle<'j, JsValue>;
|
||||
type Error = Error;
|
||||
|
||||
#[inline]
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
ser::SerializeSeq::serialize_element(self, value)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
ser::SerializeSeq::end(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<'a, 'j, C> TupleVariantSerializer<'a, 'j, C>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
fn new(cx: &'a mut C, key: &'static str) -> LibResult<Self> {
|
||||
let inner_array = JsArray::new(cx, 0);
|
||||
let outer_object = JsObject::new(cx);
|
||||
outer_object.set(cx, key, inner_array)?;
|
||||
Ok(TupleVariantSerializer {
|
||||
outer_object,
|
||||
inner: ArraySerializer {
|
||||
cx,
|
||||
array: inner_array,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<'a, 'j, C> ser::SerializeTupleVariant for TupleVariantSerializer<'a, 'j, C>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
type Ok = Handle<'j, JsValue>;
|
||||
type Error = Error;
|
||||
|
||||
#[inline]
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
use serde::ser::SerializeSeq;
|
||||
self.inner.serialize_element(value)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.outer_object.upcast())
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<'a, 'j, C> MapSerializer<'a, 'j, C>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
fn new(cx: &'a mut C) -> Self {
|
||||
let object = JsObject::new(cx);
|
||||
let key_holder = JsObject::new(cx);
|
||||
MapSerializer {
|
||||
cx,
|
||||
object,
|
||||
key_holder,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<'a, 'j, C> ser::SerializeMap for MapSerializer<'a, 'j, C>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
type Ok = Handle<'j, JsValue>;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let key = to_value(self.cx, key)?;
|
||||
self.key_holder.set(self.cx, "key", key)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let key: Handle<'j, JsValue> = self.key_holder.get(&mut *self.cx, "key")?;
|
||||
let value_obj = to_value(self.cx, value)?;
|
||||
self.object.set(self.cx, key, value_obj)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.object.upcast())
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<'a, 'j, C> StructSerializer<'a, 'j, C>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
#[inline]
|
||||
fn new(cx: &'a mut C) -> Self {
|
||||
let object = JsObject::new(cx);
|
||||
StructSerializer { cx, object }
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<'a, 'j, C> ser::SerializeStruct for StructSerializer<'a, 'j, C>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
type Ok = Handle<'j, JsValue>;
|
||||
type Error = Error;
|
||||
|
||||
#[inline]
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
key: &'static str,
|
||||
value: &T,
|
||||
) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let value = to_value(self.cx, value)?;
|
||||
self.object.set(self.cx, key, value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.object.upcast())
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<'a, 'j, C> StructVariantSerializer<'a, 'j, C>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
fn new(cx: &'a mut C, key: &'static str) -> LibResult<Self> {
|
||||
let inner_object = JsObject::new(cx);
|
||||
let outer_object = JsObject::new(cx);
|
||||
outer_object.set(cx, key, inner_object)?;
|
||||
Ok(StructVariantSerializer {
|
||||
outer_object: outer_object,
|
||||
inner: StructSerializer {
|
||||
cx,
|
||||
object: inner_object,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<'a, 'j, C> ser::SerializeStructVariant for StructVariantSerializer<'a, 'j, C>
|
||||
where
|
||||
C: Context<'j>,
|
||||
{
|
||||
type Ok = Handle<'j, JsValue>;
|
||||
type Error = Error;
|
||||
|
||||
#[inline]
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
key: &'static str,
|
||||
value: &T,
|
||||
) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
use serde::ser::SerializeStruct;
|
||||
self.inner.serialize_field(key, value)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(self.outer_object.upcast())
|
||||
}
|
||||
}
|
||||
100
components/ordhook-sdk-js/tsconfig.json
Normal file
100
components/ordhook-sdk-js/tsconfig.json
Normal file
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es5", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
|
||||
// "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
|
||||
/* Modules */
|
||||
"module": "commonjs", /* Specify what module code is generated. */
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
// "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
|
||||
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "resolveJsonModule": true, /* Enable importing .json files */
|
||||
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
|
||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
|
||||
|
||||
/* Emit */
|
||||
"declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
"declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
"sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
|
||||
"outDir": "./dist", /* Specify an output folder for all emitted files. */
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
// "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
|
||||
/* Interop Constraints */
|
||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
// "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
|
||||
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
// "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
|
||||
// "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
|
||||
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
// "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
|
||||
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
|
||||
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true, /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user