@arrirpc/codegen-rust 0.54.0 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -37,31 +37,101 @@ cargo add arri_client
37
37
 
38
38
  ## Using the generated code
39
39
 
40
- ### Initialize the client
40
+ All of the generated procedures in this client will be async functions, so you will need an async runtime like [tokio](https://tokio.rs/)
41
+
42
+ ### Initializing the client
41
43
 
42
44
  ```rust
43
45
  let config = ArriClientConfig {
44
46
  http_client: reqwest::Client::new(),
45
47
  base_url: "https://example.com".to_string(),
46
- // this function will run before every request
47
- headers: || {
48
- let mut header_map = Hashmap::<&'static str, &'static str>::new();
49
- header_map.insert("some-header", "some-header-value");
50
- header_map
51
- }
48
+ headers: Hashmap::new(),
52
49
  }
53
- let client = MyClient::create(&config);
50
+ let client = MyClient::create(config);
54
51
 
52
+ // start calling procedures
55
53
  client.my_procedure().await;
56
54
  ```
57
55
 
58
56
  The root client will be a struct containing all of the services and procedures. If you only need a particular service you can initialize just that service.
59
57
 
60
58
  ```rust
61
- let users_service = MyClientUsersService(&config);
59
+ let users_service = MyClientUsersService(config);
62
60
  users_service.some_procedure().await;
63
61
  ```
64
62
 
63
+ ### Updating Headers
64
+
65
+ For instances that you need to update the http headers (like in the case of an expired auth token), you can call the `update_headers()` function. When called, changes will propagate to all nested subservices.
66
+
67
+ ```rust
68
+ client.update_headers(new_headers);
69
+ ```
70
+
71
+ Be aware that if `update_headers()` is called from a subservice it will not propagate up to the parent service(s).
72
+
73
+ ```rust
74
+ client.subservice.update_headers(new_headers);
75
+
76
+ // this will still use the original headers
77
+ client.do_something();
78
+ ```
79
+
80
+ `update_headers()` be also be called across threads.
81
+
82
+ ```rust
83
+ let mut headers: HashMap<&'static str, String> = HashMap::new();
84
+ let config = ArriClientConfig {
85
+ http_client: reqwest::Client::new(),
86
+ base_url: "https://example.com".to_string(),
87
+ headers: headers.clone(),
88
+ }
89
+ let client = Arc::new(MyClient::create(config));
90
+ tokio::spawn(async move {
91
+ loop {
92
+ client.do_something().await;
93
+ }
94
+ });
95
+ tokio::spawn(async move {
96
+ loop {
97
+ client.do_another_thing().await;
98
+ }
99
+ });
100
+
101
+ // wait two seconds then change the headers
102
+ tokio::time::sleep(Duration::from_millis(2000)).await;
103
+ headers.insert("hello", "world".to_string());
104
+ client.update_headers(headers.clone());
105
+ // now both threads will start using the updated headers on their next loop
106
+ ```
107
+
108
+ ### Calling SSE Procedures
109
+
110
+ ```rust
111
+ let mut msg_count = 0;
112
+ let mut open_count = 0;
113
+ client
114
+ .users
115
+ .watch_user(
116
+ &mut |event, controller| match event {
117
+ SseEvent::Message(msg) => {
118
+ msg_count += 1;
119
+ printl("NEW_MESSAGE: {:?}", msg);
120
+ }
121
+ SSeEvent::Error(err) => {
122
+ // call abort to close the event stream
123
+ controller.abort()
124
+ }
125
+ SseEvent::Open => {
126
+ open_count += 1;
127
+ }
128
+ SseEvent::Close => {}
129
+ },
130
+ None, // max_retry_count (u64)
131
+ None, // max_retry_interval (u64)
132
+ ).await;
133
+ ```
134
+
65
135
  ### Using the generated types
66
136
 
67
137
  All the generated types will have the following methods implemented
package/dist/index.cjs CHANGED
@@ -1544,15 +1544,7 @@ function rustRpcFromSchema(schema, context) {
1544
1544
  }
1545
1545
  }
