Class: NeocitiesRed::Client

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

Constant Summary collapse

API_URI =
"https://neocities.org/api/"

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Client

Returns a new instance of Client.

Raises:

  • (ArgumentError)


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
52
53
54
55
56
57
58
59
60
# File 'lib/neocities_red/client.rb', line 27

def initialize(opts = {})
  @uri = URI.parse API_URI
  @opts = opts
  @pastel = Pastel.new eachline: "\n"
  @conn = Faraday.new(@uri) do |conn|
    conn.options.timeout = 10
    conn.options.open_timeout = 5
    conn.adapter :net_http

    conn.request :multipart
    conn.request :url_encoded

    conn.request :retry,
                 max: 3,
                 interval: 0.3,
                 backoff_factor: 2,
                 retry_statuses: [429, 500, 502, 503, 504],
                 exceptions: [
                   Faraday::TimeoutError,
                   Faraday::ConnectionFailed,
                   Faraday::SSLError
                 ]

    conn.response :follow_redirects
  end

  raise ArgumentError, "client requires a login (sitename/password) or an api_key" unless opts[:api_key] || (opts[:sitename] && opts[:password])

  if opts[:api_key]
    @conn.request(:authorization, "Bearer", opts[:api_key])
  else
    @conn.request(:authorization, :basic, opts[:sitename], opts[:password])
  end
end

Instance Method Details

#delete(*paths) ⇒ Object



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

def delete(*paths)
  post "delete", "filenames" => paths
end

#delete_wrapper_with_dry_run(paths, dry_run: false) ⇒ Object



171
172
173
174
175
# File 'lib/neocities_red/client.rb', line 171

def delete_wrapper_with_dry_run(paths, dry_run: false)
  return { result: "success" } if dry_run

  delete(paths)
end

#get(path, params = {}) ⇒ Object



185
186
187
188
189
190
191
# File 'lib/neocities_red/client.rb', line 185

def get(path, params = {})
  uri = @uri + path
  uri.query = URI.encode_www_form params
  resp = @conn.get(uri)

  JSON.parse resp.body, symbolize_names: true
end

#info(sitename) ⇒ Object



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

def info(sitename)
  get "info", sitename: sitename
end

#keyObject



135
136
137
# File 'lib/neocities_red/client.rb', line 135

def key
  get "key"
end

#list(path = nil) ⇒ Object



62
63
64
# File 'lib/neocities_red/client.rb', line 62

def list(path = nil)
  get "list", path: path
end

#post(path, args = {}) ⇒ Object



193
194
195
196
197
198
# File 'lib/neocities_red/client.rb', line 193

def post(path, args = {})
  uri = @uri + path
  resp = @conn.post(uri, args)

  JSON.parse resp.body, symbolize_names: true
end

#pull(sitename, last_pull_time = nil, last_pull_loc = nil, quiet: true) ⇒ Object

TODO: refactor

Raises:

  • (ArgumentError)


67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/neocities_red/client.rb', line 67

def pull(sitename, last_pull_time = nil, last_pull_loc = nil, quiet: true)
  site_info = info(sitename)

  raise ArgumentError, site_info[:message] if site_info[:result] == "error"

  info_data = site_info[:info]

  domain =
    if info_data[:domain].to_s.empty?
      "https://#{sitename}.neocities.org/"
    else
      "https://#{info_data[:domain]}/"
    end

  # start stats
  success_loaded = 0
  start_time = Time.now
  curr_dir = Dir.pwd

  # get list of files
  resp = list

  raise ArgumentError, resp[:message] if resp[:result] == "error"

  # fetch each file
  uri_parser = URI::Parser.new
  resp[:files].each do |file|
    if file[:is_directory]
      FileUtils.mkdir_p file[:path].to_s
    else
      print @pastel.bold("Pulling #{file[:path]} ... ") unless quiet

      if last_pull_time &&
         last_pull_loc &&
         Time.parse(file[:updated_at]) <= Time.parse(last_pull_time) &&
         last_pull_loc == curr_dir &&
         File.exist?(file[:path]) # case when user deletes file

        # case when file hasn't been updated since last
        print "#{@pastel.yellow.bold 'NO NEW UPDATES'}\n" unless quiet

        next
      end

      pathtotry = uri_parser.escape(domain + file[:path])
      fileconts = @conn.get pathtotry

      if fileconts.status == 200
        print "#{@pastel.green.bold 'SUCCESS'}\n" unless quiet
        success_loaded += 1

        File.write(file[:path].to_s, fileconts.body)
      elsif !quiet
        print "#{@pastel.red.bold 'FAIL'}\n"
      end
    end
  end

  # calculate time command took
  total_time = Time.now - start_time

  # stop the spinner, if there is one
  Whirly.stop if quiet

  # display stats
  puts @pastel.green "\nSuccessfully fetched #{success_loaded} files in #{total_time.round(2)} seconds"
end

#upload(path, remote_path = nil, dry_run: false) ⇒ Object

Raises:

  • (ArgumentError)


143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/neocities_red/client.rb', line 143

def upload(path, remote_path = nil, dry_run: false)
  path = Pathname path
  raise ArgumentError, "#{path} does not exist." unless path.exist?

  rpath = remote_path || path.basename
  res = upload_hash(rpath.to_s, Digest::SHA1.file(path.to_s).hexdigest)

  file_exists_remotely = if res[:files]
                           res[:files][rpath.to_s.to_sym] == true || res[:files][rpath.to_s] == true
                         else
                           false
                         end

  if file_exists_remotely
    {
      result: "error",
      error_type: "file_exists",
      message: "file already exists and matches local file, not uploading"
    }
  else
    return { result: "success" } if dry_run

    File.open(path.to_s) do |file|
      post "upload", rpath.to_s => Faraday::Multipart::FilePart.new(file, "text/html")
    end
  end
end

#upload_hash(remote_path, sha1_hash) ⇒ Object



139
140
141
# File 'lib/neocities_red/client.rb', line 139

def upload_hash(remote_path, sha1_hash)
  post "upload_hash", remote_path => sha1_hash
end