Class: SecretKnock

Inherits:
Object
  • Object
show all
Defined in:
lib/secret_knock.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(verbose: true, external: nil, short_delay: 0.35, long_delay: 0.9, debug: false) ⇒ SecretKnock

Returns a new instance of SecretKnock.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/secret_knock.rb', line 10

def initialize(verbose: true, external: nil, 
               short_delay: 0.35, long_delay: 0.9, debug: false)

  @verbose, @external, @debug = verbose, external, debug

  # ranked by frequency. see https://en.wikipedia.org/wiki/Letter_frequency
  keys = ["e", "t", "a", "o", "i", "n", "s", "h", "r", "d", "l", "c", "u", "m",
                      "w", "f", "g", "y", "p", "b", "v", "k", "j", "x", "q", "z"]


  # number the keys including numbers and special functions (i.e. backspace)

  i = 0
  a = ([' '] + keys + ('1'..'9').to_a + ['0','<backspace>']).map do |x|
    i += 1
    i += 1 while i.to_s[-1].to_i > 6 or i.to_s[-1].to_i == 0
    [x, i]
  end

  # create and sort in alphabetical order the 
  #   hash lookup and inverted hash lookup

  @h = (a.take(27).sort_by(&:first) + a[27..-1]).to_h
  @h.merge!({"7" => 7, "8" => 8, "9" => 9})

  #>  h contains the following
  # {
  #    " "=>1, "a"=>4, "b"=>33, "c"=>21, "d"=>15, "e"=>2, "f"=>25, "g"=>26,
  #    "h"=>13, "i"=>6, "j"=>36, "k"=>35, "l"=>16, "m"=>23, "n"=>11, "o"=>5, 
  #    "p"=>32, "q"=>42, "r"=>14, "s"=>12, "t"=>3, "u"=>22, "v"=>34, "w"=>24, 
  #    "x"=>41, "y"=>31, "z"=>43, "1"=>44, "2"=>45, "3"=>46, "4"=>51, "5"=>52, 
  #    "6"=>53, "7"=>7, "8"=>8, "9"=>9, "0"=>61, "<backspace>"=>62
  # }



  @hb = h.invert

  @short_delay, @long_delay = short_delay, long_delay # seconds
  @listening = false

end

Instance Attribute Details

#hObject (readonly)

Returns the value of attribute h.



8
9
10
# File 'lib/secret_knock.rb', line 8

def h
  @h
end

#listeningObject (readonly)

Returns the value of attribute listening.



8
9
10
# File 'lib/secret_knock.rb', line 8

def listening
  @listening
end

#messageObject (readonly)

Returns the value of attribute message.



8
9
10
# File 'lib/secret_knock.rb', line 8

def message
  @message
end

Instance Method Details

#autoknock(s) ⇒ Object



53
54
55
# File 'lib/secret_knock.rb', line 53

def autoknock(s)
  playback knockerize(s)
end

#detect(timeout: 2, repeat: true) ⇒ Object

listens for knocking in the background which allows the control



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/secret_knock.rb', line 58

def detect(timeout: 2, repeat: true)

  listen
  
  Thread.new do
    
    if @external and @external.respond_to? :on_listening then
      @external.on_listening
    end
    
    sleep 0.2 while @t + timeout > Time.now or @a.length <= 1
    
    if @external and @external.respond_to? :on_processing then
      @external.on_processing
    end
    
    msg = decipher()
    on_timeout msg
    
    begin
      @external.message msg if @external
    rescue
      puts
      puts "\rSecretKnock @external notifier " +  ($!).inspect
    end

    detect(timeout: timeout, repeat: repeat) if repeat
  end
end

#knockedObject Also known as: knock



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/secret_knock.rb', line 88

def knocked()

  t1 = Time.now

  if t1 < @t + @short_delay then

    @i += 1

  else

    @a << ',' if t1 > @t + @long_delay
    puts '' if @verbose
    @i = 1
    @a << 0

  end
  
  print @i.to_s + ' ' if @verbose

  @a[-1] = @i if @a.any?
  
  @t = Time.now

  @external.knock if @external
  
  puts '@a: ' + @a.inspect if @debug
  
end

#knockerize(s) ⇒ Object



126
127
128
129
130
131
132
# File 'lib/secret_knock.rb', line 126

def knockerize(s)

  s.chars.flat_map do |x| 
    @h[x].to_s.chars.map {|n| [:knocks, n.to_i]}  + [:pause]
  end

end

#knocks(n) ⇒ Object



119
120
121
122
123
124
# File 'lib/secret_knock.rb', line 119

def knocks(n)

  n.times { knocked }
  short_pause

end

#listenObject



134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/secret_knock.rb', line 134

def listen()

  @t = Time.now
  @i = 1
  @a = []    
  
  @listening = true

  if block_given? then
    yield self
    stop_listening
  end

end

#long_pauseObject Also known as: pause



149
150
151
152
153
154
# File 'lib/secret_knock.rb', line 149

def long_pause()

  puts "\n*pause*\n\n" if @verbose
  sleep @long_delay + 0.1    

end

#on_timeout(msg = '') ⇒ Object



156
157
158
# File 'lib/secret_knock.rb', line 156

def on_timeout(msg='')
  # override this method if you wish
end

#playback(instructions) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/secret_knock.rb', line 162

def playback(instructions)

  listen do |x|

    sleep 1

    instructions.each do |action|
      name, args = action
      args ? x.method(name).call(args) : x.method(name).call
    end
    
  end    

end

#resetObject



177
178
179
# File 'lib/secret_knock.rb', line 177

def reset()
  @a = []
end

#short_pauseObject



181
182
183
# File 'lib/secret_knock.rb', line 181

def short_pause()
  sleep @short_delay + 0.1
end

#stop_listeningObject



185
186
187
188
189
190
# File 'lib/secret_knock.rb', line 185

def stop_listening()

  @listening = false
  @message = decipher()

end