indexing description: "VamPeer platform (World peer group)" license: "MIT license (see ../license.txt)" author: "Beat Strasser " date: "$Date$" revision: "$Revision$" class P2P_PLATFORM inherit P2P_GENERIC_PEERGROUP export {NONE} load_module_by_specification, when_fully_started redefine init, start_with_arguments, suspend, stop, load_extern_module end P2P_CREATORS_SHARED P2P_SHARED_LOG create make feature {NONE} -- Initialization make (a_cache_directory_path: STRING; a_logger: L4E_LOGGER) is -- Create JXTA platform (world peer group) require Path_valid: a_cache_directory_path /= Void Logger_valid: a_logger /= Void local string_equality_tester: KL_EQUALITY_TESTER [STRING] do -- setup logger in shared class set_vampeer_logger (a_logger) -- general module and peer group initialization logger := a_logger id := id_creator.worldgroup_id module_id := id name := world_peergroup_name description := "Standard World Group implementation" peer_group := Current parent_group := Current implementation_advertisement := default_implementation_advertisement (ref_platform_msid, "P2P_PLATFORM", "Standard World Group Platform") logger.debugging ("platform: Initializing platform") -- peer group module manager create modules_hashed.make (1) create string_equality_tester modules_hashed.set_key_equality_tester (string_equality_tester) -- get configuration and initialize if possible create cache_manager.make (a_cache_directory_path, logger) if not cache_manager.has_failed then logger.debugging ("platform: Cache directory initialized") configuration := cache_manager.configuration_advertisement if is_configured then initialize_platform end else logger.fatal ("platform: Error initializing cache directory") module_status := init_failed end end init (group: P2P_PEERGROUP; an_id: P2P_ID; advertisement: like implementation_advertisement) is -- Unused method in this special peer group. Use `make' instead. do ensure then False -- yes, don't call it end feature -- Access standard_net_peergroup: P2P_PEERGROUP is -- Create standard net peer group instance indexing once_status: global require Configuration_valid: is_configured local npg_mia: P2P_MODULE_IMPLEMENTATION_ADVERTISEMENT once -- look for implementation advertisement if not cache_manager.has_module_implementation_advertisement (ref_net_peergroup_msid) then logger.info ("platform: Creating new standard net peer group module implementation advertisement") npg_mia := peergroup_implementation_advertisement (ref_net_peergroup_msid, "P2P_GENERIC_PEERGROUP", "Standard Net Peer Group") cache_manager.store_module_implementation_advertisement (npg_mia) end -- create net peer group instance Result ?= load_net_peergroup (id_creator.netgroup_id, ref_net_peergroup_msid, Void) if Result /= Void and Result.module_status /= init_failed then -- set net peer group name and description Result.group_advertisement.set_name (net_peergroup_name) Result.group_advertisement.set_description ("Standard Net Peer Group implementation") cache_manager.store_peergroup_advertisement (Result.group_advertisement) logger.info ("platform: Standard net peer group initialized") end end peergroup_implementation_advertisement (a_msid: P2P_MODULE_SPECIFICATION_ID; a_code, a_description: STRING): P2P_MODULE_IMPLEMENTATION_ADVERTISEMENT is -- A net peer group implementation advertisement containing all standard modules' implementation advertisements indexing once_status: global require Msid_valid: a_msid /= Void and a_msid.is_valid Code_valid: a_code /= Void and not a_code.is_empty Description_valid: a_description /= Void and not a_description.is_empty local mia: P2P_MODULE_IMPLEMENTATION_ADVERTISEMENT npg_params: P2P_UNKNOWN_ADVERTISEMENT npg_params_doc: P2P_XML_DOCUMENT once create npg_params_doc.make_with_jxta_root ("Parm") -- Endpoint Service mia := default_implementation_advertisement (ref_endpoint_msid, "P2P_ENDPOINT_SERVICE", "Standard Endpoint Service") npg_params_doc.create_root_child_element ("Svc", namespace_empty) npg_params_doc.add_child_element (npg_params_doc.last_element, mia.document.document.root_element) -- TCP Transport mia := default_implementation_advertisement (ref_transport_tcp_msid, "P2P_TCP_TRANSPORT", "Standard TCP Transport") npg_params_doc.create_root_child_element ("Proto", namespace_empty) npg_params_doc.add_child_element (npg_params_doc.last_element, mia.document.document.root_element) -- Router Transport mia := default_implementation_advertisement (ref_transport_router_msid, "P2P_ENDPOINT_ROUTER", "Standard Endpoint Router") npg_params_doc.create_root_child_element ("Proto", namespace_empty) npg_params_doc.add_child_element (npg_params_doc.last_element, mia.document.document.root_element) -- Discovery Service mia := default_implementation_advertisement (ref_discovery_msid, "P2P_DISCOVERY_SERVICE", "Standard Discovery Service") npg_params_doc.create_root_child_element ("Svc", namespace_empty) npg_params_doc.add_child_element (npg_params_doc.last_element, mia.document.document.root_element) -- Rendezvous Service mia := default_implementation_advertisement (ref_rendezvous_msid, "P2P_RENDEZVOUS_SERVICE", "Standard Rendezvous Service") npg_params_doc.create_root_child_element ("Svc", namespace_empty) npg_params_doc.add_child_element (npg_params_doc.last_element, mia.document.document.root_element) -- Resolver Service mia := default_implementation_advertisement (ref_resolver_msid, "P2P_RESOLVER_SERVICE", "Standard Resolver Service") npg_params_doc.create_root_child_element ("Svc", namespace_empty) npg_params_doc.add_child_element (npg_params_doc.last_element, mia.document.document.root_element) -- Peer Group Result := default_implementation_advertisement (a_msid, a_code, a_description) create npg_params.make_from_element (npg_params_doc.document.root_element) Result.set_parameter (npg_params) ensure Result_set: Result /= Void and Result.is_valid Result_id_set: Result.specification_id.is_equal (a_msid) end default_implementation_advertisement (a_msid: P2P_MODULE_SPECIFICATION_ID; a_code, a_description: STRING): P2P_MODULE_IMPLEMENTATION_ADVERTISEMENT is -- Create default implementation advertisement require Msid_valid: a_msid /= Void and a_msid.is_valid Code_valid: a_code /= Void Description_valid: a_description /= Void do create Result.make (a_msid, standard_module_compatibility, standard_module_code_prefix + a_code) Result.set_description (a_description) Result.set_package_uri (standard_module_package_uri) Result.set_provider (standard_module_provider) ensure Result_set: Result /= Void and Result.is_valid Result_id_set: Result.specification_id.is_equal (a_msid) end default_configuration: P2P_CONFIGURATION is -- Create new platform configuration with new peer id and default service parameters local pid: P2P_PEER_ID npg_id: P2P_NETGROUP_ID do -- Create new peer id in standard net peer group create npg_id.make create pid.make_new_with_group (npg_id.uuid) -- Create configuration advertisement create Result.make_with_id (pid) -- TCP parameter Result.add_service_parameter (transport_tcp_mcid, default_tcp_configuration) -- Rendezvous parameter Result.add_service_parameter (rendezvous_mcid, default_rendezvous_configuration) ensure Result_set: Result /= Void and Result.is_valid end default_tcp_configuration: P2P_TCP_CONFIGURATION is -- Create default configuration for the tcp transport module do -- Automatic interface detection and port selection, multicast turned off create Result.make_auto Result.set_multicast_enabled (False) ensure Result_set: Result /= Void and Result.is_valid end default_rendezvous_configuration: P2P_RENDEZVOUS_CONFIGURATION is -- Create default configuration for the NPG rendezvous service do create Result.make Result.add_seed_uri ("http://rdv.jxtahosts.net/cgi-bin/rendezvous.cgi?2") ensure Result_set: Result /= Void and Result.is_valid end feature -- Status report is_configured: BOOLEAN is -- Is platform configured do Result := configuration /= Void end feature -- Basic operations configure (config: like configuration) is -- Configure platform with given `config' require Config_valid: config /= Void and config.is_valid do configuration := config configuration.make_reconfigured cache_manager.store_configuration_advertisement (configuration) initialize_platform ensure Config_set: is_configured and configuration.is_reconfigured end load_net_peergroup (an_id: P2P_PEERGROUP_ID; specification_id: P2P_MODULE_SPECIFICATION_ID; a_loader: like net_group_loader): P2P_MODULE is -- Load a peer group require No_npg_loaded: lookup_module (net_peergroup_name) = Void Id_valid: an_id /= Void and an_id.is_valid Msid_valid: specification_id /= Void and specification_id.is_valid do -- create worker pool / job queue, if not set if job_queue = Void then create job_queue.make create worker_pool.make (worker_pool_size, job_queue) end net_group_loader := a_loader Result := load_module_by_specification (an_id, specification_id, net_peergroup_name) if Result = Void or Result.module_status = init_failed then module_status := init_failed logger.fatal ("platform: Error loading net peer group module") end ensure Registered_if_successful: (Result /= Void and Result.module_status /= init_failed) implies lookup_module (net_peergroup_name) = Result Job_queue_set: job_queue /= Void end start_with_arguments (args: ARRAY [STRING_8]) is -- Start registered net peer group local npg: P2P_MODULE do npg := lookup_module (net_peergroup_name) if npg /= Void then if worker_pool /= Void and module_status = initializing then -- start worker pool worker_pool.start end npg.start (args) module_status := npg.module_status if module_status = start_ok then logger.info ("platform: Net peer group module successfully started") else logger.fatal ("platform: Error starting net peer group module") end else module_status := start_failed logger.fatal ("platform: Error looking for net peer group module during start") end end suspend is -- Suspend registered net peer group local npg: P2P_MODULE do npg := lookup_module (net_peergroup_name) if npg /= Void then npg.suspend logger.info ("platform: Net peer group module successfully suspended") else logger.fatal ("platform: Error looking for net peer group module during suspend") end module_status := suspended end stop is -- Stop registered net peer group local npg: P2P_MODULE do npg := lookup_module (net_peergroup_name) if npg /= Void then npg.stop if worker_pool /= Void then worker_pool.stop end logger.info ("platform: Net peer group module successfully stopped") else logger.fatal ("platform: Error looking for net peer group module during stop") end module_status := stop_ok end feature {NONE} -- Implementation worker_pool: WORKER_POOL -- Vampeers worker pool (unless managed outside vampeer) Worker_pool_size: NATURAL_16 is 20 -- Number of threads in worker pool initialize_platform is -- Initialize platform with current configuration require Configuration_valid: is_configured do logger.debugging ("platform: Initializing world peer group") -- World group advertisement if not configuration.is_reconfigured then group_advertisement := cache_manager.peergroup_advertisement (id) end if group_advertisement = Void then logger.info ("platform: Creating new world peer group advertisement") create group_advertisement.make (id, ref_platform_msid) group_advertisement.set_name (name) group_advertisement.set_description (description) cache_manager.store_peergroup_advertisement (group_advertisement) end -- Peer advertisement peer_id := configuration.peer_id peer_name := configuration.name if not configuration.is_reconfigured then peer_advertisement := cache_manager.peer_advertisement (id, peer_id) end if peer_advertisement = Void then logger.info ("platform: Creating new peer advertisement for world peer group") create peer_advertisement.make (configuration.peer_id, id) if configuration.name /= Void then peer_advertisement.set_name (configuration.name) end if configuration.description /= Void then peer_advertisement.set_description (configuration.description) end cache_manager.store_peer_advertisement (peer_advertisement) end -- Fetch local ip by resolving rendezvous seed uris resolve_rendezvous_seed_uris if configuration.local_ip = Void then configuration.set_local_ip ("127.0.0.1") logger.warn ("platform: Couldn't detect local ip, set to 127.0.0.1") end -- Create list with standard modules to load create modules_list.make modules_list.put_last (["EndpointService", endpoint_mcid, ref_endpoint_msid, parent_is_owner_if_available]) modules_list.put_last (["TCPTransport", transport_tcp_mcid, ref_transport_tcp_msid, parent_is_owner_if_available]) modules_list.put_last (["RendezvousService", rendezvous_mcid, ref_rendezvous_msid, parent_is_owner_if_available]) modules_list.put_last (["ResolverService", resolver_mcid, ref_resolver_msid, parent_is_owner_if_available]) modules_list.put_last (["DiscoveryService", discovery_mcid, ref_discovery_msid, parent_is_owner_if_available]) modules_list.put_last (["EndpointRouter", transport_router_mcid, ref_transport_router_msid, parent_is_owner_if_available]) remove_disabled_modules ensure Ip_set: configuration.local_ip /= Void end net_group_loader: FUNCTION [ANY, TUPLE [P2P_PEERGROUP, P2P_ID, P2P_MODULE_IMPLEMENTATION_ADVERTISEMENT], P2P_MODULE] load_extern_module (an_id: P2P_ID; a_mia: P2P_MODULE_IMPLEMENTATION_ADVERTISEMENT; a_name: STRING): P2P_MODULE is -- Load extern module do if net_group_loader /= Void then net_group_loader.call ([Current, an_id, a_mia]) Result := net_group_loader.last_result end if Result = Void then Result := Precursor (an_id, a_mia, a_name) end end resolve_rendezvous_seed_uris is -- Fetch rendezvous seeds and update the rendezvous configuration. -- During this, we save also our local ip local failed: BOOLEAN seed_resolver: P2P_SEED_RESOLVER conf: P2P_RENDEZVOUS_CONFIGURATION seed_cursor: DS_LIST_CURSOR [STRING] do if not failed then conf ?= configuration.service_parameter (rendezvous_mcid) if conf /= Void and conf.is_valid then create seed_resolver -- loop through all seed uris from seed_cursor := conf.seed_uris.new_cursor seed_cursor.start until seed_cursor.after loop -- open http connection to get the seeds seed_resolver.resolve (seed_cursor.item) if not seed_resolver.has_failed then if seed_resolver.local_host_address /= Void then configuration.set_local_ip (seed_resolver.local_host_address) end -- store results in rendezvous configuration conf.add_seed_addresses (seed_resolver.found_seeds) end seed_cursor.forth end configuration.renew_document cache_manager.store_configuration_advertisement (configuration) end else logger.error ("platform: Unable to resolve rendezvous seeds") end rescue failed := True retry end end