Compare commits
No commits in common. "ddadfe1253069391dfe15e42cf87b7fdb0dc4a33" and "0713f323bbe338cb22e1a393d7cd229bc8f436ab" have entirely different histories.
ddadfe1253
...
0713f323bb
7 changed files with 48 additions and 108 deletions
48
.github/workflows/test.yml
vendored
48
.github/workflows/test.yml
vendored
|
@ -1,48 +0,0 @@
|
||||||
name: test
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
pull_request:
|
|
||||||
types: [synchronize, review_requested]
|
|
||||||
|
|
||||||
env:
|
|
||||||
CARGO_TERM_COLOR: always
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
toolchain:
|
|
||||||
- stable
|
|
||||||
- beta
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: dtolnay/rust-toolchain@master
|
|
||||||
with:
|
|
||||||
toolchain: ${{ matrix.toolchain }}
|
|
||||||
- run: cargo test --verbose
|
|
||||||
|
|
||||||
build:
|
|
||||||
runs-on: ${{ matrix.runner }}
|
|
||||||
needs: [test]
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
runner:
|
|
||||||
- ubuntu-latest
|
|
||||||
- windows-latest
|
|
||||||
- macos-latest
|
|
||||||
toolchain:
|
|
||||||
- stable
|
|
||||||
- beta
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: dtolnay/rust-toolchain@master
|
|
||||||
with:
|
|
||||||
toolchain: ${{ matrix.toolchain }}
|
|
||||||
- run: cargo build --release --verbose
|
|
72
README.md
72
README.md
|
@ -96,27 +96,41 @@ $ postwoman
|
||||||
Run all endpoints matching `.` (aka all of them)
|
Run all endpoints matching `.` (aka all of them)
|
||||||
```
|
```
|
||||||
$ postwoman run .
|
$ postwoman run .
|
||||||
: [22:27:17.960461] sending healthcheck ...
|
: [22:20:53.112717] sending healthcheck ...
|
||||||
+ [22:27:18.109843] healthcheck done in 149ms
|
+ [22:20:53.250755] healthcheck done in 138ms
|
||||||
{
|
Response {
|
||||||
|
url: "https://api.alemi.dev/",
|
||||||
|
status: 200,
|
||||||
|
headers: {
|
||||||
|
"server": "nginx/1.26.2",
|
||||||
|
"date": "Sat, 19 Oct 2024 20:20:53 GMT",
|
||||||
|
"content-type": "application/json",
|
||||||
|
"content-length": "161",
|
||||||
|
"connection": "keep-alive",
|
||||||
|
"vary": "Accept-Encoding",
|
||||||
|
"access-control-allow-origin": "*",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
Body: {
|
||||||
"example": [
|
"example": [
|
||||||
"https://api.alemi.dev/debug",
|
"https://api.alemi.dev/debug",
|
||||||
"https://api.alemi.dev/msg",
|
"https://api.alemi.dev/msg",
|
||||||
"https://api.alemi.dev/mumble/ping"
|
"https://api.alemi.dev/mumble/ping"
|
||||||
],
|
],
|
||||||
"time": "Saturday, 19-Oct-2024 20:27:18 GMT",
|
"time": "Saturday, 19-Oct-2024 20:20:53 GMT",
|
||||||
"up": true
|
"up": true
|
||||||
}
|
}
|
||||||
: [22:27:18.109924] sending debug ...
|
|
||||||
+ [22:27:18.268383] debug done in 158ms
|
: [22:20:53.250802] sending debug ...
|
||||||
|
+ [22:20:53.369298] debug done in 118ms
|
||||||
/debug?body=json&cache=0
|
/debug?body=json&cache=0
|
||||||
: [22:27:18.268477] sending benchmark ...
|
: [22:20:53.369352] sending benchmark ...
|
||||||
+ [22:27:18.422707] benchmark done in 154ms
|
+ [22:20:53.482720] benchmark done in 113ms
|
||||||
: [22:27:18.422775] sending notfound ...
|
: [22:20:53.482745] sending notfound ...
|
||||||
+ [22:27:18.575942] notfound done in 153ms
|
+ [22:20:53.593134] notfound done in 110ms
|
||||||
nginx/1.26.2
|
nginx/1.26.2
|
||||||
: [22:27:18.576010] sending payload ...
|
: [22:20:53.593163] sending payload ...
|
||||||
+ [22:27:18.732582] payload done in 156ms
|
+ [22:20:53.709245] payload done in 116ms
|
||||||
{
|
{
|
||||||
"body": "{\n\t\"complex\": {\n\t\t\"json\": \"payloads\",\n\t\t\"can\": \"be\",\n\t\t\"expressed\": \"this\",\n\t\t\"way\": true\n\t}\n}",
|
"body": "{\n\t\"complex\": {\n\t\t\"json\": \"payloads\",\n\t\t\"can\": \"be\",\n\t\t\"expressed\": \"this\",\n\t\t\"way\": true\n\t}\n}",
|
||||||
"headers": {
|
"headers": {
|
||||||
|
@ -128,41 +142,15 @@ nginx/1.26.2
|
||||||
"user-agent": "postwoman@sample/0.2.0",
|
"user-agent": "postwoman@sample/0.2.0",
|
||||||
"x-forwarded-proto": "https",
|
"x-forwarded-proto": "https",
|
||||||
"x-real-ip": "93.34.149.115",
|
"x-real-ip": "93.34.149.115",
|
||||||
"x-real-port": 46695,
|
"x-real-port": 46437,
|
||||||
"x-user-agent": "postwoman@sample/0.2.0"
|
"x-user-agent": "postwoman@sample/0.2.0"
|
||||||
},
|
},
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"path": "/debug",
|
"path": "/debug",
|
||||||
"time": 1729369638.7079802,
|
"time": 1729369253.6897264,
|
||||||
"version": "HTTP/1.0"
|
"version": "HTTP/1.0"
|
||||||
}
|
}
|
||||||
: [22:27:18.732676] sending cookie ...
|
: [22:20:53.709276] sending cookie ...
|
||||||
+ [22:27:18.886862] cookie done in 154ms
|
+ [22:20:53.822684] cookie done in 113ms
|
||||||
SGF2ZSBhIENvb2tpZSE=
|
SGF2ZSBhIENvb2tpZSE=
|
||||||
```
|
```
|
||||||
|
|
||||||
Debug a specific route passing `--debug`:
|
|
||||||
```
|
|
||||||
$ postwoman run notfound --debug
|
|
||||||
: [22:26:59.045642] sending notfound ...
|
|
||||||
+ [22:26:59.220103] notfound done in 174ms
|
|
||||||
Response {
|
|
||||||
url: "https://api.alemi.dev/not-found",
|
|
||||||
status: 404,
|
|
||||||
headers: {
|
|
||||||
"server": "nginx/1.26.2",
|
|
||||||
"date": "Sat, 19 Oct 2024 20:26:59 GMT",
|
|
||||||
"content-type": "text/html",
|
|
||||||
"content-length": "153",
|
|
||||||
"connection": "keep-alive",
|
|
||||||
"vary": "Accept-Encoding",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
Body: <html>
|
|
||||||
<head><title>404 Not Found</title></head>
|
|
||||||
<body>
|
|
||||||
<center><h1>404 Not Found</h1></center>
|
|
||||||
<hr><center>nginx/1.26.2</center>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
12
src/ext.rs
12
src/ext.rs
|
@ -1,15 +1,3 @@
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
pub enum StringOr<T> {
|
|
||||||
Str(String),
|
|
||||||
T(T),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Default> Default for StringOr<T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::T(T::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn stringify_toml(v: &toml::Value) -> String {
|
pub fn stringify_toml(v: &toml::Value) -> String {
|
||||||
match v {
|
match v {
|
||||||
|
|
|
@ -100,7 +100,7 @@ async fn main() -> Result<(), PostWomanError> {
|
||||||
let env = Arc::new(config.env);
|
let env = Arc::new(config.env);
|
||||||
for (name, mut endpoint) in config.route {
|
for (name, mut endpoint) in config.route {
|
||||||
if pattern.find(&name).is_some() {
|
if pattern.find(&name).is_some() {
|
||||||
if debug { endpoint.extract = Some(ext::StringOr::T(model::Extractor::Debug)) };
|
if debug { endpoint.extract = None };
|
||||||
for i in 0..repeat {
|
for i in 0..repeat {
|
||||||
let suffix = if repeat > 1 {
|
let suffix = if repeat > 1 {
|
||||||
format!("#{} ", i+1)
|
format!("#{} ", i+1)
|
||||||
|
|
|
@ -6,8 +6,7 @@ use jaq_interpret::FilterT;
|
||||||
|
|
||||||
use crate::{PostWomanError, APP_USER_AGENT};
|
use crate::{PostWomanError, APP_USER_AGENT};
|
||||||
|
|
||||||
use crate::ext::{stringify_toml, stringify_json, StringOr};
|
use super::{Extractor, PostWomanClient, StringOr};
|
||||||
use super::{Extractor, PostWomanClient};
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
|
@ -60,7 +59,7 @@ impl Endpoint {
|
||||||
vars.insert("POSTWOMAN_TIMESTAMP".to_string(), chrono::Local::now().timestamp().to_string());
|
vars.insert("POSTWOMAN_TIMESTAMP".to_string(), chrono::Local::now().timestamp().to_string());
|
||||||
|
|
||||||
for (k, v) in env {
|
for (k, v) in env {
|
||||||
vars.insert(k.to_string(), stringify_toml(v));
|
vars.insert(k.to_string(), crate::ext::stringify_toml(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (k, v) in std::env::vars() {
|
for (k, v) in std::env::vars() {
|
||||||
|
@ -174,7 +173,7 @@ impl Endpoint {
|
||||||
let json: serde_json::Value = res.json().await?;
|
let json: serde_json::Value = res.json().await?;
|
||||||
let selection = jq(&query, json)?;
|
let selection = jq(&query, json)?;
|
||||||
if selection.len() == 1 {
|
if selection.len() == 1 {
|
||||||
stringify_json(&selection[0]) + "\n"
|
crate::ext::stringify_json(&selection[0]) + "\n"
|
||||||
} else {
|
} else {
|
||||||
serde_json::to_string_pretty(&selection)? + "\n"
|
serde_json::to_string_pretty(&selection)? + "\n"
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
#[serde(tag = "type", rename_all = "lowercase")]
|
#[serde(tag = "type", rename_all = "lowercase")]
|
||||||
pub enum Extractor {
|
pub enum Extractor {
|
||||||
#[default]
|
#[default]
|
||||||
Body,
|
|
||||||
Debug,
|
Debug,
|
||||||
|
Body,
|
||||||
Discard,
|
Discard,
|
||||||
JQ { query: String },
|
JQ { query: String },
|
||||||
Regex { pattern: String },
|
Regex { pattern: String },
|
||||||
|
|
|
@ -13,3 +13,16 @@ pub struct PostWomanConfig {
|
||||||
// it's weird to name it singular but makes more sense in config
|
// it's weird to name it singular but makes more sense in config
|
||||||
pub route: indexmap::IndexMap<String, Endpoint>,
|
pub route: indexmap::IndexMap<String, Endpoint>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum StringOr<T> {
|
||||||
|
Str(String),
|
||||||
|
T(T),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Default> Default for StringOr<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::T(T::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue