|
1 | 1 | use once_cell::sync::Lazy;
|
2 | 2 | use regex::Regex;
|
3 | 3 |
|
4 |
| -use crate::protocol::{Context, OsContext, ResponseContext, RuntimeContext}; |
| 4 | +use crate::protocol::{ |
| 5 | + Context, DeviceClass, DeviceContext, OsContext, ResponseContext, RuntimeContext, |
| 6 | +}; |
5 | 7 | use crate::types::{Annotated, Empty};
|
6 | 8 |
|
7 | 9 | /// Environment.OSVersion (GetVersionEx) or RuntimeInformation.OSDescription on Windows
|
@@ -37,6 +39,8 @@ static OS_UNAME_REGEX: Lazy<Regex> = Lazy::new(|| {
|
37 | 39 | static RUNTIME_DOTNET_REGEX: Lazy<Regex> =
|
38 | 40 | Lazy::new(|| Regex::new(r#"^(?P<name>.*) (?P<version>\d+\.\d+(\.\d+){0,2}).*$"#).unwrap());
|
39 | 41 |
|
| 42 | +const GIB: u64 = 1024 * 1024 * 1024; |
| 43 | + |
40 | 44 | fn normalize_runtime_context(runtime: &mut RuntimeContext) {
|
41 | 45 | if runtime.name.value().is_empty() && runtime.version.value().is_empty() {
|
42 | 46 | if let Some(raw_description) = runtime.raw_description.as_str() {
|
@@ -199,11 +203,45 @@ fn normalize_response(response: &mut ResponseContext) {
|
199 | 203 | }
|
200 | 204 | }
|
201 | 205 |
|
| 206 | +// Reads device specs (family, memory, cpu, etc) and sets the device class to high, medium, or low. |
| 207 | +fn normalize_device_context(device: &mut DeviceContext) { |
| 208 | + // Unset device class if it is sent by the client, since this value should be computed by relay. |
| 209 | + if device.class.value().is_some() { |
| 210 | + device.class = Annotated::empty(); |
| 211 | + } |
| 212 | + if let Some(family) = device.family.value() { |
| 213 | + if family == "iPhone" || family == "iOS" || family == "iOS-Device" { |
| 214 | + if let Some(processor_frequency) = device.processor_frequency.value() { |
| 215 | + if processor_frequency < &2000 { |
| 216 | + device.class = DeviceClass::LOW.into(); |
| 217 | + } else if processor_frequency < &3000 { |
| 218 | + device.class = DeviceClass::MEDIUM.into(); |
| 219 | + } else { |
| 220 | + device.class = DeviceClass::HIGH.into(); |
| 221 | + } |
| 222 | + } |
| 223 | + } else if let (Some(&freq), Some(&proc), Some(&mem)) = ( |
| 224 | + device.processor_frequency.value(), |
| 225 | + device.processor_count.value(), |
| 226 | + device.memory_size.value(), |
| 227 | + ) { |
| 228 | + if freq < 2000 || proc < 8 || mem < 4 * GIB { |
| 229 | + device.class = DeviceClass::LOW.into(); |
| 230 | + } else if freq < 2500 || mem < 6 * GIB { |
| 231 | + device.class = DeviceClass::MEDIUM.into(); |
| 232 | + } else { |
| 233 | + device.class = DeviceClass::HIGH.into(); |
| 234 | + } |
| 235 | + } |
| 236 | + } |
| 237 | +} |
| 238 | + |
202 | 239 | pub fn normalize_context(context: &mut Context) {
|
203 | 240 | match context {
|
204 | 241 | Context::Runtime(runtime) => normalize_runtime_context(runtime),
|
205 | 242 | Context::Os(os) => normalize_os_context(os),
|
206 | 243 | Context::Response(response) => normalize_response(response),
|
| 244 | + Context::Device(device) => normalize_device_context(device), |
207 | 245 | _ => (),
|
208 | 246 | }
|
209 | 247 | }
|
@@ -580,4 +618,96 @@ mod tests {
|
580 | 618 | assert_eq!(Some("15.0"), os.kernel_version.as_str());
|
581 | 619 | assert_eq!(None, os.build.value());
|
582 | 620 | }
|
| 621 | + |
| 622 | + #[test] |
| 623 | + fn test_apple_no_device_class() { |
| 624 | + let mut device = DeviceContext { |
| 625 | + family: "iPhone".to_string().into(), |
| 626 | + ..DeviceContext::default() |
| 627 | + }; |
| 628 | + normalize_device_context(&mut device); |
| 629 | + assert_eq!(None, device.class.value()); |
| 630 | + } |
| 631 | + |
| 632 | + #[test] |
| 633 | + fn test_apple_low_device_class() { |
| 634 | + let mut device = DeviceContext { |
| 635 | + family: "iPhone".to_string().into(), |
| 636 | + processor_frequency: 1000.into(), |
| 637 | + ..DeviceContext::default() |
| 638 | + }; |
| 639 | + normalize_device_context(&mut device); |
| 640 | + assert_eq!(DeviceClass::LOW, *device.class.value().unwrap()); |
| 641 | + } |
| 642 | + |
| 643 | + #[test] |
| 644 | + fn test_apple_medium_device_class() { |
| 645 | + let mut device = DeviceContext { |
| 646 | + family: "iPhone".to_string().into(), |
| 647 | + processor_frequency: 2000.into(), |
| 648 | + ..DeviceContext::default() |
| 649 | + }; |
| 650 | + normalize_device_context(&mut device); |
| 651 | + assert_eq!(DeviceClass::MEDIUM, *device.class.value().unwrap()); |
| 652 | + } |
| 653 | + |
| 654 | + #[test] |
| 655 | + fn test_apple_high_device_class() { |
| 656 | + let mut device = DeviceContext { |
| 657 | + family: "iPhone".to_string().into(), |
| 658 | + processor_frequency: 3000.into(), |
| 659 | + ..DeviceContext::default() |
| 660 | + }; |
| 661 | + normalize_device_context(&mut device); |
| 662 | + assert_eq!(DeviceClass::HIGH, *device.class.value().unwrap()); |
| 663 | + } |
| 664 | + |
| 665 | + #[test] |
| 666 | + fn test_android_no_device_class() { |
| 667 | + let mut device = DeviceContext { |
| 668 | + family: "android".to_string().into(), |
| 669 | + ..DeviceContext::default() |
| 670 | + }; |
| 671 | + normalize_device_context(&mut device); |
| 672 | + assert_eq!(None, device.class.value()); |
| 673 | + } |
| 674 | + |
| 675 | + #[test] |
| 676 | + fn test_android_low_device_class() { |
| 677 | + let mut device = DeviceContext { |
| 678 | + family: "android".to_string().into(), |
| 679 | + processor_frequency: 1000.into(), |
| 680 | + processor_count: 6.into(), |
| 681 | + memory_size: (2 * GIB).into(), |
| 682 | + ..DeviceContext::default() |
| 683 | + }; |
| 684 | + normalize_device_context(&mut device); |
| 685 | + assert_eq!(DeviceClass::LOW, *device.class.value().unwrap()); |
| 686 | + } |
| 687 | + |
| 688 | + #[test] |
| 689 | + fn test_android_medium_device_class() { |
| 690 | + let mut device = DeviceContext { |
| 691 | + family: "android".to_string().into(), |
| 692 | + processor_frequency: 2000.into(), |
| 693 | + processor_count: 8.into(), |
| 694 | + memory_size: (6 * GIB).into(), |
| 695 | + ..DeviceContext::default() |
| 696 | + }; |
| 697 | + normalize_device_context(&mut device); |
| 698 | + assert_eq!(DeviceClass::MEDIUM, *device.class.value().unwrap()); |
| 699 | + } |
| 700 | + |
| 701 | + #[test] |
| 702 | + fn test_android_high_device_class() { |
| 703 | + let mut device = DeviceContext { |
| 704 | + family: "android".to_string().into(), |
| 705 | + processor_frequency: 2500.into(), |
| 706 | + processor_count: 8.into(), |
| 707 | + memory_size: (6 * GIB).into(), |
| 708 | + ..DeviceContext::default() |
| 709 | + }; |
| 710 | + normalize_device_context(&mut device); |
| 711 | + assert_eq!(DeviceClass::HIGH, *device.class.value().unwrap()); |
| 712 | + } |
583 | 713 | }
|
0 commit comments