mirror of
https://github.com/fusionpbx/fusionpbx.git
synced 2026-01-06 11:43:50 +00:00
Websockets (#7393)
* Initial commit of websockets * Move app_menu to the active_calls websockets * Fix hangup function * Remove connection wait-state on web socket server so events can process * Add timestamp and debug level to console for service debug output * Remove debug exit * Fix typo for ws_client instead of ws_server * Update app_config.php * Fix typo and remove empty function * Remove call to empty function * Fix the menu to point to the correct location * Remove Logging Class * Rename service file * Rename service file * Fix the in progress browser request * Fix browser reload and implement 'active_calls' default values * Add apply_filter function * Create new permission_filter object * In progress active calls now use filter * Add invalid_uuid_exception class * add event_key_filter to honor user permissions * add and_link and or_link for filters * Fix disconnected subscriber and add filters to honor permissions * Add $key and $value for filter * define a service name * catch throwable instead of exception * Add $key and $value for filter and allow returning null * Update permission checks when loading page * Add apply_filter function to honor subscriber permissions * Add create_filter_chain_for function to honor subscriber permissions * Add apply_filter function to honor subscriber permissions * Add apply_filter function to honor subscriber permissions * create interface to allow filterable payload * create interface to define functions required for websocket services * Pass in service class when creating a service token * Allow key/name and return null for filter * Adjust subscriber exceptions to return the ID of the subscriber * Add event filter to filter chain * Add command line options for ip and port for websockets and switch * update service to use is_a syntax * initial commit of base class for websockets system services * initial commit of the system cpu status service * remove extra line feed * fix path on active_calls * initial proof of concept for cpu status updated by websockets * Allow returning null * Use default settings to set the interval for cpu status broadcast * Improve the CPU percent function for Linux systems * Show more debug information * Allow child processes to re-connect to the web socket service * Fix websockets as plural instead of singular * Add class name list-row * Update active_calls.php * Update active_calls.php * Update websocket_client.js * Update app_config.php * Update app_menu.php * Update debian-websockets.service * Update debian-active_calls.service --------- Co-authored-by: FusionPBX <markjcrane@gmail.com>
This commit is contained in:
429
core/websockets/resources/classes/websocket_message.php
Normal file
429
core/websockets/resources/classes/websocket_message.php
Normal file
@@ -0,0 +1,429 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* FusionPBX
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FusionPBX
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mark J Crane <markjcrane@fusionpbx.com>
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008-2025
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Mark J Crane <markjcrane@fusionpbx.com>
|
||||
* Tim Fry <tim@fusionpbx.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* A structured web socket message easily converted to and from a json string
|
||||
*
|
||||
* @author Tim Fry <tim@fusionpbx.com>
|
||||
* @param string $service_name;
|
||||
* @param string $token_name;
|
||||
* @param string $token_hash;
|
||||
* @param string $status_string;
|
||||
* @param string $status_code;
|
||||
* @param string $request_id;
|
||||
* @param string $resource_id;
|
||||
* @param string $domain_uuid;
|
||||
* @param string $permissions;
|
||||
* @param string $topic;
|
||||
*/
|
||||
class websocket_message extends base_message {
|
||||
|
||||
// By setting these to protected we ensure the __set and __get methods are used in the parent class
|
||||
protected $service_name;
|
||||
protected $token_name;
|
||||
protected $token_hash;
|
||||
protected $status_string;
|
||||
protected $status_code;
|
||||
protected $request_id;
|
||||
protected $resource_id;
|
||||
protected $domain_uuid;
|
||||
protected $domain_name;
|
||||
protected $permissions;
|
||||
protected $topic;
|
||||
|
||||
public function __construct($associative_properties_array = []) {
|
||||
// Initialize empty default values
|
||||
$this->service_name = '';
|
||||
$this->token_name = '';
|
||||
$this->token_hash = '';
|
||||
$this->status_string = '';
|
||||
$this->status_code = '';
|
||||
$this->request_id = '';
|
||||
$this->resource_id = '';
|
||||
$this->domain_uuid = '';
|
||||
$this->domain_name = '';
|
||||
$this->permissions = [];
|
||||
$this->topic = '';
|
||||
//
|
||||
// Send to parent (base_message) constructor
|
||||
//
|
||||
parent::__construct($associative_properties_array);
|
||||
}
|
||||
|
||||
public function has_permission($permission_name) {
|
||||
return isset($this->permissions[$permission_name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of service_name.
|
||||
* @param string $service_name
|
||||
* @return $this
|
||||
* @see service_name
|
||||
*/
|
||||
public function service($service_name = null) {
|
||||
if (func_num_args() > 0) {
|
||||
$this->service_name = $service_name;
|
||||
return $this;
|
||||
}
|
||||
return $this->service_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or Sets the service name
|
||||
* If no parameters are provided then the service_name is returned. If the service name is provided, then the
|
||||
* service_name is set to the value provided.
|
||||
* @param string $service_name
|
||||
* @return $this
|
||||
*/
|
||||
public function service_name($service_name = null) {
|
||||
if (func_num_args() > 0) {
|
||||
$this->service_name = $service_name;
|
||||
return $this;
|
||||
}
|
||||
return $this->service_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or sets the permissions array
|
||||
* @param array $permissions
|
||||
* @return $this
|
||||
*/
|
||||
public function permissions($permissions = []) {
|
||||
if (func_num_args() > 0) {
|
||||
$this->permissions = $permissions;
|
||||
return $this;
|
||||
}
|
||||
return $this->permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a filter to the payload of this message.
|
||||
* When a filter returns null then the payload is set to null
|
||||
* @param filter $filter
|
||||
*/
|
||||
public function apply_filter(?filter $filter) {
|
||||
if ($filter !== null && is_array($this->payload)) {
|
||||
foreach ($this->payload as $key => $value) {
|
||||
$result = ($filter)($key, $value);
|
||||
// Check if a filter requires dropping the payload
|
||||
if ($result === null) {
|
||||
$this->payload = null;
|
||||
return;
|
||||
}
|
||||
// Remove a key if filter does not pass
|
||||
elseif(!$result) {
|
||||
unset($this->payload[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or sets the domain UUID
|
||||
* @param string $domain_uuid
|
||||
* @return $this or $domain_uuid
|
||||
*/
|
||||
public function domain_uuid($domain_uuid = '') {
|
||||
if (func_num_args() > 0) {
|
||||
$this->domain_uuid = $domain_uuid;
|
||||
return $this;
|
||||
}
|
||||
return $this->domain_uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or sets the domain name
|
||||
* @param string $domain_name
|
||||
* @return $this or $domain_name
|
||||
*/
|
||||
public function domain_name($domain_name = '') {
|
||||
if (func_num_args() > 0) {
|
||||
$this->domain_name = $domain_name;
|
||||
return $this;
|
||||
}
|
||||
return $this->domain_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or Sets the service name
|
||||
* If no parameters are provided then the service_name is returned. If the service name is provided, then the
|
||||
* topic is set to the value provided.
|
||||
* @param string $topic
|
||||
* @return $this
|
||||
*/
|
||||
public function topic($topic = null) {
|
||||
if (func_num_args() > 0) {
|
||||
$this->topic = $topic;
|
||||
return $this;
|
||||
}
|
||||
return $this->topic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or sets the token array using the key values of 'name' and 'hash'
|
||||
* @param array $token_array
|
||||
* @return array|$this
|
||||
* @see token_name
|
||||
* @see token_hash
|
||||
*/
|
||||
public function token($token_array = []) {
|
||||
if (func_num_args() > 0) {
|
||||
$this->token_name($token_array['name'] ?? '')->token_hash($token_array['hash'] ?? '');
|
||||
return $this;
|
||||
}
|
||||
return ['name' => $this->token_name, 'hash' => $this->token_hash];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the token name
|
||||
* @param string $token_name
|
||||
* @return $this
|
||||
* @see token_hash
|
||||
*/
|
||||
public function token_name($token_name = '') {
|
||||
if (func_num_args() > 0) {
|
||||
$this->token_name = $token_name;
|
||||
return $this;
|
||||
}
|
||||
return $this->token_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or sets the status code of this message
|
||||
* @param int $status_code
|
||||
* @return $this
|
||||
*/
|
||||
public function status_code($status_code = '') {
|
||||
if (func_num_args() > 0) {
|
||||
$this->status_code = $status_code;
|
||||
return $this;
|
||||
}
|
||||
return $this->status_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or sets the resource id
|
||||
* @param type $resource_id
|
||||
* @return $this
|
||||
*/
|
||||
public function resource_id($resource_id = null) {
|
||||
if (func_num_args() > 0) {
|
||||
$this->resource_id = $resource_id;
|
||||
return $this;
|
||||
}
|
||||
return $this->resource_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or sets the request ID
|
||||
* @param type $request_id
|
||||
* @return $this
|
||||
*/
|
||||
public function request_id($request_id = null) {
|
||||
if (func_num_args() > 0) {
|
||||
$this->request_id = $request_id;
|
||||
return $this;
|
||||
}
|
||||
return $this->request_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or sets the status string
|
||||
* @param type $status_string
|
||||
* @return $this
|
||||
*/
|
||||
public function status_string( $status_string = null) {
|
||||
if (func_num_args() > 0) {
|
||||
$this->status_string = $status_string;
|
||||
return $this;
|
||||
}
|
||||
return $this->status_string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or sets the token hash
|
||||
* @param type $token_hash
|
||||
* @return $this
|
||||
* @see token_name
|
||||
*/
|
||||
public function token_hash($token_hash = null) {
|
||||
if (func_num_args() > 0) {
|
||||
$this->token_hash = $token_hash;
|
||||
return $this;
|
||||
}
|
||||
return $this->token_hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the 'statusString' key that comes from javascript
|
||||
* @param type $status_string
|
||||
* @return type
|
||||
*/
|
||||
public function statusString($status_string = '') {
|
||||
return $this->status_string($status_string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the 'statusCode' key that comes from javascript
|
||||
* @param type $status_code
|
||||
* @return $this
|
||||
*/
|
||||
public function statusCode($status_code = 200) {
|
||||
return $this->status_code($status_code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwrap a JSON message to an associative array
|
||||
* @param string $json_string
|
||||
* @return array
|
||||
*/
|
||||
public static function unwrap($json_string = '') {
|
||||
return json_decode($json_string, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to respond with a connected message
|
||||
* @param type $request_id
|
||||
* @return type
|
||||
*/
|
||||
public static function connected($request_id = '') {
|
||||
return static::request_authentication($request_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to respond with a authentication message
|
||||
* @param type $request_id
|
||||
* @return type
|
||||
*/
|
||||
public static function request_authentication($request_id = '') {
|
||||
$class = static::class;
|
||||
return (new $class())
|
||||
->request_id($request_id)
|
||||
->service_name('authentication')
|
||||
->status_code(407)
|
||||
->status_string('Authentication Required')
|
||||
->topic('authenticate')
|
||||
->__toString()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to respond with a bad request message
|
||||
* @param type $request_id
|
||||
* @param type $service
|
||||
* @param type $topic
|
||||
* @return type
|
||||
*/
|
||||
public static function request_is_bad($request_id = '', $service = '', $topic = '') {
|
||||
$class = static::class;
|
||||
return (new $class())
|
||||
->request_id($request_id)
|
||||
->service_name($service)
|
||||
->topic($topic)
|
||||
->status_code(400)
|
||||
->__toString()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to respond with an authenticated message
|
||||
* @param type $request_id
|
||||
* @param type $service
|
||||
* @param type $topic
|
||||
* @return type
|
||||
*/
|
||||
public static function request_authenticated($request_id = '', $service = '', $topic = 'authenticated') {
|
||||
$class = static::class;
|
||||
return (new $class())
|
||||
->request_id($request_id)
|
||||
->service_name($service)
|
||||
->topic($topic)
|
||||
->status_code(200)
|
||||
->status_string('OK')
|
||||
->__toString()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to respond with an unauthorized request message
|
||||
* @param type $request_id
|
||||
* @param type $service
|
||||
* @param type $topic
|
||||
* @return type
|
||||
*/
|
||||
public static function request_unauthorized($request_id = '', $service = '', $topic = 'unauthorized') {
|
||||
$class = static::class;
|
||||
return (new $class())
|
||||
->request_id($request_id)
|
||||
->service_name($service)
|
||||
->topic($topic)
|
||||
->status_code(401)
|
||||
->__toString()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to respond with a forbidden message
|
||||
* @param type $request_id
|
||||
* @param type $service
|
||||
* @param type $topic
|
||||
* @return type
|
||||
*/
|
||||
public static function request_forbidden($request_id = '', $service = '', $topic = 'forbidden') {
|
||||
$class = static::class;
|
||||
return (new $class())
|
||||
->request_id($request_id)
|
||||
->service_name($service)
|
||||
->topic($topic)
|
||||
->status_code(403)
|
||||
->__toString()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a websocket_message object (or child object) using the provided JSON string or JSON array
|
||||
* @param string|array $websocket_message_json JSON array or JSON string
|
||||
* @return static|null Returns a new websocket_message object (or child object)
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function create_from_json_message($websocket_message_json) {
|
||||
if (empty($websocket_message_json)) {
|
||||
// Nothing to do
|
||||
return null;
|
||||
} elseif (is_string($websocket_message_json)) {
|
||||
$json_array = json_decode($websocket_message_json, true);
|
||||
} elseif (is_array($websocket_message_json)) {
|
||||
$json_array = $websocket_message_json;
|
||||
} else {
|
||||
throw new \InvalidArgumentException("create_from_websocket_message_json expected string or array but got " . gettype($websocket_message_json));
|
||||
}
|
||||
|
||||
return new static($json_array);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user