Skip to content

Commit c16706a

Browse files
author
ace-n
committed
Initial commit of Flex websockets sample
1 parent fa90d48 commit c16706a

File tree

13 files changed

+447
-0
lines changed

13 files changed

+447
-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: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"require": {
3+
"cboden/ratchet": "^0.4.1",
4+
"guzzlehttp/psr7": "^1.5",
5+
"silex/silex": "^2.3",
6+
"symfony/twig-bridge": "^4.2",
7+
"twig/twig": "^1.29"
8+
},
9+
"require-dev": {
10+
"phpunit/phpunit": "^7.5",
11+
"ratchet/pawl": "^0.3.4",
12+
"react/promise": "^2.7",
13+
"clue/block-react": "^1.3",
14+
"google/cloud-tools": "^0.9.1"
15+
}
16+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
{#
2+
# Copyright 2019 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#}
16+
<!doctype html>
17+
<html>
18+
<head>
19+
<title>Google App Engine Flexible Environment - PHP Websockets Chat</title>
20+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
21+
</head>
22+
<body>
23+
24+
<!-- [START gae_flex_websockets_form] -->
25+
<p>Chat demo</p>
26+
<form id="chat-form">
27+
<textarea id="chat-text" placeholder="Enter some text..."></textarea>
28+
<button type="submit">Send</button>
29+
</form>
30+
31+
<div>
32+
<p>Messages:</p>
33+
<ul id="chat-response"></ul>
34+
</div>
35+
36+
<div>
37+
<p>Status:</p>
38+
<ul id="chat-status"></ul>
39+
</div>
40+
<!-- [END gae_flex_websockets_form] -->
41+
42+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
43+
<script>
44+
// [START gae_flex_websockets_js]
45+
$(function() {
46+
/* If the main page is served via https, the WebSocket must be served via
47+
"wss" (WebSocket Secure) */
48+
var scheme = window.location.protocol == "https:" ? 'wss://' : 'ws://';
49+
var webSocketUri = scheme
50+
+ window.location.hostname
51+
+ (location.port ? ':'+location.port: '')
52+
+ '/chat';
53+
/* Get elements from the page */
54+
var form = $('#chat-form');
55+
var textarea = $('#chat-text');
56+
var output = $('#chat-response');
57+
var status = $('#chat-status');
58+
/* Helper to keep an activity log on the page. */
59+
function log(text){
60+
status.append($('<li>').text(text))
61+
}
62+
/* Establish the WebSocket connection and register event handlers. */
63+
var websocket = new WebSocket(webSocketUri);
64+
websocket.onopen = function() {
65+
log('Connected');
66+
};
67+
websocket.onclose = function() {
68+
log('Closed');
69+
};
70+
websocket.onmessage = function(e) {
71+
log('Message received');
72+
output.append($('<li>').text(e.data));
73+
};
74+
websocket.onerror = function(e) {
75+
log('Error (see console)');
76+
console.log(e);
77+
};
78+
/* Handle form submission and send a message to the websocket. */
79+
form.submit(function(e) {
80+
e.preventDefault();
81+
var data = textarea.val();
82+
websocket.send(data);
83+
});
84+
});
85+
// [END gae_flex_websockets_js]
86+
</script>
87+
</body>
88+
</html>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
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+
use Silex\Provider\RoutingServiceProvider;
23+
24+
// create the Silex application
25+
$app = new Application();
26+
$app['debug'] = true;
27+
28+
// register twig
29+
$app->register(new TwigServiceProvider(), [
30+
'twig.path' => __DIR__
31+
]);
32+
33+
$app->register(new Silex\Provider\RoutingServiceProvider());
34+
35+
$app->get('/', function () use ($app) {
36+
return $app['twig']->render('index.html.twig');
37+
});
38+
39+
// @codeCoverageIgnoreStart
40+
if (PHP_SAPI != 'cli') {
41+
$app->run();
42+
}
43+
// @codeCoverageIgnoreEnd
44+
45+
return $app;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
location /chat {
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+
<!--
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+
<phpunit bootstrap="test/bootstrap.php" colors="true">
18+
<testsuites>
19+
<testsuite name="default">
20+
<directory>test</directory>
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.php</file>
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+
<?php
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;

0 commit comments

Comments
 (0)