distributed-press-api-client 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|