Commit 15ac52f0 authored by Matthieu Le Corre's avatar Matthieu Le Corre

add user presence detection

Signed-off-by: Matthieu Le Corre's avatarMatthieu Le Corre <matthieu.lecorre@univ-nantes.fr>
parent 438f880a
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
......@@ -30,15 +30,12 @@ use OCA\whiteboard\Db\StepMapper ;
use OCA\whiteboard\Db\User ;
use OCA\whiteboard\Db\UserMapper ;
//class CollaborationEngine implements ICollaborationEngine {
class CollaborationEngine {
private $StepMapper ;
private $UserMapper ;
private $cache ;
// private $cache ;
public function __construct(ICacheFactory $cacheFactory, StepMapper $StepMapper, UserMapper $UserMapper) {
......@@ -73,11 +70,12 @@ class CollaborationEngine {
return $this->UserMapper->insert($Nuser);
} else {
$this->updateLastSeen($user,$fileId) ;
return "already there" ;
} ;
}
//ALMOST DONE
//DONE
public function removeUser(int $fileId, string $user) {
$usr = $this->UserMapper->find($user,$this->AppName,$fileId) ;
$cnt = count($this->UserMapper->findAll($this->AppName,$fileId)) ;
......@@ -98,6 +96,8 @@ class CollaborationEngine {
// DONE
public function addStep(int $fileId,string $user, string $type, string $datas) {
$this->updateLastSeen($user,$fileId) ;
$Nstep = new Step() ;
$Nstep->setAppId($this->AppName) ;
......@@ -120,8 +120,14 @@ class CollaborationEngine {
// DONE
public function getUserList($fileId) {
$result = $this->UserMapper->findAll($this->AppName,$fileId) ;
return $result ;
$users = $this->UserMapper->findAll($this->AppName,$fileId) ;
foreach ($users as $user) {
if ($user->getLastSeen() + 60 < time()) {
$this->UserMapper->delete($user) ;
}
}
return $users ;
}
// DONE
......@@ -138,6 +144,9 @@ class CollaborationEngine {
sleep(1) ;
}
} ;
$this->updateLastSeen($user,$fileId) ;
foreach ($steps as $step) {
$forwarded = explode(',',$step->getStepForwarded()) ;
$forwarded[] = $user ;
......@@ -147,5 +156,12 @@ class CollaborationEngine {
} ;
return $steps ;
}
// PRIVATE
private function updateLastSeen(string $userId, int $fileId) {
$usr = $this->UserMapper->find($userId,$this->AppName,$fileId) ;
$usr->setLastSeen(time()) ;
$this->UserMapper->update($usr) ;
}
}
\ No newline at end of file
<?php
/**
* @author 2020 Matthieu Le Corre <matthieu.lecorre@univ-nantes.fr>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\whiteboard\Collaboration ;
use OCP\User ;
interface ICollaborationEngine {
public function createSession(string $fileId): int ;
public function addUser(User $user): int ;
public function removeUser(User $user): int ;
public function addStep(User $user, string $type,string $step): int ;
public function getStep(): array ;
}
\ No newline at end of file
<?php
/**
* @author 2020 Matthieu Le Corre <matthieu.lecorre@univ-nantes.fr>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\whiteboard\Collaboration ;
use OCP\ICache ;
use OCP\ICacheFactory;
//class SimpleFileCollaborationEngine implements ICollaborationEngine {
class SimpleFileCollaborationEngine {
public function __construct(string $fileId, ICacheFactory $cacheFactory) {
$this->file = $fileId ;
$this->cache = $cacheFactory->createDistributed('WhiteboardSession::'.$this->file);
try {
$this->Fsession = json_decode(file_get_contents("/tmp/session-".$this->file),true) ;
} catch (Exception $e) {
$this->Fsession =Array() ;
}
}
public function startSession(string $file) {
if (! (in_array($file,$this->Fsession["session"]))) {
$this->Fsession["session"] = $file ;
return $this-> updateStorage() ;
} ;
}
public function addUser(string $user) {
if (! (in_array($user,$this->Fsession["user"]))) {
$this->Fsession["user"][]=$user ;
return $this-> updateStorage() ;
} ;
}
public function removeUSer(string $user) {
$index = array_search($user, $this->Fsession["user"]) ;
if ($index !== FALSE ) {
unset($this->Fsession["user"][$index]) ;
if ( $this->getUserNumber() == 0 ) {
return $this->sessionDestroy() ;
} else {
return $this-> updateStorage() ;
} ;
} ;
}
public function addStep($user,$type,$datas) {
$step = array (
"user" => $user,
"type" => $type,
"data" => $datas,
"stepid" => time()
) ;
$this->Fsession["steps"][]=$step ;
//send last step to the cache to be pushed to client should be faster then anything else !
//$this->cache->set('WhiteboardSession::'.$this->file,json_encode($step)) ;
$this->setLastStep($step) ;
return $this-> updateStorage() ;
}
public function getSteps($fromStep,$handleCheckpoint = FALSE ) {
$result = Array() ;
foreach ($this->Fsession["steps"] as $step) {
// if save step then dont send step before this one
if ($step["type"] == "save" && $handleCheckpoint == TRUE ) {
$result = [] ;
} else {
if ($step["stepid"] > $fromstep) {
$result[] = $step ;
}
}
}
return $result ;
}
public function getUserList() {
return $this->Fsession["user"] ;
}
public function waitForNewSteps(){
$timeout = 20 ;
$elapsedTime = 0;
while (empty($step) && $elapsedTime < $timeout) {
sleep(1) ;
//$step = json_decode($this->cache->get('WhiteboardSession::'.$this->file)) ;
$step = $this->getLastStep() ;
$elapsedTime++ ;
return $step ;
} ;
//remove key from cache
//$this->cache.remove('WhiteboardSession::'.$this->file) ;
return $step ;
}
/* Private methods */
private function updateStorage() {
$payload = json_encode($this->Fsession) ;
$result = file_put_contents("/tmp/session-".$this->file,$payload) ;
return $result ;
}
private function getUserNumber() {
return count($this->Fsession["user"]) ;
}
private function sessionDestroy() {
return unlink("/tmp/session-".$this->file) ;
}
private function setLastStep($step){
$jstep = json_encode($step) ;
file_put_contents("/tmp/session-queue-".$this->file,jstep,FILE_APPEND) ;
}
private function getLastStep(){
$step = file_get_contents("/tmp/session-queue-".$this->file) ;
return json_decode($step,true) ;
}
}
\ No newline at end of file
......@@ -24,8 +24,12 @@
<button class="icon-save" @click="save" />
<button class="icon-menu-sidebar" @click="sidebar" />
<ul v-if="userList.length > 1" class="AvatarList">
<li v-for="user in userList" :key="userList.indexOf(user)">
<Avatar :user="user" />
<li v-for="user in userList"
:key="userList.indexOf(user)"
:class="{ offline: isOffline(user) }">
<Avatar
:user="user.userId"
menu-position="left" />
</li>
</ul>
<AppContent :id="apped">
......@@ -60,6 +64,14 @@ export default {
}
},
methods: {
isOffline: function(user) {
const now = Math.floor(Date.now() / 1000) - 30
if (user.lastSeen < now) {
return true
} else {
return false
}
},
save() {
emit(this.appName + '::saveClick')
},
......@@ -107,4 +119,8 @@ button:hover {
.AvatarList li {
margin-left: 2px ;
}
.offline {
opacity: .4 ;
}
</style>
......@@ -83,7 +83,7 @@ export default {
),
})
this.vm.$mount(container)
this.vm.$mount(container)
subscribe(this.APP_NAME + '::saveClick', function() {
self.saveEdit()
......@@ -173,8 +173,7 @@ export default {
// engine tells us that users list changed
subscribe(this.APP_NAME + '::usersListChanged', this.ECU = (users) => {
this.userList.length = 0
users.data.forEach(user => this.userList.push(user.userId))
// console.log(this.userList)
users.data.forEach(user => this.userList.push(user))
})
},
......@@ -187,6 +186,7 @@ export default {
// unsubscribe from bus event
unsubscribe(this.APP_NAME + '::editorAddStep', this.EDS)
unsubscribe(this.APP_NAME + '::externalAddStep', this.EAS)
unsubscribe(this.APP_NAME + '::usersListChanged', this.ECU)
// stop collaboration Engine
this.CE.stop()
......@@ -195,7 +195,7 @@ export default {
this.ED.stop()
// remove app container
// TODO handle Vue destroying
this.vm.$destroy()
document.getElementById('app-content-' + this.APP_NAME).remove()
document.getElementById('app-navigation').classList.remove('hidden')
},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment