playit_api_client/
ip_resource.rs1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
2use byteorder::{BigEndian, ByteOrder};
3
4#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
5pub struct IpResource {
6 pub ip_num: u64,
7 pub region: PlayitRegion,
8}
9
10impl IpResource {
11 pub fn from_ip(ip: IpAddr) -> Self {
12 let (region, ip_num) = PlayitRegion::from_ip(ip);
13
14 let is_region_ip = ip_num >= 64 && ip_num < 128;
15 let region = match (is_region_ip, region) {
16 (true, Some(region)) => region,
17 _ => PlayitRegion::Anycast,
18 };
19
20 IpResource { ip_num, region }
21 }
22
23 pub fn to_tunnel_ip(&self) -> Ipv6Addr {
24 self.region.tunnel_address(self.ip_num)
25 }
26}
27
28#[derive(Clone, Copy, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)]
29#[repr(u16)]
30pub enum PlayitRegion {
31 Anycast = 0,
32 Global = 1,
33 NorthAmerica = 2,
34 Europe = 3,
35 Asia = 4,
36 India = 5,
37 SouthAmerica = 6,
38}
39
40impl PlayitRegion {
41 pub fn from_ip(ip: IpAddr) -> (Option<Self>, u64) {
42 match ip {
43 IpAddr::V4(ip) => Self::from_ip4(ip),
44 IpAddr::V6(ip) => Self::from_ip6(ip),
45 }
46 }
47
48 pub fn from_ip4(ip: Ipv4Addr) -> (Option<Self>, u64) {
49 let octs = ip.octets();
50
51 let net = match (octs[0], octs[1], octs[2]) {
52 (0, 0, 0) => Some(PlayitRegion::Anycast),
53 (209, 25, 140) => Some(PlayitRegion::NorthAmerica),
54 (209, 25, 141) => Some(PlayitRegion::Europe),
55 (209, 25, 142) => Some(PlayitRegion::Asia),
56 (209, 25, 143) => Some(PlayitRegion::India),
57 (23, 133, 216) => Some(PlayitRegion::SouthAmerica),
58 (198, 22, 204) => Some(PlayitRegion::SouthAmerica),
59 (147, 185, 221) => Some(PlayitRegion::Global),
60 _ => None,
61 };
62
63 (net, octs[3] as _)
64 }
65
66 pub fn from_ip6(ip: Ipv6Addr) -> (Option<Self>, u64) {
67 let parts = ip.octets();
68
69 let region_number = BigEndian::read_u16(&parts[6..8]);
70 let ip_number = BigEndian::read_u64(&parts[8..]);
71
72 let region = match region_number {
73 0 => Some(PlayitRegion::Anycast),
74 1 => Some(PlayitRegion::Global),
75 2 => Some(PlayitRegion::NorthAmerica),
76 3 => Some(PlayitRegion::Europe),
77 4 => Some(PlayitRegion::Asia),
78 5 => Some(PlayitRegion::India),
79 6 => Some(PlayitRegion::SouthAmerica),
80 _ => None,
81 };
82
83 (
84 region,
85 ip_number
86 )
87 }
88
89 pub fn tunnel_address(&self, ip_number: u64) -> Ipv6Addr {
90 let mut octs = [0u8; 16];
91 octs[0] = 0x26;
92 octs[1] = 0x02;
93 octs[2] = 0xfb;
94 octs[3] = 0xaf;
95 BigEndian::write_u16(&mut octs[6..8], *self as u16);
96 BigEndian::write_u64(&mut octs[8..], ip_number);
97 octs.into()
98 }
99}