From 52f59caa2fa6d9340e352d3fc9f105ea5c7bd587 Mon Sep 17 00:00:00 2001 From: Jisha Abubaker Date: Fri, 4 Aug 2017 14:08:20 -0700 Subject: [PATCH 01/11] adding Pusher sample --- appengine/pom.xml | 1 + appengine/pusher-chat/README.md | 51 +++++++ appengine/pusher-chat/pom.xml | 77 ++++++++++ .../appengine/pusher/AuthorizeServlet.java | 91 +++++++++++ .../example/appengine/pusher/ChatServlet.java | 73 +++++++++ .../appengine/pusher/PusherService.java | 42 +++++ .../appengine/pusher/SendMessageServlet.java | 72 +++++++++ .../src/main/webapp/WEB-INF/appengine-web.xml | 20 +++ .../src/main/webapp/WEB-INF/view/chat.jsp | 143 ++++++++++++++++++ .../src/main/webapp/WEB-INF/web.xml | 42 +++++ .../src/main/webapp/static/chat.css | 23 +++ 11 files changed, 635 insertions(+) create mode 100644 appengine/pusher-chat/README.md create mode 100644 appengine/pusher-chat/pom.xml create mode 100644 appengine/pusher-chat/src/main/java/com/example/appengine/pusher/AuthorizeServlet.java create mode 100644 appengine/pusher-chat/src/main/java/com/example/appengine/pusher/ChatServlet.java create mode 100644 appengine/pusher-chat/src/main/java/com/example/appengine/pusher/PusherService.java create mode 100644 appengine/pusher-chat/src/main/java/com/example/appengine/pusher/SendMessageServlet.java create mode 100644 appengine/pusher-chat/src/main/webapp/WEB-INF/appengine-web.xml create mode 100644 appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp create mode 100644 appengine/pusher-chat/src/main/webapp/WEB-INF/web.xml create mode 100644 appengine/pusher-chat/src/main/webapp/static/chat.css diff --git a/appengine/pom.xml b/appengine/pom.xml index e07b0e4806f..d05fc08378c 100644 --- a/appengine/pom.xml +++ b/appengine/pom.xml @@ -69,6 +69,7 @@ memcache multitenancy oauth2 + pusher-chat requests search sendgrid diff --git a/appengine/pusher-chat/README.md b/appengine/pusher-chat/README.md new file mode 100644 index 00000000000..0d9311f3338 --- /dev/null +++ b/appengine/pusher-chat/README.md @@ -0,0 +1,51 @@ +# Pusher sample for Google App Engine + +This sample demonstrates how to use the [Pusher][pusher] on [Google App +Engine][ae-docs]. +Pusher enables you to create public / private channels with presence information for real time messaging. +This application demonstrates presence channels in Pusher using chat rooms. +All users joining the chat room are authenticated. +All users currently in the chat room receive updates of users joining / leaving the room. +We will be using the [Java HTTP library](https://github.com/pusher/pusher-http-java) for publishing messages to the channel +and will be subscribing to channels using JS. + +[pusher]: https://pusher.com +[ae-docs]: https://cloud.google.com/appengine/docs/java/ + +## Setup + +Install the [Google Cloud SDK](https://cloud.google.com/sdk/) and run: +``` + gcloud init +``` +If this is your first time creating an App engine application: +``` + gcloud app create + +``` + +#### Setup Pusher + +- Create a [Pusher] application and note down the `APP_ID`, `APP_KEY`, `APP_SECRET` and the cluster. +- Update [PusherService.java](src/main/java/com/example/appengine/pusher/PusherService.java) with these credentials. +- Update [index.html](src/webapp/WEB-INF/view/index.jsp) with the `APP_ID` and cluster information. + + +## Running locally + +``` + mvn clean appengine:run +``` + +Access [http://localhost:8080](http://localhost:8080) via the browser, login and join the chat room. +The chat window will contain a link you can use to join the room as a different user in another browser. +You should now be able to view both the users within the chat application window and send messages to one another. + +## Deploying + +- Deploy the application to the project + ``` + mvn clean appengine:deploy + + ``` + Access `https://YOUR_PROJECT_ID.appspot.com` diff --git a/appengine/pusher-chat/pom.xml b/appengine/pusher-chat/pom.xml new file mode 100644 index 00000000000..fbe1e1a2d34 --- /dev/null +++ b/appengine/pusher-chat/pom.xml @@ -0,0 +1,77 @@ + + + 4.0.0 + war + 1.0-SNAPSHOT + com.example.appengine + appengine-pusher-chat + + + 1.8 + 1.8 + + + + + com.pusher + pusher-http-java + 1.0.0 + + + com.google.guava + guava + 20.0 + + + com.fasterxml.jackson.core + jackson-databind + 2.8.8 + + + javax.servlet + servlet-api + 2.5 + provided + + + com.google.appengine + appengine-api-1.0-sdk + 1.9.54 + + + + + + ${project.build.directory}/${project.build.finalName}/WEB-INF/classes + + + org.apache.maven.plugins + 3.3 + maven-compiler-plugin + + 1.7 + 1.7 + + + + com.google.cloud.tools + appengine-maven-plugin + 1.3.1 + + + + diff --git a/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/AuthorizeServlet.java b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/AuthorizeServlet.java new file mode 100644 index 00000000000..b9a3ed4e134 --- /dev/null +++ b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/AuthorizeServlet.java @@ -0,0 +1,91 @@ +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.appengine.pusher; + +import com.google.appengine.api.users.User; +import com.google.appengine.api.users.UserServiceFactory; +import com.google.common.io.CharStreams; +import com.pusher.rest.Pusher; +import com.pusher.rest.data.PresenceUser; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.HashMap; +import java.util.Map; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Authorization endpoint that is automatically triggered on `Pusher.subscribe` + * for private, presence channels. + * Successful authentication returns valid authorization token with user information. + * @see Pusher Authentication Docs + */ +public class AuthorizeServlet extends HttpServlet { + + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { + + // Instantiate a pusher connection + Pusher pusher = PusherService.getDefaultInstance(); + // Get current logged in user credentials + User user = UserServiceFactory.getUserService().getCurrentUser(); + + // redirect to homepage if user is not authorized + if (user == null) { + response.sendRedirect("/"); + return; + } + String currentUserId = user.getUserId(); + String displayName = user.getNickname().replaceFirst("@.*", ""); + + String query = CharStreams.toString(request.getReader()); + // socket_id, channel_name parameters are automatically set in the POST body of the request + // eg.socket_id=1232.12&channel_name=presence-my-channel + Map data = splitQuery(query); + String socketId = data.get("socket_id"); + String channelId = data.get("channel_name"); + + // Presence channels (presence-*) require user identification for authentication + Map userInfo = new HashMap<>(); + userInfo.put("displayName", displayName); + + // Inject custom authentication code for your application here to allow /deny current request + + String auth = pusher.authenticate(socketId, channelId, new PresenceUser(currentUserId, userInfo)); + // if successful, returns authorization in the format + // { + // "auth":"49e26cb8e9dde3dfc009:a8cf1d3deefbb1bdc6a9d1547640d49d94b4b512320e2597c257a740edd1788f", + // "channel_data":"{\"user_id\":\"23423435252\",\"user_info\":{\"displayName\":\"John Doe\"}}" + // } + + response.getWriter().append(auth); + } + + private static Map splitQuery(String query) throws UnsupportedEncodingException { + Map query_pairs = new HashMap<>(); + String[] pairs = query.split("&"); + for (String pair : pairs) { + int idx = pair.indexOf("="); + query_pairs.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), + URLDecoder.decode(pair.substring(idx + 1), "UTF-8")); + } + return query_pairs; + } +} diff --git a/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/ChatServlet.java b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/ChatServlet.java new file mode 100644 index 00000000000..06ee81a87e1 --- /dev/null +++ b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/ChatServlet.java @@ -0,0 +1,73 @@ +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.appengine.pusher; + +import com.google.appengine.api.users.User; +import com.google.appengine.api.users.UserService; +import com.google.appengine.api.users.UserServiceFactory; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Homepage of chat application, redirects user to login page if not authorized. + */ +public class ChatServlet extends HttpServlet { + + public static String getUriWithChatRoom(HttpServletRequest request, String chatRoom) { + try { + String query = ""; + if (chatRoom != null) { + query = "room=" + chatRoom; + } + URI thisUri = new URI(request.getRequestURL().toString()); + URI uriWithOptionalRoomParam = new URI( + thisUri.getScheme(), thisUri.getUserInfo(), thisUri.getHost(), + thisUri.getPort(), "/", query, ""); + return uriWithOptionalRoomParam.toString(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + final UserService userService = UserServiceFactory.getUserService(); + User currentUser = userService.getCurrentUser(); + String room = req.getParameter("room"); + // Show login link if user is not logged in. + if (currentUser == null) { + String loginUrl = userService.createLoginURL(getUriWithChatRoom(req, room)); + resp.getWriter().println("

