mirror of https://github.com/icedream/ts3bot.git
233 lines
6.4 KiB
CoffeeScript
233 lines
6.4 KiB
CoffeeScript
sqlite3 = require("sqlite3") #.verbose()
|
|
SQLite3Database = sqlite3.Database
|
|
path = require "path"
|
|
mkdirp = require "mkdirp"
|
|
SimpleIni = require "simple-ini"
|
|
fs = require "fs"
|
|
merge = require "merge"
|
|
getLogger = require "./logger"
|
|
|
|
# some properties sugar from http://bl.ocks.org/joyrexus/65cb3780a24ecd50f6df
|
|
Function::getter = (prop, get) ->
|
|
Object.defineProperty @prototype, prop, {get, configurable: yes}
|
|
Function::setter = (prop, set) ->
|
|
Object.defineProperty @prototype, prop, {set, configurable: yes}
|
|
|
|
module.exports = class SettingsFile
|
|
db: null
|
|
identities: null
|
|
defaultIdentity: null
|
|
|
|
constructor: (@configPath) ->
|
|
@log = getLogger "TS3Settings"
|
|
|
|
try
|
|
mkdirp.sync @configPath
|
|
catch err
|
|
throw new Error "Could not create TS3 config directory."
|
|
|
|
@getter "isInitialized", -> () => fs.existsSync(path.join(@configPath, "settings.db")) and fs.existsSync(path.join(@configPath, "ts3clientui_qt.secrets.conf"))
|
|
@getter "isReady", -> () => @db != null
|
|
|
|
open: (cb) =>
|
|
# settings database
|
|
@db = new SQLite3Database path.join(@configPath, "settings.db")
|
|
await @db.serialize defer()
|
|
await @query "CREATE TABLE IF NOT EXISTS TS3Tables (key varchar NOT NULL UNIQUE,timestamp integer unsigned NOT NULL)", defer()
|
|
|
|
# secrets file
|
|
@identities = []
|
|
@defaultIdentity = null
|
|
secretsPath = path.join(@configPath, "ts3clientui_qt.secrets.conf")
|
|
if fs.existsSync(secretsPath)
|
|
secrets = new SimpleIni (() => fs.readFileSync(secretsPath, "utf-8")),
|
|
quotedValues: false
|
|
for i in [1 .. secrets.Identities.size]
|
|
@identities.push
|
|
id: secrets.Identities["#{i}/id"]
|
|
identity: secrets.Identities["#{i}/identity"]
|
|
nickname: secrets.Identities["#{i}/nickname"]
|
|
@defaultIdentity = secrets.Identities.SelectedIdentity
|
|
cb?()
|
|
|
|
close: (cb) =>
|
|
if not @isReady
|
|
@log.warn "Tried to close TS3 settings when already closed"
|
|
return
|
|
|
|
await @db.close defer()
|
|
|
|
# Build secrets INI structure
|
|
secrets = new SimpleIni null,
|
|
quotedValues: false
|
|
secrets.General = {}
|
|
secrets.Bookmarks =
|
|
size: 0
|
|
secrets.Identities =
|
|
size: @identities.length
|
|
index = 1
|
|
for identity in @identities
|
|
for key, value of identity
|
|
secrets.Identities["#{index}/#{key}"] = value
|
|
index++
|
|
if @defaultIdentity
|
|
secrets.Identities.SelectedIdentity = @defaultIdentity
|
|
|
|
# Generate INI content
|
|
await secrets.save defer(iniText)
|
|
fs.writeFileSync path.join(@configPath, "ts3clientui_qt.secrets.conf"), iniText
|
|
|
|
@identities = null
|
|
@defaultIdentity = null
|
|
@db = null
|
|
|
|
cb?()
|
|
|
|
setMultiple: (sets, cb) =>
|
|
for set in sets
|
|
await @set set[0], set[1], set[2], defer(err)
|
|
if err
|
|
throw err
|
|
cb?()
|
|
|
|
set: (table, key, value, cb) =>
|
|
if not @isReady
|
|
throw new Error "You need to run open on this instance of TS3Settings first"
|
|
return
|
|
|
|
if not table
|
|
throw new Error "Need table"
|
|
|
|
await @query "create table if not exists #{table} (timestamp integer unsigned NOT NULL, key varchar NOT NULL UNIQUE, value varchar)", defer()
|
|
|
|
if not key
|
|
return
|
|
|
|
if not (typeof value == "string" || value instanceof String)
|
|
# serialize from object to ts3 dict text
|
|
strval = ""
|
|
for own k of value
|
|
strval += k + "=" + value[k] + "\n"
|
|
value = strval
|
|
|
|
timestamp = Math.round (new Date).getTime() / 1000
|
|
|
|
stmt = @db.prepare "insert or replace into TS3Tables (key, timestamp) values (?, ?)"
|
|
stmt.run table, timestamp
|
|
await stmt.finalize defer()
|
|
|
|
stmt = @db.prepare "insert or replace into #{table} (timestamp, key, value) values (?, ?, ?)"
|
|
stmt.run timestamp, key, value
|
|
await stmt.finalize defer()
|
|
|
|
cb?()
|
|
|
|
query: (stmt, cb) =>
|
|
if not @isReady
|
|
throw new Error "You need to run open on this instance of TS3Settings first"
|
|
return
|
|
|
|
await @db.run stmt, defer()
|
|
cb?()
|
|
|
|
importIdentity: (identityFilePath, cb) =>
|
|
if not @isReady
|
|
throw new Error "You need to run open on this instance of TS3Settings first"
|
|
return
|
|
|
|
if not identityFilePath
|
|
throw new Error "Need identity file path"
|
|
|
|
@log.info "Importing identity from #{identityFilePath}..."
|
|
|
|
# open identity file
|
|
idFile = new SimpleIni (() => fs.readFileSync(identityFilePath, "utf-8")),
|
|
quotedValues: true
|
|
importedIdentity = {}
|
|
for own k, v of idFile.Identity
|
|
importedIdentity[k] = v
|
|
|
|
for identity in @identities
|
|
if identity.id == importedIdentity.id
|
|
throw new Error "Identity with same ID already exists"
|
|
|
|
@identities.push importedIdentity
|
|
@log.info "Identity #{importedIdentity.id} imported successfully!"
|
|
|
|
cb? @constructIdentityObject importedIdentity
|
|
|
|
importIdentitySync: (identityFilePath) =>
|
|
await @importIdentity identityFilePath, defer retval
|
|
return retval
|
|
|
|
getIdentities: (cb) =>
|
|
if not @isReady
|
|
throw new Error "You need to run open on this instance of TS3Settings first"
|
|
return
|
|
|
|
identities = []
|
|
|
|
for identity in @identities
|
|
identities.push @constructIdentityObject identity
|
|
|
|
cb? identities
|
|
|
|
getIdentitiesSync: () =>
|
|
await @getIdentities defer retval
|
|
return retval
|
|
|
|
getIdentitiesSize: () =>
|
|
if not @isReady
|
|
throw new Error "You need to run open on this instance of TS3Settings first"
|
|
return
|
|
|
|
@identities.length
|
|
|
|
getSelectedIdentity: () =>
|
|
if not @isReady
|
|
throw new Error "You need to run open on this instance of TS3Settings first"
|
|
return
|
|
|
|
if not @defaultIdentity
|
|
return null
|
|
|
|
for own index, identity of @identities
|
|
if identity.id == @defaultIdentity
|
|
return @constructIdentityObject identity
|
|
|
|
clearIdentities: () =>
|
|
if not @isReady
|
|
throw new Error "You need to run open on this instance of TS3Settings first"
|
|
return
|
|
|
|
@log.debug "Clearing all identities"
|
|
@identities.length = 0
|
|
return
|
|
|
|
constructIdentityObject: (id) =>
|
|
settingsObj = @
|
|
clonedId = merge(true, id)
|
|
return merge clonedId, # true causes object to be cloned
|
|
select: () ->
|
|
settingsObj.defaultIdentity = @id
|
|
update: () ->
|
|
settingsObj.log.silly "Requested update of #{id.id}"
|
|
for own index, identity of settingsObj.identities
|
|
if identity.id == id.id
|
|
# remove functions from this object
|
|
cleanIdentity = merge @
|
|
for own k, v of cleanIdentity
|
|
if typeof v == "function"
|
|
delete cleanIdentity[k]
|
|
|
|
# now this is our new identity object!
|
|
settingsObj.log.silly "Updating identity #{id.id}"
|
|
settingsObj.identities[index] = cleanIdentity
|
|
return
|
|
remove: () ->
|
|
for own index, identity of settingsObj.identities
|
|
if identity.id == id.id
|
|
delete settingsObj.identities[index]
|
|
break
|
|
# TODO: Select another identity as default
|