VRFS-986 recent history sidebar for landing pages

This commit is contained in:
Brian Smith 2014-01-21 01:45:51 -05:00
commit aa056d53fd
135 changed files with 3461 additions and 1338 deletions

View File

@ -8,7 +8,7 @@ ActiveAdmin.register_page "Dashboard" do
span "JamKazam Data Administration Portal"
small ul do
li "Admin users are users with the admin boolean set to true"
li "Create/Edit JamKazam users using the 'Jam User' menu in header"
li "Invite JamKazam users using the 'Users > Invite' menu in header"
li "Admin users are created/deleted when toggling the 'admin' flag for JamKazam users"
end
end

View File

@ -0,0 +1,3 @@
ActiveAdmin.register JamRuby::IcecastAdminAuthentication, :as => 'Admin Authentication' do
menu :parent => 'Icecast'
end

View File

@ -0,0 +1,107 @@
ActiveAdmin.register_page "Bootstrap" do
menu :parent => 'Icecast'
page_action :create_server, :method => :post do
template = IcecastTemplate.find(params[:jam_ruby_icecast_server][:template_id])
hostname = params[:jam_ruby_icecast_server][:hostname]
server = IcecastServer.new
server.template = template
server.hostname = hostname
server.server_id = hostname
server.save!
redirect_to admin_bootstrap_path, :notice => "Server created. If you start job worker (bundle exec rake all_jobs), it should update your icecast config."
end
page_action :brew_template, :method => :post do
# to make this template, I just did 'brew install icecast', and then based the rest of this code on what I saw in /usr/local/etc/icecast.xml
IcecastServer.transaction do
limit = IcecastLimit.new
limit.clients = 100
limit.sources = 2
limit.queue_size = 524288
limit.client_timeout = 30
limit.header_timeout = 15
limit.source_timeout = 10
limit.burst_size = 65535
limit.save!
admin_auth = IcecastAdminAuthentication.new
admin_auth.source_pass = 'blueberryjam'
admin_auth.relay_user = 'jamjam'
admin_auth.relay_pass = 'blueberryjam'
admin_auth.admin_user = 'jamjam'
admin_auth.admin_pass = 'blueberryjam'
admin_auth.save!
path = IcecastPath.new
path.base_dir = '/usr/local/Cellar/icecast/2.3.3/share/icecast'
path.log_dir = '/usr/local/Cellar/icecast/2.3.3/var/log/icecast'
path.web_root = '/usr/local/Cellar/icecast/2.3.3/share/icecast/web'
path.admin_root = '/usr/local/Cellar/icecast/2.3.3/share/icecast/admin'
path.pid_file = nil
path.save!
security = IcecastSecurity.new
security.chroot = false
security.save!
logging = IcecastLogging.new
logging.access_log = 'access.log'
logging.error_log = 'error.log'
logging.log_level = 3 # you might want to change this after creating the template
logging.log_size = 10000
logging.save!
listen_socket1 = IcecastListenSocket.new
listen_socket1.port = 8000
listen_socket1.save!
listen_socket2 = IcecastListenSocket.new
listen_socket2.port = 8001
listen_socket2.save!
template = IcecastTemplate.new
template.name = "Brew-#{IcecastTemplate.count + 1}"
template.location = '@work'
template.admin_email = 'nobody@jamkazam.com'
template.fileserve = true
template.limit = limit
template.admin_auth = admin_auth
template.path = path
template.security = security
template.logging = logging
template.listen_sockets = [listen_socket1, listen_socket2]
template.save!
end
redirect_to admin_bootstrap_path, :notice => "Brew template created. Create a server now with that template specified."
end
action_item do
link_to "Create Brew Template", admin_bootstrap_brew_template_path, :method => :post
end
content do
if IcecastTemplate.count == 0
para "You need to create at least one template for your environment"
else
semantic_form_for IcecastServer.new, :url => admin_bootstrap_create_server_path, :builder => ActiveAdmin::FormBuilder do |f|
f.inputs "New Server" do
f.input :hostname
f.input :template
end
f.actions
end
end
end
end

View File

@ -0,0 +1,3 @@
ActiveAdmin.register JamRuby::IcecastDirectory, :as => 'Directory' do
menu :parent => 'Icecast'
end

View File

@ -0,0 +1,3 @@
ActiveAdmin.register JamRuby::IcecastLimit, :as => 'Limit' do
menu :parent => 'Icecast'
end

View File

@ -0,0 +1,3 @@
ActiveAdmin.register JamRuby::IcecastListenSocket, :as => 'Listener' do
menu :parent => 'Icecast'
end

View File

@ -0,0 +1,3 @@
ActiveAdmin.register JamRuby::IcecastLogging, :as => 'Logging' do
menu :parent => 'Icecast'
end

View File

@ -0,0 +1,3 @@
ActiveAdmin.register JamRuby::IcecastMasterServerRelay, :as => 'Master Server Relay' do
menu :parent => 'Icecast'
end

View File

@ -0,0 +1,3 @@
ActiveAdmin.register JamRuby::IcecastMount, :as => 'Mount' do
menu :parent => 'Icecast'
end

View File

@ -0,0 +1,3 @@
ActiveAdmin.register JamRuby::IcecastPath, :as => 'Path' do
menu :parent => 'Icecast'
end

View File

@ -0,0 +1,3 @@
ActiveAdmin.register JamRuby::IcecastRelay, :as => 'Relay' do
menu :parent => 'Icecast'
end

View File

@ -0,0 +1,3 @@
ActiveAdmin.register JamRuby::IcecastSecurity, :as => 'Security' do
menu :parent => 'Icecast'
end

View File

@ -0,0 +1,3 @@
ActiveAdmin.register JamRuby::IcecastServer, :as => 'Server' do
menu :parent => 'Icecast'
end

View File

@ -0,0 +1,4 @@
ActiveAdmin.register JamRuby::IcecastServerMount, :as => 'ServerMounts' do
menu :parent => 'Icecast'
end

View File

@ -0,0 +1,3 @@
ActiveAdmin.register JamRuby::IcecastServerRelay, :as => 'ServerRelays' do
menu :parent => 'Icecast'
end

View File

@ -0,0 +1,3 @@
ActiveAdmin.register JamRuby::IcecastServerSocket, :as => 'ServerListenSockets' do
menu :parent => 'Icecast'
end

View File

@ -0,0 +1,3 @@
ActiveAdmin.register JamRuby::IcecastTemplate, :as => 'Template' do
menu :parent => 'Icecast'
end

View File

@ -0,0 +1,3 @@
ActiveAdmin.register JamRuby::IcecastTemplateSocket, :as => 'TemplateListenSockets' do
menu :parent => 'Icecast'
end

View File

@ -0,0 +1,3 @@
ActiveAdmin.register JamRuby::IcecastUserAuthentication, :as => 'User Authentication' do
menu :parent => 'Icecast'
end

View File

