Skip to content

Instantly share code, notes, and snippets.

@masterpoppy
Last active December 4, 2016 10:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save masterpoppy/88612afd78add9853e95fc94070a50ea to your computer and use it in GitHub Desktop.
Save masterpoppy/88612afd78add9853e95fc94070a50ea to your computer and use it in GitHub Desktop.
//***********************
//Sample Chat App
//2016-12-04 MasterPoppy
//***********************
string html = "<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<title>Sample Chat App</title>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.4/semantic.min.js'></script>
<link rel='stylesheet' type='text/css' href='https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.4/semantic.min.css' />
<style type='text/css'>
@import url(http://fonts.googleapis.com/earlyaccess/notosansjp.css);
.ui,
.item,
input {
font-family: 'Noto Sans JP', helvetica, sans-serif;
}
.ui,
.item,
.ui.header,
.ui.table {
font-size: 1.1rem;
line-height: 1.5rem;
}
.ui.container {
padding-top: 1vh;
width: calc(100% - 16px);
}
.ui.middle.attached.segment {
height: calc(100vh - 165px);
overflow-y: auto;
}
</style>
</head>
<body>
<div id='main' class='ui container'>
<div id='id-header' class='ui top attached block header'>
Sample Chat App
</div>
<div class='ui middle attached menu'>
<div id='id-ch' class='item'>
通信チャンネル xxx
</div>
<div class='menu'>
<div id='username' class='item'><i class='user icon'></i>USRNAME</div>
</div>
<div class='right menu'>
<a id='id-logout' class='item'>LOGOUT</a>
</div>
</div>
<div id='log' class='ui middle attached segment'>
<table class='ui celled padded table'>
</table>
</div>
<div class='ui bottom attached segment'>
<div class='ui fluid action input'>
<input id='id-input' type='text' placeholder='・・・'>
<div id='id-enter' class='ui button'>ENTER</div>
</div>
</div>
</div>
<script>
$(document).ready(function() {
$.ajax({
'type': 'POST',
'url': location.href,
'dataType': 'json',
'data': 'init',
'timeout': 0
}).done(function(data) {
$('#id-ch').text('通信チャンネル ' + data.channel);
$('#username').html('<i></i>' + data.name).children().addClass('user icon');
log(data.timestamp, 'システムログ', 'チャンネル ' + data.channel + ' で開始しました。 チャンネルは ObjectDesc で変更できます。', 1);
getchat();
}).fail(function(data) {
end = new Date();
log(gettimestamp(), 'ERROR(0)', data.statusText, 2);
});
}, false);
function getchat() {
$.ajax({
'type': 'POST',
'url': location.href,
'dataType': 'json',
'data': 'getchat',
'timeout': 0
}).done(function(data) {
log(data.timestamp, data.name, data.body);
scrollbottom();
getchat();
}).fail(function(data) {
if (data.status == 504) {
getchat();
} else {
end = new Date();
log(gettimestamp(), 'ERROR(1)', data.statusText, 2);
}
});
}
$('.ui.button').on('click', function() {
var speech = $('#id-input').val();
if (speech !== '') {
$('#id-input').val('');
$.ajax({
'type': 'POST',
'url': location.href,
'dataType': 'json',
'data': JSON.stringify({
'speech': speech
})
}).done(function(data) {
log(data.timestamp, data.name, data.body);
scrollbottom();
}).fail(function(data) {
log(gettimestamp(), 'ERROR(2)', data.statusText, 2);
scrollbottom();
});
}
});
$('#id-input').on('keydown', function(e) {
if (e.keyCode === 13) {
$('#id-enter').trigger('click');
}
});
$('#id-logout').on('click', function() {
$.ajax({
'type': 'POST',
'url': location.href,
'data': 'logout'
});
});
function gettimestamp() {
var d = new Date();
var hour = (d.getHours() < 10) ? '0' + d.getHours() : d.getHours();
var min = (d.getMinutes() < 10) ? '0' + d.getMinutes() : d.getMinutes();
var sec = (d.getSeconds() < 10) ? '0' + d.getSeconds() : d.getSeconds();
return (hour + ':' + min + ':' + sec);
}
function log(a, b, c, d) {
$('table').append(
$('<tr></tr>')
.append($('<td></td>').text(a).addClass('left top aligned single line one wide'))
.append($('<td></td>').text(b).addClass('left top aligned single line one wide'))
.append($('<td></td>').text(c).addClass('left top aligned'))
);
if (d == 1) {
$('table tr:last').addClass('positive');
} else if (d == 2) {
$('table tr:last').addClass('error');
}
}
function scrollbottom() {
$('#log').scrollTop($('#log').scrollTop() + $('#log').height());
}
</script>
</body>
</html>";
integer i;
integer line;
key query_id;
vector scale;
integer status;
key request;
key client;
string URI;
integer handle;
integer ch = 100;
integer render_face = 4; //-X
float HUD_scale = 0.85;
check_memory()
{
float freememory = llGetFreeMemory()/1024.0;
llOwnerSay("freememory = " + (string)freememory+" / 64 kbyte");
}
string ConvertWallclockToTime()
{
integer now = (integer)llGetWallclock();
integer seconds = now % 60;
integer minutes = (now / 60) % 60;
integer hours = now / 3600;
return llGetSubString("0" + (string)hours, -2, -1) + ":"
+ llGetSubString("0" + (string)minutes, -2, -1) + ":"
+ llGetSubString("0" + (string)seconds, -2, -1);
}
default
{
state_entry()
{
llReleaseURL(URI);
request = llRequestURL();
check_memory();
}
changed(integer change)
{
if(change & CHANGED_REGION || change & CHANGED_REGION_START){
llReleaseURL(URI);
request = llRequestURL();
}
else if(change & CHANGED_SCALE){
scale = llGetScale();
status = llSetLinkMedia(LINK_THIS, render_face, [
PRIM_MEDIA_AUTO_SCALE, FALSE,
PRIM_MEDIA_WIDTH_PIXELS, 1024.0 * scale.y / HUD_scale,
PRIM_MEDIA_HEIGHT_PIXELS, 1024.0 * scale.z / HUD_scale,
PRIM_MEDIA_PERMS_INTERACT, PRIM_MEDIA_PERM_NONE,
PRIM_MEDIA_PERMS_CONTROL, PRIM_MEDIA_PERM_NONE
]);
}
}
on_rez(integer start_param)
{
llReleaseURL(URI);
request = llRequestURL();
}
attach(key id)
{
if(id){
llReleaseURL(URI);
request = llRequestURL();
}
}
http_request(key id, string method, string body)
{
key owner = llGetOwner();
vector ownerSize = llGetAgentSize(owner);
string useragent = llGetHTTPHeader(id, "user-agent");
if (request == id){
request = "";
if (method == URL_REQUEST_GRANTED){
URI = body;
scale = llGetScale();
llClearPrimMedia(render_face);
status = llSetLinkMedia(LINK_THIS, render_face, [
PRIM_MEDIA_HOME_URL, URI,
PRIM_MEDIA_CURRENT_URL, URI,
PRIM_MEDIA_AUTO_ZOOM, FALSE,
PRIM_MEDIA_AUTO_PLAY, TRUE,
PRIM_MEDIA_AUTO_SCALE, FALSE,
PRIM_MEDIA_WIDTH_PIXELS, 1024.0 * scale.y / HUD_scale,
PRIM_MEDIA_HEIGHT_PIXELS, 1024.0 * scale.z / HUD_scale,
PRIM_MEDIA_PERMS_INTERACT, PRIM_MEDIA_PERM_NONE,
PRIM_MEDIA_PERMS_CONTROL, PRIM_MEDIA_PERM_NONE
]);
}
else if (method == URL_REQUEST_DENIED){
llOwnerSay("Something went wrong, no url:\n" + body);
}
}
else{
if(method == "GET"){
llSetContentType(id, CONTENT_TYPE_HTML);
llHTTPResponse(id, 200, html);
}
else if(method == "POST"){
if(body == "init"){
ch = (integer)llGetObjectDesc();
if(ch == 0){
ch = 100;
}
llListenRemove(handle);
llListen(ch, "", NULL_KEY, "");
llSetContentType(id, CONTENT_TYPE_JSON);
llHTTPResponse(id, 200, llList2Json(JSON_OBJECT, [
"name",llGetDisplayName(llGetOwner()),
"timestamp",ConvertWallclockToTime(),
"channel",ch
]));
}
else if(body == "getchat"){
//グローバル変数にhttp requestのIDを保持する(*)
query_id = id;
}
else if(body == "logout"){
if(llGetAttached()){
llRequestPermissions(llGetOwner(), PERMISSION_ATTACH );
}
}
else{
string var = llJsonGetValue(body, ["speech"]);
if(var != JSON_INVALID){
//通信チャンネル向けにRegionSay
llRegionSay(ch, var);
//CEFにResponse
llHTTPResponse(id, 200, llList2Json(JSON_OBJECT, [
"name",llGetDisplayName(llGetOwner()),
"timestamp",ConvertWallclockToTime(),
"body",var
]));
}
}
}
}
}
listen(integer channel, string name, key id, string message)
{
if(query_id != NULL_KEY){
llSetContentType(query_id, CONTENT_TYPE_JSON);
if(ch == 0){
name = llGetDisplayName(id);
}
else{
name = llGetDisplayName(llGetOwnerKey(id));
}
if(name != ""){
//保持しておいたHTTP requestのID向けにResponseする(*)
llHTTPResponse(query_id, 200, llList2Json(JSON_OBJECT, [
"name",name,
"timestamp",ConvertWallclockToTime(),
"body",message
]));
}
}
}
run_time_permissions(integer perm)
{
if(perm & PERMISSION_ATTACH){
llDetachFromAvatar( );
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment