distributed-press-api-client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +68 -0
  3. data/lib/distributed_press.rb +130 -0
  4. metadata +72 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9851a2ea9ababa58c8a990d18cf2bde427e695c70c641b1fc2bf56849fe8bd95
4
+ data.tar.gz: 9a883d1d204796510a04f4588e99eed5b2093d410b940d62c7c8dd074fb265e2
5
+ SHA512:
6
+ metadata.gz: d19a77c2cef4d0d26c28fb6317c6b0602c8f5c68951c4214a634b136f01a01256077ba3d13f7f4bb1c37f4193bb6f653f7d746b7a3cfef45a300e38481e72ef1
7
+ data.tar.gz: b71374a0b60435231a4b61616935433989f727d810ae3b0c9dea924b67d9419095b3c3fa9665f15d33a5819521e469006812c0404cb5b4b124da689af99b506b
@@ -0,0 +1,68 @@
1
+ # Distributed Press API client
2
+
3
+ This is an API client for [Distributed Press](https://distributed.press/).
4
+
5
+ Supports basic configuration and uploading the website's directory. It
6
+ will create a tarball on the fly, and uses `IO` to minimize memory
7
+ usage. May not work on every operating system.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your Gemfile:
12
+
13
+ ```ruby
14
+ gem 'distributed-press-api-client'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ ```bash
20
+ bundle
21
+ ```
22
+
23
+ Or install it yourself as:
24
+
25
+ ```bash
26
+ gem install distributed-press-api-client
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ```ruby
32
+ require 'distributed_press'
33
+
34
+ dp = DistributedPress.new
35
+ url: 'https://api.distributed.press',
36
+ api_key: 'https://github.com/hyphacoop/api.distributed.press#steps',
37
+ project_domain: 'example.org'
38
+
39
+ dp.configure
40
+ dp.publish '/path/to/your/site'
41
+ ```
42
+
43
+ API key and project domain can be passed as environment variables called
44
+ `DISTRIBUTED_PRESS_API_KEY` and `DISTRIBUTED_PRESS_PROJECT_DOMAIN`
45
+ respectively. API URL is optional and defaults to
46
+ `https://api.distributed.press`.
47
+
48
+ ## Contributing
49
+
50
+ Bug reports and pull requests are welcome on 0xacab.org at
51
+ <https://0xacab.org/sutty/distributed-press-api-client>. This project is
52
+ intended to be a safe, welcoming space for collaboration, and
53
+ contributors are expected to adhere to the [Sutty code of
54
+ conduct](https://sutty.nl/en/code-of-conduct/).
55
+
56
+ If you like our plugins, [please consider
57
+ donating](https://donaciones.sutty.nl/en/)!
58
+
59
+ ## License
60
+
61
+ The gem is available as free software under the terms of the Affero GPL3
62
+ License.
63
+
64
+ ## Code of Conduct
65
+
66
+ Everyone interacting in the distributed-press-api-client project’s
67
+ codebases, issue trackers, chat rooms and mailing lists is expected to
68
+ follow the [code of conduct](https://sutty.nl/en/code-of-conduct/).
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'httparty'
4
+ require 'open3'
5
+
6
+ # Distributed Press (https://distributed.press) API client
7
+ class DistributedPress
8
+ include ::HTTParty
9
+
10
+ NEWLINE = "\r\n"
11
+ BOUNDARY = '--'
12
+
13
+ attr_reader :api_key, :project_domain
14
+
15
+ # @param options [Hash]
16
+ # @option options [String] :url API URL
17
+ # @option options [String] :api_key API Key
18
+ # @option options [String] :project_domain Domain name
19
+ def initialize(url: 'https://api.distributed.press', api_key: nil, project_domain: nil)
20
+ @api_key = api_key || ENV['DISTRIBUTED_PRESS_API_KEY']
21
+ @project_domain = project_domain || ENV['DISTRIBUTED_PRESS_PROJECT_DOMAIN']
22
+
23
+ raise ArgumentError, "API key is missing" unless @api_key
24
+ raise ArgumentError, "Project domain is missing" unless @project_domain
25
+
26
+ self.class.default_options[:base_uri] = HTTParty.normalize_base_uri(url)
27
+ end
28
+
29
+ # Configure the domain
30
+ #
31
+ # @return [Boolean] Configuration was successful
32
+ def configure
33
+ stream, config = IO.pipe
34
+
35
+ Thread.new do
36
+ write_multipart_header config, 'config.json'
37
+ IO.copy_stream StringIO.new({ 'domain' => project_domain }.to_json), config
38
+ write_multipart_footer config
39
+
40
+ config.close
41
+ end
42
+
43
+ result = upload_io('/v0/publication/configure', stream)
44
+
45
+ result['errorCode'].zero?
46
+ end
47
+
48
+ # Publishes a directory by tarballing it on the fly.
49
+ #
50
+ # @param [String] Directory path
51
+ # @return [Boolean] Upload was successful
52
+ def publish(path)
53
+ raise ArgumentError, "#{path} is not a directory" unless File.directory? path
54
+
55
+ filename = File.basename path
56
+
57
+ Open3.popen2('tar', '--to-stdout', '--create', '--gzip', '--directory', path, '.') do |stdin, stdout, thread|
58
+ stream, body = IO.pipe
59
+
60
+ # Generate a multipart body and copy contents to it.
61
+ Thread.new do
62
+ write_multipart_header body, filename
63
+ IO.copy_stream stdout, body
64
+ write_multipart_footer body
65
+
66
+ body.close
67
+ end
68
+
69
+ result = upload_io '/v0/publication/publish', stream
70
+
71
+ # wait
72
+ thread.value
73
+ result['errorCode'].zero?
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ # Write the multipart header
80
+ def write_multipart_header(io, filename)
81
+ io.write BOUNDARY
82
+ io.write boundary
83
+ io.write NEWLINE
84
+ io.write "Content-Disposition: form-data; name=\"file\"; filename=\"#{filename}.tar.gz\""
85
+ io.write NEWLINE
86
+ io.write 'Content-Type: application/octet-stream'
87
+ io.write NEWLINE
88
+ io.write NEWLINE
89
+
90
+ nil
91
+ end
92
+
93
+ # Write the multipart footer
94
+ def write_multipart_footer(io)
95
+ io.write NEWLINE
96
+ io.write BOUNDARY
97
+ io.write boundary
98
+ io.write BOUNDARY
99
+ io.write NEWLINE
100
+
101
+ nil
102
+ end
103
+
104
+ # Upload an IO object
105
+ #
106
+ # @param [String]
107
+ # @param [IO]
108
+ def upload_io(endpoint, io)
109
+ self.class.post(endpoint, body_stream: io, headers: headers(
110
+ 'Accept' => 'application/json',
111
+ 'Content-Type' => "multipart/form-data; boundary=#{boundary}",
112
+ 'Transfer-Encoding' => 'chunked'
113
+ ))
114
+ end
115
+
116
+ # Generate a MultiPart boundary and reuse it
117
+ #
118
+ # @return [String]
119
+ def boundary
120
+ @boundary ||= HTTParty::Request::MultipartBoundary.generate
121
+ end
122
+
123
+ # Default request headers
124
+ #
125
+ # @param [Hash] Extra headers
126
+ # @return [Hash]
127
+ def headers(extra = {})
128
+ extra.merge('Accept' => 'application/json', 'Authorization' => 'Bearer ' + api_key)
129
+ end
130
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: distributed-press-api-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - f
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-01-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httparty
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.18'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.18'
27
+ description: An API client for Distributed Press (https://distributed.press/)
28
+ email:
29
+ - f@sutty.nl
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files:
33
+ - README.md
34
+ files:
35
+ - README.md
36
+ - lib/distributed_press.rb
37
+ homepage: https://0xacab.org/sutty/distributed-press-api-client
38
+ licenses:
39
+ - AGPL-3.0
40
+ metadata:
41
+ bug_tracker_uri: https://0xacab.org/sutty/distributed-press-api-client/issues
42
+ homepage_uri: https://0xacab.org/sutty/distributed-press-api-client
43
+ source_code_uri: https://0xacab.org/sutty/distributed-press-api-client
44
+ changelog_uri: https://0xacab.org/sutty/distributed-press-api-client/-/blob/master/CHANGELOG.md
45
+ documentation_uri: https://rubydoc.info/gems/distributed-press-api-client
46
+ post_install_message:
47
+ rdoc_options:
48
+ - "--title"
49
+ - distributed-press-api-client - Distributed Press API Client
50
+ - "--main"
51
+ - README.md
52
+ - "--line-numbers"
53
+ - "--inline-source"
54
+ - "--quiet"
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 2.6.0
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubygems_version: 3.1.2
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: Distributed Press API Client
72
+ test_files: []