diff --git a/README.md b/README.md index 18de22f..773494b 100644 --- a/README.md +++ b/README.md @@ -1,64 +1,64 @@ # How does Server Side Swift Workout in the Real World? -1. [Introduction](docs/01-introduction.md) - 1. Brief overview of Heartwitch: The inspiration behind gBeat - 2. Introduction to gBeat: A health and fitness live streaming app -2. [The Power of Full Stack Swift](docs/02-full-stack-swift.md) - 1. Unified Language Ecosystem - 2. Type Safety Across the Stack - 3. Performance Benefits - 4. Apple's Ecosystem Integration - 5. Growing Server-Side Swift Community - 6. Simplified Deployment and Scaling - 7. Developer Productivity - 8. Future-Proofing - 9. Case Study: gBeat's Experience with Full Stack Swift -3. [The gBeat Ecosystem](docs/03-gbeat.md) - 1. How the applications work - 2. Integration with Apple Watch - 3. User experience highlights -4. [Technical Deep Dive: Full Stack Swift Implementation](docs/04-technology) - 1. [Authentication system with Sign in with Apple](docs/04-technology/01-authentication.md) - 1. Implementation across iOS and watchOS - 2. Challenge: Sign in with Apple not available on Apple Watch simulator - 1. Impact on development and testing process - 2. Workarounds and solutions - 2. Development Server Auto-discovery (emphasize this as a key technical issue) - 3. Communication with Redis and WebSockets - 4. Implementing Apple Push Notification System (APNs) - 5. OpenAPI Integration - 1. Generating API documentation - 2. Ensuring consistency between API specification and implementation - 3. Benefits for frontend-backend communication and third-party integrations - 6. Web Development: Building the gBeat Website - 1. Choosing VueJS as the frontend framework - 1. Advantages for a fitness streaming application - 2. Integration with Swift backend - 2. Implementing TypeScript for improved type safety - 1. Benefits in a large-scale application - 2. Synergies with Swift's strong typing - 3. Utilizing Vite for build tooling - 1. Fast development experience - 2. Optimized production builds - 4. Webpack configuration for advanced scenarios - 5. Challenges and solutions in creating a responsive fitness streaming interface - 6. Performance optimizations for live video streaming -5. Challenges and Solutions - 1. Android integration - 1. Integrating Firebase Cloud Messaging (FCM) for cross-platform support - 2. Implementing Sign in with Google - 2. Creating a White Label app - 1. Issues with React Native and how Swift addressed them - 3. Developing a Chrome Extension for YouTube Workouts - 1. Bridging the gap between gBeat and popular YouTube fitness content - 2. Technical challenges in integrating with YouTube's player - 3. User experience considerations for seamless workout tracking - 4. How this extension complements the core gBeat application -6. Deployment and CI/CD + +## [Introduction](docs/01-introduction.md) + * Brief overview of Heartwitch: The inspiration behind gBeat + * Introduction to gBeat: A health and fitness live streaming app +## [The Power of Full Stack Swift](docs/02-full-stack-swift.md) + * Unified Language Ecosystem + * Type Safety Across the Stack + * Performance Benefits + * Apple's Ecosystem Integration + * Growing Server-Side Swift Community + * Simplified Deployment and Scaling + * Developer Productivity + * Future-Proofing + * Case Study: gBeat's Experience with Full Stack Swift +## [The gBeat Ecosystem](docs/03-gbeat.md) + * How the applications work + * Integration with Apple Watch + * User experience highlights +## [Technical Deep Dive: Full Stack Swift Implementation](docs/04-technology) +### [Authentication system with Sign in with Apple](docs/04-technology/01-authentication.md) + * Implementation across iOS and watchOS + * Challenge: Sign in with Apple not available on Apple Watch simulator +### [Development Server Auto-discovery](docs/04-technology/02-sublimation.md) + * The challenge of discovering local development servers in full stack development + * Specific issues with Apple Watch development + * Introduction to Sublimation: A Swift package solution + * Ngrok integration (initial approach) + * Bonjour implementation (ultimate solution) + * Impact on gBeat development +### [Communication with Redis and WebSockets](docs/04-technology/03-websockets-redis.md) +### [Implementing Apple Push Notification System](docs/04-technology/04-apns.md) +### [Complementary iPhone App and WatchConnectivity](docs/04-technology/05-iPhone.md) + * Developing a companion iPhone app for the AppStore + * Implementing WatchConnectivity + * Synchronizing workout data + * Challenges and solutions + * Impact on overall user experience +### [Web Development: Building the gBeat Website](docs/04-technology/05-web-development.md) + * Choosing VueJS as the frontend framework + * Implementing TypeScript for improved type safety + * Utilizing Vite for build tooling + * Webpack configuration for advanced scenarios + * Challenges and solutions in creating a responsive fitness streaming interface +### [Challenges and Solutions](docs/05-challenges.md) + * Android integration + * Creating a White Label app - Issues with React Native and how Swift addressed them + * Developing a Chrome Extension for YouTube Workouts +### [Deployment and CI/CD](docs/06-deployment.md) 1. Deploying to Heroku 2. Setting up Continuous Integration with GitLab and GitHub -7. Future Plans - 1. Upcoming features or improvements - 2. Potential expansions of the gBeat platform -8. Conclusion +### [Future Plans](docs/07-future.md) + * OpenAPI Integration + * React Native XCFramework/Node Module + * Protobuf + * Hack Watch Networking + * Hosting Options + * Other Apple Platforms + * Other Watch Platforms +### Conclusion TBD 1. Recap of key learnings - 2. Encouragement for attendees to explore Full Stack Swift for their projects \ No newline at end of file + 2. Encouragement for attendees to explore Full Stack Swift for their projects + + diff --git a/docs/01-introduction.md b/docs/01-introduction.md index a2a0fee..c13f3d1 100644 --- a/docs/01-introduction.md +++ b/docs/01-introduction.md @@ -1,7 +1,8 @@ # Why -It's one thing to create a server-side app which works for your iPhone and runs a simple service but I wanted to create an app which was dynamic and used Apple's tiniest device - the Apple Watch. +# Introduction to Server-Side Swift +It's one thing to create a server-side app which works for your iPhone and runs a simple service but I wanted to create an app which was dynamic and used Apple's tiniest device - the Apple Watch. ## Brief overview of Heartwitch: The inspiration behind gBeat diff --git a/docs/02-full-stack-swift.md b/docs/02-full-stack-swift.md index 71addf3..6cec1bf 100644 --- a/docs/02-full-stack-swift.md +++ b/docs/02-full-stack-swift.md @@ -38,4 +38,6 @@ Being able to easily debug and analyze server-side and device side code via Xcod ## Case Study: gBeat's Experience with Full Stack Swift -Let's now talk about how gBeat took advatage of this. +Let's now talk about how gBeat took advantage of this. + +380 users \ No newline at end of file diff --git a/docs/04-technology/01-authentication.md b/docs/04-technology/01-authentication.md index 3f32157..8629423 100644 --- a/docs/04-technology/01-authentication.md +++ b/docs/04-technology/01-authentication.md @@ -16,7 +16,9 @@ - Simulator can fake HealthKit stats be not Sign In With Apple `what happens` - How can we fake **sign in with apple** -### Impact on development and testing process +### Impact on development and testing process + +`link to simulator services and code snippet` - On development server save the token as a file on the Mac and copy it to the simulator directly - Login via web site diff --git a/docs/04-technology/02-sublimation.md b/docs/04-technology/02-sublimation.md new file mode 100644 index 0000000..2e7b90e --- /dev/null +++ b/docs/04-technology/02-sublimation.md @@ -0,0 +1,253 @@ +# Development Server Auto-discovery + +Besides dealing with challenges of Apple Watch development, we needed a solution for reaching the development server we are working on. + +## The challenge of discovering local development servers in full stack development + +When you are developing a full stack Swift application, you want to easily test and debug your application on both the device (iPhone, Apple Watch, iPad, etc...) as well as your development server. If you are using simulator then setting your host server to `localhost` will work but often we need to test on an actual device. + +## Specific issues with Apple Watch development + +This is especially true when it comes to developing on for the Apple Watch. There's no easy input control for the developer change the server address. + +## Introduction to Sublimation: A Swift package solution + +So I ended up creating a Swift Package to enable automatic discovery of your local development server on the fly called Sublimation. It turns your Vapor server from a mysterious gas to a tangible solid server to connect to. + +### Overview of Sublimation's purpose and functionality + +The purpose is to optimize developer experience and remove as much need to be an IT expert or tinking with the development environment. + +### Server and Client components + +For the server and client we need a way to communicate that information without the client knowing where the server is initially. + +```mermaid +flowchart TD +%% Nodes for devices with Font Awesome icons + subgraph Devices + iPhone("fa:fa-mobile-alt iPhone") + Watch("fa:fa-square Apple Watch") + iPad("fa:fa-tablet-alt iPad") + VisionPro("fa:fa-vr-cardboard Vision Pro") + end + +%% Node for Sublimation service with Font Awesome package icon + Sublimation("fa:fa-box Sublimation") + +%% Node for API server with Font Awesome icon + Server("fa:fa-server API Server") + +%% Edge connections + Devices <--> Sublimation + Sublimation <--> Server +``` + +![Diagram on Sublimation Communication](media/Sublimation-2024-08-22-160443.svg) + +There's two ways to do this - have a consistent location for fetching the address or a way to discover the service on the network. + +## Ngrok integration (initial approach) + +The initial approach was using `ngrok` to create an a public host name and entering that info in the app's environment variables `insert picture`. This worked but required the developer to update the environment each time _ngrok_ was restarted. If there was a way to save and fetch the new host name consistently for the developer that would reduce one more step. + +### Using Ngrok for public exposure of development servers + +The missing piece was get the ngrok url created and storing in the cloud somehow via a fairly simple method. + +### How Sublimation automates the Ngrok process + + +```mermaid +sequenceDiagram + participant DevServer as Development Server + participant Sub as Sublimation (Server) + participant Ngrok as Ngrok (https://ngrok.com) + participant KVdb as KVdb (https://kvdb.io) + participant SubClient as Sublimation (Client) + participant App as iOS/watchOS App + + DevServer->>Sub: Start development server + Sub->>Ngrok: Request public URL + Ngrok-->>Sub: Provide public URL
(https://abc123.ngrok.io) + Sub->>KVdb: Store URL with bucket and key
(bucket: "fdjf9012k20cv", key: "dev-server",
url: https://abc123.ngrok.io) + App->>SubClient: Request server URL
(bucket: "fdjf9012k20cv", key: "dev-server") + SubClient->>KVdb: Request URL
(bucket: "fdjf9012k20cv", key: "dev-server") + KVdb-->>SubClient: Provide stored URL
(https://abc123.ngrok.io) + SubClient-->>App: Return server URL
(https://abc123.ngrok.io) + App->>Ngrok: Connect to development server
(https://abc123.ngrok.io) + Ngrok->>DevServer: Forward request to local server +``` + +![SublimationNgrok Diagram](media/SublimationNgrok-2024-08-22-175342.svg) + + +What I found was that we can run `ngrok` on startup and access the newly created url via the local API. To store it in the cloud I found a service called kvdb.io which only required a bucket name and key for storing the public url. + +#### Cloud setup for meta-server access (using kvdb.io) + +If you haven't already setup an account with ngrok and install the command-line tool via homebrew. Next let's setup a key-value storage with kvdb.io which is currently supported. _If you have another service, please create an issue in the repo. Your feedback is helpful._ + +Sign up at kvdb.io and get a bucket name you'll use. You'll be using that for your setup. Essentially there are three components you'll need: + +* **ngrok executable path** + - if you installed via homebrew it's `/opt/homebrew/bin/ngrok` but you can find out using: `which ngrok` after installation +* **bucket name** from your kvdb.io +* **key** from your kvdb.io + - you just need to pick something unique for your server and client to use + +Save these somewhere in your shared configuration for both your server and client to access, such as an `enum`: + +```swift +public enum SublimationConfiguration { + public static let bucketName = "fdjf9012k20cv" + public static let key = "my-" +} +``` + + +#### Server Setup + +When creating your `Sublimation` object you'll want to use the provided convience initializers ``SublimationTunnel/TunnelSublimatory/init(ngrokPath:bucketName:key:application:isConnectionRefused:ngrokClient:)`` to make it easier for **ngrok** integration with the ``SublimationTunnel/TunnelSublimatory``: + +```swift +let tunnelSublimatory = TunnelSublimatory( + ngrokPath: "/opt/homebrew/bin/ngrok", // + bucketName: SublimationConfiguration.bucketName, // "fdjf9012k20cv" + key: SublimationConfiguration.key, // "dev-server" + application: { myVaporApplication }, // pass your Vapor.Application here + isConnectionRefused: {$.isConnectionRefused}, // supplied by `SublimationVapor` + transport: AsyncHTTPClientTransport() // ClientTransport for Vapor +) + +let sublimation = Sublimation(sublimatory: tunnelSublimatory) +``` + +#### Client Setup + +For the client, you'll need to import the ``SublimationKVdb`` module and retrieve the url via: + +```swift +import SublimationKVdb + +let hostURL = try await KVdb.url(withKey: key, atBucket: bucketName) +``` + +### Limitations and challenges encountered + +- difficult setup with installing ngrok and setting up configuration for each developer +- ngrok maybe already running? + +## Bonjour Implementation + +The ultimate goal is something which requires no configuration almost 0 configuration. This is where Bonjour comes in. + +`what is Bonjour` + + + +### How Sublimation uses Bonjour for local network discovery + +```mermaid +sequenceDiagram + participant Server as Hummingbird/Vapor Server + participant BonjourSub as BonjourSublimatory + participant NWListener as NWListener + participant Network as Local Network + participant BonjourClient as BonjourClient + participant App as iOS/watchOS App + + Server->>BonjourSub: Start server, provide IP addresses,
hostnames, port, and protocol (http/https) + BonjourSub->>NWListener: Configure with server information + NWListener->>Network: Advertise service:
1. Send encoded server data
2. Use Text Record for additional info + App->>BonjourClient: Request server URL + BonjourClient->>Network: Search for advertised services + Network-->>BonjourClient: Return advertised service information + BonjourClient->>BonjourClient: 1. Receive and decode server data
2. Parse Text Record + BonjourClient-->>App: Return AsyncStream
or first available URL + App->>Server: Connect to server using discovered URL +``` + +When the Hummingbird or Vapor server begins it will tell Sublimation the ip addresses or host names which are available to access the server from (including the port number and whether to use https or http). This is called a `BonjourSublimatory`. The `BonjourSublimatory` then uses `NWListener` to advertise this information both by send the data encoded using Protocol Buffers as well as inside the Text Record advertised. + +The iPhone or Apple Watch then uses a `BonjourClient` to fetch either an `AsyncStream` of `URL` or simply get the `first` one available. + +#### Setting up your Server + +Create a `BindingConfiguration` with: + +* a list of host names and ip address +* port number of the server +* whether the server uses https or http + +``` +let bindingConfiguration = BindingConfiguration( + host: ["Leo's-Mac.local", "192.168.1.10"], + port: 8080 + isSecure: false +) +``` + +Create a `BonjourSublimatory` using that `BindingConfiguration` and include your server's logger. Then attach it to the `Sublimation` object: + +``` +let bonjour = BonjourSublimatory( + bindingConfiguration: bindingConfiguration, + logger: app.logger +) +let sublimation = Sublimation(sublimatory : bonjour) +``` + +#### Setting up your Client + +On the device, create a `BonjourClient` and either get an `AsyncStream` of `URL` objects or just ask for the first one: + +``` +let client = BonjourClient(logger: app.logger) +let hostURL = await client.first() +``` + + +### Benefits of the Bonjour approach over Ngrok + +- no external dependencies +- minimal configuration + +### Implementation details and code examples + +Lastly `Sublimation` can be used in Server Side Swift either via a Vapor `LifecycleHandler` or Lifecycle `Service`. + +If you are Hummingbird, you can just add it as a service: + +```swift +let sublimation = Sublimation( + bindingConfiguration: .init(hosts: hosts, configuration: configuration.hosting) +) + +var app = Application( + router: router, + server: .http1WebSocketUpgrade(webSocketRouter: wsRouter), + configuration: .init(address: .init(setup: configuration.hosting)) +) + +app.addServices(sublimation) +``` + +For `Vapor`, you'd add it to the lifecycle of the app: + + +```swift +let sublimation = Sublimation( + bindingConfiguration: .init(hosts: hosts, configuration: configuration.hosting) +) + +var app : Application + +app.lifecycle.use(sublimation) +``` + +## Impact on gBeat development + +### Performance and developer experience improvements + +### Seamless testing across iOS and watchOS devices \ No newline at end of file diff --git a/docs/04-technology/03-websockets-redis.md b/docs/04-technology/03-websockets-redis.md new file mode 100644 index 0000000..2136822 --- /dev/null +++ b/docs/04-technology/03-websockets-redis.md @@ -0,0 +1,12 @@ +# Communication with Redis and WebSockets + +At first we were focused on just serving the json by send the data from the push request to the web socket: + + +```How do we can track of web socket``` + +``` +chart or code here +``` + +However for both scaling purposes, we added Redis as an intermediary. We used specifically pub/sub channels to post a health stat to Redis while subscribing to any post and sending it to the websocket. \ No newline at end of file diff --git a/docs/04-technology/04-apns.md b/docs/04-technology/04-apns.md new file mode 100644 index 0000000..7278852 --- /dev/null +++ b/docs/04-technology/04-apns.md @@ -0,0 +1,30 @@ +# Implementing Apple Push Notification System (APNs) + +didRegisterForRemoteNotifications + +``` + mobileDevice = CreateMobileDeviceRequestContent( + model: AppInterfaceType.currentDevice.name, + operatingSystem: AppInterfaceType.currentDevice.systemVersion, + topic: topic, + deviceToken: deviceToken + ) +``` + +// primary id of MobileDeviceRegistration + @AppStorage("MobileDeviceRegistrationID") private var mobileDeviceRegistrationID: String? + +``` + +CREATE TABLE "MobileDevices" ( + id uuid PRIMARY KEY, + "userID" uuid NOT NULL REFERENCES "User"(id) ON DELETE CASCADE ON UPDATE CASCADE, + model text NOT NULL, + "operatingSystem" text NOT NULL, + topic text NOT NULL, + "deviceToken" bytea NOT NULL UNIQUE, + "createdAt" timestamp with time zone, + "updatedAt" timestamp with time zone +); + +``` \ No newline at end of file diff --git a/docs/04-technology/05-iPhone.md b/docs/04-technology/05-iPhone.md new file mode 100644 index 0000000..1a053af --- /dev/null +++ b/docs/04-technology/05-iPhone.md @@ -0,0 +1,65 @@ +# Complementary iPhone App and WatchConnectivity + +One of the issues we had with both apps being only on the Apple Watch was the lack of discoverability when it came to the app store. The Apple Watch app store especially in its early days was difficult to work with and communicate with users. + +## Developing a companion iPhone app for the AppStore + +Much of the code base is shared + +``` +diagram of code base sharing +``` + +However the SwiftUI is separated considerably considering how different the devices are. + +## Implementing WatchConnectivity + +### Overview of WatchConnectivity framework + +WatchConnectivity tries it's best attempt to communicate both messages and the connectivity of the watch and phone. + +``isReachable`` +``isWatchAppInstalled`` and ``isCompanionAppInstalled`` + +``updateApplicationContext`` +``sendMessage`` + +### Combining WatchConnectivity + +Combine is used throughout the application. I wanted to take advantage of Combine for dealing with connectivity and communication between the watch and the phone. + +https://github.com/brightdigit/SundialKit + +I created a library for using Combine with WatchConnectivity: + +``` +public protocol Messagable { + /// The unique key or type name to use for decoding. + static var key: String { get } + + /// Create the object based on the `Dictionary`. + /// - Parameter parameters: The parameters value. + init?(from parameters: [String: Any]?) + + /// The parameters of the `Messagable` object. + /// - Returns: The parameters of the `Messagable` object. + func parameters() -> [String: Any] +} + +public extension Messagable { + /// Converts the object into a usable `ConnectivityMessage` for + /// `WatchConnectivity` + /// - Returns: `ConnectivityMessage` i.e. `[String:Any]` for sending. + func message() -> ConnectivityMessage { + [ + MessagableKeys.typeKey: Self.key, + MessagableKeys.parametersKey: parameters() + ] + } +} +``` + +- startWorkout +- endWorkout +- workout status +- request workout status diff --git a/docs/04-technology/05-web-development.md b/docs/04-technology/05-web-development.md new file mode 100644 index 0000000..5119e9c --- /dev/null +++ b/docs/04-technology/05-web-development.md @@ -0,0 +1,12 @@ +5. Web Development: Building the gBeat Website + 1. Choosing VueJS as the frontend framework + 1. Advantages for a fitness streaming application + 2. Integration with Swift backend + 2. Implementing TypeScript for improved type safety + 1. Benefits in a large-scale application + 2. Synergies with Swift's strong typing + 3. Utilizing Vite for build tooling + 1. Fast development experience + 2. Optimized production builds + 4. Webpack configuration for advanced scenarios + 5. Challenges and solutions in creating a responsive fitness streaming interface \ No newline at end of file diff --git a/docs/05-challenges.md b/docs/05-challenges.md new file mode 100644 index 0000000..454b379 --- /dev/null +++ b/docs/05-challenges.md @@ -0,0 +1,15 @@ +# Challenges and Solutions + +## Android integration + +### Integrating Firebase Cloud Messaging (FCM) for cross-platform support + +### Implementing Sign in with Google + + 2. Creating a White Label app + 1. Issues with React Native and how Swift addressed them + 3. Developing a Chrome Extension for YouTube Workouts + 1. Bridging the gap between gBeat and popular YouTube fitness content + 2. Technical challenges in integrating with YouTube's player + 3. User experience considerations for seamless workout tracking + 4. How this extension complements the core gBeat application \ No newline at end of file diff --git a/docs/06-deployment.md b/docs/06-deployment.md new file mode 100644 index 0000000..6cdffa5 --- /dev/null +++ b/docs/06-deployment.md @@ -0,0 +1,108 @@ +# Deployment and CI/CD + +## Setting up Continuous Integration with GitLab + +AppCertificates +Heroku +Web +Swift Package +App + +App -> run fastlane + contains SPM + contains Web + +Heroku mirrors SPM with Web + + +Poly Repo +Submodules +Fastlane + +```mermaid +flowchart TD + A[("AppStoreCertificates")] == Contains ==> A1("Provisioning Profiles") & A2("Certificates") + F("Fastlane (Match)") -. Uses .-> J("Fastlane Configuration") & A + B[("Web")] -- Contains --> G1("TypeScript") & G2("Vite") & G3("TailwindCSS") & G4("VueJS") + C[("GBeatKit")] -- Contains --> H("Swift Package") + C -. Submodule of .-> B + D[("SwiftApp")] == Contains ==> I("Xcode Project Setup") & J + D -. Uses .-> F + D -. Submodule of .-> C + E[("Heroku")] == Mirrors ==> C & B + F -- Deploys to --> N["App Store"] + E -- Deploys to --> O["Heroku Platform"] + A:::repository + B:::repository + C:::repository + D:::repository + E:::repository + N:::deployment + O:::deployment + classDef repository fill:#f9f,stroke:#333,stroke-width:2px + classDef deployment fill:#bfb,stroke:#333,stroke-width:2px +``` + +```mermaid +sequenceDiagram + participant Web + participant GBeatKit + participant SwiftApp + participant Heroku Repo + participant AppStore + participant Beta Heroku + participant Prod Heroku + + Web->>Web: Build website + GBeatKit->>GBeatKit: Build on macOS + GBeatKit->>GBeatKit: Build on Linux + alt Deployment triggered for Web + GBeatKit->>Web: Pull latest code + GBeatKit->>Heroku: Push Web code + Heroku->>BetaInstance: Deploy + alt Production deployment + Heroku->>ProdInstance: Deploy + end + end + SwiftApp->>SwiftApp: Archive iOS app + alt Deployment triggered for iOS + SwiftApp->>AppStore: Push archived app + end +``` + +## Setting up Continuous Integration with GitHub + + + +```mermaid +flowchart LR + subgraph Parallel["In Parallel"] + A["Build Web FrontEnd"] + C["Build on Ubuntu"] + end + Parallel --> B["Build on macOS"] + B --> D["Linting on macOS"] + D --> E["Archiving and/or Deliver"] + A -.- note1[/"builds the Front End Website
contains TypeScript, TailwindCSS,
VueJS, and Vite"/] + C -.- note2[/"builds the Swift Package on Ubuntu
to ensure it'll work on a server"/] + B -.- note3[/"ensures the build works for
the iPhone and Watch app"/] + D -.- note4[/"ensures the code is formatted properly
and follows consistent styling"/] + E -.- note5[/"ensures the app can be archived and
if necessary gets uploaded to the App Store"/] + E -.- note6[/"If everthing passes based on branch, Heroku auto-deploys to instance."/] + note1:::note + note2:::note + note3:::note + note4:::note + note5:::note + classDef note stroke-dasharray: 2 4,stroke-opacity: 0.6, fill-opacity: 0.75 + linkStyle 3,4,5,6,7 opacity: 0.60 +``` + +## Deploying to Heroku + +### Setting up Build Packs + +### + 1. Build Packs + 1. Vapor + 2. JS \ No newline at end of file diff --git a/docs/07-future.md b/docs/07-future.md new file mode 100644 index 0000000..e72be69 --- /dev/null +++ b/docs/07-future.md @@ -0,0 +1,12 @@ +7. Future Plans + 1. Upcoming features or improvements + 5. OpenAPI Integration + 1. Generating API documentation + 2. Ensuring consistency between API specification and implementation + 3. Benefits for frontend-backend communication and third-party integrations + 6. React Native XCFramework/Node Module + 7. Alternative Networking Connections + 7. Protobuf + 8. Hack Watch Networking + 9. Hosting Options + 2. Potential expansions of the gBeat platform \ No newline at end of file diff --git a/media/Sublimation-2024-08-22-160443.svg b/media/Sublimation-2024-08-22-160443.svg new file mode 100644 index 0000000..963a68e --- /dev/null +++ b/media/Sublimation-2024-08-22-160443.svg @@ -0,0 +1 @@ +

Devices

iPhone

Apple Watch

iPad

Vision Pro

Sublimation

API Server

\ No newline at end of file diff --git a/media/SublimationNgrok-2024-08-22-175342.svg b/media/SublimationNgrok-2024-08-22-175342.svg new file mode 100644 index 0000000..41b3449 --- /dev/null +++ b/media/SublimationNgrok-2024-08-22-175342.svg @@ -0,0 +1 @@ +iOS/watchOS AppSublimation (Client)KVdb (https://kvdb.io)Ngrok (https://ngrok.com)Sublimation (Server)Development ServeriOS/watchOS AppSublimation (Client)KVdb (https://kvdb.io)Ngrok (https://ngrok.com)Sublimation (Server)Development ServerStart development serverRequest public URLProvide public URL(https://abc123.ngrok.io)Store URL with bucket and key(bucket: "fdjf9012k20cv", key: "dev-server",url: https://abc123.ngrok.io)Request server URL(bucket: "fdjf9012k20cv", key: "dev-server")Request URL(bucket: "fdjf9012k20cv", key: "dev-server")Provide stored URL(https://abc123.ngrok.io)Return server URL(https://abc123.ngrok.io)Connect to development server(https://abc123.ngrok.io)Forward request to local server \ No newline at end of file diff --git a/media/mermaid-diagram-2024-08-23-182036.svg b/media/mermaid-diagram-2024-08-23-182036.svg new file mode 100644 index 0000000..eadf707 --- /dev/null +++ b/media/mermaid-diagram-2024-08-23-182036.svg @@ -0,0 +1 @@ +iOS/watchOS AppBonjourClientLocal NetworkNWListenerBonjourSublimatoryHummingbird/Vapor ServeriOS/watchOS AppBonjourClientLocal NetworkNWListenerBonjourSublimatoryHummingbird/Vapor ServerStart server, provide IP addresses,hostnames, port, and protocol (http/https)Configure with server informationAdvertise service:1. Send encoded server data2. Use Text Record for additional infoRequest server URLSearch for advertised servicesReturn advertised service information1. Receive and decode server data2. Parse Text RecordReturn AsyncStream<URL>or first available URLConnect to server using discovered URL \ No newline at end of file diff --git a/media/mermaid-diagram-2024-08-23-182043.svg b/media/mermaid-diagram-2024-08-23-182043.svg new file mode 100644 index 0000000..eb30cc1 --- /dev/null +++ b/media/mermaid-diagram-2024-08-23-182043.svg @@ -0,0 +1 @@ +iOS/watchOS AppBonjourClientLocal NetworkNWListenerBonjourSublimatoryHummingbird/Vapor ServeriOS/watchOS AppBonjourClientLocal NetworkNWListenerBonjourSublimatoryHummingbird/Vapor ServerStart server, provide IP addresses,hostnames, port, and protocol (http/https)Configure with server informationAdvertise service:1. Send encoded server data2. Use Text Record for additional infoRequest server URLSearch for advertised servicesReturn advertised service information1. Receive and decode server data2. Parse Text RecordReturn AsyncStream<URL>or first available URLConnect to server using discovered URL \ No newline at end of file