1546
1546
  function rustHttpRpcFromSchema(schema, context) {
1547
- if (schema.isEventStream) {
1548
- console.warn(
1549
- `[rust-codegen] SSE is not supported at this time. Skipping ${context.instancePath}.`
1550
- );
1551
- return "";
1552
- }
1553
1547
  const functionName = getFunctionName(context.instancePath);
1554
- const params = schema.params ? validRustName(schema.params) : void 0;
1555
- const response = schema.response ? validRustName(schema.response) : void 0;
1556
1548
  let leading = "";
1557
1549
  if (schema.description) {
1558
1550
  leading += formatDescriptionComment(schema.description);
@@ -1561,16 +1553,44 @@ function rustHttpRpcFromSchema(schema, context) {
1561
1553
  if (schema.isDeprecated) {
1562
1554
  leading += "#[deprecated]\n";
1563
1555
  }
1564
- return `${leading}pub async fn ${functionName} (
1565
- self: &Self,
1556
+ const params = schema.params ? validRustName(schema.params) : void 0;
1557
+ const response = schema.response ? validRustName(schema.response) : void 0;
1558
+ if (schema.isEventStream) {
1559
+ return `${leading}pub async fn ${functionName}<OnEvent>(
1560
+ &self,
1561
+ ${params ? `params: ${context.typeNamePrefix}${params},` : ""}
1562
+ on_event: &mut OnEvent,
1563
+ max_retry_count: Option<u64>,
1564
+ max_retry_interval: Option<u64>,
1565
+ ) where
1566
+ OnEvent: FnMut(SseEvent<${response ? `${context.typeNamePrefix}${response}` : "EmptyArriModel"}>, &mut SseController) + std::marker::Send + std::marker::Sync,
1567
+ {
1568
+ parsed_arri_sse_request(
1569
+ ArriParsedSseRequestOptions {
1570
+ client: &self._config.http_client,
1571
+ url: format!("{}${schema.path}", &self._config.base_url),
1572
+ method: reqwest::Method::${schema.method.toUpperCase()},
1573
+ headers: self._config.headers.clone(),
1574
+ client_version: "${context.clientVersion}".to_string(),
1575
+ max_retry_count,
1576
+ max_retry_interval,
1577
+ },
1578
+ ${params ? `Some(params)` : "None::<EmptyArriModel>"},
1579
+ on_event,
1580
+ )
1581
+ .await;
1582
+ }`;
1583
+ }
1584
+ return `${leading}pub async fn ${functionName}(
1585
+ &self,
1566
1586
  ${params ? `params: ${context.typeNamePrefix}${params},` : ""}
1567
1587
  ) -> Result<${context.typeNamePrefix}${response ?? "()"}, ArriServerError> {
1568
1588
  parsed_arri_request(
1569
1589
  ArriParsedRequestOptions {
1570
- http_client: &self.config.http_client,
1571
- url: format!("{}${schema.path}", &self.config.base_url),
1590
+ http_client: &self._config.http_client,
1591
+ url: format!("{}${schema.path}", &self._config.base_url),
1572
1592
  method: reqwest::Method::${schema.method.toUpperCase()},
1573
- headers: self.config.headers,
1593
+ headers: self._config.headers.clone(),
1574
1594
  client_version: "${context.clientVersion}".to_string(),
1575
1595
  },
1576
1596
  ${params ? `Some(params)` : "None::<EmptyArriModel>"},
@@ -1637,23 +1657,30 @@ function rustServiceFromSchema(schema, context) {
1637
1657
  `[rust-codegen] Invalid schema at /procedures/${context.instancePath}.`
1638
1658
  );
1639
1659
  }
1660
+ const paramSuffix = subServices.length > 0 ? ".clone()" : "";
1640
1661
  return {
1641
1662
  name: serviceName,
1642
- content: `pub struct ${serviceName}<'a> {
1643
- config: &'a ArriClientConfig,
1644
- ${subServices.map((service) => ` pub ${service.key}: ${service.name}<'a>,`).join("\n")}
1663
+ content: `#[derive(Clone)]
1664
+ pub struct ${serviceName} {
1665
+ _config: InternalArriClientConfig,
1666
+ ${subServices.map((service) => ` pub ${service.key}: ${service.name},`).join("\n")}
1645
1667
  }
1646
1668
 
1647
- impl<'a> ArriClientService<'a> for ${serviceName}<'a> {
1648
- fn create(config: &'a ArriClientConfig) -> Self {
1669
+ impl ArriClientService for ${serviceName} {
1670
+ fn create(config: ArriClientConfig) -> Self {
1649
1671
  Self {
1650
- config: &config,
1651
- ${subServices.map((service) => ` ${service.key}: ${service.name}::create(config),`).join("\n")}
1672
+ _config: InternalArriClientConfig::from(config${paramSuffix}),
1673
+ ${subServices.map((service, index) => ` ${service.key}: ${service.name}::create(config${index === subServices.length - 1 ? "" : ".clone()"}),`).join("\n")}
1652
1674
  }
1653
1675
  }
1676
+ fn update_headers(&self, headers: HashMap<&'static str, String>) {
1677
+ let mut unwrapped_headers = self._config.headers.write().unwrap();
1678
+ *unwrapped_headers = headers.clone();
1679
+ ${subServices.map((service, index) => ` self.${service.key}.update_headers(headers${index === subServices.length - 1 ? "" : ".clone()"});`).join("\n")}
1680
+ }
1654
1681
  }
1655
1682
 
1656
- impl ${serviceName}<'_> {
1683
+ impl ${serviceName} {
1657
1684
  ${rpcParts.join("\n")}
1658
1685
  }
1659
1686
 
@@ -1892,35 +1919,51 @@ use arri_client::{
1892
1919
  utils::{serialize_date_time, serialize_string},
1893
1920
  ArriEnum, ArriModel,
1894
1921
  };
1895
- use std::collections::BTreeMap;
1922
+ use std::collections::{BTreeMap, HashMap};
1896
1923
  ${modelParts.join("\n\n")}`;
1897
1924
  }
1898
1925
  const clientName = validRustName(context.clientName);
1899
- return `#![allow(dead_code, unused_imports, unused_variables, unconditional_recursion, deprecated)]
1926
+ const paramSuffix = subServices.length > 0 ? ".clone()" : "";
1927
+ return `#![allow(
1928
+ dead_code,
1929
+ unused_imports,
1930
+ unused_variables,
1931
+ unconditional_recursion,
1932
+ deprecated
1933
+ )]
1900
1934
  use arri_client::{
1901
1935
  chrono::{DateTime, FixedOffset},
1902
- parsed_arri_request, reqwest, serde_json,
1936
+ parsed_arri_request,
1937
+ reqwest::{self, Request},
1938
+ serde_json::{self, Map},
1939
+ sse::{parsed_arri_sse_request, ArriParsedSseRequestOptions, SseController, SseEvent},
1903
1940
  utils::{serialize_date_time, serialize_string},
1904
1941
  ArriClientConfig, ArriClientService, ArriEnum, ArriModel, ArriParsedRequestOptions,
1905
- ArriServerError, EmptyArriModel,
1942
+ ArriServerError, EmptyArriModel, InternalArriClientConfig,
1906
1943
  };
1907
- use std::collections::BTreeMap;
1944
+ use std::collections::{BTreeMap, HashMap};
1908
1945
 
1909
- pub struct ${clientName}<'a> {
1910
- config: &'a ArriClientConfig,
1911
- ${subServices.map((service) => ` pub ${service.key}: ${service.name}<'a>,`).join("\n")}
1946
+ #[derive(Clone)]
1947
+ pub struct ${clientName} {
1948
+ _config: InternalArriClientConfig,
1949
+ ${subServices.map((service) => ` pub ${service.key}: ${service.name},`).join("\n")}
1912
1950
  }
1913
1951
 
1914
- impl<'a> ArriClientService<'a> for ${clientName}<'a> {
1915
- fn create(config: &'a ArriClientConfig) -> Self {
1952
+ impl ArriClientService for ${clientName} {
1953
+ fn create(config: ArriClientConfig) -> Self {
1916
1954
  Self {
1917
- config: &config,
1918
- ${subServices.map((service) => ` ${service.key}: ${service.name}::create(config),`).join("\n")}
1955
+ _config: InternalArriClientConfig::from(config${paramSuffix}),
1956
+ ${subServices.map((service, index) => ` ${service.key}: ${service.name}::create(config${index === subServices.length - 1 ? "" : ".clone()"}),`).join("\n")}
1919
1957
  }
1920
1958
  }
1959
+ fn update_headers(&self, headers: HashMap<&'static str, String>) {
1960
+ let mut unwrapped_headers = self._config.headers.write().unwrap();
1961
+ *unwrapped_headers = headers.clone();
1962
+ ${subServices.map((service, index) => ` self.${service.key}.update_headers(headers${index === subServices.length - 1 ? "" : ".clone()"});`).join("\n")}
1963
+ }
1921
1964
  }
1922
1965
 
1923
- impl ${clientName}<'_> {
1966
+ impl ${clientName} {
1924
1967
  ${rpcParts.join("\n")}
1925
1968
  }
1926
1969
 
package/dist/index.mjs CHANGED
@@ -1536,15 +1536,7 @@ function rustRpcFromSchema(schema, context) {
1536
1536
  }
1537
1537
  }
1538
1538
  function rustHttpRpcFromSchema(schema, context) {
1539
- if (schema.isEventStream) {
1540
- console.warn(
1541
- `[rust-codegen] SSE is not supported at this time. Skipping ${context.instancePath}.`
1542
- );
1543
- return "";
1544
- }
1545
1539
  const functionName = getFunctionName(context.instancePath);
1546
- const params = schema.params ? validRustName(schema.params) : void 0;
1547
- const response = schema.response ? validRustName(schema.response) : void 0;
1548
1540
  let leading = "";
1549
1541
  if (schema.description) {
1550
1542
  leading += formatDescriptionComment(schema.description);
@@ -1553,16 +1545,44 @@ function rustHttpRpcFromSchema(schema, context) {
1553
1545
  if (schema.isDeprecated) {
1554
1546
  leading += "#[deprecated]\n";
1555
1547
  }
1556
- return `${leading}pub async fn ${functionName} (
1557
- self: &Self,
1548
+ const params = schema.params ? validRustName(schema.params) : void 0;
1549
+ const response = schema.response ? validRustName(schema.response) : void 0;
1550
+ if (schema.isEventStream) {
1551
+ return `${leading}pub async fn ${functionName}<OnEvent>(
1552
+ &self,
1553
+ ${params ? `params: ${context.typeNamePrefix}${params},` : ""}
1554
+ on_event: &mut OnEvent,
1555
+ max_retry_count: Option<u64>,
1556
+ max_retry_interval: Option<u64>,
1557
+ ) where
1558
+ OnEvent: FnMut(SseEvent<${response ? `${context.typeNamePrefix}${response}` : "EmptyArriModel"}>, &mut SseController) + std::marker::Send + std::marker::Sync,
1559
+ {
1560
+ parsed_arri_sse_request(
1561
+ ArriParsedSseRequestOptions {
1562
+ client: &self._config.http_client,
1563
+ url: format!("{}${schema.path}", &self._config.base_url),
1564
+ method: reqwest::Method::${schema.method.toUpperCase()},
1565
+ headers: self._config.headers.clone(),
1566
+ client_version: "${context.clientVersion}".to_string(),
1567
+ max_retry_count,
1568
+ max_retry_interval,
1569
+ },
1570
+ ${params ? `Some(params)` : "None::<EmptyArriModel>"},
1571
+ on_event,
1572
+ )
1573
+ .await;
1574
+ }`;
1575
+ }
1576
+ return `${leading}pub async fn ${functionName}(
1577
+ &self,
1558
1578
  ${params ? `params: ${context.typeNamePrefix}${params},` : ""}
1559
1579
  ) -> Result<${context.typeNamePrefix}${response ?? "()"}, ArriServerError> {
1560
1580
  parsed_arri_request(
1561
1581
  ArriParsedRequestOptions {
1562
- http_client: &self.config.http_client,
1563
- url: format!("{}${schema.path}", &self.config.base_url),
1582
+ http_client: &self._config.http_client,
1583
+ url: format!("{}${schema.path}", &self._config.base_url),
1564
1584
  method: reqwest::Method::${schema.method.toUpperCase()},
1565
- headers: self.config.headers,
1585
+ headers: self._config.headers.clone(),
1566
1586
  client_version: "${context.clientVersion}".to_string(),
1567
1587
  },
1568
1588
  ${params ? `Some(params)` : "None::<EmptyArriModel>"},
@@ -1629,23 +1649,30 @@ function rustServiceFromSchema(schema, context) {
1629
1649
  `[rust-codegen] Invalid schema at /procedures/${context.instancePath}.`
1630
1650
  );
1631
1651
  }
1652
+ const paramSuffix = subServices.length > 0 ? ".clone()" : "";
1632
1653
  return {
1633
1654
  name: serviceName,
1634
- content: `pub struct ${serviceName}<'a> {
1635
- config: &'a ArriClientConfig,
1636
- ${subServices.map((service) => ` pub ${service.key}: ${service.name}<'a>,`).join("\n")}
1655
+ content: `#[derive(Clone)]
1656
+ pub struct ${serviceName} {
1657
+ _config: InternalArriClientConfig,
1658
+ ${subServices.map((service) => ` pub ${service.key}: ${service.name},`).join("\n")}
1637
1659
  }
1638
1660
 
1639
- impl<'a> ArriClientService<'a> for ${serviceName}<'a> {
1640
- fn create(config: &'a ArriClientConfig) -> Self {
1661
+ impl ArriClientService for ${serviceName} {
1662
+ fn create(config: ArriClientConfig) -> Self {
1641
1663
  Self {
1642
- config: &config,
1643
- ${subServices.map((service) => ` ${service.key}: ${service.name}::create(config),`).join("\n")}
1664
+ _config: InternalArriClientConfig::from(config${paramSuffix}),
1665
+ ${subServices.map((service, index) => ` ${service.key}: ${service.name}::create(config${index === subServices.length - 1 ? "" : ".clone()"}),`).join("\n")}
1644
1666
  }
1645
1667
  }
1668
+ fn update_headers(&self, headers: HashMap<&'static str, String>) {
1669
+ let mut unwrapped_headers = self._config.headers.write().unwrap();
1670
+ *unwrapped_headers = headers.clone();
1671
+ ${subServices.map((service, index) => ` self.${service.key}.update_headers(headers${index === subServices.length - 1 ? "" : ".clone()"});`).join("\n")}
1672
+ }
1646
1673
  }
1647
1674
 
1648
- impl ${serviceName}<'_> {
1675
+ impl ${serviceName} {
1649
1676
  ${rpcParts.join("\n")}
1650
1677
  }
1651
1678
 
@@ -1884,35 +1911,51 @@ use arri_client::{
1884
1911
  utils::{serialize_date_time, serialize_string},
1885
1912
  ArriEnum, ArriModel,
1886
1913
  };
1887
- use std::collections::BTreeMap;
1914
+ use std::collections::{BTreeMap, HashMap};
1888
1915
  ${modelParts.join("\n\n")}`;
1889
1916
  }
1890
1917
  const clientName = validRustName(context.clientName);
1891
- return `#![allow(dead_code, unused_imports, unused_variables, unconditional_recursion, deprecated)]
1918
+ const paramSuffix = subServices.length > 0 ? ".clone()" : "";
1919
+ return `#![allow(
1920
+ dead_code,
1921
+ unused_imports,
1922
+ unused_variables,
1923
+ unconditional_recursion,
1924
+ deprecated
1925
+ )]
1892
1926
  use arri_client::{
1893
1927
  chrono::{DateTime, FixedOffset},
1894
- parsed_arri_request, reqwest, serde_json,
1928
+ parsed_arri_request,
1929
+ reqwest::{self, Request},
1930
+ serde_json::{self, Map},
1931
+ sse::{parsed_arri_sse_request, ArriParsedSseRequestOptions, SseController, SseEvent},
1895
1932
  utils::{serialize_date_time, serialize_string},
1896
1933
  ArriClientConfig, ArriClientService, ArriEnum, ArriModel, ArriParsedRequestOptions,
1897
- ArriServerError, EmptyArriModel,
1934
+ ArriServerError, EmptyArriModel, InternalArriClientConfig,
1898
1935
  };
1899
- use std::collections::BTreeMap;
1936
+ use std::collections::{BTreeMap, HashMap};
1900
1937
 
1901
- pub struct ${clientName}<'a> {
1902
- config: &'a ArriClientConfig,
1903
- ${subServices.map((service) => ` pub ${service.key}: ${service.name}<'a>,`).join("\n")}
1938
+ #[derive(Clone)]
1939
+ pub struct ${clientName} {
1940
+ _config: InternalArriClientConfig,
1941
+ ${subServices.map((service) => ` pub ${service.key}: ${service.name},`).join("\n")}
1904
1942
  }
1905
1943
 
1906
- impl<'a> ArriClientService<'a> for ${clientName}<'a> {
1907
- fn create(config: &'a ArriClientConfig) -> Self {
1944
+ impl ArriClientService for ${clientName} {
1945
+ fn create(config: ArriClientConfig) -> Self {
1908
1946
  Self {
1909
- config: &config,
1910
- ${subServices.map((service) => ` ${service.key}: ${service.name}::create(config),`).join("\n")}
1947
+ _config: InternalArriClientConfig::from(config${paramSuffix}),
1948
+ ${subServices.map((service, index) => ` ${service.key}: ${service.name}::create(config${index === subServices.length - 1 ? "" : ".clone()"}),`).join("\n")}
1911
1949
  }
1912
1950
  }
1951
+ fn update_headers(&self, headers: HashMap<&'static str, String>) {
1952
+ let mut unwrapped_headers = self._config.headers.write().unwrap();
1953
+ *unwrapped_headers = headers.clone();
1954
+ ${subServices.map((service, index) => ` self.${service.key}.update_headers(headers${index === subServices.length - 1 ? "" : ".clone()"});`).join("\n")}
1955
+ }
1913
1956
  }
1914
1957
 
1915
- impl ${clientName}<'_> {
1958
+ impl ${clientName} {
1916
1959
  ${rpcParts.join("\n")}
1917
1960
  }
1918
1961
 
package/package.json CHANGED
@@ -22,10 +22,10 @@
22
22
  ],
23
23
  "dependencies": {
24
24
  "pathe": "^1.1.2",
25
- "@arrirpc/codegen-utils": "0.54.0"
25
+ "@arrirpc/codegen-utils": "0.57.0"
26
26
  },
27
27
  "devDependencies": {
28
- "@arrirpc/schema": "0.54.0"
28
+ "@arrirpc/schema": "0.57.0"
29
29
  },
30
- "version": "0.54.0"
30
+ "version": "0.57.0"
31
31
  }