├── .gitignore
├── renovate.json
├── .rustfmt.toml
├── Cargo.toml
├── src
├── utils.rs
├── response.rs
├── form.rs
├── lemmy_client_internal.rs
├── lemmy_client_trait.rs
└── lib.rs
├── README.md
├── .woodpecker.yml
├── cliff.toml
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | Cargo.lock
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": ["config:recommended"],
4 | "schedule": ["every weekend"],
5 | "automerge": true
6 | }
7 |
--------------------------------------------------------------------------------
/.rustfmt.toml:
--------------------------------------------------------------------------------
1 | tab_spaces = 2
2 | edition = "2021"
3 | imports_layout = "HorizontalVertical"
4 | imports_granularity = "Crate"
5 | group_imports = "One"
6 | wrap_comments = true
7 | comment_width = 100
8 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "lemmy-client"
3 | version = "1.0.5"
4 | edition = "2021"
5 | license = "AGPL-3.0"
6 | authors = ["SleeplessOne1917"]
7 | description = "A Rust HTTP client for Lemmy."
8 | homepage = "https://join-lemmy.org"
9 | repository = "https://github.com/LemmyNet/lemmy-client-rs"
10 | keywords = ["Lemmy", "HTTP-client", "API-wrapper", "fediverse"]
11 | categories = ["api-bindings", "wasm"]
12 |
13 | [dependencies]
14 | cfg-if = "1"
15 | http = "1.1"
16 | lemmy_api_common = "=0.19.14"
17 | serde = "1.0"
18 | serde_json = "1.0"
19 |
20 | [features]
21 | default = ["default-tls"]
22 | default-tls = ["reqwest/default-tls"]
23 | native-tls = ["reqwest/native-tls"]
24 | rustls-tls = ["reqwest/rustls-tls"]
25 |
26 | [target.'cfg(target_family = "wasm")'.dependencies]
27 | gloo-net = { version = "0.6", features = ["http"] }
28 | serde_urlencoded = "0.7"
29 | web-sys = "0.3"
30 |
31 | [target.'cfg(not(target_family = "wasm"))'.dependencies]
32 | reqwest = { version = "0.12", features = ["json"], default-features = false }
33 |
--------------------------------------------------------------------------------
/src/utils.rs:
--------------------------------------------------------------------------------
1 | macro_rules! impl_marker_trait {
2 | ($trait_name:ty, [$( $impler:ty ),+$(,)?]) => {
3 | $(
4 | impl $trait_name for $impler {}
5 | )*
6 | };
7 | }
8 |
9 | pub(crate) use impl_marker_trait;
10 |
11 | #[derive(Debug, Clone, PartialEq, Eq)]
12 | /// Options for instantiating a `LemmyClient`.
13 | pub struct ClientOptions {
14 | /// Domain of the instance the client will send requests to.
15 | /// ```
16 | /// use lemmy_client::ClientOptions;
17 | /// // ❌ You do not have to include the scheme for the domain.
18 | /// let options = ClientOptions {
19 | /// domain: String::from("https://lemmy.ml"),
20 | /// secure: true
21 | /// };
22 | ///
23 | /// // ✅ All you need is the domain (including subdomain, if applicable).
24 | /// let options = ClientOptions {
25 | /// domain: String::from("lemmy.ml"),
26 | /// secure: true
27 | /// };
28 | /// ```
29 | pub domain: String,
30 | /// If true, use HTTPS. If false, use HTTP
31 | pub secure: bool,
32 | }
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |

3 |

4 |

5 |

6 |

7 |

