Distributed. Can run in a variety of environments (CLI, Apache/PHP-FPM, Swoole)
Github:github.com/lizhichao/o… Yards cloud: gitee.com/vicself/one
Applicable scenario
- Regular Web/APP back-end servers
- Im instant messaging server
- TCP/UDP iot server
- Comprehensive project, various hybrid protocol communication
background
After using laravel framework, I found that its routing and database ORM is really good, but the overall is really a bit slow, execution to the controller takes about 30ms. I decided to make a very simple framework with very good routing and ORM. So you’ll notice that the route and ORM of the One box have the shadow of Laravel. However, it also has some features of its own, for example, ORM supports automatic cache (automatic read, write, refresh) to keep in sync with the database, no awareness of external use. The ONE framework also supports running under FPM, under which the overall time of the framework itself is about 1ms.
hello world
The installation
composer create-project lizhichao/one-app app
cd app
php App/swoole.php
Copy the code
test
The curl http://127.0.0.1:8081/Copy the code
The main function
- RESTful routing
- The middleware
- Websocket/TCP/HTTP… Arbitrary protocol routing
- The ORM model
- Unified session processing
- Mysql connection pool
- Redis connection pool
- Coroutine TCP-client connection pool
- HTTP/TCP/WEBOSCKET/UDP server
- The cache
- Interprocess memory sharing
- RPC(http,tcp,udp)
- The log
- RequestId tracking
- Distributed (long connections, transactions…)
routing
Router::get('/', \App\Controllers\IndexController::class . '@index');
// Routing with parameters
Router::get('/user/{id}', \App\Controllers\IndexController::class . '@user');
// Route grouping
Router::group(['namespace'= >'App\\Test\\WebSocket'].function (a){
/ / the websocket routing
Router::set('ws'.'/a'.'TestController@abc');
Router::set('ws'.'/b'.'TestController@bbb');
});
/ / middleware
Router::group([
'middle' => [
\App\Test\MixPro\TestMiddle::class . '@checkSession']],function (a) {
Router::get('/mix/ws', HttpController::class . '@ws');
Router::get('/mix/http', HttpController::class . '@http');
Router::post('/mix/http/loop', HttpController::class . '@httpLoop');
Router::post('/mix/http/send', HttpController::class . '@httpSend');
});
Copy the code
The orm model
Define the model
namespace App\Model;
use One\Database\Mysql\Model;
// There is no need to specify a primary key in the model, the framework caches the database structure
// Automatically match primary key, automatically filter non-table structure fields
class User extends Model
{
// Define the table name corresponding to the model
CONST TABLE = 'users';
// Define the relationship
public function articles(a)
{
return $this->hasMany('id',Article::class,'user_id');
}
// Define events
// Whether to enable automatic caching
/ /...
}
Copy the code
Using the model
- in
fpm
The following database connection is a single column, - in
swoole
All database operations in this mode are automatically switched to connection pools
// Query a record
$user = User::find(1);
// Associated query
$user_list = User::whereIn('id'[1.2.3])->with('articles')->findAll()->toArray();
/ / update
$r = $user->update(['name'= >'aaa']);
/ / or
$r = user::where('id'.1)->update(['name'= >'aaa']);
// $r indicates the number of affected records
Copy the code
The cache
// Set no expiration time for cache
Cache::set('ccc'.1);
// Set the cache to expire in 1 minute
Cache::set('ccc'.1.60);
/ / to get
Cache::get('ccc');
// The cache CCC expires 10 seconds below TAG1
Cache::get('ccc'.function (a){
return 'Cached information';
},10['tag1']);
// Flush all caches under tag1
Cache::flush('tag1');
Copy the code
HTTP/TCP/WEBSOCKET/UDP server
Start a WebSocket server, add HTTP service listener, add TCP service listener
[
// Master server
'server'= > ['server_type' => \One\Swoole\OneServer::SWOOLE_WEBSOCKET_SERVER,
'port'= >8082.// Event callback
'action' => \One\Swoole\Server\WsServer::class,
'mode' => SWOOLE_PROCESS,
'sock_type' => SWOOLE_SOCK_TCP,
'ip'= >'0.0.0.0'.// The swoole server sets the parameters
'set'= > ['worker_num'= >5]],// Add a listener
'add_listener' => [
[
'port'= >8081.// Event callback
'action' => \App\Server\AppHttpPort::class,
'type' => SWOOLE_SOCK_TCP,
'ip'= >'0.0.0.0'.// Set the listener parameters
'set'= > ['open_http_protocol'= >true.'open_websocket_protocol'= >false]], ['port'= >8083.// Unpack protocol
'pack_protocol' => \One\Protocol\Text::class,
// Event callback
'action' => \App\Test\MixPro\TcpPort::class,
'type' => SWOOLE_SOCK_TCP,
'ip'= >'0.0.0.0'.// Set the listener parameters
'set'= > ['open_http_protocol'= >false.'open_websocket_protocol'= >false]]]];Copy the code
RPC
Call the methods of the remote server as you would call the methods of this project. Across languages, across machines.
The service side
Start the RPC service. The framework already has the RPC service for each protocol. Add it to the action in the configuration file above. For example, HTTP calls and TCP calls are supported.
// HTTP RPC service
[
'port'= >8082.'action' => \App\Server\RpcHttpPort::class,
'type' => SWOOLE_SOCK_TCP,
'ip'= >'0.0.0.0'.'set'= > ['open_http_protocol'= >true.'open_websocket_protocol'= >false]],// TCP RPC service
[
'port'= >8083.'action' => \App\Server\RpcTcpPort::class,
'type' => SWOOLE_SOCK_TCP,
'pack_protocol' => \One\Protocol\Frame::class, // TCP packaging and unpacking protocol
'ip'= >'0.0.0.0'.'set'= > ['open_http_protocol'= >false.'open_websocket_protocol'= >false.'open_length_check'= >1.'package_length_func'= >'\One\Protocol\Frame::length'.'package_body_offset' => \One\Protocol\Frame::HEAD_LEN,
]
]
Copy the code
Add concrete services to RPC, such as a class Abc
class Abc
{
private $a;
/ / initial value
public function __construct($a = 0)
{
$this->a = $a;
}
/ / add
public function add($a, $b)
{
return $this->a + $a + $b;
}
public function time(a)
{
return date('Y-m-d H:i:s');
}
// Reset the initial value
public function setA($a)
{
$this->a = $a;
return $this; }}Copy the code
Add Abc to the RPC service
// Add Abc to RPC service
RpcServer::add(Abc::class);
// If you do not want to add all methods under Abc to the RPC service, you can also specify to add.
// An unspecified method client cannot be called.
//RpcServer::add(Abc::class,'add');
// Add a group
//RpcServer::group([
// // middleware here can do permission verification data encryption and decryption and so on
// 'middle' => [
// TestMiddle::class . '@aa'
/ /,
// // cache if set will return cache information when called with the same argument without actually calling in: second
// 'cache' => 10
//], function () {
// RpcServer::add(Abc::class);
// RpcServer::add(User::class);
/ /});
Copy the code
Client call
To facilitate the call we create a mapping class (automatically generated by the ONE framework)
class ClientAbc extends RpcClientHttp {
// RPC server address
protected $_rpc_server = 'http://127.0.0.1:8082/';
// Remote classes do not default to the current class name
protected $_remote_class_name = 'Abc';
}
Copy the code
The remote method of the RPC service is called, as is the method of this project. You can imagine this method in your project.
$abc = new ClientAbc(5);
// $res === 10
$res = $abc->add(2.3);
$res === 105
$res = $abc->setA(100)->add(2.3);
// Add the User of the above model to RPC
// RpcServer::add(User::class);
// The result is the same as above
/ / $user_list = User: : whereIn (" id ", [1, 2, 3]) - > with (' articles') - > the.findall () - > toArray ();
Copy the code
The above is called over the HTTP protocol. You can also call it through other protocols. For example, Tcp
class ClientAbc extends RpcClientTcp {
// RPC server address
protected $_rpc_server = 'TCP: / / 127.0.0.1:8083 /';
// Remote classes do not default to the current class name
protected $_remote_class_name = 'Abc';
}
Copy the code
One kind of RpcClientHttp, RpcClientTcp in framework. You can also copy and use it anywhere else.
See documentation for more
Detailed document address
Use the columns-demo
QQ communication group: 731475644