2022-12-30 21:54:44 +01:00
< ? php
declare ( strict_types = 1 );
2020-07-11 20:01:54 +02:00
/**
* Session paths module .
*
* This file is part of MadelineProto .
* MadelineProto 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 .
* MadelineProto 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 General Public License along with MadelineProto .
* If not , see < http :// www . gnu . org / licenses />.
*
* @ author Daniil Gentili < daniil @ daniil . it >
2023-01-04 12:43:01 +01:00
* @ copyright 2016 - 2023 Daniil Gentili < daniil @ daniil . it >
2020-07-11 20:01:54 +02:00
* @ license https :// opensource . org / licenses / AGPL - 3.0 AGPLv3
* @ link https :// docs . madelineproto . xyz MadelineProto documentation
*/
namespace danog\MadelineProto ;
2020-09-24 11:45:20 +02:00
use danog\MadelineProto\Ipc\IpcState ;
2022-12-30 19:21:36 +01:00
use const LOCK_EX ;
use const LOCK_SH ;
use const PHP_MAJOR_VERSION ;
use const PHP_MINOR_VERSION ;
use const PHP_VERSION ;
2023-01-19 16:18:22 +01:00
use function Amp\File\createDirectory ;
2023-01-19 17:14:04 +01:00
use function Amp\File\deleteFile ;
2020-09-24 11:45:20 +02:00
use function Amp\File\exists ;
2023-01-15 16:17:45 +01:00
use function Amp\File\getStatus ;
2023-01-19 16:18:22 +01:00
use function Amp\File\isDirectory ;
use function Amp\File\isFile ;
2023-01-03 21:51:49 +01:00
use function Amp\File\move ;
2021-12-15 13:51:01 +01:00
use function Amp\File\openFile ;
2023-01-03 21:51:49 +01:00
use function Amp\File\write ;
2020-09-22 23:10:56 +02:00
2020-07-11 20:01:54 +02:00
/**
* Session path information .
2023-02-16 18:38:47 +01:00
*
* @ internal
2020-07-11 20:01:54 +02:00
*/
2023-01-15 12:05:38 +01:00
final class SessionPaths
2020-07-11 20:01:54 +02:00
{
2020-09-22 23:10:56 +02:00
/**
* Legacy session path .
*/
2023-01-19 16:18:22 +01:00
private string $sessionDirectoryPath ;
2020-07-11 20:01:54 +02:00
/**
* Session path .
*/
private string $sessionPath ;
/**
* Session lock path .
*/
private string $lockPath ;
/**
* IPC socket path .
*/
private string $ipcPath ;
2020-09-25 19:17:16 +02:00
/**
* IPC callback socket path .
*/
private string $ipcCallbackPath ;
2020-09-22 23:10:56 +02:00
/**
* IPC light state path .
*/
private string $ipcStatePath ;
2020-07-11 20:01:54 +02:00
/**
2020-09-24 11:45:20 +02:00
* Light state path .
*/
private string $lightStatePath ;
/**
* Light state .
2020-07-11 20:01:54 +02:00
*/
2020-09-24 11:45:20 +02:00
private ? LightState $lightState = null ;
2020-07-11 20:01:54 +02:00
/**
* Construct session info from session name .
*
* @ param string $session Session name
*/
public function __construct ( string $session )
{
$session = Tools :: absolute ( $session );
2023-01-19 16:18:22 +01:00
$this -> sessionDirectoryPath = $session ;
2023-01-23 19:32:28 +01:00
$this -> sessionPath = $session . DIRECTORY_SEPARATOR . " safe.php " ;
$this -> lightStatePath = $session . DIRECTORY_SEPARATOR . " lightState.php " ;
$this -> lockPath = $session . DIRECTORY_SEPARATOR . " lock " ;
$this -> ipcPath = $session . DIRECTORY_SEPARATOR . " ipc " ;
$this -> ipcCallbackPath = $session . DIRECTORY_SEPARATOR . " callback.ipc " ;
$this -> ipcStatePath = $session . DIRECTORY_SEPARATOR . " ipcState.php " ;
2023-01-19 16:18:22 +01:00
if ( ! exists ( $session )) {
createDirectory ( $session );
return ;
}
if ( ! isDirectory ( $session ) && isFile ( " $session .safe.php " )) {
2023-01-19 17:14:04 +01:00
deleteFile ( $session );
2023-01-19 16:18:22 +01:00
createDirectory ( $session );
foreach ([ 'safe.php' , 'lightState.php' , 'lock' , 'ipc' , 'callback.ipc' , 'ipcState.php' ] as $part ) {
if ( exists ( " $session . $part " )) {
2023-01-23 19:32:28 +01:00
move ( " $session . $part " , $session . DIRECTORY_SEPARATOR . " $part " );
2023-01-19 16:18:22 +01:00
}
if ( exists ( " $session . $part .lock " )) {
2023-01-23 19:32:28 +01:00
move ( " $session . $part .lock " , $session . DIRECTORY_SEPARATOR . " $part .lock " );
2023-01-19 16:18:22 +01:00
}
}
}
2020-07-11 20:01:54 +02:00
}
2020-09-24 11:45:20 +02:00
/**
* Serialize object to file .
*/
2023-01-03 21:51:49 +01:00
public function serialize ( object $object , string $path ) : void
2020-09-24 11:45:20 +02:00
{
2021-04-08 15:38:55 +02:00
Logger :: log ( " Waiting for exclusive lock of $path .lock... " );
2022-12-30 20:24:13 +01:00
$unlock = Tools :: flock ( " $path .lock " , LOCK_EX , 0.1 );
2020-09-24 11:45:20 +02:00
2021-04-08 15:38:55 +02:00
try {
2021-04-18 16:02:59 +02:00
Logger :: log ( " Got exclusive lock of $path .lock... " );
2021-04-08 15:38:55 +02:00
2021-12-15 14:46:06 +01:00
$object = Serialization :: PHP_HEADER
2023-05-02 18:42:46 +02:00
. \chr ( Serialization :: VERSION_SERIALIZATION_AWARE )
2021-12-15 14:46:06 +01:00
. \chr ( PHP_MAJOR_VERSION )
. \chr ( PHP_MINOR_VERSION )
2023-05-02 18:42:46 +02:00
. \chr ( Magic :: $can_use_igbinary ? 1 : 0 )
. ( Magic :: $can_use_igbinary ? \igbinary_serialize ( $object ) : \serialize ( $object ));
2021-04-25 17:11:11 +02:00
2023-01-03 21:51:49 +01:00
write (
2021-12-15 14:46:06 +01:00
" $path .temp.php " ,
2022-12-30 19:21:36 +01:00
$object ,
2021-12-15 14:46:06 +01:00
);
2021-04-08 15:38:55 +02:00
2023-01-03 21:51:49 +01:00
move ( " $path .temp.php " , $path );
2021-04-08 15:38:55 +02:00
} finally {
$unlock ();
}
2020-09-24 11:45:20 +02:00
}
/**
* Deserialize new object .
*
* @ param string $path Object path , defaults to session path
*/
2023-01-03 21:51:49 +01:00
public function unserialize ( string $path = '' ) : ? object
2020-09-24 11:45:20 +02:00
{
$path = $path ? : $this -> sessionPath ;
2022-12-30 22:31:20 +01:00
if ( ! exists ( $path )) {
2020-09-24 11:45:20 +02:00
return null ;
}
2021-12-12 15:17:55 +01:00
$headerLen = \strlen ( Serialization :: PHP_HEADER );
2020-09-24 11:45:20 +02:00
2021-06-10 15:54:15 +02:00
Logger :: log ( " Waiting for shared lock of $path .lock... " , Logger :: ULTRA_VERBOSE );
2022-12-30 20:24:13 +01:00
$unlock = Tools :: flock ( " $path .lock " , LOCK_SH , 0.1 );
2020-09-24 11:45:20 +02:00
2021-04-08 15:38:55 +02:00
try {
2021-06-10 15:54:15 +02:00
Logger :: log ( " Got shared lock of $path .lock... " , Logger :: ULTRA_VERBOSE );
2020-09-24 11:45:20 +02:00
2022-12-30 22:31:20 +01:00
$file = openFile ( $path , 'rb' );
2023-01-19 23:20:49 +01:00
try {
2023-05-22 19:44:07 +02:00
\touch ( $path ); // Invalidate size cache
2023-01-20 13:49:44 +01:00
} catch ( \Throwable ) {
}
2023-01-15 16:17:45 +01:00
$size = getStatus ( $path );
2021-04-08 15:38:55 +02:00
$size = $size [ 'size' ] ? ? $headerLen ;
2022-12-30 22:31:20 +01:00
$file -> seek ( $headerLen ++ );
2023-01-03 21:51:49 +01:00
$v = \ord ( $file -> read ( null , 1 ));
2023-05-02 18:42:46 +02:00
if ( $v >= Serialization :: VERSION_OLD ) {
2023-01-03 21:51:49 +01:00
$php = $file -> read ( null , 2 );
2021-12-12 15:17:55 +01:00
$major = \ord ( $php [ 0 ]);
$minor = \ord ( $php [ 1 ]);
if ( \version_compare ( " $major . $minor " , PHP_VERSION ) > 0 ) {
throw new Exception ( " Cannot deserialize session created on newer PHP $major . $minor , currently using PHP " . PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . ', please upgrade to the latest version of PHP!' );
}
$headerLen += 2 ;
}
2023-05-02 18:42:46 +02:00
$igbinary = false ;
if ( $v >= Serialization :: VERSION_SERIALIZATION_AWARE ) {
$igbinary = ( bool ) \ord ( $file -> read ( null , 1 ));
if ( $igbinary && ! Magic :: $can_use_igbinary ) {
throw Exception :: extension ( 'igbinary' );
}
$headerLen ++ ;
}
$unserialized = $file -> read ( null , $size - $headerLen ) ? ? '' ;
$unserialized = $igbinary ? \igbinary_unserialize ( $unserialized ) : \unserialize ( $unserialized );
2022-12-30 22:31:20 +01:00
$file -> close ();
2021-04-08 15:38:55 +02:00
} finally {
$unlock ();
}
2020-09-24 11:45:20 +02:00
return $unserialized ;
}
2020-07-11 20:01:54 +02:00
/**
* Get session path .
*/
public function __toString () : string
{
2023-01-19 16:18:22 +01:00
return $this -> sessionDirectoryPath ;
2020-09-22 23:10:56 +02:00
}
/**
* Get legacy session path .
*/
2023-01-19 16:18:22 +01:00
public function getSessionDirectoryPath () : string
2020-09-22 23:10:56 +02:00
{
2023-01-19 16:18:22 +01:00
return $this -> sessionDirectoryPath ;
2020-07-11 20:01:54 +02:00
}
/**
* Get session path .
*/
public function getSessionPath () : string
{
return $this -> sessionPath ;
}
/**
* Get lock path .
*/
public function getLockPath () : string
{
return $this -> lockPath ;
}
/**
* Get IPC socket path .
*/
public function getIpcPath () : string
{
return $this -> ipcPath ;
}
/**
2020-09-24 11:45:20 +02:00
* Get IPC light state path .
2020-07-11 20:01:54 +02:00
*/
2020-09-24 11:45:20 +02:00
public function getIpcStatePath () : string
2020-07-11 20:01:54 +02:00
{
2020-09-24 11:45:20 +02:00
return $this -> ipcStatePath ;
2020-07-11 20:01:54 +02:00
}
2020-09-22 23:10:56 +02:00
/**
2020-09-24 11:45:20 +02:00
* Get IPC state .
*/
2023-01-03 21:51:49 +01:00
public function getIpcState () : ? IpcState
2020-09-24 11:45:20 +02:00
{
2023-01-03 21:51:49 +01:00
return $this -> unserialize ( $this -> ipcStatePath );
2020-09-24 11:45:20 +02:00
}
/**
* Store IPC state .
*/
2023-01-03 21:51:49 +01:00
public function storeIpcState ( IpcState $state ) : void
2020-09-24 11:45:20 +02:00
{
2023-01-03 21:51:49 +01:00
$this -> serialize ( $state , $this -> getIpcStatePath ());
2020-09-24 11:45:20 +02:00
}
/**
* Get light state path .
2020-09-22 23:10:56 +02:00
*/
2020-09-24 11:45:20 +02:00
public function getLightStatePath () : string
2020-09-22 23:10:56 +02:00
{
2020-09-24 11:45:20 +02:00
return $this -> lightStatePath ;
2020-09-22 23:10:56 +02:00
}
/**
2020-09-24 11:45:20 +02:00
* Get light state .
2020-09-22 23:10:56 +02:00
*/
2023-01-03 21:51:49 +01:00
public function getLightState () : LightState
2020-09-24 11:45:20 +02:00
{
2023-01-25 16:37:15 +01:00
/** @var LightState */
2023-01-03 21:51:49 +01:00
return $this -> lightState ? ? = $this -> unserialize ( $this -> lightStatePath );
2020-09-24 11:45:20 +02:00
}
/**
* Store light state .
*/
2023-01-03 21:51:49 +01:00
public function storeLightState ( MTProto $state ) : void
2020-09-22 23:10:56 +02:00
{
2020-09-24 11:45:20 +02:00
$this -> lightState = new LightState ( $state );
2023-01-03 21:51:49 +01:00
$this -> serialize ( $this -> lightState , $this -> getLightStatePath ());
2020-09-22 23:10:56 +02:00
}
2020-09-25 19:17:16 +02:00
/**
* Get IPC callback socket path .
*/
public function getIpcCallbackPath () : string
{
return $this -> ipcCallbackPath ;
}
2020-07-11 20:01:54 +02:00
}