Please sign in.

"); + return; + } + + // user is already logged in + if (room != null) { + req.setAttribute("room", room); + } + getServletContext().getRequestDispatcher("/WEB-INF/view/chat.jsp").forward(req, resp); + } +} diff --git a/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/PusherService.java b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/PusherService.java new file mode 100644 index 00000000000..7dd4ad0684d --- /dev/null +++ b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/PusherService.java @@ -0,0 +1,42 @@ +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.appengine.pusher; + +import com.pusher.rest.Pusher; + +abstract class PusherService { + + private final static String APP_ID = System.getenv("PUSHER_APP_ID"); + private final static String APP_KEY = System.getenv("PUSHER_APP_KEY"); + private final static String APP_SECRET = System.getenv("PUSHER_APP_SECRET"); + + private static Pusher instance; + + static Pusher getDefaultInstance() { + if (instance != null) { + return instance; + } + // [START pusher_server_initialize] + // Instantiate a pusher + Pusher pusher = new Pusher(APP_ID, APP_KEY, APP_SECRET); + pusher.setCluster("mt1"); // required, if not default mt1 (us-east-1) + pusher.setEncrypted(true); // optional, ensure subscriber also matches these settings + // [END pusher_server_initialize] + instance = pusher; + return pusher; + } +} diff --git a/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/SendMessageServlet.java b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/SendMessageServlet.java new file mode 100644 index 00000000000..74e35f84104 --- /dev/null +++ b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/SendMessageServlet.java @@ -0,0 +1,72 @@ +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.appengine.pusher; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.google.appengine.api.users.User; +import com.google.appengine.api.users.UserServiceFactory; +import com.google.common.io.CharStreams; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.pusher.rest.data.Result; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Submit a chat message over a channel. + * Note : we use socket_id to exclude the sender from receiving the message + // {@see Excluding Recipients} + */ +public class SendMessageServlet extends HttpServlet { + + private Gson gson = new GsonBuilder().create(); + private TypeReference> typeReference = + new TypeReference>() {}; + + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { + // Parse POST request body in the format : + // [{"message": "my-message", "socket_id": "1232.24", "channel": "presence-my-channel"}] + + String body = CharStreams.readLines(request.getReader()).toString(); + String json = body.replaceFirst("^\\[", "").replaceFirst("\\]$", ""); + Map data = gson.fromJson(json, typeReference.getType()); + String message = data.get("message"); + String socketId = data.get("socket_id"); + String channelId = data.get("channel_id"); + + User user = UserServiceFactory.getUserService().getCurrentUser(); + String displayName = user.getNickname().replaceFirst("@.*", ""); + + String taggedMessage = "<" + displayName + "> " + message; + Map messageData = new HashMap<>(); + messageData.put("message", taggedMessage); + Result result = PusherService.getDefaultInstance().trigger( + channelId, //the channel + "new_message", //the event + messageData, socketId); + messageData.put("status", result.getStatus().name()); + // result.getStatus() == SUCCESS indicates successful transmission + // result.getStatus() == CLIENT_ERROR : confirm cluster, credentials of the Pusher instances. + response.getWriter().println(gson.toJson(messageData)); + } +} diff --git a/appengine/pusher-chat/src/main/webapp/WEB-INF/appengine-web.xml b/appengine/pusher-chat/src/main/webapp/WEB-INF/appengine-web.xml new file mode 100644 index 00000000000..a4fe5f504aa --- /dev/null +++ b/appengine/pusher-chat/src/main/webapp/WEB-INF/appengine-web.xml @@ -0,0 +1,20 @@ + + + true + + + + + + \ No newline at end of file diff --git a/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp b/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp new file mode 100644 index 00000000000..ab9940beedc --- /dev/null +++ b/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp @@ -0,0 +1,143 @@ + +<%@ page import="com.example.appengine.pusher.ChatServlet" %> +<%@ page import="java.util.Date" %> +<%-- + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--%> + + + + + + + +
+
+
+
+
+
+
+

