Skip to content

Commit d3dbe6a

Browse files
committed
adds archiving sample app, closes #17
1 parent ca5c5ef commit d3dbe6a

File tree

14 files changed

+562
-0
lines changed

14 files changed

+562
-0
lines changed

sample/Archiving/README.md

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# OpenTok Hello World Python
2+
3+
This is a simple demo app that shows how you can use the OpenTok-Python-SDK to create Sessions,
4+
generate Tokens with those Sessions, and then pass these values to a JavaScript client that can
5+
connect and conduct a group chat.
6+
7+
## Running the App
8+
9+
First, we highly recommend setting up a [virtualenv](http://www.virtualenv.org/en/latest/).
10+
11+
```
12+
$ virtualenv venv
13+
$ source venv/bin/activate
14+
```
15+
16+
Next, download the dependencies using [Pip](http://www.pip-installer.org/en/latest/), from the
17+
current directory:
18+
19+
```
20+
(venv)$ pip install -r requirements.txt
21+
```
22+
23+
Then add your own API Key and API Secret to the environment variables. There are a few ways to do
24+
this but the simplest would be to do it right in your shell.
25+
26+
```
27+
(venv)$ export API_KEY=0000000
28+
(venv)$ export API_SECRET=abcdef1234567890abcdef01234567890abcdef
29+
```
30+
31+
Finally, start the server.
32+
33+
```
34+
(venv)$ python helloworld.py
35+
```
36+
37+
Visit <http://127.0.0.1:5000/> in your browser. Open it again in a second window. Smile! You've just
38+
set up a group chat.
39+
40+
## Walkthrough
41+
42+
This demo application uses the [Flask web microframework](http://flask.pocoo.org/). It is similar to
43+
many other popular web frameworks. We are only covering the very basics of the framework, but you can
44+
learn more by following the links above.
45+
46+
### Main Application (helloworld.py)
47+
48+
The first thing done in this file is to import the dependencies we will be using. In this case that
49+
is the Flask web framework, the os module, and most importantly the OpenTok SDK.
50+
51+
```python
52+
from flask import Flask, render_template
53+
from opentok import OpenTok
54+
import os
55+
```
56+
57+
Next this file performs some basic checks on the environment. If it cannot find the `API_KEY`and
58+
`API_SECRET` environment variables, there is no point in continuing.
59+
60+
The object `app` is our application and its initialized by instantiating an object from Flask.
61+
Then we initialize an instance of OpenTok as `opentok`. If this file is run as the main file,
62+
we should start running the app.
63+
64+
```python
65+
app = Flask(__name__)
66+
opentok = OpenTok(api_key, api_secret)
67+
68+
# ...
69+
70+
if __name__ == "__main__":
71+
app.run()
72+
```
73+
74+
Now, lets discuss the Hello World application's functionality. We want to set up a group chat so
75+
that any client that visits a page will connect to the same OpenTok Session. Once they are connected
76+
they can Publish a Stream and Subscribe to all the other streams in that Session. So we just need
77+
one Session object, and it needs to be accessible every time a request is made. On the next line we
78+
simply call the `OpenTok` instance's `create_session` method to get a Session and store it in the
79+
`session` variable. Alternatively, `session_id`s are commonly stored in databses for applications
80+
that have many of them.
81+
82+
```python
83+
session = opentok.create_session()
84+
```
85+
86+
We only need one page, so we create one route handler for any HTTP GET requests to trigger.
87+
88+
```python
89+
@app.route("/")
90+
def hello():
91+
# ...
92+
```
93+
94+
Now all we have to do is serve a page with the three values the client will need to connect to the
95+
session: `api_key`, `session_id`, and `token`. The `api_key` is available in the outer scope so we
96+
can just assign it. The `session_id` is available as the `session.session_id` attribute. The `token`
97+
is generated freshly on this request by calling the `generate_token` method of the `opentok`
98+
instance, and passing in the `session_id`. This is because a Token is a piece of information that
99+
carries a specific client's permissions in a certain Session. Ideally, as we've done here, you
100+
generate a unique token for each client that will connect.
101+
102+
```python
103+
key = api_key
104+
session_id = session.session_id
105+
token = opentok.generate_token(session_id)
106+
```
107+
108+
Now all we have to do is serve a page with those three values. Lets call our `render_template`
109+
helper that will pick up a template called `index.html` from the `templates/` directory in our
110+
application and pass in the variables for it to include on the page.
111+
112+
```python
113+
return render_template('index.html', api_key=key, session_id=session_id, token=token)
114+
```
115+
116+
### Main Template (templates/index.html)
117+
118+
This file simply sets up the HTML page for the JavaScript application to run, imports the
119+
JavaScript library, and passes the values created by the server into the JavaScript application
120+
inside `public/js/helloworld.js`
121+
122+
### JavaScript Applicaton (static/js/helloworld.js)
123+
124+
The group chat is mostly implemented in this file. At a high level, we connect to the given
125+
Session, publish a stream from our webcam, and listen for new streams from other clients to
126+
subscribe to.
127+
128+
For more details, read the comments in the file or go to the
129+
[JavaScript Client Library](http://tokbox.com/opentok/libraries/client/js/) for a full reference.

sample/Archiving/archiving.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
from flask import Flask, render_template, request, redirect, url_for
2+
from opentok import OpenTok
3+
from email.utils import formatdate
4+
import os, time
5+
6+
try:
7+
api_key = os.environ['API_KEY']
8+
api_secret = os.environ['API_SECRET']
9+
except Exception:
10+
raise Exception('You must define API_KEY and API_SECRET environment variables')
11+
12+
app = Flask(__name__)
13+
opentok = OpenTok(api_key, api_secret)
14+
session = opentok.create_session()
15+
16+
@app.template_filter('datefmt')
17+
def datefmt(dt):
18+
return formatdate(time.mktime(dt.timetuple()))
19+
20+
@app.route("/")
21+
def index():
22+
return render_template('index.html')
23+
24+
@app.route("/host")
25+
def host():
26+
key = api_key
27+
session_id = session.session_id
28+
token = opentok.generate_token(session_id)
29+
return render_template('host.html', api_key=key, session_id=session_id, token=token)
30+
31+
@app.route("/participant")
32+
def participant():
33+
key = api_key
34+
session_id = session.session_id
35+
token = opentok.generate_token(session_id)
36+
return render_template('participant.html', api_key=key, session_id=session_id, token=token)
37+
38+
@app.route("/history")
39+
def history():
40+
page = int(request.args.get('page', '1'))
41+
offset = (page - 1) * 5
42+
archives = opentok.get_archives(offset=offset, count=5)
43+
44+
show_previous = '/history?page=' + str(page-1) if page > 1 else None
45+
show_next = '/history?page=' + str(page+1) if archives.count > (offset + 5) else None
46+
47+
return render_template('history.html', archives=archives, show_previous=show_previous,
48+
show_next=show_next)
49+
50+
@app.route("/download/<archive_id>")
51+
def download(archive_id):
52+
archive = opentok.get_archive(archive_id)
53+
return redirect(archive.url)
54+
55+
@app.route("/start")
56+
def start():
57+
archive = opentok.start_archive(session.session_id, name="Python Archiving Sample App")
58+
return archive.json()
59+
60+
@app.route("/stop/<archive_id>")
61+
def stop(archive_id):
62+
archive = opentok.stop_archive(archive_id)
63+
return archive.json()
64+
65+
@app.route("/delete/<archive_id>")
66+
def delete(archive_id):
67+
opentok.delete_archive(archive_id)
68+
return redirect(url_for('history'))
69+
70+
71+
if __name__ == "__main__":
72+
app.debug = True
73+
app.run()

sample/Archiving/requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Flask
2+
-e ./../..
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/* Move down content because we have a fixed navbar that is 50px tall */
2+
body {
3+
padding-top: 50px;
4+
padding-bottom: 20px;
5+
background-color: #F2F2F2;
6+
}
7+
8+
/* Responsive: Portrait tablets and up */
9+
@media screen and (min-width: 768px) {
10+
/* Remove padding from wrapping element since we kick in the grid classes here */
11+
.body-content {
12+
padding: 0;
13+
}
14+
}
15+
16+
#subscribers div {
17+
float: left;
18+
}
19+
20+
.bump-me {
21+
padding-top: 40px;
22+
}
20.6 KB
Loading
21.3 KB
Loading
20.6 KB
Loading

sample/Archiving/static/js/host.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
var session = OT.initSession(sessionId),
2+
publisher = OT.initPublisher("publisher"),
3+
archiveID = null;
4+
5+
session.connect(apiKey, token, function(err, info) {
6+
if(err) {
7+
alert(err.message || err);
8+
}
9+
session.publish(publisher);
10+
});
11+
12+
session.on('streamCreated', function(event) {
13+
session.subscribe(event.stream, "subscribers", { insertMode: "append" });
14+
});
15+
16+
session.on('archiveStarted', function(event) {
17+
archiveID = event.id;
18+
console.log("ARCHIVE STARTED");
19+
$(".start").hide();
20+
$(".stop").show();
21+
});
22+
23+
session.on('archiveStopped', function(event) {
24+
archiveID = null;
25+
console.log("ARCHIVE STOPPED");
26+
$(".start").show();
27+
$(".stop").hide();
28+
});
29+
30+
$(document).ready(function() {
31+
$(".start").click(function(event){
32+
$.get("start");
33+
}).show();
34+
$(".stop").click(function(event){
35+
$.get("stop/" + archiveID);
36+
}).hide();
37+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
var session = OT.initSession(sessionId),
2+
publisher = OT.initPublisher("publisher");
3+
4+
session.connect(apiKey, token, function(err, info) {
5+
if(err) {
6+
alert(err.message || err);
7+
}
8+
session.publish(publisher);
9+
});
10+
11+
session.on('streamCreated', function(event) {
12+
session.subscribe(event.stream, "subscribers", { insertMode : "append" });
13+
});

sample/Archiving/templates/base.html

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
6+
<title>Archiving Sample</title>
7+
<meta name="description" content="">
8+
<meta name="viewport" content="width=device-width">
9+
10+
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/css/bootstrap.min.css">
11+
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/css/bootstrap-theme.min.css">
12+
<link rel="stylesheet" href="{{ url_for('static', filename='css/sample.css') }}">
13+
14+
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
15+
</head>
16+
<body>
17+
18+
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
19+
<!-- Brand and toggle get grouped for better mobile display -->
20+
<div class="navbar-header">
21+
<a class="navbar-brand" href="./">Archiving Sample App</a>
22+
</div>
23+
</nav>
24+
25+
{% block content %}{% endblock %}
26+
27+
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/js/bootstrap.min.js"></script>
28+
</body>
29+
</html>

0 commit comments

Comments
 (0)