1679137330
ChatMe - Simply Encryption Messaging Flutter App. Link: https://bit.ly/chatme_env #flutter #flutterapp #chatme #chat #messaging #flutterdev #flutterdeveloper #privatechat
1676638210
iOS Chat SDK in Swift - Build your own app chat experience for iOS using the official Stream Chat API
This is the official iOS SDK for Stream Chat, a service for building chat and messaging applications. This library includes both a low-level SDK and a set of reusable UI components.
The StreamChat SDK is a low level client for Stream chat service that doesn't contain any UI components. It is meant to be used when you want to build a fully custom UI. For the majority of use cases though, we recommend using our highly customizable UI SDK's.
The StreamChatUI SDK is our UI SDK for UIKit components. If your application needs to support iOS 13 and below, this is the right UI SDK for you.
The StreamChatSwiftUI SDK is our UI SDK for SwiftUI components. If your application only needs to support iOS 14 and above, this is the right UI SDK for you. This SDK is available in another repository stream-chat-swiftui.
Since the 4.20.0 release, our SDKs can be built using Xcode 14. Currently, there are no known issues on iOS 16. If you spot one, please create a ticket.
tintColor
, layoutMargins
, light/dark mode, dynamic font sizes, etc.UIKit
patterns and paradigms: The API follows the design of native system SDKs. It makes integration with your existing code easy and familiar.SwiftUI
support: We have developed a brand new SDK to help you have smoother Stream Chat integration in your SwiftUI apps.Combine
: The StreamChat SDK (Low Level Client) has Combine wrappers to make it really easy use in an app that uses Combine
.Stream is free for most side and hobby projects. You can use Stream Chat for free if you have less than five team members and no more than $10,000 in monthly revenue.
Progressive disclosure: The SDK can be used easily with very minimal knowledge of it. As you become more familiar with it, you can dig deeper and start customizing it on all levels.
Highly customizable: Every element is designed to be easily customizable. You can modify the brand color by setting tintColor
, apply appearance changes using custom UI rules, or subclass existing elements and inject them everywhere in the system, no matter how deep is the logic hierarchy.
open
by default: Everything is open
unless there's a strong reason for it to not be. This means you can easily modify almost every behavior of the SDK such that it fits your needs.
Good platform citizen: The UI elements behave like good platform citizens. They use existing iOS patterns; their behavior is predictable and matches system UI components; they respect tintColor
, layourMargins
, dynamic font sizes, and other system-defined UI constants.
This SDK tries to keep the list of external dependencies to a minimum. Starting 4.6.0, and in order to improve the developer experience, dependencies are hidden inside our libraries. (Does not apply to StreamChatSwiftUI's dependencies yet).
Learn more about our dependencies here
You can still integrate our SDKs if your project is using Objective-C. In that case, any customizations would need to be done by subclassing our components in Swift, and then use those directly from the Objective-C code.
We've recently closed a $38 million Series B funding round and we keep actively growing. Our APIs are used by more than a billion end-users, and you'll have a chance to make a huge impact on the product within a team of the strongest engineers all over the world. Check out our current openings and apply via Stream's website.
Features | Preview |
---|---|
A list of channels matching provided query | ![]() |
Channel name and image based on the channel members or custom data | |
Unread messages indicator | |
Preview of the last message | |
Online indicator for avatars | |
Create new channel and start right away | |
Features | Preview |
---|---|
A list of message in a channel | ![]() |
Photo preview | |
Message reactions | |
Message grouping based on the send time | |
Link preview | |
Inline replies | |
Message threads | |
GIPHY support | |
Features | Preview |
---|---|
Support for multiline text, expands and shrinks as needed | ![]() |
Image and file attachments | |
Replies to messages | |
Tagging of users | |
Chat commands like mute, ban, giphy | |
Features | Preview |
---|---|
Easily search commands by writing / symbol or tap bolt icon | ![]() |
GIPHY support out of box | |
Supports mute, unmute, ban, unban commands | |
WIP support of custom commands | |
Features | Preview |
---|---|
User mentions preview | ![]() |
Easily search for concrete user | |
Mention as many users as you want | |
Author: GetStream
Source Code: https://github.com/GetStream/stream-chat-swift
License: View license
1676366220
Chat SDK is a fully featured open source instant messaging framework for iOS. Chat SDK is fully featured, scalable and flexible and follows the following key principles:
Full breakdown is available on the features page.
Learn about the history of Chat SDK and our future plans in this post.
People always ask about how much Chat SDK costs to run. And will it scale to millions of users? So I wrote an article talking about just that.
If you're a freelance developer looking for work, join our Discord server. We often have customers
You can also help us by:
Email us at: team@sdk.chat
We also offer development services we are a team of full stack developers who are Firebase experts. For more information check out our consulting site.
This repository contains a fully functional version of the Chat SDK which is configured using our Firebase account. This is great way to test the features of the Chat SDK before you start itegrating it with your app.
pod install
in the Xcode directoryChat SDK Firebase.xcworkspace
file in XcodeWe are currently updating the Chat SDK to use Swift, this will happen gradually. In the meantime, the Chat SDK API is fully compatible with Swift projects.
The Chat SDK is fully compatible with Swift projects and contains a Swift demo project.
pod install
in the XcodeSwift directoryChatSDKSwift.xcworkspace
file in XcodeQuick start guide - it takes about 10 minutes!
use_frameworks!
pod "ChatSDK"
pod "ChatSDKFirebase/Adapter"
pod "ChatSDKFirebase/Upload"
pod "ChatSDKFirebase/Push"
Optional
pod "ChatSDK/ModAddContactWithQRCode"
Run pod update
to get the latest version of the code.
Open the App Delegate add the following code to initialise the chat
Swift
AppDelegate.swift
import ChatSDK
Add the following code to the start of your didFinishLaunchingWithOptions function:
let config = BConfiguration.init();
config.rootPath = "test"
// Configure other options here...
config.allowUsersToCreatePublicChats = true
// Define the modules you want to use.
var modules = [
FirebaseNetworkAdapterModule.shared(),
FirebasePushModule.shared(),
FirebaseUploadModule.shared(),
// Optional...
AddContactWithQRCodeModule.init(),
]
BChatSDK.initialize(config, app: application, options: launchOptions, modules: modules)
self.window = UIWindow.init(frame: UIScreen.main.bounds)
self.window?.rootViewController = BChatSDK.ui().splashScreenNavigationController()
self.window?.makeKeyAndVisible();
Then add the following methods:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
BChatSDK.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
BChatSDK.application(application, didReceiveRemoteNotification: userInfo)
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
return BChatSDK.application(application, open: url, sourceApplication: sourceApplication, annotation: annotation)
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return BChatSDK.application(app, open: url, options: options)
}
Objective C
Check the demo project.
The Root Path
The root path variable allows you to run multiple Chat SDK instances on one Firebase account. Each different root path will represent a completely separate set of Firebase data. This can be useful for testing because you could have separate test and prod root paths.
Note:
It is worth opening your downloadedGoogleService-Info.plist
and checking there is anAPI_KEY
field included. Sometimes Firebase's automatic download doesn’t include this in the plist. To rectify, just re-download the plist from the project settings menu.
Copy the following rows from the demo ChatSDK Info.plist file to your project's Info.plist
App Transport Security Settings
URL types
Make sure that the URL types are all set correctly. The URL type for your app should be set to your bundle id
All the privacy rows. These will allow the app to access the camera, location and address book
In the Firebase dashboard click Authentication -> Sign-in method and enable all the appropriate methods
Add the security rules. The rules also enable optimized user search so this step is very important!
Enable file storage - Click Storage -> Get Started
Enable push notifications
Enable location messages. Get a Google Maps API key. Then add it during the Chat SDK configuration
Objective C
config.googleMapsApiKey = @"YOUR API KEY";
Swift
config.googleMapsApiKey = "YOUR API KEY"
The Push Notification module allows you to send free push notifications using Firebase Cloud Messaging.
Setup Firebase Cloud Functions
Follow the instructions on our Chat SDK Firebase repository
Firebase secures your data by allowing you to write rules to govern who can access the database and what can be written. The rules are also needed to enable user search. To enable the rules see the guide Enabling Security Rules.
Congratulations! 🎉🎉 You've just turned your app into a fully featured instant messenger! Keep reading below to learn how to further customize the Chat SDK.
To go deeper, checkout the API Guide for help with:
View the API documentation here.
Next Steps
There are a number of configuration options available. Check out the BConfiguration class. Using this class you can do things like:
To customize the UI, you can register subclasses for different views. You can do that using the UI service BChatSDK.ui
. For example, to register a new login view controller you would use:
BChatSDK.ui.loginViewController = [[YourViewController alloc] initWithNibName:Nil bundle: Nil];
To modify the chat view you would register a provider:
[BChatSDK.ui setChatViewController:^BChatViewController *(id<PThread> thread) {
return [[YourChatViewController alloc] initWithThread:thread];
}];
Every view controller in the app can be customized this way.
Any of the Chat SDK views can be added into your app. Checkout the PInterfaceFacade for options. You can add a any view using the following pattern. Here we are using the interface service to get the particular view.
Objective-C
UIViewController * privateThreadsViewController = [BChatSDK.ui privateThreadsViewController];
Swift
let privateThreadsViewController = BChatSDK.ui().a.privateThreadsViewController()
To do that, you can take advantage of the BIntegrationHelper
class. This makes provides some helper methods to make it easier to integrate the Chat SDK with your app.
At the most basic level, you need to do the following:
Objective-C
[BIntegrationHelper authenticateWithToken:@"your token"];
Swift
BIntegrationHelper.authenticate(withToken: "your token")
Objective-C
[BIntegrationHelper updateUserWithName:@"Name" image: image url: imageURL];
Swift
BIntegrationHelper.updateUser(withName: "Name", image: image, url: imageURL)
Objective-C
[BIntegrationHelper logout];
Swift
BIntegrationHelper.logout()
There are a number of free and premium extensions that can be added to the Chat SDK.
For the following modules:
The free modules are located in the chat-sdk-ios/ChatSDKFirebase folder. The premium modules can be purchased and downloaded from the links provided above.
To install a module you should use the following steps:
The File UI module allows you to use the native Firebase user interface for authentication.
After adding the files to your Xcode project, add the following to the App Delegate to enable the module.
Objective C
AppDelegate.m -> application: didFinishLaunchingWithOptions:
#import "BFirebaseUIModule.h"
[[[BFirebaseUIModule alloc] init] activateWithProviders: @[]];
Swift
[YourProject]-Bridging-Header.h
#import "BFirebaseUIModule.h"
AppDelegate.swift
BFirebaseUIModule.init().activate(withProviders: []);
You should pass in array of the FUIAuthProvider
objects you want to support.
Also add the following to your Podfile depending on which authentication methods you want to support:
pod 'FirebaseUI/Facebook', '~> 4.0'
pod 'FirebaseUI/Google', '~> 4.0'
pod 'FirebaseUI/Twitter', '~> 4.0'
pod 'FirebaseUI/Phone', '~> 4.0'
Then run pod install
.
Note If you want to Firebase Auth UI make sure you comment out the following line:
BNetworkManager.shared().a.auth().setChallenge(BLoginViewController.init(nibName: nil, bundle: nil));
For the following modules:
These modules are distributed as development pods. After you've downloaded the module, unzip it and add it to the ChatSDKModules folder. Then:
pod "ChatSDKModules/[ModuleName]", :path => "[Path to ChatSDKModules folder]"
pod install
The Chat SDK API is based around the network manager and a series of handlers. A good place to start is by looking at the handlers Pods/Development Pods/ChatSDK/Core/Core/Classes/Interfaces
. Here you can review the handler interfaces which are well documented. To use a handler you would use the following code:
Objective C
[[BChatSDK.handler_name function: to: call:]
Swift
BNetworkManager.shared().a.handler_name() function: to: call:]
Searching for a user
For example, to search for a user you could use the search handler:
-(RXPromise *) usersForIndexes: (NSArray *) indexes withValue: (NSString *) value limit: (int) limit userAdded: (void(^)(id<PUser> user)) userAdded;
Here you pass in a series of indexes to be used in the search i.e. name, email etc... and a value. It will then return a series of user objects.
You can also see example implementations of these handlers by looking at the BFirebaseSearchHandler
class. And also seeing how the method is used in the Chat SDK.
Starting a chat
To start a chat you can use the core handler.
-(RXPromise *) createThreadWithUsers: (NSArray *) users
threadCreated: (void(^)(NSError * error, id<PThread> thread)) thread;
When this method completes, the thread will have been created on Firebase and all the users will have been added. You could then open the thread using the interface adapter.
UIViewController * chatViewController = [BChatSDK.ui chatViewControllerWithThread:thread];
So a more complete example would look like this:
-(void) startChatWithUser {
MBProgressHUD * hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.label.text = [NSBundle t:bCreatingThread];
[[BChatSDK.core createThreadWithUsers:@[_user] threadCreated:^(NSError * error, id<PThread> thread) {
if (!error) {
[self pushChatViewControllerWithThread:thread];
}
else {
[UIView alertWithTitle:[NSBundle t:bErrorTitle] withMessage:[NSBundle t:bThreadCreationError]];
}
[MBProgressHUD hideHUDForView:self.view animated:YES];
}];
}
-(void) pushChatViewControllerWithThread: (id<PThread>) thread {
if (thread) {
UIViewController * chatViewController = [BChatSDK.ui chatViewControllerWithThread:thread];
[self.navigationController pushViewController:chatViewController animated:YES];
}
}
We offer a choice of two license for this app. You can either use the Chat SDK license or the GPLv3 license.
Most Chat SDK users either want to add the Chat SDK to an app that will be released to the App Store or they want to use the Chat SDK in a project for their client. The Chat SDK license gives you complete flexibility to do this for free.
Chat SDK License Summary
If a user wants to distribute the Chat SDK source code, we feel that any additions or modifications they make to the code should be contributed back to the project. The GPLv3 license ensures that if source code is distributed, it must remain open source and available to the community.
GPLv3 License Summary
What does this mean?
Please check out the Licensing FAQ for more information.
Author: Chat-sdk
Source Code: https://github.com/chat-sdk/chat-sdk-ios
License: View license
1676007960
Chat SDK is a fully featured open source instant messaging framework for Android. Chat SDK is fully featured, scalable and flexible and follows the following key principles:
Please bear in mind that this version is a major update. As a result we are making new releases every few days to fix bugs and crashes. If you see an issue, please report it on the Github bug tracker and we will fix it.
Sponsor us on either Github sponsors or Paetron and get these features. For full details visit our Modules page.
When you support us on Patreon, you get: extra modules, code updates, support as well as special access to the Discord Server.
Visit our Animated GIF Gallery to see all the features.
Learn about the history of Chat SDK and our future plans in this post.
People always ask about how much Chat SDK costs to run. And will it scale to millions of users? So I wrote an article talking about just that.
The Chat SDK library with ALL modules is around 20mb
You can also help us by:
Email us at: team@sdk.chat
We also offer development services we are a team of full stack developers who are Firebase experts. For more information check out our consulting site.
If you are looking for something that is more-light weight than Chat SDK, we also have a library which only provides instant messaging functionality.
You can check out the project: Firestream on Github.
Bear in mind that the video is not updated frequently. Please cross reference with with the text based instructions for the latest gradle dependencies.
We provide extensive documentation on Github but if you’re a non-technical user or want to save yourself some work you can take advantage of our setup and integration service.
Author: Chat-sdk
Source Code: https://github.com/chat-sdk/chat-sdk-android
License: Apache-2.0 license
1675995720
Unofficial Firebase Admin SDK for PHP. Firebase Admin PHP SDK
Firebase provides the tools and infrastructure you need to develop your app, grow your user base, and earn money. The Firebase Admin PHP SDK enables access to Firebase services from privileged environments (such as servers or cloud) in PHP.
The Firebase Admin PHP SDK is available on Packagist as kreait/firebase-php
:
composer require kreait/firebase-php
Integrations for Laravel, Lumen and Symfony are available:
If you or your team rely on this project and me maintaining it, please consider becoming a Sponsor 🙏. Higher tiers enable access to extended support.
For more information, visit the Firebase Admin PHP SDK documentation.
Author: Kreait
Source Code: https://github.com/kreait/firebase-php
License: MIT license
1675359960
QKSMS is an open source replacement to the stock messaging app on Android. It is currently available on the Google Play Store and on F-Droid
A great bug report contains a description of the problem and steps to reproduce the problem. We need to know what we're looking for and where to look for it.
When reporting a bug, please make sure to provide the following information:
If you'd like to add translations to QKSMS, please join the project on Crowdin. Translations that are committed directly to source files will not be accepted.
A special thank you to Jake (@klinker41) and Luke Klinker (@klinker24) for their work on android-smsmms, which has been an unspeakably large help in implementing MMS into QKSMS.
QKSMS is developed and maintained by Moez Bhatti. Feel free to reach out to moez@qklabs.com
Author: Moezbhatti
Source Code: https://github.com/moezbhatti/qksms
License: GPL-3.0 license
1673341440
iOS 8.0 or above
GrowingTextView is available through CocoaPods. To install it, simply add the following line to your Podfile:
Swift 5.0
pod 'GrowingTextView', '0.7.2'
Swift 4.2
pod 'GrowingTextView', '0.6.1'
Swift 4.1
pod 'GrowingTextView', '~> 0.5'
Swift 3
pod 'GrowingTextView', '~> 0.4'
Swift 2.3 (Stopped update since Sep 2016)
pod 'GrowingTextView', :git => 'https://github.com/KennethTsang/GrowingTextView.git', :branch => 'swift2'
GrowingTextView is also available through Carthage. To install it, add the following line to your Cartfile:
Swift 5.0
github "KennethTsang/GrowingTextView" ~> 0.7
Swift 4.2
github "KennethTsang/GrowingTextView" ~> 0.6
Swift 4.1
github "KennethTsang/GrowingTextView" ~> 0.5
Swift 3
github "KennethTsang/GrowingTextView" ~> 0.4
Swift 2.3 (Stopped update since Sep 2016)
github "KennethTsang/GrowingTextView" "swift2"
Copy GrowingTextView.swift
into your project.
Example
GrowingTextview is just a textview, download the example to see how to use it as a input toolbar like other instant messaging apps.
Using GrowingTextview programmatically
let textView = GrowingTextView()
textView.delegate = self
addSubview(textView)
Using GrowingTextview in Storyboard
automaticallyAdjustsScrollViewInsets
Sometime the view controller may incorrectly adjust the inset of textview automatically. To avoid this, set automaticallyAdjustsScrollViewInsets
to false
override func viewDidLoad() {
super.viewDidLoad()
automaticallyAdjustsScrollViewInsets = false
}
Parameter | Type | Description | Default |
---|---|---|---|
maxLength | Int | Maximum text length. Exceeded text will be trimmed. 0 means no limit. | 0 |
trimWhiteSpaceWhenEndEditing | Bool | Trim white space and new line characters when textview did end editing. | true |
placeholder | String? | Placeholder text. | nil |
placeholderColor | UIColor | Placeholder text color. | UIColor(white: 0.8, alpha: 1.0) |
attributedPlaceholder | NSAttributedString? | Attributed Placeholder text. | nil |
minHeight | CGFloat | Minimum height of textview. | 0.0 |
maxHeight | CGFloat | Maximum height of textview. | 0.0 |
textView.maxLength = 140
textView.trimWhiteSpaceWhenEndEditing = false
textView.placeholder = "Say something..."
textView.placeholderColor = UIColor(white: 0.8, alpha: 1.0)
textView.minHeight = 25.0
textView.maxHeight = 70.0
textView.backgroundColor = UIColor.whiteColor()
textView.layer.cornerRadius = 4.0
GrowingTextViewDelegate
instead of UITextViewDelegate.class ViewController: UIViewController, GrowingTextViewDelegate {
func textViewDidChangeHeight(_ textView: GrowingTextView, height: CGFloat) {
UIView.animate(withDuration: 0.2) {
self.view.layoutIfNeeded()
}
}
}
GrowingTextViewDelegate
is inherited from UITextViewDelegate. You may use it's delegate function as a normal UITextView.
class ViewController: UIViewController, GrowingTextViewDelegate {
func textViewDidChange(_ textView: UITextView) {
...
}
func textViewDidEndEditing(_ textView: UITextView) {
...
}
}
Check out UITextViewDelegate here: https://developer.apple.com/reference/uikit/uitextviewdelegate
Author: KennethTsang
Source Code: https://github.com/KennethTsang/GrowingTextView
License: MIT license
1672303224
A concurrency (based on Amp) framework, that lets you implement an asynchronous messaging, a transparent workflow and control of long-lived business transactions by means of the Saga pattern. It implements the message based architecture and it includes the following patterns: Saga, Publish\Subscribe, Message Bus.
Jump into our Quick Start and build your first distributed solution in just 15 minutes.
Documentation can be found in the .documentation
directory
Contributions are welcome! Please read CONTRIBUTING for details.
You can find help and discussion in the following places:
Contributions are welcome! Please read CONTRIBUTING for details.
Author: php-service-bus
Source Code: https://github.com/php-service-bus/service-bus
License: MIT license
1666101060
A community-driven replacement for JSQMessagesViewController
Swift 5.3 in Xcode 12 added support for assets in Swift Packages. You can just add MessageKit package to your project by entering it's repository URL
https://github.com/MessageKit/MessageKit
Older versions of Swift and Xcode don't support MessageKit via SPM.
For iOS 12 or CocoaPods please use version 3.8.0
For iOS 11 please use version 3.3.0
For iOS 9 and iOS 10 please use version 3.1.1
Please have a look at the Quick Start guide and the FAQs.
We recommend you start by looking at the Example project or write a question with the "messagekit" tag on Stack Overflow. You can also look at previous issues here on GitHub with the "Question" tag.
For more on how to use the MessageInputBar, see the dependency it is based on InputBarAccessoryView. You can also see this short guide
Check out the full documentation here.
Each default cell is a subclass of MessageContentCell
which has 7 parts. From top down we have a: cellTopLabel
, messageTopLabel
, messageContainerView
, messageBottomLabel
, cellBottomLabel
with the avatarView
and accessoryView
on either side respectively. Above we see the basic TextMessageCell
which uses a MessageLabel
as its main content.
This structure will allow you to create a layout that suits your needs as you can customize the size, appearance and padding of each. If you need something more advanced you can implement a custom cell, which we show how to do in the Example project.
The InputBarAccessoryView
, 3rd party dependency from InputBarAccessoryView is a flexible and robust way of creating any kind of input layout you wish. Check the repo and examples there for more info.
The type of cell rendered for a given message is based on the MessageKind
public enum MessageKind {
case text(String) // TextMessageCell
case attributedText(NSAttributedString) // TextMessageCell
case photo(MediaItem) // MediaMessageCell
case video(MediaItem) // MediaMessageCell
case location(LocationItem) // LocationMessageCell
case emoji(String) // TextMessageCell
case audio(AudioItem) // AudioMessageCell
case contact(ContactItem) // ContactMessageCell
case linkPreview(LinkItem) // LinkPreviewMessageCell
/// A custom message.
/// - Note: Using this case requires that you implement the following methods and handle this case:
/// - MessagesDataSource: customCell(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UICollectionViewCell
/// - MessagesLayoutDelegate: customCellSizeCalculator(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CellSizeCalculator
case custom(Any?)
}
If you choose to use the .custom
kind you are responsible for all of the cells layout. Any UICollectionViewCell
can be returned for custom cells which means any of the styling you provide from the MessageDisplayDelegate
will not effect your custom cell. Even if you subclass your cell from MessageContentCell
. Read more about custom cells
Read more about the cases on the Quick Start guide.
Great! Look over these things first.
Check out the Releases to see what we are working on next.
Have a question or an issue about MessageKit? Create an issue!
Interested in contributing to MessageKit? Click here to join our Slack.
Add your app to the list of apps using this library and make a pull request.
Please provide attribution, it is greatly appreciated.
Many thanks to the contributors of this project.
Inspired by JSQMessagesViewController 👈 💯
Author: MessageKit
Source Code: https://github.com/MessageKit/MessageKit
License: MIT license
1663347900
In today's post we will learn about 10 Popular Golang Libraries that implement messaging Systems.
What is Messaging Systems?
A messaging system is responsible for transferring data from one application to another so the applications can focus on data without getting bogged down on data transmission and sharing. Distributed messaging is based on the concept of reliable message queuing. Messages are queued asynchronously between client applications and messaging system. There are two types of messaging patterns. The first one is a point-to-point and the other one is “publish–subscribe” (pub-sub) messaging system. Most of the messaging systems follow the pub-sub pattern.
Table of contents:
Go client to reliable queues based on Redis Cluster Streams.
Performance is dependent from:
As example, 10-nodes Redis Cluster with half of nodes in other datacenter (50 msec ping), 1 master/1 slave, with message "{}" got:
$ go run examples/performance/main.go
Produced 1000000 in 3.423883 sec, rps 292066.022156
Consumed 151000 in 1.049238 sec, rps 143913.931722
Acked 151000 in 0.973587 sec, rps 155096.612263
type errorLogger struct{}
func (l *errorLogger) AmiError(err error) {
println("Got error from Ami:", err.Error())
}
pr, err := ami.NewProducer(
ami.ProducerOptions{
ErrorNotifier: &errorLogger{},
Name: "ruthie",
PendingBufferSize: 10000000,
PipeBufferSize: 50000,
PipePeriod: time.Microsecond * 1000,
ShardsCount: 10,
},
&redis.ClusterOptions{
Addrs: []string{"172.17.0.1:7001", "172.17.0.1:7002"},
ReadTimeout: time.Second * 60,
WriteTimeout: time.Second * 60,
},
)
if err != nil {
panic(err)
}
for i := 0; i < 10000; i++ {
pr.Send("{}")
}
pr.Close()
Some things are different compared to the original client, others haven't changed.
This library uses a different package name. If moving from streadway/amqp
, using an alias may reduce the number of changes needed:
amqp "github.com/rabbitmq/amqp091-go"
Provide a functional interface that closely represents the AMQP 0.9.1 model targeted to RabbitMQ as a server. This includes the minimum necessary to interact the semantics of the protocol.
Things not intended to be supported.
basic.return
and basic.ack
frame ordering. This client uses Go channels for certain protocol events and ordering between events sent to two different channels generally cannot be guaranteed.See the _examples subdirectory for simple producers and consumers executables. If you have a use-case in mind which isn't well-represented by the examples, please file an issue.
APNS/2 is a go package designed for simple, flexible and fast Apple Push Notifications on iOS, OSX and Safari using the new HTTP/2 Push provider API.
go get -u github.com/sideshow/apns2
If you are running the test suite you will also need to install testify:
go get -u github.com/stretchr/testify
package main
import (
"log"
"fmt"
"github.com/sideshow/apns2"
"github.com/sideshow/apns2/certificate"
)
func main() {
cert, err := certificate.FromP12File("../cert.p12", "")
if err != nil {
log.Fatal("Cert Error:", err)
}
notification := &apns2.Notification{}
notification.DeviceToken = "11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"
notification.Topic = "com.sideshow.Apns2"
notification.Payload = []byte(`{"aps":{"alert":"Hello!"}}`) // See Payload section below
// If you want to test push notifications for builds running directly from XCode (Development), use
// client := apns2.NewClient(cert).Development()
// For apps published to the app store or installed as an ad-hoc distribution use Production()
client := apns2.NewClient(cert).Production()
res, err := client.Push(notification)
if err != nil {
log.Fatal("Error:", err)
}
fmt.Printf("%v %v %v\n", res.StatusCode, res.ApnsID, res.Reason)
}
Asynq is a Go library for queueing tasks and processing them asynchronously with workers. It's backed by Redis and is designed to be scalable yet easy to get started.
Highlevel overview of how Asynq works:
Task queues are used as a mechanism to distribute work across multiple machines. A system can consist of multiple worker servers and brokers, giving way to high availability and horizontal scaling.
Make sure you have Go installed (download). Version 1.14
or higher is required.
Initialize your project by creating a folder and then running go mod init github.com/your/repo
(learn more) inside the folder. Then install Asynq library with the go get
command:
go get -u github.com/hibiken/asynq
Make sure you're running a Redis server locally or from a Docker container. Version 4.0
or higher is required.
Next, write a package that encapsulates task creation and task handling.
package tasks
import (
"context"
"encoding/json"
"fmt"
"log"
"time"
"github.com/hibiken/asynq"
)
// A list of task types.
const (
TypeEmailDelivery = "email:deliver"
TypeImageResize = "image:resize"
)
type EmailDeliveryPayload struct {
UserID int
TemplateID string
}
type ImageResizePayload struct {
SourceURL string
}
//----------------------------------------------
// Write a function NewXXXTask to create a task.
// A task consists of a type and a payload.
//----------------------------------------------
func NewEmailDeliveryTask(userID int, tmplID string) (*asynq.Task, error) {
payload, err := json.Marshal(EmailDeliveryPayload{UserID: userID, TemplateID: tmplID})
if err != nil {
return nil, err
}
return asynq.NewTask(TypeEmailDelivery, payload), nil
}
func NewImageResizeTask(src string) (*asynq.Task, error) {
payload, err := json.Marshal(ImageResizePayload{SourceURL: src})
if err != nil {
return nil, err
}
// task options can be passed to NewTask, which can be overridden at enqueue time.
return asynq.NewTask(TypeImageResize, payload, asynq.MaxRetry(5), asynq.Timeout(20 * time.Minute)), nil
}
//---------------------------------------------------------------
// Write a function HandleXXXTask to handle the input task.
// Note that it satisfies the asynq.HandlerFunc interface.
//
// Handler doesn't need to be a function. You can define a type
// that satisfies asynq.Handler interface. See examples below.
//---------------------------------------------------------------
func HandleEmailDeliveryTask(ctx context.Context, t *asynq.Task) error {
var p EmailDeliveryPayload
if err := json.Unmarshal(t.Payload(), &p); err != nil {
return fmt.Errorf("json.Unmarshal failed: %v: %w", err, asynq.SkipRetry)
}
log.Printf("Sending Email to User: user_id=%d, template_id=%s", p.UserID, p.TemplateID)
// Email delivery code ...
return nil
}
// ImageProcessor implements asynq.Handler interface.
type ImageProcessor struct {
// ... fields for struct
}
func (processor *ImageProcessor) ProcessTask(ctx context.Context, t *asynq.Task) error {
var p ImageResizePayload
if err := json.Unmarshal(t.Payload(), &p); err != nil {
return fmt.Errorf("json.Unmarshal failed: %v: %w", err, asynq.SkipRetry)
}
log.Printf("Resizing image: src=%s", p.SourceURL)
// Image resizing code ...
return nil
}
func NewImageProcessor() *ImageProcessor {
return &ImageProcessor{}
}
Beaver is a real-time messaging server. With beaver you can easily build scalable in-app notifications, realtime graphs, multiplayer games, chat applications, geotracking and more in web applications and mobile apps.
Download the latest beaver binary. Make it executable from everywhere.
$ export BEAVER_LATEST_VERSION=$(curl --silent "https://api.github.com/repos/Clivern/Beaver/releases/latest" | jq '.tag_name' | sed -E 's/.*"([^"]+)".*/\1/' | tr -d v)
$ curl -sL https://github.com/Clivern/Beaver/releases/download/v{$BEAVER_LATEST_VERSION}/beaver_{$BEAVER_LATEST_VERSION}_Linux_x86_64.tar.gz | tar xz
Then install redis
cluster or a single node. Update the following config file with redis configs.
Create the configs file config.yml
from config.dist.yml
. Something like the following:
# App configs
app:
# Env mode (dev or prod)
mode: ${BEAVER_APP_MODE:-prod}
# HTTP port
port: ${BEAVER_API_PORT:-8080}
# Hostname
hostname: ${BEAVER_API_HOSTNAME:-127.0.0.1}
# TLS configs
tls:
status: ${BEAVER_API_TLS_STATUS:-off}
pemPath: ${BEAVER_API_TLS_PEMPATH:-cert/server.pem}
keyPath: ${BEAVER_API_TLS_KEYPATH:-cert/server.key}
# API Configs
api:
key: ${BEAVER_API_KEY:-6c68b836-6f8e-465e-b59f-89c1db53afca}
# Beaver Secret
secret: ${BEAVER_SECRET:-sWUhHRcs4Aqa0MEnYwbuQln3EW8CZ0oD}
# Runtime, Requests/Response and Beaver Metrics
metrics:
prometheus:
# Route for the metrics endpoint
endpoint: ${BEAVER_METRICS_PROM_ENDPOINT:-/metrics}
# Application Database
database:
# Database driver
driver: ${BEAVER_DB_DRIVER:-redis}
# Redis Configs
redis:
# Redis address
address: ${BEAVER_DB_REDIS_ADDR:-localhost:6379}
# Redis password
password: ${BEAVER_DB_REDIS_PASSWORD:- }
# Redis database
db: ${BEAVER_DB_REDIS_DB:-0}
# Log configs
log:
# Log level, it can be debug, info, warn, error, panic, fatal
level: ${BEAVER_LOG_LEVEL:-info}
# Output can be stdout or abs path to log file /var/logs/beaver.log
output: ${BEAVER_LOG_OUTPUT:-stdout}
# Format can be json
format: ${BEAVER_LOG_FORMAT:-json}
The run the beaver
with systemd
$ beaver api -c /path/to/config.yml
Benthos is a high performance and resilient stream processor, able to connect various sources and sinks in a range of brokering patterns and perform hydration, enrichments, transformations and filters on payloads.
It comes with a powerful mapping language, is easy to deploy and monitor, and ready to drop into your pipeline either as a static binary, docker image, or serverless function, making it cloud native as heck.
Benthos is declarative, with stream pipelines defined in as few as a single config file, allowing you to specify connectors and a list of processing stages:
input:
gcp_pubsub:
project: foo
subscription: bar
pipeline:
processors:
- bloblang: |
root.message = this
root.meta.link_count = this.links.length()
root.user.age = this.user.age.number()
output:
redis_streams:
url: tcp://TODO:6379
stream: baz
max_in_flight: 20
Delivery guarantees can be a dodgy subject. Benthos processes and acknowledges messages using an in-process transaction model with no need for any disk persisted state, so when connecting to at-least-once sources and sinks it's able to guarantee at-least-once delivery even in the event of crashes, disk corruption, or other unexpected server faults.
This behaviour is the default and free of caveats, which also makes deploying and scaling Benthos much simpler.
Grab a binary for your OS from here. Or use this script:
curl -Lsf https://sh.benthos.dev | bash
Or pull the docker image:
docker pull jeffail/benthos
Benthos can also be installed via Homebrew:
brew install benthos
For more information check out the getting started guide.
benthos -c ./config.yaml
Or, with docker:
# Using a config file
docker run --rm -v /path/to/your/config.yaml:/benthos.yaml jeffail/benthos
# Using a series of -s flags
docker run --rm -p 4195:4195 jeffail/benthos \
-s "input.type=http_server" \
-s "output.type=kafka" \
-s "output.kafka.addresses=kafka-server:9092" \
-s "output.kafka.topic=benthos_topic"
Bus is a minimalist event/message bus implementation for internal communication. It is heavily inspired from my event_bus package for Elixir language.
The method names and arities/args are stable now. No change should be expected on the package for the version 3.x.x
except any bug fixes.
Via go packages: go get github.com/mustafaturan/bus/v3
The package requires a unique id generator to assign ids to events. You can write your own function to generate unique ids or use a package that provides unique id generation functionality.
The bus
package respect to software design choice of the packages/projects. It supports both singleton and dependency injection to init a bus
instance.
Hint: Check the demo project for the singleton configuration.
Here is a sample initilization using monoton
id generator:
import (
"github.com/mustafaturan/bus/v3"
"github.com/mustafaturan/monoton/v2"
"github.com/mustafaturan/monoton/v2/sequencer"
)
func NewBus() *bus.Bus {
// configure id generator (it doesn't have to be monoton)
node := uint64(1)
initialTime := uint64(1577865600000) // set 2020-01-01 PST as initial time
m, err := monoton.New(sequencer.NewMillisecond(), node, initialTime)
if err != nil {
panic(err)
}
// init an id generator
var idGenerator bus.Next = m.Next
// create a new bus instance
b, err := bus.NewBus(idGenerator)
if err != nil {
panic(err)
}
// maybe register topics in here
b.RegisterTopics("order.received", "order.fulfilled")
return b
}
Centrifugo is an open-source scalable real-time messaging server. Centrifugo can instantly deliver messages to application online users connected over supported transports (WebSocket, HTTP-streaming, SSE/EventSource, GRPC, SockJS, WebTransport). Centrifugo has the concept of a channel – so it's a user-facing PUB/SUB server.
Centrifugo is language-agnostic and can be used to build chat apps, live comments, multiplayer games, real-time data visualizations, collaborative tools, etc. in combination with any backend. It is well suited for modern architectures and allows decoupling the business logic from the real-time transport layer.
Several official client SDKs for browser and mobile development wrap the bidirectional protocol. In addition, Centrifugo supports a unidirectional approach for simple use cases with no SDK dependency.
See installation instructions in Centrifugo documentation.
Chanify is a safe and simple notification tools. For developers, system administrators, and everyone can push notifications with API.
Chanify is include these features:
Download precompiled binary from here.
$ docker pull wizjin/chanify:latest
$ git clone https://github.com/chanify/chanify.git
$ cd chanify
$ make install
Use chanify to send message.
# Text message
$ chanify send --endpoint=http://<address>:<port> --token=<token> --text=<message>
# URL message
$ chanify send --endpoint=http://<address>:<port> --token=<token> --link=<web url>
# Image message
$ chanify send --endpoint=http://<address>:<port> --token=<token> --image=<image file path>
# Audio message
$ chanify send --endpoint=http://<address>:<port> --token=<token> --audio=<audio file path>
# File message
$ chanify send --endpoint=http://<address>:<port> --token=<token> --file=<file path> --text=<file description>
# Action message
$ chanify send --endpoint=http://<address>:<port> --token=<token> --text=<message> --title=<title> --action="<action name>|<action url>"
# Timeline message
$ chanify send --endpoint=http://<address>:<port> --token=<token> --timeline.code=<code> <item1>=<value1> <item2>=<value2> ...
endpoint
default value is https://api.chanify.net
, and notification will send by default server. If you have own node server, please set endpoint
to your node server url.
dbus is a simple library that implements native Go client bindings for the D-Bus message bus system.
This packages requires Go 1.12 or later. It can be installed by running the command below:
go get github.com/godbus/dbus/v5
The complete package documentation and some simple examples are available at godoc.org. Also, the _examples directory gives a short overview over the basic usage.
Please note that the API is considered unstable for now and may change without further notice.
Thank you for following this article.
Gopher in an Event-Driven playground
1659838500
Sandglass is a distributed, horizontally scalable, persistent, time ordered message queue. It was developed to support asynchronous tasks and message scheduling which makes it suitable for usage as a task queue.
EXPERIMENTAL: This is a prototype of a side project. This should not be used in production in its current form as things may change quickly without notice.
On MacOS using Homebrew:
brew install celrenheit/taps/sandglass
For other platforms, you can grab binaries here.
NOTE: All data will be stored in /tmp/node1. If you wish to change this, copy
demo/node1.yaml
and modify it accordingly.
First, let's launch sandglass server:
sandglass --config https://raw.githubusercontent.com/celrenheit/sandglass/master/demo/node1.yaml --offset_replication_factor 1
In a second terminal window, create a emails topic:
sandctl topics create emails --num_partitions 3 --replication_factor 1
...produce 10,000 messages:
sandctl produce emails '{"dest" : "hi@example.com"}' -n 10000
...and consume from the emails topic:
sandctl consume emails
(or if you wish to watch you can use sandctl consume -f emails
to see messages coming live)
We are using a single node cluster, this is not recommended for production.
Add a second node to the cluster:
sandglass --config https://raw.githubusercontent.com/celrenheit/sandglass/master/demo/node2.yaml
and repeat the same steps described above for another topic and increasing the replication factor to 2.
As previously asked (#4), the purpose of this project might not seem clear. In short, there is two goals.
The first is to be able to track each message individually (i.e. not using a single commit offset) to make suitable for asynchronous tasks.
The second is the ability to schedule messages to be consumed in the future. This make it suitable for retries.
Documentation is a work in progress and still lacking.
go get -u github.com/celrenheit/sandglass-client/go/sg
The documentation is available on godoc.
Producer
// Let's first create a client by providing adresses of nodes in the sandglass cluster
client, err := sg.NewClient(
sg.WithAddresses(":7170"),
)
if err != nil {
panic(err)
}
defer client.Close()
// Now we produce a new message
// Notice the empty string "" in the 3th argument, meaning let sandglass choose a random partition
err := client.Produce(context.Background(), "emails", "", &sgproto.Message{
Value: []byte("Hello, Sandglass!"),
})
if err != nil {
panic(err)
}
In order to produce message in the future, you need to specify a custom offset:
inOneHour := time.Now().Add(1 * time.Hour)
gen := sandflake.NewFixedTimeGenerator(inOneHour)
msg := &sgproto.Message{
Offset: gen.Next(),
Value: []byte("Hello"),
}
err := client.ProduceMessage(context.Background(), "emails", "", msg)
if err != nil {
return err
}
This will produce a message that will be available for consumption in 1h.
Consumer
// Let's first create a client by providing adresses of nodes in the sandglass cluster
client, err := sg.NewClient(
sg.WithAddresses(":7170"),
)
if err != nil {
panic(err)
}
defer client.Close()
mux := sg.NewMux()
mux.SubscribeFunc("emails", func(msg *sgproto.Message) error {
// handle message
log.Printf("received: %s\n", string(msg.Value))
return nil
})
m := &sg.MuxManager{
Client: c,
Mux: mux,
ReFetchSleepDuration: dur,
}
err = m.Start()
if err != nil {
log.Fatal(err)
}
// Let's first create a client by providing adresses of nodes in the sandglass cluster
client, err := sg.NewClient(
sg.WithAddresses(":7170"),
)
if err != nil {
panic(err)
}
defer client.Close()
// Listing partitions in order to choose one to consume from
partitions, err := client.ListPartitions(context.Background(), topic)
if err != nil {
panic(err)
}
// we are choosing only one partition for demo purposes
partition := partitions[0]
// Create a new consumer using consumer group emails-sender and consumer name consumer1
consumer := client.NewConsumer(topic, partition, "emails-sender", "consumer1")
// and consume messages
msgCh, err := consumer.Consume(context.Background())
if err != nil {
panic(err)
}
for msg := range msgCh {
// do an amazing amount of work
log.Printf("received: %s\n", string(msg.Value))
// when we are done, we Acknowledge the message
// but we can also NotAcknowledge to trigger a redelivery of the message
if err := consumer.Acknowledge(context.Background(), msg); err!=nil {
panic(err)
}
}
Interested in having client for one the following languages ?
Support is planned but there is no specific schedule. So, if you are interested to quickly have a client in your language, help is welcome!
Check the raw generated code available on https://github.com/celrenheit/sandglass-grpc and feel free to submit your through a pull request to https://github.com/celrenheit/sandglass-client.
+-----------------+
| |
+--------------------------+ +------> Consumer |
| | | | |
| Sandglass Cluster | | +-----------------+
| | |
| +-----+ Round robin consumption
+-----------------+ | +------------------+ | |
| | | | | | | +-----------------+
| Producer +-------> | | | | | |
| | | | Broker 1 | | +------> Consumer |
+-----------------+ | | | | | |
| | | | +-----------------+
| +------------------+ |
+-----------------+ | |
| | | +------------------+ |
| Producer +-------> | | | +-----------------+
| | | | | | | |
+-----------------+ | | Broker 2 | +-----+------> Consumer |
| | | | | | |
| | | | | +-----------------+
+-----------------+ | +------------------+ | |
| | | | | Failover consumption
| Producer +-------> +------------------+ | | (NOT DONE YET)
| | | | | | |
+-----------------+ | | | | | +-----------------+
| | Broker 3 | | | | |
| | | | +------+ Consumer |
| | | | | |
| +------------------+ | +-----------------+
| |
| |
+--------------------------+
There is two kinds of topics:
Timer:
KV:
A topic has a number of partitions. Data is written into a single partition. Either the destination partition is specified by the producer. Otherwise, we fallback to choosing the destination partition using a consistent hashing algorithm.
Each produced message to a partition writes a message to a Write Ahead Log (WAL) and to the View Log (VL). The WAL is used for the replication logic, it is sorted in the order each message was produced. The View Log is used for message consumption, it is mainly sorted by time (please refer to sandflake ids for the exact composition) for a Timer topics and by keys for KV topics.
A message is composed of the following fields:
index <- position in the WAL
offset <- position in the view log for timer topics
key and clusteringKey <- position in the view log for key for kv topics (key is used for partitioning)
value <- your payload
Sandglass is responsible for maintaining two offsets for each consumer group:
When consuming sandglass starts from the last commited until the last consumed message to check the redelivery of messages. And from the last consumed offset until the last produced message to deliver the new messages. These two actions are done in parallel.
Want to contribute to Sandglass ? Awesome! Feel free to submit an issue or a pull request.
Here are some ways you can help:
Author: Sandglass
Source Code: https://github.com/sandglass/sandglass
License: Apache-2.0 license
1658350680
Talk is a Laravel based user conversation (chatting) system with realtime messaging. You can easily integrate this package with any Laravel based project. It helps you to develop a messaging system in just few minutes. Here is a project screenshot that was developed by Talk.
Talk v2.1.0 supports realtime messaging. Learn more about Talk Live Messaging
If you already used Talk, please share your experience with us. It will make the project better.
If you are using Talk in your project please share your project URL or project name with us. It will inspire other people to use Talk.
See which project was Built with Talk.
Do not migrate 1.1.7 from its higher version directly. Please try our sample project first and then apply it on your project.
You may try Talk-Example project.
Or you can try live Demo by using this credentials:
username: admin
password: admin
So let's start your tour :)
Talk is a Laravel package so you can install it via Composer. Run this command in your terminal from your project directory:
composer require nahid/talk
Wait for a while, Composer will automatically install Talk in your project.
When the download is complete, you have to call this package service in config/app.php
config file. To do that, add this line in app.php
in providers
section:
Nahid\Talk\TalkServiceProvider::class,
To use facade you have to add this line in app.php
in aliases
array:
'Talk' => Nahid\Talk\Facades\Talk::class,
Now run this command in your terminal to publish this package resources:
php artisan vendor:publish --provider="Nahid\Talk\TalkServiceProvider"
After running this command, all necessary file will be included in your project. This package has two default migrations. So you have to run migrate command like this. (But make sure your database configuration is configured correctly.)
php artisan migrate
Okay, now you need to configure your user model for Talk. Go to config/talk.php
and config it:
return [
'user' => [
'model' => 'App\User',
'foreignKey' => null,
'ownerKey' => null,
],
'broadcast' => [
'enable' => true,
'app_name' => 'talk-example',
'driver' => env('TALK_BROADCAST_DRIVER', 'pusher'), // pusher or laravel-websockets
'pusher' => [
'app_id' => env('PUSHER_APP_ID', ''),
'app_key' => env('PUSHER_APP_KEY', ''),
'app_secret' => env('PUSHER_APP_SECRET', ''),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER', 'ap2'),
'encrypted' => env('PUSHER_APP_ENCRYPTION', false),
'host' => '127.0.0.1',
'port' => env('LARAVEL_WEBSOCKETS_PORT', 6001),
'scheme' => 'http',
'wsHost' => '127.0.0.1',
'wsPort' => env('LARAVEL_WEBSOCKETS_PORT', 6001),
'forceTLS' => false,
'disableStats' => true
]
],
],
'oembed' => [
'enabled' => false,
'url' => '',
'key' => ''
]
];
Its very easy to use. If you want to set authenticate user id globally then you have to set a middleware first. Go to app/Http/Kernel.php
and set it in $routeMiddleware
array:
'talk' => \Nahid\Talk\Middleware\TalkMiddleware::class,
And now you can use it from anywhere with middleware. Suppose you have a Controller and you want to set authenticate user id globally then write this in controller constructor:
$this->middleware('talk');
But instead of set id globally you can use these procedure from any method in controller:
Talk::setAuthUserId(auth()->user()->id);
Now you may use any method what you need. But if want pass authentic id instantly, this method may help you:
Talk::user(auth()->user()->id)->anyMethodHere();
Please see the API Doc.
setAuthUserId
method sets the currently loggedin user id, which you pass through parameter. If you pass null
or empty
value then it returns false.
Syntax
void setAuthUserId($userid)
Example
Constructor of a Controller is the best place to write this method.
function __construct()
{
Talk::setAuthUserId(auth()->user()->id);
}
When you pass logged in user ID, Talk will know who is currently authenticated for this system. So Talk retrieve all information based on this user.
You may use this method instead of setAuthUserId()
method. When you have to instantly access users conversations then you may use it. Syntax
object user($id)
Example When you haven't set authenticated user id globally, then you just use this method directly with others method.
$inboxes = Talk::user(auth()->user()->id)->threads();
return view('messages.threads', compact('inboxes'));
This method checks currently logged in user and if given user is already in conversation
Syntax
int|false isConversationExists($userid)
Example
if ($conversationId = Talk::isConversationExists($userId)) {
Talk::sendMessage($conversationId, $message);
}
isAuthenticUser checks if the given user exists in given conversation.
Syntax
boolean isAuthenticUser($conversationId, $userId)
Example
if (Talk::isAuthenticUser($conversationId, $userId)) {
Talk::sendMessage($conversationId, $message);
}
You can send messages via conversation id by using this method. If the message is successfully sent, it will return objects of Message model otherwise, it will return false
Syntax
object|false sendMessage($conversationId, $message)
Example
$message = Talk::sendMessage($conversationId, $message);
if ($message) {
return response()->json(['status'=>'success', 'data'=>$message], 200);
}
You can send message via receiver id by using this method. If the message is successfully sent, it will return objects of Message model otherwise, it will return false
Syntax
object|false sendMessageByUserId($userId, $message)
If you want to get all the inboxes except soft deleted message , this method may help you. This method gets all the inboxes via previously assigned authenticated user id. It returns collections of message thread with latest message.
Syntax
array getInbox([$order = 'desc'[,$offset = 0[, $take = 20]]])
Example
// controller method
$inboxes = Talk::getInbox();
return view('message.threads', compact('inboxes'));
<!-- messages/threads.blade.php -->
<ul>
@foreach($inboxes as $inbox)
<li>
<h2>{{$inbox->withUser->name}}</h2>
<p>{{$inbox->thread->message}}</p>
<span>{{$inbox->thread->humans_time}}</span>
</li>
@endforeach
</ul>
Its similar as getInbox()
method. If you want to get all the inboxes with soft deleted messages, this method may help you. This method gets all the inboxes via given user id.
Syntax
object getInboxAll([$order = 'desc'[,$offset = 0[, $take = 20]]])
This method is an alias of getInbox()
method.
Syntax
array threads([$order = 'desc'[,$offset = 0[, $take = 20]]])
This method is an alias of getInboxAll()
method.
Syntax
array threadsAll([$order = 'desc'[,$offset = 0[, $take = 20]]])
When you want to get all the conversations using your desire conversation id, you can try this method. This method returns all the conversations (except soft deleted) with sender
and withUser
objects
Syntax
array getConversationsById($conversationId[, $offset = 0[, $take = 20]])
Example
// controller method
$conversations = Talk::getConversationsById($conversationId);
$messages = $conversations->messages;
$withUser = $conversations->withUser;
return view('messages.conversations', compact('messages', 'withUser'));
This method returns two objects messages
and withUser
. messages
object contains messages collection and withUser
object contains participant User collections.
Let's see how to use it with your views
<!-- messages/conversations.blade.php -->
<div class="message-container">
<h2>Chat with {{$withUser->name}}</h2>
@foreach ($messages as $msg)
<div class="message">
<h4>{{$msg->sender->name}}</h4>
<span>{{$msg->humans_time}}</span>
<p>
{{$msg->message}}
</p>
</div>
@endforeach
</div>
This method is similar as getConversationsById()
. The only difference between this method is its return all messages with soft deleted items.
Syntax
array getConversationsAllById($conversationId[, $offset = 0[, $take = 20]])
When you want to get all the conversations using your desire receiver id, you can try this method. This method returns all the conversations (except soft deleted message) with user's objects
Syntax
object getConversationsByUserId($receiverId [, $offset = 0[, $take = 20]])
This method is similar as getConversationsByUserId()
. The only difference between this method is it returns all messages with soft deleted items.
Syntax
array getConversationsAllByUserId($receiverId[, $offset = 0[, $take = 20]])
This is a alias of getConversationsById()
method.
Syntax
array messages($conversationId[, $offset = 0[, $take = 20]])
This is a alias of getConversationsAllById()
method.
Syntax
array messagesAll($conversationId[, $offset = 0[, $take = 20]])
This is a alias of getConversationsByUserId()
method.
Syntax
array messagesByUserId($receiverId[, $offset = 0[, $take = 20]])
This is a alias of getConversationsAllByUserId()
method.
Syntax
array messagesAllByUserId($receiverId[, $offset = 0[, $take = 20]])
If you want to read a single message then you may use it. This message is return a single message object by message id.
Syntax
array readMessage($messageId)
This method returns all the information about message receiver.
This method is deprecated from version 2.0.0 and it will be removed from version 2.0.2
Syntax
object getReceiverInfo($conversationId)
If you want to set a message as seen you can use this method.
Syntax
boolean makeSeen($messageId)
When you want to delete a specific message from a conversation, you have to use this method. This method soft delete message for both user-end individually.
Syntax
boolean deleteMessage($messageId)
If you want to hard delete or permanently delete a specific message then you have to use this method.
Syntax
boolean deleteForever($messageId)
This method is used to permanently delete all conversations.
Syntax
boolean deleteConversations($conversationId)
Talk also support realtime messaging thats called Talk-Live. Talk support pusher and laravel-websocket for realtime messaging. So first you have to configure pusher or laravel-websocket. Go to app/talk.php
again and configure.
return [
'user' => [
'model' => 'App\User',
'foreignKey' => null,
'ownerKey' => null,
],
'broadcast' => [
'enable' => true,
'app_name' => 'talk-example',
'driver' => env('TALK_BROADCAST_DRIVER', 'pusher'), // pusher or laravel-websockets
'pusher' => [
'app_id' => env('PUSHER_APP_ID', ''),
'app_key' => env('PUSHER_APP_KEY', ''),
'app_secret' => env('PUSHER_APP_SECRET', ''),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER', 'ap2'),
'encrypted' => env('PUSHER_APP_ENCRYPTION', false),
'host' => '127.0.0.1',
'port' => env('LARAVEL_WEBSOCKETS_PORT', 6001),
'scheme' => 'http',
'wsHost' => '127.0.0.1',
'wsPort' => env('LARAVEL_WEBSOCKETS_PORT', 6001),
'forceTLS' => false,
'disableStats' => true
]
],
],
'oembed' => [
'enabled' => false,
'url' => '',
'key' => ''
]
];
in this new version broadcast section was added with talk config. Here broadcast is disabled by default. If you want to enable live (realtime) messaging then you have to enable it first. Then add pusher credentials to your .env file and you must add a new line called PUSHER_APP_NAME in the .env file to specify your application pusher name. Thats it. Everytime when you send message then talk will automatically fire two event, one for specific user and second for specific conversation. So you may listen or subscribe one or both as per your wish. Finally you have to subscribe these events by using talk_live()
helper function. Go to where you want to subscribe to work with message data follow this code.
<script>
var msgshow = function(data) {
// write what you want with this data
console.log(data);
}
</script>
{!! talk_live(['user'=>["id"=>auth()->user()->id, 'callback'=>['msgshow']]]) !!}
talk_live()
supports one parameters as array. The first parameter is for channel name which you want to subscribe. You have not know which channel was broadcast. Talk broadcast two channel by default. One for user and second for conversation. If you want to subscribe channel for currently loggedin user then you have to pass
logedin user id in 'user' key. ['user'=>['id'=>auth()->user()->id, 'callback'=>[]]
or you want to subscribe for conversation id you have pass conversation id as 'conversation' key. ['conversation'=>['id'=>$conversationID, 'callback'=>[]]
. You may pass both if you want.
You can pass a callback for working with pusher recieved data. For both user
and conversation
section support callbacks as array. So you can pass multiple callback as array value that was shown in previous example.
You can watch Talk-Live-Demo
Talk also supports embed urls simply use $message->toHtlmString()
in you views to render an embed link
Eg. This is a youtube embed link: https://www.youtube.com/watch?v=jNQXAC9IVRw
<div class="message-container">
<h2>Chat with {{$withUser->name}}</h2>
@foreach ($messages as $msg)
<div class="message">
<h4>{{$msg->sender->name}}</h4>
<span>{{$msg->humans_time}}</span>
<p>
{{$msg->toHtmlString()}}
</p>
</div>
@endforeach
</div>
If you want to setup your own implementation of oembed you can configure it in the talk config file. You endpoint should follow the Oembed specifications
'user' => [
...
],
...
],
'oembed' => [
'enabled' => true,
'url' => 'http://your.domain/api/oembed',
'key' => 'yout-auth-api-key'
]
Talk is backwards compatible with php 5.5. Use docker to run unit tests.
docker-compose run php55 composer install
docker-compose run php55 phpunit
docker-compose run php56 composer install
docker-compose run php56 phpunit
docker-compose run php7 composer install
docker-compose run php7 phpunit
docker-compose run hhvm composer install
docker-compose run hhvm phpunit
Thanks :)
Author: Nahid
Source Code: https://github.com/nahid/talk
License: MIT license
1652526300
gcm
The Android SDK provides a nice convenience library (com.google.android.gcm.server) that greatly simplifies the interaction between Java-based application servers and Google's GCM servers. However, Google has not provided much support for application servers implemented in languages other than Java, specifically those written in the Go programming language. The gcm
package helps to fill in this gap, providing a simple interface for sending GCM messages and automatically retrying requests in case of service unavailability.
To install gcm, use go get
:
go get github.com/Aorioli/gcm
Import gcm with the following:
import "github.com/Aorioli/gcm"
Here is a quick sample illustrating how to send a message to the GCM server:
package main
import (
"fmt"
"net/http"
"time"
"github.com/Aorioli/gcm"
)
func main() {
// Create the message to be sent.
data := map[string]interface{}{"score": "5x1", "time": "15:10"}
regIDs := []string{"4", "8", "15", "16", "23", "42"}
m := new(gcm.Message)
m.RegistrationIDs = regIDs
m.Data = data
// Create a Sender to send the message.
sender := gcm.NewSender("sample_api_key", 2, time.Minute)
// Send the message and receive the response after at most two retries.
response, err := sender.Send(m)
if err != nil {
fmt.Println("Failed to send message:", err)
return
}
/* ... */
}
Open up an issue describing the bug, enhancement or whatever so it's open for discussion.
Fork the repo, make your changes on a separate branch from master and create a pull request.
Documentation: http://godoc.org/github.com/Aorioli/gcm
Author: TheOrioli
Source Code: https://github.com/TheOrioli/gcm
License: MIT license
1651949880
jackal
jackal is a free, open-source, high performance XMPP server which aims to be known for its stability, simple configuration and low resource consumption.
jackal supports the following features:
To start using jackal, install Go 1.18+ and run the following commands:
$ git clone git@github.com:ortuman/jackal.git
$ cd jackal
$ make install installctl
This will fetch the code and install jackal
and jackalctl
binaries into your $GOPATH/bin
path.
By default the application will try to locate service configuration at config.yaml
, but alternatively you can specify a custom configuration path either through command line.
$ jackal --config=/your-custom-path/your-config.yaml
or environment variable:
$ env JACKAL_CONFIG_FILE=/your-custom-path/your-config.yaml jackal
Create a user and a database for that user:
CREATE ROLE jackal WITH LOGIN PASSWORD 'password';
CREATE DATABASE jackal;
GRANT ALL PRIVILEGES ON DATABASE jackal TO jackal;
Download lastest version of the PostgreSQL schema from jackal Github repository.
wget https://raw.githubusercontent.com/ortuman/jackal/master/sql/postgres.up.psql
Run the postgres script file to create database schema:
psql --user jackal --password -f sql/postgres.up.psql
Configure jackal to use PostgreSQL by editing the configuration file:
storage:
type: pgsql
pgsql:
host: 127.0.0.1:5432
user: jackal
password: password
database: jackal
That's it!
Your database is now ready to connect with jackal.
After completing database setup and starting jackal
service you'll have to register a new user to be able to login. To do so, you can use jackal command-line tool to create a new user proving name and password.
make installctl && jackalctl user add <user>:<password>
The purpose of clustering is to be able to use several servers for fault-tolerance and scalability.
Since jackal
is a distributed system, it needs a distributed data store like etcd to share its state across the entire cluster.
To properly run jackal
in clustering mode make sure to add a cluster
section configuration in each of your service nodes.
Here's an example of how this section should look like:
cluster:
type: kv
kv:
type: etcd
etcd:
endpoints:
- http://<etcd-host1>:<etcd-port1>
- http://<etcd-host2>:<etcd-port2>
...
port: your-cluster-node-port # default is 14369
Note the defined port
value will be used to perform cluster node communication, so make sure is reachable within your internal network.
The purpose of the extensibility framework is to provide an interface between jackal server and third-party external modules, thus offering the possibility of extending the functionality of the service for particular use cases. Extensibility gRPC API proto files can be found at jackal proto definitions repository.
The Docker deployment framework supports easy installation and configuration of jackal server.
You need to have Docker installed on your system before you can use a jackal Docker image. See Install Docker for instructions.
Download the jackal Docker image from the official Docker Hub library with this command:
docker pull ortuman/jackal:latest
Start a new jackal Docker container with custom configuration.
docker run --name=jackal \
--mount type=bind,src=/path-on-host-machine/my-custom-config.yaml,dst=/jackal/config.yaml \
-d ortuman/jackal:latest
Alternatively, and with the purpose of facilitating service mounting, you can make use of docker-compose
as follows:
docker-compose -f dockerfiles/docker-compose.yml up
This command will spin up a jackal
server along with its dependencies on a docker network and start listening for incoming connections on port 5222
.
Once up and running, don't forget to register one or more users using jackalctl
.
The jackal developer community is vital to improving jackal future releases.
Contributions of all kinds are welcome: reporting issues, updating documentation, fixing bugs, improving unit tests, sharing ideas, and any other tips that may help the jackal community.
Help us keep jackal open and inclusive. Please read and follow our Code of Conduct.
If you have any suggestion or question:
Miguel Ángel Ortuño, JID: ortuman@jackal.im, email: ortuman@pm.me
Author: ortuman
Source Code: https://github.com/ortuman/jackal
License: Apache-2.0 license
1649796720
Bus is a minimalist event/message bus implementation for internal communication. It is heavily inspired from my event_bus package for Elixir language.
The method names and arities/args are stable now. No change should be expected on the package for the version 3.x.x
except any bug fixes.
Via go packages: go get github.com/mustafaturan/bus/v3
The package requires a unique id generator to assign ids to events. You can write your own function to generate unique ids or use a package that provides unique id generation functionality.
The bus
package respect to software design choice of the packages/projects. It supports both singleton and dependency injection to init a bus
instance.
Hint: Check the demo project for the singleton configuration.
Here is a sample initilization using monoton
id generator:
import (
"github.com/mustafaturan/bus/v3"
"github.com/mustafaturan/monoton/v2"
"github.com/mustafaturan/monoton/v2/sequencer"
)
func NewBus() *bus.Bus {
// configure id generator (it doesn't have to be monoton)
node := uint64(1)
initialTime := uint64(1577865600000) // set 2020-01-01 PST as initial time
m, err := monoton.New(sequencer.NewMillisecond(), node, initialTime)
if err != nil {
panic(err)
}
// init an id generator
var idGenerator bus.Next = m.Next
// create a new bus instance
b, err := bus.NewBus(idGenerator)
if err != nil {
panic(err)
}
// maybe register topics in here
b.RegisterTopics("order.received", "order.fulfilled")
return b
}
To emit events to the topics, topic names need to be registered first:
// register topics
b.RegisterTopics("order.received", "order.fulfilled")
To receive topic events you need to register handlers; A handler basically requires two vals which are a Handle
function and topic Matcher
regex pattern.
handler := bus.Handler{
Handle: func(ctx context.Context, e bus.Event) {
// do something
// NOTE: Highly recommended to process the event in an async way
},
Matcher: ".*", // matches all topics
}
b.RegisterHandler("a unique key for the handler", handler)
// if txID val is blank, bus package generates one using the id generator
ctx := context.Background()
ctx = context.WithValue(ctx, bus.CtxKeyTxID, "some-transaction-id-if-exists")
// with optional source
ctx = context.WithValue(ctx, bus.CtxKeySource, "source-of-the-event")
// event topic name (must be registered before)
topic := "order.received"
// interface{} data for event
order := make(map[string]string)
order["orderID"] = "123456"
order["orderAmount"] = "112.20"
order["currency"] = "USD"
// emit the event
err := b.Emit(ctx, topic, order)
if err != nil {
// report the err
fmt.Println(err)
}
// emit the event with options
err := b.EmitWithOpts(ctx, topic, order, bus.WithTxID("some-tx-id"))
if err != nil {
// report the err
fmt.Println(err)
}
When an event is emitted, the topic handlers receive the event synchronously. It is highly recommended to process events asynchronous. Package leave the decision to the packages/projects to use concurrency abstractions depending on use-cases. Each handlers receive the same event as ref of bus.Event
struct:
// Event data structure
type Event struct {
ID string // identifier
TxID string // transaction identifier
Topic string // topic name
Source string // source of the event
OccurredAt time.Time // creation time in nanoseconds
Data interface{} // actual event data
}
A demo project with three consumers which increments a counter
for each event topic, printer
consumer which prints all events and lastly calculator
consumer which sums amounts.
Command:
go test -benchtime 10000000x -benchmem -run=^$ -bench=. github.com/mustafaturan/bus/v3
Results:
goos: darwin
goarch: amd64
pkg: github.com/mustafaturan/bus/v3
cpu: Intel(R) Core(TM) i5-6267U CPU @ 2.90GHz
BenchmarkEmit-4 10000000 180.5 ns/op 8 B/op 0 allocs/op
BenchmarkEmitWithoutTxID-4 10000000 244.6 ns/op 72 B/op 2 allocs/op
BenchmarkEmitWithOpts-4 10000000 280.8 ns/op 112 B/op 4 allocs/op
BenchmarkEmitWithOptsUnspecified-4 10000000 169.4 ns/op 8 B/op 0 allocs/op
PASS
ok github.com/mustafaturan/bus/v3 8.884s
All contributors should follow Contributing Guidelines before creating pull requests.
Author: Mustafaturan
Source Code: https://github.com/mustafaturan/bus
License: Apache-2.0 License