<commit_before>use std::{
  iter::FromIterator,
  net::TcpListener,
  process,
  sync::mpsc,
  thread,
  time::Duration
};
use std::convert::Infallible;
use std::net::{IpAddr, SocketAddr};

use futures::channel::oneshot::channel;
use hyper::server::Server;
use hyper::service::make_service_fn;
use log::*;
use maplit::*;
use serde_json::{self, json, Value};
use uuid::Uuid;
use webmachine_rust::*;
use webmachine_rust::context::*;
use webmachine_rust::headers::*;

use pact_matching::models::{RequestResponsePact, load_pact_from_json};
use pact_mock_server::mock_server::MockServerConfig;
use pact_mock_server::tls::TlsConfigBuilder;

use crate::{SERVER_MANAGER, SERVER_OPTIONS, ServerOpts};
use crate::verify;

fn json_error(error: String) -> String {
    let json_response = json!({ "error" : json!(error) });
    json_response.to_string()
}

fn get_next_port(base_port: Option<u16>) -> u16 {
  match base_port {
    None => 0,
    Some(p) => if p > 0 {
      let mut port = p;
      let mut listener = TcpListener::bind(("127.0.0.1", port));
      while listener.is_err() && port < p + 1000 {
        port += 1;
        listener = TcpListener::bind(("127.0.0.1", port));
      }
      match listener {
        Ok(listener) => listener.local_addr().unwrap().port(),
        Err(_) => 0
      }
    } else {
      0
    }
  }
}

fn start_provider(context: &mut WebmachineContext, options: ServerOpts) -> Result<bool, u16> {
  debug!("start_provider => {}", context.request.request_path);
  match context.request.body {
    Some(ref body) if !body.is_empty() => {
      match serde_json::from_slice(body) {
        Ok(ref json) => {
          let pact = load_pact_from_json(&context.request.request_path, json)
            .map_err(|err| {
              error!("Failed to parse Pact JSON - {}", err);
              422_u16
            })?;
          debug!("Loaded pact = {:?}", pact);
          let mock_server_id = Uuid::new_v4().to_string();
          let config = MockServerConfig {
            cors_preflight: query_param_set(context, "cors")
          };
          debug!("Mock server config = {:?}", config);

          let mut guard = SERVER_MANAGER.lock().unwrap();
          let result = if query_param_set(context, "tls") {
            debug!("Starting TLS mock server with id {}", &mock_server_id);
            let key = include_str!("self-signed.key");
            let cert = include_str!("self-signed.cert");
            TlsConfigBuilder::new()
              .key(key.as_bytes())
              .cert(cert.as_bytes())
              .build()
              .map_err(|err| {
                format!("Failed to setup TLS using self-signed certificate - {}", err)
              })
              .and_then(|tls_config| {
                guard.start_tls_mock_server(mock_server_id.clone(), pact, get_next_port(options.base_port), &tls_config, config)
              })
          } else {
            debug!("Starting mock server with id {}", &mock_server_id);
            guard.start_mock_server(mock_server_id.clone(), pact, get_next_port(options.base_port), config)
          };
          match result {
            Ok(mock_server) => {
              debug!("mock server started on port {}", mock_server);
              let mock_server_json = json!({
                "id" : json!(mock_server_id),
                "port" : json!(mock_server as i64),
              });
              let json_response = json!({ "mockServer" : mock_server_json });
              context.response.body = Some(json_response.to_string().into_bytes());
              context.response.add_header("Location",
                vec![HeaderValue::basic(format!("/mockserver/{}", mock_server_id).as_str())]);
              Ok(true)
            },
            Err(msg) => {
              context.response.body = Some(json_error(format!("Failed to start mock server - {}", msg)).into_bytes());
              Err(422)
            }
          }
        },
        Err(err) => {
            log::error!("Failed to parse json body - {}", err);
            context.response.body = Some(json_error(format!("Failed to parse json body - {}", err)).into_bytes());
            Err(422)
        }
      }
    },
    _ => {
      log::error!("No pact json was supplied");
      context.response.body = Some(json_error("No pact json was supplied".to_string()).into_bytes());
      Err(422)
    }
  }
}

fn query_param_set(context: &mut WebmachineContext, name: &str) -> bool {
  context.request.query.get(name)
    .unwrap_or(&vec![]).first().unwrap_or(&String::default())
    .eq("true")
}

