-
Notifications
You must be signed in to change notification settings - Fork 6.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Channel code samples for python #285
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
9d05488
Update app.yaml
yufengg 84e9847
Create README.md
yufengg 5391194
Added files via upload
yufengg 31d95ec
updated to use webapp2
yufengg b020979
added code sample tags
2b36f00
Merge branch 'master' into channel_yg
yufengg 2cae8dc
added code sample tags
yufengg d33210c
minor formatting fixes
yufengg cbc396f
minor formatting fixes
yufengg 4420e51
fixed project id in url
yufengg d6e0e7a
changes after review
yufengg 7bb2db7
after running linter
yufengg 5dd9920
Merge branch 'master' into channel_yg
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
To deploy, run the following command, or see [here](https://cloud.google.com/appengine/docs/python/gettingstartedpython27/uploading) for more details about uploading your application. | ||
|
||
`appcfg.py -A <YOUR_PROJECT_ID> update .` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,15 @@ | ||
application: YOUR_PROJECT_ID | ||
version: 1 | ||
module: tictactoe | ||
runtime: python27 | ||
version: 1 | ||
api_version: 1 | ||
threadsafe: true | ||
|
||
handlers: | ||
- url: /.* | ||
script: chatactoe.py | ||
script: chatactoe.app | ||
|
||
libraries: | ||
- name: webapp2 | ||
version: "2.5.2" | ||
- name: jinja2 | ||
version: "2.6" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
# Copyright 2016 Google Inc. All Rights Reserved. | ||
# | ||
# 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. | ||
""" | ||
Channel Tic Tac Toe | ||
This module demonstrates the App Engine Channel API by implementing a | ||
simple tic-tac-toe game. | ||
For more information, see the README.md. | ||
""" | ||
|
||
# [START all] | ||
|
||
import datetime | ||
import logging | ||
import os | ||
import random | ||
import re | ||
import json | ||
|
||
from google.appengine.api import channel | ||
from google.appengine.api import users | ||
from google.appengine.api import app_identity | ||
from google.appengine.ext import db | ||
import jinja2 | ||
import webapp2 | ||
|
||
CLOUD_PROJECT_ID = app_identity.get_application_id() | ||
|
||
|
||
class Game(db.Model): | ||
"""All the data we store for a game""" | ||
userX = db.UserProperty() | ||
userO = db.UserProperty() | ||
board = db.StringProperty() | ||
moveX = db.BooleanProperty() | ||
winner = db.StringProperty() | ||
winning_board = db.StringProperty() | ||
|
||
|
||
class Wins(): | ||
x_win_patterns = ['XXX......', '...XXX...', '......XXX', 'X..X..X..', | ||
'.X..X..X.', '..X..X..X', 'X...X...X', '..X.X.X..'] | ||
|
||
o_win_patterns = map(lambda s: s.replace('X', 'O'), x_win_patterns) | ||
|
||
x_wins = map(lambda s: re.compile(s), x_win_patterns) | ||
o_wins = map(lambda s: re.compile(s), o_win_patterns) | ||
|
||
|
||
# [START validate_message_3] | ||
class GameUpdater(): | ||
"""Creates an object to store the game's state, and handles validating moves | ||
and broadcasting updates to the game.""" | ||
game = None | ||
|
||
def __init__(self, game): | ||
self.game = game | ||
|
||
def get_game_message(self): | ||
gameUpdate = { | ||
'board': self.game.board, | ||
'userX': self.game.userX.user_id(), | ||
'userO': '' if not self.game.userO else self.game.userO.user_id(), | ||
'moveX': self.game.moveX, | ||
'winner': self.game.winner, | ||
'winningBoard': self.game.winning_board | ||
} | ||
return json.dumps(gameUpdate) | ||
|
||
def send_update(self): | ||
message = self.get_game_message() | ||
channel.send_message( | ||
self.game.userX.user_id() + self.game.key().id_or_name(), message) | ||
if self.game.userO: | ||
channel.send_message(self.game.userO.user_id() + | ||
self.game.key().id_or_name(), message) | ||
|
||
def check_win(self): | ||
if self.game.moveX: | ||
# O just moved, check for O wins | ||
wins = Wins().o_wins | ||
potential_winner = self.game.userO.user_id() | ||
else: | ||
# X just moved, check for X wins | ||
wins = Wins().x_wins | ||
potential_winner = self.game.userX.user_id() | ||
|
||
for win in wins: | ||
if win.match(self.game.board): | ||
self.game.winner = potential_winner | ||
self.game.winning_board = win.pattern | ||
return | ||
|
||
def make_move(self, position, user): | ||
if position >= 0 and user == self.game.userX or user == self.game.userO: | ||
if self.game.moveX == (user == self.game.userX): | ||
boardList = list(self.game.board) | ||
if (boardList[position] == ' '): | ||
boardList[position] = 'X' if self.game.moveX else 'O' | ||
self.game.board = "".join(boardList) | ||
self.game.moveX = not self.game.moveX | ||
self.check_win() | ||
self.game.put() | ||
self.send_update() | ||
return | ||
# [END validate_message_3] | ||
|
||
|
||
# [START validate_message_2] | ||
class GameFromRequest(): | ||
game = None | ||
|
||
def __init__(self, request): | ||
user = users.get_current_user() | ||
game_key = request.get('g') | ||
if user and game_key: | ||
self.game = Game.get_by_key_name(game_key) | ||
|
||
def get_game(self): | ||
return self.game | ||
# [END validate_message_2] | ||
|
||
|
||
# [START validate_message_1] | ||
class MovePage(webapp2.RequestHandler): | ||
def post(self): | ||
game = GameFromRequest(self.request).get_game() | ||
user = users.get_current_user() | ||
if game and user: | ||
id = int(self.request.get('i')) | ||
GameUpdater(game).make_move(id, user) | ||
# [END validate_message_1] | ||
|
||
|
||
class OpenedPage(webapp2.RequestHandler): | ||
def post(self): | ||
game = GameFromRequest(self.request).get_game() | ||
GameUpdater(game).send_update() | ||
|
||
|
||
# [START create_channel_1] | ||
class MainPage(webapp2.RequestHandler): | ||
"""The main UI page, renders the 'index.html' template.""" | ||
|
||
def get(self): | ||
"""Renders the main page. When this page is shown, we create a new | ||
channel to push asynchronous updates to the client.""" | ||
user = users.get_current_user() | ||
game_key = self.request.get('g') | ||
game = None | ||
if user: | ||
if not game_key: | ||
game_key = user.user_id() | ||
game = Game(key_name=game_key, | ||
userX=user, | ||
moveX=True, | ||
board=' ') | ||
game.put() | ||
else: | ||
game = Game.get_by_key_name(game_key) | ||
# if not game.userO: | ||
if not game.userO and game.userX != user: | ||
game.userO = user | ||
game.put() | ||
|
||
global CLOUD_PROJECT_ID | ||
game_link = 'https://' + CLOUD_PROJECT_ID + '.appspot.com/?g=' + game_key | ||
|
||
if game: | ||
token = channel.create_channel(user.user_id() + game_key) | ||
template_values = {'token': token, | ||
'me': user.user_id(), | ||
'game_key': game_key, | ||
'game_link': game_link, | ||
'initial_message': | ||
GameUpdater(game).get_game_message()} | ||
template = jinja_environment.get_template('index.html') | ||
self.response.out.write(template.render(template_values)) | ||
else: | ||
self.response.out.write('No such game') | ||
else: | ||
self.redirect(users.create_login_url(self.request.uri)) | ||
# [END create_channel_1] | ||
|
||
jinja_environment = jinja2.Environment( | ||
loader=jinja2.FileSystemLoader(os.path.dirname(__file__))) | ||
|
||
app = webapp2.WSGIApplication( | ||
[ | ||
('/', MainPage), ('/opened', OpenedPage), ('/move', MovePage) | ||
], | ||
debug=True) | ||
|
||
# [END all] |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
flake8 will complain about this. It should be: