resource_internal.cpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * KU Leuven. All rights reserved.
7  * Copyright (C) 2011-2014 Greg Horn
8  *
9  * CasADi is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * CasADi is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with CasADi; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 
26 #include "resource_internal.hpp"
27 #include "casadi_misc.hpp"
28 #include "archiver_impl.hpp"
29 
30 #include "filesystem_impl.hpp"
31 
32 
33 namespace casadi {
34 
35 
37  serialize_mode_ = "link";
38 }
39 
40 DirResource::DirResource(const std::string& path)
41  : ResourceInternal(),
42  path_(path) {
43  path_ = path;
44 }
45 
46 void DirResource::disp(std::ostream& stream, bool more) const {
47  stream << "DirResource(\"" << path_ << "\")";
48 }
49 
51 }
52 
53 void ResourceInternal::change_option(const std::string& option_name,
54  const GenericType& option_value) {
55  if (option_name=="serialize_mode") {
56  serialize_mode_ = option_value.to_string();
57  casadi_assert(serialize_mode_=="embed" || serialize_mode_=="link",
58  "Invalid serialization mode: " + serialize_mode_ + ". Pick 'link' or 'embed'.");
59  } else {
60  casadi_error("Option '" + option_name + "' does not exist");
61  }
62 }
63 
65  casadi_assert(Filesystem::is_enabled(),
66  "Unzipping '" + path_ + "' requires advanced filesystem access. "
67  "Compile CasADi with WITH_GHC_FILESYSTEM=ON.\n"
68  "Alternatively, manually unzip it into a direcory, "
69  "and pass this directory name instead of the zip file name.");
70 
71  // Set up temporary directory
72  setup_temp_dir(Filesystem::filename(path_), "unzipped");
73 
74  casadi_assert(Archiver::has_plugin("libzip"),
75  "Unzipping '" + path_ + "' requires libzip. Compile CasADi with WITH_LIBZIP=ON.\n"
76  "Alternatively, manually unzip it into a direcory, "
77  "and pass this directory name instead of the zip file name.");
78 
79  Archiver::getPlugin("libzip").exposed.unpack(path_, dir_);
80 }
81 
83  // Set up temporary directory
84  setup_temp_dir("zip", "unzipped");
85 
86  casadi_assert(Archiver::has_plugin("libzip"),
87  "Unzipping stream requires libzip. Compile CasADi with WITH_LIBZIP=ON.\n"
88  "Alternatively, save with serialize option set to link. ");
89 
90  Archiver::getPlugin("libzip").exposed.unpack_from_stringstream(blob_, dir_);
91  // rewind
92  blob_.clear();
93  blob_.seekg(0, std::ios::beg);
94 }
95 
96 ZipResource::ZipResource(const std::string& path)
98  path_ = path;
99  unpack();
100 }
101 
102 ZipMemResource::ZipMemResource(const std::istream& src)
104  blob_ << src.rdbuf();
105  unpack();
106 }
107 
108 void ZipResource::disp(std::ostream& stream, bool more) const {
109  stream << "ZipResource(\"" << path_ << "\") -> \"" << dir_ << "\"";
110 }
111 
112 void ZipMemResource::disp(std::ostream& stream, bool more) const {
113  stream << "ZipMemResource(blob) -> \"" << dir_ << "\"";
114 }
115 
116 void TemporaryDirResource::setup_temp_dir(const std::string& base_name, const std::string& suffix) {
117  // Resolve absolute path since cwd may be changed by the user
118  lock_file_ = Filesystem::absolute(temporary_file(base_name + ".", ".lock"));
119  dir_ = lock_file_.substr(0, lock_file_.size() - 5);
120  if (!suffix.empty()) {
121  dir_ += "." + suffix;
122  }
123  // Create the directory
125 }
126 
127 TemporaryDirResource::TemporaryDirResource(const std::string& base_name, const std::string& suffix)
128  : ResourceInternal() {
129  setup_temp_dir(base_name, suffix);
130 }
131 
132 void TemporaryDirResource::disp(std::ostream& stream, bool more) const {
133  stream << "TemporaryDirResource(\"" << dir_ << "\")";
134 }
135 
137  try {
138  casadi_assert_dev(Filesystem::remove_all(dir_));
139  } catch (...) {
140  casadi_warning("Error: Cannot remove temporary directory: " + dir_);
141  }
142  try {
143  casadi_assert_dev(Filesystem::remove(lock_file_));
144  } catch (...) {
145  casadi_warning("Error: Cannot remove lock file: " + lock_file_);
146  }
147 }
148 
150  s.version("ResourceInternal", 1);
151  serialize_type(s);
152  serialize_body(s);
153 }
154 
156  s.pack("ResourceInternal::type", class_name());
157 }
158 
160  s.pack("ResourceInternal::serialize_mode", serialize_mode_);
161 }
162 
164  s.unpack("ResourceInternal::serialize_mode", serialize_mode_);
165  serialize_mode_ = "link";
166 }
167 
169  s.version("ResourceInternal", 1);
170  std::string class_name;
171  s.unpack("ResourceInternal::type", class_name);
172  if (class_name=="DirResource") {
173  return DirResource::deserialize(s);
174  } else if (class_name=="ZipResource") {
175  return ZipResource::deserialize(s);
176  } else if (class_name=="ZipMemResource") {
177  return ZipMemResource::deserialize(s);
178  } else {
179  casadi_error("Cannot deserialize type '" + class_name + "'");
180  }
181 }
182 
184  ZipResource* ret = new ZipResource(s);
185  return ret;
186 }
187 
189 ZipMemResource* ret = new ZipMemResource(s);
190  return ret;
191 }
192 
194  DirResource* ret = new DirResource(s);
195  return ret;
196 }
197 
199  s.version("ZipResource", 1);
200  s.unpack("ZipResource::path", path_);
201  unpack();
202 }
203 
205 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
206  std::lock_guard<std::mutex> lock(mutex_blob_);
207 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
208  s.version("ZipMemResource", 1);
209  s.unpack("ZipMemResource::blob", blob_);
210  unpack();
211 }
212 
214  s.version("DirResource", 1);
215  s.unpack("DirResource::path", path_);
216 }
217 
219  if (serialize_mode_=="embed") {
220  // Decay into ZipMemResource
221  std::string class_name = "ZipMemResource";
222  s.pack("ResourceInternal::type", class_name);
223  } else if (serialize_mode_=="link") {
224  std::string class_name = "ZipResource";
225  s.pack("ResourceInternal::type", class_name);
226  } else {
227  casadi_error("Unknown serialization mode: '" + serialize_mode_+ "'.");
228  }
229 }
230 
232  if (serialize_mode_=="embed") {
233  // Decay into ZipMemResource
234  std::string class_name = "ZipMemResource";
235  s.pack("ResourceInternal::type", class_name);
236  } else if (serialize_mode_=="link") {
237  std::string class_name = "DirResource";
238  s.pack("ResourceInternal::type", class_name);
239  } else {
240  casadi_error("Unknown serialization mode: " + serialize_mode_);
241  }
242 }
243 
244 
247  s.version("ZipResource", 1);
248  if (serialize_mode_=="embed") {
249  // Decay into ZipMemResource
250  auto binary_ptr = Filesystem::ifstream_ptr(path_, std::ios_base::binary, false);
251  casadi_assert(binary_ptr,
252  "Could not open zip file '" + path_ + "'.");
253  s.pack("ZipMemResource::blob", *binary_ptr);
254  } else {
255  s.pack("ZipResource::path", path_);
256  }
257 }
258 
261  s.version("DirResource", 1);
262  if (serialize_mode_=="embed") {
263  // Decay into ZipMemResource
264  std::stringstream ss;
265  Archiver::getPlugin("libzip").exposed.pack_to_stream(path_, ss);
266  ss.clear();
267  ss.seekg(0, std::ios::beg);
268  s.pack("ZipMemResource::blob", ss);
269  } else {
270  s.pack("DirResource::path", path_);
271  }
272 }
273 
274 
275 
277 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
278  std::lock_guard<std::mutex> lock(mutex_blob_);
279 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
281  s.version("ZipMemResource", 1);
282  s.pack("ZipMemResource::blob", blob_);
283 
284  // rewind
285  blob_.clear();
286  blob_.seekg(0, std::ios::beg);
287 }
288 
289 
290 } // namespace casadi
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
void serialize_type(SerializingStream &s) const override
std::string class_name() const override
Get type name.
DirResource(const std::string &path)
Initialize with a path.
void serialize_body(SerializingStream &s) const override
const std::string & path() const override
Get path for a consumer.
void disp(std::ostream &stream, bool more) const override
Print description.
static ResourceInternal * deserialize(DeserializingStream &s)
static casadi_int remove_all(const std::string &path)
Definition: filesystem.cpp:48
static std::string absolute(const std::string &path)
Definition: filesystem.cpp:78
static std::string filename(const std::string &path)
Definition: filesystem.cpp:73
static bool create_directories(const std::string &path)
Definition: filesystem.cpp:63
static bool is_enabled()
Definition: filesystem.cpp:83
static std::unique_ptr< std::istream > ifstream_ptr(const std::string &path, std::ios_base::openmode mode=std::ios_base::in, bool fail=true)
Definition: filesystem.cpp:135
static bool remove(const std::string &path)
Definition: filesystem.cpp:43
Generic data type, can hold different types such as bool, casadi_int, std::string etc.
std::string to_string() const
Convert to a type.
static bool has_plugin(const std::string &pname, bool verbose=false)
Check if a plugin is available or can be loaded.
static Plugin & getPlugin(const std::string &pname)
Load and get the creator function.
RAII class base for reading from resources.
ResourceInternal()
Initialize with a path.
void serialize(SerializingStream &s) const
virtual void serialize_body(SerializingStream &s) const
void change_option(const std::string &option_name, const GenericType &option_value)
virtual void serialize_type(SerializingStream &s) const
static ResourceInternal * deserialize(DeserializingStream &s)
Helper class for Serialization.
void version(const std::string &name, int v)
void pack(const Sparsity &e)
Serializes an object to the output stream.
virtual std::string class_name() const =0
Readable name of the internal class.
Base class for resources that use a temporary directory.
void disp(std::ostream &stream, bool more) const override
Print description.
const std::string & path() const override
Get path for a consumer.
void setup_temp_dir(const std::string &base_name, const std::string &suffix="")
Set up lock file and directory paths from a base name.
RAII class for reading from a zip held in memory.
void serialize_body(SerializingStream &s) const override
ZipMemResource(const std::istream &src)
void disp(std::ostream &stream, bool more) const override
Print description.
static ResourceInternal * deserialize(DeserializingStream &s)
RAII class for reading from a zip file.
void disp(std::ostream &stream, bool more) const override
Print description.
static ResourceInternal * deserialize(DeserializingStream &s)
void serialize_body(SerializingStream &s) const override
void serialize_type(SerializingStream &s) const override
Potentially decay into ZipMemResource.
ZipResource(const std::string &path)
Initialize with a path.
std::string class_name() const override
Get type name.
The casadi namespace.
Definition: archiver.cpp:28
std::vector< casadi_int > path(const std::vector< casadi_int > &map, casadi_int i_start)
std::string temporary_file(const std::string &prefix, const std::string &suffix, const std::string &directory)