Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
dmccormi
project-base
Commits
f8c7d75b
Commit
f8c7d75b
authored
Aug 21, 2016
by
Dave McCormick
Browse files
adding tempt files
parent
cbec12bb
Changes
6
Hide whitespace changes
Inline
Side-by-side
app/controllers/GibberishWebSocketActor.java
0 → 100644
View file @
f8c7d75b
package
controllers
;
/**
* Created by davidmccormick on 21/08/16.
*/
import
akka.actor.*
;
import
model.GibberishHub
;
import
model.GibberishListener
;
public
class
GibberishWebSocketActor
extends
UntypedActor
{
/**
* We don't create the actor ourselves. Instead, Play will ask Akka to make it for us. We have to give Akka a
* "Props" object that tells Akka what kind of actor to create, and what constructor arguments to pass to it.
* This method produces that Props object.
*/
public
static
Props
props
(
String
topic
,
ActorRef
out
)
{
// Create a Props object that says:
// - I want a GibberishWebSocketActor,
// - and pass (topic, out) as the arguments to its constructor
return
Props
.
create
(
GibberishWebSocketActor
.
class
,
topic
,
out
);
}
/** The Actor for the client (browser) */
private
final
ActorRef
out
;
/** The topic string we have subscribed to */
private
final
String
topic
;
/** A listener that we will register with our GibberishHub */
private
final
GibberishListener
listener
;
/**
* This constructor is called by Akka to create our actor (we don't call it ourselves).
*/
public
GibberishWebSocketActor
(
String
topic
,
ActorRef
out
)
{
this
.
topic
=
topic
;
this
.
out
=
out
;
/*
Our GibberishListener, written as a Java 8 Lambda.
Whenever we receive a gibberish, if it matches our topic, convert it to a JSON string, and send it to the client.
*/
this
.
listener
=
(
g
)
->
{
String
message
=
g
.
toString
();
out
.
tell
(
message
,
self
());
};
// Register this actor to hear gibberish
GibberishHub
.
getInstance
().
addListener
(
listener
);
}
/**
* This is called whenever the browser sends a message to the serverover the websocket
*/
public
void
onReceive
(
Object
message
)
throws
Exception
{
// The client isn't going to send us messages down the websocket in this example, so this doesn't matter
if
(
message
instanceof
String
)
{
out
.
tell
(
"I received your message: "
+
message
,
self
());
}
}
/**
* This is called by Play after the WebSocket has closed
*/
public
void
postStop
()
throws
Exception
{
// De-register our listener
GibberishHub
.
getInstance
().
removeListener
(
this
.
listener
);
}
}
app/controllers/JsonExample.java
0 → 100644
View file @
f8c7d75b
package
controllers
;
/**
* Created by davidmccormick on 21/08/16.
*/
import
com.fasterxml.jackson.databind.JsonNode
;
import
com.fasterxml.jackson.databind.node.ArrayNode
;
import
com.fasterxml.jackson.databind.node.ObjectNode
;
import
model.Gibberish
;
import
model.GibberishHub
;
import
play.libs.Json
;
import
play.mvc.Controller
;
import
play.mvc.LegacyWebSocket
;
import
play.mvc.Result
;
import
play.mvc.WebSocket
;
public
class
JsonExample
extends
Controller
{
public
static
ObjectNode
toJson
(
Gibberish
g
)
{
ObjectNode
n
=
Json
.
newObject
();
n
.
put
(
"msg"
,
g
.
getSubject
());
n
.
put
(
"lat"
,
g
.
getAdverb
());
n
.
put
(
"lng"
,
g
.
getVerb
());
n
.
put
(
"adjective"
,
g
.
getAdjective
());
n
.
put
(
"object"
,
g
.
getObj
());
return
n
;
}
public
Result
getGibberish
(
int
n
)
{
ObjectNode
[]
arr
=
new
ObjectNode
[
n
];
ArrayNode
an
=
Json
.
newArray
();
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
Gibberish
g
=
new
Gibberish
();
an
.
add
(
toJson
(
g
));
// Send the gibberish to the GibberishHub
//GibberishHub.getInstance().send(g);
}
return
ok
(
an
);
}
public
static
Result
postGibberish
()
{
JsonNode
json
=
request
().
body
().
asJson
();
if
(
json
==
null
)
{
return
badRequest
(
"Expecting Json data"
);
}
else
{
Gibberish
g
=
new
Gibberish
();
g
.
setSubject
(
json
.
findPath
(
"subject"
).
textValue
());
g
.
setAdverb
(
json
.
findPath
(
"adverb"
).
textValue
());
g
.
setVerb
(
json
.
findPath
(
"verb"
).
textValue
());
g
.
setAdjective
(
json
.
findPath
(
"adjective"
).
textValue
());
g
.
setObj
(
json
.
findPath
(
"object"
).
textValue
());
System
.
out
.
println
(
g
);
return
ok
(
"printed it"
);
}
}
/**
* Our WebSockets endpoint. We'll assume we're sending String messages for now
*/
public
LegacyWebSocket
<
String
>
socket
(
String
topic
)
{
/*
Play framework provides an Actor for client automatically. That's the <code>out</code> argument below.
We need to tell Play what kind of actor we want on the server side. We do that with a "Props" object, because
Play will ask Akka to create the actor for us.
We want a GibberishWebSocketActor, and we want to pass the client actor and the topic as constructor arguments.
GibberishWebSocketActor.props(topic, out) will produce a Props object saying that.
*/
return
WebSocket
.<
String
>
withActor
((
out
)
->
GibberishWebSocketActor
.
props
(
topic
,
out
));
}
}
\ No newline at end of file
app/model/Gibberish.java
0 → 100644
View file @
f8c7d75b
package
model
;
/**
* Created by davidmccormick on 21/08/16.
*/
/**
* A nonsense class, just for sending something to the client
*/
public
class
Gibberish
{
static
final
String
[]
SUBJECTS
=
{
"Algernon"
,
"Bertie"
,
"Cecily"
,
"Dahlia"
,
"Edwin"
};
static
final
String
[]
ADVERBS
=
{
"quickly"
,
"slowly"
,
"hesitatingly"
,
"grudgingly"
,
"naughtily"
};
static
final
String
[]
VERBS
=
{
"ate"
,
"juggled"
,
"bounced"
,
"dropped"
,
"hid"
};
static
final
String
[]
ADJECTIVES
=
{
"yellow"
,
"polkadot"
,
"small"
,
"smelly"
,
"tasty"
,
"plastic"
};
static
final
String
[]
OBJS
=
{
"toy ducks"
,
"mice"
,
"bananas"
,
"tissues"
,
"shoes"
};
public
String
getSubject
()
{
return
subject
;
}
public
String
getAdverb
()
{
return
adverb
;
}
public
String
getVerb
()
{
return
verb
;
}
public
String
getAdjective
()
{
return
adjective
;
}
public
String
getObj
()
{
return
obj
;
}
public
void
setSubject
(
String
subject
)
{
this
.
subject
=
subject
;
}
public
void
setAdverb
(
String
adverb
)
{
this
.
adverb
=
adverb
;
}
public
void
setVerb
(
String
verb
)
{
this
.
verb
=
verb
;
}
public
void
setAdjective
(
String
adjective
)
{
this
.
adjective
=
adjective
;
}
public
void
setObj
(
String
obj
)
{
this
.
obj
=
obj
;
}
String
subject
;
String
adverb
;
String
verb
;
String
adjective
;
String
obj
;
public
String
allocate
(
String
[]
candidates
)
{
return
candidates
[(
int
)(
Math
.
random
()
*
candidates
.
length
)];
}
public
Gibberish
()
{
this
.
subject
=
allocate
(
SUBJECTS
);
this
.
adverb
=
allocate
(
ADVERBS
);
this
.
verb
=
allocate
(
VERBS
);
this
.
adjective
=
allocate
(
ADJECTIVES
);
this
.
obj
=
allocate
(
OBJS
);
}
@Override
public
String
toString
()
{
return
subject
+
" "
+
adverb
+
" "
+
verb
+
" "
+
adjective
+
" "
+
obj
+
"."
;
}
}
\ No newline at end of file
app/model/GibberishHub.java
0 → 100644
View file @
f8c7d75b
package
model
;
/**
* Created by davidmccormick on 21/08/16.
*/
import
com.fasterxml.jackson.databind.node.ObjectNode
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
/**
* This is a simple publish-subscribe list. It maintains a list of listeners, and whenever it receives a call to
* <code>send</code>, it calls <code>receiveGibberish</code> on every registered listener.
*/
public
class
GibberishHub
{
List
<
GibberishListener
>
listeners
;
static
final
GibberishHub
instance
=
new
GibberishHub
();
public
static
GibberishHub
getInstance
()
{
return
instance
;
}
protected
GibberishHub
()
{
this
.
listeners
=
Collections
.
synchronizedList
(
new
ArrayList
<>());
}
public
void
send
(
ObjectNode
g
)
{
for
(
GibberishListener
listener
:
listeners
)
{
listener
.
receiveGibberish
(
g
);
}
}
public
void
addListener
(
GibberishListener
l
)
{
this
.
listeners
.
add
(
l
);
}
public
void
removeListener
(
GibberishListener
l
)
{
this
.
listeners
.
remove
(
l
);
}
}
\ No newline at end of file
app/model/GibberishListener.java
0 → 100644
View file @
f8c7d75b
package
model
;
import
com.fasterxml.jackson.databind.node.ObjectNode
;
/**
* Created by davidmccormick on 21/08/16.
*/
public
interface
GibberishListener
{
public
void
receiveGibberish
(
ObjectNode
g
);
}
\ No newline at end of file
public/javascript/cbuffer.js
0 → 100644
View file @
f8c7d75b
(
function
(
global
)
{
function
CBuffer
()
{
// handle cases where "new" keyword wasn't used
if
(
!
(
this
instanceof
CBuffer
))
{
// multiple conditions need to be checked to properly emulate Array
if
(
arguments
.
length
>
1
||
typeof
arguments
[
0
]
!==
'
number
'
)
{
return
CBuffer
.
apply
(
new
CBuffer
(
arguments
.
length
),
arguments
);
}
else
{
return
new
CBuffer
(
arguments
[
0
]);
}
}
// if no arguments, then nothing needs to be set
if
(
arguments
.
length
===
0
)
throw
new
Error
(
'
Missing Argument: You must pass a valid buffer size
'
);
// this is the same in either scenario
this
.
length
=
this
.
start
=
0
;
// set to callback fn if data is about to be overwritten
this
.
overflow
=
null
;
// emulate Array based on passed arguments
if
(
arguments
.
length
>
1
||
typeof
arguments
[
0
]
!==
'
number
'
)
{
this
.
data
=
new
Array
(
arguments
.
length
);
this
.
end
=
(
this
.
size
=
arguments
.
length
)
-
1
;
this
.
push
.
apply
(
this
,
arguments
);
}
else
{
this
.
data
=
new
Array
(
arguments
[
0
]);
this
.
end
=
(
this
.
size
=
arguments
[
0
])
-
1
;
}
// need to `return this` so `return CBuffer.apply` works
return
this
;
}
function
defaultComparitor
(
a
,
b
)
{
return
a
==
b
?
0
:
a
>
b
?
1
:
-
1
;
}
CBuffer
.
prototype
=
{
// properly set constructor
constructor
:
CBuffer
,
/* mutator methods */
// pop last item
pop
:
function
()
{
var
item
;
if
(
this
.
length
===
0
)
return
;
item
=
this
.
data
[
this
.
end
];
// remove the reference to the object so it can be garbage collected
delete
this
.
data
[
this
.
end
];
this
.
end
=
(
this
.
end
-
1
+
this
.
size
)
%
this
.
size
;
this
.
length
--
;
return
item
;
},
// push item to the end
push
:
function
()
{
var
i
=
0
;
// check if overflow is set, and if data is about to be overwritten
if
(
this
.
overflow
&&
this
.
length
+
arguments
.
length
>
this
.
size
)
{
// call overflow function and send data that's about to be overwritten
for
(;
i
<
this
.
length
+
arguments
.
length
-
this
.
size
;
i
++
)
{
this
.
overflow
(
this
.
data
[(
this
.
end
+
i
+
1
)
%
this
.
size
],
this
);
}
}
// push items to the end, wrapping and erasing existing items
// using arguments variable directly to reduce gc footprint
for
(
i
=
0
;
i
<
arguments
.
length
;
i
++
)
{
this
.
data
[(
this
.
end
+
i
+
1
)
%
this
.
size
]
=
arguments
[
i
];
}
// recalculate length
if
(
this
.
length
<
this
.
size
)
{
if
(
this
.
length
+
i
>
this
.
size
)
this
.
length
=
this
.
size
;
else
this
.
length
+=
i
;
}
// recalculate end
this
.
end
=
(
this
.
end
+
i
)
%
this
.
size
;
// recalculate start
this
.
start
=
(
this
.
size
+
this
.
end
-
this
.
length
+
1
)
%
this
.
size
;
// return number current number of items in CBuffer
return
this
.
length
;
},
// reverse order of the buffer
reverse
:
function
()
{
var
i
=
0
,
tmp
;
for
(;
i
<
~~
(
this
.
length
/
2
);
i
++
)
{
tmp
=
this
.
data
[(
this
.
start
+
i
)
%
this
.
size
];
this
.
data
[(
this
.
start
+
i
)
%
this
.
size
]
=
this
.
data
[(
this
.
start
+
(
this
.
length
-
i
-
1
))
%
this
.
size
];
this
.
data
[(
this
.
start
+
(
this
.
length
-
i
-
1
))
%
this
.
size
]
=
tmp
;
}
return
this
;
},
// rotate buffer to the left by cntr, or by 1
rotateLeft
:
function
(
cntr
)
{
if
(
typeof
cntr
===
'
undefined
'
)
cntr
=
1
;
if
(
typeof
cntr
!==
'
number
'
)
throw
new
Error
(
"
Argument must be a number
"
);
while
(
--
cntr
>=
0
)
{
this
.
push
(
this
.
shift
());
}
return
this
;
},
// rotate buffer to the right by cntr, or by 1
rotateRight
:
function
(
cntr
)
{
if
(
typeof
cntr
===
'
undefined
'
)
cntr
=
1
;
if
(
typeof
cntr
!==
'
number
'
)
throw
new
Error
(
"
Argument must be a number
"
);
while
(
--
cntr
>=
0
)
{
this
.
unshift
(
this
.
pop
());
}
return
this
;
},
// remove and return first item
shift
:
function
()
{
var
item
;
// check if there are any items in CBuff
if
(
this
.
length
===
0
)
return
;
// store first item for return
item
=
this
.
data
[
this
.
start
];
// recalculate start of CBuffer
this
.
start
=
(
this
.
start
+
1
)
%
this
.
size
;
// decrement length
this
.
length
--
;
return
item
;
},
// sort items
sort
:
function
(
fn
)
{
this
.
data
.
sort
(
fn
||
defaultComparitor
);
this
.
start
=
0
;
this
.
end
=
this
.
length
-
1
;
return
this
;
},
// add item to beginning of buffer
unshift
:
function
()
{
var
i
=
0
;
// check if overflow is set, and if data is about to be overwritten
if
(
this
.
overflow
&&
this
.
length
+
arguments
.
length
>
this
.
size
)
{
// call overflow function and send data that's about to be overwritten
for
(;
i
<
this
.
length
+
arguments
.
length
-
this
.
size
;
i
++
)
{
this
.
overflow
(
this
.
data
[
this
.
end
-
(
i
%
this
.
size
)],
this
);
}
}
for
(
i
=
0
;
i
<
arguments
.
length
;
i
++
)
{
this
.
data
[(
this
.
size
+
this
.
start
-
(
i
%
this
.
size
)
-
1
)
%
this
.
size
]
=
arguments
[
i
];
}
if
(
this
.
size
-
this
.
length
-
i
<
0
)
{
this
.
end
+=
this
.
size
-
this
.
length
-
i
;
if
(
this
.
end
<
0
)
this
.
end
=
this
.
size
+
(
this
.
end
%
this
.
size
);
}
if
(
this
.
length
<
this
.
size
)
{
if
(
this
.
length
+
i
>
this
.
size
)
this
.
length
=
this
.
size
;
else
this
.
length
+=
i
;
}
this
.
start
-=
arguments
.
length
;
if
(
this
.
start
<
0
)
this
.
start
=
this
.
size
+
(
this
.
start
%
this
.
size
);
return
this
.
length
;
},
/* accessor methods */
// return index of first matched element
indexOf
:
function
(
arg
,
idx
)
{
if
(
!
idx
)
idx
=
0
;
for
(;
idx
<
this
.
length
;
idx
++
)
{
if
(
this
.
data
[(
this
.
start
+
idx
)
%
this
.
size
]
===
arg
)
return
idx
;
}
return
-
1
;
},
// return last index of the first match
lastIndexOf
:
function
(
arg
,
idx
)
{
if
(
!
idx
)
idx
=
this
.
length
-
1
;
for
(;
idx
>=
0
;
idx
--
)
{
if
(
this
.
data
[(
this
.
start
+
idx
)
%
this
.
size
]
===
arg
)
return
idx
;
}
return
-
1
;
},
// return the index an item would be inserted to if this
// is a sorted circular buffer
sortedIndex
:
function
(
value
,
comparitor
,
context
)
{
comparitor
=
comparitor
||
defaultComparitor
;
var
isFull
=
this
.
length
===
this
.
size
,
low
=
this
.
start
,
high
=
isFull
?
this
.
length
-
1
:
this
.
length
;
// Tricky part is finding if its before or after the pivot
// we can get this info by checking if the target is less than
// the last item. After that it's just a typical binary search.
if
(
low
&&
comparitor
.
call
(
context
,
value
,
this
.
data
[
high
])
>
0
)
{
low
=
0
,
high
=
this
.
end
;
}
while
(
low
<
high
)
{
var
mid
=
(
low
+
high
)
>>>
1
;
if
(
comparitor
.
call
(
context
,
value
,
this
.
data
[
mid
])
>
0
)
low
=
mid
+
1
;
else
high
=
mid
;
}
return
!
isFull
?
low
:
// http://stackoverflow.com/a/18618273/1517919
(((
low
-
this
.
start
)
%
this
.
length
)
+
this
.
length
)
%
this
.
length
;
},
/* iteration methods */
// check every item in the array against a test
every
:
function
(
callback
,
context
)
{
var
i
=
0
;
for
(;
i
<
this
.
length
;
i
++
)
{
if
(
!
callback
.
call
(
context
,
this
.
data
[(
this
.
start
+
i
)
%
this
.
size
],
i
,
this
))
return
false
;
}
return
true
;
},
// loop through each item in buffer
// TODO: figure out how to emulate Array use better
forEach
:
function
(
callback
,
context
)
{
var
i
=
0
;
for
(;
i
<
this
.
length
;
i
++
)
{
callback
.
call
(
context
,
this
.
data
[(
this
.
start
+
i
)
%
this
.
size
],
i
,
this
);
}
},
// check items agains test until one returns true
// TODO: figure out how to emuldate Array use better
some
:
function
(
callback
,
context
)
{
var
i
=
0
;
for
(;
i
<
this
.
length
;
i
++
)
{
if
(
callback
.
call
(
context
,
this
.
data
[(
this
.
start
+
i
)
%
this
.
size
],
i
,
this
))
return
true
;
}
return
false
;
},
// calculate the average value of a circular buffer
avg
:
function
()
{
return
this
.
length
==
0
?
0
:
(
this
.
sum
()
/
this
.
length
);
},
// loop through each item in buffer and calculate sum
sum
:
function
()
{
var
index
=
this
.
length
;
var
s
=
0
;
while
(
index
--
)
s
+=
this
.
data
[
index
];
return
s
;
},
// loop through each item in buffer and calculate median
median
:
function
()
{
if
(
this
.
length
===
0
)
return
0
;
var
values
=
this
.
slice
().
sort
(
defaultComparitor
);
var
half
=
Math
.
floor
(
values
.
length
/
2
);
if
(
values
.
length
%
2
)
return
values
[
half
];
else
return
(
values
[
half
-
1
]
+
values
[
half
])
/
2.0
;
},
/* utility methods */
// reset pointers to buffer with zero items
// note: this will not remove values in cbuffer, so if for security values
// need to be overwritten, run `.fill(null).empty()`
empty
:
function
()
{
var
i
=
0
;
this
.
length
=
this
.
start
=
0
;
this
.
end
=
this
.
size
-
1
;
return
this
;
},
// fill all places with passed value or function
fill
:
function
(
arg
)
{
var
i
=
0
;
if
(
typeof
arg
===
'
function
'
)
{
while
(
this
.
data
[
i
]
=
arg
(),
++
i
<
this
.
size
);
}
else
{
while
(
this
.
data
[
i
]
=
arg
,
++
i
<
this
.
size
);
}
// reposition start/end
this
.
start
=
0
;
this
.
end
=
this
.
size
-
1
;
this
.
length
=
this
.
size
;
return
this
;
},
// return first item in buffer
first
:
function
()
{
return
this
.
data
[
this
.
start
];
},
// return last item in buffer
last
:
function
()
{
return
this
.
data
[
this
.
end
];
},
// return specific index in buffer
get
:
function
(
arg
)
{
return
this
.
data
[(
this
.
start
+
arg
)
%
this
.
size
];
},
isFull
:
function
(
arg
)
{
return
this
.
size
===
this
.
length
;
},
// set value at specified index
set
:
function
(
idx
,
arg
)
{
return
this
.
data
[(
this
.
start
+
idx
)
%
this
.
size
]
=
arg
;