Room()

+

Online (0)

+
    +
  • +
+
+
+
+
+ + +
+
+
+
+ + + \ No newline at end of file diff --git a/appengine/pusher-chat/src/main/webapp/WEB-INF/web.xml b/appengine/pusher-chat/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..478514feda0 --- /dev/null +++ b/appengine/pusher-chat/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,42 @@ + + + + + chat + com.example.appengine.pusher.ChatServlet + + + authorize + com.example.appengine.pusher.AuthorizeServlet + + + sendMessage + com.example.appengine.pusher.SendMessageServlet + + + chat + / + + + authorize + /authorize + + + sendMessage + /message + + diff --git a/appengine/pusher-chat/src/main/webapp/static/chat.css b/appengine/pusher-chat/src/main/webapp/static/chat.css new file mode 100644 index 00000000000..12d563a979e --- /dev/null +++ b/appengine/pusher-chat/src/main/webapp/static/chat.css @@ -0,0 +1,23 @@ +#chat_widget_container{padding:20px 20px 5px 20px; background-color:powderblue; border:5px solid dodgerblue; + width:500px; font-size:11px; font-family: Arial,Verdana,sans-serif; + position:fixed; top:10%; left:20%} + +#chat_widget_main_container{display:none} + +#chat_widget_messages_container{float:left; width:300px; border:1px solid #DDD; height:200px; overflow:auto; + padding:5px; background-color:#FFF; position:relative} + +#chat_widget_messages{overflow-x:hidden; overflow-y:auto; position:absolute; bottom:0px} + +#chat_widget_online{width:150px; height:210px; float:left; padding:0px 10px; border:1px solid #DDD; + border-left:0px; background-color:#FFF; overflow: auto;} + +#chat_widget_online_list{list-style:none; padding:0px} + +#chat_widget_online_list >li{margin-left:0px} + +#chat_widget_input_container{margin-top:10px; text-align:left} + +#chat_widget_input{width:260px; margin-right:10px; border:1px solid #DDD; padding:2px 5px} + +.clear{clear:both} \ No newline at end of file From 8e479d866691016785dcf9973dd47be2582e9b7e Mon Sep 17 00:00:00 2001 From: Jisha Abubaker Date: Sun, 6 Aug 2017 22:12:16 -0700 Subject: [PATCH 02/11] adding doc tags --- .../appengine/pusher/AuthorizeServlet.java | 18 +- .../example/appengine/pusher/ChatServlet.java | 21 +- .../appengine/pusher/PusherService.java | 15 +- .../appengine/pusher/SendMessageServlet.java | 34 ++- .../src/main/webapp/WEB-INF/view/chat.jsp | 227 +++++++++--------- 5 files changed, 171 insertions(+), 144 deletions(-) diff --git a/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/AuthorizeServlet.java b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/AuthorizeServlet.java index b9a3ed4e134..e6e217de2f4 100644 --- a/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/AuthorizeServlet.java +++ b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/AuthorizeServlet.java @@ -21,7 +21,6 @@ import com.google.common.io.CharStreams; import com.pusher.rest.Pusher; import com.pusher.rest.data.PresenceUser; - import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; @@ -32,11 +31,13 @@ import javax.servlet.http.HttpServletResponse; /** - * Authorization endpoint that is automatically triggered on `Pusher.subscribe` - * for private, presence channels. - * Successful authentication returns valid authorization token with user information. + * Authorization endpoint that is automatically triggered on `Pusher.subscribe` for private, + * presence channels. Successful authentication returns valid authorization token with user + * information. + * * @see Pusher Authentication Docs */ +// [START pusher_authorize] public class AuthorizeServlet extends HttpServlet { @Override @@ -45,7 +46,7 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) thr // Instantiate a pusher connection Pusher pusher = PusherService.getDefaultInstance(); // Get current logged in user credentials - User user = UserServiceFactory.getUserService().getCurrentUser(); + User user = UserServiceFactory.getUserService().getCurrentUser(); // redirect to homepage if user is not authorized if (user == null) { @@ -68,7 +69,8 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) thr // Inject custom authentication code for your application here to allow /deny current request - String auth = pusher.authenticate(socketId, channelId, new PresenceUser(currentUserId, userInfo)); + String auth = + pusher.authenticate(socketId, channelId, new PresenceUser(currentUserId, userInfo)); // if successful, returns authorization in the format // { // "auth":"49e26cb8e9dde3dfc009:a8cf1d3deefbb1bdc6a9d1547640d49d94b4b512320e2597c257a740edd1788f", @@ -83,9 +85,11 @@ private static Map splitQuery(String query) throws UnsupportedEn String[] pairs = query.split("&"); for (String pair : pairs) { int idx = pair.indexOf("="); - query_pairs.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), + query_pairs.put( + URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8")); } return query_pairs; } } +// [END pusher_authorize] diff --git a/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/ChatServlet.java b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/ChatServlet.java index 06ee81a87e1..1333bee3f4a 100644 --- a/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/ChatServlet.java +++ b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/ChatServlet.java @@ -19,7 +19,6 @@ import com.google.appengine.api.users.User; import com.google.appengine.api.users.UserService; import com.google.appengine.api.users.UserServiceFactory; - import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -28,9 +27,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -/** - * Homepage of chat application, redirects user to login page if not authorized. - */ +/** Homepage of chat application, redirects user to login page if not authorized. */ public class ChatServlet extends HttpServlet { public static String getUriWithChatRoom(HttpServletRequest request, String chatRoom) { @@ -40,9 +37,15 @@ public static String getUriWithChatRoom(HttpServletRequest request, String chatR query = "room=" + chatRoom; } URI thisUri = new URI(request.getRequestURL().toString()); - URI uriWithOptionalRoomParam = new URI( - thisUri.getScheme(), thisUri.getUserInfo(), thisUri.getHost(), - thisUri.getPort(), "/", query, ""); + URI uriWithOptionalRoomParam = + new URI( + thisUri.getScheme(), + thisUri.getUserInfo(), + thisUri.getHost(), + thisUri.getPort(), + "/", + query, + ""); return uriWithOptionalRoomParam.toString(); } catch (URISyntaxException e) { throw new RuntimeException(e); @@ -58,9 +61,7 @@ public void doGet(HttpServletRequest req, HttpServletResponse resp) // Show login link if user is not logged in. if (currentUser == null) { String loginUrl = userService.createLoginURL(getUriWithChatRoom(req, room)); - resp.getWriter().println("

