Source file gapiUtils.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
module Option = GapiOption

module Infix = struct
  let ( |> ) x f = f x
  let ( -| ) f g x = f (g x)
  let ( |- ) f g x = g (f x)
end

open Infix

let is_weak_etag etag =
  if String.length etag > 2 then String.sub etag 0 2 = "W/" else false

let etag_option etag = match etag with "" -> None | v -> Some v

let merge_query_string parameters url =
  let neturl = Neturl.parse_url url in
  let fields =
    try
      Netencoding.Url.dest_url_encoded_parameters
        (Neturl.url_query ~encoded:true neturl)
    with Not_found -> []
  in
  let query_string =
    Netencoding.Url.mk_url_encoded_parameters (fields @ parameters)
  in
  let new_neturl = Neturl.modify_url ~encoded:true ~query:query_string neturl in
  Neturl.string_of_url new_neturl

let add_path_to_url ?(encoded = true) path_to_add url =
  let neturl = Neturl.parse_url url in
  let base_path =
    if List.length path_to_add > 0 && List.hd path_to_add = "" then
      (* if the path_to_add starts with /, then it's not relative, so base path
       * should be empty *)
      []
    else
      (* get the base path *)
      let base_path =
        Neturl.url_path neturl |> List.filter (fun p -> p <> "")
      in
      "" :: base_path
  in
  let path_to_add_encoded =
    List.map
      (fun p ->
        (* In some services: e.g. tasks default list (@default), the '@' should
         * not be encoded, but if the string contains '#' or '/', the resulting
         * URL will be invalid for Neturl *)
        if encoded && (String.contains p '#' || String.contains p '/') then
          Netencoding.Url.encode p
        else p)
      path_to_add
  in
  let new_path = base_path @ path_to_add_encoded in
  let new_neturl = Neturl.modify_url ~encoded ~path:new_path neturl in
  Neturl.string_of_url new_neturl

let string_after_char c s =
  let last_position = String.rindex s c in
  Str.string_after s (last_position + 1)

let string_before_char c s =
  try
    let first_occurrence = String.index s c in
    Str.string_before s first_occurrence
  with Not_found -> s

let divide_string s c =
  try
    let i = String.index s c in
    let len = String.length s in
    let j = i + 1 in
    (String.sub s 0 i, String.sub s j (len - j))
  with Invalid_argument _ -> ("", s)

let strip_string s =
  let leading_trailing_whitespace =
    Str.regexp "\\(^[ \t\r\n]+\\|[ \t\r\n]+$\\)"
  in
  Str.global_replace leading_trailing_whitespace "" s

let string_starts_with s prefix =
  let prefix_len = String.length prefix in
  if prefix_len > String.length s then false
  else
    let start = String.sub s 0 prefix_len in
    String.compare start prefix == 0

let string_ends_with s suffix =
  let len = String.length s in
  let suffix_len = String.length suffix in
  if suffix_len > len then false
  else
    let ending = String.sub s (len - suffix_len) suffix_len in
    String.compare ending suffix == 0

let wait_exponential_backoff n =
  let seconds = 1 lsl n in
  let milliseconds = Random.float 1.0 in
  let wait_time = float_of_int seconds +. milliseconds in
  Unix.select [] [] [] wait_time |> ignore

class bigarray_rec_out_channel buffer =
  object
    val mutable pos = 0

    method output b offset len =
      Netsys_mem.blit_bytes_to_memory b offset buffer pos len;
      pos <- pos + len;
      len

    method flush () = ()
    method close_out () = ()
  end

class bigarray_out_obj_channel buffer =
  Netchannels.out_obj_channel_delegation
    (Netchannels.lift_out ~buffered:false
       (`Rec (new bigarray_rec_out_channel buffer)))

class bigarray_rec_in_channel buffer =
  object
    val dim = Bigarray.Array1.dim buffer
    val mutable pos = 0

    method input b offset len =
      let input_bytes l =
        Netsys_mem.blit_memory_to_bytes buffer pos b offset l;
        pos <- pos + l;
        l
      in
      if pos >= dim then raise End_of_file
      else if pos + len > dim then input_bytes (dim - pos)
      else input_bytes len

    method close_in () = ()
  end

class bigarray_in_obj_channel buffer =
  Netchannels.in_obj_channel_delegation
    (Netchannels.lift_in ~buffered:false
       (`Rec (new bigarray_rec_in_channel buffer)))

let option_map_default f default v = Option.(map f v |> value ~default)

(* Initialize random number generator *)
let () = Random.self_init ()