docker run -p "80:80" frankwiles/hello-docker:latest
And then browse to http://localhost/
WAMP defines a lightweight protocol for doing RPC and pubsub over websockets
When using WAMP you need a WAMP router. Simpl uses crossbar for this.
A WAMP router is responsible for terminating the websocket connections, authentication, authorization, and routing messages and calls
What we call a model or modelservice in Simpl is both a crossbar WAMP router and a asyncio Python process which registers itself with the router to answer WAMP calls from the UI.
This API is the data storage for Simpl
$ git clone https://github.com/simplworld/simpl-games-api.git
$ cd simpl-games-api
$ git checkout -b simpl-bootcamp origin/simpl-bootcamp
$ docker-compose up
NOTE: Do not rename the checkout, it must be named simpl-games-api
(your terminal)$ docker-compose run --rm api bash
(container termainl)$ python3 manage.py createsuperuser
This creates a temporary container off our image and gives you a Linux shell in it. Enter email address and password when prompted.
This user is your admin account to the Simpl Games API
Login with the email and password you used to create your superuser
Released as Open Source by Facebook in 2013
code_examples/react1.js
Didn't PHP and the like teach us that mixing code and presentation is a bad idea?
function add(x, y) {
return x + y;
}
const add = (x, y) => {
return x + y;
}
var MyObject = {foo: 1, bar: 2};
var foo = MyObject.foo;
var bar = MyObject.bar;
let MyObject = {foo: 1, bar: 2};
let { foo, bar } = MyObject;
'let' creates a block scoped variable.
var someModule = require(./SomeModule);
import someModule from './someModule';
const first = "Frank";
const last = "Wiles
const myName = "FullName: " + a + " " + b;
const myText = `FullName: ${a} ${b}`;
code_examples/react2.js
One way data flow pattern used by React
{
items: ["coffee", "tea", "espresso"],
user: {
email: null,
loggedIn: false
}
}
{ type: "ADD_ITEM", data: "danish" }
{ type: "SET_USER", email: "frank@revsys.com" }
{ type: "LOGIN_USER", sessionId: "lfyBnPmRzbUQims" }
function items(state = [], action) {
switch (action.type) {
case 'ADD_ITEM':
return [...state, action.data]
default:
return state
}
}
function user(state = {email: null, loggedIn: false}, action) {
switch (action.type) {
case 'SET_USER':
return {...state, email: action.email}
case 'LOGIN_USER':
return {...state, loggedIn: true}
default:
return state
}
}
git clone https://github.com/simplworld/simpl-blackjack-ui.git
$ cd simpl-blackjack-ui
$ docker-compose up
NOTE: Do not rename the checkout, it must be named simpl-games-ui
environment:
- DJANGO_SETTINGS_MODULE=blackjack_ui.settings
- MODEL_SERVICE_WS=ws://localhost:8080/ws
- SIMPL_GAMES_URL=http://api:8000/apis/
docker-compose.yaml
urlpatterns = [
url(r"^api/", include(("users.urls", "users_api"))),
url(r"^admin/", admin.site.urls),
re_path(
r"^static/(?P.*)$",
serve,
kwargs={
"document_root": settings.STATIC_ROOT,
"show_indexes": True
},
),
url(r"^.*$", TemplateView.as_view(
template_name="core/index.html"
)),
]
blackjack_ui/urls.py
urlpatterns = [
url(r"^api/", include(("users.urls", "users_api"))),
url(r"^admin/", admin.site.urls),
re_path(
r"^static/(?P.*)$",
serve,
kwargs={
"document_root": settings.STATIC_ROOT,
"show_indexes": True
},
),
url(r"^.*$", TemplateView.as_view(
template_name="core/index.html"
)),
]
Django's routing loads this template for any path not defined above
{% load render_bundle from webpack_loader %}
<html>
<head>
Wharton Blackjack
{% render_bundle 'main' 'css' %}
</head>
<body>
{% render_bundle 'main' 'js' %}
</body>
</html>
core/templates/frontend/home.html
django-webpack-loader knows what these bundles are and what URL to load them from.
{% load render_bundle from webpack_loader %}
<html>
<head>
Wharton Blackjack
{% render_bundle 'main' 'css' %}
</head>
<body>
{% render_bundle 'main' 'js' %}
</body>
</html>
core/templates/frontend/home.html
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store/store';
import App from './app';
import '../scss/main.scss';
ReactDOM.render(
,
document.getElementById('app')
);
frontend/js/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store/store';
import App from './app';
import '../scss/main.scss';
ReactDOM.render(
,
document.getElementById('app')
);
frontend/js/index.js
git clone https://github.com/simplworld/simpl-blackjack-model.git
$ cd simpl-blackjack-model
$ docker-compose up
NOTE: Do not rename the checkout, it must be named simpl-games-model
environment:
- DJANGO_SETTINGS_MODULE=blackjack_model.settings
- SIMPL_GAMES_URL=http://api:8000/apis/
- CALLBACK_URL=http://model.backend:8080/callback
docker-compose.yaml
python manage.py run_modelservice
Provided by simpl-modelservice
Launches Crossbar and Model for us
from modelservice.games import Period
from modelservice.games import subscribe
class BlackjackPeriod(Period):
@subscribe
async def submit_decision(self, action, **kwargs):
...
Corresponds to a publish on world.simpl.sims.blackjack.model.period.1.submit_decision
// Javascript frontend
submitDecision(1, "hit")
// Autobahn Call
AutobahnReact.publish(
`model:model.period.${period.id}.submit_decision`,
[action]
)
# Python model
BlackjackPeriod.submit_decision(action="hit")
{
"deck": [],
"player_cards": [],
"dealer_cards": [],
"player_score": 0,
"dealer_score": 0,
"player_busted": False,
"dealer_busted": False,
"push": false,
"player_done": False,
"dealer_done": False,
}
For each Player Decision a new Result in this format containing the current state of play is created.