1 /*
2  * Copyright (C) 2010 Emweb bv, Herent, Belgium.
3  *
4  * See the LICENSE file for terms of use.
5  */
6 
7 #include <Wt/WApplication.h>
8 #include <Wt/WServer.h>
9 #include <Wt/WRandom.h>
10 #include <mutex>
11 
12 #include "CodeSession.h"
13 
14 std::recursive_mutex CodeSession::mutex_;
15 std::vector<std::weak_ptr<CodeSession>> CodeSession::sessions_;
16 
CodeSession(const CoderCallback & coderCallback)17 CodeSession::CodeSession(const CoderCallback& coderCallback)
18 {
19   generateId();
20 
21   coder_ = std::make_unique<Coder>();
22   coder_->sessionId = Wt::WApplication::instance()->sessionId();
23   coder_->callback = coderCallback;
24 }
25 
~CodeSession()26 CodeSession::~CodeSession()
27 {
28 }
29 
addSession(const std::shared_ptr<CodeSession> & session)30 void CodeSession::addSession(const std::shared_ptr<CodeSession> &session)
31 {
32   Lock lock(mutex_);
33   cleanExpiredSessions();
34   sessions_.push_back(session);
35 }
36 
addObserver(const std::string & id,const BufferCallback & bufferCallback)37 std::shared_ptr<CodeSession> CodeSession::addObserver(const std::string& id,
38                                        const BufferCallback& bufferCallback)
39 {
40   Lock lock(mutex_);
41 
42   for (auto& sessionPtr : sessions_) {
43     auto session = sessionPtr.lock();
44     if (session && session->id() == id) {
45       Observer observer;
46       observer.sessionId = Wt::WApplication::instance()->sessionId();
47       observer.callback = bufferCallback;
48 
49       session->observers_.push_back(observer);
50       session->postSessionChanged();
51 
52       return session;
53     }
54   }
55 
56   return 0;
57 }
58 
removeObserver()59 void CodeSession::removeObserver()
60 {
61   Lock lock(mutex_);
62 
63   std::string sessionId = Wt::WApplication::instance()->sessionId();
64 
65   for (unsigned i = 0; i < observers_.size(); ++i) {
66     if (observers_[i].sessionId == sessionId) {
67       observers_.erase(observers_.begin() + i);
68 
69       postSessionChanged();
70 
71       return;
72     }
73   }
74 }
75 
removeCoder()76 void CodeSession::removeCoder()
77 {
78   Lock lock(mutex_);
79   coder_.reset();
80 }
81 
insertBuffer(int index)82 void CodeSession::insertBuffer(int index)
83 {
84   Lock lock(mutex_);
85 
86   buffers_.insert(buffers_.begin() + index, Buffer());
87 
88   postBufferChanged(index, Inserted);
89 }
90 
updateBuffer(int buffer,const Wt::WString & name,const Wt::WString & text)91 void CodeSession::updateBuffer(int buffer, const Wt::WString& name,
92                                const Wt::WString& text)
93 {
94   Lock lock(mutex_);
95 
96   buffers_[buffer].name = name;
97   buffers_[buffer].text = text;
98 
99   postBufferChanged(buffer, Changed);
100 }
101 
buffers()102 std::vector<CodeSession::Buffer> CodeSession::buffers() const
103 {
104   Lock lock(mutex_);
105 
106   return buffers_;
107 }
108 
buffer(int buffer)109 CodeSession::Buffer CodeSession::buffer(int buffer) const
110 {
111   Lock lock(mutex_);
112 
113   return buffers_[buffer];
114 }
115 
cleanExpiredSessions()116 void CodeSession::cleanExpiredSessions()
117 {
118   auto it = sessions_.begin();
119 
120   while(it != sessions_.end()) {
121     if((*it).expired()) {
122       it = sessions_.erase(it);
123     }
124     else ++it;
125   }
126 }
127 
generateId()128 void CodeSession::generateId()
129 {
130   id_ = Wt::WRandom::generateId(32);
131 }
132 
postSessionChanged()133 void CodeSession::postSessionChanged()
134 {
135   if (coder_)
136     Wt::WServer::instance()->post(coder_->sessionId, coder_->callback);
137 }
138 
postBufferChanged(int buffer,BufferUpdate update)139 void CodeSession::postBufferChanged(int buffer, BufferUpdate update)
140 {
141   for (auto& observer : observers_) {
142     Wt::WServer::instance()
143       ->post(observer.sessionId,
144              std::bind(observer.callback, buffer, update));
145   }
146 }
147