Please sign in.

"); + resp.getWriter().println("

Please sign in.

"); return; } diff --git a/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/PusherService.java b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/PusherService.java index 7dd4ad0684d..874def14c82 100644 --- a/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/PusherService.java +++ b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/PusherService.java @@ -18,25 +18,24 @@ import com.pusher.rest.Pusher; +// [START pusher_server_initialize] abstract class PusherService { - private final static String APP_ID = System.getenv("PUSHER_APP_ID"); - private final static String APP_KEY = System.getenv("PUSHER_APP_KEY"); - private final static String APP_SECRET = System.getenv("PUSHER_APP_SECRET"); + private static final String APP_ID = System.getenv("PUSHER_APP_ID"); + private static final String APP_KEY = System.getenv("PUSHER_APP_KEY"); + private static final String APP_SECRET = System.getenv("PUSHER_APP_SECRET"); private static Pusher instance; static Pusher getDefaultInstance() { if (instance != null) { return instance; - } - // [START pusher_server_initialize] - // Instantiate a pusher + } // Instantiate a pusher Pusher pusher = new Pusher(APP_ID, APP_KEY, APP_SECRET); - pusher.setCluster("mt1"); // required, if not default mt1 (us-east-1) + pusher.setCluster("us2"); // required, if not default mt1 (us-east-1) pusher.setEncrypted(true); // optional, ensure subscriber also matches these settings - // [END pusher_server_initialize] instance = pusher; return pusher; } } +// [END pusher_server_initialize] diff --git a/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/SendMessageServlet.java b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/SendMessageServlet.java index 74e35f84104..4119439bdbc 100644 --- a/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/SendMessageServlet.java +++ b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/SendMessageServlet.java @@ -23,7 +23,6 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.pusher.rest.data.Result; - import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -32,10 +31,12 @@ import javax.servlet.http.HttpServletResponse; /** - * Submit a chat message over a channel. - * Note : we use socket_id to exclude the sender from receiving the message - // {@see Excluding Recipients} + * Submit a chat message over a channel. Note : we use socket_id to exclude the sender from + * receiving the message // {@see + * Excluding + * Recipients} */ +// [START pusher_server_send_message] public class SendMessageServlet extends HttpServlet { private Gson gson = new GsonBuilder().create(); @@ -44,29 +45,38 @@ public class SendMessageServlet extends HttpServlet { @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { - // Parse POST request body in the format : + // Parse POST request body received in the format : // [{"message": "my-message", "socket_id": "1232.24", "channel": "presence-my-channel"}] String body = CharStreams.readLines(request.getReader()).toString(); String json = body.replaceFirst("^\\[", "").replaceFirst("\\]$", ""); - Map data = gson.fromJson(json, typeReference.getType()); + Map data = gson.fromJson(json, typeReference.getType()); String message = data.get("message"); String socketId = data.get("socket_id"); String channelId = data.get("channel_id"); User user = UserServiceFactory.getUserService().getCurrentUser(); + // user email prefix as display name for current logged in user String displayName = user.getNickname().replaceFirst("@.*", ""); + // Create a message including the user email prefix to display in the chat window String taggedMessage = "<" + displayName + "> " + message; Map messageData = new HashMap<>(); messageData.put("message", taggedMessage); - Result result = PusherService.getDefaultInstance().trigger( - channelId, //the channel - "new_message", //the event - messageData, socketId); - messageData.put("status", result.getStatus().name()); + + // Send a message over the Pusher channel (maximum size of a message is 10KB) + Result result = + PusherService.getDefaultInstance() + .trigger( + channelId, + "new_message", // name of event + messageData, + socketId); // (optional) use client socket_id to exclude the sender from receiving the message + // result.getStatus() == SUCCESS indicates successful transmission - // result.getStatus() == CLIENT_ERROR : confirm cluster, credentials of the Pusher instances. + messageData.put("status", result.getStatus().name()); + response.getWriter().println(gson.toJson(messageData)); } } +// [END pusher_server_send_message] diff --git a/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp b/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp index ab9940beedc..5673df94b61 100644 --- a/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp +++ b/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp @@ -18,126 +18,139 @@ --%> - - - + + +
-
-
-
-
+
+
+
+
+
+
+