@ -22,7 +22,7 @@ cp ../pb/target/ruby/jampb/jampb-${GEM_VERSION}.gem vendor/cache/ || { echo "una
cp ../ruby/jam_ruby-${GEM_VERSION}.gem vendor/cache/ || { echo "unable to copy jam-ruby gem"; exit 1; }
# put all dependencies into vendor/bundle
rm -rf vendor/bundle
#rm -rf vendor/bundle -- let jenkins config 'wipe workspace' decide this
rm Gemfile.lock # if we don't want versions to float, pin it in the Gemfile, not count on Gemfile.lock
bundle install --path vendor/bundle
bundle update

View File

@ -91,5 +91,15 @@ module JamAdmin
config.action_controller.allow_forgery_protection = false
config.redis_host = "localhost:6379"
config.email_alerts_alias = 'alerts@jamkazam.com' # should be used for 'oh no' server down/service down sorts of emails
config.email_generic_from = 'nobody@jamkazam.com'
config.email_smtp_address = 'smtp.sendgrid.net'
config.email_smtp_port = 587
config.email_smtp_domain = 'www.jamkazam.com'
config.email_smtp_authentication = :plain
config.email_smtp_user_name = 'jamkazam'
config.email_smtp_password = 'jamjamblueberryjam'
config.email_smtp_starttls_auto = true
end
end

View File

@ -6,6 +6,11 @@ class Footer < ActiveAdmin::Component
end
end
module ActiveAdmin
class BaseController
with_role :admin
end
end
ActiveAdmin.setup do |config|

View File

@ -1,11 +1,11 @@
ActionMailer::Base.raise_delivery_errors = true
ActionMailer::Base.delivery_method = Rails.env == "test" ? :test : :smtp
ActionMailer::Base.smtp_settings = {
:address => "smtp.sendgrid.net",
:port => 587,
:domain => "www.jamkazam.com",
:authentication => :plain,
:user_name => "jamkazam",
:password => "jamjamblueberryjam",
:enable_starttls_auto => true
:address => Rails.application.config.email_smtp_address,
:port => Rails.application.config.email_smtp_port,
:domain => Rails.application.config.email_smtp_domain,
:authentication => Rails.application.config.email_smtp_authentication,
:user_name => Rails.application.config.email_smtp_user_name,
:password => Rails.application.config.email_smtp_password ,
:enable_starttls_auto => Rails.application.config.email_smtp_starttls_auto
}

View File

@ -19,7 +19,7 @@ rm -rf $TARGET
mkdir -p $PG_BUILD_OUT
mkdir -p $PG_RUBY_PACKAGE_OUT
bundle update
#bundle update
echo "building migrations"
bundle exec pg_migrate build --source . --out $PG_BUILD_OUT --test --verbose

View File

@ -88,4 +88,5 @@ icecast.sql
home_page_promos.sql
mix_job_watch.sql
music_session_constraints.sql
ms_recording_anonymous_likes.sql
ms_recording_anonymous_likes.sql
ms_user_history_add_instruments.sql

View File

@ -13,7 +13,7 @@ CREATE TABLE icecast_limits (
queue_size INTEGER NOT NULL DEFAULT 102400,
-- does not appear to be used
client_timeout INTEGER DEFAULT 10,
client_timeout INTEGER DEFAULT 30,
-- The maximum time (in seconds) to wait for a request to come in once
-- the client has made a connection to the server.
@ -35,23 +35,23 @@ CREATE TABLE icecast_limits (
);
create table icecast_admin_authentications (
CREATE TABLE icecast_admin_authentications (
id VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
-- The unencrypted password used by sources to connect to icecast2.
-- The default username for all source connections is 'source' but
-- this option allows to specify a default password. This and the username
-- The DEFAULT username for all source connections is 'source' but
-- this option allows to specify a DEFAULT password. This and the username
-- can be changed in the individual mount sections.
source_password VARCHAR(64) NOT NULL DEFAULT 'icejam321',
source_pass VARCHAR(64) NOT NULL,
-- Used in the master server as part of the authentication when a slave requests
-- the list of streams to relay. The default username is 'relay'
relay_user VARCHAR(64) NOT NULL DEFAULT 'relay',
relay_password VARCHAR(64) NOT NULL DEFAULT 'jkrelayhack',
-- the list of streams to relay. The DEFAULT username is 'relay'
relay_user VARCHAR(64) NOT NULL,
relay_pass VARCHAR(64) NOT NULL,
--The username/password used for all administration functions.
admin_user VARCHAR(64) NOT NULL DEFAULT 'jkadmin',
admin_password VARCHAR(64) NOT NULL DEFAULT 'jKadmin123',
admin_user VARCHAR(64) NOT NULL,
admin_pass VARCHAR(64) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
@ -60,249 +60,322 @@ create table icecast_admin_authentications (
--contains all the settings for listing a stream on any of the Icecast2 YP Directory servers.
-- Multiple occurances of this section can be specified in order to be listed on multiple directory servers.
create table icecast_directories (
CREATE TABLE icecast_directories (
id VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
yp_url_timeout INTEGER not null default 15,
yp_url VARCHAR(1024) not null UNIQUE default 'http://dir.xiph.org/cgi-bin/yp-cgi',
yp_url_timeout INTEGER NOT NULL DEFAULT 15,
yp_url VARCHAR(1024) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
create table icecast_servermiscs (
id VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
-- This is the DNS name or IP address that will be used for the stream directory lookups or possibily
-- the playlist generation if a Host header is not provided. While localhost is shown as an example,
-- in fact you will want something that your listeners can use.
hostname VARCHAR(256) not null default 'concertsvr.jamkazam.com',
--This sets the location string for this icecast instance. It will be shown e.g in the web interface.
location VARCHAR(128) not null default 'earth',
--This should contain contact details for getting in touch with the server administrator.
admin VARCHAR(128) not null default 'icemaster@localhost',
-- This flag turns on the icecast2 fileserver from which static files can be served.
-- All files are served relative to the path specified in the <paths><webroot> configuration
-- setting. By default the setting is enabled so that requests for the images
-- on the status page are retrievable.
fileserve INTEGER not null default 1,
-- This optional setting allows for the administrator of the server to override the
-- default server identification. The default is icecast followed by a version number
-- and most will not care to change it however this setting will change that.
server_id VARCHAR(128) not null default 'icecast 2.3',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
create table icecast_listen_sockets (
CREATE TABLE icecast_listen_sockets (
id VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
-- The TCP port that will be used to accept client connections.
port INTEGER not null default 8001,
port INTEGER NOT NULL DEFAULT 8001,
-- An optional IP address that can be used to bind to a specific network card.
-- If not supplied, then it will bind to all interfaces.
bind_address VARCHAR(128),
bind_address VARCHAR(1024),
shoutcast_mount VARCHAR(128) default NULL,
shoutcast_compat INTEGER not null default 0,
shoutcast_mount VARCHAR(1024),
shoutcast_compat INTEGER,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
create table icecast_mastersvr_relays (
CREATE TABLE icecast_relays (
id VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
-- ip address of server we are relaying from and port number
server VARCHAR(1024) NOT NULL,
port INTEGER NOT NULL DEFAULT 8001,
-- mount at server. eg /example.ogg
mount VARCHAR(1024) NOT NULL,
-- eg /different.ogg
local_mount VARCHAR(1024),
-- eg joe. could be null
relay_username VARCHAR(64),
-- user password
relay_pass VARCHAR(64),
relay_shoutcast_metadata INTEGER DEFAULT 0,
--- relay only if we have someone wanting to listen
on_demand INTEGER DEFAULT 1,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNLOGGED TABLE icecast_user_authentications(
id VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
--"htpasswd or url"
-- real name is type
authentication_type VARCHAR(16) DEFAULT 'url',
-- these are for httpasswd
filename VARCHAR(1024),
allow_duplicate_users INTEGER,
-- these options are for url
-- eg value="http://myauthserver.com/stream_start.php"
mount_add VARCHAR(1024),
--value="http://myauthserver.com/stream_end.php"
mount_remove VARCHAR(1024),
--value="http://myauthserver.com/listener_joined.php"
listener_add VARCHAR(1024),
--value="http://myauthserver.com/listener_left.php"
listener_remove VARCHAR(1024),
-- value="user"
unused_username VARCHAR(64),
-- value="pass"
unused_pass VARCHAR(64),
-- value="icecast-auth-user: 1"
auth_header VARCHAR(64) DEFAULT 'icecast-auth-user: 1',
-- value="icecast-auth-timelimit:"
timelimit_header VARCHAR(64) DEFAULT 'icecast-auth-timelimit:',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNLOGGED TABLE icecast_mounts (
id VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
-- eg/example-complex.ogg
name VARCHAR(1024) UNIQUE NOT NULL,
source_username VARCHAR(64),
source_pass VARCHAR(64),
max_listeners INTEGER DEFAULT 4,
max_listener_duration INTEGER DEFAULT 3600,
-- dump of the stream coming through on this mountpoint.
-- eg /tmp/dump-example1.ogg
dump_file VARCHAR(1024),
-- intro music to play
-- This optional value specifies a mountpoint that clients are automatically moved to
-- if the source shuts down or is not streaming at the time a listener connects.
intro VARCHAR(1024),
fallback_mount VARCHAR(1024),
-- When enabled, this allows a connecting source client or relay on this mountpoint
-- to move listening clients back from the fallback mount.
fallback_override INTEGER DEFAULT 1,
-- When set to 1, this will cause new listeners, when the max listener count for the mountpoint
-- has been reached, to move to the fallback mount if there is one specified.
fallback_when_full INTEGER DEFAULT 1,
--For non-Ogg streams like MP3, the metadata that is inserted into the stream often
-- has no defined character set.
charset VARCHAR(1024) DEFAULT 'ISO8859-1',
-- possible values are -1, 0, 1
-- real name is public but this is reserved word in ruby
is_public INTEGER DEFAULT 0,
stream_name VARCHAR(1024),
stream_description VARCHAR(10000),
-- direct to user page
stream_url VARCHAR(1024),
-- get this from the session info
genre VARCHAR(256),
bitrate INTEGER,
-- real name is type but this is reserved name in ruby
mime_type VARCHAR(64) NOT NULL DEFAULT 'audio/ogg' ,
subtype VARCHAR(64) NOT NULL DEFAULT 'vorbis',
-- This optional setting allows for providing a burst size which overrides the
-- DEFAULT burst size as defined in limits. The value is in bytes.
burst_size INTEGER,
mp3_metadata_interval INTEGER,
-- Enable this to prevent this mount from being shown on the xsl pages.
-- This is mainly for cases where a local relay is configured and you do
-- not want the source of the local relay to be shown
hidden INTEGER DEFAULT 1,
--called when the source connects or disconnects. The scripts are called with the name of the mount
on_connect VARCHAR(1024),
on_disconnect VARCHAR(1024),
-- references icecast_user_authentications(id)
authentication_id varchar(64) DEFAULT NULL,
------stats------
listeners INTEGER NOT NULL DEFAULT 0,
sourced BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE icecast_paths (
id VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
base_dir VARCHAR(1024) NOT NULL DEFAULT './',
log_dir VARCHAR(1024) NOT NULL DEFAULT './logs',
pid_file VARCHAR(1024) DEFAULT './icecast.pid',
web_root VARCHAR(1024) NOT NULL DEFAULT './web',
admin_root VARCHAR(1024) NOT NULL DEFAULT './admin',
allow_ip VARCHAR(1024),
deny_ip VARCHAR(1024),
alias_source VARCHAR(1024),
alias_dest VARCHAR(1024),
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE icecast_loggings (
id VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
access_log VARCHAR(1024) NOT NULL DEFAULT 'access.log',
error_log VARCHAR(1024) NOT NULL DEFAULT 'error.log',
playlist_log VARCHAR(1024),
-- 4 Debug, 3 Info, 2 Warn, 1 Error
log_level INTEGER NOT NULL DEFAULT 3 ,
log_archive INTEGER,
-- 10 meg log file by default
log_size INTEGER DEFAULT 10000,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE icecast_securities (
id VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
chroot INTEGER NOT NULL DEFAULT 0,
change_owner_user VARCHAR(64),
change_owner_group VARCHAR(64),
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE icecast_master_server_relays(
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
-- ip address of the master icecast server and port number
master_server VARCHAR(128) not null,
master_server_port INTEGER not null,
master_server VARCHAR(1024) NOT NULL,
master_server_port INTEGER NOT NULL DEFAULT 8001,
--The interval (in seconds) that the Relay Server will poll the Master Server for any new mountpoints to relay.
master_update_interval INTEGER not null default 120,
master_update_interval INTEGER NOT NULL DEFAULT 120,
-- This is the relay username on the master server. It is used to query the server for a list of
-- mountpoints to relay. If not specified then 'relay' is used
master_username VARCHAR(64) not null default 'relay',
master_password VARCHAR(64) not null,
master_username VARCHAR(64) NOT NULL,
master_pass VARCHAR(64) NOT NULL,
--Global on-demand setting for relays. Because you do not have individual relay options when
-- using a master server relay, you still may want those relays to only pull the stream when
-- there is at least one listener on the slave. The typical case here is to avoid surplus
-- bandwidth costs when no one is listening.
relays_on_demand INTEGER default 0,
relays_on_demand INTEGER NOT NULL DEFAULT 1,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
--make sure this combo is unique
--CONSTRAINT serverID UNIQUE KEY (master_server,master_server_port)
);
create table icecast_relays (
id VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
-- ip address of server we are relaying from and port number
server VARCHAR(128) not null,
port INTEGER not null default 8001,
-- mount at server. eg /example.ogg
mount VARCHAR(128) not null,
-- eg /different.ogg
local_mount VARCHAR(128) not null,
-- eg joe. could be null
username VARCHAR(64) default NULL ,
-- user password
password VARCHAR(64) default null ,
relay_shoutcast_metadata INTEGER default 0,
--- relay only if we have someone wanting to listen
on_demand INTEGER default 0,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
create TABLE icecast_user_authentications(
id VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
--"htpasswd or url"
-- real name is type
stype VARCHAR(16) DEFAULT NULL ,
-- these are for httpasswd
filename VARCHAR(256) default NULL,
allow_duplicate_users INTEGER DEFAULT 0,
-- these options are for url
-- eg value="http://myauthserver.com/stream_start.php"
mount_add VARCHAR(256) default NULL,
--value="http://myauthserver.com/stream_end.php"
mount_remove VARCHAR(256) default NULL,
--value="http://myauthserver.com/listener_joined.php"
listener_add VARCHAR(256) default NULL,
--value="http://myauthserver.com/listener_left.php"
listener_remove VARCHAR(256) default NULL,
-- value="user"
username VARCHAR(64) default NULL,
-- value="pass"
password VARCHAR(64) default NULL,
-- value="icecast-auth-user: 1"
auth_header VARCHAR(64) default NULL,
-- value="icecast-auth-timelimit:"
timelimit_header VARCHAR(64) default NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
create table icecast_mounts (
id VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
-- eg/example-complex.ogg
mount_name VARCHAR(128) UNIQUE NOT NULL,
username VARCHAR(64) NOT NULL DEFAULT 'jamsource',
password VARCHAR(64) NOT NULL DEFAULT 'jamksource',
max_listeners INTEGER NOT NULL DEFAULT 4,
max_listener_duration INTEGER NOT NULL DEFAULT 3600,
-- dump of the stream coming through on this mountpoint.
-- eg /tmp/dump-example1.ogg
dump_file VARCHAR(256) DEFAULT NULL,
-- intro music to play
-- This optional value specifies a mountpoint that clients are automatically moved to
-- if the source shuts down or is not streaming at the time a listener connects.
intro VARCHAR(256) NOT NULL DEFAULT '/intro.ogg',
fallback_mount VARCHAR(256) NOT NULL DEFAULT '/sourcedown.ogg',
-- When enabled, this allows a connecting source client or relay on this mountpoint
-- to move listening clients back from the fallback mount.
fallback_override INTEGER DEFAULT 1,
-- When set to 1, this will cause new listeners, when the max listener count for the mountpoint
-- has been reached, to move to the fallback mount if there is one specified.
fallback_when_full INTEGER DEFAULT 1,
--For non-Ogg streams like MP3, the metadata that is inserted into the stream often
-- has no defined character set.
charset VARCHAR(256) NOT NULL DEFAULT 'ISO8859-1',
-- possilble values are -1, 0, 1
-- real name is public but this is reserved word in ruby
publicc INTEGER DEFAULT 1,
stream_name VARCHAR(256) NOT NULL DEFAULT 'My Jamkazam Audio Stream',
stream_description VARCHAR(256) NOT NULL DEFAULT 'My JK audio description',
-- direct to user page
stream_url VARCHAR(256) NOT NULL DEFAULT 'http://wwww.jamakazam.com#user_id',
-- get this from the session info
genre VARCHAR(64) NOT NULL DEFAULT 'Unknown',
bitrate integer NOT NULL default 92,
-- real name is type but this is reserved name in ruby
mtype VARCHAR(64) NOT NULL DEFAULT 'application/ogg' ,
subtype VARCHAR(64) NOT NULL DEFAULT 'vorbis',
-- Enable this to prevent this mount from being shown on the xsl pages.
-- This is mainly for cases where a local relay is configured and you do
-- not want the source of the local relay to be shown
hidden INTEGER DEFAULT 1,
-- This optional setting allows for providing a burst size which overrides the
-- default burst size as defined in limits. The value is in bytes.
burst_size INTEGER DEFAULT 65536,
mp3_metadata_interval INTEGER DEFAULT 4096,
--called when the source connects or disconnects. The scripts are called with the name of the mount
on_connect VARCHAR(256) DEFAULT '/home/icecast/bin/source-start',
on_disconnect VARCHAR(256) DEFAULT '/home/icecast/bin/source-end',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
create table icecast_paths (
id VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
basedir VARCHAR(256) NOT NULL DEFAULT './',
logdir VARCHAR(256) NOT NULL DEFAULT './logs',
pidfile VARCHAR(256) NOT NULL DEFAULT './icecast.pid',
webroot VARCHAR(256) NOT NULL DEFAULT './web',
adminroot VARCHAR(256) NOT NULL DEFAULT './admin',
allow_ip VARCHAR(256) NOT NULL DEFAULT '/path/to/ip_allowlist',
deny_ip VARCHAR(256) NOT NULL DEFAULT '/path_to_ip_denylist',
--real name is alias but alias is reserved in ruby
aliass VARCHAR(256) DEFAULT 'source="/foo" dest="/bar"',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
create table icecast_loggings (
id VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
accesslog VARCHAR(256) NOT NULL DEFAULT 'access.log',
errorlog VARCHAR(256) NOT NULL DEFAULT 'error.log',
playlistlog VARCHAR(256) NOT NULL DEFAULT 'playlist.log',
-- 4 Debug, 3 Info, 2 Warn, 1 Error
loglevel INTEGER NOT NULL DEFAULT 4 ,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
create table icecast_securities (
id VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
chroot INTEGER NOT NULL DEFAULT 0,
changeowner_user VARCHAR(64) DEFAULT 'nobody',
changeowner_group VARCHAR(64) DEFAULT 'nogroup',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
create TABLE icecast_servers(
CREATE TABLE icecast_templates (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
icecast_limit_id VARCHAR(64) REFERENCES icecast_limits(id)
limit_id VARCHAR(64) REFERENCES icecast_limits(id),
admin_auth_id VARCHAR(64) REFERENCES icecast_admin_authentications(id),
directory_id VARCHAR(64) REFERENCES icecast_directories(id),
master_relay_id VARCHAR(64) REFERENCES icecast_master_server_relays(id),
path_id VARCHAR(64) REFERENCES icecast_paths(id),
logging_id VARCHAR(64) REFERENCES icecast_loggings(id),
security_id VARCHAR(64) REFERENCES icecast_securities(id),
location VARCHAR(1024) NOT NULL,
name VARCHAR(256) NOT NULL,
admin_email VARCHAR(1024) NOT NULL DEFAULT 'admin@jamkazam.com',
fileserve INTEGER NOT NULL DEFAULT 1,
-- configs
-- mounts
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE icecast_servers (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
--use this to mark the server configuration as needing to be regenerated
config_changed INTEGER DEFAULT 0,
limit_id VARCHAR(64) REFERENCES icecast_limits(id),
admin_auth_id VARCHAR(64) REFERENCES icecast_admin_authentications(id),
directory_id VARCHAR(64) REFERENCES icecast_directories(id),
master_relay_id VARCHAR(64) REFERENCES icecast_master_server_relays(id),
path_id VARCHAR(64) REFERENCES icecast_paths(id),
logging_id VARCHAR(64) REFERENCES icecast_loggings(id),
security_id VARCHAR(64) REFERENCES icecast_securities(id),
template_id VARCHAR(64) NOT NULL REFERENCES icecast_templates(id),
-- This is the DNS name or IP address that will be used for the stream directory lookups or possibily
-- the playlist generation if a Host header is not provided. While localhost is shown as an example,
-- in fact you will want something that your listeners can use.
hostname VARCHAR(1024) NOT NULL,
server_id VARCHAR(1024) UNIQUE NOT NULL,
--This sets the location string for this icecast instance. It will be shown e.g in the web interface.
location VARCHAR(1024),
--This should contain contact details for getting in touch with the server administrator.
admin_email VARCHAR(1024),
-- This flag turns on the icecast2 fileserver from which static files can be served.
-- All files are served relative to the path specified in the <paths><webroot> configuration
-- setting. By DEFAULT the setting is enabled so that requests for the images
-- on the status page are retrievable.
fileserve INTEGER,
-- This optional setting allows for the administrator of the server to override the
-- DEFAULT server identification. The DEFAULT is icecast followed by a version number
-- and most will not care to change it however this setting will change that.
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE icecast_server_mounts (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
--REFERENCES icecast_mounts(id) ON DELETE CASCADE,
icecast_mount_id VARCHAR(64),
icecast_server_id VARCHAR(64) REFERENCES icecast_servers(id) ON DELETE CASCADE,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
ALTER TABLE icecast_server_mounts ADD CONSTRAINT server_mount_uniqkey UNIQUE (icecast_mount_id, icecast_server_id);
CREATE TABLE icecast_server_relays (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
icecast_relay_id VARCHAR(64) REFERENCES icecast_relays(id) ON DELETE CASCADE,
icecast_server_id VARCHAR(64) REFERENCES icecast_servers(id) ON DELETE CASCADE,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
ALTER TABLE icecast_server_relays ADD CONSTRAINT server_relay_uniqkey UNIQUE (icecast_relay_id, icecast_server_id);
CREATE TABLE icecast_server_sockets (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
icecast_listen_socket_id VARCHAR(64) REFERENCES icecast_listen_sockets(id) ON DELETE CASCADE,
icecast_server_id VARCHAR(64) REFERENCES icecast_servers(id) ON DELETE CASCADE,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
ALTER TABLE icecast_server_sockets ADD CONSTRAINT server_socket_uniqkey UNIQUE (icecast_listen_socket_id, icecast_server_id);
CREATE TABLE icecast_template_sockets (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
icecast_listen_socket_id VARCHAR(64) REFERENCES icecast_listen_sockets(id) ON DELETE CASCADE,
icecast_template_id VARCHAR(64) REFERENCES icecast_templates(id) ON DELETE CASCADE,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
ALTER TABLE icecast_template_sockets ADD CONSTRAINT template_socket_uniqkey UNIQUE (icecast_listen_socket_id, icecast_template_id);

View File

@ -0,0 +1,129 @@
-- this manifest update makes every table associated with music_sessions UNLOGGED
-- tables to mark UNLOGGED
-- connections, fan_invitations, invitations, genres_music_sessions, join_requests, tracks, music_sessions
-- tables to just get rid of
-- session_plays
-- breaking foreign keys for tables
-- connections: user_id
-- fan_invitations: receiver_id, sender_id
-- music_session: user_id, band_id, claimed_recording_id, claimed_recording_initiator_id
-- genres_music_sessions: genre_id
-- invitations: sender_id, receiver_id
-- fan_invitations: user_id
-- notifications: invitation_id, join_request_id, session_id
DROP TABLE sessions_plays;
-- divorce notifications from UNLOGGED tables
-- NOTIFICATIONS
----------------
-- "notifications_session_id_fkey" FOREIGN KEY (session_id) REFERENCES music_sessions(id) ON DELETE CASCADE
ALTER TABLE notifications DROP CONSTRAINT notifications_session_id_fkey;
-- "notifications_join_request_id_fkey" FOREIGN KEY (join_request_id) REFERENCES join_requests(id) ON DELETE CASCADE
ALTER TABLE notifications DROP CONSTRAINT notifications_join_request_id_fkey;
-- "notifications_invitation_id_fkey" FOREIGN KEY (invitation_id) REFERENCES invitations(id) ON DELETE CASCADE
ALTER TABLE notifications DROP CONSTRAINT notifications_invitation_id_fkey;
-- FAN_INVITATIONS
------------------
DROP TABLE fan_invitations;
DROP TABLE invitations;
DROP TABLE join_requests;
DROP TABLE genres_music_sessions;
DROP TABLE tracks;
DROP TABLE connections;
DROP TABLE music_sessions;
-- MUSIC_SESSIONS
-----------------
CREATE UNLOGGED TABLE music_sessions (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
description VARCHAR(8000),
user_id VARCHAR(64) NOT NULL,
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
musician_access BOOLEAN NOT NULL,
band_id VARCHAR(64),
approval_required BOOLEAN NOT NULL,
fan_access BOOLEAN NOT NULL,
fan_chat BOOLEAN NOT NULL,
claimed_recording_id VARCHAR(64),
claimed_recording_initiator_id VARCHAR(64)
);
-- CONNECTIONS
--------------
CREATE UNLOGGED TABLE connections (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
user_id VARCHAR(64),
client_id VARCHAR(64) UNIQUE NOT NULL,
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
music_session_id VARCHAR(64),
ip_address VARCHAR(64),
as_musician BOOLEAN,
aasm_state VARCHAR(64) DEFAULT 'idle'::VARCHAR NOT NULL
);
ALTER TABLE ONLY connections ADD CONSTRAINT connections_music_session_id_fkey FOREIGN KEY (music_session_id) REFERENCES music_sessions(id) ON DELETE SET NULL;
-- GENRES_MUSIC_SESSIONS
------------------------
CREATE UNLOGGED TABLE genres_music_sessions (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
genre_id VARCHAR(64),
music_session_id VARCHAR(64)
);
ALTER TABLE ONLY genres_music_sessions ADD CONSTRAINT genres_music_sessions_music_session_id_fkey FOREIGN KEY (music_session_id) REFERENCES music_sessions(id) ON DELETE CASCADE;
CREATE UNLOGGED TABLE fan_invitations (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
sender_id VARCHAR(64),
receiver_id VARCHAR(64),
music_session_id VARCHAR(64),
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL
);
ALTER TABLE ONLY fan_invitations ADD CONSTRAINT fan_invitations_music_session_id_fkey FOREIGN KEY (music_session_id) REFERENCES music_sessions(id) ON DELETE CASCADE;
CREATE UNLOGGED TABLE join_requests (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
user_id VARCHAR(64),
music_session_id VARCHAR(64),
text VARCHAR(2000),
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL
);
ALTER TABLE ONLY join_requests ADD CONSTRAINT user_music_session_uniqkey UNIQUE (user_id, music_session_id);
ALTER TABLE ONLY join_requests ADD CONSTRAINT join_requests_music_session_id_fkey FOREIGN KEY (music_session_id) REFERENCES music_sessions(id) ON DELETE CASCADE;
-- INVITATIONS
--------------
CREATE UNLOGGED TABLE invitations (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
sender_id VARCHAR(64),
receiver_id VARCHAR(64),
music_session_id VARCHAR(64),
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
join_request_id VARCHAR(64)
);
ALTER TABLE ONLY invitations ADD CONSTRAINT invitations_uniqkey UNIQUE (sender_id, receiver_id, music_session_id);
ALTER TABLE ONLY invitations ADD CONSTRAINT invitations_join_request_id_fkey FOREIGN KEY (join_request_id) REFERENCES join_requests(id) ON DELETE CASCADE;
ALTER TABLE ONLY invitations ADD CONSTRAINT invitations_music_session_id_fkey FOREIGN KEY (music_session_id) REFERENCES music_sessions(id) ON DELETE CASCADE;
-- TRACKS
---------
CREATE UNLOGGED TABLE tracks (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
connection_id VARCHAR(64),
instrument_id VARCHAR(64),
sound VARCHAR(64) NOT NULL,
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
client_track_id VARCHAR(64) NOT NULL
);
ALTER TABLE ONLY tracks ADD CONSTRAINT connections_tracks_connection_id_fkey FOREIGN KEY (connection_id) REFERENCES connections(id) ON DELETE CASCADE;

View File

@ -0,0 +1 @@
alter table music_sessions_user_history add column instruments varchar(255);

View File

@ -51,6 +51,11 @@ message ClientMessage {
MUSICIAN_SESSION_FRESH = 240;
MUSICIAN_SESSION_STALE = 245;
// icecast notifications
SOURCE_UP_REQUESTED = 250;
SOURCE_DOWN_REQUESTED = 255;
TEST_SESSION_MESSAGE = 295;
@ -114,11 +119,13 @@ message ClientMessage {
// band notifications
optional BandInvitation band_invitation = 225;
optional BandInvitationAccepted band_invitation_accepted = 230;
optional BandSessionJoin band_session_join = 235;
optional MusicianSessionFresh musician_session_fresh = 240;
optional MusicianSessionStale musician_session_stale = 245;
// icecast notifications
optional SourceUpRequested source_up_requested = 250;
optional SourceDownRequested source_down_requested = 255;
// Client-Session messages (to/from)
optional TestSessionMessage test_session_message = 295;
@ -327,9 +334,10 @@ message RecordingEnded {
message RecordingMasterMixComplete {
optional string recording_id = 1;
optional string msg = 2;
optional string notification_id = 3;
optional string created_at = 4;
optional string band_id = 2;
optional string msg = 3;
optional string notification_id = 4;
optional string created_at = 5;
}
message DownloadAvailable {
@ -371,6 +379,18 @@ message MusicianSessionStale {
optional string photo_url = 4;
}
message SourceUpRequested {
optional string host = 1; // icecast server host
optional int32 port = 2; // icecast server port
optional string mount = 3; // mount name
optional string source_user = 4; // source user
optional string source_pass = 5; // source pass
}
message SourceDownRequested {
optional string mount = 1; // mount name
}
// route_to: session
// a test message used by ruby-client currently. just gives way to send out to rest of session
message TestSessionMessage {

View File

@ -30,6 +30,7 @@ gem 'resque'
gem 'resque-retry'
gem 'resque-failed-job-mailer' #, :path => "/Users/seth/workspace/resque_failed_job_mailer"
gem 'oj'
gem 'builder'
if devenv
gem 'jam_db', :path=> "../db/target/ruby_package"

View File

@ -28,8 +28,11 @@ require "jam_ruby/lib/module_overrides"
require "jam_ruby/lib/s3_util"
require "jam_ruby/lib/s3_manager"
require "jam_ruby/lib/profanity"
require "jam_ruby/lib/em_helper.rb"
require "jam_ruby/resque/audiomixer"
require "jam_ruby/resque/icecast_config_writer"
require "jam_ruby/resque/scheduled/audiomixer_retry"
require "jam_ruby/resque/scheduled/icecast_config_retry"
require "jam_ruby/mq_router"
require "jam_ruby/base_manager"
require "jam_ruby/connection_manager"
@ -98,14 +101,18 @@ require "jam_ruby/models/icecast_directory"
require "jam_ruby/models/icecast_limit"
require "jam_ruby/models/icecast_listen_socket"
require "jam_ruby/models/icecast_logging"
require "jam_ruby/models/icecast_mastersvr_relay"
require "jam_ruby/models/icecast_master_server_relay"
require "jam_ruby/models/icecast_mount"
require "jam_ruby/models/icecast_path"
require "jam_ruby/models/icecast_relay"
require "jam_ruby/models/icecast_sercurity"
require "jam_ruby/models/icecast_security"
require "jam_ruby/models/icecast_server"
require "jam_ruby/models/icecast_servermisc"
require "jam_ruby/models/icecast_template"
require "jam_ruby/models/icecast_user_authentication"
require "jam_ruby/models/icecast_server_mount"
require "jam_ruby/models/icecast_server_relay"
require "jam_ruby/models/icecast_server_socket"
require "jam_ruby/models/icecast_template_socket"
include Jampb

View File

@ -303,7 +303,7 @@ SQL
else
blk.call(db_conn, connection) unless blk.nil?
user.update_progression_field(:first_music_session_at)
MusicSessionUserHistory.save(music_session_id, user_id, client_id)
MusicSessionUserHistory.save(music_session_id, user_id, client_id, tracks)
end
end

View File

@ -0,0 +1,95 @@
require 'amqp'
require 'jam_ruby'
# Creates a connection to RabbitMQ
# On that single connection, a channel is created (which is a way to multiplex multiple queues/topics over the same TCP connection with rabbitmq)
# Then connections to the client_exchange and user_exchange are made, and put into the MQRouter static variables
# If this code completes (which implies that Rails can start to begin with, because this is in an initializer),
# then the Rails app itself is free to send messages over these exchanges
# Also starts websocket-gateway
module JamWebEventMachine
@@log = Logging.logger[JamWebEventMachine]
# starts amqp & eventmachine up first.
# and then calls your block.
# After the supplied block is done,
# waits until all EM tasks scheduled in the supplied block are done, or timeout
def self.run_wait_stop(timeout = 30, &blk)
JamWebEventMachine.start
thread = Thread.current
blk.call
# put our thread wake up event on the EM scheduler,
# meaning we go last (assuming that all EM tasks needed were scheduled in the blk)
EM.schedule do
thread.wakeup
end
sleep timeout
EM.stop
end
def self.run_em
EM.run do
# this is global because we need to check elsewhere if we are currently connected to amqp before signalling success with some APIs, such as 'create session'
$amqp_connection_manager = AmqpConnectionManager.new(true, 4, :host => APP_CONFIG.rabbitmq_host, :port => APP_CONFIG.rabbitmq_port)
$amqp_connection_manager.connect do |channel|
AMQP::Exchange.new(channel, :topic, "clients") do |exchange|
@@log.debug("#{exchange.name} is ready to go")
MQRouter.client_exchange = exchange
end
AMQP::Exchange.new(channel, :topic, "users") do |exchange|
@@log.debug("#{exchange.name} is ready to go")
MQRouter.user_exchange = exchange
end
end
end
end
def self.die_gracefully_on_signal
@@log.debug("*** die_gracefully_on_signal")
Signal.trap("INT") { EM.stop }
Signal.trap("TERM") { EM.stop }
end
def self.start
if defined?(PhusionPassenger)
@@log.debug("PhusionPassenger detected")
PhusionPassenger.on_event(:starting_worker_process) do |forked|
# for passenger, we need to avoid orphaned threads
if forked && EM.reactor_running?
@@log.debug("stopping EventMachine")
EM.stop
end
@@log.debug("starting EventMachine")
Thread.new do
run_em
end
die_gracefully_on_signal
end
elsif defined?(Unicorn)
@@log.debug("Unicorn detected--do nothing at initializer phase")
else
@@log.debug("Development environment detected")
Thread.abort_on_exception = true
# create a new thread separate from the Rails main thread that EventMachine can run on
Thread.new do
run_em
end
end
end
end

View File

@ -19,7 +19,7 @@ module JamRuby
# given a string (bytes) payload, return a client message
def parse_client_msg(payload)
return Jampb::ClientMessage.parse(payload)
Jampb::ClientMessage.parse(payload)
end
# create a login message using user/pass
@ -30,7 +30,7 @@ module JamRuby
:client_id => options[:client_id]
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::LOGIN,
:route_to => SERVER_TARGET,
:login => login
@ -44,7 +44,7 @@ module JamRuby
:client_id => options[:client_id]
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::LOGIN,
:route_to => SERVER_TARGET,
:login => login
@ -63,7 +63,7 @@ module JamRuby
:user_id => user_id
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::LOGIN_ACK,
:route_to => CLIENT_TARGET,
:login_ack => login_ack
@ -73,7 +73,7 @@ module JamRuby
def download_available
download_available = Jampb::DownloadAvailable.new
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::DOWNLOAD_AVAILABLE,
:route_to => CLIENT_TARGET,
:download_available => download_available
@ -84,7 +84,7 @@ module JamRuby
def login_music_session(music_session)
login_music_session = Jampb::LoginMusicSession.new(:music_session => music_session)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::LOGIN_MUSIC_SESSION,
:route_to => SERVER_TARGET,
:login_music_session => login_music_session
@ -95,7 +95,7 @@ module JamRuby
def login_music_session_ack(error, error_reason)
login_music_session_ack = Jampb::LoginMusicSessionAck.new(:error => error, :error_reason => error_reason)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::LOGIN_MUSIC_SESSION_ACK,
:route_to => CLIENT_TARGET,
:login_music_session_ack => login_music_session_ack
@ -106,7 +106,7 @@ module JamRuby
def leave_music_session(music_session)
leave_music_session = Jampb::LeaveMusicSession.new(:music_session => music_session)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::LEAVE_MUSIC_SESSION,
:route_to => SERVER_TARGET,
:leave_music_session => leave_music_session
@ -117,7 +117,7 @@ module JamRuby
def leave_music_session_ack(error, error_reason)
leave_music_session_ack = Jampb::LeaveMusicSessionAck.new(:error => error, :error_reason => error_reason)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::LEAVE_MUSIC_SESSION_ACK,
:route_to => CLIENT_TARGET,
:leave_music_session_ack => leave_music_session_ack
@ -128,7 +128,7 @@ module JamRuby
def heartbeat()
heartbeat = Jampb::Heartbeat.new
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::HEARTBEAT,
:route_to => SERVER_TARGET,
:heartbeat => heartbeat
@ -139,7 +139,7 @@ module JamRuby
def heartbeat_ack()
heartbeat_ack = Jampb::HeartbeatAck.new
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::HEARTBEAT_ACK,
:route_to => CLIENT_TARGET,
:heartbeat_ack => heartbeat_ack
@ -150,7 +150,7 @@ module JamRuby
def server_bad_state_recovered(original_message_id)
recovered = Jampb::ServerBadStateRecovered.new()
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::SERVER_BAD_STATE_RECOVERED,
:route_to => CLIENT_TARGET,
:server_bad_state_recovered => recovered,
@ -162,7 +162,7 @@ module JamRuby
def server_generic_error(error_msg)
error = Jampb::ServerGenericError.new(:error_msg => error_msg)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::SERVER_GENERIC_ERROR,
:route_to => CLIENT_TARGET,
:server_generic_error => error
@ -173,7 +173,7 @@ module JamRuby
def server_rejection_error(error_msg)
error = Jampb::ServerRejectionError.new(:error_msg => error_msg)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::SERVER_REJECTION_ERROR,
:route_to => CLIENT_TARGET,
:server_rejection_error => error
@ -184,7 +184,7 @@ module JamRuby
def server_permission_error(original_message_id, error_msg)
error = Jampb::ServerPermissionError.new(:error_msg => error_msg)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::SERVER_PERMISSION_ERROR,
:route_to => CLIENT_TARGET,
:server_permission_error => error,
@ -196,7 +196,7 @@ module JamRuby
def server_bad_state_error(original_message_id, error_msg)
error = Jampb::ServerBadStateError.new(:error_msg => error_msg)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::SERVER_BAD_STATE_ERROR,
:route_to => CLIENT_TARGET,
:server_bad_state_error => error,
@ -215,7 +215,7 @@ module JamRuby
:msg => msg
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::FRIEND_UPDATE,
:route_to => USER_TARGET_PREFIX + user_id,
:friend_update => friend
@ -232,7 +232,7 @@ module JamRuby
:created_at => created_at
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::FRIEND_REQUEST,
:route_to => USER_TARGET_PREFIX + receiver_id,
:friend_request => friend_request
@ -248,7 +248,7 @@ module JamRuby
:created_at => created_at
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::FRIEND_REQUEST_ACCEPTED,
:route_to => USER_TARGET_PREFIX + receiver_id,
:friend_request_accepted => friend_request_accepted
@ -263,7 +263,7 @@ module JamRuby
:created_at => created_at
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::NEW_USER_FOLLOWER,
:route_to => USER_TARGET_PREFIX + receiver_id,
:new_user_follower => new_user_follower
@ -278,7 +278,7 @@ module JamRuby
:created_at => created_at
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::NEW_BAND_FOLLOWER,
:route_to => USER_TARGET_PREFIX + receiver_id,
:new_band_follower => new_band_follower
@ -293,7 +293,7 @@ module JamRuby
:created_at => created_at
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::SESSION_INVITATION,
:route_to => USER_TARGET_PREFIX + receiver_id,
:session_invitation => session_invitation
@ -311,7 +311,7 @@ module JamRuby
:created_at => created_at
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::JOIN_REQUEST,
:route_to => SESSION_TARGET_PREFIX + session_id,
:join_request => req
@ -329,7 +329,7 @@ module JamRuby
:created_at => created_at
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::JOIN_REQUEST_APPROVED,
:route_to => SESSION_TARGET_PREFIX + session_id,
:join_request_approved => req_approved
@ -347,7 +347,7 @@ module JamRuby
:created_at => created_at
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::JOIN_REQUEST_REJECTED,
:route_to => SESSION_TARGET_PREFIX + session_id,
:join_request_rejected => req_rejected
@ -361,7 +361,7 @@ module JamRuby
:msg => msg
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::SESSION_JOIN,
:route_to => CLIENT_TARGET,
:session_join => join
@ -376,7 +376,7 @@ module JamRuby
:recording_id => recording_id
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::SESSION_DEPART,
:route_to => CLIENT_TARGET,
:session_depart => left
@ -392,7 +392,7 @@ module JamRuby
:created_at => created_at
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::MUSICIAN_SESSION_JOIN,
:route_to => USER_TARGET_PREFIX + receiver_id,
:musician_session_join => musician_session_join
@ -408,7 +408,7 @@ module JamRuby
:created_at => created_at
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::BAND_SESSION_JOIN,
:route_to => USER_TARGET_PREFIX + receiver_id,
:band_session_join => band_session_join
@ -424,7 +424,7 @@ module JamRuby
:created_at => created_at
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::MUSICIAN_RECORDING_SAVED,
:route_to => USER_TARGET_PREFIX + receiver_id,
:musician_recording_saved => musician_recording_saved
@ -440,7 +440,7 @@ module JamRuby
:created_at => created_at
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::BAND_RECORDING_SAVED,
:route_to => USER_TARGET_PREFIX + receiver_id,
:band_recording_saved => band_recording_saved
@ -453,7 +453,7 @@ module JamRuby
:msg => msg
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::RECORDING_STARTED,
:route_to => USER_TARGET_PREFIX + receiver_id,
:recording_started => recording_started
@ -466,14 +466,27 @@ module JamRuby
:msg => msg
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::RECORDING_ENDED,
:route_to => USER_TARGET_PREFIX + receiver_id,
:recording_ended => recording_ended
)
end
def recording_master_mix_complete
def recording_master_mix_complete(receiver_id, recording_id, band_id, msg, notification_id, created_at)
recording_master_mix_complete = Jampb::RecordingMasterMixComplete.new(
:recording_id => recording_id,
:band_id => band_id,
:msg => msg,
:notification_id => notification_id,
:created_at => created_at
)
Jampb::ClientMessage.new(
:type => ClientMessage::Type::RECORDING_MASTER_MIX_COMPLETE,
:route_to => USER_TARGET_PREFIX + receiver_id,
:recording_master_mix_complete => recording_master_mix_complete
)
end
# create a band invitation message
@ -487,7 +500,7 @@ module JamRuby
:created_at => created_at
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::BAND_INVITATION,
:route_to => USER_TARGET_PREFIX + receiver_id,
:band_invitation => band_invitation
@ -504,7 +517,7 @@ module JamRuby
:created_at => created_at
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::BAND_INVITATION_ACCEPTED,
:route_to => USER_TARGET_PREFIX + receiver_id,
:band_invitation_accepted => band_invitation_accepted
@ -520,7 +533,7 @@ module JamRuby
:photo_url => photo_url
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::MUSICIAN_SESSION_FRESH,
:route_to => CLIENT_TARGET,
:musician_session_fresh => fresh
@ -536,18 +549,45 @@ module JamRuby
:photo_url => photo_url
)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::MUSICIAN_SESSION_STALE,
:route_to => CLIENT_TARGET,
:musician_session_stale => stale
)
end
# create a source up requested message to send to clients in a session,
# so that one of the clients will start sending source audio to icecast
def source_up_requested (session_id, host, port, mount, source_user, source_pass)
source_up_requested = Jampb::SourceUpRequested.new(
host: host,
port: port,
mount: mount,
source_user: source_user,
source_pass: source_pass)
Jampb::ClientMessage.new(
type: ClientMessage::Type::SOURCE_UP_REQUESTED,
route_to: SESSION_TARGET_PREFIX + session_id,
source_up_requested: source_up_requested)
end
# create a source up requested message to send to clients in a session,
# so that one of the clients will start sending source audio to icecast
def source_down_requested (session_id, mount)
source_down_requested = Jampb::SourceDownRequested.new(mount: mount)
Jampb::ClientMessage.new(
type: ClientMessage::Type::SOURCE_DOWN_REQUESTED,
route_to: SESSION_TARGET_PREFIX + session_id,
source_down_requested: source_down_requested)
end
# create a test message to send in session
def test_session_message(session_id, msg)
test = Jampb::TestSessionMessage.new(:msg => msg)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::TEST_SESSION_MESSAGE,
:route_to => SESSION_TARGET_PREFIX + session_id,
:test_session_message => test
@ -560,7 +600,7 @@ module JamRuby
def ping_request(client_id, from)
ping_request = Jampb::PingRequest.new()
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::PING_REQUEST,
:route_to => CLIENT_TARGET_PREFIX + client_id,
:from => from,
@ -572,7 +612,7 @@ module JamRuby
def ping_ack(client_id, from)
ping_ack = Jampb::PingAck.new
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::PING_ACK,
:route_to => CLIENT_TARGET_PREFIX + client_id,
:from => from,
@ -584,7 +624,7 @@ module JamRuby
def test_client_message(client_id, from, msg)
test = Jampb::TestClientMessage.new(:msg => msg)
return Jampb::ClientMessage.new(
Jampb::ClientMessage.new(
:type => ClientMessage::Type::TEST_CLIENT_MESSAGE,
:route_to => CLIENT_TARGET_PREFIX + client_id,
:from => from,

View File

@ -14,6 +14,7 @@ module JamRuby
validates :biography, no_profanity: true
before_save :check_lat_lng
before_save :check_website_url
# musicians
has_many :band_musicians, :class_name => "JamRuby::BandMusician"
@ -61,6 +62,13 @@ module JamRuby
return self.music_sessions.size
end
def recent_history
recordings = ClaimedRecording.joins(:recordings).where(:recordings => {:band_id => "#{self.id}"}).limit(10)
msh = MusicSessionHistory.where(:band_id => self.id).limit(10)
recordings.concat(msh)
recordings.sort! {|a,b| b.created_at <=> a.created_at}.first(5)
end
def location
loc = self.city.blank? ? '' : self.city
loc = loc.blank? ? self.state : "#{loc}, #{self.state}" unless self.state.blank?
@ -111,23 +119,6 @@ module JamRuby
return recordings
end
def self.search(query, options = { :limit => 10 })
# only issue search if at least 2 characters are specified
if query.nil? || query.length < 2
return []
end
# create 'anded' statement
query = Search.create_tsquery(query)
if query.nil? || query.length == 0
return []
end
return Band.where("name_tsv @@ to_tsquery('jamenglish', ?)", query).limit(options[:limit])
end
# helper method for creating / updating a Band
def self.save(id, name, website, biography, city, state, country, genres, user_id, photo_url, logo_url)
user = User.find(user_id)
@ -254,6 +245,14 @@ module JamRuby
false
end
def check_website_url
if website_changed? && self.website.present?
self.website.strip!
self.website = "http://#{self.website}" unless self.website =~ /^http/
end
true
end
private
def self.validate_genres(genres, is_nil_ok)
if is_nil_ok && genres.nil?

View File

@ -1,73 +1,37 @@
module JSONable
def jdumpXml (ovb, nm, ident=1, output=$stdout)
serialized = Hash.new
ovb.myattr_accessor.each do |attribute|
#serialized[attribute] = ovb[attribute]
puts "attribute = #{attribute}"
#serialized[attribute] = self.public_send attribute
end
hash = serialized
tb = "\t"
tbs = tb * ident
tbse = tb * (ident-1)
output.puts "#{tbse}<#{nm}>"
hash.each do |key, val|
#puts "attrib: key=#{key} val=#{val}"
el = key
if key.present?
el = key.gsub(/_/, '-')
end
sv = val
if val.to_s.empty?
#skip ???
else
if val.instance_of? String
#encode the string to be xml safe
sv = CGI.escapeHTML(val)
end
end
output.puts "#{tbs}<#{el}>#{sv}</#{el}>"
end
puts "#{tbse}</#{nm}>"
end
end
module JamRuby
class IcecastAdminAuthentication < ActiveRecord::Base
include JSONable
attr_accessible :source_password, :relay_user, :relay_password, :admin_user, :admin_password
#myattr_accessor = [:source_password, :relay_user, :relay_password, :admin_user, :admin_password ]
attr_accessible :source_pass, :relay_user, :relay_pass, :admin_user, :admin_pass, as: :admin
after_initialize :init
has_many :servers, :class_name => "JamRuby::IcecastServer", :inverse_of => :admin_auth, :foreign_key => "admin_auth_id"
has_many :templates, :class_name => "JamRuby::IcecastTemplate", :inverse_of => :admin_auth, :foreign_key => "admin_auth_id"
protected
def init
#set only if nil
self.source_password ||= "UndefinedSourcePassword"
self.admin_password ||= "JKAminPw"
validates :source_pass, presence: true, length: {minimum: 5}
validates :admin_pass, presence: true, length: {minimum: 5}
validates :relay_user, presence: true, length: {minimum: 5}
validates :relay_pass, presence: true, length: {minimum: 5}
validates :admin_user, presence: true, length: {minimum: 5}
after_save :poke_config
def poke_config
IcecastServer.update(servers, config_changed: 1)
templates.each { |template| IcecastServer.update(template.servers, config_changed: 1) }
end
public
self.primary_key = 'id'
validates :source_password, presence: true, length: {minimum: 5}
validates :admin_password, presence: true, length: {minimum: 5}
def dumpXml (ident=1, output=$stdout)
self.jdumpXml(self,"authentication", ident,output)
def to_s
"admin_user=#{admin_user} relay_user=#{relay_user}"
end
def dumpXml (builder)
builder.tag! 'authentication' do |auth|
auth.tag! 'source-password', source_pass
auth.tag! 'admin-user', admin_user
auth.tag! 'relay-user', relay_user
auth.tag! 'relay-password', relay_pass
auth.tag! 'admin-password', admin_pass
end
end
end
end

View File

@ -1,10 +1,31 @@
module JamRuby
class IcecastDirectory < ActiveRecord::Base
self.primary_key = 'id'
attr_accessible :yp_url_timeout, :yp_url, as: :admin
attr_accessible :yp_url_timeout, :yp_url
attr_accessor :yp_url_timeout, :yp_url
has_many :servers, :class_name => "JamRuby::IcecastServer", :inverse_of => :directory, :foreign_key => "directory_id"
has_many :templates, :class_name => "JamRuby::IcecastTemplate", :inverse_of => :directory, :foreign_key => "directory_id"
validates :yp_url_timeout, presence: true, numericality: {only_integer: true}, length: {in: 1..30}
validates :yp_url, presence: true
after_save :poke_config
def poke_config
IcecastServer.update(servers, config_changed: 1)
templates.each { |template| IcecastServer.update(template.servers, config_changed: 1) }
end
def to_s
yp_url
end
def dumpXml (builder)
builder.tag! 'directory' do |dir|
dir.tag! 'yp-url-timeout', yp_url_timeout
dir.tag! 'yp-url', yp_url
end
end
end
end

View File

@ -1,34 +1,44 @@
module JamRuby
class IcecastLimit < ActiveRecord::Base
include JSONable
self.primary_key = 'id'
attr_accessible :clients, :sources, :queue_size, :client_timeout, :header_timeout, :source_timeout, :burst_size,
as: :admin
attr_accessible :clients, :sources, :queue_size, :client_timeout, :header_timeout, :source_timeout, :burst_size
#attr_accessor :clients, :sources, :queue_size, :client_timeout, :header_timeout, :source_timeout, :burst_size
has_many :servers, class_name: 'JamRuby::IcecastServer', inverse_of: :limit, foreign_key: 'limit_id'
has_many :templates, class_name: 'JamRuby::IcecastTemplate', inverse_of: :limit, foreign_key: 'limit_id'
#validates :clients, numericality: {only_integer: true}, length: {in: 1..15000}
validates :clients, numericality: {only_integer: true}
validates :clients, presence: true, numericality: {only_integer: true}, length: {in: 1..15000}
validates :sources, presence: true, numericality: {only_integer: true}, length: {in:1..10000}
validates :queue_size, presence: true, numericality: {only_integer: true}
validates :client_timeout, presence: true, numericality: {only_integer: true}
validates :header_timeout, presence: true, numericality: {only_integer: true}
validates :source_timeout, presence: true, numericality: {only_integer: true}
validates :burst_size, presence: true, numericality: {only_integer: true}
after_initialize :init
after_save :poke_config
def init
self.clients ||= 10000
self.sources ||= 1000
self.queue_size ||= 102400
self.client_timeout ||= 30
self.header_timeout ||= 15
self.source_timeout ||= 10
self.burst_size ||= 65536
def poke_config
IcecastServer.update(servers, config_changed: 1)
templates.each { |template| IcecastServer.update(template.servers, config_changed: 1) }
end
def setclients(val)
@clients = val
def to_s
"clients=#{clients} sources=#{sources}"
end
def dumpXml (ident=1, output=$stdout)
self.jdumpXml(self, "limits", ident, output)
def dumpXml (builder)
builder.tag! 'limits' do |limits|
limits.tag! 'clients', clients
limits.tag! 'sources', sources
limits.tag! 'queue-size', queue_size
limits.tag! 'client-timeout', client_timeout
limits.tag! 'header-timeout', header_timeout
limits.tag! 'source-timeout', source_timeout
limits.tag! 'burst-on-connect', 1
limits.tag! 'burst-size', burst_size
end
end
end
end
end

View File

@ -1,15 +1,35 @@
module JamRuby
class IcecastListenSocket < ActiveRecord::Base
self.primary_key = 'id'
attr_accessible :port, :bind_address, :shoutcast_mount, :shoutcast_compat, as: :admin
attr_accessible :port, :bind_address, :shoutcast_mount, :shoutcast_compat
attr_accessor :port, :bind_address, :shoutcast_mount, :shoutcast_compat
has_many :server_sockets, :class_name => "JamRuby::IcecastServerSocket", :inverse_of => :socket, :foreign_key => 'icecast_listen_socket_id'
has_many :servers, :class_name => "JamRuby::IcecastServer", :through => :server_sockets
def dumpXml()
has_many :template_sockets, :class_name => "JamRuby::IcecastTemplateSocket", :inverse_of => :socket, :foreign_key => 'icecast_listen_socket_id'
has_many :templates, :class_name => "JamRuby::IcecastTemplate", :through => :template_sockets
validates :port, presence: true, numericality: {only_integer: true}, length: {in: 1..65535}
validates :shoutcast_compat, :inclusion => {:in => [nil, 0, 1]}
after_save :poke_config
def poke_config
IcecastServer.update(servers, config_changed: 1)
templates.each { |template| IcecastServer.update(template.servers, config_changed: 1) }
end
def to_s
"port=#{port} bind_address=#{bind_address}"
end
def dumpXml (builder)
builder.tag! 'listen-socket' do |listen|
listen.tag! 'port', port
listen.tag! 'bind-address', bind_address if !bind_address.nil? && !bind_address.empty?
listen.tag! 'shoutcast-mount', shoutcast_mount if shoutcast_mount
listen.tag! 'shoutcast-compat', shoutcast_compat if shoutcast_compat
end
end
end
end

View File

@ -1,14 +1,36 @@
module JamRuby
class IcecastLogging < ActiveRecord::Base
self.primary_key = 'id'
attr_accessible :access_log, :error_log, :playlist_log, :log_level, :log_archive, :log_size, as: :admin
attr_accessible :accesslog, :errorlog, :playlistlog, :loglevel
attr_accessor :accesslog, :errorlog, :playlistlog, :loglevel
has_many :servers, :class_name => "JamRuby::IcecastServer", :inverse_of => :logging, :foreign_key => "logging_id"
has_many :templates, :class_name => "JamRuby::IcecastTemplate", :inverse_of => :logging, :foreign_key => "logging_id"
def dumpXml()
validates :access_log, presence: true
validates :error_log, presence: true
validates :log_level, :inclusion => {:in => [1, 2, 3, 4]}
validates :log_archive, :inclusion => {:in => [nil, 0, 1]}
validates :log_size, numericality: {only_integer: true}, if: lambda {|m| m.log_size.present?}
after_save :poke_config
def poke_config
IcecastServer.update(servers, config_changed: 1)
templates.each { |template| IcecastServer.update(template.servers, config_changed: 1) }
end
def to_s
"access_log=#{access_log} error_log=#{error_log} log_level=#{log_level}"
end
def dumpXml(builder)
builder.tag! 'logging' do |log|
log.tag! 'accesslog', access_log
log.tag! 'errorlog', error_log
log.tag! 'playlistlog', playlist_log if !playlist_log.nil? && !playlist_log.empty?
log.tag! 'logsize', log_size if log_size
log.tag! 'logarchive', log_archive if log_archive
log.tag! 'loglevel', log_level
end
end
end
end

View File

@ -0,0 +1,37 @@
module JamRuby
class IcecastMasterServerRelay < ActiveRecord::Base
attr_accessible :master_server, :master_server_port, :master_update_interval, :master_username, :master_pass,
:relays_on_demand, as: :admin
has_many :servers, :class_name => "JamRuby::IcecastServer", :inverse_of => :master_relay, :foreign_key => "master_relay_id"
has_many :templates, :class_name => "JamRuby::IcecastTemplate", :inverse_of => :master_relay, :foreign_key => "master_relay_id"
validates :master_server, presence: true, length: {minimum: 1}
validates :master_server_port, presence: true, numericality: {only_integer: true}, length: {in: 1..65535}
validates :master_update_interval, presence: true, numericality: {only_integer: true}, length: {in: 1..1200}
validates :master_username, presence: true, length: {minimum: 5}
validates :master_pass, presence: true, length: {minimum: 5}
validates :relays_on_demand, :inclusion => {:in => [0, 1]}
after_save :poke_config
def poke_config
IcecastServer.update(servers, config_changed: 1)
templates.each { |template| IcecastServer.update(template.servers, config_changed: 1) }
end
def to_s
"master_server=#{master_server} master_server_port=#{master_server_port} master_username=#{master_username}"
end
def dumpXml(builder)
builder.tag! 'master-server', master_server
builder.tag! 'master-server-port', master_server_port
builder.tag! 'master-update-interval', master_update_interval
builder.tag! 'master-username', master_username
builder.tag! 'master-password', master_pass
builder.tag! 'relays-on-demand', relays_on_demand
end
end
end

View File

@ -1,12 +0,0 @@
module JamRuby
class IcecastMastersvrRelay < ActiveRecord::Base
self.primary_key = 'id'
attr_accessible :master_server, :master_server_port, :master_username, :master_password, :relays_on_demand
attr_accessible :master_server, :master_server_port, :master_username, :master_password, :relays_on_demand
def dumpXml()
end
end
end

View File

@ -1,24 +1,121 @@
module JamRuby
class IcecastMount < ActiveRecord::Base
self.primary_key = 'id'
attr_accessible :authentication_id, :name, :source_username, :source_pass, :max_listeners, :max_listener_duration,
:dump_file, :intro, :fallback_mount, :fallback_override, :fallback_when_full, :charset, :is_public,
:stream_name, :stream_description, :stream_url, :genre, :bitrate, :mime_type, :subtype, :burst_size,
:mp3_metadata_interval, :hidden, :on_connect, :on_disconnect, as: :admin
attr_accessible :mount_name, :username, :password, :max_listeners, :max_listener_duration, :dump_file
attr_accessor :mount_name, :username, :password, :max_listeners, :max_listener_duration, :dump_file
belongs_to :authentication, class_name: "JamRuby::IcecastUserAuthentication", inverse_of: :mount, :foreign_key => 'authentication_id'
attr_accessible :intro, :fallback_mount, :fallback_override, :fallback_when_full, :charset
attr_accessor :intro, :fallback_mount, :fallback_override, :fallback_when_full, :charset
has_many :server_mounts, :class_name => "JamRuby::IcecastServerMount", :inverse_of => :mount, :foreign_key => 'icecast_mount_id'
has_many :servers, :class_name => "JamRuby::IcecastServer", :through => :server_mounts, :source => :server
attr_accessible :publicc, :stream_name, :stream_description, :stream_url, :genre, :bitrate
attr_accessor :publicc, :stream_name, :stream_description, :stream_url, :genre, :bitrate
validates :name, presence: true
validates :source_username, length: {minimum: 5}, if: lambda {|m| m.source_username.present?}
validates :source_pass, length: {minimum: 5}, if: lambda {|m| m.source_pass.present?}
validates :max_listeners, length: {in: 1..15000}, if: lambda {|m| m.max_listeners.present?}
validates :max_listener_duration, length: {in: 1..3600 * 48}, if: lambda {|m| m.max_listener_duration.present?}
validates :fallback_override, :inclusion => {:in => [0, 1]} , if: lambda {|m| m.fallback_mount.present?}
validates :fallback_when_full, :inclusion => {:in => [0, 1]} , if: lambda {|m| m.fallback_mount.present?}
validates :is_public, presence: true, :inclusion => {:in => [-1, 0, 1]}
validates :stream_name, presence: true
validates :stream_description, presence: true
validates :stream_url, presence: true
validates :genre, presence: true
validates :bitrate, numericality: {only_integer: true}, if: lambda {|m| m.bitrate.present?}
validates :mime_type, presence: true
validates :subtype, presence: true
validates :burst_size, numericality: {only_integer: true}, if: lambda {|m| m.burst_size.present?}
validates :mp3_metadata_interval, numericality: {only_integer: true}, if: lambda {|m| m.mp3_metadata_interval.present?}
validates :hidden, :inclusion => {:in => [0, 1]}
validate :name_has_correct_format
attr_accessible :mtype, :subtype, :hidden, :burst_size, :mp3_metadata_interval, :on_connect, :on_disconnect
attr_accessor :mtype, :subtype, :hidden, :burst_size, :mp3_metadata_interval, :on_connect, :on_disconnect
before_save :sanitize_active_admin
after_save :after_save
after_commit :after_commit
has_one :authentication, :class_name => "IcecastUserAuthentication"
def name_has_correct_format
errors.add(:name, "must start with /") unless name && name.start_with?('/')
end
def dumpXml()
def after_save
IcecastServer.update(servers, config_changed: 1)
# transiting to sourced from not sourced
if !sourced_was && sourced
end
end
def sanitize_active_admin
self.authentication_id = nil if self.authentication_id == ''
end
def source_up
with_lock do
self.sourced = true
self.save(:validate => false)
end
end
def source_down
with_lock do
sourced = false
save(:validate => false)
end
end
def listener_add
with_lock do
increment!(:listeners)
end
end
def listener_remove
with_lock do
decrement!(:listeners)
end
end
def dumpXml(builder)
builder.tag! 'mount' do |mount|
mount.tag! 'mount-name', name
mount.tag! 'username', source_username if !source_username.nil? && !source_username.empty?
mount.tag! 'password', source_pass if !source_pass.nil? && !source_pass.empty?
mount.tag! 'max-listeners', max_listeners unless max_listeners.nil?
mount.tag! 'max-listener-duration', max_listener_duration unless max_listener_duration.nil?
mount.tag! 'dump-file', dump_file if !dump_file.nil? && !dump_file.empty?
mount.tag! 'intro', intro if !intro.nil? && !intro.empty?
mount.tag! 'fallback-mount', fallback_mount if !fallback_mount.nil? && !fallback_mount.empty?
mount.tag! 'fallback-override', fallback_override if fallback_override
mount.tag! 'fallback-when-full', fallback_when_full if fallback_when_full
mount.tag! 'charset', charset if charset
mount.tag! 'public', is_public
mount.tag! 'stream-name', stream_name if !stream_name.nil? && !stream_name.empty?
mount.tag! 'stream-description', stream_description if !stream_description.nil? && !stream_description.empty?
mount.tag! 'stream-url', stream_url if !stream_url.nil? && !stream_url.empty?
mount.tag! 'genre', genre unless genre.empty?
mount.tag! 'bitrate', bitrate if bitrate
mount.tag! 'type', mime_type
mount.tag! 'subtype', subtype
mount.tag! 'burst-size', burst_size if burst_size
mount.tag! 'mp3-metadata-interval', mp3_metadata_interval unless mp3_metadata_interval.nil?
mount.tag! 'hidden', hidden
mount.tag! 'on-connect', on_connect if on_connect
mount.tag! 'on-disconnect', on_disconnect if on_disconnect
authentication.dumpXml(builder) if authentication
end
end
def get_media_url
raise "Unassociated server to mount" if self.server_mount.nil?
"http://" + server_mount.server.hostname + self.name
end
end
end

View File

@ -1,14 +1,40 @@
module JamRuby
class IcecastPath < ActiveRecord::Base
self.primary_key = 'id'
attr_accessible :base_dir, :log_dir, :pid_file, :web_root, :admin_root, :allow_ip, :deny_ip, :alias_source,
:alias_dest, as: :admin
attr_accessible :basedir, :logdir, :pidfile, :webroot, :adminroot, :allow_ip, :deny_ip, :aliass
attr_accessor :basedir, :logdir, :pidfile, :webroot, :adminroot, :allow_ip, :deny_ip, :aliass
has_many :servers, :class_name => "JamRuby::IcecastServer", :inverse_of => :path, :foreign_key => "path_id"
has_many :templates, :class_name => "JamRuby::IcecastTemplate", :inverse_of => :path, :foreign_key => "path_id"
def dumpXml()
validates :base_dir, presence: true
validates :log_dir, presence: true
validates :web_root, presence: true
validates :admin_root, presence: true
after_save :poke_config
def poke_config
IcecastServer.update(servers, config_changed: 1)
templates.each { |template| IcecastServer.update(template.servers, config_changed: 1) }
end
def to_s
"base_dir=#{base_dir}"
end
def dumpXml (builder)
builder.tag! 'paths' do |paths|
paths.tag! 'basedir', base_dir
paths.tag! 'logdir', log_dir
paths.tag! 'pidfile', pid_file if !pid_file.nil? && !pid_file.empty?
paths.tag! 'webroot', web_root
paths.tag! 'adminroot', admin_root
paths.tag! 'allow-ip', allow_ip if allow_ip
paths.tag! 'deny-ip', deny_ip if deny_ip
paths.tag! 'alias', :source => alias_source, :dest => alias_dest if !alias_source.nil? && !alias_source.empty?
end
end
end
end

View File

@ -1,14 +1,39 @@
module JamRuby
class IcecastRelay < ActiveRecord::Base
self.primary_key = 'id'
attr_accessible :server, :port, :mount, :local_mount, :relay_username, :relay_pass, :relay_shoutcast_metadata, :on_demand,
as: :admin
attr_accessible :server, :port, :mount, :local_mount, :username, :password, :relay_shoutcast_metadata, :on_demand
attr_accessor :server, :port, :mount, :local_mount, :username, :password, :relay_shoutcast_metadata, :on_demand
has_many :server_relays, :class_name => "JamRuby::IcecastServerRelay"
has_many :servers, :class_name => "JamRuby::IcecastServer", :through => :server_relays, :source => :server
def dumpXml()
validates :port, presence: true, numericality: {only_integer: true}, length: {in: 1..65535}
validates :mount, presence: true
validates :server, presence: true
validates :relay_shoutcast_metadata, :inclusion => {:in => [0, 1]}
validates :on_demand, presence: true, :inclusion => {:in => [0, 1]}
after_save :poke_config
def poke_config
IcecastServer.update(servers, :config_changed => true)
end
def to_s
mount
end
def dumpXml (builder)
builder.tag! 'relay' do |listen|
listen.tag! 'server', server
listen.tag! 'port', port
listen.tag! 'mount', mount
listen.tag! 'local-mount', local_mount if !local_mount.nil? && !local_mount.empty?
listen.tag! 'username', relay_username if !relay_username.nil? && !relay_username.empty?
listen.tag! 'password', relay_pass if !relay_pass.nil? && !pasword.empty?
listen.tag! 'relay-shoutcast-metadata', relay_shoutcast_metadata
listen.tag! 'on-demand', on_demand
end
end
end
end

View File

@ -0,0 +1,34 @@
module JamRuby
class IcecastSecurity < ActiveRecord::Base
attr_accessible :chroot, :change_owner_user, :change_owner_group, as: :admin
has_many :servers, :class_name => "JamRuby::IcecastServer", :inverse_of => :security, :foreign_key => "security_id"
has_many :templates, :class_name => "JamRuby::IcecastTemplate", :inverse_of => :security, :foreign_key => "security_id"
validates :chroot, :inclusion => {:in => [0, 1]}
after_save :poke_config
def poke_config
IcecastServer.update(servers, config_changed: 1)
templates.each { |template| IcecastServer.update(template.servers, config_changed: 1) }
end
def to_s
"chroot=#{chroot} change_owner_user=#{change_owner_user} change_owner_group=#{change_owner_group}"
end
def dumpXml(builder)
builder.tag! 'security' do |security|
security.tag! 'chroot', chroot
if change_owner_user
security.tag! 'changeowner' do
security.tag! 'user', change_owner_user
security.tag! 'group', change_owner_group
end
end
end
end
end
end

View File

@ -1,14 +0,0 @@
module JamRuby
class IcecastSecurity < ActiveRecord::Base
self.primary_key = 'id'
attr_accessible :chroot, :changeowner_user, :changeowner_group
attr_accessor :chroot, :changeowner_user, :changeowner_group
def dumpXml()
end
end
end

View File

@ -1,23 +1,124 @@
module JamRuby
class IcecastServer < ActiveRecord::Base
self.primary_key = 'id'
attr_accessor :skip_config_changed_flag
has_one :limit, :class_name => "JamRuby::IcecastLimit"
has_one :adminauth, :class_name => "JamRuby::IcecastAdminAuthentication"
has_one :directory, :class_name => "JamRuby::IcecastDirectory"
has_one :misc, :class_name => "JamRuby::IcecastServermisc"
has_many :listen_sockets, :class_name => "JamRuby::IcecastListenSocket"
has_one :master_relay, :class_name => "JamRuby::IcecastMastersvrRelay"
has_one :relay, :class_name => "JamRuby::IcecastRelay"
has_many :mounts, :class_name => "JamRuby::IcecastMount"
has_one :path, :class_name => "JamRuby::IcecastPath"
has_one :logging, :class_name => "JamRuby::IcecastLogging"
has_one :security, :class_name => "JamRuby::IceCastSecurity"
attr_accessible :template_id, :limit_id, :admin_auth_id, :directory_id, :master_relay_id, :path_id, :logging_id,
:security_id, :config_changed, :hostname, :location, :admin_email, :fileserve, as: :admin
def dumpXml()
belongs_to :template, :class_name => "JamRuby::IcecastTemplate", foreign_key: 'template_id', :inverse_of => :servers
# all are overrides, because the template defines all of these as well. When building the XML, we will prefer these if set
belongs_to :limit, :class_name => "JamRuby::IcecastLimit", foreign_key: 'limit_id', :inverse_of => :servers
belongs_to :admin_auth, :class_name => "JamRuby::IcecastAdminAuthentication", foreign_key: 'admin_auth_id', :inverse_of => :servers
belongs_to :directory, :class_name => "JamRuby::IcecastDirectory", foreign_key: 'directory_id', :inverse_of => :servers
belongs_to :master_relay, :class_name => "JamRuby::IcecastMasterServerRelay", foreign_key: 'master_relay_id', :inverse_of => :servers
belongs_to :path, :class_name => "JamRuby::IcecastPath", foreign_key: 'path_id', :inverse_of => :servers
belongs_to :logging, :class_name => "JamRuby::IcecastLogging", foreign_key: 'logging_id', :inverse_of => :servers
belongs_to :security, :class_name => "JamRuby::IcecastSecurity", foreign_key: 'security_id', :inverse_of => :servers
has_many :listen_socket_servers, :class_name => "JamRuby::IcecastServerSocket", :inverse_of => :server
has_many :listen_sockets, :class_name => "JamRuby::IcecastListenSocket", :through => :listen_socket_servers, :source => :socket
# mounts and relays are naturally server-specific, though
has_many :server_mounts, :class_name => "JamRuby::IcecastServerMount", :inverse_of => :server
has_many :mounts, :class_name => "JamRuby::IcecastMount", :through => :server_mounts, :source => :mount
has_many :server_relays, :class_name => "JamRuby::IcecastServerRelay", :inverse_of => :relay
has_many :relays, :class_name => "JamRuby::IcecastRelay", :through => :server_relays, :source => :relay
validates :config_changed, :inclusion => {:in => [0, 1]}
validates :hostname, presence: true
validates :fileserve, :inclusion => {:in => [0, 1]}, :if => lambda {|s| s.fileserve.present? }
validates :server_id, presence: true
validates :template, presence: true
before_save :before_save, unless: lambda { skip_config_changed_flag }
before_save :sanitize_active_admin
after_save :after_save
def before_save
self.config_changed = 1
end
def sanitize_active_admin
self.template_id = nil if self.template_id == ''
self.limit_id = nil if self.limit_id == ''
self.admin_auth_id = nil if self.admin_auth_id == ''
self.directory_id = nil if self.directory_id == ''
self.master_relay_id = nil if self.master_relay_id == ''
self.path_id = nil if self.path_id == ''
self.logging_id = nil if self.logging_id == ''
self.security_id = nil if self.security_id == ''
end
def after_save
# if we set config_changed, then queue up a job
if config_changed_was == 0 && config_changed == 1
IcecastConfigWriter.enqueue(self.server_id)
end
end
# this method is the correct way to set config_changed to false
# if you don't do it this way, then likely you'll get into a loop
# config_changed = true, enqueued job, job executes, job accidentally flags config_changed by touching the model, and repeat
def config_updated
self.skip_config_changed_flag = true
self.config_changed = 0
begin
self.save!
rescue
raise
ensure
self.skip_config_changed_flag = false
end
end
def to_s
return server_id
end
def dumpXml (output=$stdout, indent=1)
builder = ::Builder::XmlMarkup.new(:target => output, :indent => indent)
builder.tag! 'icecast' do |root|
root.tag! 'hostname', hostname
root.tag! 'location', (location.nil? || location.empty?) ? template.location : location
root.tag! 'server-id', server_id
root.tag! 'admin', (admin_email.nil? || admin_email.empty?) ? template.admin_email : admin_email
root.tag! 'fileserve', fileserve.nil? ? template.fileserve : fileserve
# do we have an override specified? or do we go with the template
current_limit = limit ? limit : template.limit
current_admin_auth = admin_auth ? admin_auth : template.admin_auth
current_directory = directory ? directory : template.directory
current_master_relay = master_relay ? master_relay : template.master_relay
current_path = path ? path : template.path
current_logging = logging ? logging : template.logging
current_security = security ? security : template.security
current_listen_sockets = listen_sockets.length > 0 ? listen_sockets : template.listen_sockets
current_limit.dumpXml(builder) unless current_limit.nil?
current_admin_auth.dumpXml(builder) unless current_admin_auth.nil?
current_directory.dumpXml(builder) unless current_directory.nil?
current_master_relay.dumpXml(builder) unless current_master_relay.nil?
current_path.dumpXml(builder) unless current_path.nil?
current_logging.dumpXml(builder) unless current_logging.nil?
current_security.dumpXml(builder) unless current_security.nil?
current_listen_sockets.each do |listen_socket|
listen_socket.dumpXml(builder)
end
relays.each do |relay|
relay.dumpXml(builder)
end
mounts.each do |mount|
mount.dumpXml(builder)
end
end
end
end
end

View File

@ -0,0 +1,13 @@
module JamRuby
class IcecastServerMount < ActiveRecord::Base
self.table_name = 'icecast_server_mounts'
attr_accessible :icecast_mount_id, :icecast_server_id, as: :admin
belongs_to :mount, :class_name => "JamRuby::IcecastMount", :foreign_key => 'icecast_mount_id', :inverse_of => :server_mounts
belongs_to :server, :class_name => "JamRuby::IcecastServer", :foreign_key => 'icecast_server_id', :inverse_of => :server_mounts
validates :server, :presence => true
validates :mount, :presence => true
end
end

View File

@ -0,0 +1,16 @@
module JamRuby
class IcecastServerRelay < ActiveRecord::Base
self.table_name = 'icecast_server_relays'
attr_accessible :icecast_relay_id, :icecast_server_id, as: :admin
belongs_to :relay, :class_name => "JamRuby::IcecastRelay", :foreign_key => 'icecast_relay_id', :inverse_of => :server_relays
belongs_to :server, :class_name => "JamRuby::IcecastServer", :foreign_key => 'icecast_server_id', :inverse_of => :server_relays
validates :server, :presence => true
validates :relay, :presence => true
end
end

View File

@ -0,0 +1,15 @@
module JamRuby
class IcecastServerSocket < ActiveRecord::Base
self.table_name = 'icecast_server_sockets'
attr_accessible :icecast_listen_socket_id, :icecast_server_id, as: :admin
belongs_to :socket, :class_name => "JamRuby::IcecastListenSocket", :foreign_key => 'icecast_listen_socket_id', :inverse_of => :server_sockets
belongs_to :server, :class_name => "JamRuby::IcecastServer", :foreign_key => 'icecast_server_id', :inverse_of => :listen_socket_servers
validates :socket, :presence => true
validates :server, :presence => true
end
end

View File

@ -1,14 +0,0 @@
module JamRuby
class IcecastServermisc < ActiveRecord::Base
self.primary_key = 'id'
attr_accessible :hostname, :location, :admin, :fileserve, :server_id
attr_accessor :hostname, :location, :admin, :fileserve, :server_id
def dumpXml()
end
end
end

View File

@ -0,0 +1,53 @@
module JamRuby
class IcecastTemplate < ActiveRecord::Base
attr_accessible :limit_id, :admin_auth_id, :directory_id, :master_relay_id, :path_id, :logging_id,
:security_id, :name, :location, :admin_email, :fileserve, as: :admin
belongs_to :limit, :class_name => "JamRuby::IcecastLimit", foreign_key: 'limit_id', :inverse_of => :templates
belongs_to :admin_auth, :class_name => "JamRuby::IcecastAdminAuthentication", foreign_key: 'admin_auth_id', :inverse_of => :templates
belongs_to :directory, :class_name => "JamRuby::IcecastDirectory", foreign_key: 'directory_id', :inverse_of => :templates
belongs_to :master_relay, :class_name => "JamRuby::IcecastMasterServerRelay", foreign_key: 'master_relay_id', :inverse_of => :templates
belongs_to :path, :class_name => "JamRuby::IcecastPath", foreign_key: 'path_id', :inverse_of => :templates
belongs_to :logging, :class_name => "JamRuby::IcecastLogging", foreign_key: 'logging_id', :inverse_of => :templates
belongs_to :security, :class_name => "JamRuby::IcecastSecurity", foreign_key: 'security_id', :inverse_of => :templates
has_many :servers, :class_name => "JamRuby::IcecastServer", :inverse_of => :template, :foreign_key => "template_id"
#has_many :server_mounts, class_name: "JamRuby::IcecastServerMount", :inverse_of => :mount, :foreign_key
#has_many :mounts, class_name: "JamRuby::IcecastMount", through: :server_mounts, :source => :template
has_many :listen_socket_templates, :class_name => "JamRuby::IcecastTemplateSocket", :inverse_of => :template, :foreign_key => 'icecast_template_id'
has_many :listen_sockets, :class_name => "JamRuby::IcecastListenSocket", :through => :listen_socket_templates , :source => :socket
validates :name, presence: true
validates :location, presence: true
validates :admin_email, presence: true
validates :fileserve, :inclusion => {:in => [0, 1]}
validates :limit, presence: true
validates :admin_auth, presence: true
validates :path, presence: true
validates :logging, presence: true
validates :security, presence: true
validates :listen_sockets, length: {minimum: 1}
before_save :sanitize_active_admin
after_save :poke_config
def poke_config
IcecastServer.update(servers, config_changed: 1)
end
def sanitize_active_admin
self.limit_id = nil if self.limit_id == ''
self.admin_auth_id = nil if self.admin_auth_id == ''
self.directory_id = nil if self.directory_id == ''
self.master_relay_id = nil if self.master_relay_id == ''
self.path_id = nil if self.path_id == ''
self.logging_id = nil if self.logging_id == ''
self.security_id = nil if self.security_id == ''
end
end
end

View File

@ -0,0 +1,15 @@
module JamRuby
class IcecastTemplateSocket < ActiveRecord::Base
self.table_name = 'icecast_template_sockets'
attr_accessible :icecast_listen_socket_id, :icecast_template_id, as: :admin
belongs_to :socket, :class_name => "JamRuby::IcecastListenSocket", :foreign_key => 'icecast_listen_socket_id', :inverse_of => :template_sockets
belongs_to :template, :class_name => "JamRuby::IcecastTemplate", :foreign_key => 'icecast_template_id', :inverse_of => :listen_socket_templates
validates :socket, :presence => true
validates :template, :presence => true
end
end

View File

@ -1,17 +1,60 @@
module JamRuby
class IcecastUserAuthentication < ActiveRecord::Base
self.primary_key = 'id'
attr_accessible :authentication_type, :filename, :allow_duplicate_users, :mount_add, :mount_remove, :listener_add,
:listener_remove, :unused_username, :unused_pass, :auth_header, :timelimit_header, as: :admin
attr_accessible :stype, :filename, :allow_duplicate_users, :mount_add, :mount_remove,
:listener_add, :listener_remove, :username, :password, :auth_header, :timelimit_header
has_one :mount, class_name: 'JamRuby::IcecastMount', inverse_of: :authentication, :foreign_key => 'authentication_id'
attr_accessor :stype, :filename, :allow_duplicate_users, :mount_add, :mount_remove,
:listener_add, :listener_remove, :username, :password, :auth_header, :timelimit_header
validates :authentication_type, presence: true, :inclusion => {:in => ["url", "htpasswd"]}
validates :allow_duplicate_users, :inclusion => {:in => [0, 1]}, if: :htpasswd_auth?
validates :unused_username, length: {minimum: 5}, if: :url_auth_and_user_present?
validates :unused_pass, length: {minimum: 5}, if: :url_auth_and_pass_present?
validates :mount_add, presence: true, if: :url_auth?
validates :mount_remove, presence: true, if: :url_auth?
validates :listener_add, presence: true, if: :url_auth?
validates :listener_remove, presence: true, if: :url_auth?
validates :auth_header, presence: true, if: :url_auth?
validates :timelimit_header, presence: true, if: :url_auth?
after_save :poke_config
def dumpXml()
def poke_config
IcecastServer.update(mount.servers, config_changed: 1) if mount
end
def to_s
"mount=#{mount} username=#{unused_username} auth_header=#{auth_header} timelimit_header=#{timelimit_header}"
end
def dumpXml (builder)
builder.tag! 'authentication', type: authentication_type do |auth|
auth.tag! 'option', name: 'mount_add', value: mount_add if !mount_add.nil? && !mount_remove.empty?
auth.tag! 'option', name: 'mount_remove', value: mount_remove if !mount_remove.nil? && !mount_remove.empty?
auth.tag! 'option', name: 'username', value: unused_username if !unused_username.nil? && !unused_username.empty?
auth.tag! 'option', name: 'password', value: unused_pass if !unused_pass.nil? && !unused_pass.empty?
auth.tag! 'option', name: 'listener_add', value: listener_add if !listener_add.nil? && !listener_add.empty?
auth.tag! 'option', name: 'listener_remove', value: listener_remove if !listener_remove.nil? && !listener_remove.empty?
auth.tag! 'option', name: 'auth_header', value: auth_header if !auth_header.nil? && !auth_header.empty?
auth.tag! 'option', name: 'timelimit_header', value: timelimit_header if !timelimit_header.nil? && !timelimit_header.empty?
end
end
def htpasswd_auth?
authentication_type == 'htpasswd'
end
def url_auth?
authentication_type == 'url'
end
def url_auth_and_user_present?
url_auth? && self.unused_username.present?
end
def url_auth_and_pass_present?
url_auth? && self.unused_pass.present?
end
end
end

View File

@ -33,6 +33,7 @@ module JamRuby
false
end
# avoid db validations
Mix.where(:id => self.id).update_all(:started_at => Time.now)
true
@ -56,9 +57,7 @@ module JamRuby
self.md5 = md5
self.completed = true
if save
recording.users.each do |user|
Notification.send_download_available(user.id)
end
Notification.send_recording_master_mix_complete(recording)
end
end
@ -96,12 +95,6 @@ module JamRuby
s3_manager.sign_url(self.url, {:expires => expiration_time, :content_type => 'audio/ogg', :secure => false}, :put)
end
def self.queue_jobs_needing_retry
Mix.find_each(:conditions => 'should_retry = TRUE or started_at is NULL', :batch_size => 100) do |mix|
mix.enqueue
end
end
private
def delete_s3_files

View File

@ -15,11 +15,11 @@ module JamRuby
:foreign_key => :band_id,
:inverse_of => :music_session_history)
has_many :music_session_history_users, :class_name => "JamRuby::MusicSessionUserHistory", :foreign_key => "music_session_id"
has_many :music_session_user_history, :class_name => "JamRuby::MusicSessionUserHistory", :foreign_key => "music_session_id"
has_many :comments, :class_name => "JamRuby::MusicSessionComment", :foreign_key => "music_session_id"
has_many :likes, :class_name => "JamRuby::MusicSessionLiker", :foreign_key => "music_session_id"
GENRE_SEPARATOR = '|'
SEPARATOR = '|'
def comment_count
self.comments.size
@ -29,6 +29,21 @@ module JamRuby
self.likes.size
end
def tracks
tracks = []
self.music_session_user_history.each do |msuh|
user = User.find(msuh.user_id)
instruments = msuh.instruments.split(SEPARATOR)
instruments.each do |instrument|
t = Track.new
t.user = user
t.instrument_id = instrument
tracks << t
end
end
tracks
end
def self.index(current_user, user_id, band_id = nil, genre = nil)
hide_private = false
if current_user.id != user_id
@ -75,7 +90,7 @@ module JamRuby
session_history.description = music_session.description unless music_session.description.nil?
session_history.user_id = music_session.creator.id
session_history.band_id = music_session.band.id unless music_session.band.nil?
session_history.genres = music_session.genres.map { |g| g.id }.join GENRE_SEPARATOR
session_history.genres = music_session.genres.map { |g| g.id }.join SEPARATOR
session_history.save!
end

View File

@ -27,7 +27,7 @@ module JamRuby
@perfdata ||= JamRuby::MusicSessionPerfData.find_by_client_id(self.client_id)
end
def self.save(music_session_id, user_id, client_id)
def self.save(music_session_id, user_id, client_id, tracks)
return true if 0 < self.where(:music_session_id => music_session_id,
:user_id => user_id,
:client_id => client_id).count
@ -35,6 +35,7 @@ module JamRuby
session_user_history.music_session_id = music_session_id
session_user_history.user_id = user_id
session_user_history.client_id = client_id
session_user_history.instruments = tracks.map {|t| t.instrument_id}.join("|")
session_user_history.save
end

View File

@ -11,6 +11,8 @@ module JamRuby
belongs_to :session, :class_name => "JamRuby::MusicSession", :foreign_key => "session_id"
belongs_to :recording, :class_name => "JamRuby::Recording", :foreign_key => "recording_id"
validates :target_user, :presence => true
def index(user_id)
Notification.where(:target_user_id => user_id).limit(50)
end
@ -658,6 +660,23 @@ module JamRuby
end
def send_recording_master_mix_complete(recording)
# only people who get told about mixes are folks who claimed it... not everyone in the session
recording.claimed_recordings.each do |claimed_recording|
notification = Notification.new
notification.band_id = recording.band.id if recording.band
notification.recording_id = recording.id
notification.target_user_id = claimed_recording.user_id
notification.description = NotificationTypes::RECORDING_MASTER_MIX_COMPLETE
notification.save
notification_msg = format_msg(notification.description, nil, recording.band)
msg = @@message_factory.recording_master_mix_complete(claimed_recording.user_id, recording.id, notification.band_id, notification_msg, notification.id, notification.created_at.to_s)
@@mq_router.publish_to_user(claimed_recording.user_id, msg)
end
end
def send_band_invitation(band, band_invitation, sender, receiver)
@ -741,12 +760,23 @@ module JamRuby
@@mq_router.server_publish_to_session(music_session, msg, sender = {:client_id => client_id})
end
def send_download_available(user_id)
msg = @@message_factory.download_available
@@mq_router.publish_to_user(user_id, msg)
end
def send_source_up_requested(music_session, host, port, mount, source_user, source_pass)
msg = @@message_factory.source_up_requested(music_session.id, host, port, mount, source_user, source_pass)
@@mg_router.server_publish_to_session(music_session, msg)
end
def send_source_down_requested(music_session, mount)
msg = @@message_factory.source_down_requested(music_session.id, mount)
@@mq_router.server_publish_to_session(music_session, msg)
end
end
end
end

View File

@ -1,73 +1,64 @@
module JamRuby
# not a active_record model; just a search result
# not a active_record model; just a search result container
class Search
attr_accessor :bands, :musicians, :fans, :recordings, :friends, :search_type
attr_accessor :bands_filter, :musicians_filter
attr_accessor :results, :search_type
attr_accessor :user_counters, :page_num, :page_count
LIMIT = 10
# performs a site-white search
def self.search(query, user_id = nil)
SEARCH_TEXT_TYPES = [:musicians, :bands, :fans]
SEARCH_TEXT_TYPE_ID = :search_text_type
users = User.search(query, :limit => LIMIT)
bands = Band.search(query, :limit => LIMIT)
# NOTE: I removed recordings from search here. This is because we switched
# to "claimed_recordings" so it's not clear what should be searched.
friends = Friendship.search(query, user_id, :limit => LIMIT)
return Search.new(users + bands + friends)
def self.band_search(txt, user = nil)
self.text_search({ SEARCH_TEXT_TYPE_ID => :bands, :query => txt }, user)
end
# performs a friend search scoped to a specific user
# def self.search_by_user(query, user_id)
# friends = Friendship.search(query, user_id, :limit => LIMIT)
# return Search.new(friends)
# end
def self.fan_search(txt, user = nil)
self.text_search({ SEARCH_TEXT_TYPE_ID => :fans, :query => txt }, user)
end
def self.musician_search(txt, user = nil)
self.text_search({ SEARCH_TEXT_TYPE_ID => :musicians, :query => txt }, user)
end
def self.text_search(params, user = nil)
srch = Search.new
unless (params.blank? || params[:query].blank? || 2 > params[:query].length)
srch.text_search(params, user)
end
srch
end
def text_search(params, user = nil)
tsquery = Search.create_tsquery(params[:query])
return [] if tsquery.blank?
rel = case params[SEARCH_TEXT_TYPE_ID].to_s
when 'bands'
@search_type = :bands
Band.scoped
when 'fans'
@search_type = :fans
User.fans
else
@search_type = :musicians
User.musicians
end
@results = rel.where("(name_tsv @@ to_tsquery('jamenglish', ?))", tsquery).limit(10)
@results
end
# search_results - results from a Tire search across band/user/recording
def initialize(search_results=nil)
@bands = []
@musicians = []
@fans = []
@recordings = []
@friends = []
@musicians_filter = []
@bands_filter = []
if search_results.nil?
return
end
search_results.take(LIMIT).each do |result|
if result.class == User
if result.musician
@musicians.push(result)
else
@fans.push(result)
end
elsif result.class == Band
@bands.push(result)
elsif result.class == Recording
@recordings.push(result)
elsif result.class == Friendship
@friends.push(result.friend)
else
raise Exception, "unknown class #{result.class} returned in search results"
end
end
@results = []
self
end
def self.create_tsquery(query)
# empty queries don't hit back to elasticsearch
if query.nil? || query.length == 0
return nil
end
return nil if query.blank?
search_terms = query.split
if search_terms.length == 0
return nil
end
return nil if search_terms.length == 0
args = nil
search_terms.each do |search_term|
@ -76,15 +67,11 @@ module JamRuby
else
args = args + " & " + search_term
end
end
args = args + ":*"
return args
args
end
attr_accessor :user_counters, :page_num, :page_count
PARAM_MUSICIAN = :srch_m
PARAM_BAND = :srch_b
@ -105,7 +92,7 @@ module JamRuby
ordering.blank? ? keys[0] : keys.detect { |oo| oo.to_s == ordering }
end
def self.musician_search(params={}, current_user=nil)
def self.musician_filter(params={}, current_user=nil)
rel = User.musicians
unless (instrument = params[:instrument]).blank?
rel = rel.joins("RIGHT JOIN musicians_instruments AS minst ON minst.user_id = users.id")
@ -140,6 +127,7 @@ module JamRuby
objs = rel.all
srch = Search.new
srch.search_type = :musicians_filter
srch.page_num, srch.page_count = page, objs.total_pages
srch.musician_results_for_user(objs, current_user)
end
@ -159,14 +147,14 @@ module JamRuby
COUNT_SESSION = :count_session
COUNTERS = [COUNT_FRIEND, COUNT_FOLLOW, COUNT_RECORD, COUNT_SESSION]
def musician_results_for_user(results, user)
@search_type, @musicians_filter = PARAM_MUSICIAN, results
def musician_results_for_user(_results, user)
@results = _results
if user
@user_counters = results.inject({}) { |hh,val| hh[val.id] = []; hh }
mids = "'#{@musicians_filter.map(&:id).join("','")}'"
@user_counters = @results.inject({}) { |hh,val| hh[val.id] = []; hh }
mids = "'#{@results.map(&:id).join("','")}'"
# this gets counts for each search result on friends/follows/records/sessions
results.each do |uu|
@results.each do |uu|
counters = { }
counters[COUNT_FRIEND] = Friendship.where(:user_id => uu.id).count
counters[COUNT_FOLLOW] = UserFollowing.where(:user_id => uu.id).count
@ -204,6 +192,26 @@ module JamRuby
public
def musicians_text_search?
:musicians == @search_type
end
def fans_text_search?
:fans == @search_type
end
def bands_text_search?
:bands == @search_type
end
def musicians_filter_search?
:musicians_filter == @search_type
end
def bands_filter_search?
:band_filter == @search_type
end
def follow_count(musician)
_count(musician, COUNT_FOLLOW)
end
@ -247,7 +255,7 @@ module JamRuby
end
end
def self.band_search(params={}, current_user=nil)
def self.band_filter(params={}, current_user=nil)
rel = Band.scoped
unless (genre = params[:genre]).blank?
@ -282,18 +290,19 @@ module JamRuby
objs = rel.all
srch = Search.new
srch.search_type = :band_filter
srch.page_num, srch.page_count = page, objs.total_pages
srch.band_results_for_user(objs, current_user)
end
def band_results_for_user(results, user)
@search_type, @bands_filter = PARAM_BAND, results
def band_results_for_user(_results, user)
@results = _results
if user
@user_counters = results.inject({}) { |hh,val| hh[val.id] = []; hh }
mids = "'#{@bands_filter.map(&:id).join("','")}'"
@user_counters = @results.inject({}) { |hh,val| hh[val.id] = []; hh }
mids = "'#{@results.map(&:id).join("','")}'"
# this gets counts for each search result
results.each do |bb|
@results.each do |bb|
counters = { }
counters[COUNT_FOLLOW] = BandFollowing.where(:band_id => bb.id).count
counters[COUNT_RECORD] = Recording.where(:band_id => bb.id).count

View File

@ -51,6 +51,10 @@ module JamRuby
Track.transaction do
connection = Connection.find_by_client_id!(clientId)
# each time tracks are synced we have to update the entry in music_sessions_user_history
msh = MusicSessionUserHistory.find_by_client_id!(clientId)
instruments = []
if tracks.length == 0
connection.tracks.delete_all
else
@ -66,9 +70,11 @@ module JamRuby
to_delete.delete(connection_track)
to_add.delete(track)
# don't update connection_id or client_id; it's unknown what would happen if these changed mid-session
connection_track.instrument = Instrument.find(track[:instrument_id])
connection_track.instrument_id = track[:instrument_id]
connection_track.sound = track[:sound]
connection_track.client_track_id = track[:client_track_id]
instruments << track[:instrument_id]
if connection_track.save
result.push(connection_track)
next
@ -80,10 +86,15 @@ module JamRuby
end
end
msh.instruments = instruments.join("|")
if !msh.save
raise ActiveRecord::Rollback
end
to_add.each do |track|
connection_track = Track.new
connection_track.connection = connection
connection_track.instrument = Instrument.find(track[:instrument_id])
connection_track.instrument_id = track[:instrument_id]
connection_track.sound = track[:sound]
connection_track.client_track_id = track[:client_track_id]
if connection_track.save
@ -94,7 +105,7 @@ module JamRuby
end
end
to_delete.each do| delete_me |
to_delete.each do |delete_me|
delete_me.delete
end
end
@ -105,7 +116,7 @@ module JamRuby
def self.save(id, connection_id, instrument_id, sound, client_track_id)
if id.nil?
track = Track.new()
track = Track.new
track.connection_id = connection_id
else
track = Track.find(id)

View File

@ -140,6 +140,7 @@ module JamRuby
validate :update_email_case_insensitive_uniqueness, :if => :updating_email
scope :musicians, where(:musician => true)
scope :fans, where(:musician => false)
scope :geocoded_users, where(['lat IS NOT NULL AND lng IS NOT NULL'])
scope :musicians_geocoded, musicians.geocoded_users
@ -285,6 +286,13 @@ module JamRuby
def session_count
return self.music_sessions.size
end
def recent_history
recordings = ClaimedRecording.joins(:recording).where(:recordings => {:owner_id => "#{self.id}"}).limit(10)
msh = MusicSessionHistory.where(:user_id => self.id).limit(10)
recordings.concat(msh)
recordings.sort! {|a,b| b.created_at <=> a.created_at}.first(5)
end
def confirm_email!
self.email_confirmed = true
@ -924,31 +932,6 @@ module JamRuby
end
end
def self.search(query, options = { :limit => 10 })
# only issue search if at least 2 characters are specified
if query.nil? || query.length < 2
return []
end
# save query for use in instrument search
search_criteria = query
# create 'anded' statement
query = Search.create_tsquery(query)
if query.nil? || query.length == 0
return []
end
# remove email_confirmed restriction due to VRFS-378
# .where("email_confirmed = true AND (name_tsv @@ to_tsquery('jamenglish', ?) OR users.id in (select user_id from musicians_instruments where instrument_id like '%#{search_criteria.downcase}%'))", query)
return query = User
.where("(name_tsv @@ to_tsquery('jamenglish', ?) OR users.id in (select user_id from musicians_instruments where instrument_id like '%#{search_criteria.downcase}%'))", query)
.limit(options[:limit])
end
def provides_location?
!self.city.blank? && (!self.state.blank? || !self.country.blank?)
end

View File

@ -77,6 +77,8 @@ class MQRouter
# sends a message to a user with no checking of permissions (RAW USAGE)
# this method deliberately has no database interactivity/active_record objects
def publish_to_user(user_id, user_msg)
@@log.warn "EM not running in publish_to_user" unless EM.reactor_running?
EM.schedule do
@@log.debug "publishing to user:#{user_id} from server"
# put it on the topic exchange for users

View File

@ -17,10 +17,20 @@ module JamRuby
:error_reason, :error_detail
def self.perform(mix_id, postback_output_url)
audiomixer = AudioMixer.new()
audiomixer.postback_output_url = postback_output_url
audiomixer.mix_id = mix_id
audiomixer.run
JamWebEventMachine.run_wait_stop do
audiomixer = AudioMixer.new()
audiomixer.postback_output_url = postback_output_url
audiomixer.mix_id = mix_id
audiomixer.run
end
end
def self.queue_jobs_needing_retry
Mix.find_each(:conditions => 'should_retry = TRUE or started_at is NULL', :batch_size => 100) do |mix|
mix.enqueue
end
end
def initialize

View File

@ -0,0 +1,110 @@
require 'json'
require 'resque'
require 'resque-retry'
require 'net/http'
require 'digest/md5'
module JamRuby
# executes a mix of tracks, creating a final output mix
class IcecastConfigWriter
@@log = Logging.logger[IcecastConfigWriter]
attr_accessor :icecast_server_id
def self.queue
queue_name(::APP_CONFIG.icecast_server_id)
end
def self.queue_jobs_needing_retry
# if we haven't seen updated_at be tickled in 5 minutes, but config_changed is still set to TRUE, this record has gotten stale
IcecastServer.find_each(:conditions => "config_changed = 1 AND updated_at < (NOW() - interval '#{APP_CONFIG.icecast_max_missing_check} second')", :batch_size => 100) do |server|
IcecastConfigWriter.enqueue(server.server_id)
end
end
def self.queue_name(server_id)
"icecast-#{server_id}"
end
def self.perform(icecast_server_id)
icecast = IcecastConfigWriter.new()
icecast.icecast_server_id = icecast_server_id
icecast.run
end
def self.enqueue(server_id)
begin
Resque.enqueue_to(queue_name(server_id), IcecastConfigWriter, server_id)
return true
rescue
@@log.error("unable to enqueue IceastConfigWriter(#{server_id}). #{$!}")
# implies redis is down
return false
end
end
def initialize
end
def validate
raise "icecast_server_id not spceified" unless icecast_server_id
raise "queue routing mismatch error" unless icecast_server_id == APP_CONFIG.icecast_server_id
end
def execute(cmd)
system cmd
$?.exitstatus
end
def reload
cmd = APP_CONFIG.icecast_reload_cmd
result = execute(cmd)
raise "unable to execute icecast reload cmd=#{cmd}. result=#{$?}" unless result == 0
end
def run
validate
config_file = APP_CONFIG.icecast_config_file
# check if the config file is there at all; if it's not, we need to generate it regardless if config has changed
query = {server_id: icecast_server_id}
icecast_server = IcecastServer.where(server_id: icecast_server_id).first
raise "can not find icecast server with query #{query}" unless icecast_server
if File.exist?(config_file) && !icecast_server.config_changed
@@log.info("config not changed. skipping run for server: #{icecast_server.server_id}")
else
icecast_server.with_lock do
# don't try to write to the file if for some reason the model isn't valid
# this could happen if an admin mucks around in the db directly
raise "icecast_server.id=#{icecast_server.server_id} not valid. errors=#{icecast_server.errors.inspect}" unless icecast_server.valid?
# write the new config to a temporary location
tmp_config = Dir::Tmpname.make_tmpname(["#{Dir.tmpdir}/icecast", '.xml'], nil)
File.open(tmp_config, 'w') do |f|
icecast_server.dumpXml(f)
end
# if written successfully, overwrite the current file
FileUtils.mv tmp_config, config_file
# reload server
reload
icecast_server.config_updated
end
end
@@log.info("successful update of config for server: #{icecast_server.server_id}")
end
end
end

View File

@ -14,7 +14,7 @@ module JamRuby
@@log = Logging.logger[AudioMixerRetry]
def self.perform
Mix.queue_jobs_needing_retry
AudioMixer.queue_jobs_needing_retry
end
end

View File

@ -0,0 +1,21 @@
require 'json'
require 'resque'
require 'resque-retry'
require 'net/http'
require 'digest/md5'
module JamRuby
# periodically scheduled to find jobs that need retrying
class IcecastConfigRetry
@queue = :icecast_config_retry
@@log = Logging.logger[IcecastConfigRetry]
def self.perform
IcecastConfigWriter.queue_jobs_needing_retry
end
end
end

View File

@ -136,8 +136,142 @@ FactoryGirl.define do
end
factory :promo_buzz, :class => JamRuby::PromoBuzz do
text_short Faker::Lorem.sentence
text_short Faker::Lorem.characters(10)
text_long Faker::Lorem.paragraphs(3).join("\n")
end
factory :icecast_limit, :class => JamRuby::IcecastLimit do
clients 5
sources 1
queue_size 102400
client_timeout 30
header_timeout 15
source_timeout 10
burst_size 65536
end
factory :icecast_admin_authentication, :class => JamRuby::IcecastAdminAuthentication do
source_pass Faker::Lorem.characters(10)
admin_user Faker::Lorem.characters(10)
admin_pass Faker::Lorem.characters(10)
relay_user Faker::Lorem.characters(10)
relay_pass Faker::Lorem.characters(10)
end
factory :icecast_directory, :class => JamRuby::IcecastDirectory do
yp_url_timeout 15
yp_url Faker::Lorem.characters(10)
end
factory :icecast_master_server_relay, :class => JamRuby::IcecastMasterServerRelay do
master_server Faker::Lorem.characters(10)
master_server_port 8000
master_update_interval 120
master_username Faker::Lorem.characters(10)
master_pass Faker::Lorem.characters(10)
relays_on_demand 1
end
factory :icecast_path, :class => JamRuby::IcecastPath do
base_dir Faker::Lorem.characters(10)
log_dir Faker::Lorem.characters(10)
pid_file Faker::Lorem.characters(10)
web_root Faker::Lorem.characters(10)
admin_root Faker::Lorem.characters(10)
end
factory :icecast_logging, :class => JamRuby::IcecastLogging do
access_log Faker::Lorem.characters(10)
error_log Faker::Lorem.characters(10)
log_level 3
log_archive nil
log_size 10000
end
factory :icecast_security, :class => JamRuby::IcecastSecurity do
chroot 0
end
factory :icecast_mount, :class => JamRuby::IcecastMount do
name "/" + Faker::Lorem.characters(10)
source_username Faker::Lorem.characters(10)
source_pass Faker::Lorem.characters(10)
max_listeners 100
max_listener_duration 3600
fallback_mount Faker::Lorem.characters(10)
fallback_override 1
fallback_when_full 1
is_public -1
stream_name Faker::Lorem.characters(10)
stream_description Faker::Lorem.characters(10)
stream_url Faker::Lorem.characters(10)
genre Faker::Lorem.characters(10)
hidden 0
factory :icecast_mount_with_auth do
association :authentication, :factory => :icecast_user_authentication
end
end
factory :icecast_listen_socket, :class => JamRuby::IcecastListenSocket do
port 8000
end
factory :icecast_relay, :class => JamRuby::IcecastRelay do
port 8000
mount Faker::Lorem.characters(10)
server Faker::Lorem.characters(10)
on_demand 1
end
factory :icecast_user_authentication, :class => JamRuby::IcecastUserAuthentication do
authentication_type 'url'
unused_username Faker::Lorem.characters(10)
unused_pass Faker::Lorem.characters(10)
mount_add Faker::Lorem.characters(10)
mount_remove Faker::Lorem.characters(10)
listener_add Faker::Lorem.characters(10)
listener_remove Faker::Lorem.characters(10)
auth_header 'icecast-auth-user: 1'
timelimit_header 'icecast-auth-timelimit:'
end
factory :icecast_server, :class => JamRuby::IcecastServer do
sequence(:hostname) { |n| "hostname-#{n}"}
sequence(:server_id) { |n| "server-#{n}"}
factory :icecast_server_minimal do
association :template, :factory => :icecast_template_minimal
factory :icecast_server_with_overrides do
association :limit, :factory => :icecast_limit
association :admin_auth, :factory => :icecast_admin_authentication
association :path, :factory => :icecast_path
association :logging, :factory => :icecast_logging
association :security, :factory => :icecast_security
before(:create) do |server|
server.listen_sockets << FactoryGirl.build(:icecast_listen_socket)
end
end
end
end
factory :icecast_template, :class => JamRuby::IcecastTemplate do
sequence(:name) { |n| "name-#{n}"}
sequence(:location) { |n| "location-#{n}"}
factory :icecast_template_minimal do
association :limit, :factory => :icecast_limit
association :admin_auth, :factory => :icecast_admin_authentication
association :path, :factory => :icecast_path
association :logging, :factory => :icecast_logging
association :security, :factory => :icecast_security
before(:create) do |template|
template.listen_sockets << FactoryGirl.build(:icecast_listen_socket)
end
end
end
end

View File

@ -45,10 +45,6 @@ describe ConnectionManager do
end
end
it "can't create bogus user_id" do
expect { @connman.create_connection("aeonuthaoentuh", "client_id", "1.1.1.1") }.to raise_error(PG::Error)
end
it "can't create two client_ids of same value" do
client_id = "client_id1"
@ -428,7 +424,6 @@ describe ConnectionManager do
@connman.delete_connection(client_id)
assert_num_connections(client_id, 0)
end
end

View File

@ -25,15 +25,15 @@ describe 'Band search' do
it "finds all bands" do
# expects all the bands
num = Band.count
results = Search.band_search({ :per_page => num })
expect(results.bands_filter.count).to eq(num)
results = Search.band_filter({ :per_page => num })
expect(results.results.count).to eq(num)
end
it "finds bands with proper ordering" do
# the ordering should be create_at since no followers exist
expect(BandFollower.count).to eq(0)
results = Search.band_search({ :per_page => Band.count })
results.bands_filter.each_with_index do |uu, idx|
results = Search.band_filter({ :per_page => Band.count })
results.results.each_with_index do |uu, idx|
expect(uu.id).to eq(@bands.reverse[idx].id)
end
end
@ -53,11 +53,11 @@ describe 'Band search' do
# refresh the order to ensure it works right
@band2.followers.concat(users[1..-1])
results = Search.band_search({ :per_page => @bands.size }, users[0])
expect(results.bands_filter[0].id).to eq(@band2.id)
results = Search.band_filter({ :per_page => @bands.size }, users[0])
expect(results.results[0].id).to eq(@band2.id)
# check the follower count for given entry
expect(results.bands_filter[0].search_follow_count.to_i).not_to eq(0)
expect(results.results[0].search_follow_count.to_i).not_to eq(0)
# check the follow relationship between current_user and result
expect(results.is_follower?(@band2)).to be true
end
@ -65,8 +65,8 @@ describe 'Band search' do
it 'paginates properly' do
# make sure pagination works right
params = { :per_page => 2, :page => 1 }
results = Search.band_search(params)
expect(results.bands_filter.count).to be 2
results = Search.band_filter(params)
expect(results.results.count).to be 2
end
end
@ -87,8 +87,8 @@ describe 'Band search' do
# establish sorting order
@band1.followers.concat(users)
results = Search.band_search({},@band1)
uu = results.bands_filter.detect { |mm| mm.id == @band1.id }
results = Search.band_filter({},@band1)
uu = results.results.detect { |mm| mm.id == @band1.id }
expect(uu).to_not be_nil
expect(results.follow_count(uu)).to eq(users.count)
end
@ -96,8 +96,8 @@ describe 'Band search' do
it "session stat shows session count" do
make_session(@band1)
@band1.reload
results = Search.band_search({},@band1)
uu = results.bands_filter.detect { |mm| mm.id == @band1.id }
results = Search.band_filter({},@band1)
uu = results.results.detect { |mm| mm.id == @band1.id }
expect(uu).to_not be_nil
expect(results.session_count(uu)).to be 1
end
@ -112,9 +112,9 @@ describe 'Band search' do
make_session(@band2)
make_session(@band1)
# order results by num recordings
results = Search.band_search({ :orderby => 'plays' })
expect(results.bands_filter[0].id).to eq(@band2.id)
expect(results.bands_filter[1].id).to eq(@band1.id)
results = Search.band_filter({ :orderby => 'plays' })
expect(results.results[0].id).to eq(@band2.id)
expect(results.results[1].id).to eq(@band1.id)
end
it "by now playing" do
@ -122,18 +122,18 @@ describe 'Band search' do
session = make_session(@band3)
FactoryGirl.create(:music_session_history, :music_session => session)
results = Search.band_search({ :orderby => 'playing' })
expect(results.bands_filter.count).to be 1
expect(results.bands_filter.first.id).to eq(@band3.id)
results = Search.band_filter({ :orderby => 'playing' })
expect(results.results.count).to be 1
expect(results.results.first.id).to eq(@band3.id)
# should get 2 results with 2 active sessions
# sort order should be created_at DESC
session = make_session(@band4)
FactoryGirl.create(:music_session_history, :music_session => session)
results = Search.band_search({ :orderby => 'playing' })
expect(results.bands_filter.count).to be 2
expect(results.bands_filter[0].id).to eq(@band4.id)
expect(results.bands_filter[1].id).to eq(@band3.id)
results = Search.band_filter({ :orderby => 'playing' })
expect(results.results.count).to be 2
expect(results.results[0].id).to eq(@band4.id)
expect(results.results[1].id).to eq(@band3.id)
end
end
@ -146,40 +146,40 @@ describe 'Band search' do
@band1.reload
ggg = @band1.genres.detect { |gg| gg.id == genre.id }
expect(ggg).to_not be_nil
results = Search.band_search({ :genre => ggg.id })
results.bands_filter.each do |rr|
results = Search.band_filter({ :genre => ggg.id })
results.results.each do |rr|
expect(rr.genres.detect { |gg| gg.id==ggg.id }.id).to eq(genre.id)
end
expect(results.bands_filter.count).to be 1
expect(results.results.count).to be 1
end
it "finds bands within a given distance of given location" do
num = Band.count
expect(@band1.lat).to_not be_nil
# short distance
results = Search.band_search({ :per_page => num,
results = Search.band_filter({ :per_page => num,
:distance => 10,
:city => 'Apex' }, @band1)
expect(results.bands_filter.count).to be num
expect(results.results.count).to be num
# long distance
results = Search.band_search({ :per_page => num,
results = Search.band_filter({ :per_page => num,
:distance => 1000,
:city => 'Miami',
:state => 'FL' }, @band1)
expect(results.bands_filter.count).to be num
expect(results.results.count).to be num
end
it "finds bands within a given distance of bands location" do
expect(@band1.lat).to_not be_nil
# uses the location of @band1
results = Search.band_search({ :distance => 10, :per_page => Band.count }, @band1)
expect(results.bands_filter.count).to be Band.count
results = Search.band_filter({ :distance => 10, :per_page => Band.count }, @band1)
expect(results.results.count).to be Band.count
end
it "finds no bands within a given distance of location" do
expect(@band1.lat).to_not be_nil
results = Search.band_search({ :distance => 10, :city => 'San Francisco' }, @band1)
expect(results.bands_filter.count).to be 0
results = Search.band_filter({ :distance => 10, :city => 'San Francisco' }, @band1)
expect(results.results.count).to be 0
end
end

View File

@ -13,7 +13,7 @@ describe User do
end
it "should allow search of one band with an exact match" do
ws = Band.search("Example Band")
ws = Search.band_search("Example Band").results
ws.length.should == 1
band_result = ws[0]
band_result.name.should == @band.name
@ -22,61 +22,61 @@ describe User do
end
it "should allow search of one band with partial matches" do
ws = Band.search("Ex")
ws = Search.band_search("Ex").results
ws.length.should == 1
ws[0].id.should == @band.id
ws = Band.search("Exa")
ws = Search.band_search("Exa").results
ws.length.should == 1
ws[0].id.should == @band.id
ws = Band.search("Exam")
ws = Search.band_search("Exam").results
ws.length.should == 1
ws[0].id.should == @band.id
ws = Band.search("Examp")
ws = Search.band_search("Examp").results
ws.length.should == 1
ws[0].id.should == @band.id
ws = Band.search("Exampl")
ws = Search.band_search("Exampl").results
ws.length.should == 1
ws[0].id.should == @band.id
ws = Band.search("Example")
ws = Search.band_search("Example").results
ws.length.should == 1
ws[0].id.should == @band.id
ws = Band.search("Ba")
ws = Search.band_search("Ba").results
ws.length.should == 1
ws[0].id.should == @band.id
ws = Band.search("Ban")
ws = Search.band_search("Ban").results
ws.length.should == 1
ws[0].id.should == @band.id
end
it "should not match mid-word searchs" do
ws = Band.search("xa")
ws = Search.band_search("xa").results
ws.length.should == 0
ws = Band.search("le")
ws = Search.band_search("le").results
ws.length.should == 0
end
it "should delete band" do
ws = Band.search("Example Band")
ws = Search.band_search("Example Band").results
ws.length.should == 1
band_result = ws[0]
band_result.id.should == @band.id
@band.destroy # delete doesn't work; you have to use destroy.
ws = Band.search("Example Band")
ws = Search.band_search("Example Band").results
ws.length.should == 0
end
it "should update band" do
ws = Band.search("Example Band")
ws = Search.band_search("Example Band").results
ws.length.should == 1
band_result = ws[0]
band_result.id.should == @band.id
@ -84,10 +84,10 @@ describe User do
@band.name = "bonus-stuff"
@band.save
ws = Band.search("Example Band")
ws = Search.band_search("Example Band").results
ws.length.should == 0
ws = Band.search("Bonus")
ws = Search.band_search("Bonus").results
ws.length.should == 1
band_result = ws[0]
band_result.id.should == @band.id
@ -96,7 +96,7 @@ describe User do
it "should tokenize correctly" do
@band2 = Band.save(nil, "Peach pit", "www.bands.com", "zomg we rock", "Apex", "NC", "US", ["hip hop"], user.id, nil, nil)
ws = Band.search("pea")
ws = Search.band_search("pea").results
ws.length.should == 1
user_result = ws[0]
user_result.id.should == @band2.id
@ -105,12 +105,12 @@ describe User do
it "should not return anything with a 1 character search" do
@band2 = Band.save(nil, "Peach pit", "www.bands.com", "zomg we rock", "Apex", "NC", "US", ["hip hop"], user.id, nil, nil)
ws = Band.search("pe")
ws = Search.band_search("pe").results
ws.length.should == 1
user_result = ws[0]
user_result.id.should == @band2.id
ws = Band.search("p")
ws = Search.band_search("p").results
ws.length.should == 0
end
end

View File

@ -0,0 +1,15 @@
require 'spec_helper'
describe Band do
let(:band) { FactoryGirl.create(:band) }
describe 'website update' do
it 'should have http prefix on website url' do
band.website = 'example.com'
band.save!
expect(band.website).to match(/^http:\/\/example.com$/)
end
end
end

View File

@ -3,23 +3,57 @@ require 'spec_helper'
describe IcecastAdminAuthentication do
let(:admin) { IcecastAdminAuthentication.new }
let(:output) { StringIO.new }
let(:builder) { ::Builder::XmlMarkup.new(:target => output, :indent => 1) }
before(:all) do
admin.source_password = "GoodJob@</>"
it "save error" do
admin.save.should be_false
admin.errors[:source_pass].length.should == 2
admin.errors[:admin_user].length.should == 2
admin.errors[:admin_pass].length.should == 2
admin.errors[:relay_user].length.should == 2
admin.errors[:relay_pass].length.should == 2
end
it "save" do
admin.save!
#puts "source password #{admin.source_password}"
#puts "id #{admin.id}"
#puts admin.errors
#puts admin.inspect
#puts admin.to_yaml
#puts JSON.pretty_generate admin
#puts admin.dumpXml (1)
#puts admin.errors.inspect
admin.errors.any?.should be_false
admin.source_pass = Faker::Lorem.characters(10)
admin.admin_user = Faker::Lorem.characters(10)
admin.admin_pass = Faker::Lorem.characters(10)
admin.relay_user = Faker::Lorem.characters(10)
admin.relay_pass = Faker::Lorem.characters(10)
admin.save.should be_true
admin.dumpXml(builder)
output.rewind
xml = Nokogiri::XML(output)
xml.css('authentication source-password').text.should == admin.source_pass
xml.css('authentication source-password').length.should == 1
xml.css('authentication admin-user').text.should == admin.admin_user
xml.css('authentication admin-user').length.should == 1
xml.css('authentication relay-user').text.should == admin.relay_user
xml.css('authentication relay-user').length.should == 1
xml.css('authentication relay-password').text.should == admin.relay_pass
xml.css('authentication relay-password').length.should == 1
xml.css('authentication admin-password').text.should == admin.admin_pass
xml.css('authentication admin-password').length.should == 1
end
describe "poke configs" do
let(:server) { a = FactoryGirl.create(:icecast_server_with_overrides); a.config_updated; IcecastServer.find(a.id) }
it "success via template" do
server.template.admin_auth.save!
server.reload
server.config_changed.should == 1
end
it "success via server" do
server.admin_auth.save!
server.reload
server.config_changed.should == 1
end
end
end

View File

@ -1,15 +1,67 @@
require 'spec_helper'
require 'stringio'
=begin
example output:
<directory>
<yp-url-timeout>15</yp-url-timeout>
<yp-url>http://dir.xiph.org/cgi-bin/yp-cgi</yp-url>
</directory>
=end
describe IcecastDirectory do
let(:idir) { IcecastDirectory.new }
let(:dir) { IcecastDirectory.new }
let(:output) { StringIO.new }
let(:builder) { ::Builder::XmlMarkup.new(:target => output, :indent => 1) }
before(:all) do
before(:each) do
end
it "save error" do
dir.save.should be_false
dir.errors[:yp_url].length.should == 1
dir.errors[:yp_url_timeout].length.should == 0
end
it "save" do
idir.save.should be_true
dir.yp_url = Faker::Lorem.characters(10)
dir.yp_url_timeout = 20
dir.save.should be_true
dir.dumpXml(builder)
output.rewind
xml = Nokogiri::XML(output)
xml.css('directory yp-url-timeout').text.should == dir.yp_url_timeout.to_s
xml.css('directory yp-url-timeout').length.should == 1
xml.css('directory yp-url').text.should == dir.yp_url
xml.css('directory yp-url').length.should == 1
end
describe "poke configs" do
let(:server) { a = FactoryGirl.create(:icecast_server_with_overrides); a.config_updated; IcecastServer.find(a.id) }
before(:each) do
server.directory = FactoryGirl.create(:icecast_directory)
server.template.directory = FactoryGirl.create(:icecast_directory)
server.template.save!
server.save!
server.config_updated
server.reload
end
it "success via template" do
server.template.directory.save!
server.reload
server.config_changed.should == 1
end
it "success via server" do
server.directory.save!
server.reload
server.config_changed.should == 1
end
end
end

View File

@ -3,26 +3,73 @@ require 'spec_helper'
describe IcecastLimit do
let(:limit) { IcecastLimit.new }
let(:output) { StringIO.new }
let(:builder) { ::Builder::XmlMarkup.new(:target => output, :indent => 1) }
before(:all) do
it "save defaults" do
limit.save.should be_true
limit.dumpXml(builder)
output.rewind
xml = Nokogiri::XML(output)
xml.css('limits clients').text.should == "1000"
xml.css('limits clients').length.should == 1
xml.css('limits sources').text.should == "50"
xml.css('limits sources').length.should == 1
xml.css('limits queue-size').text.should == "102400"
xml.css('limits queue-size').length.should == 1
xml.css('limits client-timeout').text.should == "30"
xml.css('limits client-timeout').length.should == 1
xml.css('limits header-timeout').text.should == "15"
xml.css('limits header-timeout').length.should == 1
xml.css('limits source-timeout').text.should == "10"
xml.css('limits source-timeout').length.should == 1
xml.css('limits burst-on-connect').text.should == "1"
xml.css('limits burst-on-connect').length.should == 1
xml.css('limits burst-size').text.should == "65536"
xml.css('limits burst-size').length.should == 1
end
it "save" do
limit.clients = 9999
limit.save
#limit.dumpXml
limit.errors.any?.should be_false
v = IcecastLimit.find(limit.id)
it "save specified" do
limit.clients = 10000
limit.sources = 2000
limit.queue_size = 1000
limit.client_timeout = 10
limit.header_timeout = 20
limit.source_timeout = 30
limit.burst_size = 1000
limit.save.should be_true
limit.dumpXml(builder)
output.rewind
xml = Nokogiri::XML(output)
xml.css('limits clients').text.should == limit.clients.to_s
xml.css('limits sources').text.should == limit.sources.to_s
xml.css('limits queue-size').text.should == limit.queue_size.to_s
xml.css('limits client-timeout').text.should == limit.client_timeout.to_s
xml.css('limits header-timeout').text.should == limit.header_timeout.to_s
xml.css('limits source-timeout').text.should == limit.source_timeout.to_s
xml.css('limits burst-on-connect').text.should == "1"
xml.css('limits burst-size').text.should == limit.burst_size.to_s
end
=begin
it "non-integer clients should be checked" do
limit.setclients 'a'
puts limit.clients
puts limit.inspect
limit.save.should be_false
limit.errors[:clients].should == ['is not a number']
describe "poke configs" do
let(:server) { a = FactoryGirl.create(:icecast_server_with_overrides); a.config_updated; IcecastServer.find(a.id) }
it "success via template" do
server.template.limit.save!
server.reload
server.config_changed.should == 1
end
it "success via server" do
server.limit.save!
server.reload
server.config_changed.should == 1
end
end
=end
end

View File

@ -2,14 +2,35 @@ require 'spec_helper'
describe IcecastListenSocket do
let(:iobj) { IcecastListenSocket.new }
before(:all) do
end
let(:listen) { IcecastListenSocket.new }
let(:output) { StringIO.new }
let(:builder) { ::Builder::XmlMarkup.new(:target => output, :indent => 1) }
it "save" do
iobj.save.should be_true
listen.save!
listen.dumpXml(builder)
output.rewind
xml = Nokogiri::XML(output)
xml.css('listen-socket port').text.should == "8001"
xml.css('listen-socket shoutcast-compat').length.should == 0
xml.css('listen-socket shoutcast-mount').length.should == 0
xml.css('listen-socket bind-address').length.should == 0
end
describe "poke configs" do
let(:server) { a = FactoryGirl.create(:icecast_server_with_overrides); a.config_updated; IcecastServer.find(a.id) }
it "success via template" do
server.template.listen_sockets.first.save!
server.reload
server.config_changed.should == 1
end
it "success via server" do
server.listen_sockets.first.save!
server.reload
server.config_changed.should == 1
end
end
end

View File

@ -2,14 +2,48 @@ require 'spec_helper'
describe IcecastLogging do
let(:iobj) { IcecastLogging.new }
before(:all) do
let(:logging) { IcecastLogging.new }
let(:output) { StringIO.new }
let(:builder) { ::Builder::XmlMarkup.new(:target => output, :indent => 1) }
it "save works by default db values" do
logging.save.should be_true
logging.access_log.should == 'access.log'
logging.error_log.should == 'error.log'
end
it "save" do
iobj.save.should be_true
logging.access_log = Faker::Lorem.characters(10)
logging.error_log = Faker::Lorem.characters(10)
logging.log_level = 4
logging.log_size = 20000
logging.save!
logging.dumpXml(builder)
output.rewind
xml = Nokogiri::XML(output)
xml.css('logging accesslog').text.should == logging.access_log
xml.css('logging errorlog').text.should == logging.error_log
xml.css('logging loglevel').text.should == logging.log_level.to_s
xml.css('logging logsize').text.should == logging.log_size.to_s
xml.css('logging playlistlog').length.should == 0
xml.css('logging logarchive').length.should == 0
end
describe "poke configs" do
let(:server) { a = FactoryGirl.create(:icecast_server_with_overrides); a.config_updated; IcecastServer.find(a.id) }
it "success via template" do
server.template.logging.save!
server.reload
server.config_changed.should == 1
end
it "success via server" do
server.logging.save!
server.reload
server.config_changed.should == 1
end
end
end

View File

@ -0,0 +1,63 @@
require 'spec_helper'
describe IcecastMasterServerRelay do
let(:relay) { IcecastMasterServerRelay.new }
let(:output){ StringIO.new }
let(:root) { ::Builder::XmlMarkup.new(:target => output, :indent => 1) }
it "should not save" do
relay.save.should be_false
relay.errors[:master_pass].should == ["can't be blank", "is too short (minimum is 5 characters)"]
relay.errors[:master_username].should == ["can't be blank", "is too short (minimum is 5 characters)"]
relay.errors[:master_server].should == ["can't be blank", "is too short (minimum is 1 characters)"]
end
it "should save" do
relay.master_server = "test.www.com"
relay.master_server_port = 7111
relay.master_username = "hackme-user"
relay.master_pass = "hackme-password"
relay.save!
root.tag! 'root' do |builder|
relay.dumpXml(builder)
end
output.rewind
xml = Nokogiri::XML(output)
xml.css('root master-server').text.should == relay.master_server.to_s
xml.css('root master-server-port').text.should == relay.master_server_port.to_s
xml.css('root master-update-interval').text.should == relay.master_update_interval.to_s
xml.css('root master-username').text.should == relay.master_username.to_s
xml.css('root master-password').text.should == relay.master_pass.to_s
xml.css('root relays-on-demand').text.should == relay.relays_on_demand.to_s
end
describe "poke configs" do
let(:server) { a = FactoryGirl.create(:icecast_server_with_overrides); a.config_updated; IcecastServer.find(a.id) }
before(:each) do
server.master_relay = FactoryGirl.create(:icecast_master_server_relay)
server.template.master_relay = FactoryGirl.create(:icecast_master_server_relay)
server.template.save!
server.save!
server.config_updated
server.reload
end
it "success via template" do
server.template.master_relay.save!
server.reload
server.config_changed.should == 1
end
it "success via server" do
server.master_relay.save!
server.reload
server.config_changed.should == 1
end
end
end

View File

@ -1,27 +0,0 @@
require 'spec_helper'
describe IcecastMastersvrRelay do
let(:iobj) { IcecastMastersvrRelay.new }
before(:all) do
end
=begin
it "should not save" do
iobj.save.should be_false
iobj.errors[:master_server].should_equal "is required"
end
=end
it "should save" do
iobj.master_server = "test.www.com"
iobj.master_server_port = 7111
iobj.master_username = "hack"
iobj.master_password = "hackme"
iobj.save.should be_true
end
end

View File

@ -2,16 +2,95 @@ require 'spec_helper'
describe IcecastMount do
let(:iobj) { IcecastMount.new }
before(:all) do
let(:icecast_mount) { FactoryGirl.create(:icecast_mount) }
let(:output) { StringIO.new }
let(:builder) { ::Builder::XmlMarkup.new(:target => output, :indent => 1) }
it "save error" do
mount = IcecastMount.new
mount.save.should be_false
mount.errors[:name].should == ["can't be blank", "must start with /"]
mount.errors[:stream_name].should == ["can't be blank"]
mount.errors[:stream_description].should == ["can't be blank"]
mount.errors[:stream_url].should == ["can't be blank"]
mount.errors[:genre].should == ["can't be blank"]
end
=begin
it "save" do
iobj.save.should be_true
end
=end
mount = IcecastMount.new
mount.name = "/" + Faker::Lorem.characters(10)
mount.stream_name = Faker::Lorem.characters(10)
mount.stream_description = Faker::Lorem.characters(10)
mount.stream_url = Faker::Lorem.characters(10)
mount.genre = Faker::Lorem.characters(10)
mount.source_username = Faker::Lorem.characters(10)
mount.source_pass = Faker::Lorem.characters(10)
mount.intro = Faker::Lorem.characters(10)
mount.fallback_mount = Faker::Lorem.characters(10)
mount.on_connect = Faker::Lorem.characters(10)
mount.on_disconnect = Faker::Lorem.characters(10)
mount.fallback_override = true
mount.fallback_when_full = true
mount.max_listeners = 1000
mount.max_listener_duration = 3600
mount.authentication = FactoryGirl.create(:icecast_user_authentication)
mount.save!
mount.dumpXml(builder)
output.rewind
xml = Nokogiri::XML(output)
xml.css('mount mount-name').text.should == mount.name
xml.css('mount username').text.should == mount.source_username
xml.css('mount password').text.should == mount.source_pass
xml.css('mount max-listeners').text.should == mount.max_listeners.to_s
xml.css('mount max-listener-duration').text.should == mount.max_listener_duration.to_s
xml.css('mount intro').text.should == mount.intro
xml.css('mount fallback-mount').text.should == mount.fallback_mount
xml.css('mount fallback-override').text.should == mount.fallback_override.to_s
xml.css('mount fallback-when-full').text.should == mount.fallback_when_full.to_s
xml.css('mount stream-name').text.should == mount.stream_name
xml.css('mount stream-description').text.should == mount.stream_description
xml.css('mount stream-url').text.should == mount.stream_url
xml.css('mount genre').text.should == mount.genre
xml.css('mount bitrate').length.should == 0
xml.css('mount charset').text == mount.charset
xml.css('mount public').text == mount.is_public.to_s
xml.css('mount type').text == mount.mime_type
xml.css('mount subtype').text == mount.subtype
xml.css('mount burst-size').length.should == 0
xml.css('mount mp3-metadata-interval').length.should == 0
xml.css('mount hidden').text.should == mount.hidden.to_s
xml.css('mount on-connect').text.should == mount.on_connect
xml.css('mount on-disconnect').text.should == mount.on_disconnect
xml.css('mount dump-file').length.should == 0
xml.css('mount authentication').length.should == 1 # no reason to test futher; it's tested in that model
end
describe "poke configs" do
let(:server) { a = FactoryGirl.create(:icecast_server_with_overrides); a.config_updated; IcecastServer.find(a.id) }
before(:each) do
server.mounts << FactoryGirl.create(:icecast_mount)
server.save!
server.config_updated
server.reload
server.config_changed.should == 0
end
it "success via server" do
server.mounts.first.save!
server.reload
server.config_changed.should == 1
end
end
describe "icecast server callbacks" do
it "source up" do
icecast_mount.source_up
end
end
end

View File

@ -2,14 +2,72 @@ require 'spec_helper'
describe IcecastPath do
let(:iobj) { IcecastPath.new }
let(:path) { IcecastPath.new }
let(:output) { StringIO.new }
let(:builder) { ::Builder::XmlMarkup.new(:target => output, :indent => 1) }
before(:all) do
it "save default" do
path.save.should be_true
path.dumpXml(builder)
output.rewind
xml = Nokogiri::XML(output)
xml.css('paths basedir').text.should == "./"
xml.css('paths basedir').length.should == 1
xml.css('paths logdir').text.should == "./logs"
xml.css('paths logdir').length.should == 1
xml.css('paths pidfile').text.should == "./icecast.pid"
xml.css('paths pidfile').length.should == 1
xml.css('paths webroot').text.should == "./web"
xml.css('paths webroot').length.should == 1
xml.css('paths adminroot').text.should == "./admin"
xml.css('paths adminroot').length.should == 1
xml.css('paths allow-ip').length.should == 0
xml.css('paths deny-ip').length.should == 0
xml.css('paths alias').length.should == 0
end
it "save" do
iobj.save.should be_true
it "save set values" do
path.base_dir = Faker::Lorem.characters(10)
path.log_dir = Faker::Lorem.characters(10)
path.pid_file = Faker::Lorem.characters(10)
path.web_root = Faker::Lorem.characters(10)
path.admin_root = Faker::Lorem.characters(10)
path.allow_ip = Faker::Lorem.characters(10)
path.deny_ip = Faker::Lorem.characters(10)
path.alias_source = Faker::Lorem.characters(10)
path.alias_dest = Faker::Lorem.characters(10)
path.save.should be_true
path.dumpXml(builder)
output.rewind
xml = Nokogiri::XML(output)
xml.css('paths basedir').text.should == path.base_dir
xml.css('paths logdir').text.should == path.log_dir
xml.css('paths pidfile').text.should == path.pid_file
xml.css('paths webroot').text.should == path.web_root
xml.css('paths adminroot').text.should == path.admin_root
xml.css('paths allow-ip').text.should == path.allow_ip
xml.css('paths deny-ip').text.should == path.deny_ip
xml.css('paths alias').first['source'] == path.alias_source
xml.css('paths alias').first['dest'] == path.alias_dest
end
describe "poke configs" do
let(:server) { a = FactoryGirl.create(:icecast_server_with_overrides); a.config_updated; IcecastServer.find(a.id) }
it "success via template" do
server.template.path.save!
server.reload
server.config_changed.should == 1
end
it "success via server" do
server.path.save!
server.reload
server.config_changed.should == 1
end
end
end

View File

@ -2,16 +2,51 @@ require 'spec_helper'
describe IcecastRelay do
let(:iobj) { IcecastRelay.new }
let(:relay) { IcecastRelay.new }
let(:output){ StringIO.new }
let(:builder) { ::Builder::XmlMarkup.new(:target => output, :indent => 1) }
before(:all) do
it "should not save" do
relay.save.should be_false
relay.errors[:mount].should == ["can't be blank"]
relay.errors[:server].should == ["can't be blank"]
end
=begin
it "save" do
:iobj.save.should be_true
end
=end
relay.mount = Faker::Lorem.characters(10)
relay.server = Faker::Lorem.characters(10)
relay.relay_shoutcast_metadata = false
relay.save!
relay.dumpXml(builder)
output.rewind
xml = Nokogiri::XML(output)
xml.css('relay port').text.should == relay.port.to_s
xml.css('relay mount').text.should == relay.mount
xml.css('relay server').text.should == relay.server
xml.css('relay local-mount').length.should == 0
xml.css('relay username').length.should == 0
xml.css('relay password').length.should == 0
xml.css('relay relay-shoutcast-metadata').text.should == "0"
xml.css('relay on-demand').text.should == "1"
end
describe "poke configs" do
let(:server) { a = FactoryGirl.create(:icecast_server_with_overrides); a.config_updated; IcecastServer.find(a.id) }
before(:each) do
server.relays << FactoryGirl.create(:icecast_relay)
server.save!
server.config_updated
server.reload
end
it "success via server" do
server.relays.first.save!
server.reload
server.config_changed.should == 1
end
end
end

View File

@ -0,0 +1,49 @@
require 'spec_helper'
describe IcecastSecurity do
let(:security) { IcecastSecurity.new }
let(:output) { StringIO.new }
let(:builder) { ::Builder::XmlMarkup.new(:target => output, :indent => 1) }
it "save with chroot" do
security.change_owner_user ="hotdog"
security.change_owner_group ="mongrel"
security.chroot = 1
security.save!
security.dumpXml(builder)
output.rewind
xml = Nokogiri::XML(output)
xml.css('security chroot').text.should == '1'
xml.css('security changeowner user').text.should == 'hotdog'
xml.css('security changeowner group').text.should == 'mongrel'
end
it "save without chroot" do
security.save!
security.dumpXml(builder)
output.rewind
xml = Nokogiri::XML(output)
xml.css('security chroot').text.should == '0'
xml.css('security changeowner').length.should == 0
end
describe "poke configs" do
let(:server) { a = FactoryGirl.create(:icecast_server_with_overrides); a.config_updated; IcecastServer.find(a.id) }
it "success via template" do
server.template.security.save!
server.reload
server.config_changed.should == 1
end
it "success via server" do
server.security.save!
server.reload
server.config_changed.should == 1
end
end
end

View File

@ -0,0 +1,33 @@
require 'spec_helper'
describe IcecastServer do
let(:server) { IcecastServer.new }
let(:output) { StringIO.new }
let(:builder) { ::Builder::XmlMarkup.new(:target => output, :indent => 1) }
it "save" do
server = FactoryGirl.create(:icecast_server_minimal)
server.save!
server.reload
server.dumpXml(output)
output.rewind
xml = Nokogiri::XML(output)
xml.css('icecast hostname').text.should == server.hostname
xml.css('icecast server-id').text.should == server.server_id
xml.css('icecast location').text.should == server.template.location
xml.css('icecast admin').text.should == server.template.admin_email
xml.css('icecast fileserve').text.should == server.template.fileserve.to_s
xml.css('icecast limits').length.should == 1
xml.css('icecast authentication').length.should == 1
xml.css('icecast directory').length.should == 0
xml.css('icecast master-server').length.should == 0
xml.css('icecast paths').length.should == 1
xml.css('icecast logging').length.should == 1
xml.css('icecast security').length.should == 1
xml.css('icecast listen-socket').length.should == 1
end
end

View File

@ -0,0 +1,10 @@
require 'spec_helper'
describe IcecastListenSocket do
let(:template) { template = FactoryGirl.create(:icecast_template_minimal) }
it "save" do
template.errors.any?.should be_false
end
end

View File

@ -0,0 +1,61 @@
require 'spec_helper'
describe IcecastUserAuthentication do
let(:auth) { IcecastUserAuthentication.new }
let(:output) { StringIO.new }
let(:builder) { ::Builder::XmlMarkup.new(:target => output, :indent => 1) }
it "save error" do
auth.save.should be_false
auth.errors[:mount_add].should == ["can't be blank"]
auth.errors[:mount_remove].should == ["can't be blank"]
auth.errors[:listener_add].should == ["can't be blank"]
auth.errors[:listener_remove].should == ["can't be blank"]
#auth.errors[:unused_username].should == ["is too short (minimum is 5 characters)"]
#auth.errors[:unused_pass].should == ["is too short (minimum is 5 characters)"]
end
it "save" do
auth.mount_add = Faker::Lorem.characters(10)
auth.mount_remove = Faker::Lorem.characters(10)
auth.listener_add = Faker::Lorem.characters(10)
auth.listener_remove = Faker::Lorem.characters(10)
auth.unused_username = Faker::Lorem.characters(10)
auth.unused_pass = Faker::Lorem.characters(10)
auth.save!
auth.dumpXml(builder)
output.rewind
xml = Nokogiri::XML(output)
xml.css('authentication')[0]["type"].should == auth.authentication_type
xml.css('authentication option[name="mount_add"]')[0]["value"].should == auth.mount_add
xml.css('authentication option[name="mount_remove"]')[0]["value"].should == auth.mount_remove
xml.css('authentication option[name="listener_add"]')[0]["value"].should == auth.listener_add
xml.css('authentication option[name="listener_remove"]')[0]["value"].should == auth.listener_remove
xml.css('authentication option[name="username"]')[0]["value"].should == auth.unused_username
xml.css('authentication option[name="password"]')[0]["value"].should == auth.unused_pass
xml.css('authentication option[name="auth_header"]')[0]["value"].should == auth.auth_header
xml.css('authentication option[name="timelimit_header"]')[0]["value"].should == auth.timelimit_header
end
describe "poke configs" do
let(:server) { a = FactoryGirl.create(:icecast_server_with_overrides); a.config_updated; IcecastServer.find(a.id) }
before(:each) do
server.mounts << FactoryGirl.create(:icecast_mount_with_auth)
server.save!
server.config_updated
server.reload
end
it "success via server" do
server.mounts.first.authentication.save!
server.reload
server.config_changed.should == 1
end
end
end

View File

@ -17,15 +17,16 @@ describe 'Musician search' do
it "finds all musicians" do
# expects all the users
num = User.musicians.count
results = Search.musician_search({ :per_page => num })
expect(results.musicians_filter.count).to eq(num)
results = Search.musician_filter({ :per_page => num })
expect(results.results.count).to eq(num)
expect(results.search_type).to be(:musicians_filter)
end
it "finds musicians with proper ordering" do
# the ordering should be create_at since no followers exist
expect(UserFollower.count).to eq(0)
results = Search.musician_search({ :per_page => User.musicians.count })
results.musicians_filter.each_with_index do |uu, idx|
results = Search.musician_filter({ :per_page => User.musicians.count })
results.results.each_with_index do |uu, idx|
expect(uu.id).to eq(@users.reverse[idx].id)
end
end
@ -40,11 +41,11 @@ describe 'Musician search' do
# refresh the order to ensure it works right
@user2.followers.concat([@user3, @user4, @user2])
results = Search.musician_search({ :per_page => @users.size }, @user3)
expect(results.musicians_filter[0].id).to eq(@user2.id)
results = Search.musician_filter({ :per_page => @users.size }, @user3)
expect(results.results[0].id).to eq(@user2.id)
# check the follower count for given entry
expect(results.musicians_filter[0].search_follow_count.to_i).not_to eq(0)
expect(results.results[0].search_follow_count.to_i).not_to eq(0)
# check the follow relationship between current_user and result
expect(results.is_follower?(@user2)).to be true
end
@ -52,8 +53,8 @@ describe 'Musician search' do
it 'paginates properly' do
# make sure pagination works right
params = { :per_page => 2, :page => 1 }
results = Search.musician_search(params)
expect(results.musicians_filter.count).to be 2
results = Search.musician_filter(params)
expect(results.results.count).to be 2
end
end
@ -95,8 +96,8 @@ describe 'Musician search' do
# create friendship record
Friendship.save(@user1.id, @user2.id)
# search on user2
results = Search.musician_search({}, @user2)
friend = results.musicians_filter.detect { |mm| mm.id == @user1.id }
results = Search.musician_filter({}, @user2)
friend = results.results.detect { |mm| mm.id == @user1.id }
expect(friend).to_not be_nil
expect(results.friend_count(friend)).to be 1
@user1.reload
@ -114,8 +115,8 @@ describe 'Musician search' do
expect(recording.claimed_recordings.length).to be 1
expect(@user1.recordings.detect { |rr| rr == recording }).to_not be_nil
results = Search.musician_search({},@user1)
uu = results.musicians_filter.detect { |mm| mm.id == @user1.id }
results = Search.musician_filter({},@user1)
uu = results.results.detect { |mm| mm.id == @user1.id }
expect(uu).to_not be_nil
expect(results.record_count(uu)).to be 1
@ -129,29 +130,29 @@ describe 'Musician search' do
it "by plays" do
make_recording(@user1)
# order results by num recordings
results = Search.musician_search({ :orderby => 'plays' }, @user2)
expect(results.musicians_filter[0].id).to eq(@user1.id)
results = Search.musician_filter({ :orderby => 'plays' }, @user2)
expect(results.results[0].id).to eq(@user1.id)
# add more data and make sure order still correct
make_recording(@user2); make_recording(@user2)
results = Search.musician_search({ :orderby => 'plays' }, @user2)
expect(results.musicians_filter[0].id).to eq(@user2.id)
results = Search.musician_filter({ :orderby => 'plays' }, @user2)
expect(results.results[0].id).to eq(@user2.id)
end
it "by now playing" do
# should get 1 result with 1 active session
make_session(@user3)
results = Search.musician_search({ :orderby => 'playing' }, @user2)
expect(results.musicians_filter.count).to be 1
expect(results.musicians_filter.first.id).to eq(@user3.id)
results = Search.musician_filter({ :orderby => 'playing' }, @user2)
expect(results.results.count).to be 1
expect(results.results.first.id).to eq(@user3.id)
# should get 2 results with 2 active sessions
# sort order should be created_at DESC
make_session(@user4)
results = Search.musician_search({ :orderby => 'playing' }, @user2)
expect(results.musicians_filter.count).to be 2
expect(results.musicians_filter[0].id).to eq(@user4.id)
expect(results.musicians_filter[1].id).to eq(@user3.id)
results = Search.musician_filter({ :orderby => 'playing' }, @user2)
expect(results.results.count).to be 2
expect(results.results[0].id).to eq(@user4.id)
expect(results.results[1].id).to eq(@user3.id)
end
end
@ -165,40 +166,40 @@ describe 'Musician search' do
@user1.reload
ii = @user1.instruments.detect { |inst| inst.id == 'tuba' }
expect(ii).to_not be_nil
results = Search.musician_search({ :instrument => ii.id })
results.musicians_filter.each do |rr|
results = Search.musician_filter({ :instrument => ii.id })
results.results.each do |rr|
expect(rr.instruments.detect { |inst| inst.id=='tuba' }.id).to eq(ii.id)
end
expect(results.musicians_filter.count).to be 1
expect(results.results.count).to be 1
end
it "finds musicians within a given distance of given location" do
num = User.musicians.count
expect(@user1.lat).to_not be_nil
# short distance
results = Search.musician_search({ :per_page => num,
results = Search.musician_filter({ :per_page => num,
:distance => 10,
:city => 'Apex' }, @user1)
expect(results.musicians_filter.count).to be num
expect(results.results.count).to be num
# long distance
results = Search.musician_search({ :per_page => num,
results = Search.musician_filter({ :per_page => num,
:distance => 1000,
:city => 'Miami',
:state => 'FL' }, @user1)
expect(results.musicians_filter.count).to be num
expect(results.results.count).to be num
end
it "finds musicians within a given distance of users location" do
expect(@user1.lat).to_not be_nil
# uses the location of @user1
results = Search.musician_search({ :distance => 10, :per_page => User.musicians.count }, @user1)
expect(results.musicians_filter.count).to be User.musicians.count
results = Search.musician_filter({ :distance => 10, :per_page => User.musicians.count }, @user1)
expect(results.results.count).to be User.musicians.count
end
it "finds no musicians within a given distance of location" do
expect(@user1.lat).to_not be_nil
results = Search.musician_search({ :distance => 10, :city => 'San Francisco' }, @user1)
expect(results.musicians_filter.count).to be 0
results = Search.musician_filter({ :distance => 10, :city => 'San Francisco' }, @user1)
expect(results.results.count).to be 0
end
end

View File

@ -230,94 +230,6 @@ describe Recording do
downloads["downloads"].length.should == 1
end
it "should return a file list for a user properly" do
pending
stub_const("APP_CONFIG", app_config)
@recording = Recording.start(@music_session, @user)
@recording.stop
@recording.reload
@genre = FactoryGirl.create(:genre)
@recording.claim(@user, "Recording", "Recording Description", @genre, true, true)
Recording.list_downloads(@user)["downloads"].length.should == 0
Recording.list_uploads(@user)["uploads"].length.should == 1
file = Recording.list_uploads(@user)["uploads"].first
@recorded_track = @recording.recorded_tracks.first
@recorded_track.upload_start(25000, "md5hash")
@recorded_track.upload_complete
Recording.list_downloads(@user)["downloads"].length.should == 1
Recording.list_uploads(@user)["uploads"].length.should == 0
file = Recording.list(@user)["downloads"].first
file[:type].should == "recorded_track"
file[:id].should == @recorded_track.id
file[:length].should == 25000
file[:md5].should == "md5hash"
file[:url].should == S3Manager.url(S3Manager.hashed_filename('recorded_track', @recorded_track.id))
# Note that the recording should automatically schedule a mix when the upload completes
@recording.mixes.length.should == 1
@mix = Mix.next('server')
@mix.should_not be_nil
@mix.finish(50000, "md5hash")
Recording.list_downloads(@user)["downloads"].length.should == 2
Recording.list_uploads(@user)["uploads"].length.should == 0
file = Recording.list_downloads(@user)["downloads"].last
file[:type].should == "mix"
file[:id].should == @mix.id
file[:length].should == 50000
file[:md5].should == "md5hash"
file[:url].should == S3Manager.url(S3Manager.hashed_filename('mix', @mix.id))
end
it "should create a base mix manifest properly" do
pending
stub_const("APP_CONFIG", app_config)
@user2 = FactoryGirl.create(:user)
@connection2 = FactoryGirl.create(:connection, :user => @user)
@instrument2 = FactoryGirl.create(:instrument, :description => 'a great instrument')
@track2 = FactoryGirl.create(:track, :connection => @connection2, :instrument => @instrument2)
@music_session.connections << @connection2
@music_session.save
@recording = Recording.start(@music_session, @user)
#sleep 4
@recording.stop
@recording.recorded_tracks.length.should == 2
@recorded_track = @recording.recorded_tracks.first
@recorded_track.upload_start(25000, "md5hash")
@recorded_track.upload_complete
@recorded_track2 = @recording.recorded_tracks.last
@recorded_track2.upload_start(50000, "md5hash2")
@recorded_track2.upload_complete
mix_manifest = @recording.base_mix_manifest
mix_manifest.should_not be_nil
files = mix_manifest["files"]
files.should_not be_nil
files.length.should == 2
files.first["codec"].should == "vorbis"
files.first["offset"].should == 0
files.first["url"].should == @recording.recorded_tracks.first.url
files.last["codec"].should == "vorbis"
files.last["offset"].should == 0
files.last["url"].should == @recording.recorded_tracks.last.url
timeline = mix_manifest["timeline"]
timeline.should_not be_nil
timeline.length.should == 2
timeline.first["timestamp"].should == 0
timeline.first["end"].should be_nil
mix = timeline.first["mix"]
mix.should_not be_nil
mix.length.should == 2
mix.first["balance"].should == 0
mix.first["level"].should == 100
mix.last["balance"].should == 0
mix.last["level"].should == 100
timeline.last["timestamp"].should == @recording.duration
timeline.last["end"].should == true
end
describe "chance for everyone to keep or discard" do
before(:each) do
@user2 = FactoryGirl.create(:user)

View File

@ -13,24 +13,24 @@ describe Search do
end
def assert_peachy_data
search = Search.search('peach')
search = Search.musician_search('peach')
search.results.length.should == 1
obj = search.results[0]
obj.should be_a_kind_of User
obj.id.should == @user.id
search.recordings.length.should == 0
search.bands.length.should == 1
search.musicians.length.should == 1
search.fans.length.should == 1
search = Search.fan_search('peach')
search.results.length.should == 1
obj = search.results[0]
obj.should be_a_kind_of User
obj.id.should == @fan.id
musician = search.musicians[0]
musician.should be_a_kind_of User
musician.id.should == @user.id
search = Search.band_search('peach')
search.results.length.should == 1
obj = search.results[0]
obj.should be_a_kind_of Band
obj.id.should == @band.id
band = search.bands[0]
band.should be_a_kind_of Band
band.id.should == @band.id
fan = search.fans[0]
fan.should be_a_kind_of User
fan.id.should == @fan.id
end
it "search for band & musician " do

View File

@ -9,7 +9,8 @@ describe User do
end
it "should allow search of one user" do
ws = User.search("Example User")
uu = FactoryGirl.create(:user, :musician => false)
ws = Search.musician_search("Example User").results
ws.length.should == 1
user_result = ws[0]
user_result.first_name.should == @user.first_name
@ -19,20 +20,27 @@ describe User do
user_result.musician.should == true
end
it "should allow search of one fan" do
uu = FactoryGirl.create(:user, :musician => false)
ws = Search.fan_search(uu.name).results
expect(ws.length).to be(1)
expect(ws[0].id).to eq(uu.id)
end
it "should delete user" do
ws = User.search("Example User")
ws = Search.musician_search("Example User").results
ws.length.should == 1
user_result = ws[0]
user_result.id.should == @user.id
@user.destroy
ws = User.search("Example User")
ws = Search.musician_search("Example User").results
ws.length.should == 0
end
it "should update user" do
ws = User.search("Example User")
ws = Search.musician_search("Example User").results
ws.length.should == 1
user_result = ws[0]
user_result.id.should == @user.id
@ -41,10 +49,10 @@ describe User do
@user.last_name = "more-junk"
@user.save
ws = User.search("Example User")
ws = Search.musician_search("Example User").results
ws.length.should == 0
ws = User.search("Bonus")
ws = Search.musician_search("Bonus").results
ws.length.should == 1
user_result = ws[0]
user_result.id.should == @user.id
@ -55,7 +63,7 @@ describe User do
@user2 = FactoryGirl.create(:user, first_name: "peaches", last_name: "test", email: "peach@example.com",
password: "foobar", password_confirmation: "foobar", musician: true, email_confirmed: true,
city: "Apex", state: "NC", country: "US")
ws = User.search("pea")
ws = Search.musician_search("pea").results
ws.length.should == 1
user_result = ws[0]
user_result.id.should == @user2.id
@ -65,14 +73,14 @@ describe User do
@user3 = FactoryGirl.create(:user, first_name: "unconfirmed", last_name: "unconfirmed", email: "unconfirmed@example.com",
password: "foobar", password_confirmation: "foobar", musician: true, email_confirmed: false,
city: "Apex", state: "NC", country: "US")
ws = User.search("unconfirmed")
ws = Search.musician_search("unconfirmed").results
ws.length.should == 1
# Ok, confirm the user, and see them show up
@user3.email_confirmed = true
@user3.save
ws = User.search("unconfirmed")
ws = Search.musician_search("unconfirmed").results
ws.length.should == 1
user_result = ws[0]
user_result.id.should == @user3.id

View File

@ -21,39 +21,52 @@ describe MQRouter do
@mq_router.user_publish_to_session(music_session, user1, "a message" ,:client_id => music_session_member1.client_id)
end
it "user_publish_to_session works (checking exchange callbacks)" do
user1 = FactoryGirl.create(:user) # in the jam session
user2 = FactoryGirl.create(:user) # in the jam session
music_session = FactoryGirl.create(:music_session, :creator => user1)
music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :ip_address => "1.1.1.1", :client_id => "1")
music_session_member2 = FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :ip_address => "2.2.2.2", :client_id => "2")
# this is necessary because other tests will call EM.schedule indirectly as they fiddle with AR models, since some of our
# notifications are tied to model activity. So, the issue here is that you'll have an unknown known amount of
# queued up messages ready to be sent to MQRouter (because EM.schedule will put deferred blocks onto @next_tick_queue),
# resulting in messages from other tests being sent to client_exchange or user_exchange
# there is no API I can see to clear out the EM queue. so just open up the EM module and do it manually
module EM
@next_tick_queue = []
describe "double MQRouter" do
before(:all) do
@original_client_exchange = MQRouter.client_exchange
@original_user_exchange = MQRouter.user_exchange
end
EM.run do
after(:all) do
MQRouter.client_exchange = @original_client_exchange
MQRouter.user_exchange = @original_user_exchange
end
# mock up exchange
MQRouter.client_exchange = double("client_exchange")
MQRouter.user_exchange = double("user_exchange")
it "user_publish_to_session works (checking exchange callbacks)" do
MQRouter.client_exchange.should_receive(:publish).with("a message", :routing_key => "client.#{music_session_member2.client_id}")
MQRouter.user_exchange.should_not_receive(:publish)
user1 = FactoryGirl.create(:user) # in the jam session
user2 = FactoryGirl.create(:user) # in the jam session
@mq_router.user_publish_to_session(music_session, user1, "a message", :client_id => music_session_member1.client_id)
music_session = FactoryGirl.create(:music_session, :creator => user1)
EM.stop
music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :ip_address => "1.1.1.1", :client_id => "1")
music_session_member2 = FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :ip_address => "2.2.2.2", :client_id => "2")
# this is necessary because other tests will call EM.schedule indirectly as they fiddle with AR models, since some of our
# notifications are tied to model activity. So, the issue here is that you'll have an unknown known amount of
# queued up messages ready to be sent to MQRouter (because EM.schedule will put deferred blocks onto @next_tick_queue),
# resulting in messages from other tests being sent to client_exchange or user_exchange
# there is no API I can see to clear out the EM queue. so just open up the EM module and do it manually
module EM
@next_tick_queue = []
end
# bad thing about a static singleton is that we have to 'repair' it by taking back off the double
EM.run do
# mock up exchange
MQRouter.client_exchange = double("client_exchange")
MQRouter.user_exchange = double("user_exchange")
MQRouter.client_exchange.should_receive(:publish).with("a message", :routing_key => "client.#{music_session_member2.client_id}")
MQRouter.user_exchange.should_not_receive(:publish)
@mq_router.user_publish_to_session(music_session, user1, "a message", :client_id => music_session_member1.client_id)
EM.stop
end
end
end

View File

@ -3,6 +3,7 @@ require 'fileutils'
# these tests avoid the use of ActiveRecord and FactoryGirl to do blackbox, non test-instrumented tests
describe AudioMixer do
pending "failing on build server"
include UsesTempFiles
@ -38,6 +39,14 @@ describe AudioMixer do
before(:each) do
stub_const("APP_CONFIG", app_config)
module EM
@next_tick_queue = []
end
MQRouter.client_exchange = double("client_exchange")
MQRouter.user_exchange = double("user_exchange")
MQRouter.client_exchange.should_receive(:publish).any_number_of_times
MQRouter.user_exchange.should_receive(:publish).any_number_of_times
end

View File

@ -0,0 +1,159 @@
require 'spec_helper'
require 'fileutils'
# these tests avoid the use of ActiveRecord and FactoryGirl to do blackbox, non test-instrumented tests
describe IcecastConfigWriter do
let(:worker) { IcecastConfigWriter.new }
describe "validate" do
it "no manifest" do
expect { worker.validate }.to raise_error("icecast_server_id not spceified")
end
it "no files specified" do
worker.icecast_server_id = 'something'
expect { worker.validate }.to raise_error("queue routing mismatch error")
end
it "succeeds" do
worker.icecast_server_id = APP_CONFIG.icecast_server_id
worker.validate
end
end
describe "reload" do
it "works with successful command" do
IcecastConfigWriter.any_instance.stub(:execute).and_return(0)
worker.reload
end
it "raise exception when command fails" do
IcecastConfigWriter.any_instance.stub(:execute).and_return(1)
expect { worker.reload }.to raise_error
end
end
describe "integration" do
let(:server) {FactoryGirl.create(:icecast_server_minimal, server_id: APP_CONFIG.icecast_server_id)}
describe "simulated" do
describe "perform" do
# this case does not talk to redis, does not run a real reload command.
# but it does talk to the database and verifies all the other logic
it "success" do
# return success code from reload command
IcecastConfigWriter.any_instance.stub(:execute).and_return(0)
server.location = 'hello'
server.save!
server.config_changed.should == 1
IcecastConfigWriter.perform(server.server_id)
server.reload
server.config_changed.should == 0
end
it "errored" do
# return error code from reload command, which will cause the job to blow up
IcecastConfigWriter.any_instance.stub(:execute).and_return(1)
server.save!
server.config_changed.should == 1
expect { IcecastConfigWriter.perform(server.server_id) }.to raise_error
server.reload
server.config_changed.should == 1
end
end
describe "with resque-spec" do
before(:each) do
ResqueSpec.reset!
end
it "should have been enqueued because the config changed" do
server.save!
# the act of just creating the IcecastServer puts a message on the queue
IcecastConfigWriter.should have_queue_size_of(1)
end
it "should not have been enqueued if routed to a different server_id" do
new_server = FactoryGirl.create(:icecast_server_minimal, server_id: APP_CONFIG.icecast_server_id)
with_resque do
new_server.save!
end
# nobody was around to take it from the queue
IcecastConfigWriter.should have_queue_size_of(1)
end
it "should actually run the job" do
IcecastConfigWriter.any_instance.stub(:execute).and_return(0)
with_resque do
server.save!
server.config_changed.should == 1
end
IcecastConfigWriter.should have_queue_size_of(0)
server.reload
server.config_changed.should == 0
end
it "bails out with no error if no config change present" do
IcecastConfigWriter.any_instance.stub(:execute).and_return(0)
with_resque do
server.save!
end
server.reload
server.config_changed.should == 0
with_resque do
IcecastConfigWriter.enqueue(server.server_id)
end
server.reload
server.config_changed.should == 0
end
describe "queue_jobs_needing_retry" do
it "finds an unchecked server" do
pending "failing on build server"
server.touch
begin
ActiveRecord::Base.record_timestamps = false
server.updated_at = Time.now.ago(APP_CONFIG.icecast_max_missing_check + 1)
server.save!
ensure
# very important to turn it back; it'll break all tests otherwise
ActiveRecord::Base.record_timestamps = true
end
# should enqueue 1 job
IcecastConfigWriter.queue_jobs_needing_retry
IcecastConfigWriter.should have_queue_size_of(1)
end
it "does not find a recently checked server" do
pending "failing on build server"
# should enqueue 1 job
IcecastConfigWriter.queue_jobs_needing_retry
IcecastConfigWriter.should have_queue_size_of(0)
end
end
end
end
end
end

View File

@ -84,6 +84,7 @@ Spork.prefork do
end
config.before(:each) do
stub_const("APP_CONFIG", app_config)
DatabaseCleaner.start
end

View File

@ -21,6 +21,31 @@ def app_config
ENV['AUDIOMIXER_PATH'] || audiomixer_workspace_path || "/var/lib/audiomixer/audiomixer/audiomixerapp"
end
def icecast_reload_cmd
'true' # as in, /bin/true
end
def icecast_config_file
Dir::Tmpname.make_tmpname(["#{Dir.tmpdir}/icecast", 'xml'], nil)
end
def icecast_server_id
'test'
end
def icecast_max_missing_check
2 * 60 # 2 minutes
end
def rabbitmq_host
"localhost"
end
def rabbitmq_port
5672
end
private
def audiomixer_workspace_path

View File

@ -61,9 +61,8 @@ gem 'haml-rails'
gem 'resque'
gem 'resque-retry'
gem 'resque-failed-job-mailer'
gem 'resque-dynamic-queues'
gem 'quiet_assets', :group => :development
gem "bugsnag"
group :development, :test do
@ -90,12 +89,12 @@ end
group :test, :cucumber do
gem 'capybara'
if ENV['JAMWEB_QT5'] == '1'
# necessary on platforms such as arch linux, where pacman -S qt5-webkit is your easiet option
gem "capybara-webkit", :git => 'git://github.com/thoughtbot/capybara-webkit.git'
else
#if ENV['JAMWEB_QT5'] == '1'
# # necessary on platforms such as arch linux, where pacman -S qt5-webkit is your easiet option
# gem "capybara-webkit", :git => 'git://github.com/thoughtbot/capybara-webkit.git'
#else
gem "capybara-webkit"
end
#end
gem 'capybara-screenshot'
gem 'cucumber-rails', :require => false #, '1.3.0', :require => false
gem 'guard-spork', '0.3.2'

View File

@ -113,7 +113,7 @@
players += context.JK.fillTemplate(pTemplate, playerVals);
}
var actionVals = {
profile_url: "/#/profile/" + bb.id,
profile_url: bb.website,
button_follow: bb['is_following'] ? '' : 'button-orange',
button_message: 'button-orange'
};

View File

@ -8,6 +8,20 @@
var instrument_logo_map = context.JK.getInstrumentIconMap24();
function initializeSearchNavLinks() {
$('.search-nav').click(function() {
$('.search-nav.active').removeClass('active');
$(this).addClass('active');
setTimeout(search, 100);
context.JK.Sidebar.searchTypeSelection($(this).data('search_text_type'));
});
}
context.JK.SearchResultScreen.searchTypeSelection = function(typeSelection) {
$('.search-nav.active').removeClass('active');
$('.search-result-header a[data-search_text_type='+typeSelection+']').addClass('active');
}
function beforeShow(data) {
var query = data.query;
}
@ -15,20 +29,31 @@
function afterShow(data) {
}
function search(evt) {
evt.stopPropagation();
function selectedSearchType() {
var srchtype = $('.search-nav.active').data('search_text_type');
if (srchtype === undefined) {
srchtype = $('#search_text_type').val();
}
return srchtype;
}
function search(evt) {
if (evt) {
evt.stopPropagation();
}
$('#search-results').empty();
var query = $('#search-input').val();
context.location = '#/searchResults/:' + query;
if (query) {
context.location = '#/searchResults/:' + query;
} else {
query = $('#query').html();
}
logger.debug('query=' + query);
if (query !== '') {
$('#query').html(query + "\"");
context.JK.search(query, app, onSearchSuccess);
}
else {
$('#query').html(query);
query += '&search_text_type='+selectedSearchType();
context.JK.search(query, app, context.JK.SearchResultScreen.onSearchSuccess);
} else {
$('#result-count').html('');
$('#query').html('');
}
@ -36,68 +61,147 @@
return false;
}
function onSearchSuccess(response) {
function resultDivVisibility(val, isSidebar) {
if (isSidebar) {
$('div[layout=sidebar user-id=' + val.id + '].sidebar-search-connected').hide();
$('div[layout=sidebar user-id=' + val.id + '].sidebar-search-result').show();
} else {
$('div[user-id=' + val.id + '].search-connected').hide();
$('div[user-id=' + val.id + '].search-result').show();
}
}
// TODO: generalize this for each search result type (band, musician, recordings, et. al.)
$.each(response.musicians, function(index, val) {
// fill in template for Connect pre-click
var template = $('#template-search-result').html();
var searchResultHtml = context.JK.fillTemplate(template, {
userId: val.id,
avatar_url: context.JK.resolveAvatarUrl(val.photo_url),
profile_url: "/#/profile/" + val.id,
userName: val.name,
location: val.location,
instruments: getInstrumentHtml(val.instruments)
});
$('#search-results').append(searchResultHtml);
// fill in template for Connect post-click
template = $('#template-invitation-sent').html();
var invitationSentHtml = context.JK.fillTemplate(template, {
userId: val.id,
first_name: val.first_name,
profile_url: "/#/profile/" + val.id
});
$('#search-results').append(invitationSentHtml);
// initialize visibility of the divs
$('div[user-id=' + val.id + '].search-connected').hide();
$('div[user-id=' + val.id + '].search-result').show();
// wire up button click handler if search result is not a friend or the current user
if (!val.is_friend && val.id !== context.JK.currentUserId) {
$('div[user-id=' + val.id + ']').find('.btn-connect-friend').click(sendFriendRequest);
}
else {
$('div[user-id=' + val.id + ']').find('.btn-connect-friend').hide();
}
});
var resultCount = response.musicians.length;
$('#result-count').html(resultCount);
if (resultCount === 1) {
$('#result-count').append(" Result for \"");
}
else {
$('#result-count').append(" Results for \"");
}
context.JK.SearchResultScreen.onSearchSuccess = function(response) {
searchResults(response, true);
searchResults(response, false);
}
function friendRequestCallback(userId) {
// toggle the pre-click and post-click divs
$('div[user-id=' + userId + '].search-connected').show();
$('div[user-id=' + userId + '].search-result').hide();
}
function searchResults(response, isSidebar) {
var resultCount=0;
var selector, template_name;
selector = isSidebar ? '#sidebar-search-results' : '#search-results';
$(selector).html('');
function sendFriendRequest(evt) {
if (response.search_type === 'musicians') {
resultCount = response.musicians.length;
// TODO: generalize this for each search result type (band, musician, et. al.)
template_name = isSidebar ? "#template-musicians-sidebar-search-result" : "#template-musicians-search-result";
$.each(response.musicians, function(index, val) {
// fill in template for Connect pre-click
var args = {
userId: val.id,
avatar_url: context.JK.resolveAvatarUrl(val.photo_url),
profile_url: "/#/profile/" + val.id,
userName: val.name,
location: val.location,
instruments: getInstrumentHtml(val.instruments)
};
selector = isSidebar ? '#sidebar-search-results' : '#search-results';
$(selector).append(context.JK.fillTemplate($(template_name).html(), args));
// fill in template for Connect post-click
selector = isSidebar ? '#template-sidebar-invitation-sent' : '#template-invitation-sent';
var invitationSentHtml = context.JK.fillTemplate($(selector).html(), {
userId: val.id,
first_name: val.first_name,
profile_url: "/#/profile/" + val.id
});
selector = isSidebar ? '#sidebar-search-results' : '#search-results';
$(selector).append(invitationSentHtml);
// wire up button click handler if search result is not a friend or the current use
if (isSidebar) {
var $sidebar = $('div[layout=sidebar] div[user-id=' + val.id + ']');
if (!val.is_friend && val.id !== context.JK.currentUserId) {
$sidebar.find('.btn-connect-friend').click(sendFriendRequest);
} else {
// hide the button if the search result is already a friend
$sidebar.find('.btn-connect-friend').hide();
}
} else {
if (!val.is_friend && val.id !== context.JK.currentUserId) {
$('div[user-id=' + val.id + ']').find('.btn-connect-friend').click(sendFriendRequest);
} else {
$('div[user-id=' + val.id + ']').find('.btn-connect-friend').hide();
}
}
resultDivVisibility(val, isSidebar);
});
} else if (response.search_type === 'bands') {
resultCount = response.bands.length;
template_name = isSidebar ? "#template-bands-sidebar-search-result" : "#template-bands-search-result";
$.each(response.bands, function(index, val) {
// fill in template for Connect pre-click
var searchResultHtml = context.JK.fillTemplate($(template_name).html(), {
bandId: val.id,
avatar_url: context.JK.resolveAvatarUrl(val.photo_url),
band_url: val.website,
bandName: val.name,
location: val.location
});
selector = isSidebar ? '#sidebar-search-results' : '#search-results';
$(selector).append(searchResultHtml);
resultDivVisibility(val, isSidebar);
});
} else if (response.search_type === 'fans') {
resultCount = response.fans.length;
template_name = isSidebar ? "#template-fans-sidebar-search-result" : "#template-fans-search-result";
$.each(response.fans, function(index, val) {
// fill in template for Connect pre-click
var searchResultHtml = context.JK.fillTemplate($(template_name).html(), {
userId: val.id,
avatar_url: context.JK.resolveAvatarUrl(val.photo_url),
profile_url: "/#/profile/" + val.id,
userName: val.name,
location: val.location
});
selector = isSidebar ? '#sidebar-search-results' : '#search-results';
$(selector).append(searchResultHtml);
resultDivVisibility(val, isSidebar);
});
}
if (isSidebar) {
// show header
$('#sidebar-search-header').show();
// hide panels
$('[layout-panel="contents"]').hide();
$('[layout-panel="contents"]').css({"height": "1px"});
// resize search results area
$('#sidebar-search-results').height(context.JK.Sidebar.getHeight() + 'px');
} else {
$('#result-count').html(resultCount);
if (resultCount === 1) {
$('#result-count').append(" Result for: ");
} else {
$('#result-count').append(" Results for: ");
}
}
};
function friendRequestCallbackSidebar(userId) {
// toggle the pre-click and post-click divs
$('div[layout=sidebar] div[user-id=' + userId + '].sidebar-search-connected').show();
$('div[layout=sidebar] div[user-id=' + userId + '].sidebar-search-result').hide();
}
function friendRequestCallbackSearchResults(userId) {
// toggle the pre-click and post-click divs
$('div[user-id=' + userId + '].search-connected').show();
$('div[user-id=' + userId + '].search-result').hide();
}
function sendFriendRequest(evt) {
evt.stopPropagation();
var userId = $(this).parent().attr('user-id');
context.JK.sendFriendRequest(app, userId, friendRequestCallback);
}
if ($(this).closest('#sidebar-search-results')) {
context.JK.sendFriendRequest(app, userId, friendRequestCallbackSidebar);
} else {
context.JK.sendFriendRequest(app, userId, friendRequestCallbackSearchResults);
}
}
function getInstrumentHtml(instruments) {
var instrumentLogoHtml = '';
@ -124,6 +228,7 @@
};
app.bindScreen('searchResults', screenBindings);
events();
initializeSearchNavLinks();
};
};

View File

@ -9,6 +9,18 @@
var rest = context.JK.Rest();
var invitationDialog = null;
function initializeSearchPanel() {
$('#search_text_type').change(function() {
searchForInput();
context.JK.SearchResultScreen.searchTypeSelection($('#search_text_type').val());
});
}
context.JK.Sidebar.searchTypeSelection = function(typeSelection) {
$('#search_text_type').val(typeSelection);
emptySearchResults();
}
function initializeFriendsPanel() {
/////////////////////////////////////////////////////////////
@ -211,6 +223,7 @@
else if (type === context.JK.MessageType.RECORDING_MASTER_MIX_COMPLETE) {
$notification.find('#div-actions').hide();
context.jamClient.OnDownloadAvailable(); // poke backend, letting it know a download is available
}
else if (type === context.JK.MessageType.BAND_INVITATION) {
@ -252,66 +265,13 @@
}
function search(query) {
logger.debug('query=' + query);
if (query !== '') {
context.JK.search(query, app, onSearchSuccess);
context.JK.search(query, app, context.JK.SearchResultScreen.onSearchSuccess);
}
}
function onSearchSuccess(response) {
// TODO: generalize this for each search result type (band, musician, recordings, et. al.)
$.each(response.musicians, function(index, val) {
// fill in template for Connect pre-click
var template = $('#template-sidebar-search-result').html();
var searchResultHtml = context.JK.fillTemplate(template, {
userId: val.id,
avatar_url: context.JK.resolveAvatarUrl(val.photo_url),
profile_url: "/#/profile/" + val.id,
userName: val.name,
location: val.location
});
$('#sidebar-search-results').append(searchResultHtml);
// fill in template for Connect post-click
template = $('#template-sidebar-invitation-sent').html();
var invitationSentHtml = context.JK.fillTemplate(template, {
userId: val.id,
first_name: val.first_name,
profile_url: "/#/profile/" + val.id
});
$('#sidebar-search-results').append(invitationSentHtml);
// initialize visibility of the divs
$('div[layout=sidebar] div[user-id=' + val.id + '].sidebar-search-connected').hide();
$('div[layout=sidebar] div[user-id=' + val.id + '].sidebar-search-result').show();
// wire up button click handler if search result is not a friend or the current user
var $sidebar = $('div[layout=sidebar] div[user-id=' + val.id + ']');
if (!val.is_friend && val.id !== context.JK.currentUserId) {
$sidebar.find('.btn-connect-friend').click(sendFriendRequest);
}
// hide the button if the search result is already a friend
else {
$sidebar.find('.btn-connect-friend').hide();
}
});
// show header
$('#sidebar-search-header').show();
// hide panels
$('[layout-panel="contents"]').hide();
$('[layout-panel="contents"]').css({"height": "1px"});
// resize search results area
$('#sidebar-search-results').height(getHeight() + 'px');
}
function getHeight() {
context.JK.Sidebar.getHeight = function() {
// TODO: refactor this - copied from layout.js
var sidebarHeight = $(context).height() - 75 - 2 * 60 + $('[layout-sidebar-expander]').height();
var combinedHeaderHeight = $('[layout-panel="contents"]').length * 36;
@ -324,7 +284,7 @@
function showFriendsPanel() {
var $expandedPanelContents = $('[layout-id="panelFriends"] [layout-panel="contents"]');
var expandedPanelHeight = getHeight();
var expandedPanelHeight = context.JK.Sidebar.getHeight();
// hide all other contents
$('[layout-panel="contents"]').hide();
@ -335,18 +295,6 @@
$expandedPanelContents.animate({"height": expandedPanelHeight + "px"}, 400);
}
function friendRequestCallback(userId) {
// toggle the pre-click and post-click divs
$('div[layout=sidebar] div[user-id=' + userId + '].sidebar-search-connected').show();
$('div[layout=sidebar] div[user-id=' + userId + '].sidebar-search-result').hide();
}
function sendFriendRequest(evt) {
evt.stopPropagation();
var userId = $(this).parent().attr('user-id');
context.JK.sendFriendRequest(app, userId, friendRequestCallback);
}
function hideSearchResults() {
emptySearchResults();
$('#search-input').val('');
@ -412,6 +360,21 @@
function inviteHoverOut() {
$('.invitation-button-holder').slideUp();
}
function searchForInput() {
var query = $('#search-input').val();
// logger.debug("query=" + query);
if (query === '') {
return hideSearchResults();
}
if (query.length > 2) {
// FIXME: this is in searchResults
$('#query').html(query);
query += '&search_text_type='+$('#search_text_type').val();
emptySearchResults();
search(query);
}
}
function events() {
$('#search-input').keyup(function(evt) {
@ -420,24 +383,12 @@
if (evt.which === 13) {
return hideSearchResults();
}
// ESCAPE KEY
if (evt.which === 27) {
return hideSearchResults();
}
var query = $('#search-input').val();
logger.debug("query=" + query);
if (query === '') {
return hideSearchResults();
}
if (query.length > 2) {
emptySearchResults();
search(query);
}
}, 1000);
searchForInput();
}, 500);
});
$('#sidebar-search-expand').click(function(evt) {
@ -923,6 +874,7 @@
this.initialize = function(invitationDialogInstance) {
events();
initializeSearchPanel();
initializeFriendsPanel();
initializeChatPanel();
initializeNotificationsPanel();

Some files were not shown because too many files have changed in this diff Show More