Skip to content

Commit 39eda6a

Browse files
author
Ace Nassri
authored
Merge pull request GoogleCloudPlatform#882 from GoogleCloudPlatform/flex-ws
Add GAE Flex websockets sample
2 parents ef69722 + f18498b commit 39eda6a

File tree

13 files changed

+456
-0
lines changed

13 files changed

+456
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
vendor/
2+
.gitignore
3+
.git/
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# PHP websockets sample for Google App Engine Flexible Environment
2+
3+
This sample demonstrates how to use websockets on [Google App Engine Flexible Environment](https://cloud.google.com/appengine).
4+
5+
## Running locally
6+
7+
Use the following commands to run locally:
8+
9+
```sh
10+
cd php-docs-samples/appengine/flexible/cloudsql
11+
php -S localhost:8080
12+
```
13+
14+
## Deploying
15+
Refer to the [top-level README](../README.md) for instructions on running and deploying.
16+
17+
Note that you will have to [create a firewall rule](https://cloud.google.com/sdk/gcloud/reference/compute/firewall-rules/create) that accepts traffic on port `8000`:
18+
19+
```sh
20+
gcloud compute firewall-rules create allow-8000 --allow=tcp:8000 --target-tags=websockets-allow-8000
21+
```
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[program:socket-server]
2+
command = php %(ENV_APP_DIR)s/socket-server.php
3+
enviroment = PORT="8000"
4+
stdout_logfile = /dev/stdout
5+
stdout_logfile_maxbytes=0
6+
stderr_logfile = /dev/stderr
7+
stderr_logfile_maxbytes=0
8+
user = root
9+
autostart = true
10+
autorestart = true
11+
priority = 10
12+
stopwaitsecs = 20
13+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
runtime: php
2+
env: flex
3+
4+
# Use only a single instance, so that this local-memory-only chat app will work
5+
# consistently with multiple users. To work across multiple instances, an
6+
# extra-instance messaging system or data store would be needed.
7+
manual_scaling:
8+
instances: 1
9+
10+
11+
# For applications which can take advantage of session affinity
12+
# (where the load balancer will attempt to route multiple connections from
13+
# the same user to the same App Engine instance), uncomment the folowing:
14+
15+
# network:
16+
# session_affinity: true
17+
18+
runtime_config:
19+
document_root: .
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"require": {
3+
"cboden/ratchet": "^0.4.1",
4+
"guzzlehttp/psr7": "^1.5",
5+
"silex/silex": "^1.3"
6+
},
7+
"require-dev": {
8+
"phpunit/phpunit": "^5",
9+
"ratchet/pawl": "^0.3.4",
10+
"react/promise": "^2.7",
11+
"clue/block-react": "^1.3",
12+
"google/cloud-tools": "^0.9.1"
13+
}
14+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
14+
>
15+
<html>
16+
<head>
17+
<title>Google App Engine Flexible Environment - PHP Websockets Chattitle>
18+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
19+
<meta charset="utf-8">
20+
<style>
21+
* { margin: 0; padding: 0; box-sizing: border-box; }
22+
body { font: 13px Helvetica, Arial; }
23+
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
24+
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
25+
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
26+
#messages { list-style-type: none; margin: 0; padding: 0; }
27+
#messages li { padding: 5px 10px; }
28+
#messages li:nth-child(odd) { background: #dedede; }
29+
#messages li:last-child { background: #aea; }
30+
section {
31+
background-color: #eee;
32+
border: 3px dashed #888; border-radius: 10px;
33+
margin: 30px; margin-bottom: 80px;
34+
padding: 5px;
35+
}
36+
style>
37+
head>
38+
<body>
39+
40+
41+
<h1>Websockets Chat Demoh1>
42+
43+
<form id="chat-form">
44+
<input type="text" id="chat-text" autocomplete="off" placeholder="Enter some text...">
45+
<button type="submit">Sendbutton>
46+
form>
47+
48+
<section>
49+
50+
<ul id="messages">ul>
51+
section>
52+
53+
54+
55+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js">script>
56+
<script>
57+
// [START gae_flex_websockets_js]
58+
$(function() {
59+
/* If the main page is served via https, the WebSocket must be served via
60+
"wss" (WebSocket Secure) */
61+
var scheme = window.location.protocol == "https:" ? 'wss://' : 'ws://';
62+
var webSocketUri = scheme
63+
+ window.location.hostname
64+
+ (location.port ? ':'+location.port: '')
65+
+ '/ws';
66+
/* Helper to keep an activity log on the page. */
67+
function log(text, label) {
68+
label = label || 'Status';
69+
$('#messages').append(`
  • ${label}: ${text}`);
  • 70+
    }
    71+
    /* Establish the WebSocket connection and register event handlers. */
    72+
    var websocket = new WebSocket(webSocketUri);
    73+
    websocket.onopen = function() {
    74+
    log('Connected');
    75+
    };
    76+
    websocket.onclose = function() {
    77+
    log('Closed');
    78+
    };
    79+
    websocket.onmessage = function(e) {
    80+
    log(e.data, 'Message received')
    81+
    };
    82+
    websocket.onerror = function(e) {
    83+
    log('Error (see console)');
    84+
    console.log(e);
    85+
    };
    86+
    /* Handle form submission and send a message to the websocket. */
    87+
    $('#chat-form').submit(function(e) {
    88+
    e.preventDefault();
    89+
    var data = $('#chat-text').val();
    90+
    if (data) {
    91+
    websocket.send(data);
    92+
    window.scrollTo(0, document.body.scrollHeight)
    93+
    $('#chat-text').val('');
    94+
    }
    95+
    });
    96+
    });
    97+
    // [END gae_flex_websockets_js]
    98+
    script>
    99+
    body>
    100+
    html>
    Lines changed: 44 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,44 @@
    1+
    2+
    /*
    3+
    * Copyright 2019 Google LLC.
    4+
    *
    5+
    * Licensed under the Apache License, Version 2.0 (the "License");
    6+
    * you may not use this file except in compliance with the License.
    7+
    * You may obtain a copy of the License at
    8+
    *
    9+
    * http://www.apache.org/licenses/LICENSE-2.0
    10+
    *
    11+
    * Unless required by applicable law or agreed to in writing, software
    12+
    * distributed under the License is distributed on an "AS IS" BASIS,
    13+
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14+
    * See the License for the specific language governing permissions and
    15+
    * limitations under the License.
    16+
    */
    17+
    18+
    require_once __DIR__ . '/vendor/autoload.php';
    19+
    20+
    use Silex\Application;
    21+
    use Silex\Provider\TwigServiceProvider;
    22+
    23+
    // create the Silex application
    24+
    $app = new Application();
    25+
    $app['debug'] = true;
    26+
    27+
    // register twig
    28+
    $app->register(new TwigServiceProvider(), [
    29+
    'twig.path' => __DIR__
    30+
    ]);
    31+
    32+
    $app->register(new Silex\Provider\RoutingServiceProvider());
    33+
    34+
    $app->get('/', function () use ($app) {
    35+
    return file_get_contents('index.html');
    36+
    });
    37+
    38+
    // @codeCoverageIgnoreStart
    39+
    if (PHP_SAPI != 'cli') {
    40+
    $app->run();
    41+
    }
    42+
    // @codeCoverageIgnoreEnd
    43+
    44+
    return $app;
    Lines changed: 13 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,13 @@
    1+
    location /ws {
    2+
    proxy_pass "http://localhost:8000";
    3+
    proxy_http_version 1.1;
    4+
    proxy_set_header Upgrade $http_upgrade;
    5+
    proxy_set_header Connection "upgrade";
    6+
    proxy_set_header Host $http_host;
    7+
    proxy_set_header X-Real-IP $remote_addr;
    8+
    }
    9+
    10+
    location / {
    11+
    # try to serve files directly, fallback to the front controller
    12+
    try_files $uri /$front_controller_file$is_args$args;
    13+
    }
    Lines changed: 31 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,31 @@
    1+
    xml version="1.0" encoding="UTF-8"?>
    2+
    17+
    <phpunit bootstrap="test/bootstrap.php" colors="true">
    18+
    <testsuites>
    19+
    <testsuite name="default">
    20+
    <directory>testdirectory>
    21+
    testsuite>
    22+
    testsuites>
    23+
    <logging>
    24+
    <log type="coverage-clover" target="build/logs/clover.xml"/>
    25+
    logging>
    26+
    <filter>
    27+
    <whitelist>
    28+
    <file>socket_demo.phpfile>
    29+
    whitelist>
    30+
    filter>
    31+
    phpunit>
    Lines changed: 68 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,68 @@
    1+
    2+
    /**
    3+
    * Copyright 2019 Google LLC.
    4+
    *
    5+
    * Licensed under the Apache License, Version 2.0 (the "License");
    6+
    * you may not use this file except in compliance with the License.
    7+
    * You may obtain a copy of the License at
    8+
    *
    9+
    * http://www.apache.org/licenses/LICENSE-2.0
    10+
    *
    11+
    * Unless required by applicable law or agreed to in writing, software
    12+
    * distributed under the License is distributed on an "AS IS" BASIS,
    13+
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14+
    * See the License for the specific language governing permissions and
    15+
    * limitations under the License.
    16+
    */
    17+
    18+
    # [START gae_flex_websockets_app]
    19+
    use Ratchet\MessageComponentInterface;
    20+
    use Ratchet\ConnectionInterface;
    21+
    22+
    // Install composer dependencies with "composer install"
    23+
    // @see http://getcomposer.org for more information.
    24+
    require __DIR__ . '/vendor/autoload.php';
    25+
    26+
    // Forwards any incoming messages to all connected clients
    27+
    class SocketDemo implements MessageComponentInterface
    28+
    {
    29+
    protected $clients;
    30+
    31+
    public function __construct()
    32+
    {
    33+
    $this->clients = new \SplObjectStorage;
    34+
    }
    35+
    36+
    public function onOpen(ConnectionInterface $conn)
    37+
    {
    38+
    $this->clients->attach($conn);
    39+
    echo "Connection opened!\n";
    40+
    echo "\t" . $this->clients->count() . " connection(s) active.\n";
    41+
    }
    42+
    43+
    public function onMessage(ConnectionInterface $from, $msg)
    44+
    {
    45+
    $output = "Message received: " . $msg . "\n";
    46+
    echo $output;
    47+
    foreach ($this->clients as $client) {
    48+
    $client->send($output);
    49+
    }
    50+
    }
    51+
    52+
    public function onClose(ConnectionInterface $conn)
    53+
    {
    54+
    $this->clients->detach($conn);
    55+
    echo "Connection closed gracefully!\n";
    56+
    echo "\t" . $this->clients->count() . " connection(s) active.\n";
    57+
    }
    58+
    59+
    public function onError(ConnectionInterface $conn, \Exception $e)
    60+
    {
    61+
    $conn->close();
    62+
    echo "Connection closed due to error: " . $e->getMessage() . "\n";
    63+
    echo "\t" . $this->clients->count() . " connection(s) active.\n";
    64+
    }
    65+
    }
    66+
    # [END gae_flex_websockets_app]
    67+
    68+
    return new SocketDemo;
    Lines changed: 44 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,44 @@
    1+
    2+
    /**
    3+
    * Copyright 2019 Google LLC.
    4+
    *
    5+
    * Licensed under the Apache License, Version 2.0 (the "License");
    6+
    * you may not use this file except in compliance with the License.
    7+
    * You may obtain a copy of the License at
    8+
    *
    9+
    * http://www.apache.org/licenses/LICENSE-2.0
    10+
    *
    11+
    * Unless required by applicable law or agreed to in writing, software
    12+
    * distributed under the License is distributed on an "AS IS" BASIS,
    13+
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14+
    * See the License for the specific language governing permissions and
    15+
    * limitations under the License.
    16+
    */
    17+
    18+
    // [START gae_flex_websockets_server]
    19+
    // Install composer dependencies with "composer install"
    20+
    // @see http://getcomposer.org for more information.
    21+
    require __DIR__ . '/vendor/autoload.php';
    22+
    require_once __DIR__ . '/socket-demo.php';
    23+
    24+
    use Ratchet\Server\IoServer;
    25+
    use Ratchet\Http\HttpServer;
    26+
    use Ratchet\WebSocket\WsServer;
    27+
    28+
    $socketDemo = new SocketDemo;
    29+
    30+
    $port = 8000;
    31+
    32+
    $server = IoServer::factory(
    33+
    new HttpServer(
    34+
    new WsServer($socketDemo)
    35+
    ),
    36+
    $port
    37+
    );
    38+
    // [END gae_flex_websockets_server]
    39+
    40+
    if (PHP_SAPI == 'cli') {
    41+
    $server->run();
    42+
    }
    43+
    44+
    return $server;

    0 commit comments

    Comments
     (0)