Room()

+

Online (0)

+
    +
  • +
+
+
+
+
+ + +
+
-
-

Room()

-

Online (0)

-
    -
  • -
-
-
-
-
- - -
-
-
\ No newline at end of file From 3112453d2c762033c20c96c53cf61f268ab7f615 Mon Sep 17 00:00:00 2001 From: Jisha Abubaker Date: Sun, 6 Aug 2017 22:53:48 -0700 Subject: [PATCH 03/11] adding doc tags --- appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp b/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp index 5673df94b61..541efdb5868 100644 --- a/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp +++ b/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp @@ -65,6 +65,7 @@ $('#chat_widget_counter').html($('.chat_widget_member').length); } + // [START pusher_client_initialize] // Connect to Pusher with auth endpoint on your server for private/presence channels // (default auth endpoint : /pusher/auth) var pusher = new Pusher('5c803f8fb10988b78247', { @@ -72,8 +73,12 @@ authEndpoint: '/authorize', encrypted: true }); + // [END pusher_client_initialze] + + // [START pusher_subscribe_channel] // subscribe to auth var channel = pusher.subscribe(channel_name); + // [END pusher_subscribe_channel] // [START pusher_bind_pusher_event] // bind to successful Pusher connection From 15466da68897ad316a8ccf272e74a01d06db87c6 Mon Sep 17 00:00:00 2001 From: Jisha Abubaker Date: Sun, 6 Aug 2017 22:57:45 -0700 Subject: [PATCH 04/11] doc updates --- appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp b/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp index 541efdb5868..a81d544fc4f 100644 --- a/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp +++ b/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp @@ -73,10 +73,10 @@ authEndpoint: '/authorize', encrypted: true }); - // [END pusher_client_initialze] + // [END pusher_client_initialize] // [START pusher_subscribe_channel] - // subscribe to auth + // subscribe to the chat room presence channel, eg. "presence-my-room" var channel = pusher.subscribe(channel_name); // [END pusher_subscribe_channel] From 75395eac46d7504d99388027a62e1aeb284fbbb5 Mon Sep 17 00:00:00 2001 From: Jisha Abubaker Date: Mon, 7 Aug 2017 00:02:36 -0700 Subject: [PATCH 05/11] cleanup --- appengine/pusher-chat/README.md | 4 ++-- .../java/com/example/appengine/pusher/PusherService.java | 3 ++- .../src/main/webapp/WEB-INF/appengine-web.xml | 8 +++++--- .../pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp | 9 ++++++--- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/appengine/pusher-chat/README.md b/appengine/pusher-chat/README.md index 0d9311f3338..d6a85599f3e 100644 --- a/appengine/pusher-chat/README.md +++ b/appengine/pusher-chat/README.md @@ -27,8 +27,8 @@ If this is your first time creating an App engine application: #### Setup Pusher - Create a [Pusher] application and note down the `APP_ID`, `APP_KEY`, `APP_SECRET` and the cluster. -- Update [PusherService.java](src/main/java/com/example/appengine/pusher/PusherService.java) with these credentials. -- Update [index.html](src/webapp/WEB-INF/view/index.jsp) with the `APP_ID` and cluster information. +- Update [appengine-web.xml](src/main/webapp/WEB-INF/appengine-web.xml) with these credentials. +- Update Line 73 in [chat.jsp](src/webapp/WEB-INF/view/chat.jsp) with the `APP_ID` and cluster information. ## Running locally diff --git a/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/PusherService.java b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/PusherService.java index 874def14c82..ce5551937f8 100644 --- a/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/PusherService.java +++ b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/PusherService.java @@ -24,6 +24,7 @@ abstract class PusherService { private static final String APP_ID = System.getenv("PUSHER_APP_ID"); private static final String APP_KEY = System.getenv("PUSHER_APP_KEY"); private static final String APP_SECRET = System.getenv("PUSHER_APP_SECRET"); + private static final String CLUSTER = System.getenv("PUSHER_CLUSTER"); private static Pusher instance; @@ -32,7 +33,7 @@ static Pusher getDefaultInstance() { return instance; } // Instantiate a pusher Pusher pusher = new Pusher(APP_ID, APP_KEY, APP_SECRET); - pusher.setCluster("us2"); // required, if not default mt1 (us-east-1) + pusher.setCluster(CLUSTER); // required, if not default mt1 (us-east-1) pusher.setEncrypted(true); // optional, ensure subscriber also matches these settings instance = pusher; return pusher; diff --git a/appengine/pusher-chat/src/main/webapp/WEB-INF/appengine-web.xml b/appengine/pusher-chat/src/main/webapp/WEB-INF/appengine-web.xml index a4fe5f504aa..8ab9b54cd6b 100644 --- a/appengine/pusher-chat/src/main/webapp/WEB-INF/appengine-web.xml +++ b/appengine/pusher-chat/src/main/webapp/WEB-INF/appengine-web.xml @@ -1,3 +1,4 @@ + ${project.build.directory}/${project.build.finalName}/WEB-INF/classes - - org.apache.maven.plugins - 3.3 - maven-compiler-plugin - - 1.7 - 1.7 - - com.google.cloud.tools appengine-maven-plugin From 88f00f426e413c40d8dd77d7c56359c7b57230e2 Mon Sep 17 00:00:00 2001 From: Jisha Abubaker Date: Wed, 9 Aug 2017 14:07:56 -0700 Subject: [PATCH 10/11] adding parent dependency --- appengine/pusher-chat/pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/appengine/pusher-chat/pom.xml b/appengine/pusher-chat/pom.xml index 63cbe617a3c..285c8625273 100644 --- a/appengine/pusher-chat/pom.xml +++ b/appengine/pusher-chat/pom.xml @@ -20,6 +20,13 @@ Copyright 2017 Google Inc. com.example.appengine appengine-pusher-chat + + com.google.cloud + appengine-doc-samples + 1.0.0 + .. + + 1.7 1.7 From a3967b55afba79662c20f9ce4a0a04e6e2fdd81e Mon Sep 17 00:00:00 2001 From: Jisha Abubaker Date: Wed, 9 Aug 2017 14:33:55 -0700 Subject: [PATCH 11/11] using static vars in JSP for pusher app id, cluster info --- appengine/pusher-chat/README.md | 2 -- .../java/com/example/appengine/pusher/PusherService.java | 7 ++++--- .../pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp | 5 +++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/appengine/pusher-chat/README.md b/appengine/pusher-chat/README.md index 78ca73739cd..659018d7fb0 100644 --- a/appengine/pusher-chat/README.md +++ b/appengine/pusher-chat/README.md @@ -26,8 +26,6 @@ If this is your first time creating an App engine application: - Create a [Pusher] application and note down the `app_id`, `app_key`, `app_secret` and the cluster. - Update [appengine-web.xml](src/main/webapp/WEB-INF/appengine-web.xml) with these credentials. -- Update Line 71 in [chat.jsp](src/main/webapp/WEB-INF/view/chat.jsp) with the `app_id` and cluster information. - ## Running locally diff --git a/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/PusherService.java b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/PusherService.java index ce5551937f8..f733fdf7218 100644 --- a/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/PusherService.java +++ b/appengine/pusher-chat/src/main/java/com/example/appengine/pusher/PusherService.java @@ -19,12 +19,13 @@ import com.pusher.rest.Pusher; // [START pusher_server_initialize] -abstract class PusherService { +public abstract class PusherService { + + public static final String APP_KEY = System.getenv("PUSHER_APP_KEY"); + public static final String CLUSTER = System.getenv("PUSHER_CLUSTER"); private static final String APP_ID = System.getenv("PUSHER_APP_ID"); - private static final String APP_KEY = System.getenv("PUSHER_APP_KEY"); private static final String APP_SECRET = System.getenv("PUSHER_APP_SECRET"); - private static final String CLUSTER = System.getenv("PUSHER_CLUSTER"); private static Pusher instance; diff --git a/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp b/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp index 41c8dceded3..a9f32e1210e 100644 --- a/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp +++ b/appengine/pusher-chat/src/main/webapp/WEB-INF/view/chat.jsp @@ -1,5 +1,6 @@ <%@ page import="com.example.appengine.pusher.ChatServlet" %> +<%@ page import="com.example.appengine.pusher.PusherService" %> <%@ page import="java.util.Date" %> <%-- Copyright 2017 Google Inc. @@ -68,8 +69,8 @@ // Connect to Pusher with auth endpoint on your server for private/presence channels // (default auth endpoint : /pusher/auth) - var pusher = new Pusher("pusher_app_key", { - cluster: "pusher_cluster", + var pusher = new Pusher('<%= PusherService.APP_KEY %>', { + cluster: '<%= PusherService.CLUSTER %>', authEndpoint: '/authorize', encrypted: true });