blob: 1643780d92b654ca4b6c75f90623bd90aec3b251 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use anyhow::bail;
use chrono::Local;
use once_cell::sync::Lazy;
use phper::{arrays::IterKey, sys, values::ZVal};
use serde_json::{json, Number, Value};
use std::{
ffi::CStr,
panic::{catch_unwind, UnwindSafe},
};
use systemstat::{IpAddr, Platform, System};
pub static IPS: Lazy<Vec<String>> = Lazy::new(|| {
System::new()
.networks()
.ok()
.and_then(|networks| {
let addrs = networks
.values()
.flat_map(|network| {
network
.addrs
.iter()
.filter_map(|network_addr| match network_addr.addr {
IpAddr::V4(addr) => {
if network.name == "lo"
|| network.name.starts_with("docker")
|| network.name.starts_with("br-")
{
None
} else {
Some(addr.to_string())
}
}
_ => None,
})
})
.collect::<Vec<_>>();
if addrs.is_empty() {
None
} else {
Some(addrs)
}
})
.unwrap_or_else(|| vec!["127.0.0.1".to_owned()])
});
// TODO Maybe report_instance_properties used.
#[allow(dead_code)]
pub static HOST_NAME: Lazy<String> = Lazy::new(|| {
hostname::get()
.ok()
.and_then(|hostname| hostname.into_string().ok())
.unwrap_or_else(|| "unknown".to_string())
});
// TODO Maybe report_instance_properties used.
#[allow(dead_code)]
pub const OS_NAME: &str = if cfg!(target_os = "linux") {
"Linux"
} else if cfg!(target_os = "windows") {
"Windows"
} else if cfg!(target_os = "macos") {
"Macos"
} else {
"Unknown"
};
// TODO Maybe report_instance_properties used.
#[allow(dead_code)]
pub fn current_formatted_time() -> String {
Local::now().format("%Y-%m-%d %H:%M:%S").to_string()
}
pub fn z_val_to_string(zv: &ZVal) -> Option<String> {
zv.as_z_str()
.and_then(|zs| zs.to_str().ok())
.map(|s| s.to_string())
}
pub fn catch_unwind_anyhow<F: FnOnce() -> anyhow::Result<R> + UnwindSafe, R>(
f: F,
) -> anyhow::Result<R> {
match catch_unwind(f) {
Ok(r) => r,
Err(e) => {
if let Some(s) = e.downcast_ref::<&str>() {
bail!("paniced: {}", s);
} else if let Some(s) = e.downcast_ref::<String>() {
bail!("paniced: {}", s);
} else {
bail!("paniced");
}
}
}
}
pub fn get_sapi_module_name() -> &'static CStr {
unsafe { CStr::from_ptr(sys::sapi_module.name) }
}
/// Use for later scene.
#[allow(dead_code)]
pub fn json_encode_values(values: &[ZVal]) -> serde_json::Result<String> {
fn add(json_value: &mut Value, key: Option<String>, item: Value) {
match key {
Some(key) => {
json_value.as_object_mut().unwrap().insert(key, item);
}
None => {
json_value.as_array_mut().unwrap().push(item);
}
}
}
fn handle(json_value: &mut Value, key: Option<String>, val: &ZVal) {
let type_info = val.get_type_info();
if type_info.is_null() {
add(json_value, key, Value::Null);
} else if type_info.is_true() {
add(json_value, key, Value::Bool(true));
} else if type_info.is_false() {
add(json_value, key, Value::Bool(false));
} else if type_info.is_long() {
let i = val.as_long().unwrap();
add(json_value, key, Value::Number(i.into()));
} else if type_info.is_double() {
let d = val.as_double().unwrap();
let n = match Number::from_f64(d) {
Some(n) => Value::Number(n),
None => Value::String("<NaN>".to_owned()),
};
add(json_value, key, n);
} else if type_info.is_string() {
let s = val
.as_z_str()
.unwrap()
.to_str()
.map(ToOwned::to_owned)
.unwrap_or_default();
add(json_value, key, Value::String(s));
} else if type_info.is_array() {
let arr = val.as_z_arr().unwrap();
let is_arr = arr.iter().all(|(key, _)| matches!(key, IterKey::Index(_)));
let mut new_json_value = if is_arr { json!([]) } else { json!({}) };
for (key, new_val) in arr.iter() {
if is_arr {
handle(&mut new_json_value, None, new_val);
} else {
let key = match key {
IterKey::Index(i) => i.to_string(),
IterKey::ZStr(s) => s.to_str().map(ToOwned::to_owned).unwrap_or_default(),
};
handle(&mut new_json_value, Some(key), new_val);
}
}
add(json_value, key, new_json_value);
} else if type_info.is_object() {
add(json_value, key, Value::String("<Object>".to_owned()));
}
}
let mut json_value = json!([]);
for val in values {
handle(&mut json_value, None, val);
}
serde_json::to_string(&json_value)
}