pub fn verify_mock_server_request(context: &mut WebmachineContext) -> Result<bool, u16> {
  let id = context.metadata.get("id").cloned().unwrap_or_default();
  match verify::validate_id(&id, &SERVER_MANAGER) {
    Ok(ms) => {
      let mut map = btreemap!{ "mockServer" => ms.to_json() };
      let mismatches = ms.mismatches();
      if !mismatches.is_empty() {
        map.insert("mismatches", json!(mismatches.iter().map(|m| m.to_json()).collect()));
        context.response.body = Some(json!(map).to_string().into_bytes());
        Err(422)
      } else {
        let inner = SERVER_OPTIONS.lock().unwrap();
        let options = inner.borrow();<commit_msg>fix: clippy violation - caused a compiler error<commit_after>use std::{
  iter::FromIterator,
  net::TcpListener,
  process,
  sync::mpsc,
  thread,
  time::Duration
};
use std::convert::Infallible;
use std::net::{IpAddr, SocketAddr};

use futures::channel::oneshot::channel;
use hyper::server::Server;
use hyper::service::make_service_fn;
use log::*;
use maplit::*;
use serde_json::{self, json, Value};
use uuid::Uuid;
use webmachine_rust::*;
use webmachine_rust::context::*;
use webmachine_rust::headers::*;

use pact_matching::models::{RequestResponsePact, load_pact_from_json};
use pact_mock_server::mock_server::MockServerConfig;
use pact_mock_server::tls::TlsConfigBuilder;

use crate::{SERVER_MANAGER, SERVER_OPTIONS, ServerOpts};
use crate::verify;

fn json_error(error: String) -> String {
    let json_response = json!({ "error" : json!(error) });
    json_response.to_string()
}

fn get_next_port(base_port: Option<u16>) -> u16 {
  match base_port {
    None => 0,
    Some(p) => if p > 0 {
      let mut port = p;
      let mut listener = TcpListener::bind(("127.0.0.1", port));
      while listener.is_err() && port < p + 1000 {
        port += 1;
        listener = TcpListener::bind(("127.0.0.1", port));
      }
      match listener {
        Ok(listener) => listener.local_addr().unwrap().port(),
        Err(_) => 0
      }
    } else {
      0
    }
  }
}

fn start_provider(context: &mut WebmachineContext, options: ServerOpts) -> Result<bool, u16> {
  debug!("start_provider => {}", context.request.request_path);
  match context.request.body {
    Some(ref body) if !body.is_empty() => {
      match serde_json::from_slice(body) {
        Ok(ref json) => {
          let pact = load_pact_from_json(&context.request.request_path, json)
            .map_err(|err| {
              error!("Failed to parse Pact JSON - {}", err);
              422_u16
            })?;
          debug!("Loaded pact = {:?}", pact);
          let mock_server_id = Uuid::new_v4().to_string();
          let config = MockServerConfig {
            cors_preflight: query_param_set(context, "cors")
          };
          debug!("Mock server config = {:?}", config);

          let mut guard = SERVER_MANAGER.lock().unwrap();
          let result = if query_param_set(context, "tls") {
            debug!("Starting TLS mock server with id {}", &mock_server_id);
            let key = include_str!("self-signed.key");
            let cert = include_str!("self-signed.cert");
            TlsConfigBuilder::new()
              .key(key.as_bytes())
              .cert(cert.as_bytes())
              .build()
              .map_err(|err| {
                format!("Failed to setup TLS using self-signed certificate - {}", err)
              })
              .and_then(|tls_config| {
                guard.start_tls_mock_server(mock_server_id.clone(), pact, get_next_port(options.base_port), &tls_config, config)
              })
          } else {
            debug!("Starting mock server with id {}", &mock_server_id);
            guard.start_mock_server(mock_server_id.clone(), pact, get_next_port(options.base_port), config)
          };
          match result {
            Ok(mock_server) => {
              debug!("mock server started on port {}", mock_server);
              let mock_server_json = json!({
                "id" : json!(mock_server_id),
                "port" : json!(mock_server as i64),
              });
              let json_response = json!({ "mockServer" : mock_server_json });
              context.response.body = Some(json_response.to_string().into_bytes());
              context.response.add_header("Location",
                vec![HeaderValue::basic(format!("/mockserver/{}", mock_server_id).as_str())]);
              Ok(true)
            },
            Err(msg) => {
              context.response.body = Some(json_error(format!("Failed to start mock server - {}", msg)).into_bytes());
              Err(422)
            }
          }
        },
        Err(err) => {
            log::error!("Failed to parse json body - {}", err);
            context.response.body = Some(json_error(format!("Failed to parse json body - {}", err)).into_bytes());
            Err(422)
        }
      }
    },
    _ => {
      log::error!("No pact json was supplied");
      context.response.body = Some(json_error("No pact json was supplied".to_string()).into_bytes());
      Err(422)
    }
  }
}

fn query_param_set(context: &mut WebmachineContext, name: &str) -> bool {
  context.request.query.get(name)
    .unwrap_or(&vec![]).first().unwrap_or(&String::default())
    .eq("true")
}

pub fn verify_mock_server_request(context: &mut WebmachineContext) -> Result<bool, u16> {
  let id = context.metadata.get("id").cloned().unwrap_or_default();
  match verify::validate_id(&id, &SERVER_MANAGER) {
    Ok(ms) => {
      let mut map = btreemap!{ "mockServer" => ms.to_json() };
      let mismatches = ms.mismatches();
      if !mismatches.is_empty() {
        map.insert("mismatches", json!(mismatches.iter()
          .map(|m| m.to_json()).collect::<Vec<Value>>()));
        context.response.body = Some(json!(map).to_string().into_bytes());
        Err(422)
      } else {
        let inner = SERVER_OPTIONS.lock().unwrap();
        let options = inner.borrow();
{'fraction_non_alphanumeric': 0.15578224806940605, 'fraction_numerical': 0.009343121365239775, 'mean_word_length': 2.5559322033898306, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 4, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6121543', 'n_tokens_mistral': 3294, 'n_tokens_neox': 3262, 'n_words': 626}