using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading.Tasks; using Npgsql; using NpgsqlTypes; using skyscraper5.Dvb.Descriptors; using skyscraper5.Dvb.Psi.Model; using skyscraper5.Skyscraper.Scraper.Storage.Utilities; using static skyscraper5.Dvb.Descriptors.ServiceListDescriptor; using static skyscraper5.src.InteractionChannel.Model.Rmt; namespace skyscraper5.Data.PostgreSql { public partial class PostgresqlDataStore { private HashSet _knownBatBouquets; public bool TestForBatBouquet(BatBouquet batBouquet) { if (_knownBatBouquets == null) _knownBatBouquets = new HashSet(); DatabaseKeyBatBouquet key = new DatabaseKeyBatBouquet(batBouquet.BouquetId); if (_knownBatBouquets.Contains(key)) return true; bool result = false; using (NpgsqlConnection connection = new NpgsqlConnection(connectionStringBuilder.ToString())) { connection.Open(); NpgsqlCommand command = connection.CreateCommand(); command.CommandText = "SELECT dateadded FROM dvb_bat WHERE id = @id"; command.Parameters.AddWithValue("@id", NpgsqlDbType.Integer, (int)batBouquet.BouquetId); NpgsqlDataReader dataReader = command.ExecuteReader(); result = dataReader.Read(); dataReader.Close(); command.Dispose(); connection.Close(); } if (result) _knownBatBouquets.Add(key); return result; } public void StoreBatBouquet(BatBouquet batBouquet) { DatabaseKeyBatBouquet key = new DatabaseKeyBatBouquet(batBouquet.BouquetId); EnqueueTask(x => WriteBatBouquet(x, batBouquet)); _knownBatBouquets.Add(key); if (_updatedBats == null) _updatedBats = new HashSet(); _updatedBats.Add(key); } private void WriteBatBouquet(NpgsqlConnection conn, BatBouquet bouquet) { NpgsqlCommand command = conn.CreateCommand(); command.CommandText = "insert into dvb_bat (id, bouquet_name, private_data_specifier, uri_linkage_type, uri, min_polling_interval, control_remote_access_over_internet, do_not_apply_revocation, do_not_scramble) " + "values " + "(@id, @bouquet_name, @private_data_specifier, @uri_linkage_type, @uri, @min_polling_interval, @control_remote_access_over_internet, @do_not_apply_revocation, @do_not_scramble)"; command.Parameters.AddParameter("@id", NpgsqlDbType.Integer, (int)bouquet.BouquetId); command.Parameters.AddParameter("@bouquet_name", NpgsqlDbType.Text, bouquet.BouquetName); command.Parameters.AddParameter("@private_data_specifier", NpgsqlDbType.Bigint, bouquet.PrivateDataSpecifier); command.Parameters.AddParameter("@uri_linkage_type", NpgsqlDbType.Integer, bouquet.UriLinkageType); command.Parameters.AddParameter("@uri", NpgsqlDbType.Text, bouquet.Uri); command.Parameters.AddParameter("@min_polling_interval", NpgsqlDbType.Integer, bouquet.MinPollingInterval); command.Parameters.AddParameter("@control_remote_access_over_internet", NpgsqlDbType.Integer, bouquet.ControlRemoteAccessOverInternet); command.Parameters.AddParameter("@do_not_apply_revocation", NpgsqlDbType.Boolean, bouquet.DoNotApplyRevocation); command.Parameters.AddParameter("@do_not_scramble", NpgsqlDbType.Boolean, bouquet.DoNotScramble); command.ExecuteNonQuery(); command.Dispose(); WriteBatCountryAvailability(conn, bouquet); WriteBatLinkage(conn, bouquet); WriteBatMultilingualBouquetNames(conn, bouquet); } private void WriteBatMultilingualBouquetNames(NpgsqlConnection conn, BatBouquet bouquet) { if (bouquet.MultilingualBouquetName == null) return; if (bouquet.MultilingualBouquetName.MultilingualBouquetName == null) return; NpgsqlCommand cmd = conn.CreateCommand(); cmd.CommandText = "insert into dvb_bat_multilingual_bouquet_names (id, k, v)\r\nvalues (@id,@k,@v)"; cmd.Parameters.AddWithValue("@id", NpgsqlDbType.Integer, (int)bouquet.BouquetId); cmd.Parameters.Add("@k", NpgsqlDbType.Varchar); cmd.Parameters.Add("@v", NpgsqlDbType.Text); foreach (KeyValuePair keyValuePair in bouquet.MultilingualBouquetName.MultilingualBouquetName) { cmd.Parameters["@k"].Value = keyValuePair.Key; cmd.Parameters["@v"].Value = keyValuePair.Value; cmd.ExecuteNonQuery(); } } private void WriteBatLinkage(NpgsqlConnection conn, BatBouquet bouquet) { if (bouquet.Linkages == null) return; NpgsqlCommand command = conn.CreateCommand(); command.CommandText = "insert into dvb_bat_linkages (id, ordinal, l_tsid, l_onid, l_sid, linkage_type, handover_type, handover_origin_type, handover_network_id, handover_initial_service_id, target_event_id, target_event_listed, target_event_simulcasted, table_type, private_data_bytes, bouquet_id) " + "values " + "(@id,@ordinal,@l_tsid,@l_onid,@l_sid,@linkage_type,@handover_type,@handover_origin_type,@handover_network_id,@handover_initial_service_id,@target_event_id,@target_event_listed,@target_event_simulcasted,@table_type,@private_data_bytes,@bouquet_id)"; command.Parameters.AddParameter("@id", NpgsqlDbType.Integer,bouquet.BouquetId); command.Parameters.Add("@ordinal", NpgsqlDbType.Integer); command.Parameters.Add("@l_tsid", NpgsqlDbType.Integer); command.Parameters.Add("@l_onid", NpgsqlDbType.Integer); command.Parameters.Add("@l_sid", NpgsqlDbType.Integer); command.Parameters.Add("@linkage_type", NpgsqlDbType.Integer); command.Parameters.Add("@handover_type", NpgsqlDbType.Integer); command.Parameters.Add("@handover_origin_type", NpgsqlDbType.Boolean); command.Parameters.Add("@handover_network_id", NpgsqlDbType.Integer); command.Parameters.Add("@handover_initial_service_id", NpgsqlDbType.Integer); command.Parameters.Add("@target_event_id", NpgsqlDbType.Integer); command.Parameters.Add("@target_event_listed", NpgsqlDbType.Boolean); command.Parameters.Add("@target_event_simulcasted", NpgsqlDbType.Boolean); //@table_type,@private_data_bytes,@bouquet_id)"; command.Parameters.Add("@table_type", NpgsqlDbType.Integer); command.Parameters.Add("@private_data_bytes", NpgsqlDbType.Bytea); command.Parameters.Add("@bouquet_id", NpgsqlDbType.Integer); for (int i = 0; i < bouquet.Linkages.Count; i++) { LinkageDescriptor linkage = bouquet.Linkages[i]; command.Parameters["@ordinal"].Value = i; command.Parameters["@l_tsid"].Value = (int)linkage.TransportStreamId; command.Parameters["@l_onid"].Value = (int)linkage.OriginalNetworkId; command.Parameters["@l_sid"].Value = (int)linkage.ServiceId; command.Parameters["@linkage_type"].Value = (int)linkage.LinkageType; command.Parameters["@handover_type"].Value = linkage.HandoverType.HasValue ? linkage.HandoverType.Value : DBNull.Value; command.Parameters["@handover_origin_type"].Value = linkage.HandoverOriginType.HasValue ? linkage.HandoverOriginType.Value : DBNull.Value; command.Parameters["@handover_network_id"].Value = linkage.HandoverNetworkId.HasValue ? linkage.HandoverNetworkId.Value : DBNull.Value; command.Parameters["@handover_initial_service_id"].Value = linkage.HandoverInitialServiceId.HasValue ? linkage.HandoverInitialServiceId.Value : DBNull.Value; command.Parameters["@target_event_id"].Value = linkage.TargetEventId.HasValue ? linkage.TargetEventId.Value : DBNull.Value; command.Parameters["@target_event_listed"].Value = linkage.TargetEventListed.HasValue ? linkage.TargetEventListed.Value : DBNull.Value; command.Parameters["@target_event_simulcasted"].Value = linkage.TargetEventSimulcasted.HasValue ? linkage.TargetEventSimulcasted.Value : DBNull.Value; command.Parameters["@table_type"].Value = linkage.TableType.HasValue ? (int)linkage.TableType.Value : DBNull.Value; command.Parameters["@private_data_bytes"].Value = linkage.PrivateDataBytes != null ? linkage.PrivateDataBytes : DBNull.Value; command.Parameters["@bouquet_id"].Value = linkage.BouquetId.HasValue ? linkage.BouquetId : DBNull.Value; command.ExecuteNonQuery(); WriteBatLinkageExtendedLinkages(conn, bouquet, i); WriteBatLinkageIpmacLinkage(conn, bouquet, i); WriteBatLinkageSsuLinkStructure(conn, bouquet, i); } } private void WriteBatLinkageSsuLinkStructure(NpgsqlConnection conn, BatBouquet bouquet, int ordinal) { if (bouquet.Linkages[ordinal].SystemSoftwareUpdateLinkStructure == null) return; NpgsqlCommand command = conn.CreateCommand(); command.CommandText = "INSERT INTO dvb_bat_linkages_ssu_link_structure (id, ordinal, subordinal, oui, selector) " + "VALUES (@id, @ordinal, @subordinal, @oui, @selector)"; command.Parameters.AddWithValue("@id", NpgsqlDbType.Integer, (int)bouquet.BouquetId); command.Parameters.AddWithValue("@ordinal", NpgsqlDbType.Integer, ordinal); command.Parameters.Add("@subordinal", NpgsqlDbType.Integer); command.Parameters.Add("@oui", NpgsqlDbType.Varchar); command.Parameters.AddWithValue("@selector", NpgsqlDbType.Bytea); for (int i = 0; i < bouquet.Linkages[ordinal].SystemSoftwareUpdateLinkStructure.Count; i++) { command.Parameters["@subordinal"].Value = i; command.Parameters["@oui"].Value = BitConverter.ToString(bouquet.Linkages[ordinal].SystemSoftwareUpdateLinkStructure[i].OUI); command.Parameters["@selector"].Value = bouquet.Linkages[ordinal].SystemSoftwareUpdateLinkStructure[i].Selector; command.ExecuteNonQuery(); } } private void WriteBatLinkageIpmacLinkage(NpgsqlConnection conn, BatBouquet bouquet, int ordinal) { if (bouquet.Linkages[ordinal].IpMacNotificationLinkages == null) return; for (int i = 0; i < bouquet.Linkages[ordinal].IpMacNotificationLinkages.Count; i++) { throw new NotImplementedException(); } } private void WriteBatLinkageExtendedLinkages(NpgsqlConnection conn, BatBouquet bouquet, int ordinal) { if (bouquet.Linkages[ordinal].ExtendedEventLinkages == null) return; for (int i = 0; i < bouquet.Linkages[ordinal].ExtendedEventLinkages.Length; i++) { throw new NotImplementedException(); } } private void WriteBatCountryAvailability(NpgsqlConnection conn, BatBouquet bouquet) { if (bouquet.CountryAvailabilityDictionary == null) return; NpgsqlCommand command = conn.CreateCommand(); command.CommandText = "INSERT INTO dvb_bat_country_availability (id,k,v) " + "VALUES (@id,@k,@v)"; command.Parameters.AddWithValue("@id", (int)bouquet.BouquetId); command.Parameters.Add("@k", NpgsqlDbType.Varchar); command.Parameters.Add("@v", NpgsqlDbType.Boolean); foreach (KeyValuePair keyValuePair in bouquet.CountryAvailabilityDictionary) { command.Parameters["@k"].Value = keyValuePair.Key; command.Parameters["@v"].Value = keyValuePair.Value; command.ExecuteNonQuery(); } } private HashSet _updatedBats; public bool UpdateBatBouquet(BatBouquet batBouquet) { if (_updatedBats == null) _updatedBats = new HashSet(); DatabaseKeyBatBouquet key = new DatabaseKeyBatBouquet(batBouquet.BouquetId); if (_updatedBats.Contains(key)) return false; EnqueueTask(x => WriteBatBouquetUpdate(x, batBouquet)); _updatedBats.Add(key); return true; } private void WriteBatBouquetUpdate(NpgsqlConnection connection, BatBouquet newer) { BatBouquet older = SelectBat(connection, newer.BouquetId); if (!older.NeedUpdate(newer)) return; NpgsqlCommand command = connection.CreateCommand(); command.CommandText = "UPDATE dvb_bat\r\nSET bouquet_name = @bouquet_name,\r\n private_data_specifier = @private_data_specifier,\r\n uri_linkage_type = @uri_linkage_type,\r\n uri = @uri,\r\n min_polling_interval = @min_polling_interval,\r\n control_remote_access_over_internet = @control_remote_access_over_internet,\r\n do_not_apply_revocation = @do_not_apply_revocation,\r\n do_not_scramble = @do_not_scramble,\r\n updated_counter = updated_counter + 1,\r\n updated_timestamp = CURRENT_TIMESTAMP\r\nWHERE id = @id"; command.Parameters.AddParameter("@id", NpgsqlDbType.Integer, (int)newer.BouquetId); command.Parameters.AddParameter("@bouquet_name", NpgsqlDbType.Text, newer.BouquetName); command.Parameters.AddParameter("@private_data_specifier", NpgsqlDbType.Bigint, newer.PrivateDataSpecifier); command.Parameters.AddParameter("@uri_linkage_type", NpgsqlDbType.Integer, newer.UriLinkageType); command.Parameters.AddParameter("@uri", NpgsqlDbType.Text, newer.Uri); command.Parameters.AddParameter("@min_polling_interval", NpgsqlDbType.Integer, newer.MinPollingInterval); command.Parameters.AddParameter("@control_remote_access_over_internet", NpgsqlDbType.Integer, newer.ControlRemoteAccessOverInternet); command.Parameters.AddParameter("@do_not_apply_revocation", NpgsqlDbType.Boolean, newer.DoNotApplyRevocation); command.Parameters.AddParameter("@do_not_scramble", NpgsqlDbType.Boolean, newer.DoNotScramble); command.ExecuteNonQuery(); } private BatBouquet SelectBat(NpgsqlConnection connection, int id) { NpgsqlCommand command = connection.CreateCommand(); command.CommandText = "SELECT * FROM dvb_bat WHERE id = @id"; command.Parameters.AddWithValue("@id", id); NpgsqlDataReader dataReader = command.ExecuteReader(); BatBouquet result = null; if (dataReader.Read()) { ushort id2 = (ushort)dataReader.GetInt32(0); result = new BatBouquet(id2); DateTime dateadded = dataReader.GetDateTime(1); result.BouquetName = dataReader.IsDBNull(2) ? null : dataReader.GetString(2); result.PrivateDataSpecifier = dataReader.IsDBNull(3) ? null : (ushort)dataReader.GetInt64(3); result.UriLinkageType = dataReader.IsDBNull(4) ? null : (byte)dataReader.GetInt32(4); result.Uri = dataReader.IsDBNull(5) ? null : dataReader.GetString(5); result.MinPollingInterval = dataReader.IsDBNull(6) ? null : (ushort)dataReader.GetInt32(6); result.ControlRemoteAccessOverInternet = dataReader.IsDBNull(7) ? null : dataReader.GetInt32(7); result.DoNotApplyRevocation = dataReader.IsDBNull(8) ? null : dataReader.GetBoolean(8); result.DoNotScramble = dataReader.IsDBNull(9) ? null : dataReader.GetBoolean(9); int updateCounter = dataReader.GetInt32(10); DateTime? updatedTimestamp = dataReader.IsDBNull(11) ? null : dataReader.GetDateTime(11); } dataReader.Close(); command.Dispose(); return result; } private HashSet _knownBatTs; public bool TestForBatTransportStream(ushort batBouquetBouquetId, BatTransportStream child) { if (_knownBatTs == null) _knownBatTs = new HashSet(); DatabaseKeyBatTs ts = new DatabaseKeyBatTs(batBouquetBouquetId, child.TransportStreamId, child.OriginalNetworkId); if (_knownBatTs.Contains(ts)) return true; bool result = false; using (NpgsqlConnection conn = new NpgsqlConnection(connectionStringBuilder.ToString())) { conn.Open(); NpgsqlCommand command = conn.CreateCommand(); command.CommandText = "SELECT dateAdded FROM dvb_bat_transport_stream WHERE bid = @bid AND tsid = @tsid AND onid = @onid"; command.Parameters.AddWithValue("@bid", NpgsqlDbType.Integer, (int)batBouquetBouquetId); command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, (int)child.TransportStreamId); command.Parameters.AddWithValue("@onid", NpgsqlDbType.Integer, (int)child.OriginalNetworkId); NpgsqlDataReader dataReader = command.ExecuteReader(); result = dataReader.Read(); dataReader.Close(); command.Dispose(); conn.Close(); } if (result) _knownBatTs.Add(ts); return result; } public void StoreBatTransportStream(ushort batBouquetBouquetId, BatTransportStream child) { EnqueueTask(x => WriteBatTransportStream(x, batBouquetBouquetId, child)); DatabaseKeyBatTs key = new DatabaseKeyBatTs(batBouquetBouquetId, child.TransportStreamId, child.OriginalNetworkId); _knownBatTs.Add(key); if (_updatedBatTs == null) _updatedBatTs = new HashSet(); _updatedBatTs.Add(key); } private void WriteBatTransportStream(NpgsqlConnection connection, ushort bouquetId, BatTransportStream transportStream) { NpgsqlCommand command = connection.CreateCommand(); command.CommandText = "INSERT INTO dvb_bat_transport_stream (bid, tsid, onid, private_data_specifier, default_authority) " + "VALUES (@bid, @tsid, @onid, @private_data_specifier, @default_authority)"; command.Parameters.AddWithValue("@bid", NpgsqlDbType.Integer, (int)bouquetId); command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, (int)transportStream.TransportStreamId); command.Parameters.AddWithValue("@onid", NpgsqlDbType.Integer, (int)transportStream.OriginalNetworkId); command.Parameters.AddParameter("@private_data_specifier", NpgsqlDbType.Bigint, transportStream.PrivateDataSpecifier); command.Parameters.AddParameter("@default_authority", NpgsqlDbType.Text, transportStream.DefaultAuthority); command.ExecuteNonQuery(); WriteBatTransportStreamCountryAvailability(connection, bouquetId, transportStream); WriteBatTransportStreamServiceList(connection, bouquetId, transportStream); } private bool TestForBatTransportStreamServiceList(NpgsqlConnection connection, int bouquetId, int transportStreamId, int originalNetworkId, int serviceId) { NpgsqlCommand command = connection.CreateCommand(); command.CommandText = "SELECT dateadded FROM dvb_bat_transport_stream_service_list WHERE bid = @bid AND tsid = @tsid AND onid = @onid AND sid = @sid"; command.Parameters.AddWithValue("@bid", NpgsqlDbType.Integer, bouquetId); command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, transportStreamId); command.Parameters.AddWithValue("@onid", NpgsqlDbType.Integer, originalNetworkId); command.Parameters.AddWithValue("@sid", NpgsqlDbType.Integer, serviceId); NpgsqlDataReader dataReader = command.ExecuteReader(); bool result = dataReader.Read(); dataReader.Close(); command.Dispose(); return result; } private void WriteBatTransportStreamServiceList(NpgsqlConnection connection, ushort bouquetId, BatTransportStream transportStream) { if (transportStream.ServiceList == null) return; NpgsqlCommand command = connection.CreateCommand(); command.CommandText = "INSERT INTO dvb_bat_transport_stream_service_list (bid,tsid,onid,sid,service_type)" + "VALUES (@bid,@tsid,@onid,@sid,@service_type)"; command.Parameters.AddWithValue("@bid", NpgsqlDbType.Integer, (int)bouquetId); command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, (int)transportStream.TransportStreamId); command.Parameters.AddWithValue("@onid", NpgsqlDbType.Integer, (int)transportStream.OriginalNetworkId); command.Parameters.Add("@sid", NpgsqlDbType.Integer); command.Parameters.Add("@service_type", NpgsqlDbType.Integer); foreach (ServiceListDescriptor.Service service in transportStream.ServiceList) { if (TestForBatTransportStreamServiceList(connection,(int)bouquetId,(int)transportStream.TransportStreamId,(int)transportStream.OriginalNetworkId,service.ServiceId)) { continue; } command.Parameters["@sid"].Value = (int)service.ServiceId; command.Parameters["@service_type"].Value = (int)service.ServiceType; command.ExecuteNonQuery(); } } private void WriteBatTransportStreamCountryAvailability(NpgsqlConnection connection, ushort bouquetId, BatTransportStream transportStream) { if (transportStream.CountryAvailability == null) return; foreach (KeyValuePair keyValuePair in transportStream.CountryAvailability) { throw new NotImplementedException(); } } private HashSet _updatedBatTs; public bool UpdateBatTransportStream(ushort batBouquetBouquetId, BatTransportStream child) { if (_updatedBatTs == null) _updatedBatTs = new HashSet(); DatabaseKeyBatTs key = new DatabaseKeyBatTs(batBouquetBouquetId, child.TransportStreamId, child.OriginalNetworkId); if (_updatedBatTs.Contains(key)) return false; EnqueueTask(x => WriteUpdateBatTs(x, batBouquetBouquetId, child)); _updatedBatTs.Add(key); return true; } private void WriteUpdateBatTs(NpgsqlConnection connection, ushort batBouquetBouquetId, BatTransportStream transportStream) { DatabaseKeyBatTs key = new DatabaseKeyBatTs(batBouquetBouquetId, transportStream.TransportStreamId, transportStream.OriginalNetworkId); BatTransportStream older = SelectBatTs(connection, batBouquetBouquetId, transportStream.TransportStreamId, transportStream.OriginalNetworkId); if (!older.NeedsUpdate(transportStream)) { return; } NpgsqlCommand command = connection.CreateCommand(); command.CommandText = "UPDATE dvb_bat_transport_stream " + "SET private_data_specifier = @private_data_specifier,\r\n default_authority = @default_authority " + "WHERE bid = @bid AND tsid = @tsid AND onid = @onid\r\n"; command.Parameters.AddWithValue("@bid", NpgsqlDbType.Integer, (int)batBouquetBouquetId); command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, (int)transportStream.TransportStreamId); command.Parameters.AddWithValue("@onid", NpgsqlDbType.Integer, (int)transportStream.OriginalNetworkId); command.Parameters.AddParameter("@private_data_specifier", NpgsqlDbType.Bigint, transportStream.PrivateDataSpecifier); command.Parameters.AddParameter("@default_authority", NpgsqlDbType.Text, transportStream.DefaultAuthority); command.ExecuteNonQuery(); } private BatTransportStream SelectBatTs(NpgsqlConnection conn, ushort bouquetId, ushort transportStreamId, ushort originalNetworkId) { NpgsqlCommand command = conn.CreateCommand(); command.CommandText = "SELECT * FROM dvb_bat_transport_stream WHERE bid = @bid AND tsid = @tsid AND onid = @onid"; command.Parameters.AddParameter("@bid", NpgsqlDbType.Integer, (int)bouquetId); command.Parameters.AddParameter("@tsid", NpgsqlDbType.Integer, (int)transportStreamId); command.Parameters.AddParameter("@onid", NpgsqlDbType.Integer, (int)originalNetworkId); NpgsqlDataReader dataReader = command.ExecuteReader(); BatTransportStream result = null; if (dataReader.Read()) { ushort bid = (ushort)dataReader.GetInt32(0); ushort tsid = (ushort)dataReader.GetInt32(1); ushort onid = (ushort)dataReader.GetInt32(2); DateTime dateadded = dataReader.GetDateTime(3); result = new BatTransportStream(tsid, onid); result.PrivateDataSpecifier = dataReader.IsDBNull(4) ? null : (uint)dataReader.GetInt64(4); result.DefaultAuthority = dataReader.IsDBNull(5) ? null : dataReader.GetString(5); } dataReader.Close(); command.Dispose(); return result; } } }