Implement notification stream rpc
This commit is contained in:
Generated
+2
@@ -3200,12 +3200,14 @@ name = "tora"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"colored",
|
"colored",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"nix",
|
"nix",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-stream",
|
||||||
"tonic",
|
"tonic",
|
||||||
"tonic-health",
|
"tonic-health",
|
||||||
"tora-proto",
|
"tora-proto",
|
||||||
|
|||||||
@@ -159,6 +159,136 @@ impl ::prost::Name for ResumeResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
|
pub struct NotificationsRequest {
|
||||||
|
/// If non-empty, only events for these torrent ids (or id prefixes, as
|
||||||
|
/// accepted by `Status`/`Remove`) are delivered.
|
||||||
|
#[prost(string, repeated, tag = "1")]
|
||||||
|
pub ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
|
||||||
|
/// If non-empty, only these event kinds are delivered. An empty list means
|
||||||
|
/// all kinds.
|
||||||
|
#[prost(enumeration = "NotificationKind", repeated, tag = "2")]
|
||||||
|
pub kinds: ::prost::alloc::vec::Vec<i32>,
|
||||||
|
}
|
||||||
|
impl ::prost::Name for NotificationsRequest {
|
||||||
|
const NAME: &'static str = "NotificationsRequest";
|
||||||
|
const PACKAGE: &'static str = "torrent";
|
||||||
|
fn full_name() -> ::prost::alloc::string::String {
|
||||||
|
"torrent.NotificationsRequest".into()
|
||||||
|
}
|
||||||
|
fn type_url() -> ::prost::alloc::string::String {
|
||||||
|
"/torrent.NotificationsRequest".into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
|
pub struct Notification {
|
||||||
|
/// Wall-clock time the daemon observed the change, in milliseconds since the
|
||||||
|
/// Unix epoch.
|
||||||
|
#[prost(uint64, tag = "1")]
|
||||||
|
pub observed_at_unix_millis: u64,
|
||||||
|
/// What changed. Use this to dispatch; use the `oneof detail` for
|
||||||
|
/// kind-specific payload.
|
||||||
|
#[prost(enumeration = "NotificationKind", tag = "2")]
|
||||||
|
pub kind: i32,
|
||||||
|
/// Full snapshot of the torrent *after* the change. Always populated so
|
||||||
|
/// consumers don't need to fan out to `Status` for context.
|
||||||
|
#[prost(message, optional, tag = "3")]
|
||||||
|
pub torrent: ::core::option::Option<TorrentStatus>,
|
||||||
|
#[prost(oneof = "notification::Detail", tags = "10, 11, 12, 13")]
|
||||||
|
pub detail: ::core::option::Option<notification::Detail>,
|
||||||
|
}
|
||||||
|
/// Nested message and enum types in `Notification`.
|
||||||
|
pub mod notification {
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Oneof)]
|
||||||
|
pub enum Detail {
|
||||||
|
#[prost(message, tag = "10")]
|
||||||
|
StateChanged(super::StateChanged),
|
||||||
|
#[prost(message, tag = "11")]
|
||||||
|
Progress(super::ProgressMark),
|
||||||
|
#[prost(message, tag = "12")]
|
||||||
|
Added(super::AddedInfo),
|
||||||
|
#[prost(message, tag = "13")]
|
||||||
|
Removed(super::RemovedInfo),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ::prost::Name for Notification {
|
||||||
|
const NAME: &'static str = "Notification";
|
||||||
|
const PACKAGE: &'static str = "torrent";
|
||||||
|
fn full_name() -> ::prost::alloc::string::String {
|
||||||
|
"torrent.Notification".into()
|
||||||
|
}
|
||||||
|
fn type_url() -> ::prost::alloc::string::String {
|
||||||
|
"/torrent.Notification".into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
|
pub struct StateChanged {
|
||||||
|
#[prost(enumeration = "State", tag = "1")]
|
||||||
|
pub previous: i32,
|
||||||
|
#[prost(enumeration = "State", tag = "2")]
|
||||||
|
pub current: i32,
|
||||||
|
}
|
||||||
|
impl ::prost::Name for StateChanged {
|
||||||
|
const NAME: &'static str = "StateChanged";
|
||||||
|
const PACKAGE: &'static str = "torrent";
|
||||||
|
fn full_name() -> ::prost::alloc::string::String {
|
||||||
|
"torrent.StateChanged".into()
|
||||||
|
}
|
||||||
|
fn type_url() -> ::prost::alloc::string::String {
|
||||||
|
"/torrent.StateChanged".into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
|
pub struct ProgressMark {
|
||||||
|
/// Current integer percentage 0..=100.
|
||||||
|
#[prost(uint32, tag = "1")]
|
||||||
|
pub percent: u32,
|
||||||
|
/// Bytes downloaded since the previous PROGRESS event for this torrent.
|
||||||
|
#[prost(uint64, tag = "2")]
|
||||||
|
pub bytes_delta: u64,
|
||||||
|
}
|
||||||
|
impl ::prost::Name for ProgressMark {
|
||||||
|
const NAME: &'static str = "ProgressMark";
|
||||||
|
const PACKAGE: &'static str = "torrent";
|
||||||
|
fn full_name() -> ::prost::alloc::string::String {
|
||||||
|
"torrent.ProgressMark".into()
|
||||||
|
}
|
||||||
|
fn type_url() -> ::prost::alloc::string::String {
|
||||||
|
"/torrent.ProgressMark".into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
|
pub struct AddedInfo {
|
||||||
|
/// Source string as provided to `Add` (magnet, URL, or file path).
|
||||||
|
#[prost(string, tag = "1")]
|
||||||
|
pub source: ::prost::alloc::string::String,
|
||||||
|
}
|
||||||
|
impl ::prost::Name for AddedInfo {
|
||||||
|
const NAME: &'static str = "AddedInfo";
|
||||||
|
const PACKAGE: &'static str = "torrent";
|
||||||
|
fn full_name() -> ::prost::alloc::string::String {
|
||||||
|
"torrent.AddedInfo".into()
|
||||||
|
}
|
||||||
|
fn type_url() -> ::prost::alloc::string::String {
|
||||||
|
"/torrent.AddedInfo".into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
|
pub struct RemovedInfo {
|
||||||
|
/// True if `Remove` was called with `delete_files = true`.
|
||||||
|
#[prost(bool, tag = "1")]
|
||||||
|
pub files_deleted: bool,
|
||||||
|
}
|
||||||
|
impl ::prost::Name for RemovedInfo {
|
||||||
|
const NAME: &'static str = "RemovedInfo";
|
||||||
|
const PACKAGE: &'static str = "torrent";
|
||||||
|
fn full_name() -> ::prost::alloc::string::String {
|
||||||
|
"torrent.RemovedInfo".into()
|
||||||
|
}
|
||||||
|
fn type_url() -> ::prost::alloc::string::String {
|
||||||
|
"/torrent.RemovedInfo".into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
pub struct TorrentStatus {
|
pub struct TorrentStatus {
|
||||||
#[prost(string, tag = "1")]
|
#[prost(string, tag = "1")]
|
||||||
pub id: ::prost::alloc::string::String,
|
pub id: ::prost::alloc::string::String,
|
||||||
@@ -203,6 +333,47 @@ impl ::prost::Name for TorrentStatus {
|
|||||||
}
|
}
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
|
pub enum NotificationKind {
|
||||||
|
Unspecified = 0,
|
||||||
|
/// Emitted once when a torrent is added via `Add`.
|
||||||
|
TorrentAdded = 1,
|
||||||
|
/// Emitted once when a torrent is removed via `Remove`.
|
||||||
|
TorrentRemoved = 2,
|
||||||
|
/// Emitted on any `State` transition, including PAUSED <-> DOWNLOADING,
|
||||||
|
/// DOWNLOADING <-> STALE, * -> FINISHED, * -> ERROR.
|
||||||
|
StateChanged = 3,
|
||||||
|
/// Emitted when the integer download percentage changes (rate-limited).
|
||||||
|
/// No event is sent if the percentage did not advance since the last tick.
|
||||||
|
Progress = 4,
|
||||||
|
}
|
||||||
|
impl NotificationKind {
|
||||||
|
/// String value of the enum field names used in the ProtoBuf definition.
|
||||||
|
///
|
||||||
|
/// The values are not transformed in any way and thus are considered stable
|
||||||
|
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
|
||||||
|
pub fn as_str_name(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Unspecified => "NOTIFICATION_KIND_UNSPECIFIED",
|
||||||
|
Self::TorrentAdded => "TORRENT_ADDED",
|
||||||
|
Self::TorrentRemoved => "TORRENT_REMOVED",
|
||||||
|
Self::StateChanged => "STATE_CHANGED",
|
||||||
|
Self::Progress => "PROGRESS",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||||
|
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
|
||||||
|
match value {
|
||||||
|
"NOTIFICATION_KIND_UNSPECIFIED" => Some(Self::Unspecified),
|
||||||
|
"TORRENT_ADDED" => Some(Self::TorrentAdded),
|
||||||
|
"TORRENT_REMOVED" => Some(Self::TorrentRemoved),
|
||||||
|
"STATE_CHANGED" => Some(Self::StateChanged),
|
||||||
|
"PROGRESS" => Some(Self::Progress),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||||
|
#[repr(i32)]
|
||||||
pub enum State {
|
pub enum State {
|
||||||
Unspecified = 0,
|
Unspecified = 0,
|
||||||
Pending = 1,
|
Pending = 1,
|
||||||
@@ -210,6 +381,12 @@ pub enum State {
|
|||||||
Paused = 3,
|
Paused = 3,
|
||||||
Finished = 4,
|
Finished = 4,
|
||||||
Error = 5,
|
Error = 5,
|
||||||
|
/// Live per librqbit, but the daemon has detected a stall: no byte progress
|
||||||
|
/// for several ticks AND zero connected peers. The torrent is still
|
||||||
|
/// considered live by the underlying engine; this state is an application-
|
||||||
|
/// level overlay. Recovers to DOWNLOADING automatically when bytes advance
|
||||||
|
/// or a peer connects.
|
||||||
|
Stale = 6,
|
||||||
}
|
}
|
||||||
impl State {
|
impl State {
|
||||||
/// String value of the enum field names used in the ProtoBuf definition.
|
/// String value of the enum field names used in the ProtoBuf definition.
|
||||||
@@ -224,6 +401,7 @@ impl State {
|
|||||||
Self::Paused => "PAUSED",
|
Self::Paused => "PAUSED",
|
||||||
Self::Finished => "FINISHED",
|
Self::Finished => "FINISHED",
|
||||||
Self::Error => "ERROR",
|
Self::Error => "ERROR",
|
||||||
|
Self::Stale => "STALE",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Creates an enum from field names used in the ProtoBuf definition.
|
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||||
@@ -235,13 +413,14 @@ impl State {
|
|||||||
"PAUSED" => Some(Self::Paused),
|
"PAUSED" => Some(Self::Paused),
|
||||||
"FINISHED" => Some(Self::Finished),
|
"FINISHED" => Some(Self::Finished),
|
||||||
"ERROR" => Some(Self::Error),
|
"ERROR" => Some(Self::Error),
|
||||||
|
"STALE" => Some(Self::Stale),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Encoded file descriptor set for the `torrent` package
|
/// Encoded file descriptor set for the `torrent` package
|
||||||
pub const FILE_DESCRIPTOR_SET: &[u8] = &[
|
pub const FILE_DESCRIPTOR_SET: &[u8] = &[
|
||||||
0x0a, 0x90, 0x1f, 0x0a, 0x0d, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f,
|
0x0a, 0xe0, 0x3e, 0x0a, 0x0d, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f,
|
||||||
0x74, 0x6f, 0x12, 0x07, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x22, 0x43, 0x0a, 0x0a, 0x41,
|
0x74, 0x6f, 0x12, 0x07, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x22, 0x43, 0x0a, 0x0a, 0x41,
|
||||||
0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x67,
|
0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x67,
|
||||||
0x6e, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x61, 0x67, 0x6e, 0x65,
|
0x6e, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x61, 0x67, 0x6e, 0x65,
|
||||||
@@ -267,229 +446,482 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[
|
|||||||
0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x0a, 0x0d, 0x52, 0x65,
|
0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x0a, 0x0d, 0x52, 0x65,
|
||||||
0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
||||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x10, 0x0a, 0x0e, 0x52,
|
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x10, 0x0a, 0x0e, 0x52,
|
||||||
0x65, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xec, 0x03,
|
0x65, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x59, 0x0a,
|
||||||
0x0a, 0x0d, 0x54, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12,
|
0x14, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65,
|
||||||
0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12,
|
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03,
|
||||||
0x1b, 0x0a, 0x09, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01,
|
0x28, 0x09, 0x52, 0x03, 0x69, 0x64, 0x73, 0x12, 0x2f, 0x0a, 0x05, 0x6b, 0x69, 0x6e, 0x64, 0x73,
|
||||||
0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x66, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04,
|
0x18, 0x02, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74,
|
||||||
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
|
0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x69, 0x6e,
|
||||||
0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
|
0x64, 0x52, 0x05, 0x6b, 0x69, 0x6e, 0x64, 0x73, 0x22, 0x81, 0x03, 0x0a, 0x0c, 0x4e, 0x6f, 0x74,
|
||||||
0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x75, 0x74, 0x70,
|
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x0a, 0x17, 0x6f, 0x62, 0x73,
|
||||||
0x75, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f,
|
0x65, 0x72, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x6d, 0x69,
|
||||||
0x75, 0x74, 0x70, 0x75, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74,
|
0x6c, 0x6c, 0x69, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x14, 0x6f, 0x62, 0x73, 0x65,
|
||||||
0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a,
|
0x72, 0x76, 0x65, 0x64, 0x41, 0x74, 0x55, 0x6e, 0x69, 0x78, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73,
|
||||||
0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x6f,
|
0x12, 0x2d, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19,
|
||||||
0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x07,
|
0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63,
|
||||||
0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64,
|
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12,
|
||||||
0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x08,
|
0x30, 0x0a, 0x07, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
|
||||||
0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x53,
|
0x32, 0x16, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x6f, 0x72, 0x72, 0x65,
|
||||||
0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x65,
|
0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x07, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e,
|
||||||
0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x09, 0x20, 0x01,
|
0x74, 0x12, 0x3c, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67,
|
||||||
0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65,
|
||||||
0x12, 0x2c, 0x0a, 0x12, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x73, 0x70, 0x65,
|
0x6e, 0x74, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x48,
|
||||||
0x65, 0x64, 0x5f, 0x62, 0x70, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x64, 0x6f,
|
0x00, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12,
|
||||||
0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x70, 0x65, 0x65, 0x64, 0x42, 0x70, 0x73, 0x12, 0x1f,
|
0x33, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28,
|
||||||
0x0a, 0x0b, 0x65, 0x74, 0x61, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x0b, 0x20,
|
0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x67,
|
||||||
0x01, 0x28, 0x04, 0x52, 0x0a, 0x65, 0x74, 0x61, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12,
|
0x72, 0x65, 0x73, 0x73, 0x4d, 0x61, 0x72, 0x6b, 0x48, 0x00, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67,
|
||||||
0x25, 0x0a, 0x0e, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65,
|
0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x0c, 0x20,
|
||||||
0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65,
|
0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x64,
|
||||||
0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64,
|
0x64, 0x65, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64,
|
||||||
0x5f, 0x73, 0x70, 0x65, 0x65, 0x64, 0x5f, 0x62, 0x70, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04,
|
0x12, 0x30, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28,
|
||||||
0x52, 0x0e, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x70, 0x65, 0x65, 0x64, 0x42, 0x70, 0x73,
|
0x0b, 0x32, 0x14, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x6d, 0x6f,
|
||||||
0x12, 0x14, 0x0a, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52,
|
0x76, 0x65, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76,
|
||||||
0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x65, 0x65, 0x64, 0x73, 0x18,
|
0x65, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x22, 0x64, 0x0a, 0x0c,
|
||||||
0x0f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x73, 0x65, 0x65, 0x64, 0x73, 0x2a, 0x61, 0x0a, 0x05,
|
0x53, 0x74, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x2a, 0x0a, 0x08,
|
||||||
0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55,
|
0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e,
|
||||||
0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07,
|
0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x08,
|
||||||
0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x4f, 0x57,
|
0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x12, 0x28, 0x0a, 0x07, 0x63, 0x75, 0x72, 0x72,
|
||||||
0x4e, 0x4c, 0x4f, 0x41, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x41,
|
0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x74, 0x6f, 0x72, 0x72,
|
||||||
0x55, 0x53, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x48,
|
0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x07, 0x63, 0x75, 0x72, 0x72, 0x65,
|
||||||
0x45, 0x44, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x05, 0x32,
|
0x6e, 0x74, 0x22, 0x49, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x61,
|
||||||
0xd9, 0x02, 0x0a, 0x08, 0x54, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x30, 0x0a, 0x03,
|
0x72, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20,
|
||||||
0x41, 0x64, 0x64, 0x12, 0x13, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x64,
|
0x01, 0x28, 0x0d, 0x52, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b,
|
||||||
0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65,
|
0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||||
0x6e, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38,
|
0x04, 0x52, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x22, 0x23, 0x0a,
|
||||||
0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65,
|
0x09, 0x41, 0x64, 0x64, 0x65, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f,
|
||||||
0x6e, 0x74, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72,
|
||||||
0x1a, 0x16, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x6f, 0x72, 0x72, 0x65,
|
0x63, 0x65, 0x22, 0x32, 0x0a, 0x0b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x49, 0x6e, 0x66,
|
||||||
0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x33, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74,
|
0x6f, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74,
|
||||||
0x12, 0x14, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52,
|
0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x44,
|
||||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74,
|
0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x22, 0xec, 0x03, 0x0a, 0x0d, 0x54, 0x6f, 0x72, 0x72, 0x65,
|
||||||
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a,
|
0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
|
||||||
0x06, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x16, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x6e, 0x66, 0x6f,
|
||||||
0x74, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x66,
|
||||||
0x17, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
|
0x6f, 0x48, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20,
|
||||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x50, 0x61, 0x75, 0x73,
|
0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75,
|
||||||
0x65, 0x12, 0x15, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x75, 0x73,
|
0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
||||||
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65,
|
0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68,
|
||||||
0x6e, 0x74, 0x2e, 0x50, 0x61, 0x75, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x50, 0x61,
|
||||||
0x12, 0x39, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x12, 0x16, 0x2e, 0x74, 0x6f, 0x72,
|
0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65,
|
||||||
0x72, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
|
0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79,
|
||||||
0x73, 0x74, 0x1a, 0x17, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x73,
|
0x74, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x65,
|
||||||
0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4a, 0xad, 0x14, 0x0a, 0x06,
|
0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x64,
|
||||||
0x12, 0x04, 0x00, 0x00, 0x53, 0x01, 0x0a, 0x08, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x00, 0x00, 0x12,
|
0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x24,
|
||||||
0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x02, 0x00, 0x10, 0x0a, 0x0a, 0x0a, 0x02, 0x06, 0x00,
|
0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e,
|
||||||
0x12, 0x04, 0x04, 0x00, 0x11, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x06, 0x00, 0x01, 0x12, 0x03, 0x04,
|
0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73,
|
||||||
0x08, 0x10, 0x0a, 0x5a, 0x0a, 0x04, 0x06, 0x00, 0x02, 0x00, 0x12, 0x03, 0x06, 0x02, 0x2c, 0x1a,
|
0x74, 0x61, 0x74, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65,
|
||||||
0x4d, 0x20, 0x41, 0x64, 0x64, 0x20, 0x61, 0x20, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20,
|
0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72,
|
||||||
0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x65, 0x74, 0x20, 0x6c, 0x69,
|
0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x64, 0x6f, 0x77,
|
||||||
0x6e, 0x6b, 0x20, 0x6f, 0x72, 0x20, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x66,
|
0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x73, 0x70, 0x65, 0x65, 0x64, 0x5f, 0x62, 0x70, 0x73, 0x18,
|
||||||
0x69, 0x6c, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x64, 0x6f,
|
0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x53,
|
||||||
0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x74, 0x2e, 0x0a, 0x0a, 0x0c,
|
0x70, 0x65, 0x65, 0x64, 0x42, 0x70, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x74, 0x61, 0x5f, 0x73,
|
||||||
0x0a, 0x05, 0x06, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x06, 0x06, 0x09, 0x0a, 0x0c, 0x0a, 0x05,
|
0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x65, 0x74,
|
||||||
0x06, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x06, 0x0a, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00,
|
0x61, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x75, 0x70, 0x6c, 0x6f,
|
||||||
0x02, 0x00, 0x03, 0x12, 0x03, 0x06, 0x1f, 0x2a, 0x0a, 0x3a, 0x0a, 0x04, 0x06, 0x00, 0x02, 0x01,
|
0x61, 0x64, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04,
|
||||||
0x12, 0x03, 0x08, 0x02, 0x34, 0x1a, 0x2d, 0x20, 0x47, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20,
|
0x52, 0x0d, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12,
|
||||||
0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x6f,
|
0x28, 0x0a, 0x10, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x73, 0x70, 0x65, 0x65, 0x64, 0x5f,
|
||||||
0x66, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x72, 0x72, 0x65,
|
0x62, 0x70, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x75, 0x70, 0x6c, 0x6f, 0x61,
|
||||||
0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x08,
|
0x64, 0x53, 0x70, 0x65, 0x65, 0x64, 0x42, 0x70, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x65, 0x65,
|
||||||
0x06, 0x0c, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x08, 0x0d, 0x1a,
|
0x72, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x12,
|
||||||
0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x08, 0x25, 0x32, 0x0a, 0x35,
|
0x14, 0x0a, 0x05, 0x73, 0x65, 0x65, 0x64, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05,
|
||||||
0x0a, 0x04, 0x06, 0x00, 0x02, 0x02, 0x12, 0x03, 0x0a, 0x02, 0x2f, 0x1a, 0x28, 0x20, 0x4c, 0x69,
|
0x73, 0x65, 0x65, 0x64, 0x73, 0x2a, 0x7e, 0x0a, 0x10, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63,
|
||||||
0x73, 0x74, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x20,
|
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x21, 0x0a, 0x1d, 0x4e, 0x4f, 0x54,
|
||||||
0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x61, 0x65,
|
0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x55,
|
||||||
0x6d, 0x6f, 0x6e, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03,
|
0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d,
|
||||||
0x0a, 0x06, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x0a, 0x0b,
|
0x54, 0x4f, 0x52, 0x52, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x44, 0x44, 0x45, 0x44, 0x10, 0x01, 0x12,
|
||||||
0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x0a, 0x21, 0x2d, 0x0a,
|
0x13, 0x0a, 0x0f, 0x54, 0x4f, 0x52, 0x52, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x56,
|
||||||
0x2e, 0x0a, 0x04, 0x06, 0x00, 0x02, 0x03, 0x12, 0x03, 0x0c, 0x02, 0x35, 0x1a, 0x21, 0x20, 0x52,
|
0x45, 0x44, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x43, 0x48,
|
||||||
0x65, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x61, 0x20, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20,
|
0x41, 0x4e, 0x47, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x52, 0x4f, 0x47, 0x52,
|
||||||
0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x0a, 0x0a,
|
0x45, 0x53, 0x53, 0x10, 0x04, 0x2a, 0x6c, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x15,
|
||||||
0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x0c, 0x06, 0x0c, 0x0a, 0x0c, 0x0a,
|
0x0a, 0x11, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46,
|
||||||
0x05, 0x06, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x0c, 0x0d, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x06,
|
0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47,
|
||||||
0x00, 0x02, 0x03, 0x03, 0x12, 0x03, 0x0c, 0x25, 0x33, 0x0a, 0x2b, 0x0a, 0x04, 0x06, 0x00, 0x02,
|
0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f, 0x41, 0x44, 0x49, 0x4e,
|
||||||
0x04, 0x12, 0x03, 0x0e, 0x02, 0x32, 0x1a, 0x1e, 0x20, 0x50, 0x61, 0x75, 0x73, 0x65, 0x20, 0x61,
|
0x47, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x41, 0x55, 0x53, 0x45, 0x44, 0x10, 0x03, 0x12,
|
||||||
0x20, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x72,
|
0x0c, 0x0a, 0x08, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x04, 0x12, 0x09, 0x0a,
|
||||||
0x72, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x04, 0x01, 0x12,
|
0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x54, 0x41, 0x4c,
|
||||||
0x03, 0x0e, 0x06, 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x04, 0x02, 0x12, 0x03, 0x0e,
|
0x45, 0x10, 0x06, 0x32, 0xa2, 0x03, 0x0a, 0x08, 0x54, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x73,
|
||||||
0x0c, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x04, 0x03, 0x12, 0x03, 0x0e, 0x23, 0x30,
|
0x12, 0x30, 0x0a, 0x03, 0x41, 0x64, 0x64, 0x12, 0x13, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e,
|
||||||
0x0a, 0x27, 0x0a, 0x04, 0x06, 0x00, 0x02, 0x05, 0x12, 0x03, 0x10, 0x02, 0x35, 0x1a, 0x1a, 0x20,
|
0x74, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x74,
|
||||||
0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x20, 0x61, 0x20, 0x70, 0x61, 0x75, 0x73, 0x65, 0x64, 0x20,
|
0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||||
0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02,
|
0x73, 0x65, 0x12, 0x38, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x2e, 0x74,
|
||||||
0x05, 0x01, 0x12, 0x03, 0x10, 0x06, 0x0c, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x05, 0x02,
|
0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71,
|
||||||
0x12, 0x03, 0x10, 0x0d, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x05, 0x03, 0x12, 0x03,
|
0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x54,
|
||||||
0x10, 0x25, 0x33, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x13, 0x00, 0x17, 0x01, 0x0a,
|
0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x33, 0x0a, 0x04,
|
||||||
0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x13, 0x08, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04,
|
0x4c, 0x69, 0x73, 0x74, 0x12, 0x14, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x4c,
|
||||||
0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x14, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02,
|
0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x74, 0x6f, 0x72,
|
||||||
0x00, 0x12, 0x03, 0x14, 0x02, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12,
|
0x72, 0x65, 0x6e, 0x74, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||||
0x03, 0x14, 0x09, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x14,
|
0x65, 0x12, 0x39, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x16, 0x2e, 0x74, 0x6f,
|
||||||
0x12, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, 0x16, 0x02, 0x08,
|
0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75,
|
||||||
0x0a, 0x53, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x16, 0x02, 0x18, 0x1a, 0x46, 0x20,
|
0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65,
|
||||||
0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20,
|
0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x05,
|
||||||
0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69,
|
0x50, 0x61, 0x75, 0x73, 0x65, 0x12, 0x15, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e,
|
||||||
0x64, 0x65, 0x2e, 0x20, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x20, 0x6d, 0x65, 0x61, 0x6e, 0x73, 0x20,
|
0x50, 0x61, 0x75, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x74,
|
||||||
0x75, 0x73, 0x65, 0x20, 0x74, 0x6f, 0x72, 0x61, 0x64, 0x27, 0x73, 0x20, 0x64, 0x65, 0x66, 0x61,
|
0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x75, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70,
|
||||||
0x75, 0x6c, 0x74, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03,
|
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x12, 0x16,
|
||||||
0x16, 0x09, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x16, 0x16,
|
0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x52,
|
||||||
0x17, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x01, 0x12, 0x04, 0x19, 0x00, 0x1b, 0x01, 0x0a, 0x0a, 0x0a,
|
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74,
|
||||||
0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x19, 0x08, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02,
|
0x2e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||||
0x00, 0x05, 0x12, 0x03, 0x1a, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12,
|
0x47, 0x0a, 0x0d, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
|
||||||
0x03, 0x1a, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1a,
|
0x12, 0x1d, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66,
|
||||||
0x09, 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x1a, 0x0e, 0x0f,
|
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||||
0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, 0x1d, 0x00, 0x1f, 0x01, 0x0a, 0x0a, 0x0a, 0x03,
|
0x15, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69,
|
||||||
0x04, 0x02, 0x01, 0x12, 0x03, 0x1d, 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00,
|
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x01, 0x4a, 0xc0, 0x2c, 0x0a, 0x07, 0x12, 0x05, 0x00,
|
||||||
0x05, 0x12, 0x03, 0x1e, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x00, 0x12, 0x03,
|
0x00, 0x9c, 0x01, 0x01, 0x0a, 0x08, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x00, 0x00, 0x12, 0x0a, 0x08,
|
||||||
0x1e, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1e, 0x09,
|
0x0a, 0x01, 0x02, 0x12, 0x03, 0x02, 0x00, 0x10, 0x0a, 0x0a, 0x0a, 0x02, 0x06, 0x00, 0x12, 0x04,
|
||||||
0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x1e, 0x0e, 0x0f, 0x0a,
|
0x04, 0x00, 0x15, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x06, 0x00, 0x01, 0x12, 0x03, 0x04, 0x08, 0x10,
|
||||||
0x09, 0x0a, 0x02, 0x04, 0x03, 0x12, 0x03, 0x21, 0x00, 0x16, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x03,
|
0x0a, 0x5a, 0x0a, 0x04, 0x06, 0x00, 0x02, 0x00, 0x12, 0x03, 0x06, 0x02, 0x2c, 0x1a, 0x4d, 0x20,
|
||||||
0x01, 0x12, 0x03, 0x21, 0x08, 0x13, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x04, 0x12, 0x04, 0x23, 0x00,
|
0x41, 0x64, 0x64, 0x20, 0x61, 0x20, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x72,
|
||||||
0x25, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x04, 0x01, 0x12, 0x03, 0x23, 0x08, 0x14, 0x0a, 0x0c,
|
0x6f, 0x6d, 0x20, 0x61, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x65, 0x74, 0x20, 0x6c, 0x69, 0x6e, 0x6b,
|
||||||
0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x04, 0x12, 0x03, 0x24, 0x02, 0x0a, 0x0a, 0x0b, 0x0a, 0x04,
|
0x20, 0x6f, 0x72, 0x20, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x69, 0x6c,
|
||||||
0x04, 0x04, 0x02, 0x00, 0x12, 0x03, 0x24, 0x02, 0x26, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02,
|
0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x64, 0x6f, 0x77, 0x6e,
|
||||||
0x00, 0x06, 0x12, 0x03, 0x24, 0x0b, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x01,
|
0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x74, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05,
|
||||||
0x12, 0x03, 0x24, 0x19, 0x21, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x03, 0x12, 0x03,
|
0x06, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x06, 0x06, 0x09, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00,
|
||||||
0x24, 0x24, 0x25, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x05, 0x12, 0x04, 0x27, 0x00, 0x2a, 0x01, 0x0a,
|
0x02, 0x00, 0x02, 0x12, 0x03, 0x06, 0x0a, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x00,
|
||||||
0x0a, 0x0a, 0x03, 0x04, 0x05, 0x01, 0x12, 0x03, 0x27, 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04,
|
0x03, 0x12, 0x03, 0x06, 0x1f, 0x2a, 0x0a, 0x3a, 0x0a, 0x04, 0x06, 0x00, 0x02, 0x01, 0x12, 0x03,
|
||||||
0x05, 0x02, 0x00, 0x05, 0x12, 0x03, 0x28, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02,
|
0x08, 0x02, 0x34, 0x1a, 0x2d, 0x20, 0x47, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75,
|
||||||
0x00, 0x12, 0x03, 0x28, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x00, 0x01, 0x12,
|
0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x6f, 0x66, 0x20,
|
||||||
0x03, 0x28, 0x09, 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x00, 0x03, 0x12, 0x03, 0x28,
|
0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74,
|
||||||
0x0e, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x01, 0x05, 0x12, 0x03, 0x29, 0x02, 0x06,
|
0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x08, 0x06, 0x0c,
|
||||||
0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x01, 0x12, 0x03, 0x29, 0x02, 0x18, 0x0a, 0x0c, 0x0a,
|
0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x08, 0x0d, 0x1a, 0x0a, 0x0c,
|
||||||
0x05, 0x04, 0x05, 0x02, 0x01, 0x01, 0x12, 0x03, 0x29, 0x07, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04,
|
0x0a, 0x05, 0x06, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x08, 0x25, 0x32, 0x0a, 0x35, 0x0a, 0x04,
|
||||||
0x05, 0x02, 0x01, 0x03, 0x12, 0x03, 0x29, 0x16, 0x17, 0x0a, 0x09, 0x0a, 0x02, 0x04, 0x06, 0x12,
|
0x06, 0x00, 0x02, 0x02, 0x12, 0x03, 0x0a, 0x02, 0x2f, 0x1a, 0x28, 0x20, 0x4c, 0x69, 0x73, 0x74,
|
||||||
0x03, 0x2c, 0x00, 0x19, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x06, 0x01, 0x12, 0x03, 0x2c, 0x08, 0x16,
|
0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6b, 0x6e,
|
||||||
0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x07, 0x12, 0x04, 0x2e, 0x00, 0x30, 0x01, 0x0a, 0x0a, 0x0a, 0x03,
|
0x6f, 0x77, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x61, 0x65, 0x6d, 0x6f,
|
||||||
0x04, 0x07, 0x01, 0x12, 0x03, 0x2e, 0x08, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x07, 0x02, 0x00,
|
0x6e, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x0a, 0x06,
|
||||||
0x05, 0x12, 0x03, 0x2f, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x07, 0x02, 0x00, 0x12, 0x03,
|
0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x0a, 0x0b, 0x16, 0x0a,
|
||||||
0x2f, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x07, 0x02, 0x00, 0x01, 0x12, 0x03, 0x2f, 0x09,
|
0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x0a, 0x21, 0x2d, 0x0a, 0x2e, 0x0a,
|
||||||
0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x07, 0x02, 0x00, 0x03, 0x12, 0x03, 0x2f, 0x0e, 0x0f, 0x0a,
|
0x04, 0x06, 0x00, 0x02, 0x03, 0x12, 0x03, 0x0c, 0x02, 0x35, 0x1a, 0x21, 0x20, 0x52, 0x65, 0x6d,
|
||||||
0x09, 0x0a, 0x02, 0x04, 0x08, 0x12, 0x03, 0x32, 0x00, 0x18, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x08,
|
0x6f, 0x76, 0x65, 0x20, 0x61, 0x20, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x72,
|
||||||
0x01, 0x12, 0x03, 0x32, 0x08, 0x15, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x09, 0x12, 0x04, 0x34, 0x00,
|
0x6f, 0x6d, 0x20, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a,
|
||||||
0x36, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x09, 0x01, 0x12, 0x03, 0x34, 0x08, 0x15, 0x0a, 0x0c,
|
0x05, 0x06, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x0c, 0x06, 0x0c, 0x0a, 0x0c, 0x0a, 0x05, 0x06,
|
||||||
0x0a, 0x05, 0x04, 0x09, 0x02, 0x00, 0x05, 0x12, 0x03, 0x35, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04,
|
0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x0c, 0x0d, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02,
|
||||||
0x04, 0x09, 0x02, 0x00, 0x12, 0x03, 0x35, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x09, 0x02,
|
0x03, 0x03, 0x12, 0x03, 0x0c, 0x25, 0x33, 0x0a, 0x2b, 0x0a, 0x04, 0x06, 0x00, 0x02, 0x04, 0x12,
|
||||||
0x00, 0x01, 0x12, 0x03, 0x35, 0x09, 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x09, 0x02, 0x00, 0x03,
|
0x03, 0x0e, 0x02, 0x32, 0x1a, 0x1e, 0x20, 0x50, 0x61, 0x75, 0x73, 0x65, 0x20, 0x61, 0x20, 0x64,
|
||||||
0x12, 0x03, 0x35, 0x0e, 0x0f, 0x0a, 0x09, 0x0a, 0x02, 0x04, 0x0a, 0x12, 0x03, 0x38, 0x00, 0x19,
|
0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x72, 0x72, 0x65,
|
||||||
0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x0a, 0x01, 0x12, 0x03, 0x38, 0x08, 0x16, 0x0a, 0x0a, 0x0a, 0x02,
|
0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x04, 0x01, 0x12, 0x03, 0x0e,
|
||||||
0x05, 0x00, 0x12, 0x04, 0x3a, 0x00, 0x41, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x00, 0x01, 0x12,
|
0x06, 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x04, 0x02, 0x12, 0x03, 0x0e, 0x0c, 0x18,
|
||||||
0x03, 0x3a, 0x05, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x3b,
|
0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x04, 0x03, 0x12, 0x03, 0x0e, 0x23, 0x30, 0x0a, 0x27,
|
||||||
0x02, 0x13, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x00, 0x12, 0x03, 0x3b, 0x02, 0x18, 0x0a,
|
0x0a, 0x04, 0x06, 0x00, 0x02, 0x05, 0x12, 0x03, 0x10, 0x02, 0x35, 0x1a, 0x1a, 0x20, 0x52, 0x65,
|
||||||
0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x3b, 0x16, 0x17, 0x0a, 0x0c, 0x0a,
|
0x73, 0x75, 0x6d, 0x65, 0x20, 0x61, 0x20, 0x70, 0x61, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f,
|
||||||
0x05, 0x05, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x3c, 0x02, 0x09, 0x0a, 0x0b, 0x0a, 0x04, 0x05,
|
0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x05, 0x01,
|
||||||
0x00, 0x02, 0x01, 0x12, 0x03, 0x3c, 0x02, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x01,
|
0x12, 0x03, 0x10, 0x06, 0x0c, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x05, 0x02, 0x12, 0x03,
|
||||||
0x02, 0x12, 0x03, 0x3c, 0x0c, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, 0x01, 0x12,
|
0x10, 0x0d, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x05, 0x03, 0x12, 0x03, 0x10, 0x25,
|
||||||
0x03, 0x3d, 0x02, 0x0d, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x02, 0x12, 0x03, 0x3d, 0x02,
|
0x33, 0x0a, 0xd5, 0x01, 0x0a, 0x04, 0x06, 0x00, 0x02, 0x06, 0x12, 0x03, 0x14, 0x02, 0x48, 0x1a,
|
||||||
0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x3d, 0x10, 0x11, 0x0a,
|
0xc7, 0x01, 0x20, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x20, 0x74, 0x6f, 0x20,
|
||||||
0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x3e, 0x02, 0x08, 0x0a, 0x0b, 0x0a,
|
0x61, 0x20, 0x6c, 0x69, 0x76, 0x65, 0x20, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x20, 0x6f, 0x66,
|
||||||
0x04, 0x05, 0x00, 0x02, 0x03, 0x12, 0x03, 0x3e, 0x02, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00,
|
0x20, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63,
|
||||||
0x02, 0x03, 0x02, 0x12, 0x03, 0x3e, 0x0b, 0x0c, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x04,
|
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x20, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61,
|
||||||
0x01, 0x12, 0x03, 0x3f, 0x02, 0x0a, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x04, 0x12, 0x03,
|
0x72, 0x65, 0x20, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x65, 0x64, 0x0a, 0x20, 0x66, 0x72,
|
||||||
0x3f, 0x02, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x04, 0x02, 0x12, 0x03, 0x3f, 0x0d,
|
0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
|
||||||
0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x05, 0x01, 0x12, 0x03, 0x40, 0x02, 0x07, 0x0a,
|
0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x20, 0x6f, 0x6e, 0x77, 0x61, 0x72, 0x64, 0x20, 0xe2, 0x80,
|
||||||
0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x05, 0x12, 0x03, 0x40, 0x02, 0x0c, 0x0a, 0x0c, 0x0a, 0x05,
|
0x94, 0x20, 0x6e, 0x6f, 0x20, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x69, 0x73, 0x20,
|
||||||
0x05, 0x00, 0x02, 0x05, 0x02, 0x12, 0x03, 0x40, 0x0a, 0x0b, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x0b,
|
0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x64, 0x2e, 0x20, 0x4e, 0x65, 0x77, 0x20, 0x73, 0x75,
|
||||||
0x12, 0x04, 0x43, 0x00, 0x53, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x0b, 0x01, 0x12, 0x03, 0x43,
|
0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x73, 0x0a, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20,
|
||||||
0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x00, 0x05, 0x12, 0x03, 0x44, 0x02, 0x08,
|
0x73, 0x65, 0x65, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20,
|
||||||
0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x00, 0x12, 0x03, 0x44, 0x02, 0x10, 0x0a, 0x0c, 0x0a,
|
0x66, 0x69, 0x72, 0x65, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20,
|
||||||
0x05, 0x04, 0x0b, 0x02, 0x00, 0x01, 0x12, 0x03, 0x44, 0x09, 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x04,
|
0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02,
|
||||||
0x0b, 0x02, 0x00, 0x03, 0x12, 0x03, 0x44, 0x0e, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02,
|
0x06, 0x01, 0x12, 0x03, 0x14, 0x06, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x06, 0x02,
|
||||||
0x01, 0x05, 0x12, 0x03, 0x45, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x01, 0x12,
|
0x12, 0x03, 0x14, 0x14, 0x28, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x06, 0x06, 0x12, 0x03,
|
||||||
0x03, 0x45, 0x02, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x01, 0x01, 0x12, 0x03, 0x45,
|
0x14, 0x33, 0x39, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x06, 0x03, 0x12, 0x03, 0x14, 0x3a,
|
||||||
0x09, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x01, 0x03, 0x12, 0x03, 0x45, 0x15, 0x16,
|
0x46, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x17, 0x00, 0x1b, 0x01, 0x0a, 0x0a, 0x0a,
|
||||||
0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x02, 0x05, 0x12, 0x03, 0x46, 0x02, 0x08, 0x0a, 0x0b,
|
0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x17, 0x08, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02,
|
||||||
0x0a, 0x04, 0x04, 0x0b, 0x02, 0x02, 0x12, 0x03, 0x46, 0x02, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04,
|
0x00, 0x05, 0x12, 0x03, 0x18, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12,
|
||||||
0x0b, 0x02, 0x02, 0x01, 0x12, 0x03, 0x46, 0x09, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02,
|
0x03, 0x18, 0x02, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x18,
|
||||||
0x02, 0x03, 0x12, 0x03, 0x46, 0x10, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x03, 0x05,
|
0x09, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x18, 0x12, 0x13,
|
||||||
0x12, 0x03, 0x47, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x03, 0x12, 0x03, 0x47,
|
0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, 0x1a, 0x02, 0x08, 0x0a, 0x53,
|
||||||
0x02, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x03, 0x01, 0x12, 0x03, 0x47, 0x09, 0x0f,
|
0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x1a, 0x02, 0x18, 0x1a, 0x46, 0x20, 0x4f, 0x70,
|
||||||
0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x03, 0x03, 0x12, 0x03, 0x47, 0x12, 0x13, 0x0a, 0x0c,
|
0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x64, 0x69,
|
||||||
0x0a, 0x05, 0x04, 0x0b, 0x02, 0x04, 0x05, 0x12, 0x03, 0x48, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04,
|
0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65,
|
||||||
0x04, 0x0b, 0x02, 0x04, 0x12, 0x03, 0x48, 0x02, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02,
|
0x2e, 0x20, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x20, 0x6d, 0x65, 0x61, 0x6e, 0x73, 0x20, 0x75, 0x73,
|
||||||
0x04, 0x01, 0x12, 0x03, 0x48, 0x09, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x04, 0x03,
|
0x65, 0x20, 0x74, 0x6f, 0x72, 0x61, 0x64, 0x27, 0x73, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c,
|
||||||
0x12, 0x03, 0x48, 0x17, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x05, 0x05, 0x12, 0x03,
|
0x74, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x1a, 0x09,
|
||||||
0x49, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x05, 0x12, 0x03, 0x49, 0x02, 0x19,
|
0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x1a, 0x16, 0x17, 0x0a,
|
||||||
0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x05, 0x01, 0x12, 0x03, 0x49, 0x09, 0x14, 0x0a, 0x0c,
|
0x0a, 0x0a, 0x02, 0x04, 0x01, 0x12, 0x04, 0x1d, 0x00, 0x1f, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04,
|
||||||
0x0a, 0x05, 0x04, 0x0b, 0x02, 0x05, 0x03, 0x12, 0x03, 0x49, 0x17, 0x18, 0x0a, 0x0c, 0x0a, 0x05,
|
0x01, 0x01, 0x12, 0x03, 0x1d, 0x08, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x05,
|
||||||
0x04, 0x0b, 0x02, 0x06, 0x05, 0x12, 0x03, 0x4a, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b,
|
0x12, 0x03, 0x1e, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x1e,
|
||||||
0x02, 0x06, 0x12, 0x03, 0x4a, 0x02, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x06, 0x01,
|
0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1e, 0x09, 0x0b,
|
||||||
0x12, 0x03, 0x4a, 0x09, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x06, 0x03, 0x12, 0x03,
|
0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x1e, 0x0e, 0x0f, 0x0a, 0x0a,
|
||||||
0x4a, 0x1c, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x07, 0x06, 0x12, 0x03, 0x4b, 0x02,
|
0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, 0x21, 0x00, 0x23, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02,
|
||||||
0x07, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x07, 0x12, 0x03, 0x4b, 0x02, 0x12, 0x0a, 0x0c,
|
0x01, 0x12, 0x03, 0x21, 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x05, 0x12,
|
||||||
0x0a, 0x05, 0x04, 0x0b, 0x02, 0x07, 0x01, 0x12, 0x03, 0x4b, 0x08, 0x0d, 0x0a, 0x0c, 0x0a, 0x05,
|
0x03, 0x22, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x22, 0x02,
|
||||||
0x04, 0x0b, 0x02, 0x07, 0x03, 0x12, 0x03, 0x4b, 0x10, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b,
|
0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, 0x22, 0x09, 0x0b, 0x0a,
|
||||||
0x02, 0x08, 0x05, 0x12, 0x03, 0x4c, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x08,
|
0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x22, 0x0e, 0x0f, 0x0a, 0x09, 0x0a,
|
||||||
0x12, 0x03, 0x4c, 0x02, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x08, 0x01, 0x12, 0x03,
|
0x02, 0x04, 0x03, 0x12, 0x03, 0x25, 0x00, 0x16, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x03, 0x01, 0x12,
|
||||||
0x4c, 0x09, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x08, 0x03, 0x12, 0x03, 0x4c, 0x19,
|
0x03, 0x25, 0x08, 0x13, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x04, 0x12, 0x04, 0x27, 0x00, 0x29, 0x01,
|
||||||
0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x09, 0x05, 0x12, 0x03, 0x4d, 0x02, 0x08, 0x0a,
|
0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x04, 0x01, 0x12, 0x03, 0x27, 0x08, 0x14, 0x0a, 0x0c, 0x0a, 0x05,
|
||||||
0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x09, 0x12, 0x03, 0x4d, 0x02, 0x21, 0x0a, 0x0c, 0x0a, 0x05,
|
0x04, 0x04, 0x02, 0x00, 0x04, 0x12, 0x03, 0x28, 0x02, 0x0a, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x04,
|
||||||
0x04, 0x0b, 0x02, 0x09, 0x01, 0x12, 0x03, 0x4d, 0x09, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b,
|
0x02, 0x00, 0x12, 0x03, 0x28, 0x02, 0x26, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x06,
|
||||||
0x02, 0x09, 0x03, 0x12, 0x03, 0x4d, 0x1e, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0a,
|
0x12, 0x03, 0x28, 0x0b, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x01, 0x12, 0x03,
|
||||||
0x05, 0x12, 0x03, 0x4e, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x0a, 0x12, 0x03,
|
0x28, 0x19, 0x21, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x03, 0x12, 0x03, 0x28, 0x24,
|
||||||
0x4e, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0a, 0x01, 0x12, 0x03, 0x4e, 0x09,
|
0x25, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x05, 0x12, 0x04, 0x2b, 0x00, 0x2e, 0x01, 0x0a, 0x0a, 0x0a,
|
||||||
0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0a, 0x03, 0x12, 0x03, 0x4e, 0x17, 0x19, 0x0a,
|
0x03, 0x04, 0x05, 0x01, 0x12, 0x03, 0x2b, 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02,
|
||||||
0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0b, 0x05, 0x12, 0x03, 0x4f, 0x02, 0x08, 0x0a, 0x0b, 0x0a,
|
0x00, 0x05, 0x12, 0x03, 0x2c, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x00, 0x12,
|
||||||
0x04, 0x04, 0x0b, 0x02, 0x0b, 0x12, 0x03, 0x4f, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b,
|
0x03, 0x2c, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x00, 0x01, 0x12, 0x03, 0x2c,
|
||||||
0x02, 0x0b, 0x01, 0x12, 0x03, 0x4f, 0x09, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0b,
|
0x09, 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x00, 0x03, 0x12, 0x03, 0x2c, 0x0e, 0x0f,
|
||||||
0x03, 0x12, 0x03, 0x4f, 0x1a, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0c, 0x05, 0x12,
|
0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x01, 0x05, 0x12, 0x03, 0x2d, 0x02, 0x06, 0x0a, 0x0b,
|
||||||
0x03, 0x50, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x0c, 0x12, 0x03, 0x50, 0x02,
|
0x0a, 0x04, 0x04, 0x05, 0x02, 0x01, 0x12, 0x03, 0x2d, 0x02, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04,
|
||||||
0x1f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0c, 0x01, 0x12, 0x03, 0x50, 0x09, 0x19, 0x0a,
|
0x05, 0x02, 0x01, 0x01, 0x12, 0x03, 0x2d, 0x07, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02,
|
||||||
0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0c, 0x03, 0x12, 0x03, 0x50, 0x1c, 0x1e, 0x0a, 0x0c, 0x0a,
|
0x01, 0x03, 0x12, 0x03, 0x2d, 0x16, 0x17, 0x0a, 0x09, 0x0a, 0x02, 0x04, 0x06, 0x12, 0x03, 0x30,
|
||||||
0x05, 0x04, 0x0b, 0x02, 0x0d, 0x05, 0x12, 0x03, 0x51, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04,
|
0x00, 0x19, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x06, 0x01, 0x12, 0x03, 0x30, 0x08, 0x16, 0x0a, 0x0a,
|
||||||
0x0b, 0x02, 0x0d, 0x12, 0x03, 0x51, 0x02, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0d,
|
0x0a, 0x02, 0x04, 0x07, 0x12, 0x04, 0x32, 0x00, 0x34, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x07,
|
||||||
0x01, 0x12, 0x03, 0x51, 0x09, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0d, 0x03, 0x12,
|
0x01, 0x12, 0x03, 0x32, 0x08, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x07, 0x02, 0x00, 0x05, 0x12,
|
||||||
0x03, 0x51, 0x11, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0e, 0x05, 0x12, 0x03, 0x52,
|
0x03, 0x33, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x07, 0x02, 0x00, 0x12, 0x03, 0x33, 0x02,
|
||||||
0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x0e, 0x12, 0x03, 0x52, 0x02, 0x14, 0x0a,
|
0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x07, 0x02, 0x00, 0x01, 0x12, 0x03, 0x33, 0x09, 0x0b, 0x0a,
|
||||||
0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0e, 0x01, 0x12, 0x03, 0x52, 0x09, 0x0e, 0x0a, 0x0c, 0x0a,
|
0x0c, 0x0a, 0x05, 0x04, 0x07, 0x02, 0x00, 0x03, 0x12, 0x03, 0x33, 0x0e, 0x0f, 0x0a, 0x09, 0x0a,
|
||||||
0x05, 0x04, 0x0b, 0x02, 0x0e, 0x03, 0x12, 0x03, 0x52, 0x11, 0x13, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
0x02, 0x04, 0x08, 0x12, 0x03, 0x36, 0x00, 0x18, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x08, 0x01, 0x12,
|
||||||
|
0x03, 0x36, 0x08, 0x15, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x09, 0x12, 0x04, 0x38, 0x00, 0x3a, 0x01,
|
||||||
|
0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x09, 0x01, 0x12, 0x03, 0x38, 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05,
|
||||||
|
0x04, 0x09, 0x02, 0x00, 0x05, 0x12, 0x03, 0x39, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x09,
|
||||||
|
0x02, 0x00, 0x12, 0x03, 0x39, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x09, 0x02, 0x00, 0x01,
|
||||||
|
0x12, 0x03, 0x39, 0x09, 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x09, 0x02, 0x00, 0x03, 0x12, 0x03,
|
||||||
|
0x39, 0x0e, 0x0f, 0x0a, 0x09, 0x0a, 0x02, 0x04, 0x0a, 0x12, 0x03, 0x3c, 0x00, 0x19, 0x0a, 0x0a,
|
||||||
|
0x0a, 0x03, 0x04, 0x0a, 0x01, 0x12, 0x03, 0x3c, 0x08, 0x16, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x0b,
|
||||||
|
0x12, 0x04, 0x3e, 0x00, 0x45, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x0b, 0x01, 0x12, 0x03, 0x3e,
|
||||||
|
0x08, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x00, 0x04, 0x12, 0x03, 0x41, 0x02, 0x0a,
|
||||||
|
0x0a, 0x81, 0x01, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x00, 0x12, 0x03, 0x41, 0x02, 0x1a, 0x1a, 0x74,
|
||||||
|
0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x6e, 0x2d, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2c, 0x20, 0x6f,
|
||||||
|
0x6e, 0x6c, 0x79, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74,
|
||||||
|
0x68, 0x65, 0x73, 0x65, 0x20, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x64, 0x73,
|
||||||
|
0x20, 0x28, 0x6f, 0x72, 0x20, 0x69, 0x64, 0x20, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x65, 0x73,
|
||||||
|
0x2c, 0x20, 0x61, 0x73, 0x0a, 0x20, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x20, 0x62,
|
||||||
|
0x79, 0x20, 0x60, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x60, 0x2f, 0x60, 0x52, 0x65, 0x6d, 0x6f,
|
||||||
|
0x76, 0x65, 0x60, 0x29, 0x20, 0x61, 0x72, 0x65, 0x20, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72,
|
||||||
|
0x65, 0x64, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x00, 0x05, 0x12, 0x03, 0x41,
|
||||||
|
0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x00, 0x01, 0x12, 0x03, 0x41, 0x12, 0x15,
|
||||||
|
0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x00, 0x03, 0x12, 0x03, 0x41, 0x18, 0x19, 0x0a, 0x0c,
|
||||||
|
0x0a, 0x05, 0x04, 0x0b, 0x02, 0x01, 0x04, 0x12, 0x03, 0x44, 0x02, 0x0a, 0x0a, 0x62, 0x0a, 0x04,
|
||||||
|
0x04, 0x0b, 0x02, 0x01, 0x12, 0x03, 0x44, 0x02, 0x26, 0x1a, 0x55, 0x20, 0x49, 0x66, 0x20, 0x6e,
|
||||||
|
0x6f, 0x6e, 0x2d, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2c, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x74,
|
||||||
|
0x68, 0x65, 0x73, 0x65, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x6b, 0x69, 0x6e, 0x64, 0x73,
|
||||||
|
0x20, 0x61, 0x72, 0x65, 0x20, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x65, 0x64, 0x2e, 0x20,
|
||||||
|
0x41, 0x6e, 0x20, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6d, 0x65,
|
||||||
|
0x61, 0x6e, 0x73, 0x0a, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6b, 0x69, 0x6e, 0x64, 0x73, 0x2e, 0x0a,
|
||||||
|
0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x01, 0x06, 0x12, 0x03, 0x44, 0x0b, 0x1b, 0x0a, 0x0c,
|
||||||
|
0x0a, 0x05, 0x04, 0x0b, 0x02, 0x01, 0x01, 0x12, 0x03, 0x44, 0x1c, 0x21, 0x0a, 0x0c, 0x0a, 0x05,
|
||||||
|
0x04, 0x0b, 0x02, 0x01, 0x03, 0x12, 0x03, 0x44, 0x24, 0x25, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x0c,
|
||||||
|
0x12, 0x04, 0x47, 0x00, 0x57, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x0c, 0x01, 0x12, 0x03, 0x47,
|
||||||
|
0x08, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x00, 0x05, 0x12, 0x03, 0x4a, 0x02, 0x08,
|
||||||
|
0x0a, 0x65, 0x0a, 0x04, 0x04, 0x0c, 0x02, 0x00, 0x12, 0x03, 0x4a, 0x02, 0x25, 0x1a, 0x58, 0x20,
|
||||||
|
0x57, 0x61, 0x6c, 0x6c, 0x2d, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20,
|
||||||
|
0x74, 0x68, 0x65, 0x20, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x20, 0x6f, 0x62, 0x73, 0x65, 0x72,
|
||||||
|
0x76, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2c, 0x20,
|
||||||
|
0x69, 0x6e, 0x20, 0x6d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x20,
|
||||||
|
0x73, 0x69, 0x6e, 0x63, 0x65, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x55, 0x6e, 0x69, 0x78, 0x20,
|
||||||
|
0x65, 0x70, 0x6f, 0x63, 0x68, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x00, 0x01,
|
||||||
|
0x12, 0x03, 0x4a, 0x09, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x00, 0x03, 0x12, 0x03,
|
||||||
|
0x4a, 0x23, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x01, 0x06, 0x12, 0x03, 0x4d, 0x02,
|
||||||
|
0x12, 0x0a, 0x65, 0x0a, 0x04, 0x04, 0x0c, 0x02, 0x01, 0x12, 0x03, 0x4d, 0x02, 0x1c, 0x1a, 0x58,
|
||||||
|
0x20, 0x57, 0x68, 0x61, 0x74, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x2e, 0x20, 0x55,
|
||||||
|
0x73, 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x69, 0x73, 0x70, 0x61,
|
||||||
|
0x74, 0x63, 0x68, 0x3b, 0x20, 0x75, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x60, 0x6f, 0x6e,
|
||||||
|
0x65, 0x6f, 0x66, 0x20, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x60, 0x20, 0x66, 0x6f, 0x72, 0x0a,
|
||||||
|
0x20, 0x6b, 0x69, 0x6e, 0x64, 0x2d, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20, 0x70,
|
||||||
|
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x01,
|
||||||
|
0x01, 0x12, 0x03, 0x4d, 0x13, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x01, 0x03, 0x12,
|
||||||
|
0x03, 0x4d, 0x1a, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x02, 0x06, 0x12, 0x03, 0x50,
|
||||||
|
0x02, 0x0f, 0x0a, 0x8e, 0x01, 0x0a, 0x04, 0x04, 0x0c, 0x02, 0x02, 0x12, 0x03, 0x50, 0x02, 0x1c,
|
||||||
|
0x1a, 0x80, 0x01, 0x20, 0x46, 0x75, 0x6c, 0x6c, 0x20, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f,
|
||||||
|
0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74,
|
||||||
|
0x20, 0x2a, 0x61, 0x66, 0x74, 0x65, 0x72, 0x2a, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x68, 0x61,
|
||||||
|
0x6e, 0x67, 0x65, 0x2e, 0x20, 0x41, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x20, 0x70, 0x6f, 0x70, 0x75,
|
||||||
|
0x6c, 0x61, 0x74, 0x65, 0x64, 0x20, 0x73, 0x6f, 0x0a, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d,
|
||||||
|
0x65, 0x72, 0x73, 0x20, 0x64, 0x6f, 0x6e, 0x27, 0x74, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x20, 0x74,
|
||||||
|
0x6f, 0x20, 0x66, 0x61, 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x60, 0x53, 0x74,
|
||||||
|
0x61, 0x74, 0x75, 0x73, 0x60, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78,
|
||||||
|
0x74, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x02, 0x01, 0x12, 0x03, 0x50, 0x10,
|
||||||
|
0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x02, 0x03, 0x12, 0x03, 0x50, 0x1a, 0x1b, 0x0a,
|
||||||
|
0x0c, 0x0a, 0x04, 0x04, 0x0c, 0x08, 0x00, 0x12, 0x04, 0x51, 0x02, 0x56, 0x03, 0x0a, 0x0c, 0x0a,
|
||||||
|
0x05, 0x04, 0x0c, 0x08, 0x00, 0x01, 0x12, 0x03, 0x51, 0x08, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04,
|
||||||
|
0x0c, 0x02, 0x03, 0x06, 0x12, 0x03, 0x52, 0x04, 0x10, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0c, 0x02,
|
||||||
|
0x03, 0x12, 0x03, 0x52, 0x04, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x03, 0x01, 0x12,
|
||||||
|
0x03, 0x52, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x03, 0x03, 0x12, 0x03, 0x52,
|
||||||
|
0x21, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x04, 0x06, 0x12, 0x03, 0x53, 0x04, 0x10,
|
||||||
|
0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0c, 0x02, 0x04, 0x12, 0x03, 0x53, 0x04, 0x1f, 0x0a, 0x0c, 0x0a,
|
||||||
|
0x05, 0x04, 0x0c, 0x02, 0x04, 0x01, 0x12, 0x03, 0x53, 0x11, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04,
|
||||||
|
0x0c, 0x02, 0x04, 0x03, 0x12, 0x03, 0x53, 0x1c, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02,
|
||||||
|
0x05, 0x06, 0x12, 0x03, 0x54, 0x04, 0x0d, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0c, 0x02, 0x05, 0x12,
|
||||||
|
0x03, 0x54, 0x04, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x05, 0x01, 0x12, 0x03, 0x54,
|
||||||
|
0x0e, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x05, 0x03, 0x12, 0x03, 0x54, 0x16, 0x18,
|
||||||
|
0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x06, 0x06, 0x12, 0x03, 0x55, 0x04, 0x0f, 0x0a, 0x0b,
|
||||||
|
0x0a, 0x04, 0x04, 0x0c, 0x02, 0x06, 0x12, 0x03, 0x55, 0x04, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04,
|
||||||
|
0x0c, 0x02, 0x06, 0x01, 0x12, 0x03, 0x55, 0x10, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02,
|
||||||
|
0x06, 0x03, 0x12, 0x03, 0x55, 0x1a, 0x1c, 0x0a, 0x0a, 0x0a, 0x02, 0x05, 0x00, 0x12, 0x04, 0x59,
|
||||||
|
0x00, 0x65, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x00, 0x01, 0x12, 0x03, 0x59, 0x05, 0x15, 0x0a,
|
||||||
|
0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x5a, 0x02, 0x1f, 0x0a, 0x0b, 0x0a,
|
||||||
|
0x04, 0x05, 0x00, 0x02, 0x00, 0x12, 0x03, 0x5a, 0x02, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00,
|
||||||
|
0x02, 0x00, 0x02, 0x12, 0x03, 0x5a, 0x22, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x01,
|
||||||
|
0x01, 0x12, 0x03, 0x5c, 0x02, 0x0f, 0x0a, 0x3e, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x01, 0x12, 0x03,
|
||||||
|
0x5c, 0x02, 0x14, 0x1a, 0x31, 0x20, 0x45, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x20, 0x6f, 0x6e,
|
||||||
|
0x63, 0x65, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x61, 0x20, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e,
|
||||||
|
0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x76, 0x69, 0x61, 0x20, 0x60,
|
||||||
|
0x41, 0x64, 0x64, 0x60, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x01, 0x02, 0x12,
|
||||||
|
0x03, 0x5c, 0x12, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x5e,
|
||||||
|
0x02, 0x11, 0x0a, 0x43, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x02, 0x12, 0x03, 0x5e, 0x02, 0x16, 0x1a,
|
||||||
|
0x36, 0x20, 0x45, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x63, 0x65, 0x20, 0x77,
|
||||||
|
0x68, 0x65, 0x6e, 0x20, 0x61, 0x20, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x73,
|
||||||
|
0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x76, 0x69, 0x61, 0x20, 0x60, 0x52, 0x65,
|
||||||
|
0x6d, 0x6f, 0x76, 0x65, 0x60, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, 0x02,
|
||||||
|
0x12, 0x03, 0x5e, 0x14, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03,
|
||||||
|
0x61, 0x02, 0x0f, 0x0a, 0x86, 0x01, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x03, 0x12, 0x03, 0x61, 0x02,
|
||||||
|
0x14, 0x1a, 0x79, 0x20, 0x45, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x61,
|
||||||
|
0x6e, 0x79, 0x20, 0x60, 0x53, 0x74, 0x61, 0x74, 0x65, 0x60, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73,
|
||||||
|
0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67,
|
||||||
|
0x20, 0x50, 0x41, 0x55, 0x53, 0x45, 0x44, 0x20, 0x3c, 0x2d, 0x3e, 0x20, 0x44, 0x4f, 0x57, 0x4e,
|
||||||
|
0x4c, 0x4f, 0x41, 0x44, 0x49, 0x4e, 0x47, 0x2c, 0x0a, 0x20, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f,
|
||||||
|
0x41, 0x44, 0x49, 0x4e, 0x47, 0x20, 0x3c, 0x2d, 0x3e, 0x20, 0x53, 0x54, 0x41, 0x4c, 0x45, 0x2c,
|
||||||
|
0x20, 0x2a, 0x20, 0x2d, 0x3e, 0x20, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x48, 0x45, 0x44, 0x2c, 0x20,
|
||||||
|
0x2a, 0x20, 0x2d, 0x3e, 0x20, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05,
|
||||||
|
0x05, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x61, 0x12, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00,
|
||||||
|
0x02, 0x04, 0x01, 0x12, 0x03, 0x64, 0x02, 0x0a, 0x0a, 0x9d, 0x01, 0x0a, 0x04, 0x05, 0x00, 0x02,
|
||||||
|
0x04, 0x12, 0x03, 0x64, 0x02, 0x0f, 0x1a, 0x8f, 0x01, 0x20, 0x45, 0x6d, 0x69, 0x74, 0x74, 0x65,
|
||||||
|
0x64, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67,
|
||||||
|
0x65, 0x72, 0x20, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x70, 0x65, 0x72, 0x63,
|
||||||
|
0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x28,
|
||||||
|
0x72, 0x61, 0x74, 0x65, 0x2d, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x29, 0x2e, 0x0a, 0x20,
|
||||||
|
0x4e, 0x6f, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x73, 0x20, 0x73, 0x65, 0x6e, 0x74,
|
||||||
|
0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61,
|
||||||
|
0x67, 0x65, 0x20, 0x64, 0x69, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x61, 0x64, 0x76, 0x61, 0x6e,
|
||||||
|
0x63, 0x65, 0x20, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x73,
|
||||||
|
0x74, 0x20, 0x74, 0x69, 0x63, 0x6b, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x04,
|
||||||
|
0x02, 0x12, 0x03, 0x64, 0x0d, 0x0e, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x0d, 0x12, 0x04, 0x67, 0x00,
|
||||||
|
0x6a, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x0d, 0x01, 0x12, 0x03, 0x67, 0x08, 0x14, 0x0a, 0x0c,
|
||||||
|
0x0a, 0x05, 0x04, 0x0d, 0x02, 0x00, 0x06, 0x12, 0x03, 0x68, 0x02, 0x07, 0x0a, 0x0b, 0x0a, 0x04,
|
||||||
|
0x04, 0x0d, 0x02, 0x00, 0x12, 0x03, 0x68, 0x02, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0d, 0x02,
|
||||||
|
0x00, 0x01, 0x12, 0x03, 0x68, 0x08, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0d, 0x02, 0x00, 0x03,
|
||||||
|
0x12, 0x03, 0x68, 0x13, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0d, 0x02, 0x01, 0x06, 0x12, 0x03,
|
||||||
|
0x69, 0x02, 0x07, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0d, 0x02, 0x01, 0x12, 0x03, 0x69, 0x02, 0x14,
|
||||||
|
0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0d, 0x02, 0x01, 0x01, 0x12, 0x03, 0x69, 0x08, 0x0f, 0x0a, 0x0c,
|
||||||
|
0x0a, 0x05, 0x04, 0x0d, 0x02, 0x01, 0x03, 0x12, 0x03, 0x69, 0x12, 0x13, 0x0a, 0x0a, 0x0a, 0x02,
|
||||||
|
0x04, 0x0e, 0x12, 0x04, 0x6c, 0x00, 0x71, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x0e, 0x01, 0x12,
|
||||||
|
0x03, 0x6c, 0x08, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0e, 0x02, 0x00, 0x05, 0x12, 0x03, 0x6e,
|
||||||
|
0x02, 0x08, 0x0a, 0x32, 0x0a, 0x04, 0x04, 0x0e, 0x02, 0x00, 0x12, 0x03, 0x6e, 0x02, 0x15, 0x1a,
|
||||||
|
0x25, 0x20, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65,
|
||||||
|
0x72, 0x20, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x20, 0x30, 0x2e, 0x2e,
|
||||||
|
0x3d, 0x31, 0x30, 0x30, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0e, 0x02, 0x00, 0x01, 0x12,
|
||||||
|
0x03, 0x6e, 0x09, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0e, 0x02, 0x00, 0x03, 0x12, 0x03, 0x6e,
|
||||||
|
0x13, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0e, 0x02, 0x01, 0x05, 0x12, 0x03, 0x70, 0x02, 0x08,
|
||||||
|
0x0a, 0x53, 0x0a, 0x04, 0x04, 0x0e, 0x02, 0x01, 0x12, 0x03, 0x70, 0x02, 0x19, 0x1a, 0x46, 0x20,
|
||||||
|
0x42, 0x79, 0x74, 0x65, 0x73, 0x20, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64,
|
||||||
|
0x20, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x65, 0x76, 0x69,
|
||||||
|
0x6f, 0x75, 0x73, 0x20, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x20, 0x65, 0x76, 0x65,
|
||||||
|
0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x6f, 0x72, 0x72,
|
||||||
|
0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0e, 0x02, 0x01, 0x01, 0x12, 0x03,
|
||||||
|
0x70, 0x09, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0e, 0x02, 0x01, 0x03, 0x12, 0x03, 0x70, 0x17,
|
||||||
|
0x18, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x0f, 0x12, 0x04, 0x73, 0x00, 0x76, 0x01, 0x0a, 0x0a, 0x0a,
|
||||||
|
0x03, 0x04, 0x0f, 0x01, 0x12, 0x03, 0x73, 0x08, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0f, 0x02,
|
||||||
|
0x00, 0x05, 0x12, 0x03, 0x75, 0x02, 0x08, 0x0a, 0x4e, 0x0a, 0x04, 0x04, 0x0f, 0x02, 0x00, 0x12,
|
||||||
|
0x03, 0x75, 0x02, 0x14, 0x1a, 0x41, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x73, 0x74,
|
||||||
|
0x72, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64,
|
||||||
|
0x20, 0x74, 0x6f, 0x20, 0x60, 0x41, 0x64, 0x64, 0x60, 0x20, 0x28, 0x6d, 0x61, 0x67, 0x6e, 0x65,
|
||||||
|
0x74, 0x2c, 0x20, 0x55, 0x52, 0x4c, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20,
|
||||||
|
0x70, 0x61, 0x74, 0x68, 0x29, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0f, 0x02, 0x00, 0x01,
|
||||||
|
0x12, 0x03, 0x75, 0x09, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0f, 0x02, 0x00, 0x03, 0x12, 0x03,
|
||||||
|
0x75, 0x12, 0x13, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x10, 0x12, 0x04, 0x78, 0x00, 0x7b, 0x01, 0x0a,
|
||||||
|
0x0a, 0x0a, 0x03, 0x04, 0x10, 0x01, 0x12, 0x03, 0x78, 0x08, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04,
|
||||||
|
0x10, 0x02, 0x00, 0x05, 0x12, 0x03, 0x7a, 0x02, 0x06, 0x0a, 0x46, 0x0a, 0x04, 0x04, 0x10, 0x02,
|
||||||
|
0x00, 0x12, 0x03, 0x7a, 0x02, 0x19, 0x1a, 0x39, 0x20, 0x54, 0x72, 0x75, 0x65, 0x20, 0x69, 0x66,
|
||||||
|
0x20, 0x60, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x60, 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, 0x61,
|
||||||
|
0x6c, 0x6c, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x60, 0x64, 0x65, 0x6c, 0x65, 0x74,
|
||||||
|
0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x60, 0x2e,
|
||||||
|
0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x10, 0x02, 0x00, 0x01, 0x12, 0x03, 0x7a, 0x07, 0x14, 0x0a,
|
||||||
|
0x0c, 0x0a, 0x05, 0x04, 0x10, 0x02, 0x00, 0x03, 0x12, 0x03, 0x7a, 0x17, 0x18, 0x0a, 0x0b, 0x0a,
|
||||||
|
0x02, 0x05, 0x01, 0x12, 0x05, 0x7d, 0x00, 0x8a, 0x01, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x01,
|
||||||
|
0x01, 0x12, 0x03, 0x7d, 0x05, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x00, 0x01, 0x12,
|
||||||
|
0x03, 0x7e, 0x02, 0x13, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x01, 0x02, 0x00, 0x12, 0x03, 0x7e, 0x02,
|
||||||
|
0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x00, 0x02, 0x12, 0x03, 0x7e, 0x16, 0x17, 0x0a,
|
||||||
|
0x0c, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, 0x7f, 0x02, 0x09, 0x0a, 0x0b, 0x0a,
|
||||||
|
0x04, 0x05, 0x01, 0x02, 0x01, 0x12, 0x03, 0x7f, 0x02, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01,
|
||||||
|
0x02, 0x01, 0x02, 0x12, 0x03, 0x7f, 0x0c, 0x0d, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x02,
|
||||||
|
0x01, 0x12, 0x04, 0x80, 0x01, 0x02, 0x0d, 0x0a, 0x0c, 0x0a, 0x04, 0x05, 0x01, 0x02, 0x02, 0x12,
|
||||||
|
0x04, 0x80, 0x01, 0x02, 0x12, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x02, 0x02, 0x12, 0x04,
|
||||||
|
0x80, 0x01, 0x10, 0x11, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x03, 0x01, 0x12, 0x04, 0x81,
|
||||||
|
0x01, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x04, 0x05, 0x01, 0x02, 0x03, 0x12, 0x04, 0x81, 0x01, 0x02,
|
||||||
|
0x0d, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x03, 0x02, 0x12, 0x04, 0x81, 0x01, 0x0b, 0x0c,
|
||||||
|
0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x04, 0x01, 0x12, 0x04, 0x82, 0x01, 0x02, 0x0a, 0x0a,
|
||||||
|
0x0c, 0x0a, 0x04, 0x05, 0x01, 0x02, 0x04, 0x12, 0x04, 0x82, 0x01, 0x02, 0x0f, 0x0a, 0x0d, 0x0a,
|
||||||
|
0x05, 0x05, 0x01, 0x02, 0x04, 0x02, 0x12, 0x04, 0x82, 0x01, 0x0d, 0x0e, 0x0a, 0x0d, 0x0a, 0x05,
|
||||||
|
0x05, 0x01, 0x02, 0x05, 0x01, 0x12, 0x04, 0x83, 0x01, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x04, 0x05,
|
||||||
|
0x01, 0x02, 0x05, 0x12, 0x04, 0x83, 0x01, 0x02, 0x0c, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x01, 0x02,
|
||||||
|
0x05, 0x02, 0x12, 0x04, 0x83, 0x01, 0x0a, 0x0b, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x06,
|
||||||
|
0x01, 0x12, 0x04, 0x89, 0x01, 0x02, 0x07, 0x0a, 0xc2, 0x02, 0x0a, 0x04, 0x05, 0x01, 0x02, 0x06,
|
||||||
|
0x12, 0x04, 0x89, 0x01, 0x02, 0x0c, 0x1a, 0xb3, 0x02, 0x20, 0x4c, 0x69, 0x76, 0x65, 0x20, 0x70,
|
||||||
|
0x65, 0x72, 0x20, 0x6c, 0x69, 0x62, 0x72, 0x71, 0x62, 0x69, 0x74, 0x2c, 0x20, 0x62, 0x75, 0x74,
|
||||||
|
0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x20, 0x68, 0x61, 0x73, 0x20,
|
||||||
|
0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x61, 0x20, 0x73, 0x74, 0x61, 0x6c, 0x6c,
|
||||||
|
0x3a, 0x20, 0x6e, 0x6f, 0x20, 0x62, 0x79, 0x74, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65,
|
||||||
|
0x73, 0x73, 0x0a, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x73, 0x65, 0x76, 0x65, 0x72, 0x61, 0x6c, 0x20,
|
||||||
|
0x74, 0x69, 0x63, 0x6b, 0x73, 0x20, 0x41, 0x4e, 0x44, 0x20, 0x7a, 0x65, 0x72, 0x6f, 0x20, 0x63,
|
||||||
|
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x70, 0x65, 0x65, 0x72, 0x73, 0x2e, 0x20,
|
||||||
|
0x54, 0x68, 0x65, 0x20, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x73, 0x20, 0x73,
|
||||||
|
0x74, 0x69, 0x6c, 0x6c, 0x0a, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72, 0x65, 0x64,
|
||||||
|
0x20, 0x6c, 0x69, 0x76, 0x65, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x6e, 0x64,
|
||||||
|
0x65, 0x72, 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x3b, 0x20,
|
||||||
|
0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6e,
|
||||||
|
0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x0a, 0x20, 0x6c,
|
||||||
|
0x65, 0x76, 0x65, 0x6c, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x6c, 0x61, 0x79, 0x2e, 0x20, 0x52, 0x65,
|
||||||
|
0x63, 0x6f, 0x76, 0x65, 0x72, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f,
|
||||||
|
0x41, 0x44, 0x49, 0x4e, 0x47, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61,
|
||||||
|
0x6c, 0x6c, 0x79, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x61,
|
||||||
|
0x64, 0x76, 0x61, 0x6e, 0x63, 0x65, 0x0a, 0x20, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x70, 0x65, 0x65,
|
||||||
|
0x72, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x73, 0x2e, 0x0a, 0x0a, 0x0d, 0x0a, 0x05,
|
||||||
|
0x05, 0x01, 0x02, 0x06, 0x02, 0x12, 0x04, 0x89, 0x01, 0x0a, 0x0b, 0x0a, 0x0c, 0x0a, 0x02, 0x04,
|
||||||
|
0x11, 0x12, 0x06, 0x8c, 0x01, 0x00, 0x9c, 0x01, 0x01, 0x0a, 0x0b, 0x0a, 0x03, 0x04, 0x11, 0x01,
|
||||||
|
0x12, 0x04, 0x8c, 0x01, 0x08, 0x15, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x00, 0x05, 0x12,
|
||||||
|
0x04, 0x8d, 0x01, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x11, 0x02, 0x00, 0x12, 0x04, 0x8d,
|
||||||
|
0x01, 0x02, 0x10, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x00, 0x01, 0x12, 0x04, 0x8d, 0x01,
|
||||||
|
0x09, 0x0b, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x00, 0x03, 0x12, 0x04, 0x8d, 0x01, 0x0e,
|
||||||
|
0x0f, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x01, 0x05, 0x12, 0x04, 0x8e, 0x01, 0x02, 0x08,
|
||||||
|
0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x11, 0x02, 0x01, 0x12, 0x04, 0x8e, 0x01, 0x02, 0x17, 0x0a, 0x0d,
|
||||||
|
0x0a, 0x05, 0x04, 0x11, 0x02, 0x01, 0x01, 0x12, 0x04, 0x8e, 0x01, 0x09, 0x12, 0x0a, 0x0d, 0x0a,
|
||||||
|
0x05, 0x04, 0x11, 0x02, 0x01, 0x03, 0x12, 0x04, 0x8e, 0x01, 0x15, 0x16, 0x0a, 0x0d, 0x0a, 0x05,
|
||||||
|
0x04, 0x11, 0x02, 0x02, 0x05, 0x12, 0x04, 0x8f, 0x01, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x04, 0x04,
|
||||||
|
0x11, 0x02, 0x02, 0x12, 0x04, 0x8f, 0x01, 0x02, 0x12, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02,
|
||||||
|
0x02, 0x01, 0x12, 0x04, 0x8f, 0x01, 0x09, 0x0d, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x02,
|
||||||
|
0x03, 0x12, 0x04, 0x8f, 0x01, 0x10, 0x11, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x03, 0x05,
|
||||||
|
0x12, 0x04, 0x90, 0x01, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x11, 0x02, 0x03, 0x12, 0x04,
|
||||||
|
0x90, 0x01, 0x02, 0x14, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x03, 0x01, 0x12, 0x04, 0x90,
|
||||||
|
0x01, 0x09, 0x0f, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x03, 0x03, 0x12, 0x04, 0x90, 0x01,
|
||||||
|
0x12, 0x13, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x04, 0x05, 0x12, 0x04, 0x91, 0x01, 0x02,
|
||||||
|
0x08, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x11, 0x02, 0x04, 0x12, 0x04, 0x91, 0x01, 0x02, 0x19, 0x0a,
|
||||||
|
0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x04, 0x01, 0x12, 0x04, 0x91, 0x01, 0x09, 0x14, 0x0a, 0x0d,
|
||||||
|
0x0a, 0x05, 0x04, 0x11, 0x02, 0x04, 0x03, 0x12, 0x04, 0x91, 0x01, 0x17, 0x18, 0x0a, 0x0d, 0x0a,
|
||||||
|
0x05, 0x04, 0x11, 0x02, 0x05, 0x05, 0x12, 0x04, 0x92, 0x01, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x04,
|
||||||
|
0x04, 0x11, 0x02, 0x05, 0x12, 0x04, 0x92, 0x01, 0x02, 0x19, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11,
|
||||||
|
0x02, 0x05, 0x01, 0x12, 0x04, 0x92, 0x01, 0x09, 0x14, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02,
|
||||||
|
0x05, 0x03, 0x12, 0x04, 0x92, 0x01, 0x17, 0x18, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x06,
|
||||||
|
0x05, 0x12, 0x04, 0x93, 0x01, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x11, 0x02, 0x06, 0x12,
|
||||||
|
0x04, 0x93, 0x01, 0x02, 0x1e, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x06, 0x01, 0x12, 0x04,
|
||||||
|
0x93, 0x01, 0x09, 0x19, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x06, 0x03, 0x12, 0x04, 0x93,
|
||||||
|
0x01, 0x1c, 0x1d, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x07, 0x06, 0x12, 0x04, 0x94, 0x01,
|
||||||
|
0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x11, 0x02, 0x07, 0x12, 0x04, 0x94, 0x01, 0x02, 0x12,
|
||||||
|
0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x07, 0x01, 0x12, 0x04, 0x94, 0x01, 0x08, 0x0d, 0x0a,
|
||||||
|
0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x07, 0x03, 0x12, 0x04, 0x94, 0x01, 0x10, 0x11, 0x0a, 0x0d,
|
||||||
|
0x0a, 0x05, 0x04, 0x11, 0x02, 0x08, 0x05, 0x12, 0x04, 0x95, 0x01, 0x02, 0x08, 0x0a, 0x0c, 0x0a,
|
||||||
|
0x04, 0x04, 0x11, 0x02, 0x08, 0x12, 0x04, 0x95, 0x01, 0x02, 0x1b, 0x0a, 0x0d, 0x0a, 0x05, 0x04,
|
||||||
|
0x11, 0x02, 0x08, 0x01, 0x12, 0x04, 0x95, 0x01, 0x09, 0x16, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11,
|
||||||
|
0x02, 0x08, 0x03, 0x12, 0x04, 0x95, 0x01, 0x19, 0x1a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02,
|
||||||
|
0x09, 0x05, 0x12, 0x04, 0x96, 0x01, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x11, 0x02, 0x09,
|
||||||
|
0x12, 0x04, 0x96, 0x01, 0x02, 0x21, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x09, 0x01, 0x12,
|
||||||
|
0x04, 0x96, 0x01, 0x09, 0x1b, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x09, 0x03, 0x12, 0x04,
|
||||||
|
0x96, 0x01, 0x1e, 0x20, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x0a, 0x05, 0x12, 0x04, 0x97,
|
||||||
|
0x01, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x11, 0x02, 0x0a, 0x12, 0x04, 0x97, 0x01, 0x02,
|
||||||
|
0x1a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x0a, 0x01, 0x12, 0x04, 0x97, 0x01, 0x09, 0x14,
|
||||||
|
0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x0a, 0x03, 0x12, 0x04, 0x97, 0x01, 0x17, 0x19, 0x0a,
|
||||||
|
0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x0b, 0x05, 0x12, 0x04, 0x98, 0x01, 0x02, 0x08, 0x0a, 0x0c,
|
||||||
|
0x0a, 0x04, 0x04, 0x11, 0x02, 0x0b, 0x12, 0x04, 0x98, 0x01, 0x02, 0x1d, 0x0a, 0x0d, 0x0a, 0x05,
|
||||||
|
0x04, 0x11, 0x02, 0x0b, 0x01, 0x12, 0x04, 0x98, 0x01, 0x09, 0x17, 0x0a, 0x0d, 0x0a, 0x05, 0x04,
|
||||||
|
0x11, 0x02, 0x0b, 0x03, 0x12, 0x04, 0x98, 0x01, 0x1a, 0x1c, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11,
|
||||||
|
0x02, 0x0c, 0x05, 0x12, 0x04, 0x99, 0x01, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x11, 0x02,
|
||||||
|
0x0c, 0x12, 0x04, 0x99, 0x01, 0x02, 0x1f, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x0c, 0x01,
|
||||||
|
0x12, 0x04, 0x99, 0x01, 0x09, 0x19, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x0c, 0x03, 0x12,
|
||||||
|
0x04, 0x99, 0x01, 0x1c, 0x1e, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x0d, 0x05, 0x12, 0x04,
|
||||||
|
0x9a, 0x01, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x11, 0x02, 0x0d, 0x12, 0x04, 0x9a, 0x01,
|
||||||
|
0x02, 0x14, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x0d, 0x01, 0x12, 0x04, 0x9a, 0x01, 0x09,
|
||||||
|
0x0e, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x0d, 0x03, 0x12, 0x04, 0x9a, 0x01, 0x11, 0x13,
|
||||||
|
0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x11, 0x02, 0x0e, 0x05, 0x12, 0x04, 0x9b, 0x01, 0x02, 0x08, 0x0a,
|
||||||
|
0x0c, 0x0a, 0x04, 0x04, 0x11, 0x02, 0x0e, 0x12, 0x04, 0x9b, 0x01, 0x02, 0x14, 0x0a, 0x0d, 0x0a,
|
||||||
|
0x05, 0x04, 0x11, 0x02, 0x0e, 0x01, 0x12, 0x04, 0x9b, 0x01, 0x09, 0x0e, 0x0a, 0x0d, 0x0a, 0x05,
|
||||||
|
0x04, 0x11, 0x02, 0x0e, 0x03, 0x12, 0x04, 0x9b, 0x01, 0x11, 0x13, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
||||||
0x74, 0x6f, 0x33,
|
0x74, 0x6f, 0x33,
|
||||||
];
|
];
|
||||||
include!("torrent.serde.rs");
|
include!("torrent.serde.rs");
|
||||||
|
|||||||
@@ -199,6 +199,98 @@ impl<'de> serde::Deserialize<'de> for AddResponse {
|
|||||||
deserializer.deserialize_struct("torrent.AddResponse", FIELDS, GeneratedVisitor)
|
deserializer.deserialize_struct("torrent.AddResponse", FIELDS, GeneratedVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl serde::Serialize for AddedInfo {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
use serde::ser::SerializeStruct;
|
||||||
|
let mut len = 0;
|
||||||
|
if !self.source.is_empty() {
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
let mut struct_ser = serializer.serialize_struct("torrent.AddedInfo", len)?;
|
||||||
|
if !self.source.is_empty() {
|
||||||
|
struct_ser.serialize_field("source", &self.source)?;
|
||||||
|
}
|
||||||
|
struct_ser.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'de> serde::Deserialize<'de> for AddedInfo {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
const FIELDS: &[&str] = &["source"];
|
||||||
|
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
|
enum GeneratedField {
|
||||||
|
Source,
|
||||||
|
}
|
||||||
|
impl<'de> serde::Deserialize<'de> for GeneratedField {
|
||||||
|
fn deserialize<D>(deserializer: D) -> std::result::Result<GeneratedField, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct GeneratedVisitor;
|
||||||
|
|
||||||
|
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
|
||||||
|
type Value = GeneratedField;
|
||||||
|
|
||||||
|
fn expecting(
|
||||||
|
&self,
|
||||||
|
formatter: &mut std::fmt::Formatter<'_>,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(formatter, "expected one of: {:?}", &FIELDS)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
fn visit_str<E>(self, value: &str) -> std::result::Result<GeneratedField, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
match value {
|
||||||
|
"source" => Ok(GeneratedField::Source),
|
||||||
|
_ => Err(serde::de::Error::unknown_field(value, FIELDS)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deserializer.deserialize_identifier(GeneratedVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct GeneratedVisitor;
|
||||||
|
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
|
||||||
|
type Value = AddedInfo;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
formatter.write_str("struct torrent.AddedInfo")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<V>(self, mut map_: V) -> std::result::Result<AddedInfo, V::Error>
|
||||||
|
where
|
||||||
|
V: serde::de::MapAccess<'de>,
|
||||||
|
{
|
||||||
|
let mut source__ = None;
|
||||||
|
while let Some(k) = map_.next_key()? {
|
||||||
|
match k {
|
||||||
|
GeneratedField::Source => {
|
||||||
|
if source__.is_some() {
|
||||||
|
return Err(serde::de::Error::duplicate_field("source"));
|
||||||
|
}
|
||||||
|
source__ = Some(map_.next_value()?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(AddedInfo {
|
||||||
|
source: source__.unwrap_or_default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deserializer.deserialize_struct("torrent.AddedInfo", FIELDS, GeneratedVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl serde::Serialize for ListRequest {
|
impl serde::Serialize for ListRequest {
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||||
@@ -362,6 +454,420 @@ impl<'de> serde::Deserialize<'de> for ListResponse {
|
|||||||
deserializer.deserialize_struct("torrent.ListResponse", FIELDS, GeneratedVisitor)
|
deserializer.deserialize_struct("torrent.ListResponse", FIELDS, GeneratedVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl serde::Serialize for Notification {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
use serde::ser::SerializeStruct;
|
||||||
|
let mut len = 0;
|
||||||
|
if self.observed_at_unix_millis != 0 {
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
if self.kind != 0 {
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
if self.torrent.is_some() {
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
if self.detail.is_some() {
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
let mut struct_ser = serializer.serialize_struct("torrent.Notification", len)?;
|
||||||
|
if self.observed_at_unix_millis != 0 {
|
||||||
|
#[allow(clippy::needless_borrow)]
|
||||||
|
#[allow(clippy::needless_borrows_for_generic_args)]
|
||||||
|
struct_ser.serialize_field(
|
||||||
|
"observedAtUnixMillis",
|
||||||
|
ToString::to_string(&self.observed_at_unix_millis).as_str(),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
if self.kind != 0 {
|
||||||
|
let v = NotificationKind::try_from(self.kind)
|
||||||
|
.map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", self.kind)))?;
|
||||||
|
struct_ser.serialize_field("kind", &v)?;
|
||||||
|
}
|
||||||
|
if let Some(v) = self.torrent.as_ref() {
|
||||||
|
struct_ser.serialize_field("torrent", v)?;
|
||||||
|
}
|
||||||
|
if let Some(v) = self.detail.as_ref() {
|
||||||
|
match v {
|
||||||
|
notification::Detail::StateChanged(v) => {
|
||||||
|
struct_ser.serialize_field("stateChanged", v)?;
|
||||||
|
}
|
||||||
|
notification::Detail::Progress(v) => {
|
||||||
|
struct_ser.serialize_field("progress", v)?;
|
||||||
|
}
|
||||||
|
notification::Detail::Added(v) => {
|
||||||
|
struct_ser.serialize_field("added", v)?;
|
||||||
|
}
|
||||||
|
notification::Detail::Removed(v) => {
|
||||||
|
struct_ser.serialize_field("removed", v)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct_ser.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'de> serde::Deserialize<'de> for Notification {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
const FIELDS: &[&str] = &[
|
||||||
|
"observed_at_unix_millis",
|
||||||
|
"observedAtUnixMillis",
|
||||||
|
"kind",
|
||||||
|
"torrent",
|
||||||
|
"state_changed",
|
||||||
|
"stateChanged",
|
||||||
|
"progress",
|
||||||
|
"added",
|
||||||
|
"removed",
|
||||||
|
];
|
||||||
|
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
|
enum GeneratedField {
|
||||||
|
ObservedAtUnixMillis,
|
||||||
|
Kind,
|
||||||
|
Torrent,
|
||||||
|
StateChanged,
|
||||||
|
Progress,
|
||||||
|
Added,
|
||||||
|
Removed,
|
||||||
|
}
|
||||||
|
impl<'de> serde::Deserialize<'de> for GeneratedField {
|
||||||
|
fn deserialize<D>(deserializer: D) -> std::result::Result<GeneratedField, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct GeneratedVisitor;
|
||||||
|
|
||||||
|
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
|
||||||
|
type Value = GeneratedField;
|
||||||
|
|
||||||
|
fn expecting(
|
||||||
|
&self,
|
||||||
|
formatter: &mut std::fmt::Formatter<'_>,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(formatter, "expected one of: {:?}", &FIELDS)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
fn visit_str<E>(self, value: &str) -> std::result::Result<GeneratedField, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
match value {
|
||||||
|
"observedAtUnixMillis" | "observed_at_unix_millis" => {
|
||||||
|
Ok(GeneratedField::ObservedAtUnixMillis)
|
||||||
|
}
|
||||||
|
"kind" => Ok(GeneratedField::Kind),
|
||||||
|
"torrent" => Ok(GeneratedField::Torrent),
|
||||||
|
"stateChanged" | "state_changed" => Ok(GeneratedField::StateChanged),
|
||||||
|
"progress" => Ok(GeneratedField::Progress),
|
||||||
|
"added" => Ok(GeneratedField::Added),
|
||||||
|
"removed" => Ok(GeneratedField::Removed),
|
||||||
|
_ => Err(serde::de::Error::unknown_field(value, FIELDS)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deserializer.deserialize_identifier(GeneratedVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct GeneratedVisitor;
|
||||||
|
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
|
||||||
|
type Value = Notification;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
formatter.write_str("struct torrent.Notification")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<V>(self, mut map_: V) -> std::result::Result<Notification, V::Error>
|
||||||
|
where
|
||||||
|
V: serde::de::MapAccess<'de>,
|
||||||
|
{
|
||||||
|
let mut observed_at_unix_millis__ = None;
|
||||||
|
let mut kind__ = None;
|
||||||
|
let mut torrent__ = None;
|
||||||
|
let mut detail__ = None;
|
||||||
|
while let Some(k) = map_.next_key()? {
|
||||||
|
match k {
|
||||||
|
GeneratedField::ObservedAtUnixMillis => {
|
||||||
|
if observed_at_unix_millis__.is_some() {
|
||||||
|
return Err(serde::de::Error::duplicate_field(
|
||||||
|
"observedAtUnixMillis",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
observed_at_unix_millis__ = Some(
|
||||||
|
map_.next_value::<::pbjson::private::NumberDeserialize<_>>()?
|
||||||
|
.0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
GeneratedField::Kind => {
|
||||||
|
if kind__.is_some() {
|
||||||
|
return Err(serde::de::Error::duplicate_field("kind"));
|
||||||
|
}
|
||||||
|
kind__ = Some(map_.next_value::<NotificationKind>()? as i32);
|
||||||
|
}
|
||||||
|
GeneratedField::Torrent => {
|
||||||
|
if torrent__.is_some() {
|
||||||
|
return Err(serde::de::Error::duplicate_field("torrent"));
|
||||||
|
}
|
||||||
|
torrent__ = map_.next_value()?;
|
||||||
|
}
|
||||||
|
GeneratedField::StateChanged => {
|
||||||
|
if detail__.is_some() {
|
||||||
|
return Err(serde::de::Error::duplicate_field("stateChanged"));
|
||||||
|
}
|
||||||
|
detail__ = map_
|
||||||
|
.next_value::<::std::option::Option<_>>()?
|
||||||
|
.map(notification::Detail::StateChanged);
|
||||||
|
}
|
||||||
|
GeneratedField::Progress => {
|
||||||
|
if detail__.is_some() {
|
||||||
|
return Err(serde::de::Error::duplicate_field("progress"));
|
||||||
|
}
|
||||||
|
detail__ = map_
|
||||||
|
.next_value::<::std::option::Option<_>>()?
|
||||||
|
.map(notification::Detail::Progress);
|
||||||
|
}
|
||||||
|
GeneratedField::Added => {
|
||||||
|
if detail__.is_some() {
|
||||||
|
return Err(serde::de::Error::duplicate_field("added"));
|
||||||
|
}
|
||||||
|
detail__ = map_
|
||||||
|
.next_value::<::std::option::Option<_>>()?
|
||||||
|
.map(notification::Detail::Added);
|
||||||
|
}
|
||||||
|
GeneratedField::Removed => {
|
||||||
|
if detail__.is_some() {
|
||||||
|
return Err(serde::de::Error::duplicate_field("removed"));
|
||||||
|
}
|
||||||
|
detail__ = map_
|
||||||
|
.next_value::<::std::option::Option<_>>()?
|
||||||
|
.map(notification::Detail::Removed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Notification {
|
||||||
|
observed_at_unix_millis: observed_at_unix_millis__.unwrap_or_default(),
|
||||||
|
kind: kind__.unwrap_or_default(),
|
||||||
|
torrent: torrent__,
|
||||||
|
detail: detail__,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deserializer.deserialize_struct("torrent.Notification", FIELDS, GeneratedVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl serde::Serialize for NotificationKind {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
let variant = match self {
|
||||||
|
Self::Unspecified => "NOTIFICATION_KIND_UNSPECIFIED",
|
||||||
|
Self::TorrentAdded => "TORRENT_ADDED",
|
||||||
|
Self::TorrentRemoved => "TORRENT_REMOVED",
|
||||||
|
Self::StateChanged => "STATE_CHANGED",
|
||||||
|
Self::Progress => "PROGRESS",
|
||||||
|
};
|
||||||
|
serializer.serialize_str(variant)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'de> serde::Deserialize<'de> for NotificationKind {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
const FIELDS: &[&str] = &[
|
||||||
|
"NOTIFICATION_KIND_UNSPECIFIED",
|
||||||
|
"TORRENT_ADDED",
|
||||||
|
"TORRENT_REMOVED",
|
||||||
|
"STATE_CHANGED",
|
||||||
|
"PROGRESS",
|
||||||
|
];
|
||||||
|
|
||||||
|
struct GeneratedVisitor;
|
||||||
|
|
||||||
|
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
|
||||||
|
type Value = NotificationKind;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(formatter, "expected one of: {:?}", &FIELDS)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_i64<E>(self, v: i64) -> std::result::Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
i32::try_from(v)
|
||||||
|
.ok()
|
||||||
|
.and_then(|x| x.try_into().ok())
|
||||||
|
.ok_or_else(|| {
|
||||||
|
serde::de::Error::invalid_value(serde::de::Unexpected::Signed(v), &self)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_u64<E>(self, v: u64) -> std::result::Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
i32::try_from(v)
|
||||||
|
.ok()
|
||||||
|
.and_then(|x| x.try_into().ok())
|
||||||
|
.ok_or_else(|| {
|
||||||
|
serde::de::Error::invalid_value(serde::de::Unexpected::Unsigned(v), &self)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> std::result::Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
match value {
|
||||||
|
"NOTIFICATION_KIND_UNSPECIFIED" => Ok(NotificationKind::Unspecified),
|
||||||
|
"TORRENT_ADDED" => Ok(NotificationKind::TorrentAdded),
|
||||||
|
"TORRENT_REMOVED" => Ok(NotificationKind::TorrentRemoved),
|
||||||
|
"STATE_CHANGED" => Ok(NotificationKind::StateChanged),
|
||||||
|
"PROGRESS" => Ok(NotificationKind::Progress),
|
||||||
|
_ => Err(serde::de::Error::unknown_variant(value, FIELDS)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deserializer.deserialize_any(GeneratedVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl serde::Serialize for NotificationsRequest {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
use serde::ser::SerializeStruct;
|
||||||
|
let mut len = 0;
|
||||||
|
if !self.ids.is_empty() {
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
if !self.kinds.is_empty() {
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
let mut struct_ser = serializer.serialize_struct("torrent.NotificationsRequest", len)?;
|
||||||
|
if !self.ids.is_empty() {
|
||||||
|
struct_ser.serialize_field("ids", &self.ids)?;
|
||||||
|
}
|
||||||
|
if !self.kinds.is_empty() {
|
||||||
|
let v = self
|
||||||
|
.kinds
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|v| {
|
||||||
|
NotificationKind::try_from(v)
|
||||||
|
.map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", v)))
|
||||||
|
})
|
||||||
|
.collect::<std::result::Result<Vec<_>, _>>()?;
|
||||||
|
struct_ser.serialize_field("kinds", &v)?;
|
||||||
|
}
|
||||||
|
struct_ser.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'de> serde::Deserialize<'de> for NotificationsRequest {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
const FIELDS: &[&str] = &["ids", "kinds"];
|
||||||
|
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
|
enum GeneratedField {
|
||||||
|
Ids,
|
||||||
|
Kinds,
|
||||||
|
}
|
||||||
|
impl<'de> serde::Deserialize<'de> for GeneratedField {
|
||||||
|
fn deserialize<D>(deserializer: D) -> std::result::Result<GeneratedField, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct GeneratedVisitor;
|
||||||
|
|
||||||
|
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
|
||||||
|
type Value = GeneratedField;
|
||||||
|
|
||||||
|
fn expecting(
|
||||||
|
&self,
|
||||||
|
formatter: &mut std::fmt::Formatter<'_>,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(formatter, "expected one of: {:?}", &FIELDS)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
fn visit_str<E>(self, value: &str) -> std::result::Result<GeneratedField, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
match value {
|
||||||
|
"ids" => Ok(GeneratedField::Ids),
|
||||||
|
"kinds" => Ok(GeneratedField::Kinds),
|
||||||
|
_ => Err(serde::de::Error::unknown_field(value, FIELDS)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deserializer.deserialize_identifier(GeneratedVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct GeneratedVisitor;
|
||||||
|
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
|
||||||
|
type Value = NotificationsRequest;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
formatter.write_str("struct torrent.NotificationsRequest")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<V>(
|
||||||
|
self,
|
||||||
|
mut map_: V,
|
||||||
|
) -> std::result::Result<NotificationsRequest, V::Error>
|
||||||
|
where
|
||||||
|
V: serde::de::MapAccess<'de>,
|
||||||
|
{
|
||||||
|
let mut ids__ = None;
|
||||||
|
let mut kinds__ = None;
|
||||||
|
while let Some(k) = map_.next_key()? {
|
||||||
|
match k {
|
||||||
|
GeneratedField::Ids => {
|
||||||
|
if ids__.is_some() {
|
||||||
|
return Err(serde::de::Error::duplicate_field("ids"));
|
||||||
|
}
|
||||||
|
ids__ = Some(map_.next_value()?);
|
||||||
|
}
|
||||||
|
GeneratedField::Kinds => {
|
||||||
|
if kinds__.is_some() {
|
||||||
|
return Err(serde::de::Error::duplicate_field("kinds"));
|
||||||
|
}
|
||||||
|
kinds__ = Some(
|
||||||
|
map_.next_value::<Vec<NotificationKind>>()?
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| x as i32)
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(NotificationsRequest {
|
||||||
|
ids: ids__.unwrap_or_default(),
|
||||||
|
kinds: kinds__.unwrap_or_default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deserializer.deserialize_struct("torrent.NotificationsRequest", FIELDS, GeneratedVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl serde::Serialize for PauseRequest {
|
impl serde::Serialize for PauseRequest {
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||||
@@ -525,6 +1031,125 @@ impl<'de> serde::Deserialize<'de> for PauseResponse {
|
|||||||
deserializer.deserialize_struct("torrent.PauseResponse", FIELDS, GeneratedVisitor)
|
deserializer.deserialize_struct("torrent.PauseResponse", FIELDS, GeneratedVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl serde::Serialize for ProgressMark {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
use serde::ser::SerializeStruct;
|
||||||
|
let mut len = 0;
|
||||||
|
if self.percent != 0 {
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
if self.bytes_delta != 0 {
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
let mut struct_ser = serializer.serialize_struct("torrent.ProgressMark", len)?;
|
||||||
|
if self.percent != 0 {
|
||||||
|
struct_ser.serialize_field("percent", &self.percent)?;
|
||||||
|
}
|
||||||
|
if self.bytes_delta != 0 {
|
||||||
|
#[allow(clippy::needless_borrow)]
|
||||||
|
#[allow(clippy::needless_borrows_for_generic_args)]
|
||||||
|
struct_ser.serialize_field(
|
||||||
|
"bytesDelta",
|
||||||
|
ToString::to_string(&self.bytes_delta).as_str(),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
struct_ser.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'de> serde::Deserialize<'de> for ProgressMark {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
const FIELDS: &[&str] = &["percent", "bytes_delta", "bytesDelta"];
|
||||||
|
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
|
enum GeneratedField {
|
||||||
|
Percent,
|
||||||
|
BytesDelta,
|
||||||
|
}
|
||||||
|
impl<'de> serde::Deserialize<'de> for GeneratedField {
|
||||||
|
fn deserialize<D>(deserializer: D) -> std::result::Result<GeneratedField, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct GeneratedVisitor;
|
||||||
|
|
||||||
|
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
|
||||||
|
type Value = GeneratedField;
|
||||||
|
|
||||||
|
fn expecting(
|
||||||
|
&self,
|
||||||
|
formatter: &mut std::fmt::Formatter<'_>,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(formatter, "expected one of: {:?}", &FIELDS)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
fn visit_str<E>(self, value: &str) -> std::result::Result<GeneratedField, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
match value {
|
||||||
|
"percent" => Ok(GeneratedField::Percent),
|
||||||
|
"bytesDelta" | "bytes_delta" => Ok(GeneratedField::BytesDelta),
|
||||||
|
_ => Err(serde::de::Error::unknown_field(value, FIELDS)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deserializer.deserialize_identifier(GeneratedVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct GeneratedVisitor;
|
||||||
|
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
|
||||||
|
type Value = ProgressMark;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
formatter.write_str("struct torrent.ProgressMark")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<V>(self, mut map_: V) -> std::result::Result<ProgressMark, V::Error>
|
||||||
|
where
|
||||||
|
V: serde::de::MapAccess<'de>,
|
||||||
|
{
|
||||||
|
let mut percent__ = None;
|
||||||
|
let mut bytes_delta__ = None;
|
||||||
|
while let Some(k) = map_.next_key()? {
|
||||||
|
match k {
|
||||||
|
GeneratedField::Percent => {
|
||||||
|
if percent__.is_some() {
|
||||||
|
return Err(serde::de::Error::duplicate_field("percent"));
|
||||||
|
}
|
||||||
|
percent__ = Some(
|
||||||
|
map_.next_value::<::pbjson::private::NumberDeserialize<_>>()?
|
||||||
|
.0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
GeneratedField::BytesDelta => {
|
||||||
|
if bytes_delta__.is_some() {
|
||||||
|
return Err(serde::de::Error::duplicate_field("bytesDelta"));
|
||||||
|
}
|
||||||
|
bytes_delta__ = Some(
|
||||||
|
map_.next_value::<::pbjson::private::NumberDeserialize<_>>()?
|
||||||
|
.0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(ProgressMark {
|
||||||
|
percent: percent__.unwrap_or_default(),
|
||||||
|
bytes_delta: bytes_delta__.unwrap_or_default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deserializer.deserialize_struct("torrent.ProgressMark", FIELDS, GeneratedVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl serde::Serialize for RemoveRequest {
|
impl serde::Serialize for RemoveRequest {
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||||
@@ -704,6 +1329,98 @@ impl<'de> serde::Deserialize<'de> for RemoveResponse {
|
|||||||
deserializer.deserialize_struct("torrent.RemoveResponse", FIELDS, GeneratedVisitor)
|
deserializer.deserialize_struct("torrent.RemoveResponse", FIELDS, GeneratedVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl serde::Serialize for RemovedInfo {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
use serde::ser::SerializeStruct;
|
||||||
|
let mut len = 0;
|
||||||
|
if self.files_deleted {
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
let mut struct_ser = serializer.serialize_struct("torrent.RemovedInfo", len)?;
|
||||||
|
if self.files_deleted {
|
||||||
|
struct_ser.serialize_field("filesDeleted", &self.files_deleted)?;
|
||||||
|
}
|
||||||
|
struct_ser.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'de> serde::Deserialize<'de> for RemovedInfo {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
const FIELDS: &[&str] = &["files_deleted", "filesDeleted"];
|
||||||
|
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
|
enum GeneratedField {
|
||||||
|
FilesDeleted,
|
||||||
|
}
|
||||||
|
impl<'de> serde::Deserialize<'de> for GeneratedField {
|
||||||
|
fn deserialize<D>(deserializer: D) -> std::result::Result<GeneratedField, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct GeneratedVisitor;
|
||||||
|
|
||||||
|
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
|
||||||
|
type Value = GeneratedField;
|
||||||
|
|
||||||
|
fn expecting(
|
||||||
|
&self,
|
||||||
|
formatter: &mut std::fmt::Formatter<'_>,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(formatter, "expected one of: {:?}", &FIELDS)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
fn visit_str<E>(self, value: &str) -> std::result::Result<GeneratedField, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
match value {
|
||||||
|
"filesDeleted" | "files_deleted" => Ok(GeneratedField::FilesDeleted),
|
||||||
|
_ => Err(serde::de::Error::unknown_field(value, FIELDS)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deserializer.deserialize_identifier(GeneratedVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct GeneratedVisitor;
|
||||||
|
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
|
||||||
|
type Value = RemovedInfo;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
formatter.write_str("struct torrent.RemovedInfo")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<V>(self, mut map_: V) -> std::result::Result<RemovedInfo, V::Error>
|
||||||
|
where
|
||||||
|
V: serde::de::MapAccess<'de>,
|
||||||
|
{
|
||||||
|
let mut files_deleted__ = None;
|
||||||
|
while let Some(k) = map_.next_key()? {
|
||||||
|
match k {
|
||||||
|
GeneratedField::FilesDeleted => {
|
||||||
|
if files_deleted__.is_some() {
|
||||||
|
return Err(serde::de::Error::duplicate_field("filesDeleted"));
|
||||||
|
}
|
||||||
|
files_deleted__ = Some(map_.next_value()?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(RemovedInfo {
|
||||||
|
files_deleted: files_deleted__.unwrap_or_default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deserializer.deserialize_struct("torrent.RemovedInfo", FIELDS, GeneratedVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl serde::Serialize for ResumeRequest {
|
impl serde::Serialize for ResumeRequest {
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||||
@@ -880,6 +1597,7 @@ impl serde::Serialize for State {
|
|||||||
Self::Paused => "PAUSED",
|
Self::Paused => "PAUSED",
|
||||||
Self::Finished => "FINISHED",
|
Self::Finished => "FINISHED",
|
||||||
Self::Error => "ERROR",
|
Self::Error => "ERROR",
|
||||||
|
Self::Stale => "STALE",
|
||||||
};
|
};
|
||||||
serializer.serialize_str(variant)
|
serializer.serialize_str(variant)
|
||||||
}
|
}
|
||||||
@@ -897,6 +1615,7 @@ impl<'de> serde::Deserialize<'de> for State {
|
|||||||
"PAUSED",
|
"PAUSED",
|
||||||
"FINISHED",
|
"FINISHED",
|
||||||
"ERROR",
|
"ERROR",
|
||||||
|
"STALE",
|
||||||
];
|
];
|
||||||
|
|
||||||
struct GeneratedVisitor;
|
struct GeneratedVisitor;
|
||||||
@@ -943,6 +1662,7 @@ impl<'de> serde::Deserialize<'de> for State {
|
|||||||
"PAUSED" => Ok(State::Paused),
|
"PAUSED" => Ok(State::Paused),
|
||||||
"FINISHED" => Ok(State::Finished),
|
"FINISHED" => Ok(State::Finished),
|
||||||
"ERROR" => Ok(State::Error),
|
"ERROR" => Ok(State::Error),
|
||||||
|
"STALE" => Ok(State::Stale),
|
||||||
_ => Err(serde::de::Error::unknown_variant(value, FIELDS)),
|
_ => Err(serde::de::Error::unknown_variant(value, FIELDS)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -950,6 +1670,120 @@ impl<'de> serde::Deserialize<'de> for State {
|
|||||||
deserializer.deserialize_any(GeneratedVisitor)
|
deserializer.deserialize_any(GeneratedVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl serde::Serialize for StateChanged {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
use serde::ser::SerializeStruct;
|
||||||
|
let mut len = 0;
|
||||||
|
if self.previous != 0 {
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
if self.current != 0 {
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
let mut struct_ser = serializer.serialize_struct("torrent.StateChanged", len)?;
|
||||||
|
if self.previous != 0 {
|
||||||
|
let v = State::try_from(self.previous).map_err(|_| {
|
||||||
|
serde::ser::Error::custom(format!("Invalid variant {}", self.previous))
|
||||||
|
})?;
|
||||||
|
struct_ser.serialize_field("previous", &v)?;
|
||||||
|
}
|
||||||
|
if self.current != 0 {
|
||||||
|
let v = State::try_from(self.current).map_err(|_| {
|
||||||
|
serde::ser::Error::custom(format!("Invalid variant {}", self.current))
|
||||||
|
})?;
|
||||||
|
struct_ser.serialize_field("current", &v)?;
|
||||||
|
}
|
||||||
|
struct_ser.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'de> serde::Deserialize<'de> for StateChanged {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
const FIELDS: &[&str] = &["previous", "current"];
|
||||||
|
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
|
enum GeneratedField {
|
||||||
|
Previous,
|
||||||
|
Current,
|
||||||
|
}
|
||||||
|
impl<'de> serde::Deserialize<'de> for GeneratedField {
|
||||||
|
fn deserialize<D>(deserializer: D) -> std::result::Result<GeneratedField, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct GeneratedVisitor;
|
||||||
|
|
||||||
|
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
|
||||||
|
type Value = GeneratedField;
|
||||||
|
|
||||||
|
fn expecting(
|
||||||
|
&self,
|
||||||
|
formatter: &mut std::fmt::Formatter<'_>,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(formatter, "expected one of: {:?}", &FIELDS)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
fn visit_str<E>(self, value: &str) -> std::result::Result<GeneratedField, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
match value {
|
||||||
|
"previous" => Ok(GeneratedField::Previous),
|
||||||
|
"current" => Ok(GeneratedField::Current),
|
||||||
|
_ => Err(serde::de::Error::unknown_field(value, FIELDS)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deserializer.deserialize_identifier(GeneratedVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct GeneratedVisitor;
|
||||||
|
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
|
||||||
|
type Value = StateChanged;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
formatter.write_str("struct torrent.StateChanged")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<V>(self, mut map_: V) -> std::result::Result<StateChanged, V::Error>
|
||||||
|
where
|
||||||
|
V: serde::de::MapAccess<'de>,
|
||||||
|
{
|
||||||
|
let mut previous__ = None;
|
||||||
|
let mut current__ = None;
|
||||||
|
while let Some(k) = map_.next_key()? {
|
||||||
|
match k {
|
||||||
|
GeneratedField::Previous => {
|
||||||
|
if previous__.is_some() {
|
||||||
|
return Err(serde::de::Error::duplicate_field("previous"));
|
||||||
|
}
|
||||||
|
previous__ = Some(map_.next_value::<State>()? as i32);
|
||||||
|
}
|
||||||
|
GeneratedField::Current => {
|
||||||
|
if current__.is_some() {
|
||||||
|
return Err(serde::de::Error::duplicate_field("current"));
|
||||||
|
}
|
||||||
|
current__ = Some(map_.next_value::<State>()? as i32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(StateChanged {
|
||||||
|
previous: previous__.unwrap_or_default(),
|
||||||
|
current: current__.unwrap_or_default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deserializer.deserialize_struct("torrent.StateChanged", FIELDS, GeneratedVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl serde::Serialize for StatusRequest {
|
impl serde::Serialize for StatusRequest {
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||||
|
|||||||
@@ -173,6 +173,23 @@ pub mod torrents_client {
|
|||||||
.insert(GrpcMethod::new("torrent.Torrents", "Resume"));
|
.insert(GrpcMethod::new("torrent.Torrents", "Resume"));
|
||||||
self.inner.unary(req, path, codec).await
|
self.inner.unary(req, path, codec).await
|
||||||
}
|
}
|
||||||
|
pub async fn notifications(
|
||||||
|
&mut self,
|
||||||
|
request: impl tonic::IntoRequest<super::NotificationsRequest>,
|
||||||
|
) -> std::result::Result<
|
||||||
|
tonic::Response<tonic::codec::Streaming<super::Notification>>,
|
||||||
|
tonic::Status,
|
||||||
|
> {
|
||||||
|
self.inner.ready().await.map_err(|e| {
|
||||||
|
tonic::Status::unknown(format!("Service was not ready: {}", e.into()))
|
||||||
|
})?;
|
||||||
|
let codec = tonic_prost::ProstCodec::default();
|
||||||
|
let path = http::uri::PathAndQuery::from_static("/torrent.Torrents/Notifications");
|
||||||
|
let mut req = request.into_request();
|
||||||
|
req.extensions_mut()
|
||||||
|
.insert(GrpcMethod::new("torrent.Torrents", "Notifications"));
|
||||||
|
self.inner.server_streaming(req, path, codec).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Generated server implementations.
|
/// Generated server implementations.
|
||||||
@@ -212,6 +229,15 @@ pub mod torrents_server {
|
|||||||
&self,
|
&self,
|
||||||
request: tonic::Request<super::ResumeRequest>,
|
request: tonic::Request<super::ResumeRequest>,
|
||||||
) -> std::result::Result<tonic::Response<super::ResumeResponse>, tonic::Status>;
|
) -> std::result::Result<tonic::Response<super::ResumeResponse>, tonic::Status>;
|
||||||
|
/// Server streaming response type for the Notifications method.
|
||||||
|
type NotificationsStream: tonic::codegen::tokio_stream::Stream<
|
||||||
|
Item = std::result::Result<super::Notification, tonic::Status>,
|
||||||
|
> + std::marker::Send
|
||||||
|
+ 'static;
|
||||||
|
async fn notifications(
|
||||||
|
&self,
|
||||||
|
request: tonic::Request<super::NotificationsRequest>,
|
||||||
|
) -> std::result::Result<tonic::Response<Self::NotificationsStream>, tonic::Status>;
|
||||||
}
|
}
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TorrentsServer<T> {
|
pub struct TorrentsServer<T> {
|
||||||
@@ -508,6 +534,50 @@ pub mod torrents_server {
|
|||||||
};
|
};
|
||||||
Box::pin(fut)
|
Box::pin(fut)
|
||||||
}
|
}
|
||||||
|
"/torrent.Torrents/Notifications" => {
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
struct NotificationsSvc<T: Torrents>(pub Arc<T>);
|
||||||
|
impl<T: Torrents>
|
||||||
|
tonic::server::ServerStreamingService<super::NotificationsRequest>
|
||||||
|
for NotificationsSvc<T>
|
||||||
|
{
|
||||||
|
type Response = super::Notification;
|
||||||
|
type ResponseStream = T::NotificationsStream;
|
||||||
|
type Future =
|
||||||
|
BoxFuture<tonic::Response<Self::ResponseStream>, tonic::Status>;
|
||||||
|
fn call(
|
||||||
|
&mut self,
|
||||||
|
request: tonic::Request<super::NotificationsRequest>,
|
||||||
|
) -> Self::Future {
|
||||||
|
let inner = Arc::clone(&self.0);
|
||||||
|
let fut = async move {
|
||||||
|
<T as Torrents>::notifications(&inner, request).await
|
||||||
|
};
|
||||||
|
Box::pin(fut)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let accept_compression_encodings = self.accept_compression_encodings;
|
||||||
|
let send_compression_encodings = self.send_compression_encodings;
|
||||||
|
let max_decoding_message_size = self.max_decoding_message_size;
|
||||||
|
let max_encoding_message_size = self.max_encoding_message_size;
|
||||||
|
let inner = self.inner.clone();
|
||||||
|
let fut = async move {
|
||||||
|
let method = NotificationsSvc(inner);
|
||||||
|
let codec = tonic_prost::ProstCodec::default();
|
||||||
|
let mut grpc = tonic::server::Grpc::new(codec)
|
||||||
|
.apply_compression_config(
|
||||||
|
accept_compression_encodings,
|
||||||
|
send_compression_encodings,
|
||||||
|
)
|
||||||
|
.apply_max_message_size_config(
|
||||||
|
max_decoding_message_size,
|
||||||
|
max_encoding_message_size,
|
||||||
|
);
|
||||||
|
let res = grpc.server_streaming(method, req).await;
|
||||||
|
Ok(res)
|
||||||
|
};
|
||||||
|
Box::pin(fut)
|
||||||
|
}
|
||||||
_ => Box::pin(async move {
|
_ => Box::pin(async move {
|
||||||
let mut response = http::Response::new(tonic::body::Body::default());
|
let mut response = http::Response::new(tonic::body::Body::default());
|
||||||
let headers = response.headers_mut();
|
let headers = response.headers_mut();
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ pub mod torrent {
|
|||||||
include!("generated/torrent/torrent.rs");
|
include!("generated/torrent/torrent.rs");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use torrent::notification as notification_detail;
|
||||||
pub use torrent::{
|
pub use torrent::{
|
||||||
AddRequest, AddResponse, ListRequest, ListResponse, PauseRequest, PauseResponse, RemoveRequest,
|
AddRequest, AddResponse, AddedInfo, ListRequest, ListResponse, Notification, NotificationKind,
|
||||||
RemoveResponse, ResumeRequest, ResumeResponse, State, StatusRequest, TorrentStatus,
|
NotificationsRequest, PauseRequest, PauseResponse, ProgressMark, RemoveRequest, RemoveResponse,
|
||||||
|
RemovedInfo, ResumeRequest, ResumeResponse, State, StateChanged, StatusRequest, TorrentStatus,
|
||||||
torrents_client::TorrentsClient,
|
torrents_client::TorrentsClient,
|
||||||
torrents_server::{Torrents, TorrentsServer},
|
torrents_server::{Torrents, TorrentsServer},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,12 +5,14 @@ edition = "2024"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.103"
|
anyhow = "1.0.103"
|
||||||
|
chrono = { version = "0.4", default-features = false, features = ["clock"] }
|
||||||
clap = { version = "4.6.1", features = ["derive", "env"] }
|
clap = { version = "4.6.1", features = ["derive", "env"] }
|
||||||
colored = "3"
|
colored = "3"
|
||||||
hyper-util = { version = "0.1.20", features = ["tokio"] }
|
hyper-util = { version = "0.1.20", features = ["tokio"] }
|
||||||
nix = { version = "0.31", features = ["signal"] }
|
nix = { version = "0.31", features = ["signal"] }
|
||||||
serde_json = "1.0.140"
|
serde_json = "1.0.140"
|
||||||
tokio = { version = "1.52.3", features = ["rt-multi-thread", "macros", "net"] }
|
tokio = { version = "1.52.3", features = ["rt-multi-thread", "macros", "net", "signal"] }
|
||||||
|
tokio-stream = "0.1.18"
|
||||||
tonic = "0.14.6"
|
tonic = "0.14.6"
|
||||||
tonic-health = "0.14.6"
|
tonic-health = "0.14.6"
|
||||||
tora-proto = { version = "0.1.0", path = "../proto" }
|
tora-proto = { version = "0.1.0", path = "../proto" }
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use clap::{Parser, Subcommand, ValueEnum};
|
use clap::{Parser, Subcommand, ValueEnum};
|
||||||
|
use tora_proto::NotificationKind;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(
|
#[command(
|
||||||
@@ -43,6 +44,31 @@ pub enum SortKey {
|
|||||||
Added,
|
Added,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// CLI-facing mirror of `NotificationKind` so `clap`'s `ValueEnum` derive can
|
||||||
|
/// enumerate the values. Mapped back to the proto enum via `to_proto`.
|
||||||
|
#[derive(Copy, Clone, Debug, ValueEnum)]
|
||||||
|
pub enum KindFilter {
|
||||||
|
/// `TORRENT_ADDED`
|
||||||
|
Added,
|
||||||
|
/// `TORRENT_REMOVED`
|
||||||
|
Removed,
|
||||||
|
/// `STATE_CHANGED` (includes DOWNLOADING <-> STALE, * -> FINISHED, etc.)
|
||||||
|
StateChanged,
|
||||||
|
/// `PROGRESS` (one event per integer percent advance)
|
||||||
|
Progress,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KindFilter {
|
||||||
|
pub fn to_proto(self) -> i32 {
|
||||||
|
match self {
|
||||||
|
KindFilter::Added => NotificationKind::TorrentAdded as i32,
|
||||||
|
KindFilter::Removed => NotificationKind::TorrentRemoved as i32,
|
||||||
|
KindFilter::StateChanged => NotificationKind::StateChanged as i32,
|
||||||
|
KindFilter::Progress => NotificationKind::Progress as i32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
/// Check whether torad is reachable and healthy.
|
/// Check whether torad is reachable and healthy.
|
||||||
@@ -95,4 +121,15 @@ pub enum Command {
|
|||||||
},
|
},
|
||||||
/// Stop the torad daemon.
|
/// Stop the torad daemon.
|
||||||
Stop,
|
Stop,
|
||||||
|
/// Stream torrent notifications live from torad. Runs until interrupted
|
||||||
|
/// (Ctrl-C) or the daemon disconnects.
|
||||||
|
Watch {
|
||||||
|
/// Filter to these torrent ids (UUIDs or unique prefixes). Repeatable.
|
||||||
|
/// Omit to observe all torrents.
|
||||||
|
#[arg(long = "id", value_name = "ID")]
|
||||||
|
ids: Vec<String>,
|
||||||
|
/// Only emit these event kinds. Repeatable. Omit for all kinds.
|
||||||
|
#[arg(long = "kind", value_enum)]
|
||||||
|
kinds: Vec<KindFilter>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-3
@@ -6,17 +6,18 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use cli::{Cli, Command, SortKey};
|
use cli::{Cli, Command, KindFilter, SortKey};
|
||||||
use hyper_util::rt::TokioIo;
|
use hyper_util::rt::TokioIo;
|
||||||
use output::Formatter;
|
use output::Formatter;
|
||||||
use tokio::net::UnixStream;
|
use tokio::net::UnixStream;
|
||||||
|
use tokio_stream::StreamExt;
|
||||||
use tonic::transport::{Channel, Endpoint, Uri};
|
use tonic::transport::{Channel, Endpoint, Uri};
|
||||||
use tonic_health::pb::HealthCheckRequest;
|
use tonic_health::pb::HealthCheckRequest;
|
||||||
use tonic_health::pb::health_check_response::ServingStatus;
|
use tonic_health::pb::health_check_response::ServingStatus;
|
||||||
use tonic_health::pb::health_client::HealthClient;
|
use tonic_health::pb::health_client::HealthClient;
|
||||||
use tora_proto::{
|
use tora_proto::{
|
||||||
AddRequest, ListRequest, PauseRequest, RemoveRequest, ResumeRequest, StatusRequest,
|
AddRequest, ListRequest, NotificationsRequest, PauseRequest, RemoveRequest, ResumeRequest,
|
||||||
TorrentsClient,
|
StatusRequest, TorrentsClient,
|
||||||
};
|
};
|
||||||
use tower::service_fn;
|
use tower::service_fn;
|
||||||
|
|
||||||
@@ -51,6 +52,7 @@ async fn main() -> Result<()> {
|
|||||||
download_dir,
|
download_dir,
|
||||||
} => start_daemon(&socket, &pid_file, &database_url, download_dir, f).await,
|
} => start_daemon(&socket, &pid_file, &database_url, download_dir, f).await,
|
||||||
Command::Stop => stop_daemon(&socket, &pid_file, f).await,
|
Command::Stop => stop_daemon(&socket, &pid_file, f).await,
|
||||||
|
Command::Watch { ids, kinds } => watch(&socket, ids, kinds, f).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,3 +271,44 @@ async fn stop_daemon(socket: &Path, pid_file: &Path, f: &dyn Formatter) -> Resul
|
|||||||
Err(err) => Err(err).context("failed to send SIGTERM to torad"),
|
Err(err) => Err(err).context("failed to send SIGTERM to torad"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn watch(
|
||||||
|
socket: &Path,
|
||||||
|
ids: Vec<String>,
|
||||||
|
kinds: Vec<KindFilter>,
|
||||||
|
f: &dyn Formatter,
|
||||||
|
) -> Result<()> {
|
||||||
|
let channel = connect(socket).await?;
|
||||||
|
let mut client = TorrentsClient::new(channel);
|
||||||
|
|
||||||
|
let request = NotificationsRequest {
|
||||||
|
ids,
|
||||||
|
kinds: kinds.iter().map(|k| k.to_proto()).collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let stream = client
|
||||||
|
.notifications(request)
|
||||||
|
.await
|
||||||
|
.context("Notifications RPC failed")?
|
||||||
|
.into_inner();
|
||||||
|
|
||||||
|
tokio::pin!(stream);
|
||||||
|
|
||||||
|
let stdout = std::io::stdout();
|
||||||
|
while let Some(message) = stream.next().await {
|
||||||
|
match message {
|
||||||
|
Ok(notification) => {
|
||||||
|
let line = f.watch(¬ification)?;
|
||||||
|
let mut guard = stdout.lock();
|
||||||
|
use std::io::Write;
|
||||||
|
writeln!(guard, "{line}")?;
|
||||||
|
guard.flush()?;
|
||||||
|
}
|
||||||
|
Err(status) => {
|
||||||
|
anyhow::bail!("stream error: {status}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
+109
-1
@@ -1,8 +1,12 @@
|
|||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use chrono::{Local, TimeZone};
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use tora_proto::{State, TorrentStatus};
|
use tora_proto::{
|
||||||
|
Notification, NotificationKind, ProgressMark, State, StateChanged, TorrentStatus,
|
||||||
|
notification_detail::Detail,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::cli::OutputFormat;
|
use crate::cli::OutputFormat;
|
||||||
|
|
||||||
@@ -18,6 +22,7 @@ pub trait Formatter {
|
|||||||
fn resume(&self) -> Result<String>;
|
fn resume(&self) -> Result<String>;
|
||||||
fn start(&self) -> Result<String>;
|
fn start(&self) -> Result<String>;
|
||||||
fn stop(&self) -> Result<String>;
|
fn stop(&self) -> Result<String>;
|
||||||
|
fn watch(&self, event: &Notification) -> Result<String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_format(format: OutputFormat) -> Box<dyn Formatter> {
|
pub fn from_format(format: OutputFormat) -> Box<dyn Formatter> {
|
||||||
@@ -77,6 +82,10 @@ impl Formatter for LongFormatter {
|
|||||||
fn stop(&self) -> Result<String> {
|
fn stop(&self) -> Result<String> {
|
||||||
Ok(format!(" {} torad stopped", "●".yellow()))
|
Ok(format!(" {} torad stopped", "●".yellow()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn watch(&self, event: &Notification) -> Result<String> {
|
||||||
|
Ok(format_event_long(event))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct JsonFormatter;
|
struct JsonFormatter;
|
||||||
@@ -130,6 +139,10 @@ impl Formatter for JsonFormatter {
|
|||||||
&serde_json::json!({ "stopped": true }),
|
&serde_json::json!({ "stopped": true }),
|
||||||
)?)
|
)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn watch(&self, event: &Notification) -> Result<String> {
|
||||||
|
Ok(serde_json::to_string(event)?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_status_long(status: &TorrentStatus) -> String {
|
fn format_status_long(status: &TorrentStatus) -> String {
|
||||||
@@ -216,6 +229,99 @@ fn format_status_long(status: &TorrentStatus) -> String {
|
|||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn format_event_long(event: &Notification) -> String {
|
||||||
|
let time = Local
|
||||||
|
.timestamp_millis_opt(event.observed_at_unix_millis as i64)
|
||||||
|
.single()
|
||||||
|
.map(|t| t.format("%H:%M:%S").to_string())
|
||||||
|
.unwrap_or_else(|| "??".to_string());
|
||||||
|
|
||||||
|
let kind = NotificationKind::try_from(event.kind).unwrap_or(NotificationKind::Unspecified);
|
||||||
|
let torrent = event.torrent.as_ref();
|
||||||
|
let id = torrent.map(|t| short_id(&t.id)).unwrap_or_default();
|
||||||
|
let name = torrent
|
||||||
|
.map(|t| display_name(&t.name))
|
||||||
|
.unwrap_or_else(|| "(unknown)".to_string());
|
||||||
|
let state = torrent
|
||||||
|
.and_then(|t| State::try_from(t.state).ok())
|
||||||
|
.unwrap_or(State::Unspecified);
|
||||||
|
|
||||||
|
let id_w = 8usize;
|
||||||
|
let name_w = 30usize;
|
||||||
|
|
||||||
|
let (icon, suffix) = match (&kind, event.detail.as_ref()) {
|
||||||
|
(NotificationKind::TorrentAdded, _) => ("+".green(), String::new()),
|
||||||
|
(NotificationKind::TorrentRemoved, Some(Detail::Removed(r))) => {
|
||||||
|
let note = if r.files_deleted {
|
||||||
|
" (files deleted)"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
("−".red(), format!("{}{}", colored_state(state), note.red()))
|
||||||
|
}
|
||||||
|
(NotificationKind::TorrentRemoved, _) => ("−".red(), colored_state(state).to_string()),
|
||||||
|
(
|
||||||
|
NotificationKind::StateChanged,
|
||||||
|
Some(Detail::StateChanged(StateChanged { current, .. })),
|
||||||
|
) => {
|
||||||
|
let cur = State::try_from(*current).unwrap_or(State::Unspecified);
|
||||||
|
let icon = state_icon(cur);
|
||||||
|
(icon, colored_state(cur).to_string())
|
||||||
|
}
|
||||||
|
(
|
||||||
|
NotificationKind::Progress,
|
||||||
|
Some(Detail::Progress(ProgressMark {
|
||||||
|
percent,
|
||||||
|
bytes_delta,
|
||||||
|
})),
|
||||||
|
) => {
|
||||||
|
let delta = humanize_bytes(*bytes_delta);
|
||||||
|
let pct_bar = format_pct_inline(*percent);
|
||||||
|
(
|
||||||
|
"↑".yellow(),
|
||||||
|
format!(
|
||||||
|
"{} {} {}",
|
||||||
|
pct_bar.yellow(),
|
||||||
|
format!("{}%", percent).bold(),
|
||||||
|
format!("(Δ {delta})").dimmed()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
(_, _) => ("·".dimmed(), colored_state(state).to_string()),
|
||||||
|
};
|
||||||
|
|
||||||
|
format!(
|
||||||
|
" {} {} {} {} {}",
|
||||||
|
time.dimmed(),
|
||||||
|
icon,
|
||||||
|
pad(&id, id_w).dimmed(),
|
||||||
|
pad(&name, name_w),
|
||||||
|
suffix,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state_icon(state: State) -> colored::ColoredString {
|
||||||
|
match state {
|
||||||
|
State::Finished => "✓".green(),
|
||||||
|
State::Downloading => "▶".yellow(),
|
||||||
|
State::Paused => "⏸".cyan(),
|
||||||
|
State::Error => "✗".red(),
|
||||||
|
State::Stale => "⚠".red(),
|
||||||
|
State::Pending | State::Unspecified => "·".dimmed(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_pct_inline(percent: u32) -> String {
|
||||||
|
let filled = (percent as usize * BAR_WIDTH) / 100;
|
||||||
|
let empty = BAR_WIDTH - filled;
|
||||||
|
format!(
|
||||||
|
"{}{} {:>3}%",
|
||||||
|
"█".repeat(filled),
|
||||||
|
"░".repeat(empty),
|
||||||
|
percent
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn format_list_long(torrents: &[TorrentStatus]) -> String {
|
fn format_list_long(torrents: &[TorrentStatus]) -> String {
|
||||||
if torrents.is_empty() {
|
if torrents.is_empty() {
|
||||||
return " no torrents".dimmed().to_string();
|
return " no torrents".dimmed().to_string();
|
||||||
@@ -301,6 +407,7 @@ fn colored_state(state: State) -> colored::ColoredString {
|
|||||||
State::Downloading => s.yellow(),
|
State::Downloading => s.yellow(),
|
||||||
State::Paused => s.cyan(),
|
State::Paused => s.cyan(),
|
||||||
State::Error => s.red().bold(),
|
State::Error => s.red().bold(),
|
||||||
|
State::Stale => s.red(),
|
||||||
State::Pending | State::Unspecified => s.dimmed(),
|
State::Pending | State::Unspecified => s.dimmed(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -312,6 +419,7 @@ fn pad_colored(s: &str, width: usize, state: State) -> colored::ColoredString {
|
|||||||
State::Downloading => padded.yellow(),
|
State::Downloading => padded.yellow(),
|
||||||
State::Paused => padded.cyan(),
|
State::Paused => padded.cyan(),
|
||||||
State::Error => padded.red().bold(),
|
State::Error => padded.red().bold(),
|
||||||
|
State::Stale => padded.red(),
|
||||||
State::Pending | State::Unspecified => padded.dimmed(),
|
State::Pending | State::Unspecified => padded.dimmed(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-5
@@ -23,6 +23,7 @@ pub enum TorrentState {
|
|||||||
Paused,
|
Paused,
|
||||||
Finished,
|
Finished,
|
||||||
Error,
|
Error,
|
||||||
|
Stale,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, sqlx::FromRow)]
|
#[derive(Debug, Clone, sqlx::FromRow)]
|
||||||
@@ -126,8 +127,12 @@ pub struct Progress<'a> {
|
|||||||
pub error_message: Option<&'a str>,
|
pub error_message: Option<&'a str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_progress(pool: &PgPool, id: Uuid, progress: Progress<'_>) -> Result<()> {
|
pub async fn update_progress(
|
||||||
sqlx::query(
|
pool: &PgPool,
|
||||||
|
id: Uuid,
|
||||||
|
progress: Progress<'_>,
|
||||||
|
) -> Result<TorrentRow> {
|
||||||
|
let row = sqlx::query_as::<_, TorrentRow>(
|
||||||
"UPDATE torrents
|
"UPDATE torrents
|
||||||
SET name = COALESCE($2, name),
|
SET name = COALESCE($2, name),
|
||||||
total_bytes = $3,
|
total_bytes = $3,
|
||||||
@@ -136,7 +141,8 @@ pub async fn update_progress(pool: &PgPool, id: Uuid, progress: Progress<'_>) ->
|
|||||||
error_message = $6,
|
error_message = $6,
|
||||||
updated_at = now(),
|
updated_at = now(),
|
||||||
completed_at = CASE WHEN $5 = 'finished' THEN now() ELSE completed_at END
|
completed_at = CASE WHEN $5 = 'finished' THEN now() ELSE completed_at END
|
||||||
WHERE id = $1",
|
WHERE id = $1
|
||||||
|
RETURNING id, info_hash, name, source, output_path, total_bytes, downloaded_bytes, state, error_message",
|
||||||
)
|
)
|
||||||
.bind(id)
|
.bind(id)
|
||||||
.bind(progress.name)
|
.bind(progress.name)
|
||||||
@@ -144,7 +150,7 @@ pub async fn update_progress(pool: &PgPool, id: Uuid, progress: Progress<'_>) ->
|
|||||||
.bind(progress.downloaded_bytes)
|
.bind(progress.downloaded_bytes)
|
||||||
.bind(progress.state)
|
.bind(progress.state)
|
||||||
.bind(progress.error_message)
|
.bind(progress.error_message)
|
||||||
.execute(pool)
|
.fetch_one(pool)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(row)
|
||||||
}
|
}
|
||||||
|
|||||||
+491
-27
@@ -1,19 +1,20 @@
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use librqbit::api::TorrentIdOrHash;
|
use librqbit::api::TorrentIdOrHash;
|
||||||
use librqbit::{AddTorrent, AddTorrentOptions, ManagedTorrent, Session, TorrentStatsState};
|
use librqbit::{AddTorrent, AddTorrentOptions, ManagedTorrent, Session, TorrentStatsState};
|
||||||
use librqbit_core::Id20;
|
use librqbit_core::Id20;
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::{Mutex, broadcast};
|
||||||
use tonic::{Request, Response, Status};
|
use tonic::{Request, Response, Status};
|
||||||
use tora_proto::{
|
use tora_proto::{
|
||||||
AddRequest, AddResponse, ListRequest, ListResponse, PauseRequest, PauseResponse, RemoveRequest,
|
AddRequest, AddResponse, AddedInfo, ListRequest, ListResponse, Notification, NotificationKind,
|
||||||
RemoveResponse, ResumeRequest, ResumeResponse, State as ProtoState, StatusRequest,
|
NotificationsRequest, PauseRequest, PauseResponse, ProgressMark, RemoveRequest, RemoveResponse,
|
||||||
TorrentStatus, Torrents,
|
ResumeRequest, ResumeResponse, State as ProtoState, StateChanged, StatusRequest, TorrentStatus,
|
||||||
|
Torrents,
|
||||||
};
|
};
|
||||||
use tracing::{error, info, warn};
|
use tracing::{error, info, warn};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@@ -24,6 +25,14 @@ use crate::source::SourceResolver;
|
|||||||
const POLL_INTERVAL: Duration = Duration::from_secs(2);
|
const POLL_INTERVAL: Duration = Duration::from_secs(2);
|
||||||
const ADD_TIMEOUT: Duration = Duration::from_secs(60);
|
const ADD_TIMEOUT: Duration = Duration::from_secs(60);
|
||||||
const BYTES_PER_MIB: f64 = 1_048_576.0;
|
const BYTES_PER_MIB: f64 = 1_048_576.0;
|
||||||
|
/// `broadcast` channel capacity. Subscribers that fall more than this many
|
||||||
|
/// events behind receive `Lagged` errors and continue. Picked for ~5 s of
|
||||||
|
/// slack at the maximum realistic emit rate (~50 events/sec).
|
||||||
|
const EVENT_CHANNEL_CAPACITY: usize = 256;
|
||||||
|
/// Consecutive poller ticks a `Live && !finished` torrent must show no byte
|
||||||
|
/// progress AND zero connected peers before being flipped to `Stale`.
|
||||||
|
/// At a 2 s `POLL_INTERVAL`, this is 6 s of inactivity.
|
||||||
|
const STALE_TICKS_THRESHOLD: u32 = 3;
|
||||||
|
|
||||||
pub enum ResolveError {
|
pub enum ResolveError {
|
||||||
NotFound,
|
NotFound,
|
||||||
@@ -38,6 +47,8 @@ pub struct TorrentManager {
|
|||||||
source: SourceResolver,
|
source: SourceResolver,
|
||||||
tracked: Mutex<HashMap<Uuid, Arc<ManagedTorrent>>>,
|
tracked: Mutex<HashMap<Uuid, Arc<ManagedTorrent>>>,
|
||||||
adding: Mutex<HashSet<Uuid>>,
|
adding: Mutex<HashSet<Uuid>>,
|
||||||
|
events: broadcast::Sender<Notification>,
|
||||||
|
poll_cache: Mutex<HashMap<Uuid, PollCache>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TorrentManager {
|
impl TorrentManager {
|
||||||
@@ -52,6 +63,7 @@ impl TorrentManager {
|
|||||||
.await
|
.await
|
||||||
.context("failed to create librqbit session")?;
|
.context("failed to create librqbit session")?;
|
||||||
let source = SourceResolver::new().context("failed to build source resolver")?;
|
let source = SourceResolver::new().context("failed to build source resolver")?;
|
||||||
|
let (events, _) = broadcast::channel(EVENT_CHANNEL_CAPACITY);
|
||||||
Ok(Arc::new(Self {
|
Ok(Arc::new(Self {
|
||||||
pool,
|
pool,
|
||||||
session,
|
session,
|
||||||
@@ -59,9 +71,22 @@ impl TorrentManager {
|
|||||||
source,
|
source,
|
||||||
tracked: Mutex::new(HashMap::new()),
|
tracked: Mutex::new(HashMap::new()),
|
||||||
adding: Mutex::new(HashSet::new()),
|
adding: Mutex::new(HashSet::new()),
|
||||||
|
events,
|
||||||
|
poll_cache: Mutex::new(HashMap::new()),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subscribe(&self) -> broadcast::Receiver<Notification> {
|
||||||
|
self.events.subscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn notify(&self, mut notification: Notification) {
|
||||||
|
if notification.observed_at_unix_millis == 0 {
|
||||||
|
notification.observed_at_unix_millis = now_millis();
|
||||||
|
}
|
||||||
|
let _ = self.events.send(notification);
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn add(&self, source: &str, output_dir: Option<&str>) -> Result<TorrentRow> {
|
pub async fn add(&self, source: &str, output_dir: Option<&str>) -> Result<TorrentRow> {
|
||||||
let resolved = self.source.resolve(source).await?;
|
let resolved = self.source.resolve(source).await?;
|
||||||
let stored_source = resolved.rewritten_source.as_deref().unwrap_or(source);
|
let stored_source = resolved.rewritten_source.as_deref().unwrap_or(source);
|
||||||
@@ -263,30 +288,158 @@ impl TorrentManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn report_progress(&self) {
|
async fn report_progress(&self) {
|
||||||
let tracked = self.tracked.lock().await;
|
// Snapshot stats under a brief lock; do all DB work and emission outside.
|
||||||
for (id, handle) in tracked.iter() {
|
let snapshots: Vec<(Uuid, librqbit::TorrentStats, Option<String>)> = {
|
||||||
let stats = handle.stats();
|
let tracked = self.tracked.lock().await;
|
||||||
let name = handle.name();
|
tracked
|
||||||
let state = if stats.finished {
|
.iter()
|
||||||
TorrentState::Finished
|
.map(|(id, handle)| (*id, handle.stats(), handle.name()))
|
||||||
} else {
|
.collect()
|
||||||
match stats.state {
|
};
|
||||||
TorrentStatsState::Initializing => TorrentState::Pending,
|
|
||||||
TorrentStatsState::Live => TorrentState::Downloading,
|
for (id, stats, name) in snapshots {
|
||||||
TorrentStatsState::Paused => TorrentState::Paused,
|
let raw_state = raw_state_from_stats(&stats);
|
||||||
TorrentStatsState::Error => TorrentState::Error,
|
let live = live_stats_from_stats(&stats);
|
||||||
}
|
|
||||||
};
|
let (final_state, prev_state_proto, percent, bytes_delta, state_changed) = self
|
||||||
|
.diff_and_update_cache(
|
||||||
|
id,
|
||||||
|
raw_state,
|
||||||
|
stats.progress_bytes,
|
||||||
|
live.peers,
|
||||||
|
stats.total_bytes,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
let progress = db::Progress {
|
let progress = db::Progress {
|
||||||
name: name.as_deref(),
|
name: name.as_deref(),
|
||||||
total_bytes: i64::try_from(stats.total_bytes).unwrap_or(i64::MAX),
|
total_bytes: i64::try_from(stats.total_bytes).unwrap_or(i64::MAX),
|
||||||
downloaded_bytes: i64::try_from(stats.progress_bytes).unwrap_or(i64::MAX),
|
downloaded_bytes: i64::try_from(stats.progress_bytes).unwrap_or(i64::MAX),
|
||||||
state,
|
state: final_state,
|
||||||
error_message: stats.error.as_deref(),
|
error_message: stats.error.as_deref(),
|
||||||
};
|
};
|
||||||
if let Err(err) = db::update_progress(&self.pool, *id, progress).await {
|
let row = match db::update_progress(&self.pool, id, progress).await {
|
||||||
error!(id = %id, error = %err, "failed to persist torrent progress");
|
Ok(row) => row,
|
||||||
|
Err(err) => {
|
||||||
|
error!(id = %id, error = %err, "failed to persist torrent progress");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let status = row_to_status(row, live);
|
||||||
|
|
||||||
|
if state_changed {
|
||||||
|
self.notify(Notification {
|
||||||
|
observed_at_unix_millis: 0,
|
||||||
|
kind: NotificationKind::StateChanged as i32,
|
||||||
|
torrent: Some(status.clone()),
|
||||||
|
detail: Some(tora_proto::notification_detail::Detail::StateChanged(
|
||||||
|
StateChanged {
|
||||||
|
previous: prev_state_proto as i32,
|
||||||
|
current: status.state,
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(delta) = bytes_delta {
|
||||||
|
self.notify(Notification {
|
||||||
|
observed_at_unix_millis: 0,
|
||||||
|
kind: NotificationKind::Progress as i32,
|
||||||
|
torrent: Some(status),
|
||||||
|
detail: Some(tora_proto::notification_detail::Detail::Progress(
|
||||||
|
ProgressMark {
|
||||||
|
percent,
|
||||||
|
bytes_delta: delta,
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates `poll_cache` for `id` from this tick's observation and returns
|
||||||
|
/// the data needed to emit notifications. Returns
|
||||||
|
/// `(final_state, previous_proto_state, percent, Option<bytes_delta>, state_changed)`.
|
||||||
|
async fn diff_and_update_cache(
|
||||||
|
&self,
|
||||||
|
id: Uuid,
|
||||||
|
raw_state: TorrentState,
|
||||||
|
progress_bytes: u64,
|
||||||
|
live_peers: u32,
|
||||||
|
total_bytes: u64,
|
||||||
|
) -> (TorrentState, ProtoState, u32, Option<u64>, bool) {
|
||||||
|
let mut poll_cache = self.poll_cache.lock().await;
|
||||||
|
let cache = poll_cache
|
||||||
|
.entry(id)
|
||||||
|
.or_insert_with(|| PollCache::new(proto_state(raw_state)));
|
||||||
|
compute_diff(cache, raw_state, progress_bytes, live_peers, total_bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pure diff/staleness logic. Updates `cache` in place and returns
|
||||||
|
/// `(final_state, previous_proto_state, percent, Option<bytes_delta>, state_changed)`.
|
||||||
|
/// Extracted from `diff_and_update_cache` so it can be unit-tested without a
|
||||||
|
/// live TorrentManager (which needs Postgres + librqbit session).
|
||||||
|
fn compute_diff(
|
||||||
|
cache: &mut PollCache,
|
||||||
|
raw_state: TorrentState,
|
||||||
|
progress_bytes: u64,
|
||||||
|
live_peers: u32,
|
||||||
|
total_bytes: u64,
|
||||||
|
) -> (TorrentState, ProtoState, u32, Option<u64>, bool) {
|
||||||
|
if raw_state == TorrentState::Downloading {
|
||||||
|
if progress_bytes == cache.last_bytes {
|
||||||
|
cache.stale_ticks = cache.stale_ticks.saturating_add(1);
|
||||||
|
} else {
|
||||||
|
cache.stale_ticks = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cache.stale_ticks = 0;
|
||||||
|
}
|
||||||
|
cache.last_bytes = progress_bytes;
|
||||||
|
|
||||||
|
let final_state = if raw_state == TorrentState::Downloading
|
||||||
|
&& cache.stale_ticks >= STALE_TICKS_THRESHOLD
|
||||||
|
&& live_peers == 0
|
||||||
|
{
|
||||||
|
TorrentState::Stale
|
||||||
|
} else {
|
||||||
|
raw_state
|
||||||
|
};
|
||||||
|
|
||||||
|
let prev_proto = cache.last_state;
|
||||||
|
let final_proto = proto_state(final_state);
|
||||||
|
let state_changed = prev_proto != final_proto;
|
||||||
|
cache.last_state = final_proto;
|
||||||
|
|
||||||
|
// u128 mul to avoid overflow on multi-exabyte totals; cap at 100.
|
||||||
|
let percent = if total_bytes == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
((progress_bytes as u128 * 100 / total_bytes as u128) as u32).min(100)
|
||||||
|
};
|
||||||
|
let bytes_delta = if percent != cache.last_percent {
|
||||||
|
let delta = progress_bytes.saturating_sub(cache.bytes_at_last_progress);
|
||||||
|
cache.last_percent = percent;
|
||||||
|
cache.bytes_at_last_progress = progress_bytes;
|
||||||
|
Some(delta)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
(final_state, prev_proto, percent, bytes_delta, state_changed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn raw_state_from_stats(stats: &librqbit::TorrentStats) -> TorrentState {
|
||||||
|
if stats.finished {
|
||||||
|
TorrentState::Finished
|
||||||
|
} else {
|
||||||
|
match stats.state {
|
||||||
|
TorrentStatsState::Initializing => TorrentState::Pending,
|
||||||
|
TorrentStatsState::Live => TorrentState::Downloading,
|
||||||
|
TorrentStatsState::Paused => TorrentState::Paused,
|
||||||
|
TorrentStatsState::Error => TorrentState::Error,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -301,6 +454,34 @@ struct LiveTorrentStats {
|
|||||||
seeds: u32,
|
seeds: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct PollCache {
|
||||||
|
last_state: ProtoState,
|
||||||
|
last_percent: u32,
|
||||||
|
last_bytes: u64,
|
||||||
|
bytes_at_last_progress: u64,
|
||||||
|
stale_ticks: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PollCache {
|
||||||
|
fn new(state: ProtoState) -> Self {
|
||||||
|
Self {
|
||||||
|
last_state: state,
|
||||||
|
last_percent: 0,
|
||||||
|
last_bytes: 0,
|
||||||
|
bytes_at_last_progress: 0,
|
||||||
|
stale_ticks: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn now_millis() -> u64 {
|
||||||
|
SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.map(|d| d.as_millis() as u64)
|
||||||
|
.unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
async fn persist_error(pool: &PgPool, id: Uuid, message: &str) {
|
async fn persist_error(pool: &PgPool, id: Uuid, message: &str) {
|
||||||
let progress = db::Progress {
|
let progress = db::Progress {
|
||||||
name: None,
|
name: None,
|
||||||
@@ -318,10 +499,13 @@ fn extract_live_stats(tracked: &HashMap<Uuid, Arc<ManagedTorrent>>, id: &Uuid) -
|
|||||||
let Some(handle) = tracked.get(id) else {
|
let Some(handle) = tracked.get(id) else {
|
||||||
return LiveTorrentStats::default();
|
return LiveTorrentStats::default();
|
||||||
};
|
};
|
||||||
let stats = handle.stats();
|
live_stats_from_stats(&handle.stats())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn live_stats_from_stats(stats: &librqbit::TorrentStats) -> LiveTorrentStats {
|
||||||
let uploaded_bytes = stats.uploaded_bytes;
|
let uploaded_bytes = stats.uploaded_bytes;
|
||||||
|
|
||||||
let Some(live) = stats.live else {
|
let Some(live) = stats.live.as_ref() else {
|
||||||
return LiveTorrentStats {
|
return LiveTorrentStats {
|
||||||
uploaded_bytes,
|
uploaded_bytes,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -364,6 +548,7 @@ fn proto_state(state: TorrentState) -> ProtoState {
|
|||||||
TorrentState::Paused => ProtoState::Paused,
|
TorrentState::Paused => ProtoState::Paused,
|
||||||
TorrentState::Finished => ProtoState::Finished,
|
TorrentState::Finished => ProtoState::Finished,
|
||||||
TorrentState::Error => ProtoState::Error,
|
TorrentState::Error => ProtoState::Error,
|
||||||
|
TorrentState::Stale => ProtoState::Stale,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,9 +604,18 @@ impl Torrents for GrpcTorrents {
|
|||||||
.add(&req.magnet, output_dir)
|
.add(&req.magnet, output_dir)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| Status::internal(err.to_string()))?;
|
.map_err(|err| Status::internal(err.to_string()))?;
|
||||||
Ok(Response::new(AddResponse {
|
let id_str = row.id.to_string();
|
||||||
id: row.id.to_string(),
|
let status = row_to_status(row, LiveTorrentStats::default());
|
||||||
}))
|
let source = status.source.clone();
|
||||||
|
self.manager.notify(Notification {
|
||||||
|
observed_at_unix_millis: 0,
|
||||||
|
kind: NotificationKind::TorrentAdded as i32,
|
||||||
|
torrent: Some(status),
|
||||||
|
detail: Some(tora_proto::notification_detail::Detail::Added(AddedInfo {
|
||||||
|
source,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
Ok(Response::new(AddResponse { id: id_str }))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn status(
|
async fn status(
|
||||||
@@ -468,6 +662,17 @@ impl Torrents for GrpcTorrents {
|
|||||||
.map_err(|err| Status::internal(err.to_string()))?
|
.map_err(|err| Status::internal(err.to_string()))?
|
||||||
.ok_or_else(|| Status::not_found("torrent not found"))?;
|
.ok_or_else(|| Status::not_found("torrent not found"))?;
|
||||||
info!(id = %id, name = ?row.name, "torrent removed");
|
info!(id = %id, name = ?row.name, "torrent removed");
|
||||||
|
let status = row_to_status(row, LiveTorrentStats::default());
|
||||||
|
self.manager.notify(Notification {
|
||||||
|
observed_at_unix_millis: 0,
|
||||||
|
kind: NotificationKind::TorrentRemoved as i32,
|
||||||
|
torrent: Some(status),
|
||||||
|
detail: Some(tora_proto::notification_detail::Detail::Removed(
|
||||||
|
tora_proto::RemovedInfo {
|
||||||
|
files_deleted: req.delete_files,
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
});
|
||||||
Ok(Response::new(RemoveResponse {}))
|
Ok(Response::new(RemoveResponse {}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,4 +713,263 @@ impl Torrents for GrpcTorrents {
|
|||||||
info!(id = %id, name = ?row.name, "torrent resumed");
|
info!(id = %id, name = ?row.name, "torrent resumed");
|
||||||
Ok(Response::new(ResumeResponse {}))
|
Ok(Response::new(ResumeResponse {}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NotificationsStream =
|
||||||
|
tokio_stream::wrappers::ReceiverStream<std::result::Result<Notification, Status>>;
|
||||||
|
|
||||||
|
async fn notifications(
|
||||||
|
&self,
|
||||||
|
request: Request<NotificationsRequest>,
|
||||||
|
) -> Result<Response<Self::NotificationsStream>, Status> {
|
||||||
|
use tokio::sync::mpsc;
|
||||||
|
use tokio_stream::wrappers::ReceiverStream;
|
||||||
|
|
||||||
|
let req = request.into_inner();
|
||||||
|
|
||||||
|
// Resolve id-prefix filter once at subscribe time. If any prefix fails
|
||||||
|
// to resolve, the whole subscription is rejected — partial filters
|
||||||
|
// would surprise the client.
|
||||||
|
let allowed_ids: Option<HashSet<Uuid>> = if req.ids.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let mut set = HashSet::new();
|
||||||
|
for id_str in &req.ids {
|
||||||
|
let uuid = self.manager.resolve_id(id_str).await.map_err(resolve_err)?;
|
||||||
|
set.insert(uuid);
|
||||||
|
}
|
||||||
|
Some(set)
|
||||||
|
};
|
||||||
|
|
||||||
|
let allowed_kinds: Option<HashSet<i32>> = if req.kinds.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(req.kinds.iter().copied().collect())
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut rx = self.manager.subscribe();
|
||||||
|
let (tx, rx_stream) = mpsc::channel::<std::result::Result<Notification, Status>>(64);
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
loop {
|
||||||
|
match rx.recv().await {
|
||||||
|
Ok(notification) => {
|
||||||
|
if let Some(ref allowed) = allowed_ids
|
||||||
|
&& let Some(ref torrent) = notification.torrent
|
||||||
|
&& Uuid::parse_str(&torrent.id)
|
||||||
|
.ok()
|
||||||
|
.filter(|id| allowed.contains(id))
|
||||||
|
.is_none()
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Some(ref kinds) = allowed_kinds
|
||||||
|
&& !kinds.contains(¬ification.kind)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if tx.send(Ok(notification)).await.is_err() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(broadcast::error::RecvError::Lagged(n)) => {
|
||||||
|
warn!(skipped = n, "notifications subscriber lagged");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Err(broadcast::error::RecvError::Closed) => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(Response::new(ReceiverStream::new(rx_stream)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// A `PollCache` primed as though a prior tick already recorded
|
||||||
|
/// `bytes` at `total` size, in the Downloading state. The first
|
||||||
|
/// `compute_diff` call from a test then represents the first
|
||||||
|
/// *observation* after that baseline (not an artificial advance from 0).
|
||||||
|
fn primed_cache(bytes: u64, total: u64) -> PollCache {
|
||||||
|
let percent = if total == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
((bytes as u128 * 100 / total as u128) as u32).min(100)
|
||||||
|
};
|
||||||
|
PollCache {
|
||||||
|
last_state: ProtoState::Downloading,
|
||||||
|
last_percent: percent,
|
||||||
|
last_bytes: bytes,
|
||||||
|
bytes_at_last_progress: bytes,
|
||||||
|
stale_ticks: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `(final_state, state_changed, percent, bytes_delta)`
|
||||||
|
fn simplify(
|
||||||
|
out: (TorrentState, ProtoState, u32, Option<u64>, bool),
|
||||||
|
) -> (TorrentState, bool, u32, Option<u64>) {
|
||||||
|
(out.0, out.4, out.2, out.3)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn below_stale_threshold_stays_downloading() {
|
||||||
|
let mut cache = primed_cache(100_000, 1_000_000);
|
||||||
|
// Tick 1: stale_ticks=1.
|
||||||
|
let out = compute_diff(&mut cache, TorrentState::Downloading, 100_000, 0, 1_000_000);
|
||||||
|
assert_eq!(simplify(out), (TorrentState::Downloading, false, 10, None));
|
||||||
|
// Tick 2: stale_ticks=2.
|
||||||
|
let out = compute_diff(&mut cache, TorrentState::Downloading, 100_000, 0, 1_000_000);
|
||||||
|
assert_eq!(simplify(out), (TorrentState::Downloading, false, 10, None));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stale_triggers_at_threshold_with_zero_peers() {
|
||||||
|
let mut cache = primed_cache(100_000, 1_000_000);
|
||||||
|
// Tick 1: stale_ticks=1.
|
||||||
|
compute_diff(&mut cache, TorrentState::Downloading, 100_000, 0, 1_000_000);
|
||||||
|
// Tick 2: stale_ticks=2.
|
||||||
|
compute_diff(&mut cache, TorrentState::Downloading, 100_000, 0, 1_000_000);
|
||||||
|
// Tick 3: stale_ticks=3 → STALE.
|
||||||
|
let out = compute_diff(&mut cache, TorrentState::Downloading, 100_000, 0, 1_000_000);
|
||||||
|
assert_eq!(out.0, TorrentState::Stale);
|
||||||
|
assert_eq!(out.1, ProtoState::Downloading);
|
||||||
|
assert!(out.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn peers_above_zero_prevents_stale() {
|
||||||
|
let mut cache = primed_cache(100_000, 1_000_000);
|
||||||
|
for _ in 0..10 {
|
||||||
|
let out = compute_diff(&mut cache, TorrentState::Downloading, 100_000, 1, 1_000_000);
|
||||||
|
assert_eq!(out.0, TorrentState::Downloading);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bytes_advance_resets_stale_counter() {
|
||||||
|
let mut cache = primed_cache(100_000, 1_000_000);
|
||||||
|
// Two no-progress ticks bring stale_ticks to 2.
|
||||||
|
compute_diff(&mut cache, TorrentState::Downloading, 100_000, 0, 1_000_000);
|
||||||
|
compute_diff(&mut cache, TorrentState::Downloading, 100_000, 0, 1_000_000);
|
||||||
|
// Tick 3: bytes advance to 200 — stale_ticks resets to 0, stays Downloading.
|
||||||
|
let out = compute_diff(&mut cache, TorrentState::Downloading, 200_000, 0, 1_000_000);
|
||||||
|
assert_eq!(out.0, TorrentState::Downloading);
|
||||||
|
assert!(!out.4);
|
||||||
|
// Tick 4: no progress again, stale_ticks=1 (not threshold).
|
||||||
|
let out = compute_diff(&mut cache, TorrentState::Downloading, 200_000, 0, 1_000_000);
|
||||||
|
assert_eq!(out.0, TorrentState::Downloading);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stale_recovers_on_bytes_advance() {
|
||||||
|
let mut cache = primed_cache(100_000, 1_000_000);
|
||||||
|
// Reach STALE state.
|
||||||
|
for _ in 0..3 {
|
||||||
|
compute_diff(&mut cache, TorrentState::Downloading, 100_000, 0, 1_000_000);
|
||||||
|
}
|
||||||
|
assert_eq!(cache.last_state, ProtoState::Stale);
|
||||||
|
// Bytes advance — should recover to Downloading and emit state_changed.
|
||||||
|
let out = compute_diff(&mut cache, TorrentState::Downloading, 200_000, 0, 1_000_000);
|
||||||
|
assert_eq!(out.0, TorrentState::Downloading);
|
||||||
|
assert_eq!(out.1, ProtoState::Stale);
|
||||||
|
assert!(out.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stale_recovers_on_peer_connect() {
|
||||||
|
let mut cache = primed_cache(100_000, 1_000_000);
|
||||||
|
// Reach STALE state.
|
||||||
|
for _ in 0..3 {
|
||||||
|
compute_diff(&mut cache, TorrentState::Downloading, 100_000, 0, 1_000_000);
|
||||||
|
}
|
||||||
|
assert_eq!(cache.last_state, ProtoState::Stale);
|
||||||
|
// Peer connects (bytes unchanged).
|
||||||
|
let out = compute_diff(&mut cache, TorrentState::Downloading, 100_000, 1, 1_000_000);
|
||||||
|
assert_eq!(out.0, TorrentState::Downloading);
|
||||||
|
assert_eq!(out.1, ProtoState::Stale);
|
||||||
|
assert!(out.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stale_persists_when_nothing_changes() {
|
||||||
|
let mut cache = primed_cache(100_000, 1_000_000);
|
||||||
|
for _ in 0..3 {
|
||||||
|
compute_diff(&mut cache, TorrentState::Downloading, 100_000, 0, 1_000_000);
|
||||||
|
}
|
||||||
|
assert_eq!(cache.last_state, ProtoState::Stale);
|
||||||
|
// Subsequent tick: still no progress, still no peers.
|
||||||
|
let out = compute_diff(&mut cache, TorrentState::Downloading, 100_000, 0, 1_000_000);
|
||||||
|
assert_eq!(out.0, TorrentState::Stale);
|
||||||
|
assert!(!out.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pause_and_resume_emit_state_change() {
|
||||||
|
let mut cache = primed_cache(100_000, 1_000_000);
|
||||||
|
// Pause: raw_state changes from Downloading to Paused.
|
||||||
|
let out = compute_diff(&mut cache, TorrentState::Paused, 100_000, 0, 1_000_000);
|
||||||
|
assert_eq!(out.0, TorrentState::Paused);
|
||||||
|
assert!(out.4);
|
||||||
|
// Resume: back to Downloading.
|
||||||
|
let out = compute_diff(&mut cache, TorrentState::Downloading, 100_000, 0, 1_000_000);
|
||||||
|
assert_eq!(out.0, TorrentState::Downloading);
|
||||||
|
assert!(out.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn finished_takes_precedence_over_stale() {
|
||||||
|
let mut cache = primed_cache(100_000, 1_000_000);
|
||||||
|
let out = compute_diff(&mut cache, TorrentState::Finished, 1_000_000, 0, 1_000_000);
|
||||||
|
assert_eq!(out.0, TorrentState::Finished);
|
||||||
|
assert!(out.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn percent_change_emits_progress_with_delta() {
|
||||||
|
let mut cache = primed_cache(0, 1000);
|
||||||
|
// 0% → 10% (bytes from 0 to 100 of 1000).
|
||||||
|
let out = compute_diff(&mut cache, TorrentState::Downloading, 100, 1, 1000);
|
||||||
|
assert_eq!(out.2, 10);
|
||||||
|
assert_eq!(out.3, Some(100));
|
||||||
|
// 10% → 50% (bytes from 100 to 500 of 1000).
|
||||||
|
let out = compute_diff(&mut cache, TorrentState::Downloading, 500, 1, 1000);
|
||||||
|
assert_eq!(out.2, 50);
|
||||||
|
assert_eq!(out.3, Some(400));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_progress_emit_when_percent_unchanged() {
|
||||||
|
let mut cache = primed_cache(0, 1000);
|
||||||
|
// 0% → 10%.
|
||||||
|
compute_diff(&mut cache, TorrentState::Downloading, 100, 1, 1000);
|
||||||
|
// 10% again (bytes from 100 to 109, still 10%).
|
||||||
|
let out = compute_diff(&mut cache, TorrentState::Downloading, 109, 1, 1000);
|
||||||
|
assert_eq!(out.2, 10);
|
||||||
|
assert_eq!(out.3, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn zero_total_bytes_gives_zero_percent() {
|
||||||
|
let mut cache = primed_cache(0, 0);
|
||||||
|
let out = compute_diff(&mut cache, TorrentState::Downloading, 0, 0, 0);
|
||||||
|
assert_eq!(out.2, 0);
|
||||||
|
assert_eq!(out.3, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn first_tick_initializes_state_without_false_event() {
|
||||||
|
let mut cache = PollCache::new(ProtoState::Pending);
|
||||||
|
let out = compute_diff(&mut cache, TorrentState::Pending, 0, 0, 0);
|
||||||
|
assert!(!out.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn percent_caps_at_100_on_full_download() {
|
||||||
|
let mut cache = primed_cache(0, 1000);
|
||||||
|
let out = compute_diff(&mut cache, TorrentState::Downloading, 1000, 1, 1000);
|
||||||
|
assert_eq!(out.2, 100);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -3,7 +3,8 @@ CREATE TYPE torrent_state AS ENUM (
|
|||||||
'downloading',
|
'downloading',
|
||||||
'paused',
|
'paused',
|
||||||
'finished',
|
'finished',
|
||||||
'error'
|
'error',
|
||||||
|
'stale'
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE torrents (
|
CREATE TABLE torrents (
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ service Torrents {
|
|||||||
rpc Pause(PauseRequest) returns (PauseResponse);
|
rpc Pause(PauseRequest) returns (PauseResponse);
|
||||||
// Resume a paused torrent.
|
// Resume a paused torrent.
|
||||||
rpc Resume(ResumeRequest) returns (ResumeResponse);
|
rpc Resume(ResumeRequest) returns (ResumeResponse);
|
||||||
|
// Subscribe to a live stream of torrent notifications. Events are delivered
|
||||||
|
// from the subscribe point onward — no history is replayed. New subscribers
|
||||||
|
// only see events that fire after they connect.
|
||||||
|
rpc Notifications(NotificationsRequest) returns (stream Notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
message AddRequest {
|
message AddRequest {
|
||||||
@@ -56,6 +60,69 @@ message ResumeRequest {
|
|||||||
|
|
||||||
message ResumeResponse {}
|
message ResumeResponse {}
|
||||||
|
|
||||||
|
message NotificationsRequest {
|
||||||
|
// If non-empty, only events for these torrent ids (or id prefixes, as
|
||||||
|
// accepted by `Status`/`Remove`) are delivered.
|
||||||
|
repeated string ids = 1;
|
||||||
|
// If non-empty, only these event kinds are delivered. An empty list means
|
||||||
|
// all kinds.
|
||||||
|
repeated NotificationKind kinds = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Notification {
|
||||||
|
// Wall-clock time the daemon observed the change, in milliseconds since the
|
||||||
|
// Unix epoch.
|
||||||
|
uint64 observed_at_unix_millis = 1;
|
||||||
|
// What changed. Use this to dispatch; use the `oneof detail` for
|
||||||
|
// kind-specific payload.
|
||||||
|
NotificationKind kind = 2;
|
||||||
|
// Full snapshot of the torrent *after* the change. Always populated so
|
||||||
|
// consumers don't need to fan out to `Status` for context.
|
||||||
|
TorrentStatus torrent = 3;
|
||||||
|
oneof detail {
|
||||||
|
StateChanged state_changed = 10;
|
||||||
|
ProgressMark progress = 11;
|
||||||
|
AddedInfo added = 12;
|
||||||
|
RemovedInfo removed = 13;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum NotificationKind {
|
||||||
|
NOTIFICATION_KIND_UNSPECIFIED = 0;
|
||||||
|
// Emitted once when a torrent is added via `Add`.
|
||||||
|
TORRENT_ADDED = 1;
|
||||||
|
// Emitted once when a torrent is removed via `Remove`.
|
||||||
|
TORRENT_REMOVED = 2;
|
||||||
|
// Emitted on any `State` transition, including PAUSED <-> DOWNLOADING,
|
||||||
|
// DOWNLOADING <-> STALE, * -> FINISHED, * -> ERROR.
|
||||||
|
STATE_CHANGED = 3;
|
||||||
|
// Emitted when the integer download percentage changes (rate-limited).
|
||||||
|
// No event is sent if the percentage did not advance since the last tick.
|
||||||
|
PROGRESS = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message StateChanged {
|
||||||
|
State previous = 1;
|
||||||
|
State current = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ProgressMark {
|
||||||
|
// Current integer percentage 0..=100.
|
||||||
|
uint32 percent = 1;
|
||||||
|
// Bytes downloaded since the previous PROGRESS event for this torrent.
|
||||||
|
uint64 bytes_delta = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AddedInfo {
|
||||||
|
// Source string as provided to `Add` (magnet, URL, or file path).
|
||||||
|
string source = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RemovedInfo {
|
||||||
|
// True if `Remove` was called with `delete_files = true`.
|
||||||
|
bool files_deleted = 1;
|
||||||
|
}
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
STATE_UNSPECIFIED = 0;
|
STATE_UNSPECIFIED = 0;
|
||||||
PENDING = 1;
|
PENDING = 1;
|
||||||
@@ -63,6 +130,12 @@ enum State {
|
|||||||
PAUSED = 3;
|
PAUSED = 3;
|
||||||
FINISHED = 4;
|
FINISHED = 4;
|
||||||
ERROR = 5;
|
ERROR = 5;
|
||||||
|
// Live per librqbit, but the daemon has detected a stall: no byte progress
|
||||||
|
// for several ticks AND zero connected peers. The torrent is still
|
||||||
|
// considered live by the underlying engine; this state is an application-
|
||||||
|
// level overlay. Recovers to DOWNLOADING automatically when bytes advance
|
||||||
|
// or a peer connects.
|
||||||
|
STALE = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message TorrentStatus {
|
message TorrentStatus {
|
||||||
|
|||||||
Reference in New Issue
Block a user