mirror of
https://github.com/wisdgod/cursor-api.git
synced 2025-09-27 02:56:01 +08:00
perf: optimize
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -31,5 +31,4 @@ Cargo.lock
|
||||
/*.sh
|
||||
/*.tar.gz
|
||||
/src/core/model/a.rs
|
||||
/src/core/aiserver/v1/lite.proto
|
||||
.cargo/config.toml
|
||||
|
@@ -3,18 +3,18 @@ FROM --platform=linux/${TARGETARCH} rustlang/rust:nightly-bookworm-slim AS build
|
||||
|
||||
ARG TARGETARCH
|
||||
|
||||
WORKDIR /app
|
||||
WORKDIR /build
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends build-essential protobuf-compiler nodejs npm musl-tools && rm -rf /var/lib/apt/lists/* && case "$TARGETARCH" in amd64) rustup target add x86_64-unknown-linux-musl ;; arm64) rustup target add aarch64-unknown-linux-musl ;; *) echo "Unsupported architecture for rustup: $TARGETARCH" && exit 1 ;; esac
|
||||
|
||||
COPY . .
|
||||
RUN case "$TARGETARCH" in amd64) TARGET_TRIPLE="x86_64-unknown-linux-musl"; TARGET_CPU="x86-64-v3" ;; arm64) TARGET_TRIPLE="aarch64-unknown-linux-musl"; TARGET_CPU="neoverse-n1" ;; *) echo "Unsupported architecture: $TARGETARCH" && exit 1 ;; esac && RUSTFLAGS="-C link-arg=-s -C target-feature=+crt-static -C target-cpu=$TARGET_CPU -A unused" cargo build --bin cursor-api --release --target=$TARGET_TRIPLE && cp target/$TARGET_TRIPLE/release/cursor-api /app/cursor-api
|
||||
RUN case "$TARGETARCH" in amd64) TARGET_TRIPLE="x86_64-unknown-linux-musl"; TARGET_CPU="x86-64-v3" ;; arm64) TARGET_TRIPLE="aarch64-unknown-linux-musl"; TARGET_CPU="neoverse-n1" ;; *) echo "Unsupported architecture: $TARGETARCH" && exit 1 ;; esac && RUSTFLAGS="-C link-arg=-s -C target-feature=+crt-static -C target-cpu=$TARGET_CPU -A unused" cargo build --bin cursor-api --release --target=$TARGET_TRIPLE && mkdir /app && cp target/$TARGET_TRIPLE/release/cursor-api /app/
|
||||
|
||||
# 运行阶段
|
||||
FROM scratch
|
||||
|
||||
WORKDIR /app
|
||||
COPY --chown=1001:1001 --chmod=0700 --from=builder /app /app
|
||||
|
||||
COPY --from=builder /app/cursor-api .
|
||||
WORKDIR /app
|
||||
|
||||
ENV PORT=3000
|
||||
EXPOSE ${PORT}
|
||||
|
5
build.rs
5
build.rs
@@ -261,6 +261,8 @@ fn main() -> Result<()> {
|
||||
".aiserver.v1.IRange",
|
||||
".aiserver.v1.BlockDiffPatch",
|
||||
".aiserver.v1.AvailableModelsRequest",
|
||||
".aiserver.v1.GetFilteredUsageEventsResponse",
|
||||
".aiserver.v1.GetAggregatedUsageEventsResponse",
|
||||
],
|
||||
attributes: [
|
||||
"#[derive(::serde::Deserialize)]",
|
||||
@@ -279,6 +281,9 @@ fn main() -> Result<()> {
|
||||
".aiserver.v1.CppConfigResponse",
|
||||
".aiserver.v1.AvailableCppModelsResponse",
|
||||
".aiserver.v1.AvailableModelsResponse",
|
||||
".aiserver.v1.CustomErrorDetails",
|
||||
".aiserver.v1.GetFilteredUsageEventsRequest",
|
||||
".aiserver.v1.GetAggregatedUsageEventsRequest",
|
||||
],
|
||||
attributes: [
|
||||
"#[derive(::serde::Serialize)]",
|
||||
|
@@ -39,8 +39,7 @@ fn update_version() -> Result<()> {
|
||||
// 版本号加1
|
||||
let new_version = version_num + 1;
|
||||
println!(
|
||||
"cargo:warning=Release build - bumping version from {} to {}",
|
||||
version_num, new_version
|
||||
"cargo:warning=Release build - bumping version from {version_num} to {new_version}",
|
||||
);
|
||||
|
||||
// 写回文件
|
||||
@@ -71,9 +70,9 @@ fn generate_build_info() -> Result<()> {
|
||||
#[cfg(not(debug_assertions))]
|
||||
let out_dir = "target/release/build/build_info.rs";
|
||||
let dest_path = Path::new(out_dir);
|
||||
if dest_path.is_file() {
|
||||
return Ok(());
|
||||
}
|
||||
// if dest_path.is_file() {
|
||||
// return Ok(());
|
||||
// }
|
||||
|
||||
let build_timestamp = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
@@ -108,7 +107,7 @@ pub const IS_DEBUG: bool = {is_debug};
|
||||
|
||||
#[cfg(unix)]
|
||||
pub const BUILD_EPOCH: std::time::SystemTime = unsafe {{
|
||||
#[repr(C)]
|
||||
#[allow(dead_code)]
|
||||
struct UnixSystemTime {{
|
||||
tv_sec: i64,
|
||||
tv_nsec: u32,
|
||||
@@ -122,7 +121,7 @@ pub const BUILD_EPOCH: std::time::SystemTime = unsafe {{
|
||||
|
||||
#[cfg(windows)]
|
||||
pub const BUILD_EPOCH: std::time::SystemTime = unsafe {{
|
||||
#[repr(C)]
|
||||
#[allow(dead_code)]
|
||||
struct WindowsFileTime {{
|
||||
dw_low_date_time: u32,
|
||||
dw_high_date_time: u32,
|
||||
|
@@ -1,3 +1,7 @@
|
||||
# 0.4.12 (August 5, 2025)
|
||||
|
||||
* Fix default limits on max stored reset streams and duration to more reasonable values.
|
||||
|
||||
# 0.4.11 (June 30, 2025)
|
||||
|
||||
* Fix client to not return an error when a clean shutdown otherwise doesn't get a TLS close_notify, which some servers don't bother sending.
|
||||
|
@@ -3,7 +3,7 @@ name = "h2"
|
||||
# When releasing to crates.io:
|
||||
# - Update CHANGELOG.md.
|
||||
# - Create git tag
|
||||
version = "0.4.11"
|
||||
version = "0.4.12"
|
||||
license = "MIT"
|
||||
authors = [
|
||||
"Carl Lerche <me@carllerche.com>",
|
||||
|
@@ -53,19 +53,6 @@ fn main() {
|
||||
|
||||
## FAQ
|
||||
|
||||
**How does h2 compare to [solicit] or [rust-http2]?**
|
||||
|
||||
The h2 library has implemented more of the details of the HTTP/2 specification
|
||||
than any other Rust library. It also passes the [h2spec] set of tests. The h2
|
||||
library is rapidly approaching "production ready" quality.
|
||||
|
||||
Besides the above, Solicit is built on blocking I/O and does not appear to be
|
||||
actively maintained.
|
||||
|
||||
**Is this an embedded Java SQL database engine?**
|
||||
|
||||
[No](https://www.h2database.com).
|
||||
|
||||
[solicit]: https://github.com/mlalic/solicit
|
||||
[rust-http2]: https://github.com/stepancheg/rust-http2
|
||||
[h2spec]: https://github.com/summerwind/h2spec
|
||||
|
@@ -923,7 +923,7 @@ impl Builder {
|
||||
/// received for that stream will result in a connection level protocol
|
||||
/// error, forcing the connection to terminate.
|
||||
///
|
||||
/// The default value is 10.
|
||||
/// The default value is currently 50.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -968,7 +968,7 @@ impl Builder {
|
||||
/// received for that stream will result in a connection level protocol
|
||||
/// error, forcing the connection to terminate.
|
||||
///
|
||||
/// The default value is 30 seconds.
|
||||
/// The default value is currently 1 second.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@@ -33,6 +33,10 @@ pub type WindowSize = u32;
|
||||
pub const MAX_WINDOW_SIZE: WindowSize = (1 << 31) - 1; // i32::MAX as u32
|
||||
pub const DEFAULT_REMOTE_RESET_STREAM_MAX: usize = 20;
|
||||
pub const DEFAULT_LOCAL_RESET_COUNT_MAX: usize = 1024;
|
||||
pub const DEFAULT_RESET_STREAM_MAX: usize = 10;
|
||||
pub const DEFAULT_RESET_STREAM_SECS: u64 = 30;
|
||||
// RFC 9113 suggests allowing at minimum 100 streams, it seems reasonable to
|
||||
// by default allow a portion of that to be remembered as reset for some time.
|
||||
pub const DEFAULT_RESET_STREAM_MAX: usize = 50;
|
||||
// RFC 9113#5.4.2 suggests ~1 RTT. We don't track that closely, but use a
|
||||
// reasonable guess of the average here.
|
||||
pub const DEFAULT_RESET_STREAM_SECS: u64 = 1;
|
||||
pub const DEFAULT_MAX_SEND_BUFFER_SIZE: usize = 1024 * 400;
|
||||
|
@@ -73,3 +73,56 @@ pub struct Config {
|
||||
/// When this gets exceeded, we issue GOAWAYs.
|
||||
pub local_max_error_reset_streams: Option<usize>,
|
||||
}
|
||||
|
||||
trait DebugStructExt<'a, 'b> {
|
||||
// h2_ prefixes to protect against possible future name collisions
|
||||
fn h2_field_if(&mut self, name: &str, val: &bool) -> &mut std::fmt::DebugStruct<'a, 'b>;
|
||||
|
||||
fn h2_field_if_then<T: std::fmt::Debug>(
|
||||
&mut self,
|
||||
name: &str,
|
||||
cond: bool,
|
||||
val: &T,
|
||||
) -> &mut std::fmt::DebugStruct<'a, 'b>;
|
||||
|
||||
fn h2_field_some<T: std::fmt::Debug>(
|
||||
&mut self,
|
||||
name: &str,
|
||||
val: &Option<T>,
|
||||
) -> &mut std::fmt::DebugStruct<'a, 'b>;
|
||||
}
|
||||
|
||||
impl<'a, 'b> DebugStructExt<'a, 'b> for std::fmt::DebugStruct<'a, 'b> {
|
||||
fn h2_field_if(&mut self, name: &str, val: &bool) -> &mut std::fmt::DebugStruct<'a, 'b> {
|
||||
if *val {
|
||||
self.field(name, val)
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn h2_field_if_then<T: std::fmt::Debug>(
|
||||
&mut self,
|
||||
name: &str,
|
||||
cond: bool,
|
||||
val: &T,
|
||||
) -> &mut std::fmt::DebugStruct<'a, 'b> {
|
||||
if cond {
|
||||
self.field(name, val)
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn h2_field_some<T: std::fmt::Debug>(
|
||||
&mut self,
|
||||
name: &str,
|
||||
val: &Option<T>,
|
||||
) -> &mut std::fmt::DebugStruct<'a, 'b> {
|
||||
if val.is_some() {
|
||||
self.field(name, val)
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -912,11 +912,15 @@ impl Recv {
|
||||
return;
|
||||
}
|
||||
|
||||
tracing::trace!("enqueue_reset_expiration; {:?}", stream.id);
|
||||
|
||||
if counts.can_inc_num_reset_streams() {
|
||||
counts.inc_num_reset_streams();
|
||||
tracing::trace!("enqueue_reset_expiration; added {:?}", stream.id);
|
||||
self.pending_reset_expired.push(stream);
|
||||
} else {
|
||||
tracing::trace!(
|
||||
"enqueue_reset_expiration; dropped {:?}, over max_concurrent_reset_streams",
|
||||
stream.id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
|
||||
use crate::codec::UserError;
|
||||
@@ -47,7 +48,7 @@ use self::Peer::*;
|
||||
/// ES: END_STREAM flag
|
||||
/// R: RST_STREAM frame
|
||||
/// ```
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct State {
|
||||
inner: Inner,
|
||||
}
|
||||
@@ -465,3 +466,10 @@ impl Default for State {
|
||||
State { inner: Inner::Idle }
|
||||
}
|
||||
}
|
||||
|
||||
// remove some noise for debug output
|
||||
impl fmt::Debug for State {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.inner.fmt(f)
|
||||
}
|
||||
}
|
||||
|
@@ -34,7 +34,6 @@ pub(crate) struct Key {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
struct SlabIndex(u32);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct Queue<N> {
|
||||
indices: Option<store::Indices>,
|
||||
_p: PhantomData<N>,
|
||||
@@ -378,6 +377,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<N> fmt::Debug for Queue<N> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Queue")
|
||||
.field("indices", &self.indices)
|
||||
// skip phantom data
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
// ===== impl Ptr =====
|
||||
|
||||
impl<'a> Ptr<'a> {
|
||||
|
@@ -398,35 +398,47 @@ impl fmt::Debug for Stream {
|
||||
.field("state", &self.state)
|
||||
.field("is_counted", &self.is_counted)
|
||||
.field("ref_count", &self.ref_count)
|
||||
.field("next_pending_send", &self.next_pending_send)
|
||||
.field("is_pending_send", &self.is_pending_send)
|
||||
.h2_field_some("next_pending_send", &self.next_pending_send)
|
||||
.h2_field_if("is_pending_send", &self.is_pending_send)
|
||||
.field("send_flow", &self.send_flow)
|
||||
.field("requested_send_capacity", &self.requested_send_capacity)
|
||||
.field("buffered_send_data", &self.buffered_send_data)
|
||||
.field("send_task", &self.send_task.as_ref().map(|_| ()))
|
||||
.field("pending_send", &self.pending_send)
|
||||
.field(
|
||||
.h2_field_some("send_task", &self.send_task.as_ref().map(|_| ()))
|
||||
.h2_field_if_then(
|
||||
"pending_send",
|
||||
!self.pending_send.is_empty(),
|
||||
&self.pending_send,
|
||||
)
|
||||
.h2_field_some(
|
||||
"next_pending_send_capacity",
|
||||
&self.next_pending_send_capacity,
|
||||
)
|
||||
.field("is_pending_send_capacity", &self.is_pending_send_capacity)
|
||||
.field("send_capacity_inc", &self.send_capacity_inc)
|
||||
.field("next_open", &self.next_open)
|
||||
.field("is_pending_open", &self.is_pending_open)
|
||||
.field("is_pending_push", &self.is_pending_push)
|
||||
.field("next_pending_accept", &self.next_pending_accept)
|
||||
.field("is_pending_accept", &self.is_pending_accept)
|
||||
.h2_field_if("is_pending_send_capacity", &self.is_pending_send_capacity)
|
||||
.h2_field_if("send_capacity_inc", &self.send_capacity_inc)
|
||||
.h2_field_some("next_open", &self.next_open)
|
||||
.h2_field_if("is_pending_open", &self.is_pending_open)
|
||||
.h2_field_if("is_pending_push", &self.is_pending_push)
|
||||
.h2_field_some("next_pending_accept", &self.next_pending_accept)
|
||||
.h2_field_if("is_pending_accept", &self.is_pending_accept)
|
||||
.field("recv_flow", &self.recv_flow)
|
||||
.field("in_flight_recv_data", &self.in_flight_recv_data)
|
||||
.field("next_window_update", &self.next_window_update)
|
||||
.field("is_pending_window_update", &self.is_pending_window_update)
|
||||
.field("reset_at", &self.reset_at)
|
||||
.field("next_reset_expire", &self.next_reset_expire)
|
||||
.field("pending_recv", &self.pending_recv)
|
||||
.field("is_recv", &self.is_recv)
|
||||
.field("recv_task", &self.recv_task.as_ref().map(|_| ()))
|
||||
.field("push_task", &self.push_task.as_ref().map(|_| ()))
|
||||
.field("pending_push_promises", &self.pending_push_promises)
|
||||
.h2_field_some("next_window_update", &self.next_window_update)
|
||||
.h2_field_if("is_pending_window_update", &self.is_pending_window_update)
|
||||
.h2_field_some("reset_at", &self.reset_at)
|
||||
.h2_field_some("next_reset_expire", &self.next_reset_expire)
|
||||
.h2_field_if_then(
|
||||
"pending_recv",
|
||||
!self.pending_recv.is_empty(),
|
||||
&self.pending_recv,
|
||||
)
|
||||
.h2_field_if("is_recv", &self.is_recv)
|
||||
.h2_field_some("recv_task", &self.recv_task.as_ref().map(|_| ()))
|
||||
.h2_field_some("push_task", &self.push_task.as_ref().map(|_| ()))
|
||||
.h2_field_if_then(
|
||||
"pending_push_promises",
|
||||
!self.pending_push_promises.is_empty(),
|
||||
&self.pending_push_promises,
|
||||
)
|
||||
.field("content_length", &self.content_length)
|
||||
.finish()
|
||||
}
|
||||
|
@@ -868,7 +868,7 @@ impl Builder {
|
||||
/// received for that stream will result in a connection level protocol
|
||||
/// error, forcing the connection to terminate.
|
||||
///
|
||||
/// The default value is 10.
|
||||
/// The default value is currently 50.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -993,7 +993,7 @@ impl Builder {
|
||||
/// received for that stream will result in a connection level protocol
|
||||
/// error, forcing the connection to terminate.
|
||||
///
|
||||
/// The default value is 30 seconds.
|
||||
/// The default value is currently 1 second.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@@ -253,7 +253,7 @@ pub fn init_thinking_tags() {
|
||||
let open_len = tag_len + 2;
|
||||
|
||||
// 分配开始标签
|
||||
let open_layout = ::core::alloc::Layout::array::<u8>(open_len).unwrap();
|
||||
let open_layout = ::core::alloc::Layout::array::<u8>(open_len).unwrap_unchecked();
|
||||
let open_ptr = ::std::alloc::alloc(open_layout);
|
||||
if open_ptr.is_null() {
|
||||
::std::alloc::handle_alloc_error(open_layout);
|
||||
@@ -269,7 +269,7 @@ pub fn init_thinking_tags() {
|
||||
let close_len = tag_len + 3;
|
||||
|
||||
// 分配结束标签
|
||||
let close_layout = ::core::alloc::Layout::array::<u8>(close_len).unwrap();
|
||||
let close_layout = ::core::alloc::Layout::array::<u8>(close_len).unwrap_unchecked();
|
||||
let close_ptr = ::std::alloc::alloc(close_layout);
|
||||
if close_ptr.is_null() {
|
||||
::std::alloc::handle_alloc_error(close_layout);
|
||||
|
@@ -129,7 +129,7 @@ pub async fn ensure_logger_initialized() -> &'static LoggerState {
|
||||
_ = interval.tick() => {
|
||||
// 定时刷新时,如果有积压的消息且等待时间过长,强制写入
|
||||
if !pending_messages.is_empty() {
|
||||
let oldest_seq = *pending_messages.keys().next().unwrap();
|
||||
let oldest_seq = *__unwrap!(pending_messages.keys().next());
|
||||
// 如果最旧的消息序号与期望序号相差太大,可能有消息丢失
|
||||
if oldest_seq > next_seq + 100 {
|
||||
eprintln!("日志系统警告:检测到可能的消息丢失,跳过序号 {next_seq} 到 {}", oldest_seq - 1);
|
||||
|
@@ -4,6 +4,7 @@ use ::core::{
|
||||
alloc::Layout,
|
||||
hash::Hasher,
|
||||
marker::PhantomData,
|
||||
mem::SizedTypeProperties as _,
|
||||
ptr::NonNull,
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
@@ -132,7 +133,6 @@ impl TokenKey {
|
||||
/// | string data... | UTF-8 字符串表示
|
||||
/// +----------------------+
|
||||
/// ```
|
||||
#[repr(C)]
|
||||
struct TokenInner {
|
||||
/// 原始 token 数据
|
||||
raw: RawToken,
|
||||
@@ -143,6 +143,11 @@ struct TokenInner {
|
||||
}
|
||||
|
||||
impl TokenInner {
|
||||
const STRING_MAX_LEN: usize = {
|
||||
let layout = Self::LAYOUT;
|
||||
isize::MAX as usize + 1 - layout.align() - layout.size()
|
||||
};
|
||||
|
||||
/// 获取字符串数据的起始地址
|
||||
#[inline(always)]
|
||||
const unsafe fn string_ptr(&self) -> *const u8 { (self as *const Self).add(1) as *const u8 }
|
||||
@@ -157,11 +162,17 @@ impl TokenInner {
|
||||
|
||||
/// 计算存储指定长度字符串所需的内存布局
|
||||
fn layout_for_string(string_len: usize) -> Layout {
|
||||
Layout::new::<Self>()
|
||||
.extend(__unwrap!(Layout::array::<u8>(string_len)))
|
||||
.unwrap()
|
||||
.0
|
||||
.pad_to_align()
|
||||
if string_len > Self::STRING_MAX_LEN {
|
||||
__cold_path!();
|
||||
panic!("string is too long");
|
||||
}
|
||||
unsafe {
|
||||
Layout::new::<Self>()
|
||||
.extend(Layout::array::<u8>(string_len).unwrap_unchecked())
|
||||
.unwrap_unchecked()
|
||||
.0
|
||||
.pad_to_align()
|
||||
}
|
||||
}
|
||||
|
||||
/// 在指定内存位置写入结构体和字符串数据
|
||||
|
@@ -1,3 +1,11 @@
|
||||
use ::reqwest::{
|
||||
Client, RequestBuilder,
|
||||
header::{
|
||||
ACCEPT, ACCEPT_ENCODING, ACCEPT_LANGUAGE, AUTHORIZATION, CACHE_CONTROL, CONNECTION,
|
||||
CONTENT_LENGTH, CONTENT_TYPE, COOKIE, DNT, HOST, ORIGIN, PRAGMA, REFERER, TE, USER_AGENT,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
app::{
|
||||
constant::{
|
||||
@@ -20,13 +28,6 @@ use crate::{
|
||||
},
|
||||
common::utils::StringBuilder,
|
||||
};
|
||||
use reqwest::{
|
||||
Client, RequestBuilder,
|
||||
header::{
|
||||
ACCEPT, ACCEPT_ENCODING, ACCEPT_LANGUAGE, AUTHORIZATION, CACHE_CONTROL, CONNECTION,
|
||||
CONTENT_LENGTH, CONTENT_TYPE, COOKIE, DNT, HOST, ORIGIN, PRAGMA, REFERER, TE, USER_AGENT,
|
||||
},
|
||||
};
|
||||
|
||||
trait RequestBuilderExt: Sized {
|
||||
fn opt_header<K, V>(self, key: K, value: Option<V>) -> Self
|
||||
|
@@ -10,7 +10,7 @@ pub use super::build::BUILD_EPOCH;
|
||||
/// Unix 系统的时间基准点(2024-12-23 01:30:48 UTC)
|
||||
#[cfg(unix)]
|
||||
pub const EPOCH: std::time::SystemTime = unsafe {
|
||||
#[repr(C)]
|
||||
#[allow(dead_code)]
|
||||
struct UnixSystemTime {
|
||||
tv_sec: i64,
|
||||
tv_nsec: u32,
|
||||
@@ -25,7 +25,7 @@ pub const EPOCH: std::time::SystemTime = unsafe {
|
||||
/// Windows 系统的时间基准点(2024-12-23 01:30:48 UTC)
|
||||
#[cfg(windows)]
|
||||
pub const EPOCH: std::time::SystemTime = unsafe {
|
||||
#[repr(C)]
|
||||
#[allow(dead_code)]
|
||||
struct WindowsFileTime {
|
||||
dw_low_date_time: u32,
|
||||
dw_high_date_time: u32,
|
||||
|
@@ -40,7 +40,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
mod private {
|
||||
mod sealed {
|
||||
pub trait Sealed: Sized {}
|
||||
|
||||
impl Sealed for bool {}
|
||||
@@ -48,7 +48,7 @@ mod private {
|
||||
impl Sealed for usize {}
|
||||
}
|
||||
|
||||
pub trait ParseFromEnv: private::Sealed {
|
||||
pub trait ParseFromEnv: sealed::Sealed {
|
||||
type Result = Self;
|
||||
fn parse_from_env(key: &str, default: Self) -> Self::Result;
|
||||
}
|
||||
@@ -324,8 +324,9 @@ pub async fn get_user_profile(
|
||||
pub async fn get_available_models(
|
||||
ext_token: ExtToken,
|
||||
is_pri: bool,
|
||||
request: AvailableModelsRequest,
|
||||
mut request: AvailableModelsRequest,
|
||||
) -> Option<AvailableModelsResponse> {
|
||||
request.exclude_max_named_models = true;
|
||||
let response = {
|
||||
let client = super::client::build_client_request(super::client::AiServiceRequest {
|
||||
ext_token,
|
||||
@@ -545,7 +546,7 @@ fn compress_gzip(data: &[u8]) -> Result<Vec<u8>, std::io::Error> {
|
||||
#[allow(clippy::uninit_vec)]
|
||||
#[inline(always)]
|
||||
pub fn encode_message(
|
||||
message: &impl prost::Message,
|
||||
message: &impl ::prost::Message,
|
||||
maybe_stream: bool,
|
||||
) -> Result<Vec<u8>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
const COMPRESSION_THRESHOLD: usize = 1024; // 1KB
|
||||
@@ -928,7 +929,7 @@ pub async fn get_aggregated_usage_events(
|
||||
aggregated_usage_events_url,
|
||||
is_pri,
|
||||
bytes::Bytes::from(__unwrap!(serde_json::to_vec(&{
|
||||
const DELTA: chrono::TimeDelta = chrono::TimeDelta::new(2629743, 765840000).unwrap();
|
||||
const DELTA: chrono::TimeDelta = __unwrap!(chrono::TimeDelta::new(2629743, 765840000));
|
||||
let now = DateTime::utc_now();
|
||||
let start_date = now - DELTA;
|
||||
GetAggregatedUsageEventsRequest {
|
||||
@@ -959,10 +960,10 @@ pub struct FilteredUsageArgs {
|
||||
impl From<FilteredUsageArgs> for GetFilteredUsageEventsRequest {
|
||||
#[inline]
|
||||
fn from(args: FilteredUsageArgs) -> Self {
|
||||
const TZ: chrono::FixedOffset = chrono::FixedOffset::west_opt(16 * 3600).unwrap();
|
||||
const TIME: chrono::NaiveTime = chrono::NaiveTime::from_hms_opt(0, 0, 0).unwrap();
|
||||
const TZ: chrono::FixedOffset = __unwrap!(chrono::FixedOffset::west_opt(16 * 3600));
|
||||
const TIME: chrono::NaiveTime = __unwrap!(chrono::NaiveTime::from_hms_opt(0, 0, 0));
|
||||
const START: chrono::TimeDelta = chrono::TimeDelta::days(-7);
|
||||
const END: chrono::TimeDelta = chrono::TimeDelta::new(86399, 999000000).unwrap();
|
||||
const END: chrono::TimeDelta = __unwrap!(chrono::TimeDelta::new(86399, 999000000));
|
||||
|
||||
let (start_date, end_date) = if let (Some(a), Some(b)) = (args.start, args.end) {
|
||||
(a.timestamp_millis(), b.timestamp_millis())
|
||||
|
@@ -160,9 +160,9 @@ impl<'a> StringBuilder<'a> {
|
||||
}
|
||||
result
|
||||
}
|
||||
Storage::Mixed(parts) => {
|
||||
Storage::Mixed(mut parts) => {
|
||||
if parts.len() == 1 {
|
||||
return parts.into_iter().next().unwrap().into_owned();
|
||||
return unsafe { parts.pop().unwrap_unchecked().into_owned() };
|
||||
}
|
||||
let mut result = String::with_capacity(self.total_len);
|
||||
for part in parts {
|
||||
|
@@ -264,7 +264,7 @@ async fn process_message_params(
|
||||
}),
|
||||
},
|
||||
all_thinking_blocks,
|
||||
unified_mode: Some(stream_unified_chat_request::UnifiedMode::Chat as i32),
|
||||
unified_mode: Some(if is_agentic { stream_unified_chat_request::UnifiedMode::Agent } else { stream_unified_chat_request::UnifiedMode::Chat } as i32),
|
||||
supported_tools: vec![],
|
||||
external_links,
|
||||
use_web,
|
||||
@@ -290,14 +290,13 @@ async fn process_message_params(
|
||||
composer_capability_request::ToolCallCapability {
|
||||
custom_instructions: t.description,
|
||||
tool_schemas: vec![composer_capability_request::ToolSchema {
|
||||
r#type: composer_capability_request::ToolType::Iterate as i32,
|
||||
r#type: composer_capability_request::ToolType::Unspecified as i32,
|
||||
name: t.name,
|
||||
properties: unsafe {
|
||||
::core::intrinsics::transmute_unchecked(t.input_schema.properties)
|
||||
},
|
||||
required: t.input_schema.required,
|
||||
}],
|
||||
..Default::default()
|
||||
},
|
||||
)),
|
||||
})
|
||||
@@ -429,15 +428,14 @@ pub async fn encode_message_params(
|
||||
request: Some(crate::core::aiserver::v1::stream_unified_chat_request_with_tools::Request::StreamUnifiedChatRequest(Box::new(StreamUnifiedChatRequest {
|
||||
conversation: messages,
|
||||
full_conversation_headers_only: messages_headers,
|
||||
allow_long_file_scan: Some(false),
|
||||
// allow_long_file_scan: Some(false),
|
||||
explicit_context,
|
||||
can_handle_filenames_after_language_ids: Some(false),
|
||||
// can_handle_filenames_after_language_ids: Some(false),
|
||||
model_details: Some(ModelDetails {
|
||||
model_name: Some(model.id.to_string()),
|
||||
azure_state: Some(AzureState::default()),
|
||||
enable_slow_pool: enable_slow_pool.to_opt(),
|
||||
max_mode: Some(model.max),
|
||||
..Default::default()
|
||||
}),
|
||||
use_web: if model.web {
|
||||
Some(WEB_SEARCH_MODE.to_string())
|
||||
@@ -454,7 +452,6 @@ pub async fn encode_message_params(
|
||||
start_position: Some(CursorPosition { line: 0, column: 0 }),
|
||||
end_position: Some(CursorPosition { line: 0, column: 0 }),
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
use_reference_composer_diff_prompt: Some(false),
|
||||
use_new_compression_scheme: Some(false),
|
||||
@@ -473,7 +470,7 @@ pub async fn encode_message_params(
|
||||
is_resume: Some(false),
|
||||
allow_model_fallbacks: Some(false),
|
||||
number_of_times_shown_fallback_model_warning: Some(0),
|
||||
unified_mode: Some(stream_unified_chat_request::UnifiedMode::Chat as i32),
|
||||
unified_mode: Some(if is_agentic { stream_unified_chat_request::UnifiedMode::Agent } else { stream_unified_chat_request::UnifiedMode::Chat } as i32),
|
||||
tools_requiring_accepted_return: supported_tools,
|
||||
should_disable_tools: Some(is_chat),
|
||||
thinking_level: Some(if model.is_thinking {
|
||||
@@ -484,7 +481,6 @@ pub async fn encode_message_params(
|
||||
uses_rules: Some(false),
|
||||
mode_uses_auto_apply: Some(false),
|
||||
unified_mode_name: Some(if is_chat { ASK_MODE_NAME } else { AGENT_MODE_NAME }.to_string()),
|
||||
..Default::default()
|
||||
})))
|
||||
};
|
||||
|
||||
|
@@ -241,12 +241,12 @@ async fn process_chat_inputs(
|
||||
server_bubble_id: server_bubble_id.clone(),
|
||||
is_capability_iteration: None,
|
||||
is_agentic: false,
|
||||
existed_subsequent_terminal_command: false,
|
||||
existed_previous_terminal_command: false,
|
||||
// existed_subsequent_terminal_command: false,
|
||||
// existed_previous_terminal_command: false,
|
||||
web_references,
|
||||
git_context: None,
|
||||
cached_conversation_summary: None,
|
||||
attached_human_changes: false,
|
||||
// git_context: None,
|
||||
// cached_conversation_summary: None,
|
||||
// attached_human_changes: false,
|
||||
thinking: None,
|
||||
unified_mode: Some(stream_unified_chat_request::UnifiedMode::Chat as i32),
|
||||
external_links,
|
||||
@@ -376,15 +376,14 @@ pub async fn encode_chat_message(
|
||||
request: Some(crate::core::aiserver::v1::stream_unified_chat_request_with_tools::Request::StreamUnifiedChatRequest(Box::new(StreamUnifiedChatRequest {
|
||||
conversation: messages,
|
||||
full_conversation_headers_only: messages_headers,
|
||||
allow_long_file_scan: Some(false),
|
||||
// allow_long_file_scan: Some(false),
|
||||
explicit_context,
|
||||
can_handle_filenames_after_language_ids: Some(false),
|
||||
// can_handle_filenames_after_language_ids: Some(false),
|
||||
model_details: Some(ModelDetails {
|
||||
model_name: Some(model.id.to_string()),
|
||||
azure_state: Some(AzureState::default()),
|
||||
enable_slow_pool: enable_slow_pool.to_opt(),
|
||||
max_mode: Some(model.max),
|
||||
..Default::default()
|
||||
}),
|
||||
use_web: if model.web {
|
||||
Some(WEB_SEARCH_MODE.to_string())
|
||||
@@ -401,7 +400,6 @@ pub async fn encode_chat_message(
|
||||
start_position: Some(CursorPosition { line: 0, column: 0 }),
|
||||
end_position: Some(CursorPosition { line: 0, column: 0 }),
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
use_reference_composer_diff_prompt: Some(false),
|
||||
use_new_compression_scheme: Some(false),
|
||||
@@ -410,25 +408,25 @@ pub async fn encode_chat_message(
|
||||
environment_info: Some(EnvironmentInfo::default()),
|
||||
is_agentic: false,
|
||||
supported_tools: vec![],
|
||||
use_unified_chat_prompt: false,
|
||||
// use_unified_chat_prompt: false,
|
||||
mcp_tools: vec![],
|
||||
use_full_inputs_context: long_context.to_opt(),
|
||||
is_resume: Some(false),
|
||||
allow_model_fallbacks: Some(false),
|
||||
number_of_times_shown_fallback_model_warning: Some(0),
|
||||
is_headless: false,
|
||||
// is_headless: false,
|
||||
unified_mode: Some(stream_unified_chat_request::UnifiedMode::Chat as i32),
|
||||
tools_requiring_accepted_return: vec![],
|
||||
should_disable_tools: Some(true),
|
||||
thinking_level: Some(if model.is_thinking {
|
||||
stream_unified_chat_request::ThinkingLevel::High
|
||||
} else {
|
||||
stream_unified_chat_request::ThinkingLevel::Unspecified
|
||||
} as i32),
|
||||
should_use_chat_prompt: None,
|
||||
// should_use_chat_prompt: None,
|
||||
uses_rules: Some(false),
|
||||
mode_uses_auto_apply: Some(false),
|
||||
unified_mode_name: Some(ASK_MODE_NAME.to_string()),
|
||||
..Default::default()
|
||||
})))
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
1025
src/core/aiserver/v1/lite.proto
Normal file
1025
src/core/aiserver/v1/lite.proto
Normal file
File diff suppressed because it is too large
Load Diff
@@ -39,7 +39,7 @@ impl StaticPool {
|
||||
}
|
||||
|
||||
// 计算布局,字符串不需要特殊对齐
|
||||
let layout = ::core::alloc::Layout::array::<u8>(len).unwrap();
|
||||
let layout = __unwrap!(::core::alloc::Layout::array::<u8>(len));
|
||||
|
||||
// 分配内存
|
||||
let ptr = ::std::alloc::alloc(layout);
|
||||
|
@@ -4,6 +4,7 @@ use ::core::{
|
||||
alloc::Layout,
|
||||
hash::{Hash, Hasher},
|
||||
marker::PhantomData,
|
||||
mem::SizedTypeProperties as _,
|
||||
ptr::NonNull,
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
@@ -23,7 +24,6 @@ use super::manually_init::ManuallyInit;
|
||||
/// | string data... | UTF-8 字符串数据
|
||||
/// +----------------+
|
||||
/// ```
|
||||
#[repr(C)]
|
||||
struct ArcStrInner {
|
||||
/// 原子引用计数
|
||||
count: AtomicUsize,
|
||||
@@ -32,6 +32,11 @@ struct ArcStrInner {
|
||||
}
|
||||
|
||||
impl ArcStrInner {
|
||||
const MAX_LEN: usize = {
|
||||
let layout = Self::LAYOUT;
|
||||
isize::MAX as usize + 1 - layout.align() - layout.size()
|
||||
};
|
||||
|
||||
/// 获取字符串数据的起始地址
|
||||
///
|
||||
/// # Safety
|
||||
@@ -54,11 +59,17 @@ impl ArcStrInner {
|
||||
|
||||
/// 计算存储指定长度字符串所需的内存布局
|
||||
fn layout_for_string(string_len: usize) -> Layout {
|
||||
Layout::new::<Self>()
|
||||
.extend(Layout::array::<u8>(string_len).unwrap())
|
||||
.unwrap()
|
||||
.0
|
||||
.pad_to_align()
|
||||
if string_len > Self::MAX_LEN {
|
||||
__cold_path!();
|
||||
panic!("string is too long");
|
||||
}
|
||||
unsafe {
|
||||
Layout::new::<Self>()
|
||||
.extend(Layout::array::<u8>(string_len).unwrap_unchecked())
|
||||
.unwrap_unchecked()
|
||||
.0
|
||||
.pad_to_align()
|
||||
}
|
||||
}
|
||||
|
||||
/// 在指定内存位置写入结构体和字符串数据
|
||||
@@ -442,9 +453,10 @@ pub fn clear_pool_for_test() {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::{thread, time::Duration};
|
||||
|
||||
use super::*;
|
||||
|
||||
/// 运行隔离的测试,确保池状态不会相互影响
|
||||
fn run_isolated_test<F: FnOnce()>(f: F) {
|
||||
clear_pool_for_test();
|
||||
|
@@ -6,7 +6,8 @@
|
||||
const_trait_impl,
|
||||
const_default,
|
||||
core_intrinsics,
|
||||
associated_type_defaults
|
||||
associated_type_defaults,
|
||||
sized_type_properties
|
||||
)]
|
||||
#![allow(clippy::redundant_static_lifetimes)]
|
||||
|
||||
|
Reference in New Issue
Block a user