parent
1afe462c0b
commit
eba441b624
|
@ -613,6 +613,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||||
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
|
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
|
||||||
},
|
},
|
||||||
|
"dirty": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dirty/-/dirty-1.1.0.tgz",
|
||||||
|
"integrity": "sha1-cO3SuZlUHcmXT9Ooy9DGcP4jYHg="
|
||||||
|
},
|
||||||
"ee-first": {
|
"ee-first": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "satyr",
|
"name": "satyr",
|
||||||
"version": "0.2.0",
|
"version": "0.3.0",
|
||||||
"description": "A livestreaming server.",
|
"description": "A livestreaming server.",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"author": "knotteye",
|
"author": "knotteye",
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
"bcrypt": "^3.0.6",
|
"bcrypt": "^3.0.6",
|
||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.19.0",
|
||||||
"config": "^3.2.2",
|
"config": "^3.2.2",
|
||||||
|
"dirty": "^1.1.0",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"flags": "^0.1.3",
|
"flags": "^0.1.3",
|
||||||
"mysql": "^2.17.1",
|
"mysql": "^2.17.1",
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
84
src/http.ts
84
src/http.ts
|
@ -4,18 +4,21 @@ import * as bodyparser from "body-parser";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import * as socketio from "socket.io";
|
import * as socketio from "socket.io";
|
||||||
import * as http from "http";
|
import * as http from "http";
|
||||||
|
import * as dirty from "dirty";
|
||||||
import * as api from "./api";
|
import * as api from "./api";
|
||||||
import * as db from "./database";
|
import * as db from "./database";
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const server = http.createServer(app);
|
const server = http.createServer(app);
|
||||||
const io = socketio(server);
|
const io = socketio(server);
|
||||||
|
const store = dirty();
|
||||||
var njkconf;
|
var njkconf;
|
||||||
|
|
||||||
function init(satyr: any, port: number){
|
function init(satyr: any, port: number){
|
||||||
njk.configure('templates', {
|
njk.configure('templates', {
|
||||||
autoescape: true,
|
autoescape: true,
|
||||||
express : app,
|
express : app,
|
||||||
|
watch: true
|
||||||
});
|
});
|
||||||
njkconf ={
|
njkconf ={
|
||||||
sitename: satyr.name,
|
sitename: satyr.name,
|
||||||
|
@ -83,6 +86,9 @@ function init(satyr: any, port: number){
|
||||||
app.get('/changesk', (req, res) => {
|
app.get('/changesk', (req, res) => {
|
||||||
res.render('changesk.njk', njkconf);
|
res.render('changesk.njk', njkconf);
|
||||||
});
|
});
|
||||||
|
app.get('/chat', (req, res) => {
|
||||||
|
res.render('chat.html', njkconf);
|
||||||
|
});
|
||||||
//api handlers
|
//api handlers
|
||||||
app.post('/api/register', (req, res) => {
|
app.post('/api/register', (req, res) => {
|
||||||
api.register(req.body.username, req.body.password, req.body.confirm).then( (result) => {
|
api.register(req.body.username, req.body.password, req.body.confirm).then( (result) => {
|
||||||
|
@ -111,10 +117,84 @@ function init(satyr: any, port: number){
|
||||||
res.status(404).render('404.njk', njkconf);
|
res.status(404).render('404.njk', njkconf);
|
||||||
});
|
});
|
||||||
//socket.io chat logic
|
//socket.io chat logic
|
||||||
io.on('connection', (socket) => {
|
io.on('connection', async (socket) => {
|
||||||
|
socket.nick = await newNick(socket);
|
||||||
|
socket.on('JOINROOM', async (data) => {
|
||||||
|
let t: any = await db.query('select username from users where username='+db.raw.escape(data));
|
||||||
|
if(t[0]){
|
||||||
|
socket.join(data);
|
||||||
|
io.to(data).emit('JOINED', {nick: socket.nick});
|
||||||
|
}
|
||||||
|
else socket.emit('ALERT', 'Room does not exist');
|
||||||
|
});
|
||||||
|
socket.on('LEAVEROOM', (data) => {
|
||||||
|
socket.leave(data);
|
||||||
|
io.to(data).emit('LEFT', {nick: socket.nick});
|
||||||
|
});
|
||||||
|
socket.on('disconnecting', (reason) => {
|
||||||
|
let rooms = Object.keys(socket.rooms);
|
||||||
|
for(let i=1;i<rooms.length;i++){
|
||||||
|
io.to(rooms[i]).emit('ALERT', socket.nick+' disconnected');
|
||||||
|
}
|
||||||
|
store.rm(socket.nick);
|
||||||
|
});
|
||||||
|
socket.on('NICK', async (data) => {
|
||||||
|
data.nick = data.nick.replace(' ','');
|
||||||
|
if(store.get(data.nick)){
|
||||||
|
socket.emit('ALERT', 'Nickname is already in use');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let user = await db.query('select username from users where username='+db.raw.escape(data.nick));
|
||||||
|
if(user[0]){
|
||||||
|
if(!data.password){
|
||||||
|
socket.emit('ALERT','Incorrect username or password');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(await db.validatePassword(data.nick, data.password)){
|
||||||
|
chgNick(socket, data.nick);
|
||||||
|
}
|
||||||
|
else socket.emit('ALERT','Incorrect username or password');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
chgNick(socket, data.nick);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
socket.on('MSG', (data) => {
|
||||||
|
io.to(data.room).emit('MSG', {nick: socket.nick, msg: data.msg});
|
||||||
|
});
|
||||||
|
socket.on('KICK', (data) => {
|
||||||
|
if(socket.nick === data.room){
|
||||||
|
//find client with data.nick
|
||||||
|
let id: string = store.get(data.nick);
|
||||||
|
if(id){
|
||||||
|
let target = io.sockets.connected[id];
|
||||||
|
io.in(data.room).emit('ALERT', data.nick+' has been kicked.');
|
||||||
|
target.disconnect(true);
|
||||||
|
}
|
||||||
|
else socket.emit('ALERT', 'No such user found.');
|
||||||
|
}
|
||||||
|
else socket.emit('ALERT', 'Not authorized to do that.');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
server.listen(port);
|
server.listen(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function newNick(socket) {
|
||||||
|
let n: string = 'Guest'+Math.floor(Math.random() * Math.floor(100));
|
||||||
|
if(store.get(n)) return newNick(socket);
|
||||||
|
else {
|
||||||
|
store.set(n, socket.id);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function chgNick(socket, nick) {
|
||||||
|
let rooms = Object.keys(socket.rooms);
|
||||||
|
for(let i=1;i<rooms.length;i++){
|
||||||
|
io.to(rooms[i]).emit('ALERT', socket.nick+' is now known as '+nick);
|
||||||
|
}
|
||||||
|
store.rm(socket.nick);
|
||||||
|
store.set(nick, socket.id);
|
||||||
|
socket.nick = nick;
|
||||||
|
}
|
||||||
|
|
||||||
export { init };
|
export { init };
|
|
@ -8,7 +8,7 @@
|
||||||
<body>
|
<body>
|
||||||
<div id="wrapper">
|
<div id="wrapper">
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<span style="float:left;"><h4><a href="/">{{ sitename }}</a> | <a href="/users">Users</a> <a href="/users/live">Live</a> <a href="/about">About</a></h4></span><span style="float:right;"><h4>| <a href="/profile">Profile</a></h4></span>
|
<span style="float:left;"><h4><a href="/">{{ sitename }}</a> | <a href="/users">Users</a> <a href="/users/live">Live</a> <a href="/about">About</a></h4></span><span style="float:right;"><h4><a href="/chat">Chat</a> | <a href="/profile">Profile</a></h4></span>
|
||||||
</div>
|
</div>
|
||||||
<div id="content">
|
<div id="content">
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
<!doctype html>
|
||||||
|
<head>
|
||||||
|
<title>{{ sitename }} Webchat</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/styles.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="/local.css">
|
||||||
|
<style>
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
#wrapper {border: 3px solid black; display: inline-block; width: 100%; height: 100%;}
|
||||||
|
body { font: 13px; background: white; height: 100%; color: black; }
|
||||||
|
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
|
||||||
|
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; color: black; background: white; }
|
||||||
|
form button { width: 9%; background: #074115; border: none; padding: 10px; color: #074115;}
|
||||||
|
#messages { list-style-type: none; margin: 0; padding: 0; }
|
||||||
|
#messages li { padding: 5px 10px; }
|
||||||
|
</style>
|
||||||
|
<script src="/socket.io/socket.io.js"></script>
|
||||||
|
<script>
|
||||||
|
var socket = io();
|
||||||
|
var room;
|
||||||
|
function send(){
|
||||||
|
let m = document.getElementById('m').value;
|
||||||
|
if(m.startsWith('/nick')){
|
||||||
|
socket.emit('NICK', {
|
||||||
|
nick: m.split(' ')[1],
|
||||||
|
password: m.split(' ')[2]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if(m.startsWith('/join')){
|
||||||
|
socket.emit('LEAVEROOM', room);
|
||||||
|
socket.emit('JOINROOM', m.split(' ')[1]);
|
||||||
|
room = m.split(' ')[1];
|
||||||
|
}
|
||||||
|
else if(m.startsWith('/kick')){
|
||||||
|
socket.emit('KICK', {nick: m.split(' ')[1], room: room});
|
||||||
|
}
|
||||||
|
else socket.emit('MSG', {room: room, msg: m});
|
||||||
|
document.getElementById('m').value = '';
|
||||||
|
}
|
||||||
|
socket.on('MSG', function(data){
|
||||||
|
document.getElementById('messages').innerHTML+='<li><b>'+data.nick+':</b> '+data.msg+'</span></li>';
|
||||||
|
window.scrollTo(0,document.body.scrollHeight);
|
||||||
|
});
|
||||||
|
socket.on('ALERT', function(data){
|
||||||
|
document.getElementById('messages').innerHTML+='<li><i>'+data+'</i></li>';
|
||||||
|
window.scrollTo(0,document.body.scrollHeight);
|
||||||
|
});
|
||||||
|
socket.on('JOINED', function(data){
|
||||||
|
document.getElementById('messages').innerHTML+='<li><i>'+data.nick+' has joined the chat</i></li>';
|
||||||
|
window.scrollTo(0,document.body.scrollHeight);
|
||||||
|
});
|
||||||
|
socket.on('LEFT', function(data){
|
||||||
|
document.getElementById('messages').innerHTML+='<li><i>'+data.nick+' has left the chat</i></li>';
|
||||||
|
window.scrollTo(0,document.body.scrollHeight);
|
||||||
|
});
|
||||||
|
function getUrlParameter(name) {
|
||||||
|
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
|
||||||
|
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
|
||||||
|
var results = regex.exec(location.search);
|
||||||
|
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
|
||||||
|
};
|
||||||
|
socket.once('connect', () => {
|
||||||
|
iname = getUrlParameter('nick');
|
||||||
|
iroom = getUrlParameter('room');
|
||||||
|
if(iname !== '') socket.emit('NICK', {nick: iname});
|
||||||
|
if(iroom !== '') {
|
||||||
|
socket.emit('JOINROOM', iroom);
|
||||||
|
room = iroom;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="wrapper">
|
||||||
|
<ul id="messages"></ul><li> </li><li> </li>
|
||||||
|
</div>
|
||||||
|
<form id="f" action="" onSubmit="send(); return false">
|
||||||
|
<input id="m" autocomplete="off" /><button><img src="/send.png" alt="send" width="15px" style="display: inline-block;"></img></button>
|
||||||
|
</form>
|
||||||
|
</body>
|
|
@ -1,13 +1,19 @@
|
||||||
{% extends "base.njk" %}
|
{% extends "base.njk" %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<script>
|
||||||
|
function newPopup(url) {
|
||||||
|
popupWindow = window.open(
|
||||||
|
url,'popUpWindow','height=700,width=450,scrollbars=yes,toolbar=no,menubar=no,location=no,directories=no,status=yes')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</br>
|
</br>
|
||||||
<span style="float: left;font-size: large;"><a href="rtmp://{{ domain }}/live{{ user }}">{{ user }}</a> | {{ streamtitle | escape }}</b></span><span style="float: right;font-size: large;"> Links | <a href="/vods/{{ user }}">VODs</a></span>
|
<span style="float: left;font-size: large;"><a href="/live/{{ user }}/index.m3u8">{{ user }}</a> | {{ streamtitle | escape }}</b></span><span style="float: right;font-size: large;"> Links | <a href="rtmp://{{ domain }}/live/{{ user }}">Watch</a> <a href="JavaScript:newPopup('/chat?room={{ user }}');">Chat</a> <a href="/vods/{{ user }}">VODs</a></span>
|
||||||
<div id="jscontainer">
|
<div id="jscontainer">
|
||||||
<div id="jschild" style="width: 70%;height: 100%;">
|
<div id="jschild" style="width: 70%;height: 100%;">
|
||||||
<video controls poster="/thumbnail.jpg" class="video-js vjs-default-skin" id="live-video" style="width:100%;height:100%;"></video>
|
<video controls poster="/thumbnail.jpg" class="video-js vjs-default-skin" id="live-video" style="width:100%;height:100%;"></video>
|
||||||
</div>
|
</div>
|
||||||
<div id="jschild" style="width: 30%;height: 100%;">
|
<div id="jschild" class="webchat" style="width: 30%;height: 100%;">
|
||||||
<img src="/chat.jpg" style="width: 100%;height: 100%" />
|
<iframe src="/chat?room={{ user }}" frameborder="0" style="width: 100%;height: 100%;"></iframe>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>window.HELP_IMPROVE_VIDEOJS = false;</script>
|
<script>window.HELP_IMPROVE_VIDEOJS = false;</script>
|
||||||
|
|
Reference in New Issue