return dir.file_string();
}
+std::string Base::get_thread_idx_path() const {
+ const boost::filesystem::path dir(get_board_idx_dir_path());
+ const boost::filesystem::path xml = dir / (thread_ + ".xml");
+ return xml.file_string();
+}
+
+
+std::string Base::get_thread_dat_uri() const {
+ return "http://" + host_ + "/" + board_ + "/dat/" + thread_ + ".dat";
+}
+
std::string Base::get_another_thread_uri(const std::string& thread) const {
return "http://" + host_ + "/test/read.cgi/" + board_ + "/" + thread + "/";
}
return bbs_name;
}
-void Base::load_thread(text_view::Layoutable& output) const {
- std::string filepath = get_thread_file_path();
+void Base::load_thread_from_string(const std::string& dat,
+ text_view::Layoutable& output) const {
- std::ifstream ifs(filepath.c_str());
- int resnum = 1;
+ int resnum = output.get_res_num()+1;
+
+ std::stringstream ss;
+ ss << dat << std::flush;
std::string line;
Glib::IConv iconv("UTF-8", get_encoding());
- while (std::getline(ifs, line)) {
+ while (std::getline(ss, line)) {
dialektos::BufferBuilder builder(output, resnum);
try {
dialektos::run_parser<
}
++resnum;
}
+
+ output.set_res_num(resnum-1);
+}
+
+void Base::load_thread(text_view::Layoutable& output) const {
+ std::string filepath = get_thread_file_path();
+
+ std::ifstream ifs(filepath.c_str());
+ std::stringstream ss;
+ ss << ifs.rdbuf() << std::flush;
+ load_thread_from_string(ss.str(), output);
}
void Base::load_subject(std::vector<SubjectItem>& output) const {
return host_ == rhs.host_ && board_ == rhs.board_ && thread_ == rhs.thread_;
}
+std::string Base::get_title_from_string(const std::string& dat) const {
+ using namespace boost::xpressive;
+ const sregex regex = bos >> -repeat<4>(*(~_n) >> "<>")
+ >> (s1=*(~_n)) >> _n >> -*_;
+
+ smatch what;
+ if (regex_match(dat, what, regex)) {
+ try {
+ return Glib::convert(what[1], "UTF-8", get_encoding());
+ } catch (const Glib::ConvertError& e) {
+ std::cerr << "convert error!! - " << e.what() << " "
+ << what[1] << std::endl;
+ }
+ }
+ return "";
+}
+
+http::Header Base::get_thread_dat_request_header() const {
+ http::Header request_header;
+ request_header.insert(std::make_pair("Host", host_));
+
+ if (boost::filesystem::exists(get_thread_file_path())) {
+ const size_t file_size = boost::filesystem::file_size(get_thread_file_path());
+ if (file_size > 0) {
+ std::string str = boost::lexical_cast<std::string>(file_size);
+ str = "bytes=" + str + "-";
+ request_header.insert(std::make_pair("Range", str));
+ }
+ }
+ return request_header;
+}
+
//Base* Base::judge(const std::string& uri) {
//}
virtual ~Base();
virtual std::string get_board_dir_path() const;
virtual std::string get_thread_file_path() const;
+ virtual std::string get_thread_idx_path() const;
+ virtual std::string get_thread_dat_uri() const;
virtual std::string get_another_thread_uri(const std::string& thread) const;
virtual std::string get_board_subject_path() const;
virtual std::string get_board_subject_uri() const;
virtual std::string get_board_subject_idx_path() const;
virtual std::string get_board_idx_dir_path() const;
virtual http::Header get_board_subject_request_header() const;
+ virtual http::Header get_thread_dat_request_header() const;
+ virtual std::string get_title_from_string(const std::string& dat) const;
virtual const std::string& get_encoding() const;
virtual void load_thread(text_view::Layoutable& output) const;
+ virtual void load_thread_from_string(
+ const std::string& dat, text_view::Layoutable& output) const;
virtual void load_subject(std::vector<SubjectItem>& output) const;
virtual void load_subject_from_string(
const std::string&, std::vector<SubjectItem>& output) const;
Scrollable(), pango_layout_(create_pango_layout("")), line_list_(),
id_map_(new text_element::IDMap),
res_num_map_(new text_element::ResNumMap),
+ res_num_(0),
width_(-1) {
}
void set_res_num_map(ResNumMapPtrType map) { res_num_map_ = map; }
IDMapPtrType get_id_map() const { return id_map_; }
ResNumMapPtrType get_res_num_map() const { return res_num_map_; }
+ void set_res_num(int res_num) { res_num_ = res_num; }
+ int get_res_num() const { return res_num_; }
protected:
//virtual bool on_expose_event(GdkEventExpose*);
virtual bool on_configure_event(GdkEventConfigure*);
LineListType line_list_;
boost::shared_ptr<text_element::IDMap> id_map_;
boost::shared_ptr<text_element::ResNumMap> res_num_map_;
+ int res_num_;
/* cached */
gint width_;
};
#include <glibmm/convert.h>
#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/filesystem.hpp>
#include <iostream>
+#include <fstream>
#include "bbs_detail_base.hxx"
+#include "thread_idx.hxx"
+#include "http_get.hxx"
namespace dialektos {
SuperClass(),
text_view_(),
scrolled_(text_view_.get_adjustment()),
- bbs_(bbs) {
+ bbs_(bbs), http_getter_(), idx_() {
set_default_size(400,300);
std::cout <<
to_simple_string(microsec_clock::local_time() - start) << std::endl;
+
+ idx_ = ThreadIdx::from_xml(bbs_->get_thread_idx_path());
}
return false;
return lhs == bbs;
}
+void ThreadWindow::on_action_view_refresh() {
+ if (http_getter_) return;
+
+ statusbar_.push("HTTP/1.0 GET...");
+
+ const std::string uri = bbs_->get_thread_dat_uri();
+ http::Header request_header = bbs_->get_thread_dat_request_header();
+ if (request_header.find("Range") != request_header.end()) {
+ if (!idx_.last_modified_.empty())
+ request_header.insert(
+ std::make_pair("If-Modified-Since", idx_.last_modified_));
+ if (!idx_.etag_.empty())
+ request_header.insert(std::make_pair("If-None-Match", idx_.etag_));
+ }
+
+ http_getter_.reset(new http::GetInThread(uri, request_header));
+ http_getter_->signal_end().connect(
+ sigc::mem_fun(*this, &ThreadWindow::on_http_get_end));
+ http_getter_->run();
+}
+
+void ThreadWindow::on_http_get_end(bool success) {
+// const std::string uri = http_getter_->get_uri();
+// const http::Header request_header = http_getter_->get_request_header();
+ const http::Response response = http_getter_->get_response();
+ http_getter_.reset(0);
+ on_refresh_end(response.get_status_line(), response.get_header());
+
+ const int code = response.get_status_line().get_code();
+ if (code != 200 && code != 206) return;
+
+ bbs_->load_thread_from_string(response.get_content(), text_view_);
+ text_view_.relayout();
+ text_view_.queue_draw();
+
+ save_content(response);
+}
+
+void ThreadWindow::on_refresh_end(const http::StatusLine& status,
+ const http::Header& header) {
+ std::string message = status.get_line();
+ http::Header::const_iterator it = header.find("Last-Modified");
+ if (it != header.end()) {
+ message += " ";
+ message += it->second;
+ }
+ statusbar_.push(message);
+}
+
+void ThreadWindow::save_content(const http::Response& response) {
+ const int code = response.get_status_line().get_code();
+ if (code != 200 && code != 206) return;
+
+ std::ofstream ofs(bbs_->get_thread_file_path().c_str(),
+ code == 200 ?
+ std::ios::out | std::ios::trunc : std::ios::out | std::ios::app);
+ ofs << response.get_content();
+ ofs.close();
+
+ if (code == 200)
+ idx_.title_ = bbs_->get_title_from_string(response.get_content());
+
+ http::Header::const_iterator it = response.get_header().find("Last-Modified");
+ if (it != response.get_header().end()) idx_.last_modified_ = it->second;
+ it = response.get_header().find("ETag");
+ if (it != response.get_header().end()) idx_.etag_ = it->second;
+
+ idx_.line_count_ = text_view_.get_res_num();
+
+ idx_.to_xml(boost::filesystem::path(bbs_->get_thread_idx_path()));
+}
+
} // namespace dialektos
#include "application_framework.hxx"
#include "text_view.hxx"
#include "scrolled_container.hxx"
+#include "http_get.hxx"
+#include "thread_idx.hxx"
namespace dialektos {
virtual ~ThreadWindow(){}
protected:
ThreadWindow(std::auto_ptr<bbs_detail::Base> bbs);
+
+ virtual void on_action_view_refresh();
private:
virtual bool is_same(const bbs_detail::Base& bbs) const;
+ void on_http_get_end(bool);
+ void on_refresh_end(const http::StatusLine&, const http::Header&);
+
+ void save_content(const http::Response&);
+
text_view::TextView text_view_;
ScrolledContainer scrolled_;
boost::scoped_ptr<bbs_detail::Base> bbs_;
+ boost::scoped_ptr<http::GetInThread> http_getter_;
+ ThreadIdx idx_;
};