terminalwire-core 0.3.0.alpha1
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/lib/terminalwire/adapter.rb +53 -0
- data/lib/terminalwire/cache.rb +116 -0
- data/lib/terminalwire/logging.rb +8 -0
- data/lib/terminalwire/transport.rb +58 -0
- data/lib/terminalwire/version.rb +5 -0
- data/lib/terminalwire-core.rb +3 -0
- data/lib/terminalwire.rb +55 -0
- metadata +153 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c16ed0f8c654d33471f56add7eb3637b8439b2283c41a764b852999a3cb0eb2a
|
4
|
+
data.tar.gz: 5bfe86bc41fe0e368739a7997348612fc14ef63c9289a8c7520957a64983e6de
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8ce7a3ca741099a128f01cc3470b99fa16f8b446d60218be22136a4bfa8d03453273e82e72c2765ebf9150728a30c9e3b243fb46e668099ef3425ada7f85680e
|
7
|
+
data.tar.gz: 1f25dda033f5402f7ebb0f26384441a0604645868d06006d779d7e9100556023d0c209d257dbdf5372b9ab0ccea1ad4e0dc161e8d119ff28729f33be0ed96298
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'msgpack'
|
2
|
+
|
3
|
+
module Terminalwire::Adapter
|
4
|
+
# Works with Test, TCP, Unix, WebSocket, and other socket-like abstractions.
|
5
|
+
class Socket
|
6
|
+
include Terminalwire::Logging
|
7
|
+
|
8
|
+
attr_reader :transport
|
9
|
+
|
10
|
+
def initialize(transport)
|
11
|
+
@transport = transport
|
12
|
+
end
|
13
|
+
|
14
|
+
def write(data)
|
15
|
+
logger.debug "Adapter: Sending #{data.inspect}"
|
16
|
+
packed_data = MessagePack.pack(data, symbolize_keys: true)
|
17
|
+
@transport.write(packed_data)
|
18
|
+
end
|
19
|
+
|
20
|
+
def read
|
21
|
+
logger.debug "Adapter: Reading"
|
22
|
+
packed_data = @transport.read
|
23
|
+
return nil if packed_data.nil?
|
24
|
+
data = MessagePack.unpack(packed_data, symbolize_keys: true)
|
25
|
+
logger.debug "Adapter: Received #{data.inspect}"
|
26
|
+
data
|
27
|
+
end
|
28
|
+
|
29
|
+
def close
|
30
|
+
@transport.close
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# This is a test adapter that can be used for testing purposes.
|
35
|
+
class Test
|
36
|
+
attr_reader :responses
|
37
|
+
|
38
|
+
def initialize(responses = [])
|
39
|
+
@responses = responses
|
40
|
+
end
|
41
|
+
|
42
|
+
def write(**data)
|
43
|
+
@responses << data
|
44
|
+
end
|
45
|
+
|
46
|
+
def response
|
47
|
+
@responses.pop
|
48
|
+
end
|
49
|
+
|
50
|
+
def close
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "msgpack"
|
3
|
+
require "base64"
|
4
|
+
require "time"
|
5
|
+
require "fileutils"
|
6
|
+
|
7
|
+
# Caches used on the client side for licesens, HTTP requests, etc.
|
8
|
+
module Terminalwire::Cache
|
9
|
+
module File
|
10
|
+
# Hoist the File class to avoid conflicts with the standard library.
|
11
|
+
File = ::File
|
12
|
+
|
13
|
+
class Store
|
14
|
+
include Enumerable
|
15
|
+
|
16
|
+
def initialize(path:)
|
17
|
+
@path = Pathname.new(path).expand_path
|
18
|
+
FileUtils.mkdir_p(@path) unless @path.directory?
|
19
|
+
end
|
20
|
+
|
21
|
+
def entry(key)
|
22
|
+
Entry.new(path: @path.join(Entry.key_path(key)))
|
23
|
+
end
|
24
|
+
alias :[] :entry
|
25
|
+
|
26
|
+
def evict
|
27
|
+
each(&:evict)
|
28
|
+
end
|
29
|
+
|
30
|
+
def destroy
|
31
|
+
each(&:destroy)
|
32
|
+
end
|
33
|
+
|
34
|
+
def each
|
35
|
+
@path.each_child do |path|
|
36
|
+
yield Entry.new(path:)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Entry
|
42
|
+
VERSION = "1.0"
|
43
|
+
|
44
|
+
def self.key_path(value)
|
45
|
+
Base64.urlsafe_encode64(value)
|
46
|
+
end
|
47
|
+
|
48
|
+
attr_accessor :value, :expires
|
49
|
+
|
50
|
+
def initialize(path:)
|
51
|
+
@path = path
|
52
|
+
deserialize if persisted?
|
53
|
+
end
|
54
|
+
|
55
|
+
def nil?
|
56
|
+
@value.nil?
|
57
|
+
end
|
58
|
+
|
59
|
+
def present?
|
60
|
+
not nil?
|
61
|
+
end
|
62
|
+
|
63
|
+
def persisted?
|
64
|
+
File.exist? @path
|
65
|
+
end
|
66
|
+
|
67
|
+
def expired?(time: Time.now)
|
68
|
+
@expires && @expires < time.utc
|
69
|
+
end
|
70
|
+
|
71
|
+
def fresh?(...)
|
72
|
+
not expired?(...)
|
73
|
+
end
|
74
|
+
|
75
|
+
def hit?
|
76
|
+
persisted? and fresh?
|
77
|
+
end
|
78
|
+
|
79
|
+
def miss?
|
80
|
+
not hit?
|
81
|
+
end
|
82
|
+
|
83
|
+
def save
|
84
|
+
File.open(@path, "wb") do |file| # Write in binary mode
|
85
|
+
file.write(serialize)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def evict
|
90
|
+
destroy if expired?
|
91
|
+
end
|
92
|
+
|
93
|
+
def deserialize
|
94
|
+
case MessagePack.unpack(File.open(@path, "rb", &:read), symbolize_keys: true)
|
95
|
+
in { value:, expires:, version: VERSION }
|
96
|
+
@value = value
|
97
|
+
@expires = Time.parse(expires).utc if expires
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def destroy
|
102
|
+
File.delete(@path)
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def serialize
|
108
|
+
MessagePack.pack(
|
109
|
+
value: @value,
|
110
|
+
expires: @expires&.utc&.iso8601,
|
111
|
+
version: VERSION
|
112
|
+
)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'async/websocket/client'
|
3
|
+
|
4
|
+
module Terminalwire
|
5
|
+
module Transport
|
6
|
+
class Base
|
7
|
+
def self.connect(url)
|
8
|
+
raise NotImplementedError, "Subclass must implement .connect"
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.listen(url)
|
12
|
+
raise NotImplementedError, "Subclass must implement .listen"
|
13
|
+
end
|
14
|
+
|
15
|
+
def read
|
16
|
+
raise NotImplementedError, "Subclass must implement #read"
|
17
|
+
end
|
18
|
+
|
19
|
+
def write(data)
|
20
|
+
raise NotImplementedError, "Subclass must implement #write"
|
21
|
+
end
|
22
|
+
|
23
|
+
def close
|
24
|
+
raise NotImplementedError, "Subclass must implement #close"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class WebSocket < Base
|
29
|
+
def self.connect(url)
|
30
|
+
uri = URI(url)
|
31
|
+
endpoint = Async::HTTP::Endpoint.parse(uri)
|
32
|
+
adapter = Async::WebSocket::Client.connect(endpoint)
|
33
|
+
new(adapter)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.listen(url)
|
37
|
+
# This would need to be implemented with a WebSocket server library
|
38
|
+
raise NotImplementedError, "WebSocket server not implemented"
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize(websocket)
|
42
|
+
@websocket = websocket
|
43
|
+
end
|
44
|
+
|
45
|
+
def read
|
46
|
+
@websocket.read&.buffer
|
47
|
+
end
|
48
|
+
|
49
|
+
def write(data)
|
50
|
+
@websocket.write(data)
|
51
|
+
end
|
52
|
+
|
53
|
+
def close
|
54
|
+
@websocket.close
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/terminalwire.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "terminalwire/version"
|
4
|
+
|
5
|
+
require 'forwardable'
|
6
|
+
require 'uri'
|
7
|
+
|
8
|
+
require 'async'
|
9
|
+
require 'async/http/endpoint'
|
10
|
+
require 'async/websocket/client'
|
11
|
+
require 'async/websocket/adapters/rack'
|
12
|
+
require 'uri-builder'
|
13
|
+
|
14
|
+
require "zeitwerk"
|
15
|
+
Zeitwerk::Loader.for_gem.tap do |loader|
|
16
|
+
loader.ignore File.join(__dir__, "terminalwire-core.rb")
|
17
|
+
loader.setup
|
18
|
+
end
|
19
|
+
|
20
|
+
module Terminalwire
|
21
|
+
class Error < StandardError; end
|
22
|
+
|
23
|
+
# Used by Terminalwire client to connect to Terminalire.com for license
|
24
|
+
# validations, etc.
|
25
|
+
TERMINALWIRE_URL = "https://terminalwire.com".freeze
|
26
|
+
def self.url = URI.build(TERMINALWIRE_URL)
|
27
|
+
|
28
|
+
module Resource
|
29
|
+
class Base
|
30
|
+
attr_reader :name, :adapter
|
31
|
+
|
32
|
+
def initialize(name, adapter)
|
33
|
+
@name = name.to_s
|
34
|
+
@adapter = adapter
|
35
|
+
end
|
36
|
+
|
37
|
+
def connect; end
|
38
|
+
def disconnect; end
|
39
|
+
|
40
|
+
def fail(response, **data)
|
41
|
+
respond(status: "failure", response:, **data)
|
42
|
+
end
|
43
|
+
|
44
|
+
def succeed(response, **data)
|
45
|
+
respond(status: "success", response:, **data)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def respond(**response)
|
51
|
+
adapter.write(event: "resource", name: @name, **response)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
metadata
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: terminalwire-core
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0.alpha1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brad Gessler
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-12-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: async-websocket
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.30'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.30'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: zeitwerk
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: msgpack
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.7'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.7'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: uri-builder
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.1.9
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.1.9
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: base64
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.2.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.2.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '13.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '13.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.0'
|
111
|
+
description: Stream command-line apps from your server without a web API
|
112
|
+
email:
|
113
|
+
- brad@terminalwire.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- lib/terminalwire-core.rb
|
119
|
+
- lib/terminalwire.rb
|
120
|
+
- lib/terminalwire/adapter.rb
|
121
|
+
- lib/terminalwire/cache.rb
|
122
|
+
- lib/terminalwire/logging.rb
|
123
|
+
- lib/terminalwire/transport.rb
|
124
|
+
- lib/terminalwire/version.rb
|
125
|
+
homepage: https://terminalwire.com/ruby
|
126
|
+
licenses:
|
127
|
+
- Proprietary (https://terminalwire.com/license)
|
128
|
+
metadata:
|
129
|
+
allowed_push_host: https://rubygems.org/
|
130
|
+
homepage_uri: https://terminalwire.com/ruby
|
131
|
+
source_code_uri: https://github.com/terminalwire/ruby
|
132
|
+
changelog_uri: https://github.com/terminalwire/ruby/tags
|
133
|
+
funding_uri: https://terminalwire.com/funding
|
134
|
+
post_install_message:
|
135
|
+
rdoc_options: []
|
136
|
+
require_paths:
|
137
|
+
- lib
|
138
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: 3.0.0
|
143
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - ">="
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0'
|
148
|
+
requirements: []
|
149
|
+
rubygems_version: 3.5.9
|
150
|
+
signing_key:
|
151
|
+
specification_version: 4
|
152
|
+
summary: Ship a CLI for your web app. No API required.
|
153
|
+
test_files: []
|