diff --git a/db/manifest b/db/manifest index b0892ecfe..00a8e8bb2 100755 --- a/db/manifest +++ b/db/manifest @@ -116,4 +116,8 @@ plays_likes_counters.sql add_upright_bass.sql music_session_history_public.sql track_claimed_recording.sql -remove_is_downloadable.sql \ No newline at end of file +scores_mod_users.sql +scores_mod_connections.sql +scores_create_schemas_and_extensions.sql +scores_create_tables.sql +remove_is_downloadable.sql diff --git a/db/up/scores_create_schemas_and_extensions.sql b/db/up/scores_create_schemas_and_extensions.sql new file mode 100644 index 000000000..7de46b7a8 --- /dev/null +++ b/db/up/scores_create_schemas_and_extensions.sql @@ -0,0 +1,10 @@ +-- integrating scores, modify schemas and extensions for postgis + +CREATE SCHEMA tiger; +CREATE SCHEMA topology; + +CREATE EXTENSION IF NOT EXISTS fuzzystrmatch WITH SCHEMA public; +CREATE EXTENSION IF NOT EXISTS postgis WITH SCHEMA public; +CREATE EXTENSION IF NOT EXISTS postgis_tiger_geocoder WITH SCHEMA tiger; +CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; +CREATE EXTENSION IF NOT EXISTS postgis_topology WITH SCHEMA topology; diff --git a/db/up/scores_create_tables.sql b/db/up/scores_create_tables.sql new file mode 100644 index 000000000..4becde36b --- /dev/null +++ b/db/up/scores_create_tables.sql @@ -0,0 +1,145 @@ +-- integrating scores, create geoip tables and jam shadows of those and scores + +----------------- +-- geoipblocks -- +----------------- + +CREATE TABLE geoipblocks +( + beginip BIGINT NOT NULL, + endip BIGINT NOT NULL, + locid INTEGER NOT NULL +); + +-------------- +-- geoipisp -- +-------------- + +CREATE TABLE geoipisp +( + beginip BIGINT NOT NULL, + endip BIGINT NOT NULL, + company CHARACTER VARYING(50) NOT NULL +); + +CREATE INDEX geoipisp_company_ndx ON geoipisp (company); + +-------------------- +-- geoiplocations -- +-------------------- + +CREATE TABLE geoiplocations +( + locid INTEGER PRIMARY KEY, + countrycode CHARACTER VARYING(2), + region CHARACTER VARYING(2), + city CHARACTER VARYING(255), + postalcode CHARACTER VARYING(8), + latitude DOUBLE PRECISION NOT NULL, + longitude DOUBLE PRECISION NOT NULL, + metrocode INTEGER, + areacode CHARACTER(3) +); + +---------------- +-- jamcompany -- +---------------- + +CREATE TABLE jamcompany +( + coid SERIAL PRIMARY KEY, + company CHARACTER VARYING(50) NOT NULL +); + +CREATE UNIQUE INDEX jamcompany_company_ndx ON jamcompany (company); + +------------ +-- jamisp -- +------------ + +CREATE TABLE jamisp +( + beginip BIGINT NOT NULL, + endip BIGINT NOT NULL, + coid INTEGER NOT NULL +); + +CREATE INDEX jamisp_coid_ndx ON jamisp (coid); + +------------ +-- scores -- +------------ + +CREATE TABLE scores +( + alocidispid BIGINT NOT NULL, + anodeid CHARACTER VARYING(64) NOT NULL, + aaddr BIGINT NOT NULL, + blocidispid BIGINT NOT NULL, + bnodeid CHARACTER VARYING(64) NOT NULL, + baddr BIGINT NOT NULL, + score INTEGER NOT NULL, + scorer INTEGER NOT NULL, + score_dt TIMESTAMP NOT NULL DEFAULT current_timestamp +); + +CREATE INDEX scores_alocidispid_blocidispid_score_dt_ndx ON scores (alocidispid, blocidispid, score_dt); +CREATE INDEX scores_blocidispid_alocidispid_score_dt_ndx ON scores (blocidispid, alocidispid, score_dt); + +delete from GeoIPLocations; +insert into GeoIPLocations (locId, countryCode, region, city, postalCode, latitude, longitude, metroCode, areaCode) values + (17192,'US','TX','Austin','78749',30.2076,-97.8587,635,'512'); + +delete from GeoIPBlocks; +insert into GeoIPBlocks (beginIp, endIp, locId) values + (0,4294967295,17192); + +delete from GeoIPISP; +insert into GeoIPISP values + (0,4294967295,'Intergalactic Boogie Corp'); + +DELETE FROM jamcompany; +ALTER SEQUENCE jamcompany_coid_seq RESTART WITH 1; +INSERT INTO jamcompany (company) SELECT DISTINCT company FROM geoipisp ORDER BY company; + +DELETE FROM jamisp; +INSERT INTO jamisp (beginip, endip, coid) SELECT x.beginip, x.endip, y.coid FROM geoipisp x, jamcompany y WHERE x.company = y.company; + +--ALTER TABLE geoiplocations DROP COLUMN geog; +ALTER TABLE geoiplocations ADD COLUMN geog geography(point, 4326); +UPDATE geoiplocations SET geog = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326)::geography; +CREATE INDEX geoiplocations_geog_gix ON geoiplocations USING GIST (geog); + +--ALTER TABLE geoipblocks DROP COLUMN geom; +ALTER TABLE geoipblocks ADD COLUMN geom geometry(polygon); +UPDATE geoipblocks SET geom = ST_MakeEnvelope(beginip, -1, endip, 1); +CREATE INDEX geoipblocks_geom_gix ON geoipblocks USING GIST (geom); + +--ALTER TABLE jamisp DROP COLUMN geom; +ALTER TABLE jamisp ADD COLUMN geom geometry(polygon); +UPDATE jamisp SET geom = ST_MakeEnvelope(beginip, -1, endip, 1); +CREATE INDEX jamisp_geom_gix ON jamisp USING GIST (geom); + +--DROP VIEW current_scores; +CREATE VIEW current_scores AS SELECT * FROM scores s WHERE score_dt = (SELECT max(score_dt) FROM scores s0 WHERE s0.alocidispid = s.alocidispid AND s0.blocidispid = s.blocidispid); + +--DROP FUNCTION get_work (mylocidispid BIGINT); +CREATE FUNCTION get_work (mylocidispid BIGINT) + RETURNS TABLE (client_id VARCHAR(64)) +LANGUAGE plpgsql +ROWS 5 +VOLATILE +AS $BODY$ +BEGIN + CREATE TEMPORARY TABLE foo (locidispid BIGINT, locid INT); + INSERT INTO foo SELECT DISTINCT locidispid, locidispid/1000000 FROM connections; + DELETE FROM foo WHERE locidispid IN (SELECT DISTINCT blocidispid FROM current_scores WHERE alocidispid = mylocidispid AND (current_timestamp - score_dt) < interval '24 hours'); + DELETE FROM foo WHERE locid NOT IN (SELECT locid FROM geoiplocations WHERE geog && st_buffer((SELECT geog from geoiplocations WHERE locid = mylocidispid/1000000), 806000)); + CREATE TEMPORARY TABLE bar (client_id VARCHAR(64), locidispid BIGINT, r DOUBLE PRECISION); + INSERT INTO bar SELECT l.client_id, l.locidispid, random() FROM connections l, foo f WHERE l.locidispid = f.locidispid; + DROP TABLE foo; + DELETE FROM bar b WHERE r != (SELECT max(r) FROM bar b0 WHERE b0.locidispid = b.locidispid); + RETURN QUERY SELECT b.client_id FROM bar b ORDER BY r LIMIT 5; + DROP TABLE bar; + RETURN; +END $BODY$; diff --git a/db/up/scores_mod_connections.sql b/db/up/scores_mod_connections.sql new file mode 100644 index 000000000..2611d15b0 --- /dev/null +++ b/db/up/scores_mod_connections.sql @@ -0,0 +1,28 @@ +-- integrating scores, modify connections object to: +-- drop ip_address (text field) +-- add addr, locidispid, latitude, longitude, countrycode, region, city +-- note, this will force logout of everyone so that the new not null columns will be populated. + +DELETE FROM connections; + +-- ALTER TABLE connections DROP COLUMN ip_address; + +ALTER TABLE connections ADD COLUMN addr BIGINT; +ALTER TABLE connections ALTER COLUMN addr SET NOT NULL; + +ALTER TABLE connections ADD COLUMN locidispid INT; +ALTER TABLE connections ALTER COLUMN locidispid SET NOT NULL; + +ALTER TABLE connections ADD COLUMN latitude DOUBLE PRECISION; +ALTER TABLE connections ALTER COLUMN latitude SET NOT NULL; + +ALTER TABLE connections ADD COLUMN longitude DOUBLE PRECISION; +ALTER TABLE connections ALTER COLUMN longitude SET NOT NULL; + +ALTER TABLE connections ADD COLUMN countrycode CHARACTER VARYING(2); + +ALTER TABLE connections ADD COLUMN region CHARACTER VARYING(2); + +ALTER TABLE connections ADD COLUMN city CHARACTER VARYING(255); + +CREATE INDEX connections_locidispid_ndx ON connections (locidispid); diff --git a/db/up/scores_mod_users.sql b/db/up/scores_mod_users.sql new file mode 100644 index 000000000..f99ca2dc3 --- /dev/null +++ b/db/up/scores_mod_users.sql @@ -0,0 +1,15 @@ +-- integrating scores, modify users table to: +-- todo state should be region, country should be countrycode, lat, lng should be latitude, longitude +-- add addr, locidispid +-- these fields will be updated on login to reflect the last connection details + +ALTER TABLE users ADD COLUMN addr BIGINT; +ALTER TABLE users ADD COLUMN locidispid INTEGER; + +ALTER TABLE users ALTER COLUMN addr SET DEFAULT 0; +ALTER TABLE users ALTER COLUMN locidispid SET DEFAULT 0; + +UPDATE users SET addr = 0, locidispid = 0; + +ALTER TABLE users ALTER COLUMN addr SET NOT NULL; +ALTER TABLE users ALTER COLUMN locidispid SET NOT NULL; diff --git a/ruby/lib/jam_ruby/connection_manager.rb b/ruby/lib/jam_ruby/connection_manager.rb index bf9fb7614..0e9ee5baf 100644 --- a/ruby/lib/jam_ruby/connection_manager.rb +++ b/ruby/lib/jam_ruby/connection_manager.rb @@ -5,7 +5,7 @@ module JamRuby # for 'SQL convenience', this is a obvious place we can go away from a database # as an optimization if we find it's too much db traffic created' # At a minimum, though, we could make connections an UNLOGGED table because if the database crashes, -# all clients should reconnect and restablish their connection anyway +# all clients should reconnect and re-establish their connection anyway # # All methods in here could also be refactored as stored procedures, if we stick with a database. # This may make sense in the short term if we are still managing connections in the database, but @@ -43,8 +43,8 @@ module JamRuby music_session.before_destroy if music_session end - # reclaim the existing connection, - def reconnect(conn, reconnect_music_session_id) + # reclaim the existing connection, if ip_address is not nil then perhaps a new address as well + def reconnect(conn, reconnect_music_session_id, ip_address) music_session_id = nil reconnected = false @@ -55,6 +55,9 @@ module JamRuby music_session_id_expression = "(CASE WHEN music_session_id='#{reconnect_music_session_id}' THEN music_session_id ELSE NULL END)" end + if ip_address + # todo turn ip_address string into a number, then fetch the locid and ispid and the other stuff... + end sql =< JamRuby::Connection do sequence(:client_id) { |n| "Client#{n}" } + ip_address "1.1.1.1" as_musician true + addr 0 + locidispid 0 + latitude 0.0 + longitude 0.0 + countrycode 'US' + region 'TX' + city 'Austin' end factory :invitation, :class => JamRuby::Invitation do diff --git a/web/app/controllers/api_bands_controller.rb b/web/app/controllers/api_bands_controller.rb index e3fcfedbc..ebb1f56dc 100644 --- a/web/app/controllers/api_bands_controller.rb +++ b/web/app/controllers/api_bands_controller.rb @@ -32,7 +32,7 @@ class ApiBandsController < ApiController def validate @band = Band.build_band(current_user, params) @band.valid? - + puts ">>>>>>>>>>>>>>>>> #{@band.errors.inspect}" if @band.errors.any? respond_with_model(@band) end diff --git a/web/spec/factories.rb b/web/spec/factories.rb index 83782cc56..3e83166a6 100644 --- a/web/spec/factories.rb +++ b/web/spec/factories.rb @@ -70,9 +70,16 @@ FactoryGirl.define do factory :connection, :class => JamRuby::Connection do + sequence(:client_id) { |n| "client_id#{n}"} ip_address "1.1.1.1" as_musician true - sequence(:client_id) { |n| "client_id#{n}"} + addr 0 + locidispid 0 + latitude 0.0 + longitude 0.0 + countrycode 'US' + region 'TX' + city 'Austin' end factory :friendship, :class => JamRuby::Friendship do diff --git a/web/spec/features/bands_spec.rb b/web/spec/features/bands_spec.rb index f61e65ff1..44b004b46 100644 --- a/web/spec/features/bands_spec.rb +++ b/web/spec/features/bands_spec.rb @@ -47,6 +47,7 @@ describe "Bands", :js => true, :type => :feature, :capybara_feature => true do first('#band-genres input[type="checkbox"]').trigger(:click) end + sleep 1 # work around race condition find('#btn-band-setup-next').trigger(:click) find('h2', text: 'Step 2: Add Band Members') diff --git a/websocket-gateway/lib/jam_websockets/router.rb b/websocket-gateway/lib/jam_websockets/router.rb index b61ad42ef..7e32be0b9 100644 --- a/websocket-gateway/lib/jam_websockets/router.rb +++ b/websocket-gateway/lib/jam_websockets/router.rb @@ -463,6 +463,7 @@ module JamWebsockets end client.client_id = client_id + remote_ip = extract_ip(client) if !user.nil? @log.debug "user #{user} logged in with client_id #{client_id}" @@ -475,7 +476,7 @@ module JamWebsockets music_session_upon_reentry = connection.music_session ConnectionManager.active_record_transaction do |connection_manager| - music_session_id, reconnected = connection_manager.reconnect(connection, reconnect_music_session_id) + music_session_id, reconnected = connection_manager.reconnect(connection, reconnect_music_session_id, remote_ip) context = @client_lookup[client_id] if music_session_id.nil? # if this is a reclaim of a connection, but music_session_id comes back null, then we need to check if this connection was IN a music session before. @@ -494,7 +495,6 @@ module JamWebsockets end # respond with LOGIN_ACK to let client know it was successful - remote_ip = extract_ip(client) @semaphore.synchronize do # remove from pending_queue @@ -545,7 +545,7 @@ module JamWebsockets connection.touch ConnectionManager.active_record_transaction do |connection_manager| - connection_manager.reconnect(connection, connection.music_session_id) + connection_manager.reconnect(connection, connection.music_session_id, nil) end if connection.stale? end