2020-12-08 11:09:46 +00:00
|
|
|
import net from 'net'
|
|
|
|
import parser from 'p3x-xml2json'
|
2018-06-26 18:35:12 +00:00
|
|
|
|
|
|
|
let io
|
|
|
|
let logger
|
|
|
|
let currentHost
|
2020-12-08 11:09:46 +00:00
|
|
|
let client
|
|
|
|
let db
|
|
|
|
|
|
|
|
let queue = []
|
|
|
|
let reconnectInterval = 1000
|
|
|
|
let isReconnecting = false
|
|
|
|
let connected = false
|
|
|
|
let playing = false
|
|
|
|
let lastError = ''
|
|
|
|
|
|
|
|
function startReconnecting() {
|
|
|
|
connected = false
|
|
|
|
playing = false
|
|
|
|
if (queue.length) {
|
|
|
|
queue.splice(0, queue.length)
|
|
|
|
}
|
|
|
|
if(isReconnecting !== false) return
|
|
|
|
reconnectInterval = Math.min(reconnectInterval * 1.5, 1000 * 60 * 5)
|
|
|
|
isReconnecting = setTimeout(connect, reconnectInterval)
|
|
|
|
}
|
|
|
|
|
|
|
|
function clearReconnect() {
|
|
|
|
if(isReconnecting === false) return
|
|
|
|
clearTimeout(isReconnecting)
|
|
|
|
isReconnecting = false
|
|
|
|
}
|
|
|
|
|
|
|
|
export function queueCommand(command) {
|
|
|
|
return new Promise((res, rej) => {
|
|
|
|
if (isReconnecting) {
|
|
|
|
return rej(new Error('CasparCG is not connected, unable to play command'))
|
|
|
|
}
|
|
|
|
let request = {
|
|
|
|
command: command,
|
|
|
|
res: res,
|
|
|
|
rej: rej,
|
|
|
|
started: new Date(),
|
|
|
|
finished: null,
|
|
|
|
timeout: null,
|
|
|
|
}
|
|
|
|
queue.push(request)
|
|
|
|
|
|
|
|
request.timeout = setTimeout(function() {
|
|
|
|
if (request.finished) return
|
|
|
|
queue.splice(queue.indexOf(request), 1)
|
|
|
|
rej(new Error(`CasparCGCommand "${command}" timed out after 15 seconds`))
|
|
|
|
}, 15000)
|
|
|
|
|
|
|
|
logger.info('CasparCG Command:', command)
|
|
|
|
client.write(command + '\r\n')
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function checkPlaying(db, io, wasSuccess) {
|
|
|
|
if (!connected) return
|
|
|
|
let path = `http://${db.get('settings.casparplayhost').value()}/client.html`
|
|
|
|
|
|
|
|
try {
|
|
|
|
logger.info('CasparCG: Checking if already playing')
|
|
|
|
let res = await queueCommand('INFO 1-100')
|
|
|
|
if (res.body.channel
|
|
|
|
&& res.body.channel.stage
|
|
|
|
&& res.body.channel.stage.layer
|
|
|
|
&& res.body.channel.stage.layer.layer_100
|
|
|
|
&& res.body.channel.stage.layer.layer_100.foreground
|
|
|
|
&& res.body.channel.stage.layer.layer_100.foreground.file
|
|
|
|
&& res.body.channel.stage.layer.layer_100.foreground.file.path === path) {
|
|
|
|
logger.info('CasparCG: Player is playing')
|
|
|
|
playing = true
|
|
|
|
lastError = ''
|
|
|
|
io.emit('casparcg.status', currentStatus())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if (wasSuccess) {
|
|
|
|
logger.warn(res.body, 'CasparCG: Playing was marked as succeeded but could not verify it')
|
|
|
|
playing = true
|
|
|
|
lastError = 'Sending play command succeeded but was unable to verify'
|
|
|
|
io.emit('casparcg.status', currentStatus())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
playing = false
|
|
|
|
lastError = 'Sending play command'
|
|
|
|
io.emit('casparcg.status', currentStatus())
|
|
|
|
logger.info(res.body, 'CasparCG: Sending play command')
|
|
|
|
res = await queueCommand(`PLAY 1-100 [HTML] "${path}" CUT 1 LINEAR RIGHT`)
|
|
|
|
return setTimeout(function() {
|
|
|
|
checkPlaying(db, io, true).then()
|
|
|
|
}, 300)
|
|
|
|
} catch (err) {
|
|
|
|
playing = false
|
|
|
|
lastError = `CasparCG: Error checking if playing: ${err.message}. Checking again in 5seconds`
|
|
|
|
logger.error(err, 'CasparCG: Error checking if playing')
|
|
|
|
io.emit('casparcg.status', currentStatus())
|
|
|
|
}
|
2018-06-26 18:35:12 +00:00
|
|
|
|
2020-12-08 11:09:46 +00:00
|
|
|
return setTimeout(function() {
|
|
|
|
checkPlaying(db, io, false).then()
|
|
|
|
}, 5000)
|
|
|
|
}
|
|
|
|
|
|
|
|
export function initialise(log, database, ioOrg) {
|
|
|
|
io = ioOrg
|
2018-06-26 18:35:12 +00:00
|
|
|
logger = log
|
2020-12-08 11:09:46 +00:00
|
|
|
db = database
|
|
|
|
|
|
|
|
client = new net.Socket()
|
|
|
|
client.setEncoding('utf8')
|
|
|
|
|
|
|
|
client.on('connect', function () {
|
|
|
|
clearReconnect()
|
|
|
|
connected = true
|
|
|
|
lastError = ''
|
|
|
|
reconnectInterval = 1000
|
|
|
|
logger.info('CasparCG: Connected to server')
|
|
|
|
io.emit('casparcg.status', currentStatus())
|
|
|
|
checkPlaying(db, io, false).then()
|
|
|
|
// client.write('INFO 1-100\r\n');
|
|
|
|
})
|
|
|
|
|
|
|
|
client.on('data', function (data) {
|
|
|
|
let request = null
|
|
|
|
|
|
|
|
if (queue.length > 0) {
|
|
|
|
request = queue[0]
|
|
|
|
queue.splice(0, 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!request) {
|
|
|
|
return logger.warn({ data }, 'Received unknown response with no command')
|
|
|
|
}
|
|
|
|
|
|
|
|
let status
|
|
|
|
let splitted
|
|
|
|
let header
|
|
|
|
let body
|
|
|
|
let parsed
|
|
|
|
|
|
|
|
try {
|
|
|
|
splitted = data.split('\n')
|
|
|
|
header = splitted[0].replace('\r', '')
|
|
|
|
status = Number(header.split(' ')[0])
|
|
|
|
body = splitted.slice(1)
|
|
|
|
parsed = JSON.parse(parser.toJson(body.join('\n')))
|
|
|
|
} catch (err) {
|
|
|
|
return request.rej(err)
|
|
|
|
}
|
2018-06-26 18:35:12 +00:00
|
|
|
|
2020-12-08 11:09:46 +00:00
|
|
|
request.finished = new Date()
|
|
|
|
clearTimeout(request.timeout)
|
|
|
|
if (status && status < 300) {
|
|
|
|
request.res({
|
|
|
|
status: status,
|
|
|
|
header: header,
|
|
|
|
body: parsed || {},
|
|
|
|
raw: data
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
request.err({
|
|
|
|
status: status,
|
|
|
|
header: header,
|
|
|
|
body: parsed || {},
|
|
|
|
raw: data
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
client.on('error', function (err) {
|
|
|
|
lastError = 'CasparCG TCP Error: ' + err.code + ', retrying in ' + Math.round(reconnectInterval / 1000) + ' sec'
|
|
|
|
logger.warn(lastError)
|
|
|
|
io.emit('casparcg.status', currentStatus())
|
|
|
|
startReconnecting()
|
|
|
|
})
|
|
|
|
client.on('close', function() {
|
|
|
|
startReconnecting()
|
|
|
|
})
|
|
|
|
client.on('end', function() {
|
|
|
|
startReconnecting()
|
|
|
|
})
|
|
|
|
|
|
|
|
connect()
|
2018-06-26 18:35:12 +00:00
|
|
|
}
|
|
|
|
|
2020-12-08 11:09:46 +00:00
|
|
|
export function connect() {
|
|
|
|
clearReconnect()
|
2020-04-06 22:47:58 +00:00
|
|
|
currentHost = db.get('settings').value().casparhost
|
2020-12-08 11:09:46 +00:00
|
|
|
lastError = 'CasparCG: Connecting to ' + currentHost + ':' + 5250
|
|
|
|
logger.info(lastError)
|
|
|
|
io.emit('casparcg.status', currentStatus())
|
2018-06-26 18:35:12 +00:00
|
|
|
|
2020-12-08 11:09:46 +00:00
|
|
|
client.connect({
|
2018-06-26 18:35:12 +00:00
|
|
|
port: 5250,
|
2020-12-08 11:09:46 +00:00
|
|
|
host: currentHost
|
2018-06-26 18:35:12 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
export function currentStatus(e) {
|
|
|
|
return {
|
2020-12-08 11:09:46 +00:00
|
|
|
connected: connected,
|
|
|
|
playing: playing,
|
|
|
|
error: lastError,
|
2018-06-26 18:35:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-08 11:09:46 +00:00
|
|
|
export function sendCommand(command) {
|
|
|
|
return new Promise(function(res, rej) {
|
|
|
|
|
|
|
|
})
|
|
|
|
}
|
|
|
|
/*
|
2020-04-06 22:47:58 +00:00
|
|
|
export async function startPlaying(db) {
|
|
|
|
let ip = db.get('settings').value().casparplayhost
|
2018-06-26 18:35:12 +00:00
|
|
|
|
|
|
|
// Check if we lost connection while attempting to start playing
|
|
|
|
if (!connection.connected) {
|
|
|
|
logger.error('CasparCG: Attempted to play but connection was lost')
|
|
|
|
}
|
|
|
|
|
2020-04-05 05:12:55 +00:00
|
|
|
let success = false
|
2018-06-26 18:35:12 +00:00
|
|
|
|
2020-04-05 05:12:55 +00:00
|
|
|
try {
|
|
|
|
// Send a play command
|
2020-04-06 22:47:58 +00:00
|
|
|
let command = `PLAY 1-100 [HTML] "http://${ip}/client.html" CUT 1 LINEAR RIGHT`
|
2020-04-05 05:12:55 +00:00
|
|
|
logger.info(`CasparCG Command: ${command}`)
|
|
|
|
await connection.do(new AMCP.CustomCommand(command))
|
|
|
|
success = true
|
|
|
|
} catch (e) {
|
|
|
|
// Weird error where it throws an error despite a successful play command on reconnect
|
|
|
|
if (e && e.responseProtocol && e.responseProtocol.code >= 200 && e.responseProtocol.code < 300) {
|
|
|
|
success = true
|
|
|
|
} else {
|
|
|
|
logger.error(e, 'CasparCG: Error starting play on client')
|
2018-06-26 18:35:12 +00:00
|
|
|
}
|
2020-04-05 05:12:55 +00:00
|
|
|
}
|
2018-06-26 18:35:12 +00:00
|
|
|
|
2020-04-05 05:12:55 +00:00
|
|
|
if (success) {
|
2018-06-26 18:35:12 +00:00
|
|
|
casparIsPlaying = true
|
|
|
|
|
|
|
|
// We are playing, notify all clients
|
|
|
|
io.emit('casparcg.status', currentStatus())
|
2020-04-05 05:12:55 +00:00
|
|
|
logger.info('CasparCG: client is up and playing')
|
2020-04-06 22:47:58 +00:00
|
|
|
/* console.log(connection)
|
2020-12-08 11:09:46 +00:00
|
|
|
for (let key in connection) {
|
2020-04-06 22:47:58 +00:00
|
|
|
console.log(key, '=', typeof(connection[key]))
|
2020-12-08 11:09:46 +00:00
|
|
|
}
|
2020-04-06 22:47:58 +00:00
|
|
|
connection.autoConnect = false
|
|
|
|
// connection.close()
|
2020-04-05 05:12:55 +00:00
|
|
|
} else {
|
2018-06-26 18:35:12 +00:00
|
|
|
// Unknown error occured
|
2020-04-05 05:12:55 +00:00
|
|
|
casparIsPlaying = false
|
2018-06-26 18:35:12 +00:00
|
|
|
io.emit('casparcg.status', currentStatus(e))
|
|
|
|
}
|
2020-12-08 11:09:46 +00:00
|
|
|
}*/
|