distributed-press-api-client 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []