<commit_before>require 'socket'
require 'ipaddr'

module Wemote
  class Switch
    MULTICAST_ADDR = '192.168.127.12'
    BIND_ADDR = '0.0.0.0'
    PORT = 1900
    DISCOVERY= <<-EOF
M-SEARCH * HTTP/1.1\r
HOST: 192.168.127.12:1900\r
MAN: "ssdp:discover"\r
MX: 10\r
ST: urn:Belkin:device:lightswitch:1\r
\r
EOF

    GET_HEADERS = {
      "SOAPACTION"   => '"urn:Belkin:service:basicevent:1#GetBinaryState"',
      "Content-type" => 'text/xml; charset="utf-8"'
    }

    SET_HEADERS = {
      "SOAPACTION"   => '"urn:Belkin:service:basicevent:1#SetBinaryState"',
      "Content-type" => 'text/xml; charset="utf-8"'
    }

    class << self
      def all(refresh=false)
        @switches = nil if refresh
        @switches ||= fetch_switches
      end

      def find(name)
        all.detect{|s|s.name == name}
      end

      private

      def fetch_switches
        socket = UDPSocket.new
        membership = IPAddr.new(MULTICAST_ADDR).hton + IPAddr.new(BIND_ADDR).hton

        socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, membership)
        socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_TTL, 1)
        socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1)
        socket.bind(BIND_ADDR,PORT)

        switches = []

        3.times { socket.send(DISCOVERY, 0, MULTICAST_ADDR, PORT) }

        # The following is a bit silly, but is necessary for JRuby support,
        # which seems to have some issues with socket interruption.
        # If you have a working JRuby solution that doesn't require this<commit_msg>Abstracted out some socket logic<commit_after>require 'socket'
require 'ipaddr'

module Wemote
  class Switch
    MULTICAST_ADDR = '192.168.127.12'
    BIND_ADDR = '0.0.0.0'
    PORT = 1900
    DISCOVERY= <<-EOF
M-SEARCH * HTTP/1.1\r
HOST: 192.168.127.12:1900\r
MAN: "ssdp:discover"\r
MX: 10\r
ST: urn:Belkin:device:lightswitch:1\r
\r
EOF

    GET_HEADERS = {
      "SOAPACTION"   => '"urn:Belkin:service:basicevent:1#GetBinaryState"',
      "Content-type" => 'text/xml; charset="utf-8"'
    }

    SET_HEADERS = {
      "SOAPACTION"   => '"urn:Belkin:service:basicevent:1#SetBinaryState"',
      "Content-type" => 'text/xml; charset="utf-8"'
    }

    class << self
      def all(refresh=false)
        @switches = nil if refresh
        @switches ||= fetch_switches
      end

      def find(name)
        all.detect{|s|s.name == name}
      end

      private

      def ssdp_socket
        socket = UDPSocket.new
        socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, IPAddr.new(MULTICAST_ADDR).hton + IPAddr.new(BIND_ADDR).hton)
        socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_TTL, 1)
        socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1)
        socket.bind(BIND_ADDR,PORT)
        socket
      end

      def fetch_switches
        socket = ssdp_socket
        switches = []

        3.times { socket.send(DISCOVERY, 0, MULTICAST_ADDR, PORT) }

        # The following is a bit silly, but is necessary for JRuby support,
        # which seems to have some issues with socket interruption.
        # If you have a working JRuby solution that doesn't require this
{'fraction_non_alphanumeric': 0.12060301507537688, 'fraction_numerical': 0.029522613065326633, 'mean_word_length': 2.8189448441247, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 6, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1161998', 'n_tokens_mistral': 1215, 'n_tokens_neox': 1108, 'n_words': 231}