Skip to content

Commit 01e0f75

Browse files
committed
feat: Enhance server configuration with HTTP gateway and tiered memory settings
- Added HTTP gateway module to the server for improved request handling. - Updated tiered memory configuration with new parameters: lower_watermark and promotion_cooldown_ms. - Adjusted physical memory limit in logs and tests to reflect new settings. - Enhanced schema serialization for MorpheusSchema to support new features.
1 parent 2859f4a commit 01e0f75

13 files changed

Lines changed: 826 additions & 199 deletions

File tree

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,8 @@ perf.data*
128128
*.onnx_data
129129

130130

131-
nohup.out
131+
# Heaptrack profiling dumps
132+
heaptrack.*.zst
133+
134+
135+
nohup.out

HTTP_API.md

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
# Morpheus HTTP API
2+
3+
Base URL: `http://127.0.0.1:8080` (default)
4+
5+
Environment:
6+
- `MORPHEUS_HTTP_ADDR`: bind address (default `127.0.0.1:8080`)
7+
- `MORPHEUS_HTTP_ADMIN_TOKEN`: when set, admin endpoints require `Authorization: Bearer <token>`
8+
- `MORPHEUS_HTTP_CORS=permissive`: enable permissive CORS
9+
10+
## Response and Errors
11+
12+
Success response:
13+
```json
14+
{ "data": { ... } }
15+
```
16+
17+
Error response:
18+
```json
19+
{ "code": "...", "message": "..." }
20+
```
21+
22+
## ID Format
23+
24+
Cell, vertex, edge IDs are base58-encoded 16-byte IDs. The server returns base58 strings for IDs.
25+
26+
## Data Encoding
27+
28+
Graph vertex data and edge body use JSON objects (maps). Cell data accepts a generic `HttpValue`.
29+
30+
### Map
31+
```json
32+
{ "k": "v" }
33+
```
34+
35+
### Array
36+
```json
37+
[1, 2, 3]
38+
```
39+
40+
### Typed Values
41+
Use `{"$type": "...", "value": ...}` for non-JSON or specific types.
42+
43+
Examples:
44+
```json
45+
{"$type":"u64","value":123}
46+
{"$type":"id","value":"5QqkMJFr5s7J9wB8Q2kN1J"}
47+
{"$type":"bytes","value":[1,2,3]}
48+
{"$type":"u32[]","value":[1,2,3]}
49+
```
50+
51+
Supported `$type` values:
52+
- `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`, `f32`, `f64`
53+
- `char`, `string`, `bool`, `na`
54+
- `id` (base58 string value)
55+
- `bytes`, `small_bytes` (array of byte numbers)
56+
- `map`, `array`
57+
- `bool[]`, `char[]`, `i8[]`, `i16[]`, `i32[]`, `i64[]`, `u8[]`, `u16[]`, `u32[]`, `u64[]`,
58+
`f32[]`, `f64[]`, `pos2d32[]`, `pos2d64[]`, `pos3d32[]`, `pos3d64[]`, `id[]`, `string[]`,
59+
`bytes[]`, `small_bytes[]`
60+
61+
Notes:
62+
- Untagged numbers are interpreted as `i64`, `u64`, or `f64` depending on JSON parsing.
63+
- `id` decoding also accepts `{ "higher": <u64>, "lower": <u64> }` for backward compatibility, but responses return base58 strings.
64+
65+
## Health
66+
67+
`GET /v1/health`
68+
69+
Response:
70+
```json
71+
{ "data": {} }
72+
```
73+
74+
## Graph Schemas (Morpheus)
75+
76+
`GET /v1/graph/schemas`
77+
78+
`GET /v1/graph/schemas/:name`
79+
80+
`POST /v1/graph/schemas` (admin)
81+
82+
Request:
83+
```json
84+
{
85+
"id": 0,
86+
"name": "my_vertex",
87+
"schema_type": "Vertex",
88+
"key_field": null,
89+
"fields": [],
90+
"is_dynamic": true
91+
}
92+
```
93+
94+
Edge schema example:
95+
```json
96+
{
97+
"name": "my_edge",
98+
"schema_type": {
99+
"Edge": {
100+
"edge_type": "Directed",
101+
"has_body": true
102+
}
103+
},
104+
"fields": [],
105+
"is_dynamic": true
106+
}
107+
```
108+
109+
`DELETE /v1/graph/schemas/:name` (admin)
110+
111+
## Cell Schemas (Neb)
112+
113+
`GET /v1/cell/schemas`
114+
115+
`GET /v1/cell/schemas/:name`
116+
117+
`POST /v1/cell/schemas` (admin)
118+
119+
Request:
120+
```json
121+
{
122+
"id": 0,
123+
"name": "my_cell",
124+
"key_field": null,
125+
"fields": [],
126+
"is_dynamic": true,
127+
"is_scannable": false
128+
}
129+
```
130+
131+
`DELETE /v1/cell/schemas/:name` (admin)
132+
133+
## Graph Operations
134+
135+
`POST /v1/graph/vertices` (admin)
136+
137+
Request by schema name:
138+
```json
139+
{
140+
"schema_name": "my_vertex",
141+
"data": {}
142+
}
143+
```
144+
145+
Request by schema id:
146+
```json
147+
{
148+
"schema_id": 42,
149+
"data": {},
150+
"id": "5QqkMJFr5s7J9wB8Q2kN1J"
151+
}
152+
```
153+
154+
`GET /v1/graph/vertices/:id`
155+
156+
`DELETE /v1/graph/vertices/:id` (admin)
157+
158+
`POST /v1/graph/edges` (admin)
159+
160+
Request:
161+
```json
162+
{
163+
"from_id": "5QqkMJFr5s7J9wB8Q2kN1J",
164+
"to_id": "3Yv8v4Cw1W5Hk9p2LxQw9Q",
165+
"schema_name": "my_edge",
166+
"body": {}
167+
}
168+
```
169+
170+
`GET /v1/graph/vertices/:id/edges?schema=<name-or-id>&direction=outbound|inbound|undirected`
171+
172+
## Cell CRUD
173+
174+
All cell CRUD endpoints require admin token when `MORPHEUS_HTTP_ADMIN_TOKEN` is set.
175+
176+
`GET /v1/cells/:id`
177+
178+
`POST /v1/cells/:id`
179+
180+
`PUT /v1/cells/:id`
181+
182+
`DELETE /v1/cells/:id`
183+
184+
Request (POST/PUT):
185+
```json
186+
{
187+
"schema_id": 123,
188+
"data": {}
189+
}
190+
```
191+
192+
## Legacy Schema Endpoints
193+
194+
These map to graph schema reads:
195+
- `GET /v1/schemas`
196+
- `GET /v1/schemas/:name`
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
name = "morpheus-http-client"
3+
version = "0.1.0"
4+
edition = "2024"
5+
rust-version = "1.85"
6+
7+
[lints.rust]
8+
unsafe_code = "warn"
9+
10+
[lints.clippy]
11+
all = "warn"
12+
pedantic = "warn"
13+
14+
[dependencies]
15+
reqwest = { version = "0.12", features = ["json"] }
16+
serde = { version = "1", features = ["derive"] }
17+
serde_json = "1"
18+
url = "2"
19+
bs58 = "0.5"
20+
21+
[dev-dependencies]
22+
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use std::fmt;
2+
3+
use reqwest::header::InvalidHeaderValue;
4+
use url::ParseError;
5+
6+
use crate::types::ApiErrorBody;
7+
8+
#[derive(Debug, Clone)]
9+
pub struct ApiError {
10+
pub status: u16,
11+
pub body: ApiErrorBody,
12+
}
13+
14+
impl fmt::Display for ApiError {
15+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16+
write!(
17+
f,
18+
"api error {}: {}: {}",
19+
self.status, self.body.code, self.body.message
20+
)
21+
}
22+
}
23+
24+
impl std::error::Error for ApiError {}
25+
26+
#[derive(Debug)]
27+
pub enum ClientError {
28+
InvalidUrl(ParseError),
29+
InvalidHeaderValue(InvalidHeaderValue),
30+
Http(reqwest::Error),
31+
Api(ApiError),
32+
InvalidArgument(String),
33+
}
34+
35+
impl ClientError {
36+
pub fn invalid_url(e: ParseError) -> Self {
37+
Self::InvalidUrl(e)
38+
}
39+
40+
pub fn invalid_header_value(e: InvalidHeaderValue) -> Self {
41+
Self::InvalidHeaderValue(e)
42+
}
43+
44+
pub fn http(e: reqwest::Error) -> Self {
45+
Self::Http(e)
46+
}
47+
48+
pub fn api(err: ApiError) -> Self {
49+
Self::Api(err)
50+
}
51+
52+
pub fn invalid_argument(msg: impl Into<String>) -> Self {
53+
Self::InvalidArgument(msg.into())
54+
}
55+
}
56+
57+
impl fmt::Display for ClientError {
58+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59+
match self {
60+
ClientError::InvalidUrl(e) => write!(f, "invalid base url: {e}"),
61+
ClientError::InvalidHeaderValue(e) => write!(f, "invalid header value: {e}"),
62+
ClientError::Http(e) => write!(f, "http error: {e}"),
63+
ClientError::Api(e) => write!(f, "{e}"),
64+
ClientError::InvalidArgument(msg) => write!(f, "invalid argument: {msg}"),
65+
}
66+
}
67+
}
68+
69+
impl std::error::Error for ClientError {
70+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
71+
match self {
72+
ClientError::InvalidUrl(e) => Some(e),
73+
ClientError::InvalidHeaderValue(e) => Some(e),
74+
ClientError::Http(e) => Some(e),
75+
ClientError::Api(e) => Some(e),
76+
ClientError::InvalidArgument(_) => None,
77+
}
78+
}
79+
}

0 commit comments

Comments
 (0)