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.
- checksums.yaml +7 -0
- data/README.md +68 -0
- data/lib/distributed_press.rb +130 -0
- metadata +72 -0
checksums.yaml
ADDED
@@ -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
|
data/README.md
ADDED
@@ -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: []
|