Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F949940
PhabricatorBot.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
PhabricatorBot.php
View Options
<?php
/**
* Simple IRC bot which runs as a Phabricator daemon. Although this bot is
* somewhat useful, it is also intended to serve as a demo of how to write
* "system agents" which communicate with Phabricator over Conduit, so you can
* script system interactions and integrate with other systems.
*
* NOTE: This is super janky and experimental right now.
*/
final
class
PhabricatorBot
extends
PhabricatorDaemon
{
private
$handlers
;
private
$conduit
;
private
$config
;
private
$pollFrequency
;
protected
function
run
()
{
$argv
=
$this
->
getArgv
();
if
(
count
(
$argv
)
!==
1
)
{
throw
new
Exception
(
pht
(
'Usage: %s %s'
,
__CLASS__
,
'<json_config_file>'
));
}
$json_raw
=
Filesystem
::
readFile
(
$argv
[
0
]);
try
{
$config
=
phutil_json_decode
(
$json_raw
);
}
catch
(
PhutilJSONParserException
$ex
)
{
throw
new
PhutilProxyException
(
pht
(
"File '%s' is not valid JSON!"
,
$argv
[
0
]),
$ex
);
}
$nick
=
idx
(
$config
,
'nick'
,
'phabot'
);
$handlers
=
idx
(
$config
,
'handlers'
,
array
());
$protocol_adapter_class
=
idx
(
$config
,
'protocol-adapter'
,
'PhabricatorIRCProtocolAdapter'
);
$this
->
pollFrequency
=
idx
(
$config
,
'poll-frequency'
,
1
);
$this
->
config
=
$config
;
foreach
(
$handlers
as
$handler
)
{
$obj
=
newv
(
$handler
,
array
(
$this
));
$this
->
handlers
[]
=
$obj
;
}
$ca_bundle
=
idx
(
$config
,
'https.cabundle'
);
if
(
$ca_bundle
)
{
HTTPSFuture
::
setGlobalCABundleFromPath
(
$ca_bundle
);
}
$conduit_uri
=
idx
(
$config
,
'conduit.uri'
);
if
(
$conduit_uri
)
{
$conduit_token
=
idx
(
$config
,
'conduit.token'
);
// Normalize the path component of the URI so users can enter the
// domain without the "/api/" part.
$conduit_uri
=
new
PhutilURI
(
$conduit_uri
);
$conduit_host
=
(
string
)
$conduit_uri
->
setPath
(
'/'
);
$conduit_uri
=
(
string
)
$conduit_uri
->
setPath
(
'/api/'
);
$conduit
=
new
ConduitClient
(
$conduit_uri
);
if
(
$conduit_token
)
{
$conduit
->
setConduitToken
(
$conduit_token
);
}
else
{
$conduit_user
=
idx
(
$config
,
'conduit.user'
);
$conduit_cert
=
idx
(
$config
,
'conduit.cert'
);
$response
=
$conduit
->
callMethodSynchronous
(
'conduit.connect'
,
array
(
'client'
=>
__CLASS__
,
'clientVersion'
=>
'1.0'
,
'clientDescription'
=>
php_uname
(
'n'
).
':'
.
$nick
,
'host'
=>
$conduit_host
,
'user'
=>
$conduit_user
,
'certificate'
=>
$conduit_cert
,
));
}
$this
->
conduit
=
$conduit
;
}
// Instantiate Protocol Adapter, for now follow same technique as
// handler instantiation
$this
->
protocolAdapter
=
newv
(
$protocol_adapter_class
,
array
());
$this
->
protocolAdapter
->
setConfig
(
$this
->
config
)
->
connect
();
$this
->
runLoop
();
$this
->
protocolAdapter
->
disconnect
();
}
public
function
getConfig
(
$key
,
$default
=
null
)
{
return
idx
(
$this
->
config
,
$key
,
$default
);
}
private
function
runLoop
()
{
do
{
$this
->
stillWorking
();
$messages
=
$this
->
protocolAdapter
->
getNextMessages
(
$this
->
pollFrequency
);
if
(
count
(
$messages
)
>
0
)
{
foreach
(
$messages
as
$message
)
{
$this
->
routeMessage
(
$message
);
}
}
foreach
(
$this
->
handlers
as
$handler
)
{
$handler
->
runBackgroundTasks
();
}
}
while
(!
$this
->
shouldExit
());
}
public
function
writeMessage
(
PhabricatorBotMessage
$message
)
{
return
$this
->
protocolAdapter
->
writeMessage
(
$message
);
}
private
function
routeMessage
(
PhabricatorBotMessage
$message
)
{
$ignore
=
$this
->
getConfig
(
'ignore'
);
if
(
$ignore
)
{
$sender
=
$message
->
getSender
();
if
(
$sender
&&
in_array
(
$sender
->
getName
(),
$ignore
))
{
return
;
}
}
if
(
$message
->
getCommand
()
==
'LOG'
)
{
$this
->
log
(
'[LOG] '
.
$message
->
getBody
());
}
foreach
(
$this
->
handlers
as
$handler
)
{
try
{
$handler
->
receiveMessage
(
$message
);
}
catch
(
Exception
$ex
)
{
phlog
(
$ex
);
}
}
}
public
function
getAdapter
()
{
return
$this
->
protocolAdapter
;
}
public
function
getConduit
()
{
if
(
empty
(
$this
->
conduit
))
{
throw
new
Exception
(
pht
(
"This bot is not configured with a Conduit uplink. Set '%s', "
.
"'%s' and '%s' in the configuration to connect."
,
'conduit.uri'
,
'conduit.user'
,
'conduit.cert'
));
}
return
$this
->
conduit
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Tue, Jun 17, 1:51 PM (2 d)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
223977
Default Alt Text
PhabricatorBot.php (4 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment