Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F1066140
PhabricatorAphlictManagementWorkflow.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
PhabricatorAphlictManagementWorkflow.php
View Options
<?php
abstract
class
PhabricatorAphlictManagementWorkflow
extends
PhabricatorManagementWorkflow
{
private
$debug
=
false
;
private
$clientHost
;
private
$clientPort
;
protected
function
didConstruct
()
{
$this
->
setArguments
(
array
(
array
(
'name'
=>
'client-host'
,
'param'
=>
'hostname'
,
'help'
=>
pht
(
'Hostname to bind to for the client server.'
),
),
array
(
'name'
=>
'client-port'
,
'param'
=>
'port'
,
'help'
=>
pht
(
'Port to bind to for the client server.'
),
),
));
}
public
function
execute
(
PhutilArgumentParser
$args
)
{
$this
->
clientHost
=
$args
->
getArg
(
'client-host'
);
$this
->
clientPort
=
$args
->
getArg
(
'client-port'
);
return
0
;
}
final
public
function
getPIDPath
()
{
return
PhabricatorEnv
::
getEnvConfig
(
'notification.pidfile'
);
}
final
public
function
getLogPath
()
{
$path
=
PhabricatorEnv
::
getEnvConfig
(
'notification.log'
);
try
{
$dir
=
dirname
(
$path
);
if
(!
Filesystem
::
pathExists
(
$dir
))
{
Filesystem
::
createDirectory
(
$dir
,
0755
,
true
);
}
}
catch
(
FilesystemException
$ex
)
{
throw
new
Exception
(
pht
(
"Failed to create '%s'. You should manually create this directory."
,
$dir
));
}
return
$path
;
}
final
public
function
getPID
()
{
$pid
=
null
;
if
(
Filesystem
::
pathExists
(
$this
->
getPIDPath
()))
{
$pid
=
(
int
)
Filesystem
::
readFile
(
$this
->
getPIDPath
());
}
return
$pid
;
}
final
public
function
cleanup
(
$signo
=
'?'
)
{
global
$g_future
;
if
(
$g_future
)
{
$g_future
->
resolveKill
();
$g_future
=
null
;
}
Filesystem
::
remove
(
$this
->
getPIDPath
());
exit
(
1
);
}
protected
final
function
setDebug
(
$debug
)
{
$this
->
debug
=
$debug
;
}
public
static
function
requireExtensions
()
{
self
::
mustHaveExtension
(
'pcntl'
);
self
::
mustHaveExtension
(
'posix'
);
}
private
static
function
mustHaveExtension
(
$ext
)
{
if
(!
extension_loaded
(
$ext
))
{
echo
"ERROR: The PHP extension '{$ext}' is not installed. You must "
.
"install it to run aphlict on this machine.
\n
"
;
exit
(
1
);
}
$extension
=
new
ReflectionExtension
(
$ext
);
foreach
(
$extension
->
getFunctions
()
as
$function
)
{
$function
=
$function
->
name
;
if
(!
function_exists
(
$function
))
{
echo
"ERROR: The PHP function {$function}() is disabled. You must "
.
"enable it to run aphlict on this machine.
\n
"
;
exit
(
1
);
}
}
}
final
protected
function
willLaunch
()
{
$console
=
PhutilConsole
::
getConsole
();
$pid
=
$this
->
getPID
();
if
(
$pid
)
{
throw
new
PhutilArgumentUsageException
(
pht
(
'Unable to start notifications server because it is already '
.
'running. Use `aphlict restart` to restart it.'
));
}
if
(
posix_getuid
()
==
0
)
{
throw
new
PhutilArgumentUsageException
(
pht
(
// TODO: Update this message after a while.
'The notification server should not be run as root. It no '
.
'longer requires access to privileged ports.'
));
}
// Make sure we can write to the PID file.
if
(!
$this
->
debug
)
{
Filesystem
::
writeFile
(
$this
->
getPIDPath
(),
''
);
}
// First, start the server in configuration test mode with --test. This
// will let us error explicitly if there are missing modules, before we
// fork and lose access to the console.
$test_argv
=
$this
->
getServerArgv
();
$test_argv
[]
=
'--test=true'
;
execx
(
'%s %s %Ls'
,
$this
->
getNodeBinary
(),
$this
->
getAphlictScriptPath
(),
$test_argv
);
}
private
function
getServerArgv
()
{
$ssl_key
=
PhabricatorEnv
::
getEnvConfig
(
'notification.ssl-key'
);
$ssl_cert
=
PhabricatorEnv
::
getEnvConfig
(
'notification.ssl-cert'
);
$server_uri
=
PhabricatorEnv
::
getEnvConfig
(
'notification.server-uri'
);
$server_uri
=
new
PhutilURI
(
$server_uri
);
$client_uri
=
PhabricatorEnv
::
getEnvConfig
(
'notification.client-uri'
);
$client_uri
=
new
PhutilURI
(
$client_uri
);
$log
=
$this
->
getLogPath
();
$server_argv
=
array
();
$server_argv
[]
=
'--client-port='
.
coalesce
(
$this
->
clientPort
,
$client_uri
->
getPort
());
$server_argv
[]
=
'--admin-port='
.
$server_uri
->
getPort
();
$server_argv
[]
=
'--admin-host='
.
$server_uri
->
getDomain
();
if
(
$ssl_key
)
{
$server_argv
[]
=
'--ssl-key='
.
$ssl_key
;
}
if
(
$ssl_cert
)
{
$server_argv
[]
=
'--ssl-cert='
.
$ssl_cert
;
}
$server_argv
[]
=
'--log='
.
$log
;
if
(
$this
->
clientHost
)
{
$server_argv
[]
=
'--client-host='
.
$this
->
clientHost
;
}
return
$server_argv
;
}
private
function
getAphlictScriptPath
()
{
$root
=
dirname
(
phutil_get_library_root
(
'phabricator'
));
return
$root
.
'/support/aphlict/server/aphlict_server.js'
;
}
final
protected
function
launch
()
{
$console
=
PhutilConsole
::
getConsole
();
if
(
$this
->
debug
)
{
$console
->
writeOut
(
pht
(
"Starting Aphlict server in foreground...
\n
"
));
}
else
{
Filesystem
::
writeFile
(
$this
->
getPIDPath
(),
getmypid
());
}
$command
=
csprintf
(
'%s %s %Ls'
,
$this
->
getNodeBinary
(),
$this
->
getAphlictScriptPath
(),
$this
->
getServerArgv
());
if
(!
$this
->
debug
)
{
declare
(
ticks
=
1
);
pcntl_signal
(
SIGINT
,
array
(
$this
,
'cleanup'
));
pcntl_signal
(
SIGTERM
,
array
(
$this
,
'cleanup'
));
}
register_shutdown_function
(
array
(
$this
,
'cleanup'
));
if
(
$this
->
debug
)
{
$console
->
writeOut
(
"Launching server:
\n\n
$ "
.
$command
.
"
\n\n
"
);
$err
=
phutil_passthru
(
'%C'
,
$command
);
$console
->
writeOut
(
">>> Server exited!
\n
"
);
exit
(
$err
);
}
else
{
while
(
true
)
{
global
$g_future
;
$g_future
=
new
ExecFuture
(
'exec %C'
,
$command
);
$g_future
->
resolve
();
// If the server exited, wait a couple of seconds and restart it.
unset
(
$g_future
);
sleep
(
2
);
}
}
}
/* -( Commands )----------------------------------------------------------- */
final
protected
function
executeStartCommand
()
{
$console
=
PhutilConsole
::
getConsole
();
$this
->
willLaunch
();
$pid
=
pcntl_fork
();
if
(
$pid
<
0
)
{
throw
new
Exception
(
'Failed to fork()!'
);
}
else
if
(
$pid
)
{
$console
->
writeErr
(
pht
(
"Aphlict Server started.
\n
"
));
exit
(
0
);
}
// When we fork, the child process will inherit its parent's set of open
// file descriptors. If the parent process of bin/aphlict is waiting for
// bin/aphlict's file descriptors to close, it will be stuck waiting on
// the daemonized process. (This happens if e.g. bin/aphlict is started
// in another script using passthru().)
fclose
(
STDOUT
);
fclose
(
STDERR
);
$this
->
launch
();
return
0
;
}
final
protected
function
executeStopCommand
()
{
$console
=
PhutilConsole
::
getConsole
();
$pid
=
$this
->
getPID
();
if
(!
$pid
)
{
$console
->
writeErr
(
pht
(
"Aphlict is not running.
\n
"
));
return
0
;
}
$console
->
writeErr
(
pht
(
"Stopping Aphlict Server (%s)...
\n
"
,
$pid
));
posix_kill
(
$pid
,
SIGINT
);
$start
=
time
();
do
{
if
(!
PhabricatorDaemonReference
::
isProcessRunning
(
$pid
))
{
$console
->
writeOut
(
"%s
\n
"
,
pht
(
'Aphlict Server (%s) exited normally.'
,
$pid
));
$pid
=
null
;
break
;
}
usleep
(
100000
);
}
while
(
time
()
<
$start
+
5
);
if
(
$pid
)
{
$console
->
writeErr
(
pht
(
'Sending %s a SIGKILL.'
,
$pid
).
"
\n
"
);
posix_kill
(
$pid
,
SIGKILL
);
unset
(
$pid
);
}
Filesystem
::
remove
(
$this
->
getPIDPath
());
return
0
;
}
private
function
getNodeBinary
()
{
if
(
Filesystem
::
binaryExists
(
'nodejs'
))
{
return
'nodejs'
;
}
if
(
Filesystem
::
binaryExists
(
'node'
))
{
return
'node'
;
}
throw
new
PhutilArgumentUsageException
(
pht
(
'No `nodejs` or `node` binary was found in $PATH. You must install '
.
'Node.js to start the Aphlict server.'
));
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sun, Jun 29, 12:16 PM (2 d)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
259284
Default Alt Text
PhabricatorAphlictManagementWorkflow.php (7 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment