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

  1. Regular Web/APP back-end servers
  2. Im instant messaging server
  3. TCP/UDP iot server
  4. 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

  • infpmThe following database connection is a single column,
  • inswooleAll 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