8 |
9 |
10 |
11 |
12 |
13 |
lemmy-client
14 |
A Rust HTTP client for Lemmy. Uses the browser's built-in fetch API when targeting WASM to keep the binary size small.
15 |
16 |
17 | ## IMPORTANT NOTICE
18 |
19 | This crate now uses a different versioning scheme than before so as not to be too tied down to Lemmy releases. For Lemmy versions 0.19.4 and up, use versions 1.x.x. For Lemmy versions 0.19.3 and under, use versions 0.19.5 and up. This is confusing, but should become a non issue as Lemmy accumulates versions and fewer servers use Lemmy versions use 0.19.3 and lower.
20 |
--------------------------------------------------------------------------------
/src/response.rs:
--------------------------------------------------------------------------------
1 | use crate::utils::impl_marker_trait;
2 | use lemmy_api_common::{
3 | comment::*, community::*, custom_emoji::*, lemmy_db_schema::source::login_token::LoginToken,
4 | person::*, post::*, private_message::*, site::*, LemmyErrorType, SuccessResponse,
5 | };
6 | use serde::Deserialize;
7 |
8 | pub trait LemmyResponse: for<'de> Deserialize<'de> {}
9 |
10 | pub type LemmyResult = Result;
11 |
12 | impl_marker_trait!(
13 | LemmyResponse,
14 | [
15 | String,
16 | SuccessResponse,
17 | // Comments
18 | CommentReportResponse,
19 | CommentResponse,
20 | CreateCommentReport,
21 | GetCommentsResponse,
22 | ListCommentLikesResponse,
23 | ListCommentReportsResponse,
24 | // Communities
25 | AddModToCommunityResponse,
26 | BanFromCommunityResponse,
27 | BlockCommunityResponse,
28 | CommunityResponse,
29 | GetCommunityResponse,
30 | ListCommunitiesResponse,
31 | // Custom Emojis
32 | CustomEmojiResponse,
33 | // Person
34 | AddAdminResponse,
35 | BanPersonResponse,
36 | BannedPersonsResponse,
37 | BlockPersonResponse,
38 | CaptchaResponse,
39 | CommentReplyResponse,
40 | GenerateTotpSecretResponse,
41 | GetCaptchaResponse,
42 | GetPersonDetailsResponse,
43 | GetPersonMentionsResponse,
44 | GetRepliesResponse,
45 | GetReportCountResponse,
46 | GetUnreadCountResponse,
47 | LoginResponse,
48 | PersonMentionResponse,
49 | UpdateTotpResponse,
50 | Vec,
51 | // Posts
52 | GetPostResponse,
53 | GetPostsResponse,
54 | GetSiteMetadataResponse,
55 | ListPostLikesResponse,
56 | ListPostReportsResponse,
57 | PostReportResponse,
58 | PostResponse,
59 | // Private Messages
60 | ListPrivateMessageReportsResponse,
61 | PrivateMessageReportResponse,
62 | PrivateMessageResponse,
63 | PrivateMessagesResponse,
64 | // Site
65 | BlockInstanceResponse,
66 | GetFederatedInstancesResponse,
67 | GetModlogResponse,
68 | GetSiteResponse,
69 | GetUnreadRegistrationApplicationCountResponse,
70 | ListRegistrationApplicationsResponse,
71 | RegistrationApplicationResponse,
72 | ResolveObjectResponse,
73 | SearchResponse,
74 | SiteResponse,
75 | // Media
76 | ListMediaResponse
77 | ]
78 | );
79 |
--------------------------------------------------------------------------------
/.woodpecker.yml:
--------------------------------------------------------------------------------
1 | variables:
2 | - &rust_image "rust:1.92-slim-bookworm"
3 |
4 | steps:
5 | toml_fmt:
6 | image: tamasfe/taplo:0.9.3
7 | commands:
8 | - taplo format --check
9 | when:
10 | - event: pull_request
11 |
12 | cargo_fmt:
13 | image: rustlang/rust:nightly-alpine
14 | commands:
15 | - rustup component add rustfmt
16 | - cargo +nightly fmt -- --check
17 | when:
18 | - event: pull_request
19 |
20 | cargo_machete:
21 | image: *rust_image
22 | commands:
23 | - apt update && apt -y install wget
24 | - wget -O- https://github.com/cargo-bins/cargo-binstall/releases/latest/download/cargo-binstall-x86_64-unknown-linux-musl.tgz | tar -xvz -C /usr/local/cargo/bin
25 | - cargo binstall -y cargo-machete
26 | - cargo machete
27 | when:
28 | - event: pull_request
29 |
30 | cargo_clippy:
31 | image: *rust_image
32 | commands:
33 | - apt update && apt install pkg-config libssl-dev -y
34 | - rustup component add clippy
35 | - cargo clippy --tests --all-targets -- -D warnings
36 | when:
37 | - event: pull_request
38 |
39 | cargo_build:
40 | image: *rust_image
41 | commands:
42 | - apt update && apt install pkg-config libssl-dev -y
43 | - cargo build
44 | when:
45 | - event: pull_request
46 |
47 | cargo_test:
48 | image: *rust_image
49 | environment:
50 | RUST_BACKTRACE: "1"
51 | commands:
52 | - apt update && apt install pkg-config libssl-dev -y
53 | - cargo test --no-fail-fast
54 | when:
55 | - event: pull_request
56 |
57 | publish_to_crates_io:
58 | image: *rust_image
59 | environment:
60 | CARGO_API_TOKEN:
61 | from_secret: cargo_api_token
62 | commands:
63 | - cargo publish --allow-dirty --no-verify --token "$CARGO_API_TOKEN"
64 | when:
65 | - event: tag
66 |
67 | notify_success:
68 | image: alpine:3
69 | commands:
70 | - apk add curl
71 | - "curl -H'Title: ✔️ ${CI_REPO_NAME}/${CI_COMMIT_SOURCE_BRANCH}' -d'${CI_PIPELINE_URL}' ntfy.sh/lemmy_drone_ci"
72 | when:
73 | - event: pull_request
74 | status: [success]
75 |
76 | notify_failure:
77 | image: alpine:3
78 | commands:
79 | - apk add curl
80 | - "curl -H'Title: ❌ ${CI_REPO_NAME}/${CI_COMMIT_SOURCE_BRANCH}' -d'${CI_PIPELINE_URL}' ntfy.sh/lemmy_drone_ci"
81 | when:
82 | - event: pull_request
83 | status: [failure]
84 |
85 | notify_on_tag_deploy:
86 | image: alpine:3
87 | commands:
88 | - apk add curl
89 | - "curl -H'Title: ${CI_REPO_NAME}:${CI_COMMIT_TAG} deployed' -d'${CI_PIPELINE_URL}' ntfy.sh/lemmy_drone_ci"
90 | when:
91 | event: tag
92 |
--------------------------------------------------------------------------------
/cliff.toml:
--------------------------------------------------------------------------------
1 | # git-cliff ~ configuration file
2 | # https://git-cliff.org/docs/configuration
3 |
4 | [remote.github]
5 | owner = "LemmyNet"
6 | repo = "lemmy-client-rs"
7 | # token = ""
8 |
9 | [changelog]
10 | # A Tera template to be rendered for each release in the changelog.
11 | # See https://keats.github.io/tera/docs/#introduction
12 | body = """
13 | ## What's Changed
14 |
15 | {%- if version %} in {{ version }}{%- endif -%}
16 | {% for commit in commits %}
17 | {% if commit.remote.pr_title -%}
18 | {%- set commit_message = commit.remote.pr_title -%}
19 | {%- else -%}
20 | {%- set commit_message = commit.message -%}
21 | {%- endif -%}
22 | * {{ commit_message | split(pat="\n") | first | trim }}\
23 | {% if commit.remote.username %} by @{{ commit.remote.username }}{%- endif -%}
24 | {% if commit.remote.pr_number %} in \
25 | [#{{ commit.remote.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.remote.pr_number }}) \
26 | {%- endif %}
27 | {%- endfor -%}
28 |
29 | {%- if github -%}
30 | {% if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %}
31 | {% raw %}\n{% endraw -%}
32 | ## New Contributors
33 | {%- endif %}\
34 | {% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %}
35 | * @{{ contributor.username }} made their first contribution
36 | {%- if contributor.pr_number %} in \
37 | [#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \
38 | {%- endif %}
39 | {%- endfor -%}
40 | {%- endif -%}
41 |
42 | {% if version %}
43 | {% if previous.version %}
44 | **Full Changelog**: {{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }}
45 | {% endif %}
46 | {% else -%}
47 | {% raw %}\n{% endraw %}
48 | {% endif %}
49 |
50 | {%- macro remote_url() -%}
51 | https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
52 | {%- endmacro -%}
53 | """
54 | # Remove leading and trailing whitespaces from the changelog's body.
55 | trim = true
56 | # A Tera template to be rendered as the changelog's footer.
57 | # See https://keats.github.io/tera/docs/#introduction
58 | footer = """
59 |
60 | """
61 | # An array of regex based postprocessors to modify the changelog.
62 | # Replace the placeholder `` with a URL.
63 | postprocessors = []
64 |
65 | [git]
66 | # Parse commits according to the conventional commits specification.
67 | # See https://www.conventionalcommits.org
68 | conventional_commits = false
69 | # Exclude commits that do not match the conventional commits specification.
70 | filter_unconventional = true
71 | # Split commits on newlines, treating each line as an individual commit.
72 | split_commits = false
73 | # An array of regex based parsers to modify commit messages prior to further processing.
74 | commit_preprocessors = [{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "" }]
75 | # Exclude commits that are not matched by any commit parser.
76 | commit_parsers = [{ field = "author.name", pattern = "renovate", skip = true }]
77 | filter_commits = false
78 | # Order releases topologically instead of chronologically.
79 | topo_order = false
80 | # Order of commits in each group/release within the changelog.
81 | # Allowed values: newest, oldest
82 | sort_commits = "newest"
83 |
--------------------------------------------------------------------------------
/src/form.rs:
--------------------------------------------------------------------------------
1 | use lemmy_api_common::{
2 | comment::*, community::*, custom_emoji::*, person::*, post::*, private_message::*, site::*,
3 | };
4 | use serde::Serialize;
5 | use std::fmt;
6 |
7 | use crate::utils::impl_marker_trait;
8 |
9 | pub trait LemmyForm: Serialize + Clone + fmt::Debug {}
10 |
11 | #[derive(Debug, Clone)]
12 | /// A request to send to lemmy. If you don't want to set the JWT for each request, you can set the Authorization header with [`LemmyClient::headers_mut`](lemmy_client::LemmyClient.headers_mut).
13 | pub struct LemmyRequest
14 | where
15 | Body: LemmyForm,
16 | {
17 | /// The body to send with the request. Uses [`unit`] for when a body is not required.
18 | pub body: Body,
19 | /// The JWT that is used when authorization is required.
20 | pub jwt: Option,
21 | }
22 |
23 | impl LemmyRequest<()> {
24 | /// Returns a request with no body or JWT.
25 | pub fn empty() -> Self {
26 | Self {
27 | body: (),
28 | jwt: None,
29 | }
30 | }
31 |
32 | /// Returns a request with no body and JWT if [`Some`].
33 | pub fn from_jwt(jwt: Option) -> Self {
34 | Self { body: (), jwt }
35 | }
36 | }
37 |
38 | impl