2022-08-29 10:44:06 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace MediaWiki\Extension\VisualEditor;
|
|
|
|
|
|
|
|
use ConfigException;
|
2022-08-28 19:25:04 +00:00
|
|
|
use IBufferingStatsdDataFactory;
|
2022-08-29 10:44:06 +00:00
|
|
|
use MediaWiki\Config\ServiceOptions;
|
2022-08-28 19:25:04 +00:00
|
|
|
use MediaWiki\Edit\ParsoidOutputStash;
|
2022-08-29 10:44:06 +00:00
|
|
|
use MediaWiki\Http\HttpRequestFactory;
|
|
|
|
use MediaWiki\MainConfigNames;
|
2022-08-28 19:25:04 +00:00
|
|
|
use MediaWiki\Parser\Parsoid\HTMLTransformFactory;
|
|
|
|
use MediaWiki\Parser\Parsoid\ParsoidOutputAccess;
|
|
|
|
use MediaWiki\Permissions\Authority;
|
2022-08-29 10:44:06 +00:00
|
|
|
use ParsoidVirtualRESTService;
|
2022-09-04 09:00:14 +00:00
|
|
|
use Psr\Log\LoggerInterface;
|
2022-08-28 19:25:04 +00:00
|
|
|
use RequestContext;
|
2022-08-29 10:44:06 +00:00
|
|
|
use RestbaseVirtualRESTService;
|
|
|
|
use VirtualRESTService;
|
|
|
|
use VirtualRESTServiceClient;
|
|
|
|
|
2022-09-04 09:00:14 +00:00
|
|
|
/**
|
|
|
|
* @since 1.40
|
|
|
|
*/
|
2022-08-29 10:44:06 +00:00
|
|
|
class VisualEditorParsoidClientFactory {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal For use by ServiceWiring.php only or when locating the service
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
public const SERVICE_NAME = 'VisualEditor.ParsoidClientFactory';
|
|
|
|
|
|
|
|
/** @var bool */
|
|
|
|
public const ENABLE_COOKIE_FORWARDING = 'EnableCookieForwarding';
|
|
|
|
|
|
|
|
/** @var bool */
|
|
|
|
public const USE_AUTO_CONFIG = 'VisualEditorParsoidAutoConfig';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal For used by ServiceWiring.php
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
public const CONSTRUCTOR_OPTIONS = [
|
|
|
|
MainConfigNames::VirtualRestConfig,
|
|
|
|
self::USE_AUTO_CONFIG,
|
|
|
|
self::ENABLE_COOKIE_FORWARDING
|
|
|
|
];
|
|
|
|
|
|
|
|
/** @var HttpRequestFactory */
|
|
|
|
private $httpRequestFactory;
|
|
|
|
|
|
|
|
/** @var VirtualRESTServiceClient */
|
|
|
|
private $serviceClient = null;
|
|
|
|
|
|
|
|
/** @var ServiceOptions */
|
|
|
|
private $options;
|
|
|
|
|
2022-09-04 09:00:14 +00:00
|
|
|
/** @var LoggerInterface */
|
|
|
|
private $logger;
|
2022-08-29 10:44:06 +00:00
|
|
|
|
2022-08-28 19:25:04 +00:00
|
|
|
/** @var ParsoidOutputStash */
|
|
|
|
private $parsoidOutputStash;
|
|
|
|
|
|
|
|
/** @var IBufferingStatsdDataFactory */
|
|
|
|
private $statsDataFactory;
|
|
|
|
|
|
|
|
/** @var ParsoidOutputAccess */
|
|
|
|
private $parsoidOutputAccess;
|
|
|
|
|
|
|
|
/** @var HTMLTransformFactory */
|
|
|
|
private $htmlTransformFactory;
|
|
|
|
|
2022-08-29 10:44:06 +00:00
|
|
|
/**
|
|
|
|
* @param ServiceOptions $options
|
|
|
|
* @param HttpRequestFactory $httpRequestFactory
|
2022-09-04 09:00:14 +00:00
|
|
|
* @param LoggerInterface $logger
|
2022-08-28 19:25:04 +00:00
|
|
|
* @param ParsoidOutputStash $parsoidOutputStash
|
|
|
|
* @param IBufferingStatsdDataFactory $statsDataFactory
|
|
|
|
* @param ParsoidOutputAccess $parsoidOutputAccess
|
|
|
|
* @param HTMLTransformFactory $htmlTransformFactory
|
2022-08-29 10:44:06 +00:00
|
|
|
*/
|
|
|
|
public function __construct(
|
|
|
|
ServiceOptions $options,
|
2022-09-04 09:00:14 +00:00
|
|
|
HttpRequestFactory $httpRequestFactory,
|
2022-08-28 19:25:04 +00:00
|
|
|
LoggerInterface $logger,
|
|
|
|
ParsoidOutputStash $parsoidOutputStash,
|
|
|
|
IBufferingStatsdDataFactory $statsDataFactory,
|
|
|
|
ParsoidOutputAccess $parsoidOutputAccess,
|
|
|
|
HTMLTransformFactory $htmlTransformFactory
|
2022-08-29 10:44:06 +00:00
|
|
|
) {
|
|
|
|
$this->options = $options;
|
|
|
|
$this->options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
|
|
|
|
|
|
|
|
$this->httpRequestFactory = $httpRequestFactory;
|
2022-09-04 09:00:14 +00:00
|
|
|
$this->logger = $logger;
|
2022-08-28 19:25:04 +00:00
|
|
|
$this->parsoidOutputStash = $parsoidOutputStash;
|
|
|
|
$this->statsDataFactory = $statsDataFactory;
|
|
|
|
$this->parsoidOutputAccess = $parsoidOutputAccess;
|
|
|
|
$this->htmlTransformFactory = $htmlTransformFactory;
|
2022-08-29 10:44:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-09-04 09:00:14 +00:00
|
|
|
* Create a ParsoidClient for accessing Parsoid.
|
|
|
|
*
|
|
|
|
* @param string|string[]|false $cookiesToForward
|
2022-08-28 19:25:04 +00:00
|
|
|
* @param Authority|null $performer
|
2022-09-04 09:00:14 +00:00
|
|
|
*
|
|
|
|
* @return ParsoidClient
|
2022-08-29 10:44:06 +00:00
|
|
|
*/
|
2022-08-28 19:25:04 +00:00
|
|
|
public function createParsoidClient( $cookiesToForward, ?Authority $performer = null ): ParsoidClient {
|
|
|
|
if ( $performer === null ) {
|
|
|
|
$performer = RequestContext::getMain()->getAuthority();
|
|
|
|
}
|
2022-09-04 09:00:14 +00:00
|
|
|
|
2022-10-13 10:05:13 +00:00
|
|
|
if ( $this->useRestbase() ) {
|
2022-09-04 09:00:14 +00:00
|
|
|
$client = new VRSParsoidClient(
|
|
|
|
$this->getVRSClient( $cookiesToForward ),
|
|
|
|
$this->logger
|
|
|
|
);
|
2022-10-13 10:05:13 +00:00
|
|
|
} else {
|
|
|
|
$client = $this->createDirectClient( $performer );
|
2022-09-04 09:00:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return $client;
|
|
|
|
}
|
|
|
|
|
2022-10-13 10:05:13 +00:00
|
|
|
public function useRestbase(): bool {
|
2022-09-04 09:00:14 +00:00
|
|
|
// We haven't checked configuration yet.
|
|
|
|
// Check to see if any of the restbase-related configuration
|
|
|
|
// variables are set, and bail if so:
|
|
|
|
$vrs = $this->options->get( MainConfigNames::VirtualRestConfig );
|
|
|
|
if ( isset( $vrs['modules'] ) &&
|
|
|
|
( isset( $vrs['modules']['restbase'] ) ||
|
|
|
|
isset( $vrs['modules']['parsoid'] ) )
|
|
|
|
) {
|
2022-10-13 10:05:13 +00:00
|
|
|
return true;
|
2022-09-04 09:00:14 +00:00
|
|
|
}
|
2022-10-13 10:05:13 +00:00
|
|
|
|
2022-09-04 09:00:14 +00:00
|
|
|
// Eventually we'll do something fancy, but I'm hacking here...
|
|
|
|
if ( !$this->options->get( self::USE_AUTO_CONFIG ) ) {
|
|
|
|
// explicit opt out
|
2022-10-13 10:05:13 +00:00
|
|
|
return true;
|
2022-09-04 09:00:14 +00:00
|
|
|
}
|
|
|
|
|
2022-10-13 10:05:13 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a ParsoidClient for accessing Parsoid.
|
|
|
|
*
|
|
|
|
* @param Authority $performer
|
|
|
|
*
|
|
|
|
* @return ParsoidClient
|
|
|
|
*/
|
|
|
|
private function createDirectClient( Authority $performer ): ParsoidClient {
|
2022-09-04 09:00:14 +00:00
|
|
|
return new DirectParsoidClient(
|
2022-08-28 19:25:04 +00:00
|
|
|
$this->parsoidOutputStash,
|
|
|
|
$this->statsDataFactory,
|
|
|
|
$this->parsoidOutputAccess,
|
|
|
|
$this->htmlTransformFactory,
|
|
|
|
$performer
|
2022-08-29 10:44:06 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates the virtual REST service object to be used in VE's API calls. The
|
|
|
|
* method determines whether to instantiate a ParsoidVirtualRESTService or a
|
|
|
|
* RestbaseVirtualRESTService object based on configuration directives: if
|
|
|
|
* $wgVirtualRestConfig['modules']['restbase'] is defined, RESTBase is chosen,
|
|
|
|
* otherwise Parsoid is used (either by using the MW Core config, or the
|
|
|
|
* VE-local one).
|
|
|
|
*
|
|
|
|
* @param string|string[]|false $forwardCookies False if header is unset; otherwise the
|
|
|
|
* header value(s) as either a string (the default) or an array, if
|
|
|
|
* WebRequest::GETHEADER_LIST flag was set.
|
|
|
|
*
|
|
|
|
* @return VirtualRESTService the VirtualRESTService object to use
|
|
|
|
*/
|
2022-09-04 09:00:14 +00:00
|
|
|
private function createVRSObject( $forwardCookies ): VirtualRESTService {
|
2022-08-29 10:44:06 +00:00
|
|
|
// the params array to create the service object with
|
|
|
|
$params = [];
|
|
|
|
// the VRS class to use, defaults to Parsoid
|
|
|
|
$class = ParsoidVirtualRESTService::class;
|
|
|
|
// The global virtual rest service config object, if any
|
|
|
|
$vrs = $this->options->get( MainConfigNames::VirtualRestConfig );
|
|
|
|
if ( isset( $vrs['modules'] ) && isset( $vrs['modules']['restbase'] ) ) {
|
|
|
|
// if restbase is available, use it
|
|
|
|
$params = $vrs['modules']['restbase'];
|
|
|
|
// backward compatibility
|
|
|
|
$params['parsoidCompat'] = false;
|
|
|
|
$class = RestbaseVirtualRESTService::class;
|
|
|
|
} elseif ( isset( $vrs['modules'] ) && isset( $vrs['modules']['parsoid'] ) ) {
|
|
|
|
// there's a global parsoid config, use it next
|
|
|
|
$params = $vrs['modules']['parsoid'];
|
|
|
|
$params['restbaseCompat'] = true;
|
|
|
|
} elseif ( $this->options->get( self::USE_AUTO_CONFIG ) ) {
|
|
|
|
$params = $vrs['modules']['parsoid'] ?? [];
|
|
|
|
$params['restbaseCompat'] = true;
|
|
|
|
// forward cookies on private wikis
|
|
|
|
$params['forwardCookies'] = $this->options->get( self::ENABLE_COOKIE_FORWARDING );
|
|
|
|
} else {
|
|
|
|
// No global modules defined, so no way to contact the document server.
|
|
|
|
throw new ConfigException( "The VirtualRESTService for the document server is not defined;" .
|
|
|
|
" see https://www.mediawiki.org/wiki/Extension:VisualEditor" );
|
|
|
|
}
|
|
|
|
// merge the global and service-specific params
|
|
|
|
if ( isset( $vrs['global'] ) ) {
|
|
|
|
$params = array_merge( $vrs['global'], $params );
|
|
|
|
}
|
|
|
|
// set up cookie forwarding
|
|
|
|
if ( isset( $params['forwardCookies'] ) && $params['forwardCookies'] ) {
|
|
|
|
$params['forwardCookies'] = $forwardCookies;
|
|
|
|
} else {
|
|
|
|
$params['forwardCookies'] = false;
|
|
|
|
}
|
|
|
|
// create the VRS object and return it
|
|
|
|
return new $class( $params );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates the object which directs queries to the virtual REST service, depending on the path.
|
|
|
|
*
|
2022-09-04 09:00:14 +00:00
|
|
|
* @param string|string[]|false $cookiesToForward False if header is unset; otherwise the
|
2022-08-29 10:44:06 +00:00
|
|
|
* header value(s) as either a string (the default) or an array, if
|
|
|
|
* WebRequest::GETHEADER_LIST flag was set.
|
|
|
|
*
|
|
|
|
* @return VirtualRESTServiceClient
|
|
|
|
*/
|
2022-09-04 09:00:14 +00:00
|
|
|
private function getVRSClient( $cookiesToForward ): VirtualRESTServiceClient {
|
2022-08-29 10:44:06 +00:00
|
|
|
if ( !$this->serviceClient ) {
|
|
|
|
$this->serviceClient = new VirtualRESTServiceClient( $this->httpRequestFactory->createMultiClient() );
|
2022-09-04 09:00:14 +00:00
|
|
|
$this->serviceClient->mount( '/restbase/', $this->createVRSObject( $cookiesToForward ) );
|
2022-08-29 10:44:06 +00:00
|
|
|
}
|
|
|
|
return $this->serviceClient;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|